diff --git a/.changeset/spec-cloud-subpath-retired.md b/.changeset/spec-cloud-subpath-retired.md new file mode 100644 index 0000000000..ecbef526de --- /dev/null +++ b/.changeset/spec-cloud-subpath-retired.md @@ -0,0 +1,55 @@ +--- +"@objectstack/spec": minor +"@objectstack/cli": patch +"@objectstack/metadata": patch +--- + +feat(spec)!: the `@objectstack/spec/cloud` subpath is removed — the cloud control plane's contracts leave the open-source spec, and the package & marketplace format moves to `@objectstack/spec/marketplace` (#16325) + + + +**BREAKING** — a published subpath export of `@objectstack/spec` is deleted, with no +alias and no deprecation window (maintainer, 2026-08-27, verbatim: 「项目在创业阶段, +用户也很少,短期不考虑渐进。」). Shipped as `minor` under the repo's launch-window +convention, in which `major` is refused by `check-changeset-no-major` and breaking-ness +is carried by this banner plus the ADR-0087 disposition; the hand-migration prescription +is registered under protocol major 18 as `cloud-subpath-retired`. + +## What moved, and why + +Maintainer direction (2026-09-06, verbatim): 「我一直觉得 cloud 的协议应该放在云端,没必要开源」, +ruled option B "cut by owner" on #16325 (director batch #62, 2026-09-07, 「同意」). +`packages/spec/src/cloud/` held two families with different owners: + +- **The cloud control plane's own contracts** — `environment.zod`, `environment-package.zod`, + `tenant.zod`, `developer-portal.zod`, `marketplace-admin.zod`, `app-store.zod` (62 JSON-Schema + defs, 2087 lines). Their producer and every consumer live in the closed cloud repo; the + open-source tree read exactly one type from them. They are gone from `@objectstack/spec`: + `environment` and `tenant` are re-declared in the cloud repo (objectstack-ai/cloud#2037), and + the other four are deleted outright — zero consumers in any repo (#16526, ruled A). All of it + is recoverable from git history at `d5d8d50db`. +- **The package & marketplace format** — `package.zod`, `package-version.zod`, `marketplace.zod`, + `package-l10n`, `template-manifest.zod` (30 defs, 1400 lines). A package author needs it and the + open-source CLI's `os package publish` speaks it, so it STAYS, relocated to `src/marketplace/` + and published as `@objectstack/spec/marketplace`. Every def, key and JSON Schema is + byte-identical under the new `$id` category (`RENAMED_DEFS`, 32 entries; nothing left the + author-facing contract). + +## FROM → TO + +| you wrote | write instead | +|:--|:--| +| `import { PackageSchema, CreatePackageRequestSchema, … } from '@objectstack/spec/cloud'` | `… from '@objectstack/spec/marketplace'` — same symbols, same shapes | +| `import { EnvironmentArtifactSchema } from '@objectstack/spec/cloud'` | `… from '@objectstack/spec/system'` (it was only ever a re-export of that declaration) | +| `import type { EnvironmentType } from '@objectstack/spec/cloud'` | `… from '@objectstack/spec/api'` (re-declared beside the discovery fold table that reads it) | +| `import { EnvironmentSchema, TenantPlanSchema, ProvisionEnvironmentRequestSchema, … } from '@objectstack/spec/cloud'` | no open-source replacement — these are the cloud repo's own declarations now | +| `/docs/references/cloud/` | `/docs/references/marketplace/` for the format pages (redirected); the control-plane pages have no successor | + +Why the mis-binding hazard closes with this: `client.environments.*` keeps its erased `any` +deliberately (#11925/#12036), and the camelCase `Environment` row used to be the obvious-looking +binding for it — it compiled and read `undefined` at runtime against the snake_case wire. That +type no longer exists in the open-source package, so the wrong binding is structurally +impossible rather than warned about in a docblock. + +`@objectstack/cli` and `@objectstack/metadata` change only an import path (`marketplace` and +`system` respectively); no behaviour moves. diff --git a/apps/docs/redirects.mjs b/apps/docs/redirects.mjs index 62e2092c72..da39dcb1f5 100644 --- a/apps/docs/redirects.mjs +++ b/apps/docs/redirects.mjs @@ -128,7 +128,20 @@ export const docsRedirects = [ ['/docs/guides/metadata', '/docs/concepts/metadata-driven'], ['/docs/guides/solutions', '/docs'], ['/docs/guides/cheatsheets', '/docs/getting-started/quick-reference'], + // `content/docs/references/cloud/` retired with the `@objectstack/spec/cloud` + // subpath (#16325). The package & marketplace format pages moved to + // `references/marketplace/`; the environment-artifact page documents the + // `system/` declaration it only ever re-exported; the cloud control plane's + // own contract pages (environment, environment-package, tenant, + // developer-portal, marketplace-admin, app-store) have no successor page — + // section index, same as the cloud-artifact-api entry above. + ['/docs/references/cloud/marketplace', '/docs/references/marketplace/marketplace'], + ['/docs/references/cloud/package', '/docs/references/marketplace/package'], + ['/docs/references/cloud/package-version', '/docs/references/marketplace/package-version'], + ['/docs/references/cloud/template-manifest', '/docs/references/marketplace/template-manifest'], + ['/docs/references/cloud/environment-artifact', '/docs/references/system/environment-artifact'], // folder moves (wildcards — keep after exact entries) + ['/docs/references/cloud/:path*', '/docs/references'], ['/docs/guides/runtime-services/:path*', '/docs/kernel/runtime-services/:path*'], ['/docs/guides/contracts/:path*', '/docs/kernel/contracts/:path*'], // ObjectOS layer-name retirement: the System Protocol section is now "kernel" diff --git a/content/docs/concepts/north-star.mdx b/content/docs/concepts/north-star.mdx index 5b24bdb330..bbdb2764c6 100644 --- a/content/docs/concepts/north-star.mdx +++ b/content/docs/concepts/north-star.mdx @@ -62,7 +62,7 @@ validated against `ObjectStackDefinitionSchema`). When published to Cloud it is wrapped in the immutable environment artifact envelope defined by `EnvironmentArtifactSchema` in `packages/spec/src/system/environment-artifact.zod.ts` (the single -declaration; `@objectstack/spec/cloud` re-exports it). +declaration, published on `@objectstack/spec/system`). The artifact contains: diff --git a/content/docs/deployment/troubleshooting.mdx b/content/docs/deployment/troubleshooting.mdx index 3ebadfc246..2055cfb075 100644 --- a/content/docs/deployment/troubleshooting.mdx +++ b/content/docs/deployment/troubleshooting.mdx @@ -344,7 +344,7 @@ import { FieldSchema } from '@objectstack/spec/data'; import { ErrorResponseSchema } from '@objectstack/spec/api'; ``` -Available subpaths: `data`, `api`, `ui`, `system`, `kernel`, `ai`, `automation`, `contracts`, `integration`, `security`, `studio`, `cloud`, `qa`, `identity`, `shared`. +Available subpaths (the `./*` entries of the package's `exports` map, in its order): `data`, `system`, `kernel`, `ai`, `automation`, `api`, `ui`, `contracts`, `integration`, `security`, `studio`, `marketplace`, `qa`, `identity`, `shared`, `meta-spelling`. --- diff --git a/content/docs/getting-started/glossary.mdx b/content/docs/getting-started/glossary.mdx index 105b56ebe2..18de8baba1 100644 --- a/content/docs/getting-started/glossary.mdx +++ b/content/docs/getting-started/glossary.mdx @@ -11,7 +11,7 @@ To navigate the ObjectStack ecosystem effectively, it is helpful to understand t The umbrella term for the entire suite of protocols and reference implementations. It is organized into **15 protocol namespaces** grouped into three architectural layers. ### Protocol Namespace -A logical grouping of related schemas and types defined with Zod. ObjectStack has 15 protocol namespaces: Data, UI, System, Automation, AI, API, Identity, Security, Kernel, Cloud, QA, Contracts, Integration, Studio, and Shared. +A logical grouping of related schemas and types defined with Zod. ObjectStack has 15 protocol namespaces: Data, UI, System, Automation, AI, API, Identity, Security, Kernel, Marketplace, QA, Contracts, Integration, Studio, and Shared. --- @@ -22,7 +22,7 @@ The 15 namespaces collapse into three top-level layers: | Layer | Also called | Namespaces it includes | Purpose | | :--- | :--- | :--- | :--- | | **ObjectQL** | Data Layer | Data | Objects, fields, queries, relations, validation, data access | -| **Kernel** | Control Layer / System Layer (formerly named "ObjectOS") | Kernel, System, Automation, AI, API, Identity, Security, Cloud, Integration, Studio, QA, Contracts, Shared | Runtime, permissions, automation, plugins, tenants, agent tools, artifact loading | +| **Kernel** | Control Layer / System Layer (formerly named "ObjectOS") | Kernel, System, Automation, AI, API, Identity, Security, Marketplace, Integration, Studio, QA, Contracts, Shared | Runtime, permissions, automation, plugins, packages, agent tools, artifact loading | | **ObjectUI** | View Layer | UI | Apps, views, dashboards, actions, presentation metadata | Older docs and talks used **ObjectOS** as the name of this control layer. That name now refers exclusively to the commercial ObjectOS runtime environment ([docs.objectos.ai](https://docs.objectos.ai)); the open control layer is called the **Kernel**, described by the System/Kernel/AI/API protocol namespaces below. @@ -58,8 +58,8 @@ User, organization, and position schemas for identity management. ### Security Protocol RBAC, permissions, policy, and access-control schemas. -### Cloud Protocol -Multi-tenant cloud, deployment, environment, and package distribution schemas. +### Marketplace Protocol +The package & marketplace format: package identity and translations, immutable package versions, marketplace listing / submission / install shapes, and the template manifest — what a package author publishes and what the marketplace answers with. The cloud control plane's own contracts (environments, tenants, deployment) are not an open-source protocol; they live in the cloud repo. ### QA Protocol Test, validation, and quality-assurance schemas. @@ -172,7 +172,7 @@ A map within the UI Runtime that links a string identifier (e.g., `"chart.bar"`) ## Governance ### Tenant (Space / Workspace) -A logical isolation unit in the Cloud Protocol for multi-tenancy, modeled by the `tenant` schema (`cloud/tenant.zod.ts`). A single ObjectStack instance can host multiple tenants. Data is segregated by tenant isolation strategies. "Space" and "Workspace" are informal aliases for the same concept. +A logical isolation unit for multi-tenancy. Its `tenant` schema is a cloud control-plane contract declared in the cloud repo — it left `@objectstack/spec` with the `./cloud` subpath — so it is not one of the open-source protocol namespaces above. A single ObjectStack instance can host multiple tenants. Data is segregated by tenant isolation strategies. "Space" and "Workspace" are informal aliases for the same concept. ### FLS (Field-Level Security) A granular permission model (Security Protocol) where access control is applied to individual fields (columns), not just the whole object (row). diff --git a/content/docs/getting-started/quick-reference.mdx b/content/docs/getting-started/quick-reference.mdx index 61d46b0730..f906dcf642 100644 --- a/content/docs/getting-started/quick-reference.mdx +++ b/content/docs/getting-started/quick-reference.mdx @@ -182,15 +182,18 @@ User identity, organizations, and position management. | **[Position](/docs/references/identity/position)** | `position.zod.ts` | Position | Permission-set distribution (岗位, ADR-0090) | | **[SCIM](/docs/references/identity/scim)** | `scim.zod.ts` | SCIMUser, SCIMGroup | SCIM 2.0 provisioning | -## Cloud Protocol (3 of 11 schemas) +## Marketplace Protocol (2 of 4 schemas) -Environments, marketplace, licensing, and multi-tenancy. +The package & marketplace format — what a package author publishes and what the +marketplace answers with. (The cloud control plane's own contracts — environments, +tenants, the developer portal, marketplace administration — are not an open-source +protocol; they left `@objectstack/spec` with the `./cloud` subpath and live in the +cloud repo beside their producer.) | Protocol | Source File | Key Schemas | Purpose | |:---------|:-----------|:------------|:--------| -| **[Environment](/docs/references/cloud/environment)** | `environment.zod.ts` | Environment, EnvironmentType | Deployment environments | -| **[Marketplace](/docs/references/cloud/marketplace)** | `marketplace.zod.ts` | MarketplaceListing, PackageSubmission | Plugin marketplace | -| **[Tenant](/docs/references/cloud/tenant)** | `tenant.zod.ts` | Tenant | Multi-tenancy isolation | +| **[Package](/docs/references/marketplace/package)** | `package.zod.ts` | Package, CreatePackageRequest, PackageTranslations | Package identity and listing text | +| **[Marketplace](/docs/references/marketplace/marketplace)** | `marketplace.zod.ts` | MarketplaceListing, PackageSubmission | Plugin marketplace | ## Integration Protocol (1 of 1 schema) diff --git a/content/docs/permissions/system-context.mdx b/content/docs/permissions/system-context.mdx index 76d26caf59..749d333f33 100644 --- a/content/docs/permissions/system-context.mdx +++ b/content/docs/permissions/system-context.mdx @@ -47,16 +47,17 @@ is left open deliberately rather than hidden — see ## Which `isSystem` this page is about -Four unrelated declarations share the identifier. **This page documents only the +Three unrelated declarations share the identifier. **This page documents only the first.** The others are ordinary metadata fields on a stored document and have -nothing to do with elevation. +nothing to do with elevation. (A fourth, `Environment.isSystem` — a +platform-infrastructure environment, not user data — left this repo with the +`@objectstack/spec/cloud` subpath in #16325 and is declared in the cloud repo.) | Declaration | What it is | This page? | |:---|:---|:---:| | `ExecutionContext.isSystem` — `packages/spec/src/kernel/execution-context.zod.ts#isSystem` | The elevation flag on an operation's context | ✅ | | `Object.isSystem` — `packages/spec/src/data/object.zod.ts#isSystem` | Marks a **system object** (protected from deletion; defaults its org-wide sharing to `public` when no `sharingModel` is set) | ❌ | | `EmailTemplate.isSystem` — `packages/spec/src/system/email-template.zod.ts#isSystem` | Built-in template; tenants may override but should not delete | ❌ | -| `Environment.isSystem` — `packages/spec/src/cloud/environment.zod.ts#isSystem` | Platform-infrastructure environment, not user data | ❌ | The collision is a genuine hazard rather than a naming nit: `Object.isSystem` changes an object's **default sharing**, and `ExecutionContext.isSystem` changes @@ -382,10 +383,10 @@ test files certifies nothing. ⛔ Do not re-add them to `DECLARED_COUNTS` — a self-test case in the gate refuses that by name. Re-measure them with `node scripts/isystem-census.mjs` when you want them current, and move the date. -**What the enforced declarations row counts.** Not the four field declarations -above — those are four *distinct fields* that happen to share a name, and only +**What the enforced declarations row counts.** Not the three field declarations +above — those are three *distinct fields* that happen to share a name, and only the first is elevation. This row counts every position where the parser puts the -identifier in a **declaring** slot: those four, plus the structural type literals +identifier in a **declaring** slot: those three, plus the structural type literals that restate `ExecutionContext.isSystem`'s shape inline rather than importing it (`{ isSystem: true; tenantId?: string }`, `context?: { isSystem?: boolean }`, and the `get isSystem()` accessor on the engine's context wrapper). A restatement is diff --git a/content/docs/plugins/packages.mdx b/content/docs/plugins/packages.mdx index c8902050c5..137e982351 100644 --- a/content/docs/plugins/packages.mdx +++ b/content/docs/plugins/packages.mdx @@ -24,7 +24,7 @@ ObjectStack is organized into **72 package manifests** across multiple categorie **The Constitution** — Protocol schemas, types, and constants for the entire ObjectStack ecosystem. - **Purpose**: Zod-first schema definitions for all 15 protocol domains -- **Exports**: Builder functions (`defineStack`, `defineView`, `defineApp`, `defineFlow`, `defineAgent`, `defineTool`, `defineSkill`) from the root entry, plus `ObjectSchema.create()` for objects from the `@objectstack/spec/data` subpath. Protocol namespaces (Data, UI, System, Automation, AI, API, Identity, Security, Kernel, Cloud, QA, Contracts, Integration, Studio, Shared) are not re-exported from the top-level entry for tree-shaking reasons — import them from subpaths such as `@objectstack/spec/data` and `@objectstack/spec/ui`. +- **Exports**: Builder functions (`defineStack`, `defineView`, `defineApp`, `defineFlow`, `defineAgent`, `defineTool`, `defineSkill`) from the root entry, plus `ObjectSchema.create()` for objects from the `@objectstack/spec/data` subpath. Protocol namespaces (Data, UI, System, Automation, AI, API, Identity, Security, Kernel, Marketplace, QA, Contracts, Integration, Studio, Shared) are not re-exported from the top-level entry for tree-shaking reasons — import them from subpaths such as `@objectstack/spec/data` and `@objectstack/spec/ui`. - **When to use**: Import types, schemas, and builder functions when authoring metadata. - **Documentation**: [Protocol Reference](/docs/references) diff --git a/content/docs/references/api/discovery.mdx b/content/docs/references/api/discovery.mdx index 0465e3254e..d5074ce898 100644 --- a/content/docs/references/api/discovery.mdx +++ b/content/docs/references/api/discovery.mdx @@ -12,8 +12,8 @@ description: Discovery protocol schemas ## TypeScript Usage ```typescript -import { ApiRoutesSchema, CapabilityDescriptorSchema, DiscoverySchema, DiscoveryEnvironmentSchema, RouteHealthEntrySchema, RouteHealthReportSchema, ServiceInfoSchema, ServiceSelfInfoSchema, ServiceStatus, WellKnownCapabilitiesSchema } from '@objectstack/spec/api'; -import type { ApiRoutes, CapabilityDescriptor, DiscoveryEnvironment, RouteHealthEntry, RouteHealthReport, ServiceInfo, ServiceSelfInfo, ServiceStatus, WellKnownCapabilities } from '@objectstack/spec/api'; +import { ApiRoutesSchema, CapabilityDescriptorSchema, DiscoverySchema, DiscoveryEnvironmentSchema, EnvironmentTypeSchema, RouteHealthEntrySchema, RouteHealthReportSchema, ServiceInfoSchema, ServiceSelfInfoSchema, ServiceStatus, WellKnownCapabilitiesSchema } from '@objectstack/spec/api'; +import type { ApiRoutes, CapabilityDescriptor, DiscoveryEnvironment, EnvironmentType, RouteHealthEntry, RouteHealthReport, ServiceInfo, ServiceSelfInfo, ServiceStatus, WellKnownCapabilities } from '@objectstack/spec/api'; // Validate data const result = ApiRoutesSchema.parse(data); @@ -161,6 +161,23 @@ Deployment posture a discovery response advertises. Deliberately three coarse bu * `development` +--- + +## EnvironmentType + +Environment categorical tag (prod/sandbox/dev/test/…) + +### Allowed Values + +* `production` +* `sandbox` +* `development` +* `test` +* `staging` +* `preview` +* `trial` + + --- ## RouteHealthEntry diff --git a/content/docs/references/cloud/app-store.mdx b/content/docs/references/cloud/app-store.mdx deleted file mode 100644 index 99f3ac328b..0000000000 --- a/content/docs/references/cloud/app-store.mdx +++ /dev/null @@ -1,345 +0,0 @@ ---- -title: App Store -description: App Store protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## App Store Protocol (Customer Experience) - -Defines schemas for the end-customer experience when browsing, evaluating, -installing, and managing marketplace apps from within ObjectOS. - -### Architecture Alignment -- **Salesforce AppExchange (Customer)**: Browse apps, read reviews, 1-click install -- **Shopify App Store (Merchant)**: App evaluation, trial, install, manage subscriptions -- **Apple App Store (User)**: Ratings, reviews, featured collections, personalized recs - -### Customer Journey -``` -Discover → Evaluate → Install → Configure → Use → Rate/Review → Manage -``` - -### Key Concepts -- **Reviews & Ratings**: User-submitted ratings and reviews with moderation -- **Collections & Recommendations**: Personalized discovery and curated picks -- **Subscription Management**: Manage licenses, billing, and renewals -- **Installed App Management**: Enable, disable, configure, upgrade, uninstall - - -**Source:** `packages/spec/src/cloud/app-store.zod.ts` - - -## TypeScript Usage - -```typescript -import { AppDiscoveryRequestSchema, AppDiscoveryResponseSchema, AppSubscriptionSchema, InstalledAppSummarySchema, ListInstalledAppsRequestSchema, ListInstalledAppsResponseSchema, ListReviewsRequestSchema, ListReviewsResponseSchema, RecommendationReasonSchema, RecommendedAppSchema, ReviewModerationStatusSchema, SubmitReviewRequestSchema, SubscriptionStatusSchema, UserReviewSchema } from '@objectstack/spec/cloud'; -import type { AppDiscoveryRequest, AppDiscoveryResponse, AppSubscription, InstalledAppSummary, ListInstalledAppsRequest, ListInstalledAppsResponse, ListReviewsRequest, ListReviewsResponse, RecommendationReason, RecommendedApp, ReviewModerationStatus, SubmitReviewRequest, SubscriptionStatus, UserReview } from '@objectstack/spec/cloud'; - -// Validate data -const result = AppDiscoveryRequestSchema.parse(data); -``` - ---- - -## AppDiscoveryRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **tenantId** | `string` | optional | | -| **categories** | `Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| 'integration' \| 'automation' \| 'ai' \| 'security' \| 'developer-tools' \| 'ui-theme' \| 'storage' \| 'other'>[]` | optional | | -| **platformVersion** | `string` | optional | | -| **limit** | `integer` | optional (default: `10`) | | - - ---- - -## AppDiscoveryResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **featured** | `{ listingId: string; name: string; tagline?: string; iconUrl?: string; … }[]` | optional | | -| **recommended** | `{ listingId: string; name: string; tagline?: string; iconUrl?: string; … }[]` | optional | | -| **trending** | `{ listingId: string; name: string; tagline?: string; iconUrl?: string; … }[]` | optional | | -| **newArrivals** | `{ listingId: string; name: string; tagline?: string; iconUrl?: string; … }[]` | optional | | -| **collections** | `{ id: string; name: string; description?: string; coverImageUrl?: string; … }[]` | optional | | - -### Nested Shape: `AppDiscoveryResponse.featured[number]` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **name** | `string` | ✅ | | -| **tagline** | `string` | optional | | -| **iconUrl** | `string` | optional | | -| **category** | `Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| …>` | ✅ | Marketplace package category | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | ✅ | Package pricing model | -| **averageRating** | `number` | optional | | -| **activeInstalls** | `integer` | optional | | -| **reason** | `Enum<'popular-in-category' \| 'similar-users' \| 'complements-installed' \| 'trending' \| …>` | ✅ | | - -### Nested Shape: `AppDiscoveryResponse.recommended[number]` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **name** | `string` | ✅ | | -| **tagline** | `string` | optional | | -| **iconUrl** | `string` | optional | | -| **category** | `Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| …>` | ✅ | Marketplace package category | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | ✅ | Package pricing model | -| **averageRating** | `number` | optional | | -| **activeInstalls** | `integer` | optional | | -| **reason** | `Enum<'popular-in-category' \| 'similar-users' \| 'complements-installed' \| 'trending' \| …>` | ✅ | | - -### Nested Shape: `AppDiscoveryResponse.trending[number]` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **name** | `string` | ✅ | | -| **tagline** | `string` | optional | | -| **iconUrl** | `string` | optional | | -| **category** | `Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| …>` | ✅ | Marketplace package category | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | ✅ | Package pricing model | -| **averageRating** | `number` | optional | | -| **activeInstalls** | `integer` | optional | | -| **reason** | `Enum<'popular-in-category' \| 'similar-users' \| 'complements-installed' \| 'trending' \| …>` | ✅ | | - -### Nested Shape: `AppDiscoveryResponse.newArrivals[number]` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **name** | `string` | ✅ | | -| **tagline** | `string` | optional | | -| **iconUrl** | `string` | optional | | -| **category** | `Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| …>` | ✅ | Marketplace package category | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | ✅ | Package pricing model | -| **averageRating** | `number` | optional | | -| **activeInstalls** | `integer` | optional | | -| **reason** | `Enum<'popular-in-category' \| 'similar-users' \| 'complements-installed' \| 'trending' \| …>` | ✅ | | - - ---- - -## AppSubscription - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Subscription ID | -| **listingId** | `string` | ✅ | App listing ID | -| **tenantId** | `string` | ✅ | Customer tenant ID | -| **status** | `Enum<'active' \| 'trialing' \| 'past-due' \| 'cancelled' \| 'expired'>` | ✅ | | -| **licenseKey** | `string` | optional | | -| **plan** | `string` | optional | Subscription plan name | -| **billingCycle** | `Enum<'monthly' \| 'annual'>` | optional | | -| **priceInCents** | `integer` | optional | | -| **currentPeriodStart** | `string` | optional | | -| **currentPeriodEnd** | `string` | optional | | -| **trialEndDate** | `string` | optional | | -| **autoRenew** | `boolean` | optional (default: `true`) | | -| **createdAt** | `string` | ✅ | | - - ---- - -## InstalledAppSummary - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **packageId** | `string` | ✅ | | -| **name** | `string` | ✅ | | -| **iconUrl** | `string` | optional | | -| **installedVersion** | `string` | ✅ | | -| **latestVersion** | `string` | optional | | -| **updateAvailable** | `boolean` | optional (default: `false`) | | -| **enabled** | `boolean` | optional (default: `true`) | | -| **subscriptionStatus** | `Enum<'active' \| 'trialing' \| 'past-due' \| 'cancelled' \| 'expired'>` | optional | | -| **installedAt** | `string` | ✅ | | - - ---- - -## ListInstalledAppsRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **tenantId** | `string` | optional | | -| **enabled** | `boolean` | optional | | -| **updateAvailable** | `boolean` | optional | | -| **sortBy** | `Enum<'name' \| 'installed-date' \| 'updated-date'>` | optional (default: `"name"`) | | -| **page** | `integer` | optional (default: `1`) | | -| **pageSize** | `integer` | optional (default: `20`) | | - - ---- - -## ListInstalledAppsResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **items** | `{ listingId: string; packageId: string; name: string; iconUrl?: string; … }[]` | ✅ | | -| **total** | `integer` | ✅ | | -| **page** | `integer` | ✅ | | -| **pageSize** | `integer` | ✅ | | - - ---- - -## ListReviewsRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | Listing to get reviews for | -| **sortBy** | `Enum<'newest' \| 'oldest' \| 'highest' \| 'lowest' \| 'most-helpful'>` | optional (default: `"newest"`) | | -| **rating** | `integer` | optional | | -| **page** | `integer` | optional (default: `1`) | | -| **pageSize** | `integer` | optional (default: `10`) | | - - ---- - -## ListReviewsResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **items** | `{ id: string; listingId: string; userId: string; displayName?: string; … }[]` | ✅ | | -| **total** | `integer` | ✅ | | -| **page** | `integer` | ✅ | | -| **pageSize** | `integer` | ✅ | | -| **ratingSummary** | `{ averageRating: number; totalRatings: integer; distribution: object }` | optional | | - -### Nested Shape: `ListReviewsResponse.items[number]` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Review ID | -| **listingId** | `string` | ✅ | Listing being reviewed | -| **userId** | `string` | ✅ | Review author user ID | -| **displayName** | `string` | optional | Reviewer display name | -| **rating** | `integer` | ✅ | Star rating (1-5) | -| **title** | `string` | optional | Review title | -| **body** | `string` | optional | Review text | -| **appVersion** | `string` | optional | App version being reviewed | -| **moderationStatus** | `Enum<'pending' \| 'approved' \| 'flagged' \| 'rejected'>` | optional (default: `"pending"`) | | -| **helpfulCount** | `integer` | optional (default: `0`) | | -| **publisherResponse** | `{ body: string; respondedAt: string }` | optional | Publisher response to review | -| **submittedAt** | `string` | ✅ | | -| **updatedAt** | `string` | optional | | - - ---- - -## RecommendationReason - -### Allowed Values - -* `popular-in-category` -* `similar-users` -* `complements-installed` -* `trending` -* `new-release` -* `editor-pick` - - ---- - -## RecommendedApp - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **name** | `string` | ✅ | | -| **tagline** | `string` | optional | | -| **iconUrl** | `string` | optional | | -| **category** | `Enum<'crm' \| 'erp' \| 'hr' \| 'finance' \| 'project' \| 'collaboration' \| 'analytics' \| 'integration' \| 'automation' \| 'ai' \| 'security' \| 'developer-tools' \| 'ui-theme' \| 'storage' \| 'other'>` | ✅ | Marketplace package category | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | ✅ | Package pricing model | -| **averageRating** | `number` | optional | | -| **activeInstalls** | `integer` | optional | | -| **reason** | `Enum<'popular-in-category' \| 'similar-users' \| 'complements-installed' \| 'trending' \| 'new-release' \| 'editor-pick'>` | ✅ | | - - ---- - -## ReviewModerationStatus - -### Allowed Values - -* `pending` -* `approved` -* `flagged` -* `rejected` - - ---- - -## SubmitReviewRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | Listing to review | -| **rating** | `integer` | ✅ | Star rating | -| **title** | `string` | optional | | -| **body** | `string` | optional | | - - ---- - -## SubscriptionStatus - -### Allowed Values - -* `active` -* `trialing` -* `past-due` -* `cancelled` -* `expired` - - ---- - -## UserReview - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Review ID | -| **listingId** | `string` | ✅ | Listing being reviewed | -| **userId** | `string` | ✅ | Review author user ID | -| **displayName** | `string` | optional | Reviewer display name | -| **rating** | `integer` | ✅ | Star rating (1-5) | -| **title** | `string` | optional | Review title | -| **body** | `string` | optional | Review text | -| **appVersion** | `string` | optional | App version being reviewed | -| **moderationStatus** | `Enum<'pending' \| 'approved' \| 'flagged' \| 'rejected'>` | optional (default: `"pending"`) | | -| **helpfulCount** | `integer` | optional (default: `0`) | | -| **publisherResponse** | `{ body: string; respondedAt: string }` | optional | Publisher response to review | -| **submittedAt** | `string` | ✅ | | -| **updatedAt** | `string` | optional | | - - ---- - diff --git a/content/docs/references/cloud/developer-portal.mdx b/content/docs/references/cloud/developer-portal.mdx deleted file mode 100644 index 15d37bd079..0000000000 --- a/content/docs/references/cloud/developer-portal.mdx +++ /dev/null @@ -1,232 +0,0 @@ ---- -title: Developer Portal -description: Developer Portal protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## Developer Portal Protocol - -Defines schemas for the developer-facing side of the marketplace ecosystem. -Covers the complete developer journey: - -``` -Register → Create App → Develop → Validate → Build → Submit → Monitor → Iterate -``` - -### Architecture Alignment -- **Salesforce Partner Portal**: ISV registration, AppExchange publishing, Trialforce -- **Shopify Partner Dashboard**: App management, analytics, billing -- **VS Code Marketplace Management**: Extension publishing, statistics, tokens - -### Identity Integration (better-auth) -Authentication, organization management, and API keys are handled by the -Identity module (`@objectstack/spec` Identity namespace), which follows the -better-auth specification. This module only defines marketplace-specific -extensions on top of the shared identity layer: - -- **User** → `Identity.UserSchema`; the session wire shape is `Session` from - `@objectstack/spec/api` (the identity module deliberately declares no bare - `SessionSchema` — #4641) -- **Organization & Members** → `Identity.OrganizationSchema`, `Identity.MemberSchema` -- **API Keys** → the `sys_api_key` ObjectSchema in - `@objectstack/platform-objects` (`identity/sys-api-key.object.ts`), minted via - `POST /api/v1/keys`; its `scopes` column is the marketplace-scope carrier. - There is no `Identity.ApiKeySchema` — #8715 retired it (it documented - better-auth's apiKey plugin, which this platform does not load) - -### Key Concepts -- **Publisher Profile**: Links an Identity Organization to a marketplace publisher -- **App Listing Management**: CRUD for marketplace listings (draft → published) -- **Version Channels**: alpha / beta / rc / stable release channels -- **Publishing Analytics**: Install trends, revenue, ratings over time - - -**Source:** `packages/spec/src/cloud/developer-portal.zod.ts` - - -## TypeScript Usage - -```typescript -import { AnalyticsTimeRangeSchema, CreateListingRequestSchema, ListingActionRequestSchema, PublisherProfileSchema, PublishingAnalyticsRequestSchema, PublishingAnalyticsResponseSchema, ReleaseChannelSchema, TimeSeriesPointSchema, UpdateListingRequestSchema, VersionReleaseSchema } from '@objectstack/spec/cloud'; -import type { AnalyticsTimeRange, CreateListingRequest, ListingActionRequest, PublisherProfile, PublishingAnalyticsRequest, PublishingAnalyticsResponse, ReleaseChannel, TimeSeriesPoint, UpdateListingRequest, VersionRelease } from '@objectstack/spec/cloud'; - -// Validate data -const result = AnalyticsTimeRangeSchema.parse(data); -``` - ---- - -## AnalyticsTimeRange - -### Allowed Values - -* `last_7d` -* `last_30d` -* `last_90d` -* `last_365d` -* `all_time` - - ---- - -## CreateListingRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **packageId** | `string` | ✅ | Package identifier | -| **name** | `string` | ✅ | App display name | -| **tagline** | `string` | optional | | -| **description** | `string` | optional | | -| **category** | `string` | ✅ | Marketplace category | -| **tags** | `string[]` | optional | | -| **iconUrl** | `string` | optional | | -| **screenshots** | `{ url: string; caption?: string }[]` | optional | | -| **documentationUrl** | `string` | optional | | -| **supportUrl** | `string` | optional | | -| **repositoryUrl** | `string` | optional | | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | optional (default: `"free"`) | | -| **priceInCents** | `integer` | optional | | - - ---- - -## ListingActionRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | Listing ID | -| **action** | `Enum<'submit' \| 'unlist' \| 'deprecate' \| 'reactivate'>` | ✅ | Action to perform on listing | -| **reason** | `string` | optional | | - - ---- - -## PublisherProfile - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **organizationId** | `string` | ✅ | Identity Organization ID | -| **publisherId** | `string` | ✅ | Marketplace publisher ID | -| **verification** | `Enum<'unverified' \| 'pending' \| 'verified' \| 'trusted' \| 'partner'>` | optional (default: `"unverified"`) | Publisher verification status | -| **agreementVersion** | `string` | optional | Accepted developer agreement version | -| **website** | `string` | optional | Publisher website | -| **supportEmail** | `string` | optional | Publisher support email | -| **registeredAt** | `string` | ✅ | | - - ---- - -## PublishingAnalyticsRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | Listing to get analytics for | -| **timeRange** | `Enum<'last_7d' \| 'last_30d' \| 'last_90d' \| 'last_365d' \| 'all_time'>` | optional (default: `"last_30d"`) | | -| **metrics** | `Enum<'installs' \| 'uninstalls' \| 'active_installs' \| 'ratings' \| 'revenue' \| 'page_views'>[]` | optional | Metrics to include (default: all) | - - ---- - -## PublishingAnalyticsResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **timeRange** | `Enum<'last_7d' \| 'last_30d' \| 'last_90d' \| 'last_365d' \| 'all_time'>` | ✅ | | -| **summary** | `{ totalInstalls: integer; activeInstalls: integer; totalUninstalls: integer; averageRating?: number; … }` | ✅ | | -| **timeSeries** | `Record` | optional | Time series keyed by metric name | -| **ratingDistribution** | `{ 1: integer; 2: integer; 3: integer; 4: integer; … }` | optional | | - -### Nested Shape: `PublishingAnalyticsResponse.summary` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **totalInstalls** | `integer` | ✅ | | -| **activeInstalls** | `integer` | ✅ | | -| **totalUninstalls** | `integer` | ✅ | | -| **averageRating** | `number` | optional | | -| **totalRatings** | `integer` | ✅ | | -| **totalRevenue** | `number` | optional | Revenue in cents | -| **pageViews** | `integer` | ✅ | | - - ---- - -## ReleaseChannel - -### Allowed Values - -* `alpha` -* `beta` -* `rc` -* `stable` - - ---- - -## TimeSeriesPoint - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **date** | `string` | ✅ | | -| **value** | `number` | ✅ | | - - ---- - -## UpdateListingRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | Listing ID to update | -| **name** | `string` | optional | | -| **tagline** | `string` | optional | | -| **description** | `string` | optional | | -| **category** | `string` | optional | | -| **tags** | `string[]` | optional | | -| **iconUrl** | `string` | optional | | -| **screenshots** | `{ url: string; caption?: string }[]` | optional | | -| **documentationUrl** | `string` | optional | | -| **supportUrl** | `string` | optional | | -| **repositoryUrl** | `string` | optional | | -| **pricing** | `Enum<'free' \| 'freemium' \| 'paid' \| 'subscription' \| 'usage-based' \| 'contact-sales'>` | optional | | -| **priceInCents** | `integer` | optional | | - - ---- - -## VersionRelease - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **version** | `string` | ✅ | Semver version (e.g., 2.1.0-beta.1) | -| **channel** | `Enum<'alpha' \| 'beta' \| 'rc' \| 'stable'>` | optional (default: `"stable"`) | | -| **releaseNotes** | `string` | optional | Release notes (Markdown) | -| **changelog** | `{ type: Enum<'added' \| 'changed' \| 'fixed' \| 'removed' \| 'deprecated' \| 'security'>; description: string }[]` | optional | Structured changelog entries | -| **minPlatformVersion** | `string` | optional | | -| **artifactUrl** | `string` | optional | Built package artifact URL | -| **artifactChecksum** | `string` | optional | SHA-256 checksum | -| **deprecated** | `boolean` | optional (default: `false`) | | -| **deprecationMessage** | `string` | optional | | -| **releasedAt** | `string` | optional | | - - ---- - diff --git a/content/docs/references/cloud/environment-artifact.mdx b/content/docs/references/cloud/environment-artifact.mdx deleted file mode 100644 index 8fbd7a8827..0000000000 --- a/content/docs/references/cloud/environment-artifact.mdx +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Environment Artifact -description: Environment Artifact protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## Environment Artifact Envelope — re-export (#4740, #4535 C10) - -The envelope has exactly ONE declaration: -`../system/environment-artifact.zod` (maintainer route A′ on #4740 — -`./system` holds the live wire shape, `./cloud` re-exports it). Importing -from `@objectstack/spec/cloud` and `@objectstack/spec/system` yields the -SAME symbols, so the import path can never change the shape a consumer -gets (the #4411 dual-source trap, closed for this name). - -Do NOT re-declare the envelope here. A second declaration under this name -is exactly what `check:dual-source-exports` and the symbol-identity pin in -`../system/environment-artifact.test.ts` exist to reject. - - -**Source:** `packages/spec/src/cloud/environment-artifact.zod.ts` - - -## TypeScript Usage - -```typescript -import { Sha256DigestSchema } from '@objectstack/spec/cloud'; -import type { Sha256Digest } from '@objectstack/spec/cloud'; - -// Validate data -const result = Sha256DigestSchema.parse(data); -``` - ---- - -## Sha256Digest - -SHA-256 digest (64 hex chars) - -**Type:** `string` - - ---- - diff --git a/content/docs/references/cloud/environment-package.mdx b/content/docs/references/cloud/environment-package.mdx deleted file mode 100644 index 385ca26204..0000000000 --- a/content/docs/references/cloud/environment-package.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: Environment Package -description: Environment Package protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## Environment Package Installation Protocol - -Models `sys_package_installation` — the pairing between an Environment and -a specific, immutable `sys_package_version` snapshot. - -Key invariants (per ADR-0003): -- One active version per package per environment at any time - (UNIQUE `(environment_id, package_id)`). -- **Upgrade** = atomic `UPDATE package_version_id` to a newer version UUID. -- **Rollback** = atomic `UPDATE package_version_id` to an older version UUID. -- Only `status = 'published'` versions may be installed in production - environments (draft/pre-release allowed in dev/sandbox with `allowDraft`). - -Stored in the **Control Plane DB** (not in environment data-plane DBs). - - -**Source:** `packages/spec/src/cloud/environment-package.zod.ts` - - -## TypeScript Usage - -```typescript -import { EnvironmentPackageInstallationSchema, EnvironmentPackageStatusSchema, InstallPackageToEnvironmentRequestSchema, ListEnvironmentPackagesResponseSchema, RollbackEnvironmentPackageRequestSchema, UpgradeEnvironmentPackageRequestSchema } from '@objectstack/spec/cloud'; -import type { EnvironmentPackageInstallation, EnvironmentPackageStatus, InstallPackageToEnvironmentRequest, ListEnvironmentPackagesResponse, RollbackEnvironmentPackageRequest, UpgradeEnvironmentPackageRequest } from '@objectstack/spec/cloud'; - -// Validate data -const result = EnvironmentPackageInstallationSchema.parse(data); -``` - ---- - -## EnvironmentPackageInstallation - -Package installation record in an environment (sys_package_installation) - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique installation record ID | -| **environmentId** | `string` | ✅ | Environment this installation belongs to | -| **packageVersionId** | `string` | ✅ | UUID of the installed sys_package_version row | -| **packageId** | `string` | ✅ | UUID of the parent sys_package row (denormalized for constraint enforcement) | -| **status** | `Enum<'installed' \| 'installing' \| 'upgrading' \| 'disabled' \| 'error'>` | optional (default: `"installed"`) | Package installation status within an environment | -| **enabled** | `boolean` | optional (default: `true`) | Whether the package metadata is loaded | -| **settings** | `Record` | optional | Per-installation configuration settings | -| **withSampleData** | `boolean` | optional (default: `false`) | Replay the package seed datasets on next kernel cold-start | -| **installedAt** | `string` | ✅ | Installation timestamp (ISO-8601) | -| **installedBy** | `string` | optional | User ID of the installer | -| **updatedAt** | `string` | optional | Last update timestamp (ISO-8601) | -| **errorMessage** | `string` | optional | Error message when status is error | - - ---- - -## EnvironmentPackageStatus - -Package installation status within an environment - -### Allowed Values - -* `installed` -* `installing` -* `upgrading` -* `disabled` -* `error` - - ---- - -## InstallPackageToEnvironmentRequest - -Install a package version into a specific environment - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **packageVersionId** | `string` | optional | Exact package version UUID to install (preferred) | -| **packageManifestId** | `string` | optional | Package manifest ID (reverse-domain, e.g. com.acme.crm) — resolved to version UUID | -| **version** | `string` | optional | Version string (defaults to latest published) | -| **allowDraft** | `boolean` | optional (default: `false`) | Allow installing a draft version (dev/sandbox environments only) | -| **settings** | `Record` | optional | Installation-time configuration settings | -| **withSampleData** | `boolean` | optional (default: `false`) | Replay the package seed datasets on next kernel cold-start | -| **enableOnInstall** | `boolean` | optional (default: `true`) | Activate the package immediately after install | -| **installedBy** | `string` | optional | User ID of the installer | - - ---- - -## ListEnvironmentPackagesResponse - -List of packages installed in an environment - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **packages** | `{ id: string; environmentId: string; packageVersionId: string; packageId: string; … }[]` | ✅ | Packages installed in this environment | -| **total** | `number` | ✅ | Total count | - -### Nested Shape: `ListEnvironmentPackagesResponse.packages[number]` - -Package installation record in an environment (sys_package_installation) - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique installation record ID | -| **environmentId** | `string` | ✅ | Environment this installation belongs to | -| **packageVersionId** | `string` | ✅ | UUID of the installed sys_package_version row | -| **packageId** | `string` | ✅ | UUID of the parent sys_package row (denormalized for constraint enforcement) | -| **status** | `Enum<'installed' \| 'installing' \| 'upgrading' \| 'disabled' \| 'error'>` | optional (default: `"installed"`) | Package installation status within an environment | -| **enabled** | `boolean` | optional (default: `true`) | Whether the package metadata is loaded | -| **settings** | `Record` | optional | Per-installation configuration settings | -| **withSampleData** | `boolean` | optional (default: `false`) | Replay the package seed datasets on next kernel cold-start | -| **installedAt** | `string` | ✅ | Installation timestamp (ISO-8601) | -| **installedBy** | `string` | optional | User ID of the installer | -| **updatedAt** | `string` | optional | Last update timestamp (ISO-8601) | -| **errorMessage** | `string` | optional | Error message when status is error | - - ---- - -## RollbackEnvironmentPackageRequest - -Roll back a package installation to a specific older version - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **targetPackageVersionId** | `string` | ✅ | Package version UUID to roll back to | -| **rolledBackBy** | `string` | optional | User ID performing the rollback | - - ---- - -## UpgradeEnvironmentPackageRequest - -Upgrade a package installation to a newer version - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **targetPackageVersionId** | `string` | optional | Target package version UUID (preferred) | -| **targetVersion** | `string` | optional | Target version string (defaults to latest published) | -| **allowDraft** | `boolean` | optional (default: `false`) | Allow upgrading to a draft version | -| **upgradedBy** | `string` | optional | User ID performing the upgrade | - - ---- - diff --git a/content/docs/references/cloud/environment.mdx b/content/docs/references/cloud/environment.mdx deleted file mode 100644 index 5c6b762caa..0000000000 --- a/content/docs/references/cloud/environment.mdx +++ /dev/null @@ -1,318 +0,0 @@ ---- -title: Environment -description: Environment protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## Environment Protocol (runtime container) - -An **Environment** is the runtime container of an organization's data. -It owns a physically isolated database, a canonical hostname, a plan/quota -tier, and per-environment RBAC. An organization may own many environments -(dev/test/prod/sandbox/preview/…) — exactly one is marked `is_default`. - -This file defines the Control-Plane schemas for the `sys_environment`, -`sys_environment_credential` and `sys_environment_member` tables. Business -data lives in each environment's own database — those data-plane DBs hold -no system tables. - -See ADR-0006 v4: `sys_project` was renamed to `sys_environment`; the -separate dev-workspace `Project` concept introduced in v3 has been -dropped — user code is now modelled as an implicit `sys_package` with -a per-org `manifest_id` (see ADR-0003), so a single package + version -+ installation model serves both Marketplace apps and user projects. - -Split of concerns: -- **Control Plane**: `sys_environment` (includes physical DB addressing), - `sys_package_installation` (with `environment_id`), `sys_environment_credential`, - `sys_environment_member`, `sys_metadata` (on the metadata tables, `environment_id` - is deprecated in favor of `organization_id` — ADR-0006 v4). -- **Data Plane**: each environment DB contains only business objects - (account, task, …). No system tables, no `environment_id` columns. - - -**Source:** `packages/spec/src/cloud/environment.zod.ts` - - -## TypeScript Usage - -```typescript -import { EnvironmentSchema, EnvironmentCredentialSchema, EnvironmentCredentialStatusSchema, EnvironmentDriverSchema, EnvironmentMemberSchema, EnvironmentRoleSchema, EnvironmentStatusSchema, EnvironmentTypeSchema, EnvironmentVisibilitySchema, ProvisionEnvironmentRequestSchema, ProvisionEnvironmentResponseSchema, ProvisionOrganizationRequestSchema, ProvisionOrganizationResponseSchema } from '@objectstack/spec/cloud'; -import type { Environment, EnvironmentCredential, EnvironmentCredentialStatus, EnvironmentDriver, EnvironmentMember, EnvironmentRole, EnvironmentStatus, EnvironmentType, EnvironmentVisibility, ProvisionEnvironmentRequest, ProvisionEnvironmentResponse, ProvisionOrganizationRequest, ProvisionOrganizationResponse } from '@objectstack/spec/cloud'; - -// Validate data -const result = EnvironmentSchema.parse(data); -``` - ---- - -## Environment - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | UUID of the environment (stable, never reused) | -| **organizationId** | `string` | ✅ | Organization that owns this environment | -| **displayName** | `string` | ✅ | Display name shown in Studio and APIs | -| **isDefault** | `boolean` | optional (default: `false`) | Whether this is the default environment for the organization | -| **isSystem** | `boolean` | optional (default: `false`) | Whether this is a system environment (platform infrastructure, not user data) | -| **plan** | `string` | optional (default: `"free"`) | Plan tier for this environment | -| **status** | `Enum<'provisioning' \| 'active' \| 'suspended' \| 'archived' \| 'failed' \| 'migrating'>` | optional (default: `"provisioning"`) | Environment lifecycle status | -| **createdBy** | `string` | ✅ | User ID that created the environment | -| **createdAt** | `string` | ✅ | Creation timestamp (ISO-8601) | -| **updatedAt** | `string` | ✅ | Last update timestamp (ISO-8601) | -| **databaseUrl** | `string` | optional | Full connection URL for the environment database | -| **databaseDriver** | `string` | optional | Data-plane driver key (turso, libsql, sqlite, memory, postgres) | -| **storageLimitMb** | `integer` | optional | Storage quota in megabytes | -| **provisionedAt** | `string` | optional | Provisioning timestamp (ISO-8601) | -| **metadata** | `Record` | optional | Free-form metadata | -| **hostname** | `string` | optional | Canonical hostname for this environment. UNIQUE. Auto-set on creation; can be overridden for custom domains. | -| **consoleUrl** | `string` | optional | Pre-computed admin Console URL for this environment | -| **apiBaseUrl** | `string` | optional | Pre-computed REST API base URL for this environment | -| **visibility** | `Enum<'private' \| 'unlisted' \| 'public'>` | optional (default: `"private"`) | Public exposure of this environment artifacts (private \| unlisted \| public). | - - ---- - -## EnvironmentCredential - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | UUID of the credential | -| **environmentId** | `string` | ✅ | Environment this credential authorizes | -| **secretCiphertext** | `string` | ✅ | Encrypted auth token or secret (ciphertext) | -| **encryptionKeyId** | `string` | ✅ | Encryption key ID used to encrypt the secret | -| **authorization** | `Enum<'full_access' \| 'read_only'>` | optional (default: `"full_access"`) | Authorization scope for this credential | -| **status** | `Enum<'active' \| 'rotating' \| 'revoked'>` | optional (default: `"active"`) | Credential lifecycle status | -| **createdAt** | `string` | ✅ | Creation timestamp (ISO-8601) | -| **expiresAt** | `string` | optional | Optional expiry timestamp | -| **revokedAt** | `string` | optional | Revocation timestamp (if revoked) | - - ---- - -## EnvironmentCredentialStatus - -Credential lifecycle status - -### Allowed Values - -* `active` -* `rotating` -* `revoked` - - ---- - -## EnvironmentDriver - -Data-plane driver key (e.g. `turso`, `libsql`, `sqlite`, `postgres`) - -**Type:** `string` - - ---- - -## EnvironmentMember - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | UUID of the membership | -| **environmentId** | `string` | ✅ | Environment this membership grants access to | -| **userId** | `string` | ✅ | User ID | -| **role** | `Enum<'owner' \| 'admin' \| 'maker' \| 'reader' \| 'guest'>` | ✅ | Per-environment role | -| **invitedBy** | `string` | ✅ | User ID that granted this membership | -| **createdAt** | `string` | ✅ | Creation timestamp (ISO-8601) | -| **updatedAt** | `string` | ✅ | Last update timestamp (ISO-8601) | - - ---- - -## EnvironmentRole - -Per-environment role - -### Allowed Values - -* `owner` -* `admin` -* `maker` -* `reader` -* `guest` - - ---- - -## EnvironmentStatus - -Environment lifecycle status - -### Allowed Values - -* `provisioning` -* `active` -* `suspended` -* `archived` -* `failed` -* `migrating` - - ---- - -## EnvironmentType - -Environment categorical tag (prod/sandbox/dev/test/…) - -### Allowed Values - -* `production` -* `sandbox` -* `development` -* `test` -* `staging` -* `preview` -* `trial` - - ---- - -## EnvironmentVisibility - -Public exposure of this environment artifacts (private | unlisted | public). - -### Allowed Values - -* `private` -* `unlisted` -* `public` - - ---- - -## ProvisionEnvironmentRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **organizationId** | `string` | ✅ | Organization that will own the new environment | -| **displayName** | `string` | ✅ | Display name shown in Studio and APIs | -| **driver** | `string` | optional | Driver key (defaults to provisioning service config) | -| **plan** | `string` | optional | Plan tier | -| **storageLimitMb** | `integer` | optional | Storage quota in megabytes | -| **isDefault** | `boolean` | optional | Mark as the organization default environment | -| **createdBy** | `string` | ✅ | User ID that initiated the provisioning | -| **metadata** | `Record` | optional | Free-form metadata | -| **hostname** | `string` | optional | Canonical hostname (auto-generated if omitted) | -| **templateId** | `string` | optional | Starter package to seed into the new environment on first provisioning (e.g. "crm", "todo"). Defaults to "blank". | -| **visibility** | `Enum<'private' \| 'unlisted' \| 'public'>` | optional (default: `"private"`) | Public exposure of this environment artifacts. private = auth required for every read (default); unlisted = downloadable when commit id is known; public = listed and freely downloadable via /pub/v1/environments/:id/*. | - - ---- - -## ProvisionEnvironmentResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **environment** | `{ id: string; organizationId: string; displayName: string; isDefault: boolean; … }` | ✅ | Provisioned environment (includes database addressing) | -| **credential** | `{ id: string; environmentId: string; secretCiphertext: string; encryptionKeyId: string; … }` | ✅ | Freshly-minted credential for the environment DB | -| **durationMs** | `number` | ✅ | Total provisioning duration in milliseconds | -| **warnings** | `string[]` | optional | Non-fatal warnings emitted during provisioning | -| **hostnameAssignment** | `{ requestedHostname: string; assignedHostname: string }` | optional | Populated ONLY when the control plane auto-renamed the requested hostname to avoid a collision. Absent means the requested hostname was assigned unchanged — never read absence as "unknown". | - -### Nested Shape: `ProvisionEnvironmentResponse.environment` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | UUID of the environment (stable, never reused) | -| **organizationId** | `string` | ✅ | Organization that owns this environment | -| **displayName** | `string` | ✅ | Display name shown in Studio and APIs | -| **isDefault** | `boolean` | optional (default: `false`) | Whether this is the default environment for the organization | -| **isSystem** | `boolean` | optional (default: `false`) | Whether this is a system environment (platform infrastructure, not user data) | -| **plan** | `string` | optional (default: `"free"`) | Plan tier for this environment | -| **status** | `Enum<'provisioning' \| 'active' \| 'suspended' \| 'archived' \| 'failed' \| 'migrating'>` | optional (default: `"provisioning"`) | Environment lifecycle status | -| **createdBy** | `string` | ✅ | User ID that created the environment | -| **createdAt** | `string` | ✅ | Creation timestamp (ISO-8601) | -| **updatedAt** | `string` | ✅ | Last update timestamp (ISO-8601) | -| **databaseUrl** | `string` | optional | Full connection URL for the environment database | -| **databaseDriver** | `string` | optional | Data-plane driver key (turso, libsql, sqlite, memory, postgres) | -| **storageLimitMb** | `integer` | optional | Storage quota in megabytes | -| **provisionedAt** | `string` | optional | Provisioning timestamp (ISO-8601) | -| **metadata** | `Record` | optional | Free-form metadata | -| **hostname** | `string` | optional | Canonical hostname for this environment. UNIQUE. Auto-set on creation; can be overridden for custom domains. | -| **consoleUrl** | `string` | optional | Pre-computed admin Console URL for this environment | -| **apiBaseUrl** | `string` | optional | Pre-computed REST API base URL for this environment | -| **visibility** | `Enum<'private' \| 'unlisted' \| 'public'>` | optional (default: `"private"`) | Public exposure of this environment artifacts (private \| unlisted \| public). | - -### Nested Shape: `ProvisionEnvironmentResponse.credential` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | UUID of the credential | -| **environmentId** | `string` | ✅ | Environment this credential authorizes | -| **secretCiphertext** | `string` | ✅ | Encrypted auth token or secret (ciphertext) | -| **encryptionKeyId** | `string` | ✅ | Encryption key ID used to encrypt the secret | -| **authorization** | `Enum<'full_access' \| 'read_only'>` | optional (default: `"full_access"`) | Authorization scope for this credential | -| **status** | `Enum<'active' \| 'rotating' \| 'revoked'>` | optional (default: `"active"`) | Credential lifecycle status | -| **createdAt** | `string` | ✅ | Creation timestamp (ISO-8601) | -| **expiresAt** | `string` | optional | Optional expiry timestamp | -| **revokedAt** | `string` | optional | Revocation timestamp (if revoked) | - -### Nested Shape: `ProvisionEnvironmentResponse.hostnameAssignment` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **requestedHostname** | `string` | ✅ | Hostname the caller asked for (explicitly, or as auto-derived from displayName) | -| **assignedHostname** | `string` | ✅ | Hostname actually assigned after the collision-avoiding rename; equals `environment.hostname` | - - ---- - -## ProvisionOrganizationRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **organizationId** | `string` | ✅ | Organization being bootstrapped | -| **defaultEnvironmentDisplayName** | `string` | optional (default: `"Production"`) | Display name for the default environment | -| **driver** | `string` | optional | Driver key | -| **plan** | `string` | optional | Plan tier | -| **storageLimitMb** | `integer` | optional | Storage quota in megabytes | -| **createdBy** | `string` | ✅ | User ID that initiated provisioning | -| **metadata** | `Record` | optional | Free-form metadata | - - ---- - -## ProvisionOrganizationResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **defaultEnvironment** | `{ environment: object; credential: object; durationMs: number; warnings?: string[]; … }` | ✅ | Default environment that was created | -| **durationMs** | `number` | ✅ | Total bootstrap duration in milliseconds | -| **warnings** | `string[]` | optional | Non-fatal warnings | - -### Nested Shape: `ProvisionOrganizationResponse.defaultEnvironment` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **environment** | `{ id: string; organizationId: string; displayName: string; isDefault: boolean; … }` | ✅ | Provisioned environment (includes database addressing) | -| **credential** | `{ id: string; environmentId: string; secretCiphertext: string; encryptionKeyId: string; … }` | ✅ | Freshly-minted credential for the environment DB | -| **durationMs** | `number` | ✅ | Total provisioning duration in milliseconds | -| **warnings** | `string[]` | optional | Non-fatal warnings emitted during provisioning | -| **hostnameAssignment** | `{ requestedHostname: string; assignedHostname: string }` | optional | Populated ONLY when the control plane auto-renamed the requested hostname to avoid a collision. Absent means the requested hostname was assigned unchanged — never read absence as "unknown". | - - ---- - diff --git a/content/docs/references/cloud/index.mdx b/content/docs/references/cloud/index.mdx deleted file mode 100644 index d93e7744b9..0000000000 --- a/content/docs/references/cloud/index.mdx +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Cloud Protocol -description: Complete reference for all cloud protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -This section contains all protocol schemas for the cloud layer of ObjectStack. - - - - - - - - - - - - - - diff --git a/content/docs/references/cloud/marketplace-admin.mdx b/content/docs/references/cloud/marketplace-admin.mdx deleted file mode 100644 index a96fbee061..0000000000 --- a/content/docs/references/cloud/marketplace-admin.mdx +++ /dev/null @@ -1,220 +0,0 @@ ---- -title: Marketplace Admin -description: Marketplace Admin protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -## Marketplace Administration Protocol - -Defines schemas for the platform (Cloud) side of marketplace operations. -Covers the administrative workflows for managing and governing the marketplace. - -### Architecture Alignment -- **Salesforce AppExchange Admin**: Security review, ISV monitoring, partner management -- **Apple App Store Connect Review**: Human review process, guidelines, rejection reasons -- **Google Play Console**: Policy enforcement, quality gates, content moderation - -### Key Concepts -- **Review Process**: Structured workflow for submission review (automated + manual) -- **Curation**: Featured apps, curated collections, editorial picks -- **Governance**: Policy enforcement, takedown, compliance -- **Platform Analytics**: Marketplace health, trending, abuse detection - - -**Source:** `packages/spec/src/cloud/marketplace-admin.zod.ts` - - -## TypeScript Usage - -```typescript -import { CuratedCollectionSchema, FeaturedListingSchema, MarketplaceHealthMetricsSchema, PolicyActionSchema, PolicyViolationTypeSchema, RejectionReasonSchema, ReviewCriterionSchema, ReviewDecisionSchema, SubmissionReviewSchema, TrendingListingSchema } from '@objectstack/spec/cloud'; -import type { CuratedCollection, FeaturedListing, MarketplaceHealthMetrics, PolicyAction, PolicyViolationType, RejectionReason, ReviewCriterion, ReviewDecision, SubmissionReview, TrendingListing } from '@objectstack/spec/cloud'; - -// Validate data -const result = CuratedCollectionSchema.parse(data); -``` - ---- - -## CuratedCollection - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Collection ID | -| **name** | `string` | ✅ | Collection name | -| **description** | `string` | optional | | -| **coverImageUrl** | `string` | optional | | -| **listingIds** | `string[]` | ✅ | Ordered listing IDs | -| **published** | `boolean` | optional (default: `false`) | | -| **sortOrder** | `integer` | optional (default: `0`) | | -| **createdBy** | `string` | optional | | -| **createdAt** | `string` | optional | | -| **updatedAt** | `string` | optional | | - - ---- - -## FeaturedListing - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | Featured listing ID | -| **priority** | `integer` | optional (default: `0`) | | -| **bannerUrl** | `string` | optional | | -| **editorialNote** | `string` | optional | | -| **startDate** | `string` | ✅ | | -| **endDate** | `string` | optional | | -| **active** | `boolean` | optional (default: `true`) | | - - ---- - -## MarketplaceHealthMetrics - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **totalListings** | `integer` | ✅ | | -| **listingsByStatus** | `Record` | optional | | -| **listingsByCategory** | `Record` | optional | | -| **totalPublishers** | `integer` | ✅ | | -| **verifiedPublishers** | `integer` | ✅ | | -| **totalInstalls** | `integer` | ✅ | | -| **averageReviewTime** | `number` | optional | | -| **pendingReviews** | `integer` | ✅ | | -| **listingsByPricing** | `Record` | optional | | -| **snapshotAt** | `string` | ✅ | | - - ---- - -## PolicyAction - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Action ID | -| **listingId** | `string` | ✅ | Target listing ID | -| **violationType** | `Enum<'malware' \| 'data-harvesting' \| 'spam' \| 'copyright' \| 'inappropriate-content' \| 'terms-of-service' \| 'security-risk' \| 'abandoned'>` | ✅ | | -| **action** | `Enum<'warning' \| 'suspend' \| 'takedown' \| 'restrict'>` | ✅ | | -| **reason** | `string` | ✅ | Explanation of the violation | -| **actionBy** | `string` | ✅ | Admin user ID | -| **actionAt** | `string` | ✅ | | -| **resolution** | `string` | optional | | -| **resolved** | `boolean` | optional (default: `false`) | | - - ---- - -## PolicyViolationType - -### Allowed Values - -* `malware` -* `data-harvesting` -* `spam` -* `copyright` -* `inappropriate-content` -* `terms-of-service` -* `security-risk` -* `abandoned` - - ---- - -## RejectionReason - -### Allowed Values - -* `security-vulnerability` -* `policy-violation` -* `quality-below-standard` -* `misleading-metadata` -* `incompatible` -* `duplicate` -* `insufficient-documentation` -* `other` - - ---- - -## ReviewCriterion - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Criterion ID | -| **category** | `Enum<'security' \| 'performance' \| 'quality' \| 'ux' \| 'documentation' \| 'policy' \| 'compatibility'>` | ✅ | | -| **description** | `string` | ✅ | | -| **required** | `boolean` | optional (default: `true`) | | -| **passed** | `boolean` | optional | | -| **notes** | `string` | optional | | - - ---- - -## ReviewDecision - -### Allowed Values - -* `approved` -* `rejected` -* `changes-requested` - - ---- - -## SubmissionReview - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Review ID | -| **submissionId** | `string` | ✅ | Submission being reviewed | -| **reviewerId** | `string` | ✅ | Platform reviewer ID | -| **decision** | `Enum<'approved' \| 'rejected' \| 'changes-requested'>` | optional | Final decision | -| **criteria** | `{ id: string; category: Enum<'security' \| 'performance' \| 'quality' \| 'ux' \| 'documentation' \| 'policy' \| 'compatibility'>; description: string; required: boolean; … }[]` | optional | Review checklist results | -| **rejectionReasons** | `Enum<'security-vulnerability' \| 'policy-violation' \| 'quality-below-standard' \| 'misleading-metadata' \| 'incompatible' \| 'duplicate' \| 'insufficient-documentation' \| 'other'>[]` | optional | | -| **feedback** | `string` | optional | Detailed review feedback (Markdown) | -| **internalNotes** | `string` | optional | Internal reviewer notes | -| **startedAt** | `string` | optional | | -| **completedAt** | `string` | optional | | - -### Nested Shape: `SubmissionReview.criteria[number]` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Criterion ID | -| **category** | `Enum<'security' \| 'performance' \| 'quality' \| 'ux' \| 'documentation' \| 'policy' \| 'compatibility'>` | ✅ | | -| **description** | `string` | ✅ | | -| **required** | `boolean` | optional (default: `true`) | | -| **passed** | `boolean` | optional | | -| **notes** | `string` | optional | | - - ---- - -## TrendingListing - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **listingId** | `string` | ✅ | | -| **rank** | `integer` | ✅ | | -| **trendScore** | `number` | ✅ | | -| **installVelocity** | `number` | ✅ | | -| **period** | `string` | ✅ | | - - ---- - diff --git a/content/docs/references/cloud/meta.json b/content/docs/references/cloud/meta.json deleted file mode 100644 index 589077dc52..0000000000 --- a/content/docs/references/cloud/meta.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "title": "Cloud Protocol", - "pages": [ - "---Environments & Packages---", - "environment", - "environment-artifact", - "environment-package", - "package", - "package-version", - "template-manifest", - "---Marketplace & Distribution---", - "app-store", - "developer-portal", - "marketplace", - "marketplace-admin", - "---Tenancy & Security---", - "tenant" - ] -} \ No newline at end of file diff --git a/content/docs/references/cloud/tenant.mdx b/content/docs/references/cloud/tenant.mdx deleted file mode 100644 index 6aaf6e8873..0000000000 --- a/content/docs/references/cloud/tenant.mdx +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: Tenant -description: Tenant protocol schemas ---- - -{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} - -Multi-Tenant Architecture Schema - -Defines the schema for managing multi-tenant architecture with: -- Global control plane: Single database for auth, org management, tenant registry -- Tenant data plane: Isolated databases per organization (UUID-based naming) - -Design decisions: -- Database naming: \{uuid\}.turso.io (not org-slug, since slugs can be modified) -- Each tenant has its own Turso database for complete data isolation -- Global database stores user auth, organizations, and tenant metadata - - -**Source:** `packages/spec/src/cloud/tenant.zod.ts` - - -## TypeScript Usage - -```typescript -import { PackageInstallationSchema, PackageInstallationStatusSchema, ProvisionTenantRequestSchema, ProvisionTenantResponseSchema, TenantContextSchema, TenantDatabaseSchema, TenantDatabaseStatusSchema, TenantIdentificationSourceSchema, TenantPlanSchema, TenantRoutingConfigSchema } from '@objectstack/spec/cloud'; -import type { PackageInstallation, PackageInstallationStatus, ProvisionTenantRequest, ProvisionTenantResponse, TenantContext, TenantDatabase, TenantDatabaseStatus, TenantIdentificationSource, TenantPlan, TenantRoutingConfig } from '@objectstack/spec/cloud'; - -// Validate data -const result = PackageInstallationSchema.parse(data); -``` - ---- - -## PackageInstallation - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique installation identifier | -| **tenantId** | `string` | ✅ | Tenant database ID | -| **packageId** | `string` | ✅ | Package identifier | -| **version** | `string` | ✅ | Installed package version | -| **status** | `Enum<'installing' \| 'active' \| 'disabled' \| 'uninstalling' \| 'failed'>` | optional (default: `"installing"`) | Installation status | -| **installedAt** | `string` | ✅ | Installation timestamp | -| **installedBy** | `string` | ✅ | User ID who installed the package | -| **config** | `Record` | optional | Package-specific configuration | -| **updatedAt** | `string` | ✅ | Last update timestamp | - - ---- - -## PackageInstallationStatus - -### Allowed Values - -* `installing` -* `active` -* `disabled` -* `uninstalling` -* `failed` - - ---- - -## ProvisionTenantRequest - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **organizationId** | `string` | ✅ | Organization ID | -| **region** | `string` | optional | Deployment region preference | -| **plan** | `string` | optional (default: `"free"`) | Tenant plan tier | -| **storageLimitMb** | `integer` | optional | Storage limit in megabytes | -| **metadata** | `Record` | optional | Custom tenant metadata | - - ---- - -## ProvisionTenantResponse - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **tenant** | `{ id: string; organizationId: string; databaseName: string; databaseUrl: string; … }` | ✅ | Provisioned tenant database | -| **durationMs** | `number` | ✅ | Provisioning duration in milliseconds | -| **warnings** | `string[]` | optional | Provisioning warnings | - -### Nested Shape: `ProvisionTenantResponse.tenant` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique tenant database identifier (UUID) | -| **organizationId** | `string` | ✅ | Organization ID (foreign key to sys_organization) | -| **databaseName** | `string` | ✅ | Database name (UUID-based) | -| **databaseUrl** | `string` | ✅ | Full database URL | -| **authToken** | `string` | ✅ | Encrypted tenant-specific auth token | -| **status** | `Enum<'provisioning' \| 'active' \| 'suspended' \| 'archived' \| 'failed'>` | optional (default: `"provisioning"`) | Database status | -| **region** | `string` | ✅ | Deployment region | -| **plan** | `string` | optional (default: `"free"`) | Tenant plan tier | -| **storageLimitMb** | `integer` | ✅ | Storage limit in megabytes | -| **createdAt** | `string` | ✅ | Database creation timestamp | -| **updatedAt** | `string` | ✅ | Last update timestamp | -| **lastAccessedAt** | `string` | optional | Last accessed timestamp | -| **metadata** | `Record` | optional | Custom tenant configuration | - - ---- - -## TenantContext - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **tenantId** | `string` | ✅ | Current tenant database ID | -| **organizationId** | `string` | ✅ | Current organization ID | -| **organizationSlug** | `string` | optional | Organization slug | -| **databaseUrl** | `string` | ✅ | Tenant database URL | -| **plan** | `string` | ✅ | Tenant plan tier | -| **metadata** | `Record` | optional | Custom tenant metadata | - - ---- - -## TenantDatabase - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **id** | `string` | ✅ | Unique tenant database identifier (UUID) | -| **organizationId** | `string` | ✅ | Organization ID (foreign key to sys_organization) | -| **databaseName** | `string` | ✅ | Database name (UUID-based) | -| **databaseUrl** | `string` | ✅ | Full database URL | -| **authToken** | `string` | ✅ | Encrypted tenant-specific auth token | -| **status** | `Enum<'provisioning' \| 'active' \| 'suspended' \| 'archived' \| 'failed'>` | optional (default: `"provisioning"`) | Database status | -| **region** | `string` | ✅ | Deployment region | -| **plan** | `string` | optional (default: `"free"`) | Tenant plan tier | -| **storageLimitMb** | `integer` | ✅ | Storage limit in megabytes | -| **createdAt** | `string` | ✅ | Database creation timestamp | -| **updatedAt** | `string` | ✅ | Last update timestamp | -| **lastAccessedAt** | `string` | optional | Last accessed timestamp | -| **metadata** | `Record` | optional | Custom tenant configuration | - - ---- - -## TenantDatabaseStatus - -### Allowed Values - -* `provisioning` -* `active` -* `suspended` -* `archived` -* `failed` - - ---- - -## TenantIdentificationSource - -### Allowed Values - -* `subdomain` -* `custom_domain` -* `header` -* `jwt_claim` -* `session` -* `default` - - ---- - -## TenantPlan - -Opaque plan/tier identifier. The vocabulary is control-plane config owned by the cloud distribution, not protocol — this schema accepts any string and does not enumerate valid values. Convention: an empty or unrecognized value is treated as the free tier by cloud-side readers (not enforced by this schema). - -**Type:** `string` - - ---- - -## TenantRoutingConfig - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **enabled** | `boolean` | optional (default: `false`) | Enable multi-tenant mode | -| **identificationSources** | `Enum<'subdomain' \| 'custom_domain' \| 'header' \| 'jwt_claim' \| 'session' \| 'default'>[]` | optional (default: `["subdomain","header","jwt_claim"]`) | Tenant identification strategy (in order of precedence) | -| **defaultTenantId** | `string` | optional | Default tenant ID | -| **subdomainPattern** | `string` | optional | Subdomain pattern for tenant extraction | -| **customDomainMapping** | `Record` | optional | Custom domain to tenant ID mapping | -| **tenantHeaderName** | `string` | optional (default: `"X-Tenant-ID"`) | Header name for tenant ID | -| **jwtOrganizationClaim** | `string` | optional (default: `"organizationId"`) | JWT claim name for organization ID | - - ---- - diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index 1baba330da..8d8694f35d 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 — 1583 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1520 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,20 +20,20 @@ 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) | 31 | 437 | REST contracts, endpoints, routing, realtime, batch, discovery. | +| [API Protocol](/docs/references/api) | 31 | 438 | REST contracts, endpoints, routing, realtime, batch, discovery. | | [Automation Protocol](/docs/references/automation) | 13 | 73 | 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 | 173 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | | [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. | | [Integration Protocol](/docs/references/integration) | 1 | 24 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. | | [Kernel Protocol](/docs/references/kernel) | 30 | 162 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | +| [Marketplace Protocol](/docs/references/marketplace) | 4 | 30 | The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests. | | [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. | | [Security Protocol](/docs/references/security) | 5 | 30 | Permission sets, row-level security, sharing rules, tenancy posture. | | [Shared Protocol](/docs/references/shared) | 9 | 29 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 33 | 272 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 153 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **198** | **1583** | 14 protocol modules | +| **Total** | **191** | **1520** | 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` · **31 pages, 437 schemas** +**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **31 pages, 438 schemas** REST contracts, endpoints, routing, realtime, batch, discovery. @@ -73,7 +73,7 @@ REST contracts, endpoints, routing, realtime, batch, discovery. | [`automation-api.zod.ts`](/docs/references/api/automation-api) | `AutomationApiErrorCode`, `AutomationFlowPathParams`, `AutomationRunPathParams`, `CreateFlowRequest`, `CreateFlowResponse`, `DeleteFlowRequest`, `DeleteFlowResponse`, `FlowSummary`, `GetFlowRequest`, `GetFlowResponse`, `GetRunRequest`, `GetRunResponse`, `ListFlowsRequest`, `ListFlowsResponse`, `ListRunsRequest`, `ListRunsResponse`, `ResumeFailureDetails`, `ToggleFlowRequest`, `ToggleFlowResponse`, `TriggerFlowRequest`, `TriggerFlowResponse`, `UpdateFlowRequest`, `UpdateFlowResponse` | | [`batch.zod.ts`](/docs/references/api/batch) | `BatchConfig`, `BatchOperationResult`, `BatchOperationType`, `BatchOptions`, `BatchRecord`, `BatchUpdateRequest`, `BatchUpdateResponse`, `CrossObjectBatchDroppedFields`, `CrossObjectBatchOperation`, `CrossObjectBatchRequest`, `CrossObjectBatchResponse`, `DeleteManyRequest`, `UpdateManyRecord`, `UpdateManyRequest` | | [`contract.zod.ts`](/docs/references/api/contract) | `ApiError`, `BaseResponse`, `BatchLoadingStrategy`, `BulkRequest`, `BulkResponse`, `CreateRequest`, `DataLoaderConfig`, `DeleteResponse`, `ExportRequest`, `IdRequest`, `ListRecordResponse`, `ModificationResult`, `QueryOptimizationConfig`, `RecordData`, `SingleRecordResponse`, `UpdateRequest` | -| [`discovery.zod.ts`](/docs/references/api/discovery) | `ApiRoutes`, `CapabilityDescriptor`, `Discovery`, `DiscoveryEnvironment`, `RouteHealthEntry`, `RouteHealthReport`, `ServiceInfo`, `ServiceSelfInfo`, `ServiceStatus`, `WellKnownCapabilities` | +| [`discovery.zod.ts`](/docs/references/api/discovery) | `ApiRoutes`, `CapabilityDescriptor`, `Discovery`, `DiscoveryEnvironment`, `EnvironmentType`, `RouteHealthEntry`, `RouteHealthReport`, `ServiceInfo`, `ServiceSelfInfo`, `ServiceStatus`, `WellKnownCapabilities` | | [`dispatcher.zod.ts`](/docs/references/api/dispatcher) | `DispatcherConfig`, `DispatcherErrorCode`, `DispatcherErrorResponse`, `DispatcherRoute` | | [`documentation.zod.ts`](/docs/references/api/documentation) | `ApiChangelogEntry`, `ApiDocumentationConfig`, `ApiTestCollection`, `ApiTestRequest`, `ApiTestingUiConfig`, `ApiTestingUiType`, `CodeGenerationTemplate`, `GeneratedApiDocumentation`, `OpenApiSecurityScheme`, `OpenApiServer`, `OpenApiSpec` | | [`endpoint.zod.ts`](/docs/references/api/endpoint) | `ApiEndpoint`, `ApiMapping` | @@ -125,28 +125,6 @@ Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execu --- -## Cloud Protocol - -**Source:** `packages/spec/src/cloud/` · **Import:** `@objectstack/spec/cloud` · **11 pages, 94 schemas** - -Environments, packages and versions, marketplace, developer portal, tenancy. - -| File | Schemas | -| :--- | :--- | -| [`app-store.zod.ts`](/docs/references/cloud/app-store) | `AppDiscoveryRequest`, `AppDiscoveryResponse`, `AppSubscription`, `InstalledAppSummary`, `ListInstalledAppsRequest`, `ListInstalledAppsResponse`, `ListReviewsRequest`, `ListReviewsResponse`, `RecommendationReason`, `RecommendedApp`, `ReviewModerationStatus`, `SubmitReviewRequest`, `SubscriptionStatus`, `UserReview` | -| [`developer-portal.zod.ts`](/docs/references/cloud/developer-portal) | `AnalyticsTimeRange`, `CreateListingRequest`, `ListingActionRequest`, `PublisherProfile`, `PublishingAnalyticsRequest`, `PublishingAnalyticsResponse`, `ReleaseChannel`, `TimeSeriesPoint`, `UpdateListingRequest`, `VersionRelease` | -| [`environment.zod.ts`](/docs/references/cloud/environment) | `Environment`, `EnvironmentCredential`, `EnvironmentCredentialStatus`, `EnvironmentDriver`, `EnvironmentMember`, `EnvironmentRole`, `EnvironmentStatus`, `EnvironmentType`, `EnvironmentVisibility`, `ProvisionEnvironmentRequest`, `ProvisionEnvironmentResponse`, `ProvisionOrganizationRequest`, `ProvisionOrganizationResponse` | -| [`environment-artifact.zod.ts`](/docs/references/cloud/environment-artifact) | `Sha256Digest` | -| [`environment-package.zod.ts`](/docs/references/cloud/environment-package) | `EnvironmentPackageInstallation`, `EnvironmentPackageStatus`, `InstallPackageToEnvironmentRequest`, `ListEnvironmentPackagesResponse`, `RollbackEnvironmentPackageRequest`, `UpgradeEnvironmentPackageRequest` | -| [`marketplace.zod.ts`](/docs/references/cloud/marketplace) | `ArtifactDownloadResponse`, `ArtifactReference`, `ListingStatus`, `MarketplaceCategory`, `MarketplaceInstallRequest`, `MarketplaceInstallResponse`, `MarketplaceListing`, `MarketplaceSearchRequest`, `MarketplaceSearchResponse`, `PackageSubmission`, `PricingModel`, `Publisher`, `PublisherVerification` | -| [`marketplace-admin.zod.ts`](/docs/references/cloud/marketplace-admin) | `CuratedCollection`, `FeaturedListing`, `MarketplaceHealthMetrics`, `PolicyAction`, `PolicyViolationType`, `RejectionReason`, `ReviewCriterion`, `ReviewDecision`, `SubmissionReview`, `TrendingListing` | -| [`package.zod.ts`](/docs/references/cloud/package) | `CreatePackageRequest`, `Package`, `PackageCategory`, `PackageLocale`, `PackagePublisher`, `PackageTranslation`, `PackageTranslations`, `PackageVisibility`, `UpdatePackageRequest` | -| [`package-version.zod.ts`](/docs/references/cloud/package-version) | `CreatePackageVersionRequest`, `PackageDependency`, `PackageManifest`, `PackageVersion`, `PackageVersionStatus`, `PublishPackageVersionRequest`, `UpdatePackageVersionRequest` | -| [`template-manifest.zod.ts`](/docs/references/cloud/template-manifest) | `TemplateManifest` | -| [`tenant.zod.ts`](/docs/references/cloud/tenant) | `PackageInstallation`, `PackageInstallationStatus`, `ProvisionTenantRequest`, `ProvisionTenantResponse`, `TenantContext`, `TenantDatabase`, `TenantDatabaseStatus`, `TenantIdentificationSource`, `TenantPlan`, `TenantRoutingConfig` | - ---- - ## Data Protocol **Source:** `packages/spec/src/data/` · **Import:** `@objectstack/spec/data` · **29 pages, 173 schemas** @@ -256,6 +234,21 @@ Plugin lifecycle and manifests, capabilities and security, metadata loading, ser --- +## Marketplace Protocol + +**Source:** `packages/spec/src/marketplace/` · **Import:** `@objectstack/spec/marketplace` · **4 pages, 30 schemas** + +The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests. + +| File | Schemas | +| :--- | :--- | +| [`marketplace.zod.ts`](/docs/references/marketplace/marketplace) | `ArtifactDownloadResponse`, `ArtifactReference`, `ListingStatus`, `MarketplaceCategory`, `MarketplaceInstallRequest`, `MarketplaceInstallResponse`, `MarketplaceListing`, `MarketplaceSearchRequest`, `MarketplaceSearchResponse`, `PackageSubmission`, `PricingModel`, `Publisher`, `PublisherVerification` | +| [`package.zod.ts`](/docs/references/marketplace/package) | `CreatePackageRequest`, `Package`, `PackageCategory`, `PackageLocale`, `PackagePublisher`, `PackageTranslation`, `PackageTranslations`, `PackageVisibility`, `UpdatePackageRequest` | +| [`package-version.zod.ts`](/docs/references/marketplace/package-version) | `CreatePackageVersionRequest`, `PackageDependency`, `PackageManifest`, `PackageVersion`, `PackageVersionStatus`, `PublishPackageVersionRequest`, `UpdatePackageVersionRequest` | +| [`template-manifest.zod.ts`](/docs/references/marketplace/template-manifest) | `TemplateManifest` | + +--- + ## QA Protocol **Source:** `packages/spec/src/qa/` · **Import:** `@objectstack/spec/qa` · **1 page, 8 schemas** diff --git a/content/docs/references/marketplace/index.mdx b/content/docs/references/marketplace/index.mdx new file mode 100644 index 0000000000..80df67276d --- /dev/null +++ b/content/docs/references/marketplace/index.mdx @@ -0,0 +1,15 @@ +--- +title: Marketplace Protocol +description: Complete reference for all marketplace protocol schemas +--- + +{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} + +This section contains all protocol schemas for the marketplace layer of ObjectStack. + + + + + + + diff --git a/content/docs/references/cloud/marketplace.mdx b/content/docs/references/marketplace/marketplace.mdx similarity index 99% rename from content/docs/references/cloud/marketplace.mdx rename to content/docs/references/marketplace/marketplace.mdx index 4e633feacf..f7146f815a 100644 --- a/content/docs/references/cloud/marketplace.mdx +++ b/content/docs/references/marketplace/marketplace.mdx @@ -40,14 +40,14 @@ platform, and customers who install plugins. ``` -**Source:** `packages/spec/src/cloud/marketplace.zod.ts` +**Source:** `packages/spec/src/marketplace/marketplace.zod.ts` ## TypeScript Usage ```typescript -import { ArtifactDownloadResponseSchema, ArtifactReferenceSchema, ListingStatusSchema, MarketplaceCategorySchema, MarketplaceInstallRequestSchema, MarketplaceInstallResponseSchema, MarketplaceListingSchema, MarketplaceSearchRequestSchema, MarketplaceSearchResponseSchema, PackageSubmissionSchema, PricingModelSchema, PublisherSchema, PublisherVerificationSchema } from '@objectstack/spec/cloud'; -import type { ArtifactDownloadResponse, ArtifactReference, ListingStatus, MarketplaceCategory, MarketplaceInstallRequest, MarketplaceInstallResponse, MarketplaceListing, MarketplaceSearchRequest, MarketplaceSearchResponse, PackageSubmission, PricingModel, Publisher, PublisherVerification } from '@objectstack/spec/cloud'; +import { ArtifactDownloadResponseSchema, ArtifactReferenceSchema, ListingStatusSchema, MarketplaceCategorySchema, MarketplaceInstallRequestSchema, MarketplaceInstallResponseSchema, MarketplaceListingSchema, MarketplaceSearchRequestSchema, MarketplaceSearchResponseSchema, PackageSubmissionSchema, PricingModelSchema, PublisherSchema, PublisherVerificationSchema } from '@objectstack/spec/marketplace'; +import type { ArtifactDownloadResponse, ArtifactReference, ListingStatus, MarketplaceCategory, MarketplaceInstallRequest, MarketplaceInstallResponse, MarketplaceListing, MarketplaceSearchRequest, MarketplaceSearchResponse, PackageSubmission, PricingModel, Publisher, PublisherVerification } from '@objectstack/spec/marketplace'; // Validate data const result = ArtifactDownloadResponseSchema.parse(data); diff --git a/content/docs/references/marketplace/meta.json b/content/docs/references/marketplace/meta.json new file mode 100644 index 0000000000..57bd5c1825 --- /dev/null +++ b/content/docs/references/marketplace/meta.json @@ -0,0 +1,11 @@ +{ + "title": "Marketplace Protocol", + "pages": [ + "---Packages & Versions---", + "package", + "package-version", + "template-manifest", + "---Marketplace---", + "marketplace" + ] +} \ No newline at end of file diff --git a/content/docs/references/cloud/package-version.mdx b/content/docs/references/marketplace/package-version.mdx similarity index 97% rename from content/docs/references/cloud/package-version.mdx rename to content/docs/references/marketplace/package-version.mdx index d3a4480432..ba4d6134a5 100644 --- a/content/docs/references/cloud/package-version.mdx +++ b/content/docs/references/marketplace/package-version.mdx @@ -20,14 +20,14 @@ specific `sys_package_version` UUID. Upgrading swaps that pointer atomically. See `docs/adr/0003-package-as-first-class-citizen.md` for the full rationale. -**Source:** `packages/spec/src/cloud/package-version.zod.ts` +**Source:** `packages/spec/src/marketplace/package-version.zod.ts` ## TypeScript Usage ```typescript -import { CreatePackageVersionRequestSchema, PackageDependencySchema, PackageManifestSchema, PackageVersionSchema, PackageVersionStatusSchema, PublishPackageVersionRequestSchema, UpdatePackageVersionRequestSchema } from '@objectstack/spec/cloud'; -import type { CreatePackageVersionRequest, PackageDependency, PackageManifest, PackageVersion, PackageVersionStatus, PublishPackageVersionRequest, UpdatePackageVersionRequest } from '@objectstack/spec/cloud'; +import { CreatePackageVersionRequestSchema, PackageDependencySchema, PackageManifestSchema, PackageVersionSchema, PackageVersionStatusSchema, PublishPackageVersionRequestSchema, UpdatePackageVersionRequestSchema } from '@objectstack/spec/marketplace'; +import type { CreatePackageVersionRequest, PackageDependency, PackageManifest, PackageVersion, PackageVersionStatus, PublishPackageVersionRequest, UpdatePackageVersionRequest } from '@objectstack/spec/marketplace'; // Validate data const result = CreatePackageVersionRequestSchema.parse(data); diff --git a/content/docs/references/cloud/package.mdx b/content/docs/references/marketplace/package.mdx similarity index 95% rename from content/docs/references/cloud/package.mdx rename to content/docs/references/marketplace/package.mdx index 0b51a92958..fc6a468366 100644 --- a/content/docs/references/cloud/package.mdx +++ b/content/docs/references/marketplace/package.mdx @@ -14,20 +14,22 @@ flows, translations, agents — into a named, versioned artifact. Architecture: - `sys_package` — identity (one row per logical package) -- `sys_package_version` — immutable release snapshots (see [package-version.zod.ts](/docs/references/cloud/package-version)) -- `sys_package_installation` — env ↔ version pairing (see [environment-package.zod.ts](/docs/references/cloud/environment-package)) +- `sys_package_version` — immutable release snapshots (see [package-version.zod.ts](/docs/references/marketplace/package-version)) +- `sys_package_installation` — env ↔ version pairing; a cloud control-plane row, + declared in the cloud repo since #16325 (it left `@objectstack/spec` with the + `./cloud` subpath) See `docs/adr/0003-package-as-first-class-citizen.md` for the full rationale. -**Source:** `packages/spec/src/cloud/package.zod.ts` +**Source:** `packages/spec/src/marketplace/package.zod.ts` ## TypeScript Usage ```typescript -import { CreatePackageRequestSchema, PackageSchema, PackageCategorySchema, PackageLocaleSchema, PackagePublisherSchema, PackageTranslationSchema, PackageTranslationsSchema, PackageVisibilitySchema, UpdatePackageRequestSchema } from '@objectstack/spec/cloud'; -import type { CreatePackageRequest, Package, PackageCategory, PackageLocale, PackagePublisher, PackageTranslation, PackageTranslations, PackageVisibility, UpdatePackageRequest } from '@objectstack/spec/cloud'; +import { CreatePackageRequestSchema, PackageSchema, PackageCategorySchema, PackageLocaleSchema, PackagePublisherSchema, PackageTranslationSchema, PackageTranslationsSchema, PackageVisibilitySchema, UpdatePackageRequestSchema } from '@objectstack/spec/marketplace'; +import type { CreatePackageRequest, Package, PackageCategory, PackageLocale, PackagePublisher, PackageTranslation, PackageTranslations, PackageVisibility, UpdatePackageRequest } from '@objectstack/spec/marketplace'; // Validate data const result = CreatePackageRequestSchema.parse(data); diff --git a/content/docs/references/cloud/template-manifest.mdx b/content/docs/references/marketplace/template-manifest.mdx similarity index 94% rename from content/docs/references/cloud/template-manifest.mdx rename to content/docs/references/marketplace/template-manifest.mdx index 3ba9f63eda..0d8390c6cd 100644 --- a/content/docs/references/cloud/template-manifest.mdx +++ b/content/docs/references/marketplace/template-manifest.mdx @@ -18,14 +18,14 @@ Every shipped `objectstack.manifest.json` is parsed against this schema by assertion nothing reads. -**Source:** `packages/spec/src/cloud/template-manifest.zod.ts` +**Source:** `packages/spec/src/marketplace/template-manifest.zod.ts` ## TypeScript Usage ```typescript -import { TemplateManifestSchema } from '@objectstack/spec/cloud'; -import type { TemplateManifest } from '@objectstack/spec/cloud'; +import { TemplateManifestSchema } from '@objectstack/spec/marketplace'; +import type { TemplateManifest } from '@objectstack/spec/marketplace'; // Validate data const result = TemplateManifestSchema.parse(data); diff --git a/content/docs/references/meta.json b/content/docs/references/meta.json index 357008a34a..2fd0d2b726 100644 --- a/content/docs/references/meta.json +++ b/content/docs/references/meta.json @@ -5,11 +5,11 @@ "ai", "api", "automation", - "cloud", "data", "identity", "integration", "kernel", + "marketplace", "qa", "security", "shared", diff --git a/content/docs/references/system/environment-artifact.mdx b/content/docs/references/system/environment-artifact.mdx index 1487c75371..c0d73a4967 100644 --- a/content/docs/references/system/environment-artifact.mdx +++ b/content/docs/references/system/environment-artifact.mdx @@ -8,10 +8,12 @@ description: Environment Artifact protocol schemas ## Environment Artifact Envelope THE single declaration of the environment artifact envelope (#4740, -#4535 C10 — maintainer route A′). `@objectstack/spec/cloud` re-exports -this file; both entry points resolve to these exact symbols, so the -chosen entry point can never change the shape a consumer gets (the -#4411 dual-source trap, closed for this name). +#4535 C10 — maintainer route A′). `@objectstack/spec/system` is now its +ONLY entry point: `@objectstack/spec/cloud` re-exported this file until +#16325 removed that subpath, and no other entry has ever declared or +re-exported the name, so the chosen entry point can never change the +shape a consumer gets (the #4411 dual-source trap, closed for this name — +pinned by `holdersOf` in `./environment-artifact.test.ts`). Describes the response shape of `GET /api/v1/cloud/environments/:environmentId/artifact` — the assembled 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 092f44feb7..3788e5d558 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md @@ -258,10 +258,10 @@ directory rather than per file. |---|---| | `ai/` | 77 | | `api/` | 451 | -| `cloud/` | 83 | | `identity/` | 32 | | `integration/` | 8 | | `kernel/` | 260 | +| `marketplace/` | 29 | | `qa/` | 6 | | `shared/` | 20 | | `system/` | 351 | diff --git a/docs/design/marketplace-publishing.md b/docs/design/marketplace-publishing.md index f0aa65e1ee..c5cd0e75c5 100644 --- a/docs/design/marketplace-publishing.md +++ b/docs/design/marketplace-publishing.md @@ -45,7 +45,7 @@ The marketplace protocol consists of three primary schema files: 1. **`packages/spec/src/kernel/manifest.zod.ts`** — Package manifest schema defining the structure of all packages 2. **`packages/spec/src/kernel/package-registry.zod.ts`** — Runtime lifecycle management for installed packages -3. **`packages/spec/src/cloud/marketplace.zod.ts`** — Marketplace ecosystem schemas for publishing and discovery +3. **`packages/spec/src/marketplace/marketplace.zod.ts`** — Marketplace ecosystem schemas for publishing and discovery ### Reference Implementation @@ -108,7 +108,7 @@ Supports semantic versioning ranges: ## 3. Developer Publishing Flow -From `packages/spec/src/cloud/marketplace.zod.ts`: +From `packages/spec/src/marketplace/marketplace.zod.ts`: ``` 1. Develop → Build plugin locally using ObjectStack CLI @@ -526,7 +526,7 @@ Validates: **Deliverables:** - ✅ `packages/spec/src/kernel/manifest.zod.ts` - ✅ `packages/spec/src/kernel/package-registry.zod.ts` -- ✅ `packages/spec/src/cloud/marketplace.zod.ts` +- ✅ `packages/spec/src/marketplace/marketplace.zod.ts` - 🚧 `packages/kernel/src/registry/schema-registry.ts` ### Phase 2: CLI Tooling (Q2 2026) @@ -619,7 +619,7 @@ This comprehensive design document establishes the **Marketplace Protocol** for **Key Protocol Files:** - ✅ `packages/spec/src/kernel/manifest.zod.ts` - ✅ `packages/spec/src/kernel/package-registry.zod.ts` -- ✅ `packages/spec/src/cloud/marketplace.zod.ts` +- ✅ `packages/spec/src/marketplace/marketplace.zod.ts` **Next Steps:** 1. Implement Phase 1: SchemaRegistry.installPackage() with 30+ metadata registration diff --git a/packages/cli/src/commands/package/publish.ts b/packages/cli/src/commands/package/publish.ts index d4f4cc1ed7..9b263e57e7 100644 --- a/packages/cli/src/commands/package/publish.ts +++ b/packages/cli/src/commands/package/publish.ts @@ -29,7 +29,7 @@ import { readFile } from 'node:fs/promises'; import { resolve as resolvePath, basename, dirname, isAbsolute } from 'node:path'; import { Args, Command, Flags } from '@oclif/core'; -import { PackageSchema } from '@objectstack/spec/cloud'; +import { PackageSchema } from '@objectstack/spec/marketplace'; import { printHeader, printKV, printSuccess, printError, printStep } from '../../utils/format.js'; import { DEFAULT_CLOUD_URL, tryReadCloudConfig } from '../../utils/cloud-config.js'; import { readErrorMessage } from '../../utils/response-envelope.js'; @@ -543,7 +543,7 @@ export default class PackagePublish extends Command { } // Marketplace per-locale translations. Schema is - // `PackageTranslationsSchema` from @objectstack/spec/cloud. Per-entry + // `PackageTranslationsSchema` from @objectstack/spec/marketplace. Per-entry // `readme` may be inlined markdown OR a path (e.g. `README.zh-CN.md`) // — we resolve paths against the manifest directory. if (m.translations && typeof m.translations === 'object') { diff --git a/packages/cli/src/utils/protocol-version-gap.ts b/packages/cli/src/utils/protocol-version-gap.ts index c8816ef6d3..ff5f774641 100644 --- a/packages/cli/src/utils/protocol-version-gap.ts +++ b/packages/cli/src/utils/protocol-version-gap.ts @@ -33,7 +33,7 @@ import { checkProtocolCompat, type ProtocolHandshakeManifest } from '@objectstac * (`assertProtocolCompat`, raising `OS_PROTOCOL_INCOMPATIBLE`). `specVersion` * is retired from the stack config's CLI vocabulary; it keeps its meaning on * the unrelated marketplace TEMPLATE manifest - * (`packages/spec/src/cloud/template-manifest.zod.ts`), which is a different + * (`packages/spec/src/marketplace/template-manifest.zod.ts`), which is a different * surface and is untouched. * * ## Why the range is judged by `checkProtocolCompat` and not re-parsed here diff --git a/packages/cli/test/package-publish-manifest-id.test.ts b/packages/cli/test/package-publish-manifest-id.test.ts index 715a673b37..6c7636b132 100644 --- a/packages/cli/test/package-publish-manifest-id.test.ts +++ b/packages/cli/test/package-publish-manifest-id.test.ts @@ -41,7 +41,7 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { PackageSchema } from '@objectstack/spec/cloud'; +import { PackageSchema } from '@objectstack/spec/marketplace'; import PackagePublish, { deriveManifestId, isManifestId } from '../src/commands/package/publish.js'; const HERE = dirname(fileURLToPath(import.meta.url)); diff --git a/packages/cli/test/package-publish-namespace.test.ts b/packages/cli/test/package-publish-namespace.test.ts index aef5e82013..13b146d664 100644 --- a/packages/cli/test/package-publish-namespace.test.ts +++ b/packages/cli/test/package-publish-namespace.test.ts @@ -17,7 +17,7 @@ import { describe, it, expect, afterEach, vi } from 'vitest'; import { mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; -import { CreatePackageRequestSchema } from '@objectstack/spec/cloud'; +import { CreatePackageRequestSchema } from '@objectstack/spec/marketplace'; import PackagePublish, { NAMESPACE_RE } from '../src/commands/package/publish.js'; type Call = { url: string; body: any }; diff --git a/packages/client/src/client.environments-namespace.test.ts b/packages/client/src/client.environments-namespace.test.ts index 0598f85fa2..298ceee6d7 100644 --- a/packages/client/src/client.environments-namespace.test.ts +++ b/packages/client/src/client.environments-namespace.test.ts @@ -127,9 +127,10 @@ export function createDeclaresNoDatabaseBlock(): void { * ⚖️ Maintainer ruling, 2026-08-29, verbatim: 「同意」 — option 甲. `warnings` * and `durationMs` are declared PRESENT, `hostnameAssignment` OPTIONAL (the * producer's own "absence stays absence" contract), all three typed as the - * INLINE WIRE SHAPE and ⛔ NOT bound to `@objectstack/spec/cloud`'s - * `ProvisionEnvironmentResponseSchema` — those are camelCase row contracts for - * a control plane that speaks snake_case on `/api/v1/cloud/*` (#11925/#12036). + * INLINE WIRE SHAPE and ⛔ NOT bound to `ProvisionEnvironmentResponseSchema` + * (declared by `@objectstack/spec/cloud` until #16325, by the cloud repo since) + * — those are camelCase row contracts for a control plane that speaks + * snake_case on `/api/v1/cloud/*` (#11925/#12036). * * Each read below is a separate assertion on purpose: a key that regresses on * its own is named by the failure instead of hidden behind a sibling's. diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 264f459c6d..25f5c9605d 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -2739,9 +2739,9 @@ export class ObjectStackClient { * environment-scoped `packages` block nested inside it, keeps its erased * `any` DELIBERATELY (#12036). * - * `@objectstack/spec/cloud` does declare row contracts that look like the - * obvious binding — `Environment`, `EnvironmentCredential`, - * `EnvironmentPackageInstallation` — and they are camelCase + * Until #16325 `@objectstack/spec/cloud` declared row contracts that looked + * like the obvious binding — `Environment`, `EnvironmentCredential`, + * `EnvironmentPackageInstallation` — and they were camelCase * (`displayName`, `organizationId`, `isDefault`, `databaseUrl`; zero * snake_case keys across all three schemas). The `/api/v1/cloud/*` control * plane this namespace calls speaks **snake_case**: the in-repo CLI @@ -2856,8 +2856,9 @@ export class ObjectStackClient { // OPTIONAL (the producer's own "absence stays absence" contract), and // all three are typed as the INLINE WIRE SHAPE. // - // ⛔ Inline, and NOT bound to `@objectstack/spec/cloud`'s - // `ProvisionEnvironmentResponseSchema`. That is the namespace docblock's + // ⛔ Inline, and NOT bound to `ProvisionEnvironmentResponseSchema` + // (declared by `@objectstack/spec/cloud` until #16325; the cloud repo's + // own declaration since). That is the namespace docblock's // #11925/#12036 constraint applied to the response side: those contracts // are camelCase row types for a control plane that speaks snake_case on // `/api/v1/cloud/*`, so binding them would typecheck and be false. The diff --git a/packages/client/src/return-type-precision.test.ts b/packages/client/src/return-type-precision.test.ts index a94ff9eee6..59d6deecba 100644 --- a/packages/client/src/return-type-precision.test.ts +++ b/packages/client/src/return-type-precision.test.ts @@ -107,7 +107,16 @@ import type { DuplicatePackageResponse, } from '@objectstack/spec/api'; import type { ResolvedBook } from '@objectstack/spec/system'; -import type { Environment } from '@objectstack/spec/cloud'; +// [#16325] `Environment` — the camelCase row type that used to be the +// obvious-looking (and false) binding for `client.environments.*` — is no +// longer a name `@objectstack/spec` offers from ANY entry: the cloud control +// plane's row contracts left with the `./cloud` subpath and live in the cloud +// repo beside their producer. The near-miss is therefore pinned at the import +// rather than at a member read (regression guard 2 below): the day a row type +// called `Environment` reappears on the package-format subpath, this line +// stops erroring and the unused directive goes red. +// @ts-expect-error `Environment` is not exported by `@objectstack/spec/marketplace` (#16325) +import type { Environment as _RetiredSpecEnvironmentRow } from '@objectstack/spec/marketplace'; declare const client: ObjectStackClient; declare const scoped: ScopedEnvironmentClient; @@ -1036,25 +1045,24 @@ export async function returnTypePrecisionPins14314(): Promise { * (`restoredVersion`) whose false declaration this family just paid to * remove. * - * 2. `Environment` is the obvious-looking binding for `client.environments.*` and - * is camelCase, while the `/api/v1/cloud/*` control plane those methods - * call speaks snake_case (measured from this repo's own CLI consumers: - * `p.display_name`, `p.organization_id`, `p.is_default`). Binding it would - * typecheck, be false, and break those callers. + * 2. `Environment` WAS the obvious-looking binding for `client.environments.*` + * — camelCase, while the `/api/v1/cloud/*` control plane those methods call + * speaks snake_case (measured from this repo's own CLI consumers: + * `p.display_name`, `p.organization_id`, `p.is_default`); binding it would + * have typechecked, been false, and broken those callers. Since #16325 the + * row contract is not published by `@objectstack/spec` at all — it left + * with the `./cloud` subpath — so the guard moved from a member read + * (`specEnvironmentRow.display_name`, which needs the type to exist) to the + * `@ts-expect-error`'d import at the top of this file. The former + * `environmentIsNotTheCloudWireRow` pin had no subject left to read. */ declare const commitRollbackPayload: RollbackToPackageCommitResponse; -declare const specEnvironmentRow: Environment; export function commitRollbackResponseIsNotTheVersionRollbackShape(): void { // @ts-expect-error the COMMIT-rollback payload carries no version identity void commitRollbackPayload.restoredVersion; } -export function environmentIsNotTheCloudWireRow(): void { - // @ts-expect-error the control plane sends `display_name`; this row declares `displayName` - void specEnvironmentRow.display_name; -} - /** * [#13023] `meta.deleteItem` declared a return the reset door has never * answered — on BOTH twins. @@ -1188,7 +1196,8 @@ describe('client SDK return-type precision (#8140)', () => { expect(typeof deleteDataResponseIsNotTheMetaResetShape).toBe('function'); expect(typeof metaResetResponseDeclaresTheWireReceipt).toBe('function'); expect(typeof commitRollbackResponseIsNotTheVersionRollbackShape).toBe('function'); - expect(typeof environmentIsNotTheCloudWireRow).toBe('function'); + // `environmentIsNotTheCloudWireRow` left with its subject (#16325): the + // guard is now the `@ts-expect-error`'d import at the top of the file. }); it('unwraps exactly one `{ success, data }` envelope — the premise the annotations rest on', async () => { diff --git a/packages/create-objectstack/src/template-consistency.test.ts b/packages/create-objectstack/src/template-consistency.test.ts index 6b3968ff57..466f305d7a 100644 --- a/packages/create-objectstack/src/template-consistency.test.ts +++ b/packages/create-objectstack/src/template-consistency.test.ts @@ -207,7 +207,7 @@ describe('bundled template declared version surfaces', () => { expect( typeof manifest.specVersion, `${template}/objectstack.manifest.json must declare specVersion — it is REQUIRED by ` + - 'TemplateManifestSchema (packages/spec/src/cloud/template-manifest.zod.ts)', + 'TemplateManifestSchema (packages/spec/src/marketplace/template-manifest.zod.ts)', ).toBe('string'); const match = /^\^(\d+)\.\d+\.\d+$/.exec(manifest.specVersion); diff --git a/packages/metadata/src/plugin.ts b/packages/metadata/src/plugin.ts index 84af55bd2c..0bdb14843b 100644 --- a/packages/metadata/src/plugin.ts +++ b/packages/metadata/src/plugin.ts @@ -892,7 +892,7 @@ export class MetadataPlugin implements Plugin { * landing. */ private async _parseAndRegisterArtifact(ctx: PluginContext, raw: unknown, label: string): Promise { - const { EnvironmentArtifactSchema } = await import('@objectstack/spec/cloud'); + const { EnvironmentArtifactSchema } = await import('@objectstack/spec/system'); const { ObjectStackDefinitionSchema } = await import('@objectstack/spec'); let metadata: Record; diff --git a/packages/runtime/src/spec-subpath-alias-coverage.pin.test.ts b/packages/runtime/src/spec-subpath-alias-coverage.pin.test.ts index d1f1849a70..3c871ddce8 100644 --- a/packages/runtime/src/spec-subpath-alias-coverage.pin.test.ts +++ b/packages/runtime/src/spec-subpath-alias-coverage.pin.test.ts @@ -121,9 +121,11 @@ describe('every published `@objectstack/spec` subpath resolves to spec SOURCE (# // A short population would make every loop below pass vacuously, which is // the exact shape of the defect this file pins. expect(PUBLISHED_SUBPATHS.length).toBeGreaterThanOrEqual(15); - // The three the hand-written enumeration had missed, named individually so - // that a filter bug dropping them cannot be invisible. - expect(PUBLISHED_SUBPATHS).toContain('@objectstack/spec/cloud'); + // The three the hand-written enumeration had missed (#9457), named + // individually so that a filter bug dropping them cannot be invisible. + // `cloud` left the exports map at #16325; `marketplace` — the subpath that + // took its package-format half — stands in for it here. + expect(PUBLISHED_SUBPATHS).toContain('@objectstack/spec/marketplace'); expect(PUBLISHED_SUBPATHS).toContain('@objectstack/spec/integration'); expect(PUBLISHED_SUBPATHS).toContain('@objectstack/spec/studio'); }); diff --git a/packages/spec/api-surface/api.json b/packages/spec/api-surface/api.json index 6275edbcd2..64fcb8267a 100644 --- a/packages/spec/api-surface/api.json +++ b/packages/spec/api-surface/api.json @@ -344,6 +344,8 @@ "EnhancedApiError (type)", "EnhancedApiErrorParsed (type)", "EnhancedApiErrorSchema (const)", + "EnvironmentType (type)", + "EnvironmentTypeSchema (const)", "ErrorCategory (const)", "ErrorCategory (type)", "ErrorCode (const)", diff --git a/packages/spec/api-surface/cloud.json b/packages/spec/api-surface/cloud.json deleted file mode 100644 index b53fb81d8e..0000000000 --- a/packages/spec/api-surface/cloud.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "description": "Every exported `name (kind)` of one published entry point of @objectstack/spec — the breadth half of the ADR-0059 backward-compatibility gate. Sharded by entry point (#5837) so two PRs touching different entry points never share a file. Reads the BUILT dist/*.d.ts: regenerate with `pnpm --filter @objectstack/spec gen:api-surface` after a real build.", - "entry": "./cloud", - "exports": [ - "AnalyticsTimeRange (type)", - "AnalyticsTimeRangeSchema (const)", - "AppDiscoveryRequest (type)", - "AppDiscoveryRequestParsed (type)", - "AppDiscoveryRequestSchema (const)", - "AppDiscoveryResponse (type)", - "AppDiscoveryResponseSchema (const)", - "AppSubscription (type)", - "AppSubscriptionParsed (type)", - "AppSubscriptionSchema (const)", - "ArtifactDownloadResponse (type)", - "ArtifactDownloadResponseSchema (const)", - "ArtifactReference (type)", - "ArtifactReferenceParsed (type)", - "ArtifactReferenceSchema (const)", - "CreateListingRequest (type)", - "CreateListingRequestParsed (type)", - "CreateListingRequestSchema (const)", - "CreatePackageRequest (type)", - "CreatePackageRequestSchema (const)", - "CreatePackageVersionRequest (type)", - "CreatePackageVersionRequestSchema (const)", - "CuratedCollection (type)", - "CuratedCollectionParsed (type)", - "CuratedCollectionSchema (const)", - "Environment (type)", - "EnvironmentArtifact (type)", - "EnvironmentArtifactParsed (type)", - "EnvironmentArtifactSchema (const)", - "EnvironmentCredential (type)", - "EnvironmentCredentialParsed (type)", - "EnvironmentCredentialSchema (const)", - "EnvironmentCredentialStatus (type)", - "EnvironmentCredentialStatusSchema (const)", - "EnvironmentDriver (type)", - "EnvironmentDriverSchema (const)", - "EnvironmentMember (type)", - "EnvironmentMemberSchema (const)", - "EnvironmentPackageInstallation (type)", - "EnvironmentPackageInstallationParsed (type)", - "EnvironmentPackageInstallationSchema (const)", - "EnvironmentPackageStatus (type)", - "EnvironmentPackageStatusSchema (const)", - "EnvironmentParsed (type)", - "EnvironmentRole (type)", - "EnvironmentRoleSchema (const)", - "EnvironmentSchema (const)", - "EnvironmentStatus (type)", - "EnvironmentStatusSchema (const)", - "EnvironmentType (type)", - "EnvironmentTypeSchema (const)", - "EnvironmentVisibility (type)", - "EnvironmentVisibilitySchema (const)", - "FeaturedListing (type)", - "FeaturedListingParsed (type)", - "FeaturedListingSchema (const)", - "InstallPackageToEnvironmentRequest (type)", - "InstallPackageToEnvironmentRequestParsed (type)", - "InstallPackageToEnvironmentRequestSchema (const)", - "InstalledAppSummary (type)", - "InstalledAppSummaryParsed (type)", - "InstalledAppSummarySchema (const)", - "ListEnvironmentPackagesResponse (type)", - "ListEnvironmentPackagesResponseParsed (type)", - "ListEnvironmentPackagesResponseSchema (const)", - "ListInstalledAppsRequest (type)", - "ListInstalledAppsRequestParsed (type)", - "ListInstalledAppsRequestSchema (const)", - "ListInstalledAppsResponse (type)", - "ListInstalledAppsResponseParsed (type)", - "ListInstalledAppsResponseSchema (const)", - "ListReviewsRequest (type)", - "ListReviewsRequestParsed (type)", - "ListReviewsRequestSchema (const)", - "ListReviewsResponse (type)", - "ListReviewsResponseParsed (type)", - "ListReviewsResponseSchema (const)", - "ListingActionRequest (type)", - "ListingActionRequestSchema (const)", - "ListingStatus (type)", - "ListingStatusSchema (const)", - "MarketplaceCategory (type)", - "MarketplaceCategorySchema (const)", - "MarketplaceHealthMetrics (type)", - "MarketplaceHealthMetricsSchema (const)", - "MarketplaceInstallRequest (type)", - "MarketplaceInstallRequestParsed (type)", - "MarketplaceInstallRequestSchema (const)", - "MarketplaceInstallResponse (type)", - "MarketplaceInstallResponseSchema (const)", - "MarketplaceListing (type)", - "MarketplaceListingParsed (type)", - "MarketplaceListingSchema (const)", - "MarketplaceSearchRequest (type)", - "MarketplaceSearchRequestParsed (type)", - "MarketplaceSearchRequestSchema (const)", - "MarketplaceSearchResponse (type)", - "MarketplaceSearchResponseParsed (type)", - "MarketplaceSearchResponseSchema (const)", - "Package (type)", - "PackageCategory (type)", - "PackageCategorySchema (const)", - "PackageDependency (type)", - "PackageDependencyParsed (type)", - "PackageDependencySchema (const)", - "PackageInstallation (type)", - "PackageInstallationParsed (type)", - "PackageInstallationSchema (const)", - "PackageInstallationStatus (type)", - "PackageInstallationStatusSchema (const)", - "PackageL10nField (type)", - "PackageLocale (type)", - "PackageLocaleSchema (const)", - "PackageManifest (type)", - "PackageManifestParsed (type)", - "PackageManifestSchema (const)", - "PackageParsed (type)", - "PackagePublisher (type)", - "PackagePublisherSchema (const)", - "PackageSchema (const)", - "PackageSubmission (type)", - "PackageSubmissionParsed (type)", - "PackageSubmissionSchema (const)", - "PackageTranslation (type)", - "PackageTranslationSchema (const)", - "PackageTranslations (type)", - "PackageTranslationsSchema (const)", - "PackageVersion (type)", - "PackageVersionParsed (type)", - "PackageVersionSchema (const)", - "PackageVersionStatus (type)", - "PackageVersionStatusSchema (const)", - "PackageVisibility (type)", - "PackageVisibilitySchema (const)", - "PolicyAction (type)", - "PolicyActionParsed (type)", - "PolicyActionSchema (const)", - "PolicyViolationType (type)", - "PolicyViolationTypeSchema (const)", - "PricingModel (type)", - "PricingModelSchema (const)", - "ProvisionEnvironmentRequest (type)", - "ProvisionEnvironmentRequestParsed (type)", - "ProvisionEnvironmentRequestSchema (const)", - "ProvisionEnvironmentResponse (type)", - "ProvisionEnvironmentResponseParsed (type)", - "ProvisionEnvironmentResponseSchema (const)", - "ProvisionOrganizationRequest (type)", - "ProvisionOrganizationRequestParsed (type)", - "ProvisionOrganizationRequestSchema (const)", - "ProvisionOrganizationResponse (type)", - "ProvisionOrganizationResponseParsed (type)", - "ProvisionOrganizationResponseSchema (const)", - "ProvisionTenantRequest (type)", - "ProvisionTenantRequestParsed (type)", - "ProvisionTenantRequestSchema (const)", - "ProvisionTenantResponse (type)", - "ProvisionTenantResponseParsed (type)", - "ProvisionTenantResponseSchema (const)", - "PublishPackageVersionRequest (type)", - "PublishPackageVersionRequestSchema (const)", - "Publisher (type)", - "PublisherParsed (type)", - "PublisherProfile (type)", - "PublisherProfileParsed (type)", - "PublisherProfileSchema (const)", - "PublisherSchema (const)", - "PublisherVerification (type)", - "PublisherVerificationSchema (const)", - "PublishingAnalyticsRequest (type)", - "PublishingAnalyticsRequestParsed (type)", - "PublishingAnalyticsRequestSchema (const)", - "PublishingAnalyticsResponse (type)", - "PublishingAnalyticsResponseParsed (type)", - "PublishingAnalyticsResponseSchema (const)", - "RecommendationReason (type)", - "RecommendationReasonSchema (const)", - "RecommendedApp (type)", - "RecommendedAppSchema (const)", - "RejectionReason (type)", - "RejectionReasonSchema (const)", - "ReleaseChannel (type)", - "ReleaseChannelSchema (const)", - "ResolvePackageL10nOptions (interface)", - "ReviewCriterion (type)", - "ReviewCriterionParsed (type)", - "ReviewCriterionSchema (const)", - "ReviewDecision (type)", - "ReviewDecisionSchema (const)", - "ReviewModerationStatus (type)", - "ReviewModerationStatusSchema (const)", - "RollbackEnvironmentPackageRequest (type)", - "RollbackEnvironmentPackageRequestSchema (const)", - "Sha256Digest (type)", - "Sha256DigestSchema (const)", - "SubmissionReview (type)", - "SubmissionReviewParsed (type)", - "SubmissionReviewSchema (const)", - "SubmitReviewRequest (type)", - "SubmitReviewRequestSchema (const)", - "SubscriptionStatus (type)", - "SubscriptionStatusSchema (const)", - "TemplateManifest (type)", - "TemplateManifestSchema (const)", - "TenantContext (type)", - "TenantContextSchema (const)", - "TenantDatabase (type)", - "TenantDatabaseParsed (type)", - "TenantDatabaseSchema (const)", - "TenantDatabaseStatus (type)", - "TenantDatabaseStatusSchema (const)", - "TenantIdentificationSource (type)", - "TenantIdentificationSourceSchema (const)", - "TenantPlan (type)", - "TenantPlanSchema (const)", - "TenantRoutingConfig (type)", - "TenantRoutingConfigParsed (type)", - "TenantRoutingConfigSchema (const)", - "TimeSeriesPoint (type)", - "TimeSeriesPointSchema (const)", - "TrendingListing (type)", - "TrendingListingSchema (const)", - "UpdateListingRequest (type)", - "UpdateListingRequestSchema (const)", - "UpdatePackageRequest (type)", - "UpdatePackageRequestSchema (const)", - "UpdatePackageVersionRequest (type)", - "UpdatePackageVersionRequestSchema (const)", - "UpgradeEnvironmentPackageRequest (type)", - "UpgradeEnvironmentPackageRequestParsed (type)", - "UpgradeEnvironmentPackageRequestSchema (const)", - "UserReview (type)", - "UserReviewParsed (type)", - "UserReviewSchema (const)", - "VersionRelease (type)", - "VersionReleaseParsed (type)", - "VersionReleaseSchema (const)", - "resolvePackageL10n (function)", - "resolvePackageL10nField (function)", - "resolveScreenshotCaptions (function)" - ] -} diff --git a/packages/spec/api-surface/marketplace.json b/packages/spec/api-surface/marketplace.json new file mode 100644 index 0000000000..1f6f584222 --- /dev/null +++ b/packages/spec/api-surface/marketplace.json @@ -0,0 +1,82 @@ +{ + "description": "Every exported `name (kind)` of one published entry point of @objectstack/spec — the breadth half of the ADR-0059 backward-compatibility gate. Sharded by entry point (#5837) so two PRs touching different entry points never share a file. Reads the BUILT dist/*.d.ts: regenerate with `pnpm --filter @objectstack/spec gen:api-surface` after a real build.", + "entry": "./marketplace", + "exports": [ + "ArtifactDownloadResponse (type)", + "ArtifactDownloadResponseSchema (const)", + "ArtifactReference (type)", + "ArtifactReferenceParsed (type)", + "ArtifactReferenceSchema (const)", + "CreatePackageRequest (type)", + "CreatePackageRequestSchema (const)", + "CreatePackageVersionRequest (type)", + "CreatePackageVersionRequestSchema (const)", + "ListingStatus (type)", + "ListingStatusSchema (const)", + "MarketplaceCategory (type)", + "MarketplaceCategorySchema (const)", + "MarketplaceInstallRequest (type)", + "MarketplaceInstallRequestParsed (type)", + "MarketplaceInstallRequestSchema (const)", + "MarketplaceInstallResponse (type)", + "MarketplaceInstallResponseSchema (const)", + "MarketplaceListing (type)", + "MarketplaceListingParsed (type)", + "MarketplaceListingSchema (const)", + "MarketplaceSearchRequest (type)", + "MarketplaceSearchRequestParsed (type)", + "MarketplaceSearchRequestSchema (const)", + "MarketplaceSearchResponse (type)", + "MarketplaceSearchResponseParsed (type)", + "MarketplaceSearchResponseSchema (const)", + "Package (type)", + "PackageCategory (type)", + "PackageCategorySchema (const)", + "PackageDependency (type)", + "PackageDependencyParsed (type)", + "PackageDependencySchema (const)", + "PackageL10nField (type)", + "PackageLocale (type)", + "PackageLocaleSchema (const)", + "PackageManifest (type)", + "PackageManifestParsed (type)", + "PackageManifestSchema (const)", + "PackageParsed (type)", + "PackagePublisher (type)", + "PackagePublisherSchema (const)", + "PackageSchema (const)", + "PackageSubmission (type)", + "PackageSubmissionParsed (type)", + "PackageSubmissionSchema (const)", + "PackageTranslation (type)", + "PackageTranslationSchema (const)", + "PackageTranslations (type)", + "PackageTranslationsSchema (const)", + "PackageVersion (type)", + "PackageVersionParsed (type)", + "PackageVersionSchema (const)", + "PackageVersionStatus (type)", + "PackageVersionStatusSchema (const)", + "PackageVisibility (type)", + "PackageVisibilitySchema (const)", + "PricingModel (type)", + "PricingModelSchema (const)", + "PublishPackageVersionRequest (type)", + "PublishPackageVersionRequestSchema (const)", + "Publisher (type)", + "PublisherParsed (type)", + "PublisherSchema (const)", + "PublisherVerification (type)", + "PublisherVerificationSchema (const)", + "ResolvePackageL10nOptions (interface)", + "TemplateManifest (type)", + "TemplateManifestSchema (const)", + "UpdatePackageRequest (type)", + "UpdatePackageRequestSchema (const)", + "UpdatePackageVersionRequest (type)", + "UpdatePackageVersionRequestSchema (const)", + "resolvePackageL10n (function)", + "resolvePackageL10nField (function)", + "resolveScreenshotCaptions (function)" + ] +} diff --git a/packages/spec/authorable-defaults/cloud.json b/packages/spec/authorable-defaults/cloud.json deleted file mode 100644 index 5af6ee244c..0000000000 --- a/packages/spec/authorable-defaults/cloud.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "description": "Ratchet of the DEFAULT VALUE of every authorable key in one category that has one (#4666) — what a metadata author gets when they omit the key, which for AI-authored metadata is most of the time. Sharded by category like authorable-surface/; the gate reads the whole authorable-defaults/ directory as ONE set. Each line is \": = \". Additions (a NEW key that ships with a default) are auto-recorded — commit the change. CHANGING, ADDING or REMOVING the default of a key that already existed is NOT auto-recorded: it silently alters the behaviour of already-deployed metadata, so it fails check:authorable-surface until it is declared in DEFAULT_CHANGES_BY_MAJOR (scripts/lib/default-changes.ts). Constraints are deliberately NOT recorded here — a tightened bound REJECTS a document loudly, which is a different and self-announcing class (maintainer ruling on #4666, direction B). See #4666, #4661.", - "category": "cloud", - "defaults": [ - "cloud/AppDiscoveryRequest:limit = 10", - "cloud/AppSubscription:autoRenew = true", - "cloud/ArtifactReference:format = \"tgz\"", - "cloud/CreateListingRequest:pricing = \"free\"", - "cloud/CuratedCollection:published = false", - "cloud/CuratedCollection:sortOrder = 0", - "cloud/Environment:isDefault = false", - "cloud/Environment:isSystem = false", - "cloud/Environment:plan = \"free\"", - "cloud/Environment:status = \"provisioning\"", - "cloud/Environment:visibility = \"private\"", - "cloud/EnvironmentCredential:authorization = \"full_access\"", - "cloud/EnvironmentCredential:status = \"active\"", - "cloud/EnvironmentPackageInstallation:enabled = true", - "cloud/EnvironmentPackageInstallation:status = \"installed\"", - "cloud/EnvironmentPackageInstallation:withSampleData = false", - "cloud/FeaturedListing:active = true", - "cloud/FeaturedListing:priority = 0", - "cloud/InstallPackageToEnvironmentRequest:allowDraft = false", - "cloud/InstallPackageToEnvironmentRequest:enableOnInstall = true", - "cloud/InstallPackageToEnvironmentRequest:withSampleData = false", - "cloud/InstalledAppSummary:enabled = true", - "cloud/InstalledAppSummary:updateAvailable = false", - "cloud/ListInstalledAppsRequest:page = 1", - "cloud/ListInstalledAppsRequest:pageSize = 20", - "cloud/ListInstalledAppsRequest:sortBy = \"name\"", - "cloud/ListReviewsRequest:page = 1", - "cloud/ListReviewsRequest:pageSize = 10", - "cloud/ListReviewsRequest:sortBy = \"newest\"", - "cloud/MarketplaceInstallRequest:enableOnInstall = true", - "cloud/MarketplaceListing:packageType = \"app\"", - "cloud/MarketplaceListing:pricing = \"free\"", - "cloud/MarketplaceListing:status = \"draft\"", - "cloud/MarketplaceSearchRequest:page = 1", - "cloud/MarketplaceSearchRequest:pageSize = 20", - "cloud/MarketplaceSearchRequest:sortBy = \"relevance\"", - "cloud/MarketplaceSearchRequest:sortDirection = \"desc\"", - "cloud/Package:isStarter = false", - "cloud/Package:publisher = \"private\"", - "cloud/Package:visibility = \"private\"", - "cloud/PackageDependency:optional = false", - "cloud/PackageInstallation:status = \"installing\"", - "cloud/PackageManifest:dependencies = []", - "cloud/PackageManifest:metadataTypes = []", - "cloud/PackageManifest:migrations = []", - "cloud/PackageManifest:scope = \"environment\"", - "cloud/PackageSubmission:isNewListing = false", - "cloud/PackageSubmission:status = \"pending\"", - "cloud/PackageVersion:isPreRelease = false", - "cloud/PackageVersion:status = \"draft\"", - "cloud/PolicyAction:resolved = false", - "cloud/ProvisionEnvironmentRequest:visibility = \"private\"", - "cloud/ProvisionOrganizationRequest:defaultEnvironmentDisplayName = \"Production\"", - "cloud/ProvisionTenantRequest:plan = \"free\"", - "cloud/Publisher:verification = \"unverified\"", - "cloud/PublisherProfile:verification = \"unverified\"", - "cloud/PublishingAnalyticsRequest:timeRange = \"last_30d\"", - "cloud/ReviewCriterion:required = true", - "cloud/TenantDatabase:plan = \"free\"", - "cloud/TenantDatabase:status = \"provisioning\"", - "cloud/TenantRoutingConfig:enabled = false", - "cloud/TenantRoutingConfig:identificationSources = [\"subdomain\",\"header\",\"jwt_claim\"]", - "cloud/TenantRoutingConfig:jwtOrganizationClaim = \"organizationId\"", - "cloud/TenantRoutingConfig:tenantHeaderName = \"X-Tenant-ID\"", - "cloud/UpgradeEnvironmentPackageRequest:allowDraft = false", - "cloud/UserReview:helpfulCount = 0", - "cloud/UserReview:moderationStatus = \"pending\"", - "cloud/VersionRelease:channel = \"stable\"", - "cloud/VersionRelease:deprecated = false" - ] -} diff --git a/packages/spec/authorable-defaults/marketplace.json b/packages/spec/authorable-defaults/marketplace.json new file mode 100644 index 0000000000..5c9679f463 --- /dev/null +++ b/packages/spec/authorable-defaults/marketplace.json @@ -0,0 +1,28 @@ +{ + "description": "Ratchet of the DEFAULT VALUE of every authorable key in one category that has one (#4666) — what a metadata author gets when they omit the key, which for AI-authored metadata is most of the time. Sharded by category like authorable-surface/; the gate reads the whole authorable-defaults/ directory as ONE set. Each line is \": = \". Additions (a NEW key that ships with a default) are auto-recorded — commit the change. CHANGING, ADDING or REMOVING the default of a key that already existed is NOT auto-recorded: it silently alters the behaviour of already-deployed metadata, so it fails check:authorable-surface until it is declared in DEFAULT_CHANGES_BY_MAJOR (scripts/lib/default-changes.ts). Constraints are deliberately NOT recorded here — a tightened bound REJECTS a document loudly, which is a different and self-announcing class (maintainer ruling on #4666, direction B). See #4666, #4661.", + "category": "marketplace", + "defaults": [ + "marketplace/ArtifactReference:format = \"tgz\"", + "marketplace/MarketplaceInstallRequest:enableOnInstall = true", + "marketplace/MarketplaceListing:packageType = \"app\"", + "marketplace/MarketplaceListing:pricing = \"free\"", + "marketplace/MarketplaceListing:status = \"draft\"", + "marketplace/MarketplaceSearchRequest:page = 1", + "marketplace/MarketplaceSearchRequest:pageSize = 20", + "marketplace/MarketplaceSearchRequest:sortBy = \"relevance\"", + "marketplace/MarketplaceSearchRequest:sortDirection = \"desc\"", + "marketplace/Package:isStarter = false", + "marketplace/Package:publisher = \"private\"", + "marketplace/Package:visibility = \"private\"", + "marketplace/PackageDependency:optional = false", + "marketplace/PackageManifest:dependencies = []", + "marketplace/PackageManifest:metadataTypes = []", + "marketplace/PackageManifest:migrations = []", + "marketplace/PackageManifest:scope = \"environment\"", + "marketplace/PackageSubmission:isNewListing = false", + "marketplace/PackageSubmission:status = \"pending\"", + "marketplace/PackageVersion:isPreRelease = false", + "marketplace/PackageVersion:status = \"draft\"", + "marketplace/Publisher:verification = \"unverified\"" + ] +} diff --git a/packages/spec/authorable-surface/cloud.json b/packages/spec/authorable-surface/cloud.json deleted file mode 100644 index ecfbbe51d8..0000000000 --- a/packages/spec/authorable-surface/cloud.json +++ /dev/null @@ -1,518 +0,0 @@ -{ - "description": "Ratchet of every AUTHORABLE key in one category of the spec — what a metadata author may write, which for this platform IS the third-party API. Sharded by category (#5837) so two PRs touching different categories never share a file; the gate reads the whole authorable-surface/ directory as ONE set, so deleting a shard deletes its keys exactly as deleting lines did. Auto-updated on additions (commit the change). A key that disappears without a tombstone fails gen:schema, because these schemas are not .strict() and Zod would silently strip it. \"[RETIRED]\" marks a tombstoned key that still rejects with an upgrade prescription. See #3855, ADR-0059 §5.", - "category": "cloud", - "keys": [ - "cloud/AppDiscoveryRequest:categories", - "cloud/AppDiscoveryRequest:limit", - "cloud/AppDiscoveryRequest:platformVersion", - "cloud/AppDiscoveryRequest:tenantId", - "cloud/AppDiscoveryResponse:collections", - "cloud/AppDiscoveryResponse:featured", - "cloud/AppDiscoveryResponse:newArrivals", - "cloud/AppDiscoveryResponse:recommended", - "cloud/AppDiscoveryResponse:trending", - "cloud/AppSubscription:autoRenew", - "cloud/AppSubscription:billingCycle", - "cloud/AppSubscription:createdAt", - "cloud/AppSubscription:currentPeriodEnd", - "cloud/AppSubscription:currentPeriodStart", - "cloud/AppSubscription:id", - "cloud/AppSubscription:licenseKey", - "cloud/AppSubscription:listingId", - "cloud/AppSubscription:plan", - "cloud/AppSubscription:priceInCents", - "cloud/AppSubscription:status", - "cloud/AppSubscription:tenantId", - "cloud/AppSubscription:trialEndDate", - "cloud/ArtifactDownloadResponse:downloadUrl", - "cloud/ArtifactDownloadResponse:expiresAt", - "cloud/ArtifactDownloadResponse:format", - "cloud/ArtifactDownloadResponse:sha256", - "cloud/ArtifactDownloadResponse:size", - "cloud/ArtifactReference:format", - "cloud/ArtifactReference:sha256", - "cloud/ArtifactReference:size", - "cloud/ArtifactReference:uploadedAt", - "cloud/ArtifactReference:url", - "cloud/CreateListingRequest:category", - "cloud/CreateListingRequest:description", - "cloud/CreateListingRequest:documentationUrl", - "cloud/CreateListingRequest:iconUrl", - "cloud/CreateListingRequest:name", - "cloud/CreateListingRequest:packageId", - "cloud/CreateListingRequest:priceInCents", - "cloud/CreateListingRequest:pricing", - "cloud/CreateListingRequest:repositoryUrl", - "cloud/CreateListingRequest:screenshots", - "cloud/CreateListingRequest:supportUrl", - "cloud/CreateListingRequest:tagline", - "cloud/CreateListingRequest:tags", - "cloud/CreatePackageRequest:category", - "cloud/CreatePackageRequest:createdBy", - "cloud/CreatePackageRequest:description", - "cloud/CreatePackageRequest:displayName", - "cloud/CreatePackageRequest:homepageUrl", - "cloud/CreatePackageRequest:iconUrl", - "cloud/CreatePackageRequest:isStarter", - "cloud/CreatePackageRequest:license", - "cloud/CreatePackageRequest:manifestId", - "cloud/CreatePackageRequest:namespace", - "cloud/CreatePackageRequest:ownerOrgId", - "cloud/CreatePackageRequest:publisher", - "cloud/CreatePackageRequest:tags", - "cloud/CreatePackageRequest:translations", - "cloud/CreatePackageRequest:visibility", - "cloud/CreatePackageVersionRequest:createdBy", - "cloud/CreatePackageVersionRequest:isPreRelease", - "cloud/CreatePackageVersionRequest:manifestJson", - "cloud/CreatePackageVersionRequest:packageId", - "cloud/CreatePackageVersionRequest:releaseNotes", - "cloud/CreatePackageVersionRequest:version", - "cloud/CuratedCollection:coverImageUrl", - "cloud/CuratedCollection:createdAt", - "cloud/CuratedCollection:createdBy", - "cloud/CuratedCollection:description", - "cloud/CuratedCollection:id", - "cloud/CuratedCollection:listingIds", - "cloud/CuratedCollection:name", - "cloud/CuratedCollection:published", - "cloud/CuratedCollection:sortOrder", - "cloud/CuratedCollection:updatedAt", - "cloud/Environment:apiBaseUrl", - "cloud/Environment:consoleUrl", - "cloud/Environment:createdAt", - "cloud/Environment:createdBy", - "cloud/Environment:databaseDriver", - "cloud/Environment:databaseUrl", - "cloud/Environment:displayName", - "cloud/Environment:hostname", - "cloud/Environment:id", - "cloud/Environment:isDefault", - "cloud/Environment:isSystem", - "cloud/Environment:metadata", - "cloud/Environment:organizationId", - "cloud/Environment:plan", - "cloud/Environment:provisionedAt", - "cloud/Environment:status", - "cloud/Environment:storageLimitMb", - "cloud/Environment:updatedAt", - "cloud/Environment:visibility", - "cloud/EnvironmentCredential:authorization", - "cloud/EnvironmentCredential:createdAt", - "cloud/EnvironmentCredential:encryptionKeyId", - "cloud/EnvironmentCredential:environmentId", - "cloud/EnvironmentCredential:expiresAt", - "cloud/EnvironmentCredential:id", - "cloud/EnvironmentCredential:revokedAt", - "cloud/EnvironmentCredential:secretCiphertext", - "cloud/EnvironmentCredential:status", - "cloud/EnvironmentMember:createdAt", - "cloud/EnvironmentMember:environmentId", - "cloud/EnvironmentMember:id", - "cloud/EnvironmentMember:invitedBy", - "cloud/EnvironmentMember:role", - "cloud/EnvironmentMember:updatedAt", - "cloud/EnvironmentMember:userId", - "cloud/EnvironmentPackageInstallation:enabled", - "cloud/EnvironmentPackageInstallation:environmentId", - "cloud/EnvironmentPackageInstallation:errorMessage", - "cloud/EnvironmentPackageInstallation:id", - "cloud/EnvironmentPackageInstallation:installedAt", - "cloud/EnvironmentPackageInstallation:installedBy", - "cloud/EnvironmentPackageInstallation:packageId", - "cloud/EnvironmentPackageInstallation:packageVersionId", - "cloud/EnvironmentPackageInstallation:settings", - "cloud/EnvironmentPackageInstallation:status", - "cloud/EnvironmentPackageInstallation:updatedAt", - "cloud/EnvironmentPackageInstallation:withSampleData", - "cloud/FeaturedListing:active", - "cloud/FeaturedListing:bannerUrl", - "cloud/FeaturedListing:editorialNote", - "cloud/FeaturedListing:endDate", - "cloud/FeaturedListing:listingId", - "cloud/FeaturedListing:priority", - "cloud/FeaturedListing:startDate", - "cloud/InstallPackageToEnvironmentRequest:allowDraft", - "cloud/InstallPackageToEnvironmentRequest:enableOnInstall", - "cloud/InstallPackageToEnvironmentRequest:installedBy", - "cloud/InstallPackageToEnvironmentRequest:packageManifestId", - "cloud/InstallPackageToEnvironmentRequest:packageVersionId", - "cloud/InstallPackageToEnvironmentRequest:settings", - "cloud/InstallPackageToEnvironmentRequest:version", - "cloud/InstallPackageToEnvironmentRequest:withSampleData", - "cloud/InstalledAppSummary:enabled", - "cloud/InstalledAppSummary:iconUrl", - "cloud/InstalledAppSummary:installedAt", - "cloud/InstalledAppSummary:installedVersion", - "cloud/InstalledAppSummary:latestVersion", - "cloud/InstalledAppSummary:listingId", - "cloud/InstalledAppSummary:name", - "cloud/InstalledAppSummary:packageId", - "cloud/InstalledAppSummary:subscriptionStatus", - "cloud/InstalledAppSummary:updateAvailable", - "cloud/ListEnvironmentPackagesResponse:packages", - "cloud/ListEnvironmentPackagesResponse:total", - "cloud/ListInstalledAppsRequest:enabled", - "cloud/ListInstalledAppsRequest:page", - "cloud/ListInstalledAppsRequest:pageSize", - "cloud/ListInstalledAppsRequest:sortBy", - "cloud/ListInstalledAppsRequest:tenantId", - "cloud/ListInstalledAppsRequest:updateAvailable", - "cloud/ListInstalledAppsResponse:items", - "cloud/ListInstalledAppsResponse:page", - "cloud/ListInstalledAppsResponse:pageSize", - "cloud/ListInstalledAppsResponse:total", - "cloud/ListReviewsRequest:listingId", - "cloud/ListReviewsRequest:page", - "cloud/ListReviewsRequest:pageSize", - "cloud/ListReviewsRequest:rating", - "cloud/ListReviewsRequest:sortBy", - "cloud/ListReviewsResponse:items", - "cloud/ListReviewsResponse:page", - "cloud/ListReviewsResponse:pageSize", - "cloud/ListReviewsResponse:ratingSummary", - "cloud/ListReviewsResponse:total", - "cloud/ListingActionRequest:action", - "cloud/ListingActionRequest:listingId", - "cloud/ListingActionRequest:reason", - "cloud/MarketplaceHealthMetrics:averageReviewTime", - "cloud/MarketplaceHealthMetrics:listingsByCategory", - "cloud/MarketplaceHealthMetrics:listingsByPricing", - "cloud/MarketplaceHealthMetrics:listingsByStatus", - "cloud/MarketplaceHealthMetrics:pendingReviews", - "cloud/MarketplaceHealthMetrics:snapshotAt", - "cloud/MarketplaceHealthMetrics:totalInstalls", - "cloud/MarketplaceHealthMetrics:totalListings", - "cloud/MarketplaceHealthMetrics:totalPublishers", - "cloud/MarketplaceHealthMetrics:verifiedPublishers", - "cloud/MarketplaceInstallRequest:artifactRef", - "cloud/MarketplaceInstallRequest:enableOnInstall", - "cloud/MarketplaceInstallRequest:licenseKey", - "cloud/MarketplaceInstallRequest:listingId", - "cloud/MarketplaceInstallRequest:settings", - "cloud/MarketplaceInstallRequest:tenantId", - "cloud/MarketplaceInstallRequest:version", - "cloud/MarketplaceInstallResponse:message", - "cloud/MarketplaceInstallResponse:packageId", - "cloud/MarketplaceInstallResponse:success", - "cloud/MarketplaceInstallResponse:version", - "cloud/MarketplaceListing:category", - "cloud/MarketplaceListing:description", - "cloud/MarketplaceListing:documentationUrl", - "cloud/MarketplaceListing:iconUrl", - "cloud/MarketplaceListing:id", - "cloud/MarketplaceListing:latestVersion", - "cloud/MarketplaceListing:minPlatformVersion", - "cloud/MarketplaceListing:name", - "cloud/MarketplaceListing:packageId", - "cloud/MarketplaceListing:packageType", - "cloud/MarketplaceListing:priceInCents", - "cloud/MarketplaceListing:pricing", - "cloud/MarketplaceListing:publishedAt", - "cloud/MarketplaceListing:publisherId", - "cloud/MarketplaceListing:repositoryUrl", - "cloud/MarketplaceListing:screenshots", - "cloud/MarketplaceListing:stats", - "cloud/MarketplaceListing:status", - "cloud/MarketplaceListing:supportUrl", - "cloud/MarketplaceListing:tagline", - "cloud/MarketplaceListing:tags", - "cloud/MarketplaceListing:translations", - "cloud/MarketplaceListing:updatedAt", - "cloud/MarketplaceListing:versions", - "cloud/MarketplaceSearchRequest:category", - "cloud/MarketplaceSearchRequest:page", - "cloud/MarketplaceSearchRequest:pageSize", - "cloud/MarketplaceSearchRequest:platformVersion", - "cloud/MarketplaceSearchRequest:pricing", - "cloud/MarketplaceSearchRequest:publisherVerification", - "cloud/MarketplaceSearchRequest:query", - "cloud/MarketplaceSearchRequest:sortBy", - "cloud/MarketplaceSearchRequest:sortDirection", - "cloud/MarketplaceSearchRequest:tags", - "cloud/MarketplaceSearchResponse:facets", - "cloud/MarketplaceSearchResponse:items", - "cloud/MarketplaceSearchResponse:page", - "cloud/MarketplaceSearchResponse:pageSize", - "cloud/MarketplaceSearchResponse:total", - "cloud/Package:category", - "cloud/Package:createdAt", - "cloud/Package:createdBy", - "cloud/Package:description", - "cloud/Package:displayName", - "cloud/Package:homepageUrl", - "cloud/Package:iconUrl", - "cloud/Package:id", - "cloud/Package:isStarter", - "cloud/Package:license", - "cloud/Package:manifestId", - "cloud/Package:namespace", - "cloud/Package:ownerOrgId", - "cloud/Package:publisher", - "cloud/Package:readme", - "cloud/Package:tags", - "cloud/Package:translations", - "cloud/Package:updatedAt", - "cloud/Package:visibility", - "cloud/PackageDependency:optional", - "cloud/PackageDependency:packageId", - "cloud/PackageDependency:versionRange", - "cloud/PackageInstallation:config", - "cloud/PackageInstallation:id", - "cloud/PackageInstallation:installedAt", - "cloud/PackageInstallation:installedBy", - "cloud/PackageInstallation:packageId", - "cloud/PackageInstallation:status", - "cloud/PackageInstallation:tenantId", - "cloud/PackageInstallation:updatedAt", - "cloud/PackageInstallation:version", - "cloud/PackageManifest:configurationSchema", - "cloud/PackageManifest:dependencies", - "cloud/PackageManifest:description", - "cloud/PackageManifest:id", - "cloud/PackageManifest:metadata", - "cloud/PackageManifest:metadataTypes", - "cloud/PackageManifest:migrations", - "cloud/PackageManifest:minPlatformVersion", - "cloud/PackageManifest:name", - "cloud/PackageManifest:scope", - "cloud/PackageManifest:version", - "cloud/PackageSubmission:artifactUrl", - "cloud/PackageSubmission:id", - "cloud/PackageSubmission:isNewListing", - "cloud/PackageSubmission:packageId", - "cloud/PackageSubmission:publisherId", - "cloud/PackageSubmission:releaseNotes", - "cloud/PackageSubmission:reviewedAt", - "cloud/PackageSubmission:reviewerNotes", - "cloud/PackageSubmission:scanResults", - "cloud/PackageSubmission:status", - "cloud/PackageSubmission:submittedAt", - "cloud/PackageSubmission:version", - "cloud/PackageTranslation:description", - "cloud/PackageTranslation:displayName", - "cloud/PackageTranslation:readme", - "cloud/PackageTranslation:screenshotCaptions", - "cloud/PackageTranslation:tagline", - "cloud/PackageVersion:checksum", - "cloud/PackageVersion:createdAt", - "cloud/PackageVersion:createdBy", - "cloud/PackageVersion:id", - "cloud/PackageVersion:isPreRelease", - "cloud/PackageVersion:manifestJson", - "cloud/PackageVersion:minPlatformVersion", - "cloud/PackageVersion:packageId", - "cloud/PackageVersion:publishedAt", - "cloud/PackageVersion:publishedBy", - "cloud/PackageVersion:releaseNotes", - "cloud/PackageVersion:status", - "cloud/PackageVersion:updatedAt", - "cloud/PackageVersion:version", - "cloud/PolicyAction:action", - "cloud/PolicyAction:actionAt", - "cloud/PolicyAction:actionBy", - "cloud/PolicyAction:id", - "cloud/PolicyAction:listingId", - "cloud/PolicyAction:reason", - "cloud/PolicyAction:resolution", - "cloud/PolicyAction:resolved", - "cloud/PolicyAction:violationType", - "cloud/ProvisionEnvironmentRequest:createdBy", - "cloud/ProvisionEnvironmentRequest:displayName", - "cloud/ProvisionEnvironmentRequest:driver", - "cloud/ProvisionEnvironmentRequest:hostname", - "cloud/ProvisionEnvironmentRequest:isDefault", - "cloud/ProvisionEnvironmentRequest:metadata", - "cloud/ProvisionEnvironmentRequest:organizationId", - "cloud/ProvisionEnvironmentRequest:plan", - "cloud/ProvisionEnvironmentRequest:storageLimitMb", - "cloud/ProvisionEnvironmentRequest:templateId", - "cloud/ProvisionEnvironmentRequest:visibility", - "cloud/ProvisionEnvironmentResponse:credential", - "cloud/ProvisionEnvironmentResponse:durationMs", - "cloud/ProvisionEnvironmentResponse:environment", - "cloud/ProvisionEnvironmentResponse:hostnameAssignment", - "cloud/ProvisionEnvironmentResponse:warnings", - "cloud/ProvisionOrganizationRequest:createdBy", - "cloud/ProvisionOrganizationRequest:defaultEnvironmentDisplayName", - "cloud/ProvisionOrganizationRequest:driver", - "cloud/ProvisionOrganizationRequest:metadata", - "cloud/ProvisionOrganizationRequest:organizationId", - "cloud/ProvisionOrganizationRequest:plan", - "cloud/ProvisionOrganizationRequest:storageLimitMb", - "cloud/ProvisionOrganizationResponse:defaultEnvironment", - "cloud/ProvisionOrganizationResponse:durationMs", - "cloud/ProvisionOrganizationResponse:warnings", - "cloud/ProvisionTenantRequest:metadata", - "cloud/ProvisionTenantRequest:organizationId", - "cloud/ProvisionTenantRequest:plan", - "cloud/ProvisionTenantRequest:region", - "cloud/ProvisionTenantRequest:storageLimitMb", - "cloud/ProvisionTenantResponse:durationMs", - "cloud/ProvisionTenantResponse:tenant", - "cloud/ProvisionTenantResponse:warnings", - "cloud/PublishPackageVersionRequest:publishedBy", - "cloud/Publisher:description", - "cloud/Publisher:email", - "cloud/Publisher:id", - "cloud/Publisher:logoUrl", - "cloud/Publisher:name", - "cloud/Publisher:registeredAt", - "cloud/Publisher:type", - "cloud/Publisher:verification", - "cloud/Publisher:website", - "cloud/PublisherProfile:agreementVersion", - "cloud/PublisherProfile:organizationId", - "cloud/PublisherProfile:publisherId", - "cloud/PublisherProfile:registeredAt", - "cloud/PublisherProfile:supportEmail", - "cloud/PublisherProfile:verification", - "cloud/PublisherProfile:website", - "cloud/PublishingAnalyticsRequest:listingId", - "cloud/PublishingAnalyticsRequest:metrics", - "cloud/PublishingAnalyticsRequest:timeRange", - "cloud/PublishingAnalyticsResponse:listingId", - "cloud/PublishingAnalyticsResponse:ratingDistribution", - "cloud/PublishingAnalyticsResponse:summary", - "cloud/PublishingAnalyticsResponse:timeRange", - "cloud/PublishingAnalyticsResponse:timeSeries", - "cloud/RecommendedApp:activeInstalls", - "cloud/RecommendedApp:averageRating", - "cloud/RecommendedApp:category", - "cloud/RecommendedApp:iconUrl", - "cloud/RecommendedApp:listingId", - "cloud/RecommendedApp:name", - "cloud/RecommendedApp:pricing", - "cloud/RecommendedApp:reason", - "cloud/RecommendedApp:tagline", - "cloud/ReviewCriterion:category", - "cloud/ReviewCriterion:description", - "cloud/ReviewCriterion:id", - "cloud/ReviewCriterion:notes", - "cloud/ReviewCriterion:passed", - "cloud/ReviewCriterion:required", - "cloud/RollbackEnvironmentPackageRequest:rolledBackBy", - "cloud/RollbackEnvironmentPackageRequest:targetPackageVersionId", - "cloud/SubmissionReview:completedAt", - "cloud/SubmissionReview:criteria", - "cloud/SubmissionReview:decision", - "cloud/SubmissionReview:feedback", - "cloud/SubmissionReview:id", - "cloud/SubmissionReview:internalNotes", - "cloud/SubmissionReview:rejectionReasons", - "cloud/SubmissionReview:reviewerId", - "cloud/SubmissionReview:startedAt", - "cloud/SubmissionReview:submissionId", - "cloud/SubmitReviewRequest:body", - "cloud/SubmitReviewRequest:listingId", - "cloud/SubmitReviewRequest:rating", - "cloud/SubmitReviewRequest:title", - "cloud/TemplateManifest:category", - "cloud/TemplateManifest:description", - "cloud/TemplateManifest:displayName", - "cloud/TemplateManifest:homepageUrl", - "cloud/TemplateManifest:iconUrl", - "cloud/TemplateManifest:isStarter", - "cloud/TemplateManifest:license", - "cloud/TemplateManifest:manifestId", - "cloud/TemplateManifest:name", - "cloud/TemplateManifest:namespace", - "cloud/TemplateManifest:preview", - "cloud/TemplateManifest:publisher", - "cloud/TemplateManifest:readmePath", - "cloud/TemplateManifest:scaffold", - "cloud/TemplateManifest:skills", - "cloud/TemplateManifest:specVersion", - "cloud/TemplateManifest:tags", - "cloud/TemplateManifest:translations", - "cloud/TemplateManifest:visibility", - "cloud/TenantContext:databaseUrl", - "cloud/TenantContext:metadata", - "cloud/TenantContext:organizationId", - "cloud/TenantContext:organizationSlug", - "cloud/TenantContext:plan", - "cloud/TenantContext:tenantId", - "cloud/TenantDatabase:authToken", - "cloud/TenantDatabase:createdAt", - "cloud/TenantDatabase:databaseName", - "cloud/TenantDatabase:databaseUrl", - "cloud/TenantDatabase:id", - "cloud/TenantDatabase:lastAccessedAt", - "cloud/TenantDatabase:metadata", - "cloud/TenantDatabase:organizationId", - "cloud/TenantDatabase:plan", - "cloud/TenantDatabase:region", - "cloud/TenantDatabase:status", - "cloud/TenantDatabase:storageLimitMb", - "cloud/TenantDatabase:updatedAt", - "cloud/TenantRoutingConfig:customDomainMapping", - "cloud/TenantRoutingConfig:defaultTenantId", - "cloud/TenantRoutingConfig:enabled", - "cloud/TenantRoutingConfig:identificationSources", - "cloud/TenantRoutingConfig:jwtOrganizationClaim", - "cloud/TenantRoutingConfig:subdomainPattern", - "cloud/TenantRoutingConfig:tenantHeaderName", - "cloud/TimeSeriesPoint:date", - "cloud/TimeSeriesPoint:value", - "cloud/TrendingListing:installVelocity", - "cloud/TrendingListing:listingId", - "cloud/TrendingListing:period", - "cloud/TrendingListing:rank", - "cloud/TrendingListing:trendScore", - "cloud/UpdateListingRequest:category", - "cloud/UpdateListingRequest:description", - "cloud/UpdateListingRequest:documentationUrl", - "cloud/UpdateListingRequest:iconUrl", - "cloud/UpdateListingRequest:listingId", - "cloud/UpdateListingRequest:name", - "cloud/UpdateListingRequest:priceInCents", - "cloud/UpdateListingRequest:pricing", - "cloud/UpdateListingRequest:repositoryUrl", - "cloud/UpdateListingRequest:screenshots", - "cloud/UpdateListingRequest:supportUrl", - "cloud/UpdateListingRequest:tagline", - "cloud/UpdateListingRequest:tags", - "cloud/UpdatePackageRequest:category", - "cloud/UpdatePackageRequest:description", - "cloud/UpdatePackageRequest:displayName", - "cloud/UpdatePackageRequest:homepageUrl", - "cloud/UpdatePackageRequest:iconUrl", - "cloud/UpdatePackageRequest:isStarter", - "cloud/UpdatePackageRequest:license", - "cloud/UpdatePackageRequest:publisher", - "cloud/UpdatePackageRequest:readme", - "cloud/UpdatePackageRequest:tags", - "cloud/UpdatePackageRequest:translations", - "cloud/UpdatePackageRequest:visibility", - "cloud/UpdatePackageVersionRequest:isPreRelease", - "cloud/UpdatePackageVersionRequest:manifestJson", - "cloud/UpdatePackageVersionRequest:releaseNotes", - "cloud/UpgradeEnvironmentPackageRequest:allowDraft", - "cloud/UpgradeEnvironmentPackageRequest:targetPackageVersionId", - "cloud/UpgradeEnvironmentPackageRequest:targetVersion", - "cloud/UpgradeEnvironmentPackageRequest:upgradedBy", - "cloud/UserReview:appVersion", - "cloud/UserReview:body", - "cloud/UserReview:displayName", - "cloud/UserReview:helpfulCount", - "cloud/UserReview:id", - "cloud/UserReview:listingId", - "cloud/UserReview:moderationStatus", - "cloud/UserReview:publisherResponse", - "cloud/UserReview:rating", - "cloud/UserReview:submittedAt", - "cloud/UserReview:title", - "cloud/UserReview:updatedAt", - "cloud/UserReview:userId", - "cloud/VersionRelease:artifactChecksum", - "cloud/VersionRelease:artifactUrl", - "cloud/VersionRelease:changelog", - "cloud/VersionRelease:channel", - "cloud/VersionRelease:deprecated", - "cloud/VersionRelease:deprecationMessage", - "cloud/VersionRelease:minPlatformVersion", - "cloud/VersionRelease:releaseNotes", - "cloud/VersionRelease:releasedAt", - "cloud/VersionRelease:version" - ] -} diff --git a/packages/spec/authorable-surface/marketplace.json b/packages/spec/authorable-surface/marketplace.json new file mode 100644 index 0000000000..bbf285ed0f --- /dev/null +++ b/packages/spec/authorable-surface/marketplace.json @@ -0,0 +1,195 @@ +{ + "description": "Ratchet of every AUTHORABLE key in one category of the spec — what a metadata author may write, which for this platform IS the third-party API. Sharded by category (#5837) so two PRs touching different categories never share a file; the gate reads the whole authorable-surface/ directory as ONE set, so deleting a shard deletes its keys exactly as deleting lines did. Auto-updated on additions (commit the change). A key that disappears without a tombstone fails gen:schema, because these schemas are not .strict() and Zod would silently strip it. \"[RETIRED]\" marks a tombstoned key that still rejects with an upgrade prescription. See #3855, ADR-0059 §5.", + "category": "marketplace", + "keys": [ + "marketplace/ArtifactDownloadResponse:downloadUrl", + "marketplace/ArtifactDownloadResponse:expiresAt", + "marketplace/ArtifactDownloadResponse:format", + "marketplace/ArtifactDownloadResponse:sha256", + "marketplace/ArtifactDownloadResponse:size", + "marketplace/ArtifactReference:format", + "marketplace/ArtifactReference:sha256", + "marketplace/ArtifactReference:size", + "marketplace/ArtifactReference:uploadedAt", + "marketplace/ArtifactReference:url", + "marketplace/CreatePackageRequest:category", + "marketplace/CreatePackageRequest:createdBy", + "marketplace/CreatePackageRequest:description", + "marketplace/CreatePackageRequest:displayName", + "marketplace/CreatePackageRequest:homepageUrl", + "marketplace/CreatePackageRequest:iconUrl", + "marketplace/CreatePackageRequest:isStarter", + "marketplace/CreatePackageRequest:license", + "marketplace/CreatePackageRequest:manifestId", + "marketplace/CreatePackageRequest:namespace", + "marketplace/CreatePackageRequest:ownerOrgId", + "marketplace/CreatePackageRequest:publisher", + "marketplace/CreatePackageRequest:tags", + "marketplace/CreatePackageRequest:translations", + "marketplace/CreatePackageRequest:visibility", + "marketplace/CreatePackageVersionRequest:createdBy", + "marketplace/CreatePackageVersionRequest:isPreRelease", + "marketplace/CreatePackageVersionRequest:manifestJson", + "marketplace/CreatePackageVersionRequest:packageId", + "marketplace/CreatePackageVersionRequest:releaseNotes", + "marketplace/CreatePackageVersionRequest:version", + "marketplace/MarketplaceInstallRequest:artifactRef", + "marketplace/MarketplaceInstallRequest:enableOnInstall", + "marketplace/MarketplaceInstallRequest:licenseKey", + "marketplace/MarketplaceInstallRequest:listingId", + "marketplace/MarketplaceInstallRequest:settings", + "marketplace/MarketplaceInstallRequest:tenantId", + "marketplace/MarketplaceInstallRequest:version", + "marketplace/MarketplaceInstallResponse:message", + "marketplace/MarketplaceInstallResponse:packageId", + "marketplace/MarketplaceInstallResponse:success", + "marketplace/MarketplaceInstallResponse:version", + "marketplace/MarketplaceListing:category", + "marketplace/MarketplaceListing:description", + "marketplace/MarketplaceListing:documentationUrl", + "marketplace/MarketplaceListing:iconUrl", + "marketplace/MarketplaceListing:id", + "marketplace/MarketplaceListing:latestVersion", + "marketplace/MarketplaceListing:minPlatformVersion", + "marketplace/MarketplaceListing:name", + "marketplace/MarketplaceListing:packageId", + "marketplace/MarketplaceListing:packageType", + "marketplace/MarketplaceListing:priceInCents", + "marketplace/MarketplaceListing:pricing", + "marketplace/MarketplaceListing:publishedAt", + "marketplace/MarketplaceListing:publisherId", + "marketplace/MarketplaceListing:repositoryUrl", + "marketplace/MarketplaceListing:screenshots", + "marketplace/MarketplaceListing:stats", + "marketplace/MarketplaceListing:status", + "marketplace/MarketplaceListing:supportUrl", + "marketplace/MarketplaceListing:tagline", + "marketplace/MarketplaceListing:tags", + "marketplace/MarketplaceListing:translations", + "marketplace/MarketplaceListing:updatedAt", + "marketplace/MarketplaceListing:versions", + "marketplace/MarketplaceSearchRequest:category", + "marketplace/MarketplaceSearchRequest:page", + "marketplace/MarketplaceSearchRequest:pageSize", + "marketplace/MarketplaceSearchRequest:platformVersion", + "marketplace/MarketplaceSearchRequest:pricing", + "marketplace/MarketplaceSearchRequest:publisherVerification", + "marketplace/MarketplaceSearchRequest:query", + "marketplace/MarketplaceSearchRequest:sortBy", + "marketplace/MarketplaceSearchRequest:sortDirection", + "marketplace/MarketplaceSearchRequest:tags", + "marketplace/MarketplaceSearchResponse:facets", + "marketplace/MarketplaceSearchResponse:items", + "marketplace/MarketplaceSearchResponse:page", + "marketplace/MarketplaceSearchResponse:pageSize", + "marketplace/MarketplaceSearchResponse:total", + "marketplace/Package:category", + "marketplace/Package:createdAt", + "marketplace/Package:createdBy", + "marketplace/Package:description", + "marketplace/Package:displayName", + "marketplace/Package:homepageUrl", + "marketplace/Package:iconUrl", + "marketplace/Package:id", + "marketplace/Package:isStarter", + "marketplace/Package:license", + "marketplace/Package:manifestId", + "marketplace/Package:namespace", + "marketplace/Package:ownerOrgId", + "marketplace/Package:publisher", + "marketplace/Package:readme", + "marketplace/Package:tags", + "marketplace/Package:translations", + "marketplace/Package:updatedAt", + "marketplace/Package:visibility", + "marketplace/PackageDependency:optional", + "marketplace/PackageDependency:packageId", + "marketplace/PackageDependency:versionRange", + "marketplace/PackageManifest:configurationSchema", + "marketplace/PackageManifest:dependencies", + "marketplace/PackageManifest:description", + "marketplace/PackageManifest:id", + "marketplace/PackageManifest:metadata", + "marketplace/PackageManifest:metadataTypes", + "marketplace/PackageManifest:migrations", + "marketplace/PackageManifest:minPlatformVersion", + "marketplace/PackageManifest:name", + "marketplace/PackageManifest:scope", + "marketplace/PackageManifest:version", + "marketplace/PackageSubmission:artifactUrl", + "marketplace/PackageSubmission:id", + "marketplace/PackageSubmission:isNewListing", + "marketplace/PackageSubmission:packageId", + "marketplace/PackageSubmission:publisherId", + "marketplace/PackageSubmission:releaseNotes", + "marketplace/PackageSubmission:reviewedAt", + "marketplace/PackageSubmission:reviewerNotes", + "marketplace/PackageSubmission:scanResults", + "marketplace/PackageSubmission:status", + "marketplace/PackageSubmission:submittedAt", + "marketplace/PackageSubmission:version", + "marketplace/PackageTranslation:description", + "marketplace/PackageTranslation:displayName", + "marketplace/PackageTranslation:readme", + "marketplace/PackageTranslation:screenshotCaptions", + "marketplace/PackageTranslation:tagline", + "marketplace/PackageVersion:checksum", + "marketplace/PackageVersion:createdAt", + "marketplace/PackageVersion:createdBy", + "marketplace/PackageVersion:id", + "marketplace/PackageVersion:isPreRelease", + "marketplace/PackageVersion:manifestJson", + "marketplace/PackageVersion:minPlatformVersion", + "marketplace/PackageVersion:packageId", + "marketplace/PackageVersion:publishedAt", + "marketplace/PackageVersion:publishedBy", + "marketplace/PackageVersion:releaseNotes", + "marketplace/PackageVersion:status", + "marketplace/PackageVersion:updatedAt", + "marketplace/PackageVersion:version", + "marketplace/PublishPackageVersionRequest:publishedBy", + "marketplace/Publisher:description", + "marketplace/Publisher:email", + "marketplace/Publisher:id", + "marketplace/Publisher:logoUrl", + "marketplace/Publisher:name", + "marketplace/Publisher:registeredAt", + "marketplace/Publisher:type", + "marketplace/Publisher:verification", + "marketplace/Publisher:website", + "marketplace/TemplateManifest:category", + "marketplace/TemplateManifest:description", + "marketplace/TemplateManifest:displayName", + "marketplace/TemplateManifest:homepageUrl", + "marketplace/TemplateManifest:iconUrl", + "marketplace/TemplateManifest:isStarter", + "marketplace/TemplateManifest:license", + "marketplace/TemplateManifest:manifestId", + "marketplace/TemplateManifest:name", + "marketplace/TemplateManifest:namespace", + "marketplace/TemplateManifest:preview", + "marketplace/TemplateManifest:publisher", + "marketplace/TemplateManifest:readmePath", + "marketplace/TemplateManifest:scaffold", + "marketplace/TemplateManifest:skills", + "marketplace/TemplateManifest:specVersion", + "marketplace/TemplateManifest:tags", + "marketplace/TemplateManifest:translations", + "marketplace/TemplateManifest:visibility", + "marketplace/UpdatePackageRequest:category", + "marketplace/UpdatePackageRequest:description", + "marketplace/UpdatePackageRequest:displayName", + "marketplace/UpdatePackageRequest:homepageUrl", + "marketplace/UpdatePackageRequest:iconUrl", + "marketplace/UpdatePackageRequest:isStarter", + "marketplace/UpdatePackageRequest:license", + "marketplace/UpdatePackageRequest:publisher", + "marketplace/UpdatePackageRequest:readme", + "marketplace/UpdatePackageRequest:tags", + "marketplace/UpdatePackageRequest:translations", + "marketplace/UpdatePackageRequest:visibility", + "marketplace/UpdatePackageVersionRequest:isPreRelease", + "marketplace/UpdatePackageVersionRequest:manifestJson", + "marketplace/UpdatePackageVersionRequest:releaseNotes" + ] +} diff --git a/packages/spec/browser-reachable-entries.json b/packages/spec/browser-reachable-entries.json index 3e016a50ab..3833f5a5c6 100644 --- a/packages/spec/browser-reachable-entries.json +++ b/packages/spec/browser-reachable-entries.json @@ -16,11 +16,11 @@ "./ai", "./api", "./automation", - "./cloud", "./data", "./identity", "./integration", "./kernel", + "./marketplace", "./qa", "./security", "./shared", diff --git a/packages/spec/declaration-map/api.json b/packages/spec/declaration-map/api.json index 774f94795f..aaca948358 100644 --- a/packages/spec/declaration-map/api.json +++ b/packages/spec/declaration-map/api.json @@ -243,6 +243,8 @@ "EndpointRegistrySchema": "api/EndpointRegistry", "EnhancedApiError": "api/EnhancedApiError", "EnhancedApiErrorSchema": "api/EnhancedApiError", + "EnvironmentType": "api/EnvironmentType", + "EnvironmentTypeSchema": "api/EnvironmentType", "ErrorCategory": "api/ErrorCategory", "ErrorCode": "api/ErrorCode", "ErrorHandlingConfig": "api/ErrorHandlingConfig", diff --git a/packages/spec/declaration-map/cloud.json b/packages/spec/declaration-map/cloud.json deleted file mode 100644 index f938ca97d3..0000000000 --- a/packages/spec/declaration-map/cloud.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "description": "TS declaration name → spec registry name (def key) for the schemas @objectstack/spec publishes: entries['ObjectSchemaBase'] === 'data/Object'. Composed from json-schema.manifest/ (the def keys), export-origins/ (which declaration each export resolves to), and a syntactic unwinding of wrapper initializers that recovers module-private base declarations (the ObjectSchemaBase case — see scripts/build-declaration-map.ts). A name that maps to two different def keys is DROPPED into `collisions` rather than guessed, so a lookup miss means \"not known to be an authorable container\". Consumers hold a changed line’s enclosing declaration name and ask which authorable container it declares (docs-audit anchor qualification is the funding one). Generated — never hand-edited; regenerate with `pnpm --filter @objectstack/spec gen:declaration-map` and read the diff.", - "category": "cloud", - "entries": { - "AnalyticsTimeRange": "cloud/AnalyticsTimeRange", - "AnalyticsTimeRangeSchema": "cloud/AnalyticsTimeRange", - "AppDiscoveryRequest": "cloud/AppDiscoveryRequest", - "AppDiscoveryRequestSchema": "cloud/AppDiscoveryRequest", - "AppDiscoveryResponse": "cloud/AppDiscoveryResponse", - "AppDiscoveryResponseSchema": "cloud/AppDiscoveryResponse", - "AppSubscription": "cloud/AppSubscription", - "AppSubscriptionSchema": "cloud/AppSubscription", - "ArtifactDownloadResponse": "cloud/ArtifactDownloadResponse", - "ArtifactDownloadResponseSchema": "cloud/ArtifactDownloadResponse", - "ArtifactReference": "cloud/ArtifactReference", - "ArtifactReferenceSchema": "cloud/ArtifactReference", - "CreateListingRequest": "cloud/CreateListingRequest", - "CreateListingRequestSchema": "cloud/CreateListingRequest", - "CreatePackageRequest": "cloud/CreatePackageRequest", - "CreatePackageRequestSchema": "cloud/CreatePackageRequest", - "CreatePackageVersionRequest": "cloud/CreatePackageVersionRequest", - "CreatePackageVersionRequestSchema": "cloud/CreatePackageVersionRequest", - "CuratedCollection": "cloud/CuratedCollection", - "CuratedCollectionSchema": "cloud/CuratedCollection", - "Environment": "cloud/Environment", - "EnvironmentCredential": "cloud/EnvironmentCredential", - "EnvironmentCredentialSchema": "cloud/EnvironmentCredential", - "EnvironmentCredentialStatus": "cloud/EnvironmentCredentialStatus", - "EnvironmentCredentialStatusSchema": "cloud/EnvironmentCredentialStatus", - "EnvironmentDriver": "cloud/EnvironmentDriver", - "EnvironmentDriverSchema": "cloud/EnvironmentDriver", - "EnvironmentMember": "cloud/EnvironmentMember", - "EnvironmentMemberSchema": "cloud/EnvironmentMember", - "EnvironmentPackageInstallation": "cloud/EnvironmentPackageInstallation", - "EnvironmentPackageInstallationSchema": "cloud/EnvironmentPackageInstallation", - "EnvironmentPackageStatus": "cloud/EnvironmentPackageStatus", - "EnvironmentPackageStatusSchema": "cloud/EnvironmentPackageStatus", - "EnvironmentRole": "cloud/EnvironmentRole", - "EnvironmentRoleSchema": "cloud/EnvironmentRole", - "EnvironmentSchema": "cloud/Environment", - "EnvironmentStatus": "cloud/EnvironmentStatus", - "EnvironmentStatusSchema": "cloud/EnvironmentStatus", - "EnvironmentType": "cloud/EnvironmentType", - "EnvironmentTypeSchema": "cloud/EnvironmentType", - "EnvironmentVisibility": "cloud/EnvironmentVisibility", - "EnvironmentVisibilitySchema": "cloud/EnvironmentVisibility", - "FeaturedListing": "cloud/FeaturedListing", - "FeaturedListingSchema": "cloud/FeaturedListing", - "InstallPackageToEnvironmentRequest": "cloud/InstallPackageToEnvironmentRequest", - "InstallPackageToEnvironmentRequestSchema": "cloud/InstallPackageToEnvironmentRequest", - "InstalledAppSummary": "cloud/InstalledAppSummary", - "InstalledAppSummarySchema": "cloud/InstalledAppSummary", - "ListEnvironmentPackagesResponse": "cloud/ListEnvironmentPackagesResponse", - "ListEnvironmentPackagesResponseSchema": "cloud/ListEnvironmentPackagesResponse", - "ListInstalledAppsRequest": "cloud/ListInstalledAppsRequest", - "ListInstalledAppsRequestSchema": "cloud/ListInstalledAppsRequest", - "ListInstalledAppsResponse": "cloud/ListInstalledAppsResponse", - "ListInstalledAppsResponseSchema": "cloud/ListInstalledAppsResponse", - "ListReviewsRequest": "cloud/ListReviewsRequest", - "ListReviewsRequestSchema": "cloud/ListReviewsRequest", - "ListReviewsResponse": "cloud/ListReviewsResponse", - "ListReviewsResponseSchema": "cloud/ListReviewsResponse", - "ListingActionRequest": "cloud/ListingActionRequest", - "ListingActionRequestSchema": "cloud/ListingActionRequest", - "ListingStatus": "cloud/ListingStatus", - "ListingStatusSchema": "cloud/ListingStatus", - "MarketplaceCategory": "cloud/MarketplaceCategory", - "MarketplaceCategorySchema": "cloud/MarketplaceCategory", - "MarketplaceHealthMetrics": "cloud/MarketplaceHealthMetrics", - "MarketplaceHealthMetricsSchema": "cloud/MarketplaceHealthMetrics", - "MarketplaceInstallRequest": "cloud/MarketplaceInstallRequest", - "MarketplaceInstallRequestSchema": "cloud/MarketplaceInstallRequest", - "MarketplaceInstallResponse": "cloud/MarketplaceInstallResponse", - "MarketplaceInstallResponseSchema": "cloud/MarketplaceInstallResponse", - "MarketplaceListing": "cloud/MarketplaceListing", - "MarketplaceListingSchema": "cloud/MarketplaceListing", - "MarketplaceSearchRequest": "cloud/MarketplaceSearchRequest", - "MarketplaceSearchRequestSchema": "cloud/MarketplaceSearchRequest", - "MarketplaceSearchResponse": "cloud/MarketplaceSearchResponse", - "MarketplaceSearchResponseSchema": "cloud/MarketplaceSearchResponse", - "Package": "cloud/Package", - "PackageCategory": "cloud/PackageCategory", - "PackageCategorySchema": "cloud/PackageCategory", - "PackageDependency": "cloud/PackageDependency", - "PackageDependencySchema": "cloud/PackageDependency", - "PackageInstallation": "cloud/PackageInstallation", - "PackageInstallationSchema": "cloud/PackageInstallation", - "PackageInstallationStatus": "cloud/PackageInstallationStatus", - "PackageInstallationStatusSchema": "cloud/PackageInstallationStatus", - "PackageLocale": "cloud/PackageLocale", - "PackageLocaleSchema": "cloud/PackageLocale", - "PackageManifest": "cloud/PackageManifest", - "PackageManifestSchema": "cloud/PackageManifest", - "PackagePublisher": "cloud/PackagePublisher", - "PackagePublisherSchema": "cloud/PackagePublisher", - "PackageSchema": "cloud/Package", - "PackageSubmission": "cloud/PackageSubmission", - "PackageSubmissionSchema": "cloud/PackageSubmission", - "PackageTranslation": "cloud/PackageTranslation", - "PackageTranslationSchema": "cloud/PackageTranslation", - "PackageTranslations": "cloud/PackageTranslations", - "PackageTranslationsSchema": "cloud/PackageTranslations", - "PackageVersion": "cloud/PackageVersion", - "PackageVersionSchema": "cloud/PackageVersion", - "PackageVersionStatus": "cloud/PackageVersionStatus", - "PackageVersionStatusSchema": "cloud/PackageVersionStatus", - "PackageVisibility": "cloud/PackageVisibility", - "PackageVisibilitySchema": "cloud/PackageVisibility", - "PolicyAction": "cloud/PolicyAction", - "PolicyActionSchema": "cloud/PolicyAction", - "PolicyViolationType": "cloud/PolicyViolationType", - "PolicyViolationTypeSchema": "cloud/PolicyViolationType", - "PricingModel": "cloud/PricingModel", - "PricingModelSchema": "cloud/PricingModel", - "ProvisionEnvironmentRequest": "cloud/ProvisionEnvironmentRequest", - "ProvisionEnvironmentRequestSchema": "cloud/ProvisionEnvironmentRequest", - "ProvisionEnvironmentResponse": "cloud/ProvisionEnvironmentResponse", - "ProvisionEnvironmentResponseSchema": "cloud/ProvisionEnvironmentResponse", - "ProvisionOrganizationRequest": "cloud/ProvisionOrganizationRequest", - "ProvisionOrganizationRequestSchema": "cloud/ProvisionOrganizationRequest", - "ProvisionOrganizationResponse": "cloud/ProvisionOrganizationResponse", - "ProvisionOrganizationResponseSchema": "cloud/ProvisionOrganizationResponse", - "ProvisionTenantRequest": "cloud/ProvisionTenantRequest", - "ProvisionTenantRequestSchema": "cloud/ProvisionTenantRequest", - "ProvisionTenantResponse": "cloud/ProvisionTenantResponse", - "ProvisionTenantResponseSchema": "cloud/ProvisionTenantResponse", - "PublishPackageVersionRequest": "cloud/PublishPackageVersionRequest", - "PublishPackageVersionRequestSchema": "cloud/PublishPackageVersionRequest", - "Publisher": "cloud/Publisher", - "PublisherProfile": "cloud/PublisherProfile", - "PublisherProfileSchema": "cloud/PublisherProfile", - "PublisherSchema": "cloud/Publisher", - "PublisherVerification": "cloud/PublisherVerification", - "PublisherVerificationSchema": "cloud/PublisherVerification", - "PublishingAnalyticsRequest": "cloud/PublishingAnalyticsRequest", - "PublishingAnalyticsRequestSchema": "cloud/PublishingAnalyticsRequest", - "PublishingAnalyticsResponse": "cloud/PublishingAnalyticsResponse", - "PublishingAnalyticsResponseSchema": "cloud/PublishingAnalyticsResponse", - "RecommendationReason": "cloud/RecommendationReason", - "RecommendationReasonSchema": "cloud/RecommendationReason", - "RecommendedApp": "cloud/RecommendedApp", - "RecommendedAppSchema": "cloud/RecommendedApp", - "RejectionReason": "cloud/RejectionReason", - "RejectionReasonSchema": "cloud/RejectionReason", - "ReleaseChannel": "cloud/ReleaseChannel", - "ReleaseChannelSchema": "cloud/ReleaseChannel", - "ReviewCriterion": "cloud/ReviewCriterion", - "ReviewCriterionSchema": "cloud/ReviewCriterion", - "ReviewDecision": "cloud/ReviewDecision", - "ReviewDecisionSchema": "cloud/ReviewDecision", - "ReviewModerationStatus": "cloud/ReviewModerationStatus", - "ReviewModerationStatusSchema": "cloud/ReviewModerationStatus", - "RollbackEnvironmentPackageRequest": "cloud/RollbackEnvironmentPackageRequest", - "RollbackEnvironmentPackageRequestSchema": "cloud/RollbackEnvironmentPackageRequest", - "SubmissionReview": "cloud/SubmissionReview", - "SubmissionReviewSchema": "cloud/SubmissionReview", - "SubmitReviewRequest": "cloud/SubmitReviewRequest", - "SubmitReviewRequestSchema": "cloud/SubmitReviewRequest", - "SubscriptionStatus": "cloud/SubscriptionStatus", - "SubscriptionStatusSchema": "cloud/SubscriptionStatus", - "TemplateManifest": "cloud/TemplateManifest", - "TemplateManifestSchema": "cloud/TemplateManifest", - "TenantContext": "cloud/TenantContext", - "TenantContextSchema": "cloud/TenantContext", - "TenantDatabase": "cloud/TenantDatabase", - "TenantDatabaseSchema": "cloud/TenantDatabase", - "TenantDatabaseStatus": "cloud/TenantDatabaseStatus", - "TenantDatabaseStatusSchema": "cloud/TenantDatabaseStatus", - "TenantIdentificationSource": "cloud/TenantIdentificationSource", - "TenantIdentificationSourceSchema": "cloud/TenantIdentificationSource", - "TenantPlan": "cloud/TenantPlan", - "TenantPlanSchema": "cloud/TenantPlan", - "TenantRoutingConfig": "cloud/TenantRoutingConfig", - "TenantRoutingConfigSchema": "cloud/TenantRoutingConfig", - "TimeSeriesPoint": "cloud/TimeSeriesPoint", - "TimeSeriesPointSchema": "cloud/TimeSeriesPoint", - "TrendingListing": "cloud/TrendingListing", - "TrendingListingSchema": "cloud/TrendingListing", - "UpdateListingRequest": "cloud/UpdateListingRequest", - "UpdateListingRequestSchema": "cloud/UpdateListingRequest", - "UpdatePackageRequest": "cloud/UpdatePackageRequest", - "UpdatePackageRequestSchema": "cloud/UpdatePackageRequest", - "UpdatePackageVersionRequest": "cloud/UpdatePackageVersionRequest", - "UpdatePackageVersionRequestSchema": "cloud/UpdatePackageVersionRequest", - "UpgradeEnvironmentPackageRequest": "cloud/UpgradeEnvironmentPackageRequest", - "UpgradeEnvironmentPackageRequestSchema": "cloud/UpgradeEnvironmentPackageRequest", - "UserReview": "cloud/UserReview", - "UserReviewSchema": "cloud/UserReview", - "VersionRelease": "cloud/VersionRelease", - "VersionReleaseSchema": "cloud/VersionRelease" - }, - "collisions": [] -} diff --git a/packages/spec/declaration-map/marketplace.json b/packages/spec/declaration-map/marketplace.json new file mode 100644 index 0000000000..d4fbf617fe --- /dev/null +++ b/packages/spec/declaration-map/marketplace.json @@ -0,0 +1,67 @@ +{ + "description": "TS declaration name → spec registry name (def key) for the schemas @objectstack/spec publishes: entries['ObjectSchemaBase'] === 'data/Object'. Composed from json-schema.manifest/ (the def keys), export-origins/ (which declaration each export resolves to), and a syntactic unwinding of wrapper initializers that recovers module-private base declarations (the ObjectSchemaBase case — see scripts/build-declaration-map.ts). A name that maps to two different def keys is DROPPED into `collisions` rather than guessed, so a lookup miss means \"not known to be an authorable container\". Consumers hold a changed line’s enclosing declaration name and ask which authorable container it declares (docs-audit anchor qualification is the funding one). Generated — never hand-edited; regenerate with `pnpm --filter @objectstack/spec gen:declaration-map` and read the diff.", + "category": "marketplace", + "entries": { + "ArtifactDownloadResponse": "marketplace/ArtifactDownloadResponse", + "ArtifactDownloadResponseSchema": "marketplace/ArtifactDownloadResponse", + "ArtifactReference": "marketplace/ArtifactReference", + "ArtifactReferenceSchema": "marketplace/ArtifactReference", + "CreatePackageRequest": "marketplace/CreatePackageRequest", + "CreatePackageRequestSchema": "marketplace/CreatePackageRequest", + "CreatePackageVersionRequest": "marketplace/CreatePackageVersionRequest", + "CreatePackageVersionRequestSchema": "marketplace/CreatePackageVersionRequest", + "ListingStatus": "marketplace/ListingStatus", + "ListingStatusSchema": "marketplace/ListingStatus", + "MarketplaceCategory": "marketplace/MarketplaceCategory", + "MarketplaceCategorySchema": "marketplace/MarketplaceCategory", + "MarketplaceInstallRequest": "marketplace/MarketplaceInstallRequest", + "MarketplaceInstallRequestSchema": "marketplace/MarketplaceInstallRequest", + "MarketplaceInstallResponse": "marketplace/MarketplaceInstallResponse", + "MarketplaceInstallResponseSchema": "marketplace/MarketplaceInstallResponse", + "MarketplaceListing": "marketplace/MarketplaceListing", + "MarketplaceListingSchema": "marketplace/MarketplaceListing", + "MarketplaceSearchRequest": "marketplace/MarketplaceSearchRequest", + "MarketplaceSearchRequestSchema": "marketplace/MarketplaceSearchRequest", + "MarketplaceSearchResponse": "marketplace/MarketplaceSearchResponse", + "MarketplaceSearchResponseSchema": "marketplace/MarketplaceSearchResponse", + "Package": "marketplace/Package", + "PackageCategory": "marketplace/PackageCategory", + "PackageCategorySchema": "marketplace/PackageCategory", + "PackageDependency": "marketplace/PackageDependency", + "PackageDependencySchema": "marketplace/PackageDependency", + "PackageLocale": "marketplace/PackageLocale", + "PackageLocaleSchema": "marketplace/PackageLocale", + "PackageManifest": "marketplace/PackageManifest", + "PackageManifestSchema": "marketplace/PackageManifest", + "PackagePublisher": "marketplace/PackagePublisher", + "PackagePublisherSchema": "marketplace/PackagePublisher", + "PackageSchema": "marketplace/Package", + "PackageSubmission": "marketplace/PackageSubmission", + "PackageSubmissionSchema": "marketplace/PackageSubmission", + "PackageTranslation": "marketplace/PackageTranslation", + "PackageTranslationSchema": "marketplace/PackageTranslation", + "PackageTranslations": "marketplace/PackageTranslations", + "PackageTranslationsSchema": "marketplace/PackageTranslations", + "PackageVersion": "marketplace/PackageVersion", + "PackageVersionSchema": "marketplace/PackageVersion", + "PackageVersionStatus": "marketplace/PackageVersionStatus", + "PackageVersionStatusSchema": "marketplace/PackageVersionStatus", + "PackageVisibility": "marketplace/PackageVisibility", + "PackageVisibilitySchema": "marketplace/PackageVisibility", + "PricingModel": "marketplace/PricingModel", + "PricingModelSchema": "marketplace/PricingModel", + "PublishPackageVersionRequest": "marketplace/PublishPackageVersionRequest", + "PublishPackageVersionRequestSchema": "marketplace/PublishPackageVersionRequest", + "Publisher": "marketplace/Publisher", + "PublisherSchema": "marketplace/Publisher", + "PublisherVerification": "marketplace/PublisherVerification", + "PublisherVerificationSchema": "marketplace/PublisherVerification", + "TemplateManifest": "marketplace/TemplateManifest", + "TemplateManifestSchema": "marketplace/TemplateManifest", + "UpdatePackageRequest": "marketplace/UpdatePackageRequest", + "UpdatePackageRequestSchema": "marketplace/UpdatePackageRequest", + "UpdatePackageVersionRequest": "marketplace/UpdatePackageVersionRequest", + "UpdatePackageVersionRequestSchema": "marketplace/UpdatePackageVersionRequest" + }, + "collisions": [] +} diff --git a/packages/spec/export-origins/api.json b/packages/spec/export-origins/api.json index 883f2289d3..36256fd3d2 100644 --- a/packages/spec/export-origins/api.json +++ b/packages/spec/export-origins/api.json @@ -327,6 +327,8 @@ "EnhancedApiError": "src/api/errors.zod.ts#EnhancedApiError (type)", "EnhancedApiErrorParsed": "src/api/errors.zod.ts#EnhancedApiErrorParsed (type)", "EnhancedApiErrorSchema": "src/api/errors.zod.ts#EnhancedApiErrorSchema (const)", + "EnvironmentType": "src/api/discovery.zod.ts#EnvironmentType (type)", + "EnvironmentTypeSchema": "src/api/discovery.zod.ts#EnvironmentTypeSchema (const)", "ErrorCategory": "src/api/errors.zod.ts#ErrorCategory (type)", "ErrorCode": "src/api/error-code-ledger.zod.ts#ErrorCode (type)", "ErrorHandlingConfig": "src/api/plugin-rest-api.zod.ts#ErrorHandlingConfig (type)", diff --git a/packages/spec/export-origins/cloud.json b/packages/spec/export-origins/cloud.json deleted file mode 100644 index 88e863050b..0000000000 --- a/packages/spec/export-origins/cloud.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "description": "Which SOURCE DECLARATION each name exported by one public entry point of @objectstack/spec resolves to, after its alias chain is unwound: `# ()`. Two exports share an origin string iff they are the same declaration — so equal origins across two entries are a harmless re-export, and different origins under one name are the #4411 dual-source trap. Generated from src/ (no build needed) and read by the export-surface pin tests, which compare against it instead of each building their own ts.createProgram — that was ~55s of compilation per CI lap and a non-deterministic timeout that ejected unrelated PRs from the merge queue (#4796). Sharded by entry point (#5837) so two retirement PRs never share a file. Carries NO line numbers: the pins asserted the line as `\\d+`, and recording it would rewrite this artifact on every edit that shifts a line in any .zod.ts. Regenerate with `pnpm --filter @objectstack/spec gen:export-origins` and read the diff.", - "entry": "./cloud", - "exports": { - "AnalyticsTimeRange": "src/cloud/developer-portal.zod.ts#AnalyticsTimeRange (type)", - "AnalyticsTimeRangeSchema": "src/cloud/developer-portal.zod.ts#AnalyticsTimeRangeSchema (const)", - "AppDiscoveryRequest": "src/cloud/app-store.zod.ts#AppDiscoveryRequest (type)", - "AppDiscoveryRequestParsed": "src/cloud/app-store.zod.ts#AppDiscoveryRequestParsed (type)", - "AppDiscoveryRequestSchema": "src/cloud/app-store.zod.ts#AppDiscoveryRequestSchema (const)", - "AppDiscoveryResponse": "src/cloud/app-store.zod.ts#AppDiscoveryResponse (type)", - "AppDiscoveryResponseSchema": "src/cloud/app-store.zod.ts#AppDiscoveryResponseSchema (const)", - "AppSubscription": "src/cloud/app-store.zod.ts#AppSubscription (type)", - "AppSubscriptionParsed": "src/cloud/app-store.zod.ts#AppSubscriptionParsed (type)", - "AppSubscriptionSchema": "src/cloud/app-store.zod.ts#AppSubscriptionSchema (const)", - "ArtifactDownloadResponse": "src/cloud/marketplace.zod.ts#ArtifactDownloadResponse (type)", - "ArtifactDownloadResponseSchema": "src/cloud/marketplace.zod.ts#ArtifactDownloadResponseSchema (const)", - "ArtifactReference": "src/cloud/marketplace.zod.ts#ArtifactReference (type)", - "ArtifactReferenceParsed": "src/cloud/marketplace.zod.ts#ArtifactReferenceParsed (type)", - "ArtifactReferenceSchema": "src/cloud/marketplace.zod.ts#ArtifactReferenceSchema (const)", - "CreateListingRequest": "src/cloud/developer-portal.zod.ts#CreateListingRequest (type)", - "CreateListingRequestParsed": "src/cloud/developer-portal.zod.ts#CreateListingRequestParsed (type)", - "CreateListingRequestSchema": "src/cloud/developer-portal.zod.ts#CreateListingRequestSchema (const)", - "CreatePackageRequest": "src/cloud/package.zod.ts#CreatePackageRequest (type)", - "CreatePackageRequestSchema": "src/cloud/package.zod.ts#CreatePackageRequestSchema (const)", - "CreatePackageVersionRequest": "src/cloud/package-version.zod.ts#CreatePackageVersionRequest (type)", - "CreatePackageVersionRequestSchema": "src/cloud/package-version.zod.ts#CreatePackageVersionRequestSchema (const)", - "CuratedCollection": "src/cloud/marketplace-admin.zod.ts#CuratedCollection (type)", - "CuratedCollectionParsed": "src/cloud/marketplace-admin.zod.ts#CuratedCollectionParsed (type)", - "CuratedCollectionSchema": "src/cloud/marketplace-admin.zod.ts#CuratedCollectionSchema (const)", - "Environment": "src/cloud/environment.zod.ts#Environment (type)", - "EnvironmentArtifact": "src/system/environment-artifact.zod.ts#EnvironmentArtifact (type)", - "EnvironmentArtifactParsed": "src/system/environment-artifact.zod.ts#EnvironmentArtifactParsed (type)", - "EnvironmentArtifactSchema": "src/system/environment-artifact.zod.ts#EnvironmentArtifactSchema (const)", - "EnvironmentCredential": "src/cloud/environment.zod.ts#EnvironmentCredential (type)", - "EnvironmentCredentialParsed": "src/cloud/environment.zod.ts#EnvironmentCredentialParsed (type)", - "EnvironmentCredentialSchema": "src/cloud/environment.zod.ts#EnvironmentCredentialSchema (const)", - "EnvironmentCredentialStatus": "src/cloud/environment.zod.ts#EnvironmentCredentialStatus (type)", - "EnvironmentCredentialStatusSchema": "src/cloud/environment.zod.ts#EnvironmentCredentialStatusSchema (const)", - "EnvironmentDriver": "src/cloud/environment.zod.ts#EnvironmentDriver (type)", - "EnvironmentDriverSchema": "src/cloud/environment.zod.ts#EnvironmentDriverSchema (const)", - "EnvironmentMember": "src/cloud/environment.zod.ts#EnvironmentMember (type)", - "EnvironmentMemberSchema": "src/cloud/environment.zod.ts#EnvironmentMemberSchema (const)", - "EnvironmentPackageInstallation": "src/cloud/environment-package.zod.ts#EnvironmentPackageInstallation (type)", - "EnvironmentPackageInstallationParsed": "src/cloud/environment-package.zod.ts#EnvironmentPackageInstallationParsed (type)", - "EnvironmentPackageInstallationSchema": "src/cloud/environment-package.zod.ts#EnvironmentPackageInstallationSchema (const)", - "EnvironmentPackageStatus": "src/cloud/environment-package.zod.ts#EnvironmentPackageStatus (type)", - "EnvironmentPackageStatusSchema": "src/cloud/environment-package.zod.ts#EnvironmentPackageStatusSchema (const)", - "EnvironmentParsed": "src/cloud/environment.zod.ts#EnvironmentParsed (type)", - "EnvironmentRole": "src/cloud/environment.zod.ts#EnvironmentRole (type)", - "EnvironmentRoleSchema": "src/cloud/environment.zod.ts#EnvironmentRoleSchema (const)", - "EnvironmentSchema": "src/cloud/environment.zod.ts#EnvironmentSchema (const)", - "EnvironmentStatus": "src/cloud/environment.zod.ts#EnvironmentStatus (type)", - "EnvironmentStatusSchema": "src/cloud/environment.zod.ts#EnvironmentStatusSchema (const)", - "EnvironmentType": "src/cloud/environment.zod.ts#EnvironmentType (type)", - "EnvironmentTypeSchema": "src/cloud/environment.zod.ts#EnvironmentTypeSchema (const)", - "EnvironmentVisibility": "src/cloud/environment.zod.ts#EnvironmentVisibility (type)", - "EnvironmentVisibilitySchema": "src/cloud/environment.zod.ts#EnvironmentVisibilitySchema (const)", - "FeaturedListing": "src/cloud/marketplace-admin.zod.ts#FeaturedListing (type)", - "FeaturedListingParsed": "src/cloud/marketplace-admin.zod.ts#FeaturedListingParsed (type)", - "FeaturedListingSchema": "src/cloud/marketplace-admin.zod.ts#FeaturedListingSchema (const)", - "InstallPackageToEnvironmentRequest": "src/cloud/environment-package.zod.ts#InstallPackageToEnvironmentRequest (type)", - "InstallPackageToEnvironmentRequestParsed": "src/cloud/environment-package.zod.ts#InstallPackageToEnvironmentRequestParsed (type)", - "InstallPackageToEnvironmentRequestSchema": "src/cloud/environment-package.zod.ts#InstallPackageToEnvironmentRequestSchema (const)", - "InstalledAppSummary": "src/cloud/app-store.zod.ts#InstalledAppSummary (type)", - "InstalledAppSummaryParsed": "src/cloud/app-store.zod.ts#InstalledAppSummaryParsed (type)", - "InstalledAppSummarySchema": "src/cloud/app-store.zod.ts#InstalledAppSummarySchema (const)", - "ListEnvironmentPackagesResponse": "src/cloud/environment-package.zod.ts#ListEnvironmentPackagesResponse (type)", - "ListEnvironmentPackagesResponseParsed": "src/cloud/environment-package.zod.ts#ListEnvironmentPackagesResponseParsed (type)", - "ListEnvironmentPackagesResponseSchema": "src/cloud/environment-package.zod.ts#ListEnvironmentPackagesResponseSchema (const)", - "ListInstalledAppsRequest": "src/cloud/app-store.zod.ts#ListInstalledAppsRequest (type)", - "ListInstalledAppsRequestParsed": "src/cloud/app-store.zod.ts#ListInstalledAppsRequestParsed (type)", - "ListInstalledAppsRequestSchema": "src/cloud/app-store.zod.ts#ListInstalledAppsRequestSchema (const)", - "ListInstalledAppsResponse": "src/cloud/app-store.zod.ts#ListInstalledAppsResponse (type)", - "ListInstalledAppsResponseParsed": "src/cloud/app-store.zod.ts#ListInstalledAppsResponseParsed (type)", - "ListInstalledAppsResponseSchema": "src/cloud/app-store.zod.ts#ListInstalledAppsResponseSchema (const)", - "ListReviewsRequest": "src/cloud/app-store.zod.ts#ListReviewsRequest (type)", - "ListReviewsRequestParsed": "src/cloud/app-store.zod.ts#ListReviewsRequestParsed (type)", - "ListReviewsRequestSchema": "src/cloud/app-store.zod.ts#ListReviewsRequestSchema (const)", - "ListReviewsResponse": "src/cloud/app-store.zod.ts#ListReviewsResponse (type)", - "ListReviewsResponseParsed": "src/cloud/app-store.zod.ts#ListReviewsResponseParsed (type)", - "ListReviewsResponseSchema": "src/cloud/app-store.zod.ts#ListReviewsResponseSchema (const)", - "ListingActionRequest": "src/cloud/developer-portal.zod.ts#ListingActionRequest (type)", - "ListingActionRequestSchema": "src/cloud/developer-portal.zod.ts#ListingActionRequestSchema (const)", - "ListingStatus": "src/cloud/marketplace.zod.ts#ListingStatus (type)", - "ListingStatusSchema": "src/cloud/marketplace.zod.ts#ListingStatusSchema (const)", - "MarketplaceCategory": "src/cloud/marketplace.zod.ts#MarketplaceCategory (type)", - "MarketplaceCategorySchema": "src/cloud/marketplace.zod.ts#MarketplaceCategorySchema (const)", - "MarketplaceHealthMetrics": "src/cloud/marketplace-admin.zod.ts#MarketplaceHealthMetrics (type)", - "MarketplaceHealthMetricsSchema": "src/cloud/marketplace-admin.zod.ts#MarketplaceHealthMetricsSchema (const)", - "MarketplaceInstallRequest": "src/cloud/marketplace.zod.ts#MarketplaceInstallRequest (type)", - "MarketplaceInstallRequestParsed": "src/cloud/marketplace.zod.ts#MarketplaceInstallRequestParsed (type)", - "MarketplaceInstallRequestSchema": "src/cloud/marketplace.zod.ts#MarketplaceInstallRequestSchema (const)", - "MarketplaceInstallResponse": "src/cloud/marketplace.zod.ts#MarketplaceInstallResponse (type)", - "MarketplaceInstallResponseSchema": "src/cloud/marketplace.zod.ts#MarketplaceInstallResponseSchema (const)", - "MarketplaceListing": "src/cloud/marketplace.zod.ts#MarketplaceListing (type)", - "MarketplaceListingParsed": "src/cloud/marketplace.zod.ts#MarketplaceListingParsed (type)", - "MarketplaceListingSchema": "src/cloud/marketplace.zod.ts#MarketplaceListingSchema (const)", - "MarketplaceSearchRequest": "src/cloud/marketplace.zod.ts#MarketplaceSearchRequest (type)", - "MarketplaceSearchRequestParsed": "src/cloud/marketplace.zod.ts#MarketplaceSearchRequestParsed (type)", - "MarketplaceSearchRequestSchema": "src/cloud/marketplace.zod.ts#MarketplaceSearchRequestSchema (const)", - "MarketplaceSearchResponse": "src/cloud/marketplace.zod.ts#MarketplaceSearchResponse (type)", - "MarketplaceSearchResponseParsed": "src/cloud/marketplace.zod.ts#MarketplaceSearchResponseParsed (type)", - "MarketplaceSearchResponseSchema": "src/cloud/marketplace.zod.ts#MarketplaceSearchResponseSchema (const)", - "Package": "src/cloud/package.zod.ts#Package (type)", - "PackageCategory": "src/cloud/package.zod.ts#PackageCategory (type)", - "PackageCategorySchema": "src/cloud/package.zod.ts#PackageCategorySchema (const)", - "PackageDependency": "src/cloud/package-version.zod.ts#PackageDependency (type)", - "PackageDependencyParsed": "src/cloud/package-version.zod.ts#PackageDependencyParsed (type)", - "PackageDependencySchema": "src/cloud/package-version.zod.ts#PackageDependencySchema (const)", - "PackageInstallation": "src/cloud/tenant.zod.ts#PackageInstallation (type)", - "PackageInstallationParsed": "src/cloud/tenant.zod.ts#PackageInstallationParsed (type)", - "PackageInstallationSchema": "src/cloud/tenant.zod.ts#PackageInstallationSchema (const)", - "PackageInstallationStatus": "src/cloud/tenant.zod.ts#PackageInstallationStatus (type)", - "PackageInstallationStatusSchema": "src/cloud/tenant.zod.ts#PackageInstallationStatusSchema (const)", - "PackageL10nField": "src/cloud/package-l10n.ts#PackageL10nField (type)", - "PackageLocale": "src/cloud/package.zod.ts#PackageLocale (type)", - "PackageLocaleSchema": "src/cloud/package.zod.ts#PackageLocaleSchema (const)", - "PackageManifest": "src/cloud/package-version.zod.ts#PackageManifest (type)", - "PackageManifestParsed": "src/cloud/package-version.zod.ts#PackageManifestParsed (type)", - "PackageManifestSchema": "src/cloud/package-version.zod.ts#PackageManifestSchema (const)", - "PackageParsed": "src/cloud/package.zod.ts#PackageParsed (type)", - "PackagePublisher": "src/cloud/package.zod.ts#PackagePublisher (type)", - "PackagePublisherSchema": "src/cloud/package.zod.ts#PackagePublisherSchema (const)", - "PackageSchema": "src/cloud/package.zod.ts#PackageSchema (const)", - "PackageSubmission": "src/cloud/marketplace.zod.ts#PackageSubmission (type)", - "PackageSubmissionParsed": "src/cloud/marketplace.zod.ts#PackageSubmissionParsed (type)", - "PackageSubmissionSchema": "src/cloud/marketplace.zod.ts#PackageSubmissionSchema (const)", - "PackageTranslation": "src/cloud/package.zod.ts#PackageTranslation (type)", - "PackageTranslationSchema": "src/cloud/package.zod.ts#PackageTranslationSchema (const)", - "PackageTranslations": "src/cloud/package.zod.ts#PackageTranslations (type)", - "PackageTranslationsSchema": "src/cloud/package.zod.ts#PackageTranslationsSchema (const)", - "PackageVersion": "src/cloud/package-version.zod.ts#PackageVersion (type)", - "PackageVersionParsed": "src/cloud/package-version.zod.ts#PackageVersionParsed (type)", - "PackageVersionSchema": "src/cloud/package-version.zod.ts#PackageVersionSchema (const)", - "PackageVersionStatus": "src/cloud/package-version.zod.ts#PackageVersionStatus (type)", - "PackageVersionStatusSchema": "src/cloud/package-version.zod.ts#PackageVersionStatusSchema (const)", - "PackageVisibility": "src/cloud/package.zod.ts#PackageVisibility (type)", - "PackageVisibilitySchema": "src/cloud/package.zod.ts#PackageVisibilitySchema (const)", - "PolicyAction": "src/cloud/marketplace-admin.zod.ts#PolicyAction (type)", - "PolicyActionParsed": "src/cloud/marketplace-admin.zod.ts#PolicyActionParsed (type)", - "PolicyActionSchema": "src/cloud/marketplace-admin.zod.ts#PolicyActionSchema (const)", - "PolicyViolationType": "src/cloud/marketplace-admin.zod.ts#PolicyViolationType (type)", - "PolicyViolationTypeSchema": "src/cloud/marketplace-admin.zod.ts#PolicyViolationTypeSchema (const)", - "PricingModel": "src/cloud/marketplace.zod.ts#PricingModel (type)", - "PricingModelSchema": "src/cloud/marketplace.zod.ts#PricingModelSchema (const)", - "ProvisionEnvironmentRequest": "src/cloud/environment.zod.ts#ProvisionEnvironmentRequest (type)", - "ProvisionEnvironmentRequestParsed": "src/cloud/environment.zod.ts#ProvisionEnvironmentRequestParsed (type)", - "ProvisionEnvironmentRequestSchema": "src/cloud/environment.zod.ts#ProvisionEnvironmentRequestSchema (const)", - "ProvisionEnvironmentResponse": "src/cloud/environment.zod.ts#ProvisionEnvironmentResponse (type)", - "ProvisionEnvironmentResponseParsed": "src/cloud/environment.zod.ts#ProvisionEnvironmentResponseParsed (type)", - "ProvisionEnvironmentResponseSchema": "src/cloud/environment.zod.ts#ProvisionEnvironmentResponseSchema (const)", - "ProvisionOrganizationRequest": "src/cloud/environment.zod.ts#ProvisionOrganizationRequest (type)", - "ProvisionOrganizationRequestParsed": "src/cloud/environment.zod.ts#ProvisionOrganizationRequestParsed (type)", - "ProvisionOrganizationRequestSchema": "src/cloud/environment.zod.ts#ProvisionOrganizationRequestSchema (const)", - "ProvisionOrganizationResponse": "src/cloud/environment.zod.ts#ProvisionOrganizationResponse (type)", - "ProvisionOrganizationResponseParsed": "src/cloud/environment.zod.ts#ProvisionOrganizationResponseParsed (type)", - "ProvisionOrganizationResponseSchema": "src/cloud/environment.zod.ts#ProvisionOrganizationResponseSchema (const)", - "ProvisionTenantRequest": "src/cloud/tenant.zod.ts#ProvisionTenantRequest (type)", - "ProvisionTenantRequestParsed": "src/cloud/tenant.zod.ts#ProvisionTenantRequestParsed (type)", - "ProvisionTenantRequestSchema": "src/cloud/tenant.zod.ts#ProvisionTenantRequestSchema (const)", - "ProvisionTenantResponse": "src/cloud/tenant.zod.ts#ProvisionTenantResponse (type)", - "ProvisionTenantResponseParsed": "src/cloud/tenant.zod.ts#ProvisionTenantResponseParsed (type)", - "ProvisionTenantResponseSchema": "src/cloud/tenant.zod.ts#ProvisionTenantResponseSchema (const)", - "PublishPackageVersionRequest": "src/cloud/package-version.zod.ts#PublishPackageVersionRequest (type)", - "PublishPackageVersionRequestSchema": "src/cloud/package-version.zod.ts#PublishPackageVersionRequestSchema (const)", - "Publisher": "src/cloud/marketplace.zod.ts#Publisher (type)", - "PublisherParsed": "src/cloud/marketplace.zod.ts#PublisherParsed (type)", - "PublisherProfile": "src/cloud/developer-portal.zod.ts#PublisherProfile (type)", - "PublisherProfileParsed": "src/cloud/developer-portal.zod.ts#PublisherProfileParsed (type)", - "PublisherProfileSchema": "src/cloud/developer-portal.zod.ts#PublisherProfileSchema (const)", - "PublisherSchema": "src/cloud/marketplace.zod.ts#PublisherSchema (const)", - "PublisherVerification": "src/cloud/marketplace.zod.ts#PublisherVerification (type)", - "PublisherVerificationSchema": "src/cloud/marketplace.zod.ts#PublisherVerificationSchema (const)", - "PublishingAnalyticsRequest": "src/cloud/developer-portal.zod.ts#PublishingAnalyticsRequest (type)", - "PublishingAnalyticsRequestParsed": "src/cloud/developer-portal.zod.ts#PublishingAnalyticsRequestParsed (type)", - "PublishingAnalyticsRequestSchema": "src/cloud/developer-portal.zod.ts#PublishingAnalyticsRequestSchema (const)", - "PublishingAnalyticsResponse": "src/cloud/developer-portal.zod.ts#PublishingAnalyticsResponse (type)", - "PublishingAnalyticsResponseParsed": "src/cloud/developer-portal.zod.ts#PublishingAnalyticsResponseParsed (type)", - "PublishingAnalyticsResponseSchema": "src/cloud/developer-portal.zod.ts#PublishingAnalyticsResponseSchema (const)", - "RecommendationReason": "src/cloud/app-store.zod.ts#RecommendationReason (type)", - "RecommendationReasonSchema": "src/cloud/app-store.zod.ts#RecommendationReasonSchema (const)", - "RecommendedApp": "src/cloud/app-store.zod.ts#RecommendedApp (type)", - "RecommendedAppSchema": "src/cloud/app-store.zod.ts#RecommendedAppSchema (const)", - "RejectionReason": "src/cloud/marketplace-admin.zod.ts#RejectionReason (type)", - "RejectionReasonSchema": "src/cloud/marketplace-admin.zod.ts#RejectionReasonSchema (const)", - "ReleaseChannel": "src/cloud/developer-portal.zod.ts#ReleaseChannel (type)", - "ReleaseChannelSchema": "src/cloud/developer-portal.zod.ts#ReleaseChannelSchema (const)", - "ResolvePackageL10nOptions": "src/cloud/package-l10n.ts#ResolvePackageL10nOptions (interface)", - "ReviewCriterion": "src/cloud/marketplace-admin.zod.ts#ReviewCriterion (type)", - "ReviewCriterionParsed": "src/cloud/marketplace-admin.zod.ts#ReviewCriterionParsed (type)", - "ReviewCriterionSchema": "src/cloud/marketplace-admin.zod.ts#ReviewCriterionSchema (const)", - "ReviewDecision": "src/cloud/marketplace-admin.zod.ts#ReviewDecision (type)", - "ReviewDecisionSchema": "src/cloud/marketplace-admin.zod.ts#ReviewDecisionSchema (const)", - "ReviewModerationStatus": "src/cloud/app-store.zod.ts#ReviewModerationStatus (type)", - "ReviewModerationStatusSchema": "src/cloud/app-store.zod.ts#ReviewModerationStatusSchema (const)", - "RollbackEnvironmentPackageRequest": "src/cloud/environment-package.zod.ts#RollbackEnvironmentPackageRequest (type)", - "RollbackEnvironmentPackageRequestSchema": "src/cloud/environment-package.zod.ts#RollbackEnvironmentPackageRequestSchema (const)", - "Sha256Digest": "src/system/environment-artifact.zod.ts#Sha256Digest (type)", - "Sha256DigestSchema": "src/system/environment-artifact.zod.ts#Sha256DigestSchema (const)", - "SubmissionReview": "src/cloud/marketplace-admin.zod.ts#SubmissionReview (type)", - "SubmissionReviewParsed": "src/cloud/marketplace-admin.zod.ts#SubmissionReviewParsed (type)", - "SubmissionReviewSchema": "src/cloud/marketplace-admin.zod.ts#SubmissionReviewSchema (const)", - "SubmitReviewRequest": "src/cloud/app-store.zod.ts#SubmitReviewRequest (type)", - "SubmitReviewRequestSchema": "src/cloud/app-store.zod.ts#SubmitReviewRequestSchema (const)", - "SubscriptionStatus": "src/cloud/app-store.zod.ts#SubscriptionStatus (type)", - "SubscriptionStatusSchema": "src/cloud/app-store.zod.ts#SubscriptionStatusSchema (const)", - "TemplateManifest": "src/cloud/template-manifest.zod.ts#TemplateManifest (type)", - "TemplateManifestSchema": "src/cloud/template-manifest.zod.ts#TemplateManifestSchema (const)", - "TenantContext": "src/cloud/tenant.zod.ts#TenantContext (type)", - "TenantContextSchema": "src/cloud/tenant.zod.ts#TenantContextSchema (const)", - "TenantDatabase": "src/cloud/tenant.zod.ts#TenantDatabase (type)", - "TenantDatabaseParsed": "src/cloud/tenant.zod.ts#TenantDatabaseParsed (type)", - "TenantDatabaseSchema": "src/cloud/tenant.zod.ts#TenantDatabaseSchema (const)", - "TenantDatabaseStatus": "src/cloud/tenant.zod.ts#TenantDatabaseStatus (type)", - "TenantDatabaseStatusSchema": "src/cloud/tenant.zod.ts#TenantDatabaseStatusSchema (const)", - "TenantIdentificationSource": "src/cloud/tenant.zod.ts#TenantIdentificationSource (type)", - "TenantIdentificationSourceSchema": "src/cloud/tenant.zod.ts#TenantIdentificationSourceSchema (const)", - "TenantPlan": "src/cloud/tenant.zod.ts#TenantPlan (type)", - "TenantPlanSchema": "src/cloud/tenant.zod.ts#TenantPlanSchema (const)", - "TenantRoutingConfig": "src/cloud/tenant.zod.ts#TenantRoutingConfig (type)", - "TenantRoutingConfigParsed": "src/cloud/tenant.zod.ts#TenantRoutingConfigParsed (type)", - "TenantRoutingConfigSchema": "src/cloud/tenant.zod.ts#TenantRoutingConfigSchema (const)", - "TimeSeriesPoint": "src/cloud/developer-portal.zod.ts#TimeSeriesPoint (type)", - "TimeSeriesPointSchema": "src/cloud/developer-portal.zod.ts#TimeSeriesPointSchema (const)", - "TrendingListing": "src/cloud/marketplace-admin.zod.ts#TrendingListing (type)", - "TrendingListingSchema": "src/cloud/marketplace-admin.zod.ts#TrendingListingSchema (const)", - "UpdateListingRequest": "src/cloud/developer-portal.zod.ts#UpdateListingRequest (type)", - "UpdateListingRequestSchema": "src/cloud/developer-portal.zod.ts#UpdateListingRequestSchema (const)", - "UpdatePackageRequest": "src/cloud/package.zod.ts#UpdatePackageRequest (type)", - "UpdatePackageRequestSchema": "src/cloud/package.zod.ts#UpdatePackageRequestSchema (const)", - "UpdatePackageVersionRequest": "src/cloud/package-version.zod.ts#UpdatePackageVersionRequest (type)", - "UpdatePackageVersionRequestSchema": "src/cloud/package-version.zod.ts#UpdatePackageVersionRequestSchema (const)", - "UpgradeEnvironmentPackageRequest": "src/cloud/environment-package.zod.ts#UpgradeEnvironmentPackageRequest (type)", - "UpgradeEnvironmentPackageRequestParsed": "src/cloud/environment-package.zod.ts#UpgradeEnvironmentPackageRequestParsed (type)", - "UpgradeEnvironmentPackageRequestSchema": "src/cloud/environment-package.zod.ts#UpgradeEnvironmentPackageRequestSchema (const)", - "UserReview": "src/cloud/app-store.zod.ts#UserReview (type)", - "UserReviewParsed": "src/cloud/app-store.zod.ts#UserReviewParsed (type)", - "UserReviewSchema": "src/cloud/app-store.zod.ts#UserReviewSchema (const)", - "VersionRelease": "src/cloud/developer-portal.zod.ts#VersionRelease (type)", - "VersionReleaseParsed": "src/cloud/developer-portal.zod.ts#VersionReleaseParsed (type)", - "VersionReleaseSchema": "src/cloud/developer-portal.zod.ts#VersionReleaseSchema (const)", - "resolvePackageL10n": "src/cloud/package-l10n.ts#resolvePackageL10n (function)", - "resolvePackageL10nField": "src/cloud/package-l10n.ts#resolvePackageL10nField (function)", - "resolveScreenshotCaptions": "src/cloud/package-l10n.ts#resolveScreenshotCaptions (function)" - } -} diff --git a/packages/spec/export-origins/marketplace.json b/packages/spec/export-origins/marketplace.json new file mode 100644 index 0000000000..f57afc7808 --- /dev/null +++ b/packages/spec/export-origins/marketplace.json @@ -0,0 +1,82 @@ +{ + "description": "Which SOURCE DECLARATION each name exported by one public entry point of @objectstack/spec resolves to, after its alias chain is unwound: `# ()`. Two exports share an origin string iff they are the same declaration — so equal origins across two entries are a harmless re-export, and different origins under one name are the #4411 dual-source trap. Generated from src/ (no build needed) and read by the export-surface pin tests, which compare against it instead of each building their own ts.createProgram — that was ~55s of compilation per CI lap and a non-deterministic timeout that ejected unrelated PRs from the merge queue (#4796). Sharded by entry point (#5837) so two retirement PRs never share a file. Carries NO line numbers: the pins asserted the line as `\\d+`, and recording it would rewrite this artifact on every edit that shifts a line in any .zod.ts. Regenerate with `pnpm --filter @objectstack/spec gen:export-origins` and read the diff.", + "entry": "./marketplace", + "exports": { + "ArtifactDownloadResponse": "src/marketplace/marketplace.zod.ts#ArtifactDownloadResponse (type)", + "ArtifactDownloadResponseSchema": "src/marketplace/marketplace.zod.ts#ArtifactDownloadResponseSchema (const)", + "ArtifactReference": "src/marketplace/marketplace.zod.ts#ArtifactReference (type)", + "ArtifactReferenceParsed": "src/marketplace/marketplace.zod.ts#ArtifactReferenceParsed (type)", + "ArtifactReferenceSchema": "src/marketplace/marketplace.zod.ts#ArtifactReferenceSchema (const)", + "CreatePackageRequest": "src/marketplace/package.zod.ts#CreatePackageRequest (type)", + "CreatePackageRequestSchema": "src/marketplace/package.zod.ts#CreatePackageRequestSchema (const)", + "CreatePackageVersionRequest": "src/marketplace/package-version.zod.ts#CreatePackageVersionRequest (type)", + "CreatePackageVersionRequestSchema": "src/marketplace/package-version.zod.ts#CreatePackageVersionRequestSchema (const)", + "ListingStatus": "src/marketplace/marketplace.zod.ts#ListingStatus (type)", + "ListingStatusSchema": "src/marketplace/marketplace.zod.ts#ListingStatusSchema (const)", + "MarketplaceCategory": "src/marketplace/marketplace.zod.ts#MarketplaceCategory (type)", + "MarketplaceCategorySchema": "src/marketplace/marketplace.zod.ts#MarketplaceCategorySchema (const)", + "MarketplaceInstallRequest": "src/marketplace/marketplace.zod.ts#MarketplaceInstallRequest (type)", + "MarketplaceInstallRequestParsed": "src/marketplace/marketplace.zod.ts#MarketplaceInstallRequestParsed (type)", + "MarketplaceInstallRequestSchema": "src/marketplace/marketplace.zod.ts#MarketplaceInstallRequestSchema (const)", + "MarketplaceInstallResponse": "src/marketplace/marketplace.zod.ts#MarketplaceInstallResponse (type)", + "MarketplaceInstallResponseSchema": "src/marketplace/marketplace.zod.ts#MarketplaceInstallResponseSchema (const)", + "MarketplaceListing": "src/marketplace/marketplace.zod.ts#MarketplaceListing (type)", + "MarketplaceListingParsed": "src/marketplace/marketplace.zod.ts#MarketplaceListingParsed (type)", + "MarketplaceListingSchema": "src/marketplace/marketplace.zod.ts#MarketplaceListingSchema (const)", + "MarketplaceSearchRequest": "src/marketplace/marketplace.zod.ts#MarketplaceSearchRequest (type)", + "MarketplaceSearchRequestParsed": "src/marketplace/marketplace.zod.ts#MarketplaceSearchRequestParsed (type)", + "MarketplaceSearchRequestSchema": "src/marketplace/marketplace.zod.ts#MarketplaceSearchRequestSchema (const)", + "MarketplaceSearchResponse": "src/marketplace/marketplace.zod.ts#MarketplaceSearchResponse (type)", + "MarketplaceSearchResponseParsed": "src/marketplace/marketplace.zod.ts#MarketplaceSearchResponseParsed (type)", + "MarketplaceSearchResponseSchema": "src/marketplace/marketplace.zod.ts#MarketplaceSearchResponseSchema (const)", + "Package": "src/marketplace/package.zod.ts#Package (type)", + "PackageCategory": "src/marketplace/package.zod.ts#PackageCategory (type)", + "PackageCategorySchema": "src/marketplace/package.zod.ts#PackageCategorySchema (const)", + "PackageDependency": "src/marketplace/package-version.zod.ts#PackageDependency (type)", + "PackageDependencyParsed": "src/marketplace/package-version.zod.ts#PackageDependencyParsed (type)", + "PackageDependencySchema": "src/marketplace/package-version.zod.ts#PackageDependencySchema (const)", + "PackageL10nField": "src/marketplace/package-l10n.ts#PackageL10nField (type)", + "PackageLocale": "src/marketplace/package.zod.ts#PackageLocale (type)", + "PackageLocaleSchema": "src/marketplace/package.zod.ts#PackageLocaleSchema (const)", + "PackageManifest": "src/marketplace/package-version.zod.ts#PackageManifest (type)", + "PackageManifestParsed": "src/marketplace/package-version.zod.ts#PackageManifestParsed (type)", + "PackageManifestSchema": "src/marketplace/package-version.zod.ts#PackageManifestSchema (const)", + "PackageParsed": "src/marketplace/package.zod.ts#PackageParsed (type)", + "PackagePublisher": "src/marketplace/package.zod.ts#PackagePublisher (type)", + "PackagePublisherSchema": "src/marketplace/package.zod.ts#PackagePublisherSchema (const)", + "PackageSchema": "src/marketplace/package.zod.ts#PackageSchema (const)", + "PackageSubmission": "src/marketplace/marketplace.zod.ts#PackageSubmission (type)", + "PackageSubmissionParsed": "src/marketplace/marketplace.zod.ts#PackageSubmissionParsed (type)", + "PackageSubmissionSchema": "src/marketplace/marketplace.zod.ts#PackageSubmissionSchema (const)", + "PackageTranslation": "src/marketplace/package.zod.ts#PackageTranslation (type)", + "PackageTranslationSchema": "src/marketplace/package.zod.ts#PackageTranslationSchema (const)", + "PackageTranslations": "src/marketplace/package.zod.ts#PackageTranslations (type)", + "PackageTranslationsSchema": "src/marketplace/package.zod.ts#PackageTranslationsSchema (const)", + "PackageVersion": "src/marketplace/package-version.zod.ts#PackageVersion (type)", + "PackageVersionParsed": "src/marketplace/package-version.zod.ts#PackageVersionParsed (type)", + "PackageVersionSchema": "src/marketplace/package-version.zod.ts#PackageVersionSchema (const)", + "PackageVersionStatus": "src/marketplace/package-version.zod.ts#PackageVersionStatus (type)", + "PackageVersionStatusSchema": "src/marketplace/package-version.zod.ts#PackageVersionStatusSchema (const)", + "PackageVisibility": "src/marketplace/package.zod.ts#PackageVisibility (type)", + "PackageVisibilitySchema": "src/marketplace/package.zod.ts#PackageVisibilitySchema (const)", + "PricingModel": "src/marketplace/marketplace.zod.ts#PricingModel (type)", + "PricingModelSchema": "src/marketplace/marketplace.zod.ts#PricingModelSchema (const)", + "PublishPackageVersionRequest": "src/marketplace/package-version.zod.ts#PublishPackageVersionRequest (type)", + "PublishPackageVersionRequestSchema": "src/marketplace/package-version.zod.ts#PublishPackageVersionRequestSchema (const)", + "Publisher": "src/marketplace/marketplace.zod.ts#Publisher (type)", + "PublisherParsed": "src/marketplace/marketplace.zod.ts#PublisherParsed (type)", + "PublisherSchema": "src/marketplace/marketplace.zod.ts#PublisherSchema (const)", + "PublisherVerification": "src/marketplace/marketplace.zod.ts#PublisherVerification (type)", + "PublisherVerificationSchema": "src/marketplace/marketplace.zod.ts#PublisherVerificationSchema (const)", + "ResolvePackageL10nOptions": "src/marketplace/package-l10n.ts#ResolvePackageL10nOptions (interface)", + "TemplateManifest": "src/marketplace/template-manifest.zod.ts#TemplateManifest (type)", + "TemplateManifestSchema": "src/marketplace/template-manifest.zod.ts#TemplateManifestSchema (const)", + "UpdatePackageRequest": "src/marketplace/package.zod.ts#UpdatePackageRequest (type)", + "UpdatePackageRequestSchema": "src/marketplace/package.zod.ts#UpdatePackageRequestSchema (const)", + "UpdatePackageVersionRequest": "src/marketplace/package-version.zod.ts#UpdatePackageVersionRequest (type)", + "UpdatePackageVersionRequestSchema": "src/marketplace/package-version.zod.ts#UpdatePackageVersionRequestSchema (const)", + "resolvePackageL10n": "src/marketplace/package-l10n.ts#resolvePackageL10n (function)", + "resolvePackageL10nField": "src/marketplace/package-l10n.ts#resolvePackageL10nField (function)", + "resolveScreenshotCaptions": "src/marketplace/package-l10n.ts#resolveScreenshotCaptions (function)" + } +} diff --git a/packages/spec/json-schema.manifest/api.json b/packages/spec/json-schema.manifest/api.json index 6bea8f1451..299e71d049 100644 --- a/packages/spec/json-schema.manifest/api.json +++ b/packages/spec/json-schema.manifest/api.json @@ -134,6 +134,7 @@ "api/EnablePackageResponse", "api/EndpointRegistry", "api/EnhancedApiError", + "api/EnvironmentType", "api/ErrorCategory", "api/ErrorCode", "api/ErrorHandlingConfig", diff --git a/packages/spec/json-schema.manifest/cloud.json b/packages/spec/json-schema.manifest/cloud.json deleted file mode 100644 index f8d158eee3..0000000000 --- a/packages/spec/json-schema.manifest/cloud.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "description": "Ratchet manifest of every JSON Schema emitted by scripts/build-schemas.ts for one category. Sharded by category (#5837); the gate reads the whole json-schema.manifest/ directory as ONE set. Auto-appended when new schemas are added (commit the change). A listed schema that a build no longer emits fails gen:schema. DELETING a key is gated too (#4725): the removal is measured against this directory at the merge base with origin/main — which the commit under test cannot rewrite — and every def that leaves the published set must be declared in RETIRED_DEFS_BY_MAJOR (src/migrations/registry.ts), or in RENAMED_DEFS (scripts/lib/renamed-defs.ts) when it is a rename rather than a removal. See #2978, #4725.", - "category": "cloud", - "schemas": [ - "cloud/AnalyticsTimeRange", - "cloud/AppDiscoveryRequest", - "cloud/AppDiscoveryResponse", - "cloud/AppSubscription", - "cloud/ArtifactDownloadResponse", - "cloud/ArtifactReference", - "cloud/CreateListingRequest", - "cloud/CreatePackageRequest", - "cloud/CreatePackageVersionRequest", - "cloud/CuratedCollection", - "cloud/Environment", - "cloud/EnvironmentCredential", - "cloud/EnvironmentCredentialStatus", - "cloud/EnvironmentDriver", - "cloud/EnvironmentMember", - "cloud/EnvironmentPackageInstallation", - "cloud/EnvironmentPackageStatus", - "cloud/EnvironmentRole", - "cloud/EnvironmentStatus", - "cloud/EnvironmentType", - "cloud/EnvironmentVisibility", - "cloud/FeaturedListing", - "cloud/InstallPackageToEnvironmentRequest", - "cloud/InstalledAppSummary", - "cloud/ListEnvironmentPackagesResponse", - "cloud/ListInstalledAppsRequest", - "cloud/ListInstalledAppsResponse", - "cloud/ListReviewsRequest", - "cloud/ListReviewsResponse", - "cloud/ListingActionRequest", - "cloud/ListingStatus", - "cloud/MarketplaceCategory", - "cloud/MarketplaceHealthMetrics", - "cloud/MarketplaceInstallRequest", - "cloud/MarketplaceInstallResponse", - "cloud/MarketplaceListing", - "cloud/MarketplaceSearchRequest", - "cloud/MarketplaceSearchResponse", - "cloud/Package", - "cloud/PackageCategory", - "cloud/PackageDependency", - "cloud/PackageInstallation", - "cloud/PackageInstallationStatus", - "cloud/PackageLocale", - "cloud/PackageManifest", - "cloud/PackagePublisher", - "cloud/PackageSubmission", - "cloud/PackageTranslation", - "cloud/PackageTranslations", - "cloud/PackageVersion", - "cloud/PackageVersionStatus", - "cloud/PackageVisibility", - "cloud/PolicyAction", - "cloud/PolicyViolationType", - "cloud/PricingModel", - "cloud/ProvisionEnvironmentRequest", - "cloud/ProvisionEnvironmentResponse", - "cloud/ProvisionOrganizationRequest", - "cloud/ProvisionOrganizationResponse", - "cloud/ProvisionTenantRequest", - "cloud/ProvisionTenantResponse", - "cloud/PublishPackageVersionRequest", - "cloud/Publisher", - "cloud/PublisherProfile", - "cloud/PublisherVerification", - "cloud/PublishingAnalyticsRequest", - "cloud/PublishingAnalyticsResponse", - "cloud/RecommendationReason", - "cloud/RecommendedApp", - "cloud/RejectionReason", - "cloud/ReleaseChannel", - "cloud/ReviewCriterion", - "cloud/ReviewDecision", - "cloud/ReviewModerationStatus", - "cloud/RollbackEnvironmentPackageRequest", - "cloud/Sha256Digest", - "cloud/SubmissionReview", - "cloud/SubmitReviewRequest", - "cloud/SubscriptionStatus", - "cloud/TemplateManifest", - "cloud/TenantContext", - "cloud/TenantDatabase", - "cloud/TenantDatabaseStatus", - "cloud/TenantIdentificationSource", - "cloud/TenantPlan", - "cloud/TenantRoutingConfig", - "cloud/TimeSeriesPoint", - "cloud/TrendingListing", - "cloud/UpdateListingRequest", - "cloud/UpdatePackageRequest", - "cloud/UpdatePackageVersionRequest", - "cloud/UpgradeEnvironmentPackageRequest", - "cloud/UserReview", - "cloud/VersionRelease" - ] -} diff --git a/packages/spec/json-schema.manifest/marketplace.json b/packages/spec/json-schema.manifest/marketplace.json new file mode 100644 index 0000000000..73c1c27f0b --- /dev/null +++ b/packages/spec/json-schema.manifest/marketplace.json @@ -0,0 +1,36 @@ +{ + "description": "Ratchet manifest of every JSON Schema emitted by scripts/build-schemas.ts for one category. Sharded by category (#5837); the gate reads the whole json-schema.manifest/ directory as ONE set. Auto-appended when new schemas are added (commit the change). A listed schema that a build no longer emits fails gen:schema. DELETING a key is gated too (#4725): the removal is measured against this directory at the merge base with origin/main — which the commit under test cannot rewrite — and every def that leaves the published set must be declared in RETIRED_DEFS_BY_MAJOR (src/migrations/registry.ts), or in RENAMED_DEFS (scripts/lib/renamed-defs.ts) when it is a rename rather than a removal. See #2978, #4725.", + "category": "marketplace", + "schemas": [ + "marketplace/ArtifactDownloadResponse", + "marketplace/ArtifactReference", + "marketplace/CreatePackageRequest", + "marketplace/CreatePackageVersionRequest", + "marketplace/ListingStatus", + "marketplace/MarketplaceCategory", + "marketplace/MarketplaceInstallRequest", + "marketplace/MarketplaceInstallResponse", + "marketplace/MarketplaceListing", + "marketplace/MarketplaceSearchRequest", + "marketplace/MarketplaceSearchResponse", + "marketplace/Package", + "marketplace/PackageCategory", + "marketplace/PackageDependency", + "marketplace/PackageLocale", + "marketplace/PackageManifest", + "marketplace/PackagePublisher", + "marketplace/PackageSubmission", + "marketplace/PackageTranslation", + "marketplace/PackageTranslations", + "marketplace/PackageVersion", + "marketplace/PackageVersionStatus", + "marketplace/PackageVisibility", + "marketplace/PricingModel", + "marketplace/PublishPackageVersionRequest", + "marketplace/Publisher", + "marketplace/PublisherVerification", + "marketplace/TemplateManifest", + "marketplace/UpdatePackageRequest", + "marketplace/UpdatePackageVersionRequest" + ] +} diff --git a/packages/spec/llms.txt b/packages/spec/llms.txt index 40bc8372c6..fc3bf3a893 100644 --- a/packages/spec/llms.txt +++ b/packages/spec/llms.txt @@ -77,7 +77,7 @@ const query = { --- -## 3. Schema Inventory by Domain (205 schemas) +## 3. Schema Inventory by Domain (198 schemas) Counted as `*.zod.ts` modules under `packages/spec/src//` — the sources that ship in this tarball (`files` includes `src/**/*.zod.ts`), so every number @@ -93,8 +93,8 @@ here is verifiable from the installed package. | automation | 13 | Flow, Approval, BPMN Interop, Control Flow, State Machine, Webhook | | shared | 14 | Enums, HTTP, Identifiers, Mapping, Metadata Types, Connector Auth, Retry Policy, Value Domain, Epoch Instant (EpochMs) | | ai | 11 | Agent, Conversation, Knowledge Source/Document, Model Registry, MCP, Skill, Tool | -| cloud | 11 | Marketplace, Developer Portal, App Store, Environment, Package, Tenant | | identity | 5 | Identity, Organization, Position, SCIM, Eval User | +| marketplace | 4 | Marketplace, Package, Package Version, Template Manifest | | security | 4 | Permission, RLS, Sharing, Explain | | studio | 3 | Flow Builder, Object Designer, Studio Plugin | | integration | 1 | Connector | diff --git a/packages/spec/package.json b/packages/spec/package.json index 8af62b08ce..2b5bd7cd7d 100644 --- a/packages/spec/package.json +++ b/packages/spec/package.json @@ -167,24 +167,14 @@ "default": "./dist/studio/index.js" } }, - "./cloud": { - "browser": { - "import": { - "types": "./dist/cloud/index.d.mts", - "default": "./dist/browser/cloud/index.mjs" - }, - "require": { - "types": "./dist/cloud/index.d.ts", - "default": "./dist/browser/cloud/index.js" - } - }, + "./marketplace": { "import": { - "types": "./dist/cloud/index.d.mts", - "default": "./dist/cloud/index.mjs" + "types": "./dist/marketplace/index.d.mts", + "default": "./dist/marketplace/index.mjs" }, "require": { - "types": "./dist/cloud/index.d.ts", - "default": "./dist/cloud/index.js" + "types": "./dist/marketplace/index.d.ts", + "default": "./dist/marketplace/index.js" } }, "./qa": { diff --git a/packages/spec/scripts/authorable-defaults.test.ts b/packages/spec/scripts/authorable-defaults.test.ts index e5e44720b2..39e8be58de 100644 --- a/packages/spec/scripts/authorable-defaults.test.ts +++ b/packages/spec/scripts/authorable-defaults.test.ts @@ -31,6 +31,7 @@ import { NO_DEFAULT, authorableDefaultsShardTexts, authoriseDefaultChanges, + carryDefaultsThroughRenames, collectAuthorableDefaults, defaultFingerprintOf, diffAuthorableDefaults, @@ -213,6 +214,61 @@ describe('diffAuthorableDefaults — the discrimination the gate rests on', () = }); }); +describe('carryDefaultsThroughRenames — a declared def rename moves no default (#16325)', () => { + // The exact shape measured on the cloud → marketplace category move: the + // OLD def's default under the OLD key at the baseline, the SAME value under + // the NEW key in this build, and a key-set the gate already carries. + const RENAMES = { 'cloud/Package': 'marketplace/Package' } as const; + const OLD = 'cloud/Package:visibility'; + const NEW = 'marketplace/Package:visibility'; + + it('carries the baseline default onto the renamed def, so the diff reports nothing', () => { + const baseline = carryDefaultsThroughRenames(new Map([[OLD, '"private"']]), RENAMES); + expect([...baseline]).toEqual([[NEW, '"private"']]); + expect( + diffAuthorableDefaults({ + baseline, + current: new Map([[NEW, '"private"']]), + baselineKeys: live(NEW), // the key-set half is carried by the gate already + currentKeys: live(NEW), + }), + ).toEqual([]); + }); + + it('is the discriminating half: WITHOUT the carry the same rename reads as an `added` flip', () => { + // Negative control — what the gate reported before this helper existed + // (22 such findings on #16325): a key the carried key-set says already + // existed, with no baseline default under its new name. + expect( + diffAuthorableDefaults({ + baseline: new Map([[OLD, '"private"']]), + current: new Map([[NEW, '"private"']]), + baselineKeys: live(NEW), + currentKeys: live(NEW), + }), + ).toEqual([{ key: NEW, kind: 'added', from: NO_DEFAULT, to: '"private"' }]); + }); + + it('still catches a default that REALLY moved across the rename', () => { + const baseline = carryDefaultsThroughRenames(new Map([[OLD, '"private"']]), RENAMES); + expect( + diffAuthorableDefaults({ + baseline, + current: new Map([[NEW, '"org"']]), + baselineKeys: live(NEW), + currentKeys: live(NEW), + }), + ).toEqual([{ key: NEW, kind: 'changed', from: '"private"', to: '"org"' }]); + }); + + it('leaves a key whose def is not declared renamed untouched, fingerprint included', () => { + const carried = carryDefaultsThroughRenames(new Map([[RETRY, '3'], [OLD, '"private"']]), RENAMES); + expect(carried.get(RETRY)).toBe('3'); + expect(carried.has(OLD)).toBe(false); + expect(carried.get(NEW)).toBe('"private"'); + }); +}); + describe('authoriseDefaultChanges — the acknowledged-change exit stays honest', () => { const change = { key: RETRY, kind: 'changed', from: '0', to: '3' } as const; const declare = (over: Partial = {}): DeclaredDefaultChange => ({ diff --git a/packages/spec/scripts/build-docs.ts b/packages/spec/scripts/build-docs.ts index 010cdaea39..0da1d529d8 100644 --- a/packages/spec/scripts/build-docs.ts +++ b/packages/spec/scripts/build-docs.ts @@ -556,11 +556,6 @@ const SECTION_GROUPS: Record { section: 'Integration & Data', pages: ['connector', 'webhook', 'bpmn-interop'] }, { section: 'Approvals & Jobs', pages: ['approval', 'job'] }, ], - cloud: [ - { section: 'Environments & Packages', pages: ['environment', 'environment-artifact', 'environment-package', 'package', 'package-version', 'template-manifest', 'provisioning'] }, - { section: 'Marketplace & Distribution', pages: ['marketplace', 'marketplace-admin', 'app-store', 'developer-portal'] }, - { section: 'Tenancy & Security', pages: ['tenant', 'plugin-security'] }, - ], data: [ { section: 'Objects & Fields', pages: ['object', 'field', 'validation', 'hook', 'hook-body', 'mapping'] }, { section: 'Query & Analytics', pages: ['query', 'filter', 'data-engine', 'analytics', 'date-macros'] }, @@ -596,6 +591,15 @@ const SECTION_GROUPS: Record { section: 'Packages', pages: ['package-artifact', 'package-registry', 'package-upgrade'] }, { section: 'Metadata & Runtime', pages: ['metadata-plugin', 'metadata-loader', 'metadata-protection', 'metadata-persistence', 'misc', 'context', 'execution-context', 'service-registry', 'startup-orchestrator', 'cluster', 'feature', 'cli-extension', 'dev-plugin', 'state-machine'] }, ], + // [#16325] The package & marketplace FORMAT half of what used to be `cloud/`. + // The cloud control plane's own contracts (environment, environment-package, + // tenant, developer-portal, marketplace-admin, app-store) left the open-source + // spec with the `./cloud` subpath; `environment-artifact` was only ever a + // re-export of the `system/` declaration and is documented there. + marketplace: [ + { section: 'Packages & Versions', pages: ['package', 'package-version', 'template-manifest'] }, + { section: 'Marketplace', pages: ['marketplace'] }, + ], system: [ { section: 'Config & Settings', pages: ['settings-manifest', 'settings-client', 'registry-config', 'auth-config', 'email-config', 'email-template', 'license', 'migration', 'deploy-bundle', 'environment-artifact', 'app-install', 'provisioning', 'tenant'] }, // `metadata-loader` removed at #4696 — that file lives in `kernel/`, and the @@ -693,13 +697,13 @@ const CATEGORY_BLURBS: Record = { ai: 'Agents, tools, skills, RAG and knowledge sources, model registry, conversations.', api: 'REST contracts, endpoints, routing, realtime, batch, discovery.', automation: 'Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records.', - cloud: 'Environments, packages and versions, marketplace, developer portal, tenancy.', data: 'Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer.', // "API keys" deliberately absent since #8715: the sys_api_key table is // declared by @objectstack/platform-objects, not by a spec identity schema. identity: 'Users and accounts, organizations, positions, SCIM provisioning.', integration: 'The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances.', kernel: 'Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry.', + marketplace: 'The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests.', qa: 'Declarative test suites — scenarios, steps, actions and assertions.', security: 'Permission sets, row-level security, sharing rules, tenancy posture.', shared: 'Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums.', diff --git a/packages/spec/scripts/build-schemas.ts b/packages/spec/scripts/build-schemas.ts index c15199abb8..e16316dfa5 100644 --- a/packages/spec/scripts/build-schemas.ts +++ b/packages/spec/scripts/build-schemas.ts @@ -66,6 +66,7 @@ import { AUTHORABLE_DEFAULTS_DIR_NAME, authorableDefaultsShardTexts, authoriseDefaultChanges, + carryDefaultsThroughRenames, collectAuthorableDefaults, diffAuthorableDefaults, parseDefaultEntries, @@ -79,12 +80,12 @@ import { import * as AI from '../src/ai'; import * as API from '../src/api'; import * as Automation from '../src/automation'; -import * as Cloud from '../src/cloud'; import * as Contracts from '../src/contracts'; import * as Data from '../src/data'; import * as Identity from '../src/identity'; import * as Integration from '../src/integration'; import * as Kernel from '../src/kernel'; +import * as Marketplace from '../src/marketplace'; import * as QA from '../src/qa'; import * as Security from '../src/security'; import * as Shared from '../src/shared'; @@ -96,8 +97,8 @@ import * as UI from '../src/ui'; // packages/spec/src/index.ts). Build subpath-by-subpath instead so every // category folder under json-schema/ gets populated. const Protocol: Record> = { - AI, API, Automation, Cloud, Contracts, Data, Identity, Integration, - Kernel, QA, Security, Shared, Studio, System, UI, + AI, API, Automation, Contracts, Data, Identity, Integration, + Kernel, Marketplace, QA, Security, Shared, Studio, System, UI, }; /** The package root — every generated artifact below is resolved from here. */ @@ -2526,12 +2527,16 @@ if (resolvedSurfaceBase) { `authorable-defaults change check (#4666)`, ); if (upstream) { + // BOTH halves of the baseline are carried through RENAMED_DEFS — the keys + // here and the defaults below. Carrying only the keys charged a declared + // rename with `(none) → (added)` for every default it moved + // (#16325: 22 of them on the cloud → marketplace category move). const keys = new Map(); for (const entry of resolvedSurfaceBase.doc.keys ?? []) { keys.set(carryAuthorableKey(entry.replace(RETIRED_MARK, '')), entry.endsWith(RETIRED_MARK)); } defaultsBaseline = { - defaults: parseDefaultEntries(upstream.entries), + defaults: carryDefaultsThroughRenames(parseDefaultEntries(upstream.entries)), keys, label: `upstream ${resolvedSurfaceBase.rev.slice(0, 12)}`, }; @@ -2543,7 +2548,7 @@ if (!defaultsBaseline && committedDefaults && surfaceDoc) { keys.set(carryAuthorableKey(entry.replace(RETIRED_MARK, '')), entry.endsWith(RETIRED_MARK)); } defaultsBaseline = { - defaults: committedDefaults, + defaults: carryDefaultsThroughRenames(committedDefaults), keys, label: 'in-tree (this commit owns these bytes — no upstream baseline was reachable)', }; diff --git a/packages/spec/scripts/check-template-manifests.ts b/packages/spec/scripts/check-template-manifests.ts index 051def3753..737176eb7e 100644 --- a/packages/spec/scripts/check-template-manifests.ts +++ b/packages/spec/scripts/check-template-manifests.ts @@ -41,7 +41,7 @@ import { tmpdir } from 'node:os'; import { dirname, join, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { TemplateManifestSchema } from '../src/cloud/template-manifest.zod'; +import { TemplateManifestSchema } from '../src/marketplace/template-manifest.zod'; const pkgRoot = join(dirname(fileURLToPath(import.meta.url)), '..'); const repoRoot = join(pkgRoot, '..', '..'); @@ -285,7 +285,7 @@ function main(): void { ` value. Fix the manifest.\n` + ` • the SCHEMA is wrong — it demands something no template can supply, the way\n` + ` it required a publish-time \`manifestId\` from a source tree (#7319). Fix\n` + - ` packages/spec/src/cloud/template-manifest.zod.ts, and keep the relaxation\n` + + ` packages/spec/src/marketplace/template-manifest.zod.ts, and keep the relaxation\n` + ` LOCAL: CreatePackageRequestSchema is the publish request and must stay strict.\n`, ); process.exit(1); diff --git a/packages/spec/scripts/check-yaml-examples.ts b/packages/spec/scripts/check-yaml-examples.ts index e44002562d..8bf1f1f476 100644 --- a/packages/spec/scripts/check-yaml-examples.ts +++ b/packages/spec/scripts/check-yaml-examples.ts @@ -129,12 +129,12 @@ import { import * as AI from '../src/ai'; import * as API from '../src/api'; import * as Automation from '../src/automation'; -import * as Cloud from '../src/cloud'; import * as Contracts from '../src/contracts'; import * as Data from '../src/data'; import * as Identity from '../src/identity'; import * as Integration from '../src/integration'; import * as Kernel from '../src/kernel'; +import * as Marketplace from '../src/marketplace'; import * as QA from '../src/qa'; import * as Security from '../src/security'; import * as Shared from '../src/shared'; @@ -413,8 +413,8 @@ function parseDecl(raw: string): { decl?: ParsedDecl; error?: string } { * access), so only the names markers actually declare are ever probed. */ const NAMESPACES: Record> = { - AI, API, Automation, Cloud, Contracts, Data, Identity, Integration, - Kernel, QA, Security, Shared, Studio, System, UI, + AI, API, Automation, Contracts, Data, Identity, Integration, + Kernel, Marketplace, QA, Security, Shared, Studio, System, UI, }; type NameIndex = Record>; diff --git a/packages/spec/scripts/export-origins.test.ts b/packages/spec/scripts/export-origins.test.ts index b340582336..03104d2452 100644 --- a/packages/spec/scripts/export-origins.test.ts +++ b/packages/spec/scripts/export-origins.test.ts @@ -50,12 +50,12 @@ const ENTRY_NAMESPACES: ReadonlyArray<[string, () => Promise]> = [ ['./ai', () => import('../src/ai/index')], ['./api', () => import('../src/api/index')], ['./automation', () => import('../src/automation/index')], - ['./cloud', () => import('../src/cloud/index')], ['./contracts', () => import('../src/contracts/index')], ['./data', () => import('../src/data/index')], ['./identity', () => import('../src/identity/index')], ['./integration', () => import('../src/integration/index')], ['./kernel', () => import('../src/kernel/index')], + ['./marketplace', () => import('../src/marketplace/index')], ['./meta-spelling', () => import('../src/meta-spelling/index')], ['./qa', () => import('../src/qa/index')], ['./security', () => import('../src/security/index')], diff --git a/packages/spec/scripts/file-description.test.ts b/packages/spec/scripts/file-description.test.ts index e4b297d3b6..d10330ddda 100644 --- a/packages/spec/scripts/file-description.test.ts +++ b/packages/spec/scripts/file-description.test.ts @@ -311,7 +311,7 @@ describe('findModuleDocBlock — #13263: an import injected between a block and }); it('keeps a header written ABOVE the imports, even with a declaration right after them', () => { - // `system/doc.zod.ts`, `cloud/template-manifest.zod.ts`, + // `system/doc.zod.ts`, `marketplace/template-manifest.zod.ts`, // `api/error-code-ledger.zod.ts`. The codemod injects AFTER the last // import, so a block preceding every import preceded them beforehand too — // the position is the proof, and dropping this limb blanks all three. @@ -1298,7 +1298,7 @@ describe('renderFileDescription — #6420: a bare path in parentheses still link * `identity/auth.zod.ts` — matched nothing on either side and fell through as * plain prose. Not a link, and not the code-span fallback either: nine such * references on four published pages (`api/realtime-shared:19,21`, - * `cloud/package:17,18`, `identity/identity:13`, + * `marketplace/package:17,18` (then `cloud/package`), `identity/identity:13`, * `system/security-context:14,16,17,18`), which is the one outcome of the three * that is simply wrong. * @@ -1336,7 +1336,7 @@ describe('renderFileDescription — #6484: a same-directory path resolves agains */ const PAGES: Record = { api: ['auth', 'realtime', 'realtime-shared', 'websocket'], - cloud: ['environment-package', 'package', 'package-version'], + marketplace: ['package', 'package-version'], identity: ['identity', 'organization'], system: ['cache', 'encryption', 'security-context'], }; @@ -1363,14 +1363,15 @@ describe('renderFileDescription — #6484: a same-directory path resolves agains ); }); - it('links a same-directory path mid-sentence — the published `cloud/package` line', () => { - // `packages/spec/src/cloud/package.zod.ts:15` verbatim. A different + it('links a same-directory path mid-sentence — the published `marketplace/package` line', () => { + // `packages/spec/src/marketplace/package.zod.ts:15` verbatim (`cloud/package` + // until #16325 relocated the package format). A different // position from the `@see` case above (inside a list item, in ordinary // parentheses), so neither published page can regress on its own. expect( - describedBy('cloud', '- `sys_package_version` — immutable release snapshots (see package-version.zod.ts)'), + describedBy('marketplace', '- `sys_package_version` — immutable release snapshots (see package-version.zod.ts)'), ).toBe( - '- `sys_package_version` — immutable release snapshots (see [package-version.zod.ts](/docs/references/cloud/package-version))', + '- `sys_package_version` — immutable release snapshots (see [package-version.zod.ts](/docs/references/marketplace/package-version))', ); }); @@ -1567,7 +1568,7 @@ describe('corpus — no reference source donates a symbol comment to its page', .toBe('MySQL / MariaDB driver configuration — the `config` slot of a `datasource`'); expect(openingOf('data/driver/sqlite.zod.ts')) .toBe('SQLite driver configuration — the `config` slot of a `datasource` whose'); - expect(openingOf('cloud/template-manifest.zod.ts')) + expect(openingOf('marketplace/template-manifest.zod.ts')) .toBe('`objectstack.manifest.json` — on-disk descriptor for a template / package'); expect(openingOf('system/doc.zod.ts')) .toBe('Package Documentation Metadata Protocol (ADR-0046)'); @@ -1904,7 +1905,11 @@ describe('corpus — every rendered description is well-formed markdown', () => // whose "description" was one schema's detached comment; the diff of every // per-file verdict, old selector vs new over all 208 sources, is in that // card's PR: 200 identical, 8 SELECTED→null, 0 to a different block). - expect(described.length).toBeGreaterThan(140); + // 138 at #16325: the seven `cloud/*.zod.ts` sources that left with the + // `./cloud` subpath (six control-plane modules plus the environment-artifact + // re-export) took their descriptions with them; the four package-format + // modules moved to `marketplace/` and still count. + expect(described.length).toBeGreaterThan(130); }); it('never cuts an inline code span in half (#5553)', () => { @@ -2094,10 +2099,17 @@ describe('corpus — every rendered description is well-formed markdown', () => .filter(d => d.untouched !== d.emitted); // (38 -> 37: `kernel/metadata-customization.zod.ts` — one of the level-1 - // openers — was removed whole by #13135's ADR-0049 retirement.) - expect(shifted.length).toBe(37); + // openers — was removed whole by #13135's ADR-0049 retirement. + // 37 -> 31: six of the seven `cloud/*.zod.ts` sources that left with the + // `./cloud` subpath at #16325 opened at level 1 — `app-store`, + // `developer-portal`, `environment-package`, `environment`, + // `marketplace-admin` and the `environment-artifact` re-export; `tenant` + // opened at level 2 and was never counted. `marketplace.zod.ts`, the one + // level-1 opener among the four modules that moved to `marketplace/`, + // still counts.) + expect(shifted.length).toBe(31); // …and every one of them was shifted because it opened at level 1. - expect(shifted.filter(d => /^ {0,3}#(?:[ \t]|$)/m.test(withoutFences(d.untouched)))).toHaveLength(37); + expect(shifted.filter(d => /^ {0,3}#(?:[ \t]|$)/m.test(withoutFences(d.untouched)))).toHaveLength(31); }); it('never opens a page on the `@module` marker (#13796)', () => { diff --git a/packages/spec/scripts/lib/authorable-defaults.ts b/packages/spec/scripts/lib/authorable-defaults.ts index 2720ef872f..275ad15f4d 100644 --- a/packages/spec/scripts/lib/authorable-defaults.ts +++ b/packages/spec/scripts/lib/authorable-defaults.ts @@ -54,6 +54,7 @@ * internals to track across a Zod major. */ +import { RENAMED_DEFS, carryAuthorableKey } from './renamed-defs.js'; import { categoryOfDefKey, serializeShard } from './sharded-artifacts.js'; /** `packages/spec/authorable-defaults/.json` — the #4666 default ratchet. */ @@ -264,6 +265,34 @@ export interface DefaultDiffInput { * would demand a second declaration for one retirement — check (b) * already demands the real one. */ +/** + * Carry a recorded defaults baseline through the declared def renames + * (`RENAMED_DEFS`) — the same discipline the gate applies to the baseline's + * KEY set beside it, and for the same reason: a rename moves a def's keys AND + * their defaults, and it must not be able to make either look like a change. + * + * Without this half the two halves of one baseline disagreed (#16325, measured + * on the `cloud/` → `marketplace/` category move): the carried key-set said + * `marketplace/Package:visibility` already existed, the uncarried defaults map + * had no entry under that name, and {@link diffAuthorableDefaults} charged the + * rename with 22 `(none) → (added)` flips that no value had made. The + * only exit would have been 22 false rows in DEFAULT_CHANGES_BY_MAJOR — a + * rename riding the acknowledged-change table, which is exactly what + * `scripts/lib/renamed-defs.ts` exists to prevent. + * + * Only the def part of each key is rewritten (a rename moves keys, it never + * renames them); a key whose def is not declared renamed passes through + * unchanged, fingerprint included. + */ +export function carryDefaultsThroughRenames( + defaults: ReadonlyMap, + renames: Readonly> = RENAMED_DEFS, +): Map { + const carried = new Map(); + for (const [key, fingerprint] of defaults) carried.set(carryAuthorableKey(key, renames), fingerprint); + return carried; +} + export function diffAuthorableDefaults(input: DefaultDiffInput): ObservedDefaultChange[] { const { baseline, current, baselineKeys, currentKeys } = input; const changes: ObservedDefaultChange[] = []; diff --git a/packages/spec/scripts/lib/category-title.ts b/packages/spec/scripts/lib/category-title.ts index 27f804e294..cc1067c4b9 100644 --- a/packages/spec/scripts/lib/category-title.ts +++ b/packages/spec/scripts/lib/category-title.ts @@ -71,13 +71,16 @@ export const CATEGORY_TITLES: Readonly> = { ai: 'AI Protocol', api: 'API Protocol', automation: 'Automation Protocol', - cloud: 'Cloud Protocol', contracts: 'Contracts Protocol', conversions: 'Conversions Protocol', data: 'Data Protocol', identity: 'Identity Protocol', integration: 'Integration Protocol', kernel: 'Kernel Protocol', + // [#16325] The package & marketplace FORMAT — what a package author writes + // and what the marketplace answers with. Relocated out of `cloud/` when the + // cloud control plane's own contracts left the open-source spec. + marketplace: 'Marketplace Protocol', // [#10096] The schema-free `/meta` URL-spelling entry. "Vocabulary", not // "Protocol": the entry carries the spelling contract's data and folds // without the schema machinery every Protocol category links. diff --git a/packages/spec/scripts/lib/file-description.ts b/packages/spec/scripts/lib/file-description.ts index 73c6399981..ed5a5bc989 100644 --- a/packages/spec/scripts/lib/file-description.ts +++ b/packages/spec/scripts/lib/file-description.ts @@ -75,7 +75,7 @@ * imports is where the codemod cannot have put it: the injection point is * after the last import, so a block preceding every import was preceding them * before the codemod ran too. Without that half, `api/error-code-ledger`, - * `cloud/template-manifest` and `system/doc` — three real headers whose + * `marketplace/template-manifest` and `system/doc` — three real headers whose * imports happen to be followed directly by a declaration — lose their * opening paragraph. * - **A comment directly against the block's far side still ends the preamble.** diff --git a/packages/spec/scripts/lib/renamed-defs.ts b/packages/spec/scripts/lib/renamed-defs.ts index 5153357a96..11231db63c 100644 --- a/packages/spec/scripts/lib/renamed-defs.ts +++ b/packages/spec/scripts/lib/renamed-defs.ts @@ -115,9 +115,10 @@ export const RENAMED_DEFS: Readonly> = { // (`packageId` / `versionRange` / `optional`), `kernel` is the RESOLVER form // the dependency graph walks (`name` / `versionConstraint` / `type` / // `resolvedVersion`). Two concepts, not two spellings. The resolver side - // takes the descriptive name; `cloud/PackageDependency` keeps the bare one - // and is deliberately absent from this table — it is neither source nor - // target, and it is emitted byte-for-byte unchanged by this build. + // takes the descriptive name; `cloud/PackageDependency` kept the bare one + // and was deliberately absent from this table — neither source nor target, + // emitted byte-for-byte unchanged by that build. (It is a SOURCE below since + // #16325, for the category move to `marketplace/` — a different change.) 'kernel/PackageDependency': 'kernel/ResolvedPackageDependency', // 4 keys carried // #5832 / ADR-0112 D9 — `shared/http.zod.ts` declared TWO different enums @@ -162,6 +163,61 @@ export const RENAMED_DEFS: Readonly> = { // to prevent. The rename removes the collision at its source, so the baseline // stays empty rather than gaining its first exception. 'system/ServiceStatus': 'system/KernelServiceStatus', // 6 keys carried + + // #16325 — the `./cloud` subpath left `@objectstack/spec` (maintainer ruling, + // option B "cut by owner": the cloud control plane's own contracts are the + // cloud repo's, not an open-source protocol). The package & marketplace + // FORMAT half — `package.zod`, `package-version.zod`, `marketplace.zod`, + // `package-l10n`, `template-manifest.zod` — stays and moves to + // `src/marketplace/`, so every def it emits changes CATEGORY and nothing + // else: the same Zod, the same keys, the same JSON Schema bytes under a new + // `$id`. That is exactly the shape this table exists for — a rename that + // must carry every key — and NOT the retirement kit, which is reserved below + // for the six control-plane files whose defs really did leave + // (`RETIRED_DEFS_BY_MAJOR[18]`, one `entries/retired-defs/18.cloud__*.ts` + // each). + // + // Two 0-key defs move category the same way rather than retiring: + // - `cloud/EnvironmentType` — the 7-member environment taxonomy the + // discovery fold table is total over; re-declared in + // `api/discovery.zod.ts`, its only open-source reader. + // - `cloud/Sha256Digest` — was emitted twice, once per entry that exported + // the `system/environment-artifact.zod.ts` declaration (`./cloud` + // re-exported it, #4740 route A′). With `./cloud` gone it is emitted + // once, under `system/` — a rename onto a def that already existed, + // which the manifest rewrite handles by dropping the stale key. + 'cloud/ArtifactDownloadResponse': 'marketplace/ArtifactDownloadResponse', + 'cloud/ArtifactReference': 'marketplace/ArtifactReference', + 'cloud/CreatePackageRequest': 'marketplace/CreatePackageRequest', + 'cloud/CreatePackageVersionRequest': 'marketplace/CreatePackageVersionRequest', + 'cloud/ListingStatus': 'marketplace/ListingStatus', + 'cloud/MarketplaceCategory': 'marketplace/MarketplaceCategory', + 'cloud/MarketplaceInstallRequest': 'marketplace/MarketplaceInstallRequest', + 'cloud/MarketplaceInstallResponse': 'marketplace/MarketplaceInstallResponse', + 'cloud/MarketplaceListing': 'marketplace/MarketplaceListing', + 'cloud/MarketplaceSearchRequest': 'marketplace/MarketplaceSearchRequest', + 'cloud/MarketplaceSearchResponse': 'marketplace/MarketplaceSearchResponse', + 'cloud/Package': 'marketplace/Package', + 'cloud/PackageCategory': 'marketplace/PackageCategory', + 'cloud/PackageDependency': 'marketplace/PackageDependency', + 'cloud/PackageLocale': 'marketplace/PackageLocale', + 'cloud/PackageManifest': 'marketplace/PackageManifest', + 'cloud/PackagePublisher': 'marketplace/PackagePublisher', + 'cloud/PackageSubmission': 'marketplace/PackageSubmission', + 'cloud/PackageTranslation': 'marketplace/PackageTranslation', + 'cloud/PackageTranslations': 'marketplace/PackageTranslations', + 'cloud/PackageVersion': 'marketplace/PackageVersion', + 'cloud/PackageVersionStatus': 'marketplace/PackageVersionStatus', + 'cloud/PackageVisibility': 'marketplace/PackageVisibility', + 'cloud/PricingModel': 'marketplace/PricingModel', + 'cloud/PublishPackageVersionRequest': 'marketplace/PublishPackageVersionRequest', + 'cloud/Publisher': 'marketplace/Publisher', + 'cloud/PublisherVerification': 'marketplace/PublisherVerification', + 'cloud/TemplateManifest': 'marketplace/TemplateManifest', + 'cloud/UpdatePackageRequest': 'marketplace/UpdatePackageRequest', + 'cloud/UpdatePackageVersionRequest': 'marketplace/UpdatePackageVersionRequest', + 'cloud/EnvironmentType': 'api/EnvironmentType', // 0-key carry: enum def + 'cloud/Sha256Digest': 'system/Sha256Digest', // 0-key carry: string def, onto its surviving twin }; /** diff --git a/packages/spec/scripts/lib/unemitted-schemas.ts b/packages/spec/scripts/lib/unemitted-schemas.ts index f7fa5dcdf8..f0edf850c7 100644 --- a/packages/spec/scripts/lib/unemitted-schemas.ts +++ b/packages/spec/scripts/lib/unemitted-schemas.ts @@ -25,7 +25,8 @@ * reaches no page at all. * * #16431 measured the population for the first time: **23 exports**, across - * `Automation` / `Cloud` / `Data` / `Kernel` / `System` / `UI`, in one build. + * `Automation` / `Cloud` (since #16325: `Marketplace`) / `Data` / `Kernel` / + * `System` / `UI`, in one build. * The card that found it saw four of them. Nobody was tracking the other 19, * and nothing would have reported the 24th. * diff --git a/packages/spec/scripts/root-meta.test.ts b/packages/spec/scripts/root-meta.test.ts index e377c7249b..f590123dba 100644 --- a/packages/spec/scripts/root-meta.test.ts +++ b/packages/spec/scripts/root-meta.test.ts @@ -67,8 +67,8 @@ describe('rootCategoryDirs — which categories reach the root sidebar (#11482)' // filters agree on all 14 — the byte-identical root `meta.json` the issue // itself measured, and the acceptance bar this fix must not move. const categories = [ - 'ai', 'api', 'automation', 'cloud', 'data', 'identity', 'integration', - 'kernel', 'qa', 'security', 'shared', 'studio', 'system', 'ui', + 'ai', 'api', 'automation', 'data', 'identity', 'integration', + 'kernel', 'marketplace', 'qa', 'security', 'shared', 'studio', 'system', 'ui', ]; const metaPages = new Map(categories.map(c => [c, ['some-page']])); diff --git a/packages/spec/src/api/discovery-environment-subset.pin.test.ts b/packages/spec/src/api/discovery-environment-subset.pin.test.ts index dd5a2507c8..57bd908df3 100644 --- a/packages/spec/src/api/discovery-environment-subset.pin.test.ts +++ b/packages/spec/src/api/discovery-environment-subset.pin.test.ts @@ -37,9 +37,7 @@ import { describe, it, expect } from 'vitest'; -import { EnvironmentTypeSchema } from '../cloud/environment.zod'; - -import { DiscoveryEnvironmentSchema } from './discovery.zod'; +import { DiscoveryEnvironmentSchema, EnvironmentTypeSchema } from './discovery.zod'; /** `.options` through the `lazySchema` Proxy — read once, asserted below. */ const discoveryMembers = DiscoveryEnvironmentSchema.options as readonly string[]; diff --git a/packages/spec/src/api/discovery.test.ts b/packages/spec/src/api/discovery.test.ts index a54326dfa3..d4912010db 100644 --- a/packages/spec/src/api/discovery.test.ts +++ b/packages/spec/src/api/discovery.test.ts @@ -20,8 +20,9 @@ import { type RouteHealthEntry, type RouteHealthReport, type DiscoveryEnvironment, + EnvironmentTypeSchema, + type EnvironmentType, } from './discovery.zod'; -import { EnvironmentTypeSchema, type EnvironmentType } from '../cloud/environment.zod'; describe('ApiRoutesSchema', () => { it('should accept valid minimal routes', () => { diff --git a/packages/spec/src/api/discovery.zod.ts b/packages/spec/src/api/discovery.zod.ts index 1663a8376c..f74688572f 100644 --- a/packages/spec/src/api/discovery.zod.ts +++ b/packages/spec/src/api/discovery.zod.ts @@ -2,10 +2,6 @@ import { z } from 'zod'; import { HttpMethod } from '../shared/http.zod'; -// [#6287] Type-only: erased at compile time, so this carries no runtime edge -// from `api/` to `cloud/`. It is what makes the NODE_ENV fold table provably -// total over the environment taxonomy rather than total by inspection. -import type { EnvironmentType } from '../cloud/environment.zod'; /** * Service Status Enum @@ -410,6 +406,37 @@ export const ApiRoutesSchema = lazySchema(() => z.object({ mcp: z.string().optional().describe('e.g. /api/v1/mcp — always the unscoped base; absent when MCP is disabled or unserveable'), })); +/** + * Environment categorical tag — the 7-member taxonomy the NODE_ENV fold table + * below is total over. + * + * Until #16325 this enum was declared by `cloud/environment.zod.ts`, beside the + * cloud control plane's own environment row (`sys_environment`). That row and + * its siblings are not an open-source protocol — their producer and their + * consumers both live in the closed cloud repo — so they left + * `@objectstack/spec` with the `./cloud` subpath (maintainer direction, + * verbatim: 「我一直觉得 cloud 的协议应该放在云端,没必要开源」). The taxonomy + * stays HERE, in the one open-source module that reads it: + * `NODE_ENV_TO_DISCOVERY_ENVIRONMENT` is typed + * `Record`, which is what makes the fold + * provably total over the taxonomy rather than total by inspection (#6287). + * + * Its relation to the 3-member `DiscoveryEnvironmentSchema` below is a strict + * subset: `resolveDiscoveryEnvironment` folds `test` → `development` and + * `staging` / `preview` / `trial` → `sandbox` (#4828, #6287), and the subset is + * pinned in `discovery-environment-subset.pin.test.ts` (#5676). + * + * ⚠️ Adding a member here is a decision about the fold table too: a new bucket + * does not compile until it says which of the three coarse postures it + * advertises — on purpose, because before #6287 `preview` and `trial` reached + * `development` through a `??` fallback instead of a decision (#5673). + */ +export const EnvironmentTypeSchema = lazySchema(() => z + .enum(['production', 'sandbox', 'development', 'test', 'staging', 'preview', 'trial']) + .describe('Environment categorical tag (prod/sandbox/dev/test/…)')); + +export type EnvironmentType = z.input; + /** * Discovery Response Schema * The root object returned by the Metadata Discovery Endpoint. @@ -508,7 +535,8 @@ export type DiscoveryEnvironment = z.input; * * 1. **What they are here.** In this repo's taxonomy an environment is a * provisioned runtime container — isolated database, canonical hostname, - * plan tier, per-environment RBAC (`cloud/environment.zod.ts`). A `preview` + * plan tier, per-environment RBAC (the cloud repo's `sys_environment` row — + * declared under `@objectstack/spec/cloud` until #16325). A `preview` * or `trial` environment is that, not an ephemeral developer-class run. The * `development` bucket is reserved for the machine-and-CI class (`development`, * `dev`, `test`); `sandbox` is the enum's provisioned pre-production member, diff --git a/packages/spec/src/api/package-api.zod.ts b/packages/spec/src/api/package-api.zod.ts index cd68a6684a..eb9798a9d3 100644 --- a/packages/spec/src/api/package-api.zod.ts +++ b/packages/spec/src/api/package-api.zod.ts @@ -7,7 +7,7 @@ import { DependencyResolutionResultSchema } from '../kernel/dependency-resolutio import { UpgradePlanSchema } from '../kernel/package-upgrade.zod'; import { PackageArtifactSchema } from '../kernel/package-artifact.zod'; import { ManifestSchema } from '../kernel/manifest.zod'; -import { ArtifactReferenceSchema } from '../cloud/marketplace.zod'; +import { ArtifactReferenceSchema } from '../marketplace/marketplace.zod'; /** * # Package API Protocol diff --git a/packages/spec/src/cloud/app-store.test.ts b/packages/spec/src/cloud/app-store.test.ts deleted file mode 100644 index 421d4614db..0000000000 --- a/packages/spec/src/cloud/app-store.test.ts +++ /dev/null @@ -1,390 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { - ReviewModerationStatusSchema, - UserReviewSchema, - SubmitReviewRequestSchema, - ListReviewsRequestSchema, - ListReviewsResponseSchema, - RecommendationReasonSchema, - RecommendedAppSchema, - AppDiscoveryRequestSchema, - AppDiscoveryResponseSchema, - SubscriptionStatusSchema, - AppSubscriptionSchema, - InstalledAppSummarySchema, - ListInstalledAppsRequestSchema, - ListInstalledAppsResponseSchema, -} from './app-store.zod'; - -describe('ReviewModerationStatusSchema', () => { - it('should accept all moderation statuses', () => { - const statuses = ['pending', 'approved', 'flagged', 'rejected']; - statuses.forEach(status => { - expect(() => ReviewModerationStatusSchema.parse(status)).not.toThrow(); - }); - }); -}); - -describe('UserReviewSchema', () => { - it('should accept minimal review (rating only)', () => { - const review = { - id: 'rev-001', - listingId: 'listing-001', - userId: 'user-001', - rating: 5, - submittedAt: '2025-06-01T10:00:00Z', - }; - const parsed = UserReviewSchema.parse(review); - expect(parsed.moderationStatus).toBe('pending'); - expect(parsed.helpfulCount).toBe(0); - }); - - it('should accept full review with publisher response', () => { - const review = { - id: 'rev-001', - listingId: 'listing-001', - userId: 'user-001', - displayName: 'John Doe', - rating: 4, - title: 'Great CRM plugin!', - body: 'This plugin transformed our sales process. The pipeline view is excellent.', - appVersion: '2.1.0', - moderationStatus: 'approved' as const, - helpfulCount: 12, - publisherResponse: { - body: 'Thank you for the kind review! We are glad you enjoy the pipeline view.', - respondedAt: '2025-06-02T14:00:00Z', - }, - submittedAt: '2025-06-01T10:00:00Z', - updatedAt: '2025-06-02T14:00:00Z', - }; - const parsed = UserReviewSchema.parse(review); - expect(parsed.publisherResponse?.body).toContain('Thank you'); - expect(parsed.helpfulCount).toBe(12); - }); - - it('should enforce rating range 1-5', () => { - const base = { - id: 'rev-001', - listingId: 'listing-001', - userId: 'user-001', - submittedAt: '2025-06-01T10:00:00Z', - }; - expect(() => UserReviewSchema.parse({ ...base, rating: 0 })).toThrow(); - expect(() => UserReviewSchema.parse({ ...base, rating: 6 })).toThrow(); - expect(() => UserReviewSchema.parse({ ...base, rating: 1 })).not.toThrow(); - expect(() => UserReviewSchema.parse({ ...base, rating: 5 })).not.toThrow(); - }); - - it('should enforce title max length', () => { - const review = { - id: 'rev-001', - listingId: 'listing-001', - userId: 'user-001', - rating: 3, - title: 'x'.repeat(201), - submittedAt: '2025-06-01T10:00:00Z', - }; - expect(() => UserReviewSchema.parse(review)).toThrow(); - }); - - it('should enforce body max length', () => { - const review = { - id: 'rev-001', - listingId: 'listing-001', - userId: 'user-001', - rating: 3, - body: 'x'.repeat(5001), - submittedAt: '2025-06-01T10:00:00Z', - }; - expect(() => UserReviewSchema.parse(review)).toThrow(); - }); -}); - -describe('SubmitReviewRequestSchema', () => { - it('should accept minimal review submission', () => { - const request = { - listingId: 'listing-001', - rating: 5, - }; - const parsed = SubmitReviewRequestSchema.parse(request); - expect(parsed.rating).toBe(5); - }); - - it('should accept review with title and body', () => { - const request = { - listingId: 'listing-001', - rating: 4, - title: 'Great app', - body: 'Works perfectly for our needs.', - }; - const parsed = SubmitReviewRequestSchema.parse(request); - expect(parsed.title).toBe('Great app'); - }); -}); - -describe('ListReviewsRequestSchema', () => { - it('should accept minimal request', () => { - const request = { listingId: 'listing-001' }; - const parsed = ListReviewsRequestSchema.parse(request); - expect(parsed.sortBy).toBe('newest'); - expect(parsed.page).toBe(1); - expect(parsed.pageSize).toBe(10); - }); - - it('should accept filtered request', () => { - const request = { - listingId: 'listing-001', - sortBy: 'most-helpful' as const, - rating: 5, - page: 2, - pageSize: 25, - }; - const parsed = ListReviewsRequestSchema.parse(request); - expect(parsed.rating).toBe(5); - }); - - it('should reject invalid page size', () => { - expect(() => ListReviewsRequestSchema.parse({ - listingId: 'listing-001', - pageSize: 0, - })).toThrow(); - expect(() => ListReviewsRequestSchema.parse({ - listingId: 'listing-001', - pageSize: 51, - })).toThrow(); - }); -}); - -describe('ListReviewsResponseSchema', () => { - it('should accept empty response', () => { - const response = { - items: [], - total: 0, - page: 1, - pageSize: 10, - }; - const parsed = ListReviewsResponseSchema.parse(response); - expect(parsed.items).toHaveLength(0); - }); - - it('should accept response with rating summary', () => { - const response = { - items: [{ - id: 'rev-001', - listingId: 'listing-001', - userId: 'user-001', - rating: 5, - submittedAt: '2025-06-01T10:00:00Z', - }], - total: 1, - page: 1, - pageSize: 10, - ratingSummary: { - averageRating: 4.5, - totalRatings: 120, - distribution: { 1: 2, 2: 5, 3: 15, 4: 48, 5: 50 }, - }, - }; - const parsed = ListReviewsResponseSchema.parse(response); - expect(parsed.ratingSummary?.averageRating).toBe(4.5); - expect(parsed.ratingSummary?.distribution[5]).toBe(50); - }); -}); - -describe('RecommendationReasonSchema', () => { - it('should accept all recommendation reasons', () => { - const reasons = [ - 'popular-in-category', 'similar-users', 'complements-installed', - 'trending', 'new-release', 'editor-pick', - ]; - reasons.forEach(reason => { - expect(() => RecommendationReasonSchema.parse(reason)).not.toThrow(); - }); - }); -}); - -describe('RecommendedAppSchema', () => { - it('should accept recommended app', () => { - const app = { - listingId: 'listing-001', - name: 'Acme CRM', - tagline: 'Complete CRM for ObjectStack', - iconUrl: 'https://acme.com/icon.png', - category: 'crm' as const, - pricing: 'freemium' as const, - averageRating: 4.5, - activeInstalls: 3200, - reason: 'popular-in-category' as const, - }; - const parsed = RecommendedAppSchema.parse(app); - expect(parsed.reason).toBe('popular-in-category'); - }); -}); - -describe('AppDiscoveryRequestSchema', () => { - it('should accept empty discovery request', () => { - const parsed = AppDiscoveryRequestSchema.parse({}); - expect(parsed.limit).toBe(10); - }); - - it('should accept personalized discovery request', () => { - const request = { - tenantId: 'tenant-001', - categories: ['crm', 'analytics'], - platformVersion: '1.5.0', - limit: 20, - }; - const parsed = AppDiscoveryRequestSchema.parse(request); - expect(parsed.categories).toHaveLength(2); - }); -}); - -describe('AppDiscoveryResponseSchema', () => { - it('should accept full discovery response', () => { - const app = { - listingId: 'listing-001', - name: 'Acme CRM', - category: 'crm' as const, - pricing: 'free' as const, - reason: 'editor-pick' as const, - }; - const response = { - featured: [app], - recommended: [{ ...app, reason: 'popular-in-category' as const }], - trending: [{ ...app, reason: 'trending' as const }], - newArrivals: [{ ...app, reason: 'new-release' as const }], - collections: [{ - id: 'col-001', - name: 'Best for Small Business', - apps: [app], - }], - }; - const parsed = AppDiscoveryResponseSchema.parse(response); - expect(parsed.featured).toHaveLength(1); - expect(parsed.collections).toHaveLength(1); - }); - - it('should accept minimal discovery response', () => { - const response = {}; - const parsed = AppDiscoveryResponseSchema.parse(response); - expect(parsed.featured).toBeUndefined(); - }); -}); - -describe('SubscriptionStatusSchema', () => { - it('should accept all subscription statuses', () => { - const statuses = ['active', 'trialing', 'past-due', 'cancelled', 'expired']; - statuses.forEach(status => { - expect(() => SubscriptionStatusSchema.parse(status)).not.toThrow(); - }); - }); -}); - -describe('AppSubscriptionSchema', () => { - it('should accept active subscription', () => { - const subscription = { - id: 'sub-001', - listingId: 'listing-001', - tenantId: 'tenant-001', - status: 'active' as const, - plan: 'Professional', - billingCycle: 'annual' as const, - priceInCents: 11988, - currentPeriodStart: '2025-01-01T00:00:00Z', - currentPeriodEnd: '2026-01-01T00:00:00Z', - autoRenew: true, - createdAt: '2025-01-01T00:00:00Z', - }; - const parsed = AppSubscriptionSchema.parse(subscription); - expect(parsed.status).toBe('active'); - expect(parsed.autoRenew).toBe(true); - }); - - it('should accept trial subscription', () => { - const subscription = { - id: 'sub-002', - listingId: 'listing-001', - tenantId: 'tenant-001', - status: 'trialing' as const, - trialEndDate: '2025-07-01T00:00:00Z', - createdAt: '2025-06-01T00:00:00Z', - }; - const parsed = AppSubscriptionSchema.parse(subscription); - expect(parsed.status).toBe('trialing'); - expect(parsed.trialEndDate).toBe('2025-07-01T00:00:00Z'); - }); -}); - -describe('InstalledAppSummarySchema', () => { - it('should accept installed app with update available', () => { - const app = { - listingId: 'listing-001', - packageId: 'com.acme.crm', - name: 'Acme CRM', - iconUrl: 'https://acme.com/icon.png', - installedVersion: '2.0.0', - latestVersion: '2.1.0', - updateAvailable: true, - enabled: true, - subscriptionStatus: 'active' as const, - installedAt: '2025-03-01T00:00:00Z', - }; - const parsed = InstalledAppSummarySchema.parse(app); - expect(parsed.updateAvailable).toBe(true); - expect(parsed.subscriptionStatus).toBe('active'); - }); - - it('should accept minimal installed app', () => { - const app = { - listingId: 'listing-002', - packageId: 'com.acme.utils', - name: 'Acme Utils', - installedVersion: '1.0.0', - installedAt: '2025-06-01T00:00:00Z', - }; - const parsed = InstalledAppSummarySchema.parse(app); - expect(parsed.updateAvailable).toBe(false); - expect(parsed.enabled).toBe(true); - }); -}); - -describe('ListInstalledAppsRequestSchema', () => { - it('should accept empty request', () => { - const parsed = ListInstalledAppsRequestSchema.parse({}); - expect(parsed.sortBy).toBe('name'); - expect(parsed.page).toBe(1); - expect(parsed.pageSize).toBe(20); - }); - - it('should accept filtered request', () => { - const request = { - tenantId: 'tenant-001', - enabled: true, - updateAvailable: true, - sortBy: 'installed-date' as const, - }; - const parsed = ListInstalledAppsRequestSchema.parse(request); - expect(parsed.updateAvailable).toBe(true); - }); -}); - -describe('ListInstalledAppsResponseSchema', () => { - it('should accept response with installed apps', () => { - const response = { - items: [{ - listingId: 'listing-001', - packageId: 'com.acme.crm', - name: 'Acme CRM', - installedVersion: '2.0.0', - installedAt: '2025-03-01T00:00:00Z', - }], - total: 1, - page: 1, - pageSize: 20, - }; - const parsed = ListInstalledAppsResponseSchema.parse(response); - expect(parsed.items).toHaveLength(1); - expect(parsed.total).toBe(1); - }); -}); diff --git a/packages/spec/src/cloud/app-store.zod.ts b/packages/spec/src/cloud/app-store.zod.ts deleted file mode 100644 index a9e0d8782e..0000000000 --- a/packages/spec/src/cloud/app-store.zod.ts +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { z } from 'zod'; -import { MarketplaceCategorySchema, PricingModelSchema } from './marketplace.zod'; - -/** - * # App Store Protocol (Customer Experience) - * - * Defines schemas for the end-customer experience when browsing, evaluating, - * installing, and managing marketplace apps from within ObjectOS. - * - * ## Architecture Alignment - * - **Salesforce AppExchange (Customer)**: Browse apps, read reviews, 1-click install - * - **Shopify App Store (Merchant)**: App evaluation, trial, install, manage subscriptions - * - **Apple App Store (User)**: Ratings, reviews, featured collections, personalized recs - * - * ## Customer Journey - * ``` - * Discover → Evaluate → Install → Configure → Use → Rate/Review → Manage - * ``` - * - * ## Key Concepts - * - **Reviews & Ratings**: User-submitted ratings and reviews with moderation - * - **Collections & Recommendations**: Personalized discovery and curated picks - * - **Subscription Management**: Manage licenses, billing, and renewals - * - **Installed App Management**: Enable, disable, configure, upgrade, uninstall - */ - -// ========================================== -// User Reviews & Ratings -// ========================================== - -/** - * Review Moderation Status - */ -import { lazySchema } from '../shared/lazy-schema'; -export const ReviewModerationStatusSchema = lazySchema(() => z.enum([ - 'pending', // Awaiting moderation - 'approved', // Approved and visible - 'flagged', // Flagged for review - 'rejected', // Rejected (spam, inappropriate) -])); - -/** - * User Review Schema — a customer's review of an installed app - */ -export const UserReviewSchema = lazySchema(() => z.object({ - /** Review ID */ - id: z.string().describe('Review ID'), - - /** Listing ID being reviewed */ - listingId: z.string().describe('Listing being reviewed'), - - /** Reviewer user ID */ - userId: z.string().describe('Review author user ID'), - - /** Reviewer display name */ - displayName: z.string().optional().describe('Reviewer display name'), - - /** Star rating (1-5) */ - rating: z.number().int().min(1).max(5).describe('Star rating (1-5)'), - - /** Review title */ - title: z.string().max(200).optional().describe('Review title'), - - /** Review body text */ - body: z.string().max(5000).optional().describe('Review text'), - - /** Version the reviewer is using */ - appVersion: z.string().optional().describe('App version being reviewed'), - - /** Moderation status */ - moderationStatus: ReviewModerationStatusSchema.default('pending'), - - /** Number of "helpful" votes from other users */ - helpfulCount: z.number().int().min(0).default(0), - - /** Publisher's response to this review */ - publisherResponse: z.object({ - body: z.string(), - respondedAt: z.string().datetime(), - }).optional().describe('Publisher response to review'), - - /** Submitted timestamp */ - submittedAt: z.string().datetime(), - - /** Updated timestamp */ - updatedAt: z.string().datetime().optional(), -})); - -/** - * Submit Review Request - */ -export const SubmitReviewRequestSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string().describe('Listing to review'), - - /** Star rating (1-5) */ - rating: z.number().int().min(1).max(5).describe('Star rating'), - - /** Review title */ - title: z.string().max(200).optional(), - - /** Review body */ - body: z.string().max(5000).optional(), -})); - -/** - * List Reviews Request — customer browsing reviews - */ -export const ListReviewsRequestSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string().describe('Listing to get reviews for'), - - /** Sort by */ - sortBy: z.enum(['newest', 'oldest', 'highest', 'lowest', 'most-helpful']) - .default('newest'), - - /** Filter by rating */ - rating: z.number().int().min(1).max(5).optional(), - - /** Pagination */ - page: z.number().int().min(1).default(1), - pageSize: z.number().int().min(1).max(50).default(10), -})); - -/** - * List Reviews Response - */ -export const ListReviewsResponseSchema = lazySchema(() => z.object({ - /** Reviews */ - items: z.array(UserReviewSchema), - - /** Total count */ - total: z.number().int().min(0), - - /** Pagination */ - page: z.number().int().min(1), - pageSize: z.number().int().min(1), - - /** Rating summary */ - ratingSummary: z.object({ - averageRating: z.number().min(0).max(5), - totalRatings: z.number().int().min(0), - distribution: z.object({ - 1: z.number().int().min(0).default(0), - 2: z.number().int().min(0).default(0), - 3: z.number().int().min(0).default(0), - 4: z.number().int().min(0).default(0), - 5: z.number().int().min(0).default(0), - }), - }).optional(), -})); - -// ========================================== -// App Discovery & Recommendations -// ========================================== - -/** - * App Recommendation Reason - */ -export const RecommendationReasonSchema = lazySchema(() => z.enum([ - 'popular-in-category', // Popular in your industry/category - 'similar-users', // Used by similar organizations - 'complements-installed', // Complements apps you already use - 'trending', // Currently trending - 'new-release', // Recently released / major update - 'editor-pick', // Editorial/curated recommendation -])); - -/** - * Recommended App - */ -export const RecommendedAppSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string(), - - /** App name */ - name: z.string(), - - /** Short tagline */ - tagline: z.string().optional(), - - /** Icon URL */ - iconUrl: z.string().url().optional(), - - /** Category */ - category: MarketplaceCategorySchema, - - /** Pricing */ - pricing: PricingModelSchema, - - /** Average rating */ - averageRating: z.number().min(0).max(5).optional(), - - /** Active installs */ - activeInstalls: z.number().int().min(0).optional(), - - /** Why this is recommended */ - reason: RecommendationReasonSchema, -})); - -/** - * App Discovery Request — personalized browse/home page - */ -export const AppDiscoveryRequestSchema = lazySchema(() => z.object({ - /** Tenant ID for personalization */ - tenantId: z.string().optional(), - - /** Categories the customer is interested in */ - categories: z.array(MarketplaceCategorySchema).optional(), - - /** Platform version for compatibility filtering */ - platformVersion: z.string().optional(), - - /** Max number of items per section */ - limit: z.number().int().min(1).max(50).default(10), -})); - -/** - * App Discovery Response — structured content for the storefront - */ -export const AppDiscoveryResponseSchema = lazySchema(() => z.object({ - /** Featured apps (editorial picks) */ - featured: z.array(RecommendedAppSchema).optional(), - - /** Personalized recommendations */ - recommended: z.array(RecommendedAppSchema).optional(), - - /** Trending apps */ - trending: z.array(RecommendedAppSchema).optional(), - - /** Recently added */ - newArrivals: z.array(RecommendedAppSchema).optional(), - - /** Curated collections */ - collections: z.array(z.object({ - id: z.string(), - name: z.string(), - description: z.string().optional(), - coverImageUrl: z.string().url().optional(), - apps: z.array(RecommendedAppSchema), - })).optional(), -})); - -// ========================================== -// Subscription & License Management -// ========================================== - -/** - * Subscription Status - */ -export const SubscriptionStatusSchema = lazySchema(() => z.enum([ - 'active', // Active and paid - 'trialing', // Free trial period - 'past-due', // Payment overdue - 'cancelled', // Cancelled (still active until period ends) - 'expired', // Expired / ended -])); - -/** - * App Subscription Schema — customer's license/subscription for an app - */ -export const AppSubscriptionSchema = lazySchema(() => z.object({ - /** Subscription ID */ - id: z.string().describe('Subscription ID'), - - /** Listing ID */ - listingId: z.string().describe('App listing ID'), - - /** Tenant ID */ - tenantId: z.string().describe('Customer tenant ID'), - - /** Subscription status */ - status: SubscriptionStatusSchema, - - /** License key */ - licenseKey: z.string().optional(), - - /** Plan/tier name (if multiple plans) */ - plan: z.string().optional().describe('Subscription plan name'), - - /** Billing cycle */ - billingCycle: z.enum(['monthly', 'annual']).optional(), - - /** Price per billing cycle (in cents) */ - priceInCents: z.number().int().min(0).optional(), - - /** Current period start */ - currentPeriodStart: z.string().datetime().optional(), - - /** Current period end */ - currentPeriodEnd: z.string().datetime().optional(), - - /** Trial end date (if trialing) */ - trialEndDate: z.string().datetime().optional(), - - /** Whether auto-renew is on */ - autoRenew: z.boolean().default(true), - - /** Created timestamp */ - createdAt: z.string().datetime(), -})); - -// ========================================== -// Installed App Management (Customer Side) -// ========================================== - -/** - * Installed App Summary — what the customer sees in their "My Apps" dashboard - */ -export const InstalledAppSummarySchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string(), - - /** Package ID */ - packageId: z.string(), - - /** Display name */ - name: z.string(), - - /** Icon URL */ - iconUrl: z.string().url().optional(), - - /** Installed version */ - installedVersion: z.string(), - - /** Latest available version */ - latestVersion: z.string().optional(), - - /** Whether an update is available */ - updateAvailable: z.boolean().default(false), - - /** Whether the app is currently enabled */ - enabled: z.boolean().default(true), - - /** Subscription status (for paid apps) */ - subscriptionStatus: SubscriptionStatusSchema.optional(), - - /** Installed timestamp */ - installedAt: z.string().datetime(), -})); - -/** - * List Installed Apps Request - */ -export const ListInstalledAppsRequestSchema = lazySchema(() => z.object({ - /** Tenant ID */ - tenantId: z.string().optional(), - - /** Filter by enabled/disabled */ - enabled: z.boolean().optional(), - - /** Filter by update availability */ - updateAvailable: z.boolean().optional(), - - /** Sort by */ - sortBy: z.enum(['name', 'installed-date', 'updated-date']).default('name'), - - /** Pagination */ - page: z.number().int().min(1).default(1), - pageSize: z.number().int().min(1).max(100).default(20), -})); - -/** - * List Installed Apps Response - */ -export const ListInstalledAppsResponseSchema = lazySchema(() => z.object({ - /** Installed apps */ - items: z.array(InstalledAppSummarySchema), - - /** Total count */ - total: z.number().int().min(0), - - /** Pagination */ - page: z.number().int().min(1), - pageSize: z.number().int().min(1), -})); - -// ========================================== -// Export Types -// ========================================== - -export type ReviewModerationStatus = z.input; -export type UserReview = z.input; -/** Post-parse shape of {@link UserReview} — defaults applied, transforms run (ADR-0122). */ -export type UserReviewParsed = z.infer; -export type SubmitReviewRequest = z.input; -export type ListReviewsRequest = z.input; -/** Post-parse shape of {@link ListReviewsRequest} — defaults applied, transforms run (ADR-0122). */ -export type ListReviewsRequestParsed = z.infer; -export type ListReviewsResponse = z.input; -/** Post-parse shape of {@link ListReviewsResponse} — defaults applied, transforms run (ADR-0122). */ -export type ListReviewsResponseParsed = z.infer; -export type RecommendationReason = z.input; -export type RecommendedApp = z.input; -export type AppDiscoveryRequest = z.input; -/** Post-parse shape of {@link AppDiscoveryRequest} — defaults applied, transforms run (ADR-0122). */ -export type AppDiscoveryRequestParsed = z.infer; -export type AppDiscoveryResponse = z.input; -export type SubscriptionStatus = z.input; -export type AppSubscription = z.input; -/** Post-parse shape of {@link AppSubscription} — defaults applied, transforms run (ADR-0122). */ -export type AppSubscriptionParsed = z.infer; -export type InstalledAppSummary = z.input; -/** Post-parse shape of {@link InstalledAppSummary} — defaults applied, transforms run (ADR-0122). */ -export type InstalledAppSummaryParsed = z.infer; -export type ListInstalledAppsRequest = z.input; -/** Post-parse shape of {@link ListInstalledAppsRequest} — defaults applied, transforms run (ADR-0122). */ -export type ListInstalledAppsRequestParsed = z.infer; -export type ListInstalledAppsResponse = z.input; -/** Post-parse shape of {@link ListInstalledAppsResponse} — defaults applied, transforms run (ADR-0122). */ -export type ListInstalledAppsResponseParsed = z.infer; diff --git a/packages/spec/src/cloud/developer-portal.test.ts b/packages/spec/src/cloud/developer-portal.test.ts deleted file mode 100644 index 3358e229e3..0000000000 --- a/packages/spec/src/cloud/developer-portal.test.ts +++ /dev/null @@ -1,254 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { - PublisherProfileSchema, - ReleaseChannelSchema, - VersionReleaseSchema, - CreateListingRequestSchema, - UpdateListingRequestSchema, - ListingActionRequestSchema, - AnalyticsTimeRangeSchema, - PublishingAnalyticsRequestSchema, - PublishingAnalyticsResponseSchema, - TimeSeriesPointSchema, -} from './developer-portal.zod'; - -describe('PublisherProfileSchema', () => { - it('should accept minimal publisher profile', () => { - const profile = { - organizationId: 'org-001', - publisherId: 'pub-001', - registeredAt: '2025-01-15T10:00:00Z', - }; - const parsed = PublisherProfileSchema.parse(profile); - expect(parsed.verification).toBe('unverified'); - }); - - it('should accept full publisher profile', () => { - const profile = { - organizationId: 'org-001', - publisherId: 'pub-001', - verification: 'verified' as const, - agreementVersion: '2.0', - website: 'https://acme.com', - supportEmail: 'support@acme.com', - registeredAt: '2025-01-15T10:00:00Z', - }; - const parsed = PublisherProfileSchema.parse(profile); - expect(parsed.verification).toBe('verified'); - expect(parsed.agreementVersion).toBe('2.0'); - }); - - it('should require valid support email', () => { - const profile = { - organizationId: 'org-001', - publisherId: 'pub-001', - supportEmail: 'not-an-email', - registeredAt: '2025-01-15T10:00:00Z', - }; - expect(() => PublisherProfileSchema.parse(profile)).toThrow(); - }); - - it('should require valid website URL', () => { - const profile = { - organizationId: 'org-001', - publisherId: 'pub-001', - website: 'not-a-url', - registeredAt: '2025-01-15T10:00:00Z', - }; - expect(() => PublisherProfileSchema.parse(profile)).toThrow(); - }); -}); - -describe('ReleaseChannelSchema', () => { - it('should accept all channels', () => { - const channels = ['alpha', 'beta', 'rc', 'stable']; - channels.forEach(channel => { - expect(() => ReleaseChannelSchema.parse(channel)).not.toThrow(); - }); - }); -}); - -describe('VersionReleaseSchema', () => { - it('should accept minimal release', () => { - const release = { - version: '1.0.0', - }; - const parsed = VersionReleaseSchema.parse(release); - expect(parsed.channel).toBe('stable'); - expect(parsed.deprecated).toBe(false); - }); - - it('should accept beta release with changelog', () => { - const release = { - version: '2.0.0-beta.1', - channel: 'beta' as const, - releaseNotes: '## Beta Release\n\nNew pipeline view', - changelog: [ - { type: 'added' as const, description: 'New pipeline view' }, - { type: 'fixed' as const, description: 'Fixed pagination bug' }, - ], - minPlatformVersion: '1.2.0', - artifactUrl: 'https://registry.objectstack.io/com.acme.crm-2.0.0-beta.1.tgz', - artifactChecksum: 'sha256:abc123...', - releasedAt: '2025-06-01T00:00:00Z', - }; - const parsed = VersionReleaseSchema.parse(release); - expect(parsed.channel).toBe('beta'); - expect(parsed.changelog).toHaveLength(2); - }); - - it('should accept deprecated release with message', () => { - const release = { - version: '1.0.0', - deprecated: true, - deprecationMessage: 'Please upgrade to v2.0.0', - }; - const parsed = VersionReleaseSchema.parse(release); - expect(parsed.deprecated).toBe(true); - expect(parsed.deprecationMessage).toBe('Please upgrade to v2.0.0'); - }); -}); - -describe('CreateListingRequestSchema', () => { - it('should accept minimal listing creation', () => { - const request = { - packageId: 'com.acme.crm', - name: 'Acme CRM', - category: 'crm', - }; - const parsed = CreateListingRequestSchema.parse(request); - expect(parsed.pricing).toBe('free'); - }); - - it('should accept full listing creation', () => { - const request = { - packageId: 'com.acme.crm', - name: 'Acme CRM', - tagline: 'Complete CRM for ObjectStack', - description: '# Acme CRM\n\nFull-featured...', - category: 'crm', - tags: ['sales', 'pipeline'], - iconUrl: 'https://acme.com/icon.png', - screenshots: [{ url: 'https://acme.com/s1.png', caption: 'Dashboard' }], - documentationUrl: 'https://docs.acme.com', - supportUrl: 'https://support.acme.com', - repositoryUrl: 'https://github.com/acme/crm', - pricing: 'freemium' as const, - priceInCents: 999, - }; - const parsed = CreateListingRequestSchema.parse(request); - expect(parsed.screenshots).toHaveLength(1); - }); - - it('should enforce tagline max length', () => { - const request = { - packageId: 'com.acme.crm', - name: 'Test', - category: 'other', - tagline: 'x'.repeat(121), - }; - expect(() => CreateListingRequestSchema.parse(request)).toThrow(); - }); -}); - -describe('UpdateListingRequestSchema', () => { - it('should accept partial update', () => { - const request = { - listingId: 'listing-001', - tagline: 'Updated tagline', - }; - const parsed = UpdateListingRequestSchema.parse(request); - expect(parsed.tagline).toBe('Updated tagline'); - expect(parsed.name).toBeUndefined(); - }); -}); - -describe('ListingActionRequestSchema', () => { - it('should accept all listing actions', () => { - const actions = ['submit', 'unlist', 'deprecate', 'reactivate']; - actions.forEach(action => { - const request = { listingId: 'listing-001', action }; - expect(() => ListingActionRequestSchema.parse(request)).not.toThrow(); - }); - }); - - it('should accept action with reason', () => { - const request = { - listingId: 'listing-001', - action: 'deprecate' as const, - reason: 'Replaced by com.acme.crm-v2', - }; - const parsed = ListingActionRequestSchema.parse(request); - expect(parsed.reason).toBe('Replaced by com.acme.crm-v2'); - }); -}); - -describe('AnalyticsTimeRangeSchema', () => { - it('should accept all time ranges', () => { - const ranges = ['last_7d', 'last_30d', 'last_90d', 'last_365d', 'all_time']; - ranges.forEach(range => { - expect(() => AnalyticsTimeRangeSchema.parse(range)).not.toThrow(); - }); - }); -}); - -describe('PublishingAnalyticsRequestSchema', () => { - it('should accept minimal request', () => { - const request = { listingId: 'listing-001' }; - const parsed = PublishingAnalyticsRequestSchema.parse(request); - expect(parsed.timeRange).toBe('last_30d'); - }); - - it('should accept request with specific metrics', () => { - const request = { - listingId: 'listing-001', - timeRange: 'last_90d' as const, - metrics: ['installs', 'ratings', 'revenue'], - }; - const parsed = PublishingAnalyticsRequestSchema.parse(request); - expect(parsed.metrics).toHaveLength(3); - }); -}); - -describe('TimeSeriesPointSchema', () => { - it('should accept data point', () => { - const point = { date: '2025-06-01', value: 42 }; - const parsed = TimeSeriesPointSchema.parse(point); - expect(parsed.value).toBe(42); - }); -}); - -describe('PublishingAnalyticsResponseSchema', () => { - it('should accept analytics response', () => { - const response = { - listingId: 'listing-001', - timeRange: 'last_30d' as const, - summary: { - totalInstalls: 5000, - activeInstalls: 3200, - totalUninstalls: 800, - averageRating: 4.5, - totalRatings: 120, - totalRevenue: 99900, - pageViews: 15000, - }, - timeSeries: { - installs: [ - { date: '2025-06-01', value: 45 }, - { date: '2025-06-02', value: 52 }, - ], - }, - ratingDistribution: { - 1: 2, - 2: 5, - 3: 15, - 4: 48, - 5: 50, - }, - }; - const parsed = PublishingAnalyticsResponseSchema.parse(response); - expect(parsed.summary.totalInstalls).toBe(5000); - expect(parsed.timeSeries?.installs).toHaveLength(2); - expect(parsed.ratingDistribution?.[5]).toBe(50); - }); -}); diff --git a/packages/spec/src/cloud/developer-portal.zod.ts b/packages/spec/src/cloud/developer-portal.zod.ts deleted file mode 100644 index 50976509b7..0000000000 --- a/packages/spec/src/cloud/developer-portal.zod.ts +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { z } from 'zod'; -import { PublisherVerificationSchema } from './marketplace.zod'; - -/** - * # Developer Portal Protocol - * - * Defines schemas for the developer-facing side of the marketplace ecosystem. - * Covers the complete developer journey: - * - * ``` - * Register → Create App → Develop → Validate → Build → Submit → Monitor → Iterate - * ``` - * - * ## Architecture Alignment - * - **Salesforce Partner Portal**: ISV registration, AppExchange publishing, Trialforce - * - **Shopify Partner Dashboard**: App management, analytics, billing - * - **VS Code Marketplace Management**: Extension publishing, statistics, tokens - * - * ## Identity Integration (better-auth) - * Authentication, organization management, and API keys are handled by the - * Identity module (`@objectstack/spec` Identity namespace), which follows the - * better-auth specification. This module only defines marketplace-specific - * extensions on top of the shared identity layer: - * - * - **User** → `Identity.UserSchema`; the session wire shape is `Session` from - * `@objectstack/spec/api` (the identity module deliberately declares no bare - * `SessionSchema` — #4641) - * - **Organization & Members** → `Identity.OrganizationSchema`, `Identity.MemberSchema` - * - **API Keys** → the `sys_api_key` ObjectSchema in - * `@objectstack/platform-objects` (`identity/sys-api-key.object.ts`), minted via - * `POST /api/v1/keys`; its `scopes` column is the marketplace-scope carrier. - * There is no `Identity.ApiKeySchema` — #8715 retired it (it documented - * better-auth's apiKey plugin, which this platform does not load) - * - * ## Key Concepts - * - **Publisher Profile**: Links an Identity Organization to a marketplace publisher - * - **App Listing Management**: CRUD for marketplace listings (draft → published) - * - **Version Channels**: alpha / beta / rc / stable release channels - * - **Publishing Analytics**: Install trends, revenue, ratings over time - */ - -// ========================================== -// Publisher Profile (extends Identity.Organization) -// ========================================== - -/** - * Publisher Profile Schema - * - * Links an Identity Organization to a marketplace publisher identity. - * The organization itself (name, slug, logo, members) is managed via - * Identity.OrganizationSchema and Identity.MemberSchema (better-auth aligned). - * - * This schema only holds marketplace-specific publisher metadata. - */ -import { lazySchema } from '../shared/lazy-schema'; -export const PublisherProfileSchema = lazySchema(() => z.object({ - /** Organization ID (references Identity.Organization.id) */ - organizationId: z.string().describe('Identity Organization ID'), - - /** Publisher ID (marketplace-assigned identifier) */ - publisherId: z.string().describe('Marketplace publisher ID'), - - /** Verification level (marketplace trust tier) */ - verification: PublisherVerificationSchema.default('unverified'), - - /** Accepted developer program agreement version */ - agreementVersion: z.string().optional().describe('Accepted developer agreement version'), - - /** Publisher-specific website (may differ from org) */ - website: z.string().url().optional().describe('Publisher website'), - - /** Publisher-specific support email */ - supportEmail: z.string().email().optional().describe('Publisher support email'), - - /** Registration timestamp (when org became a publisher) */ - registeredAt: z.string().datetime(), -})); - -// ========================================== -// Version Channels & Release Management -// ========================================== - -/** - * Release Channel — allows pre-release distribution - */ -export const ReleaseChannelSchema = lazySchema(() => z.enum([ - 'alpha', // Early development, unstable - 'beta', // Feature-complete, testing phase - 'rc', // Release candidate, final testing - 'stable', // Production-ready, general availability -])); - -/** - * Version Release Schema - * - * A single version release of a package with channel assignment. - */ -export const VersionReleaseSchema = lazySchema(() => z.object({ - /** Semver version string */ - version: z.string().describe('Semver version (e.g., 2.1.0-beta.1)'), - - /** Release channel */ - channel: ReleaseChannelSchema.default('stable'), - - /** Release notes (Markdown) */ - releaseNotes: z.string().optional().describe('Release notes (Markdown)'), - - /** Changelog entries (structured) */ - changelog: z.array(z.object({ - type: z.enum(['added', 'changed', 'fixed', 'removed', 'deprecated', 'security']), - description: z.string(), - })).optional().describe('Structured changelog entries'), - - /** Minimum platform version required */ - minPlatformVersion: z.string().optional(), - - /** Build artifact URL */ - artifactUrl: z.string().optional().describe('Built package artifact URL'), - - /** Artifact checksum (integrity) */ - artifactChecksum: z.string().optional().describe('SHA-256 checksum'), - - /** Whether this version is deprecated */ - deprecated: z.boolean().default(false), - - /** Deprecation message (if deprecated) */ - deprecationMessage: z.string().optional(), - - /** Release timestamp */ - releasedAt: z.string().datetime().optional(), -})); - -// ========================================== -// App Listing Management (Developer CRUD) -// ========================================== - -/** - * Create Listing Request — developer creates a new marketplace listing - */ -export const CreateListingRequestSchema = lazySchema(() => z.object({ - /** Package ID (reverse domain, e.g., com.acme.crm) */ - packageId: z.string().describe('Package identifier'), - - /** Display name */ - name: z.string().describe('App display name'), - - /** Short tagline (max 120 chars) */ - tagline: z.string().max(120).optional(), - - /** Full description (Markdown) */ - description: z.string().optional(), - - /** Category */ - category: z.string().describe('Marketplace category'), - - /** Additional tags */ - tags: z.array(z.string()).optional(), - - /** Icon URL */ - iconUrl: z.string().url().optional(), - - /** Screenshots */ - screenshots: z.array(z.object({ - url: z.string().url(), - caption: z.string().optional(), - })).optional(), - - /** Documentation URL */ - documentationUrl: z.string().url().optional(), - - /** Support URL */ - supportUrl: z.string().url().optional(), - - /** Source repository URL */ - repositoryUrl: z.string().url().optional(), - - /** Pricing model */ - pricing: z.enum([ - 'free', 'freemium', 'paid', 'subscription', 'usage-based', 'contact-sales', - ]).default('free'), - - /** Price in cents (if paid) */ - priceInCents: z.number().int().min(0).optional(), -})); - -/** - * Update Listing Request — developer updates listing metadata - */ -export const UpdateListingRequestSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string().describe('Listing ID to update'), - - /** Updatable fields (all optional, partial update) */ - name: z.string().optional(), - tagline: z.string().max(120).optional(), - description: z.string().optional(), - category: z.string().optional(), - tags: z.array(z.string()).optional(), - iconUrl: z.string().url().optional(), - screenshots: z.array(z.object({ - url: z.string().url(), - caption: z.string().optional(), - })).optional(), - documentationUrl: z.string().url().optional(), - supportUrl: z.string().url().optional(), - repositoryUrl: z.string().url().optional(), - pricing: z.enum([ - 'free', 'freemium', 'paid', 'subscription', 'usage-based', 'contact-sales', - ]).optional(), - priceInCents: z.number().int().min(0).optional(), -})); - -/** - * Listing Action Request — lifecycle actions on a listing - */ -export const ListingActionRequestSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string().describe('Listing ID'), - - /** Action to perform */ - action: z.enum([ - 'submit', // Submit for review - 'unlist', // Remove from public search (keep accessible by direct link) - 'deprecate', // Mark as deprecated - 'reactivate', // Reactivate unlisted/deprecated listing - ]).describe('Action to perform on listing'), - - /** Reason for action (e.g., deprecation message) */ - reason: z.string().optional(), -})); - -// ========================================== -// Publishing Analytics (Developer Dashboard) -// ========================================== - -/** - * Analytics Time Range - */ -export const AnalyticsTimeRangeSchema = lazySchema(() => z.enum([ - 'last_7d', - 'last_30d', - 'last_90d', - 'last_365d', - 'all_time', -])); - -/** - * Publishing Analytics Request - */ -export const PublishingAnalyticsRequestSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string().describe('Listing to get analytics for'), - - /** Time range */ - timeRange: AnalyticsTimeRangeSchema.default('last_30d'), - - /** Metrics to include */ - metrics: z.array(z.enum([ - 'installs', // Install count over time - 'uninstalls', // Uninstall count over time - 'active_installs', // Active install trend - 'ratings', // Rating distribution - 'revenue', // Revenue (for paid apps) - 'page_views', // Listing page views - ])).optional().describe('Metrics to include (default: all)'), -})); - -/** - * Time Series Data Point - */ -export const TimeSeriesPointSchema = lazySchema(() => z.object({ - /** ISO date string (day granularity) */ - date: z.string(), - /** Metric value */ - value: z.number(), -})); - -/** - * Publishing Analytics Response - */ -export const PublishingAnalyticsResponseSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string(), - - /** Time range */ - timeRange: AnalyticsTimeRangeSchema, - - /** Summary statistics */ - summary: z.object({ - totalInstalls: z.number().int().min(0), - activeInstalls: z.number().int().min(0), - totalUninstalls: z.number().int().min(0), - averageRating: z.number().min(0).max(5).optional(), - totalRatings: z.number().int().min(0), - totalRevenue: z.number().min(0).optional().describe('Revenue in cents'), - pageViews: z.number().int().min(0), - }), - - /** Time series data by metric */ - timeSeries: z.record(z.string(), z.array(TimeSeriesPointSchema)).optional() - .describe('Time series keyed by metric name'), - - /** Rating distribution (1-5 stars) */ - ratingDistribution: z.object({ - 1: z.number().int().min(0).default(0), - 2: z.number().int().min(0).default(0), - 3: z.number().int().min(0).default(0), - 4: z.number().int().min(0).default(0), - 5: z.number().int().min(0).default(0), - }).optional(), -})); - -// ========================================== -// Export Types -// ========================================== - -export type PublisherProfile = z.input; -/** Post-parse shape of {@link PublisherProfile} — defaults applied, transforms run (ADR-0122). */ -export type PublisherProfileParsed = z.infer; -export type ReleaseChannel = z.input; -export type VersionRelease = z.input; -/** Post-parse shape of {@link VersionRelease} — defaults applied, transforms run (ADR-0122). */ -export type VersionReleaseParsed = z.infer; -export type CreateListingRequest = z.input; -/** Post-parse shape of {@link CreateListingRequest} — defaults applied, transforms run (ADR-0122). */ -export type CreateListingRequestParsed = z.infer; -export type UpdateListingRequest = z.input; -export type ListingActionRequest = z.input; -export type AnalyticsTimeRange = z.input; -export type PublishingAnalyticsRequest = z.input; -/** Post-parse shape of {@link PublishingAnalyticsRequest} — defaults applied, transforms run (ADR-0122). */ -export type PublishingAnalyticsRequestParsed = z.infer; -export type TimeSeriesPoint = z.input; -export type PublishingAnalyticsResponse = z.input; -/** Post-parse shape of {@link PublishingAnalyticsResponse} — defaults applied, transforms run (ADR-0122). */ -export type PublishingAnalyticsResponseParsed = z.infer; diff --git a/packages/spec/src/cloud/environment-artifact.zod.ts b/packages/spec/src/cloud/environment-artifact.zod.ts deleted file mode 100644 index 8da7fb31f5..0000000000 --- a/packages/spec/src/cloud/environment-artifact.zod.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -/** - * # Environment Artifact Envelope — re-export (#4740, #4535 C10) - * - * The envelope has exactly ONE declaration: - * `../system/environment-artifact.zod` (maintainer route A′ on #4740 — - * `./system` holds the live wire shape, `./cloud` re-exports it). Importing - * from `@objectstack/spec/cloud` and `@objectstack/spec/system` yields the - * SAME symbols, so the import path can never change the shape a consumer - * gets (the #4411 dual-source trap, closed for this name). - * - * Do NOT re-declare the envelope here. A second declaration under this name - * is exactly what `check:dual-source-exports` and the symbol-identity pin in - * `../system/environment-artifact.test.ts` exist to reject. - */ -export { - Sha256DigestSchema, - EnvironmentArtifactSchema, -} from '../system/environment-artifact.zod'; -export type { - Sha256Digest, - EnvironmentArtifact, - EnvironmentArtifactParsed, -} from '../system/environment-artifact.zod'; diff --git a/packages/spec/src/cloud/environment-package.zod.ts b/packages/spec/src/cloud/environment-package.zod.ts deleted file mode 100644 index c614940879..0000000000 --- a/packages/spec/src/cloud/environment-package.zod.ts +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { z } from 'zod'; -import { lazySchema } from '../shared/lazy-schema'; - -/** - * # Environment Package Installation Protocol - * - * Models `sys_package_installation` — the pairing between an Environment and - * a specific, immutable `sys_package_version` snapshot. - * - * Key invariants (per ADR-0003): - * - One active version per package per environment at any time - * (UNIQUE `(environment_id, package_id)`). - * - **Upgrade** = atomic `UPDATE package_version_id` to a newer version UUID. - * - **Rollback** = atomic `UPDATE package_version_id` to an older version UUID. - * - Only `status = 'published'` versions may be installed in production - * environments (draft/pre-release allowed in dev/sandbox with `allowDraft`). - * - * Stored in the **Control Plane DB** (not in environment data-plane DBs). - */ - -// --------------------------------------------------------------------------- -// Enums -// --------------------------------------------------------------------------- - -/** - * Lifecycle status of a package installation within an environment. - */ -export const EnvironmentPackageStatusSchema = lazySchema(() => z - .enum([ - 'installed', // Active and running; metadata loaded into this environment - 'installing', // Install in progress (async) - 'upgrading', // Version swap in progress (async) - 'disabled', // Installed but not active — metadata not loaded - 'error', // Install/upgrade failed; see errorMessage - ]) - .describe('Package installation status within an environment')); - -export type EnvironmentPackageStatus = z.input; - -// --------------------------------------------------------------------------- -// sys_package_installation — Environment ↔ version pairing -// --------------------------------------------------------------------------- - -/** - * One row in `sys_package_installation`. - * - * Unique by `(environment_id, package_id)` — only one version of a given - * package may be active per environment. - */ -export const EnvironmentPackageInstallationSchema = lazySchema(() => z.object({ - /** Unique installation record ID (UUID). */ - id: z.string().uuid().describe('Unique installation record ID'), - - /** Environment that owns this installation (FK → sys_environment). */ - environmentId: z.string().uuid().describe('Environment this installation belongs to'), - - /** - * The specific, immutable version snapshot that is installed - * (FK → sys_package_version.id). - * - * Upgrading = swapping this field to a newer version UUID. - * Rollback = swapping this field to an older version UUID. - */ - packageVersionId: z.string().uuid() - .describe('UUID of the installed sys_package_version row'), - - /** - * Denormalized package UUID (FK → sys_package.id) copied from the version - * row at install time. Used for the UNIQUE (environment_id, package_id) - * constraint without a join. - */ - packageId: z.string().uuid() - .describe('UUID of the parent sys_package row (denormalized for constraint enforcement)'), - - /** Current lifecycle status within this environment. */ - status: EnvironmentPackageStatusSchema.default('installed'), - - /** Whether the package is active (metadata loaded and available). */ - enabled: z.boolean().default(true).describe('Whether the package metadata is loaded'), - - /** - * Per-installation configuration values. - * Keys mirror the package manifest's `configurationSchema.properties`. - */ - settings: z.record(z.string(), z.unknown()).optional() - .describe('Per-installation configuration settings'), - - /** - * When true, the environment runtime will replay the package's seed - * datasets (demo Accounts / Contacts / …) into the primary organization - * the next time the environment kernel boots. Set at install time and - * never auto-cleared so the env can re-seed on cold-start until the user - * explicitly disables it. - */ - withSampleData: z.boolean().optional().default(false) - .describe('Replay the package seed datasets on next kernel cold-start'), - - /** ISO-8601 timestamp when this installation was created. */ - installedAt: z.string().datetime().describe('Installation timestamp (ISO-8601)'), - - /** User ID of the member who performed the install (null for system installs). */ - installedBy: z.string().optional().describe('User ID of the installer'), - - /** ISO-8601 timestamp of the most recent update (version swap, enable/disable). */ - updatedAt: z.string().datetime().optional().describe('Last update timestamp (ISO-8601)'), - - /** Error details when `status === "error"`. */ - errorMessage: z.string().optional().describe('Error message when status is error'), -}).describe('Package installation record in an environment (sys_package_installation)')); - -export type EnvironmentPackageInstallation = z.input; -/** Post-parse shape of {@link EnvironmentPackageInstallation} — defaults applied, transforms run (ADR-0122). */ -export type EnvironmentPackageInstallationParsed = z.infer; - -// --------------------------------------------------------------------------- -// Install / Upgrade / Rollback requests -// --------------------------------------------------------------------------- - -/** - * Request body for `POST /cloud/environments/:environmentId/packages` - * (or the legacy `/cloud/environments/:environmentId/packages` alias). - */ -export const InstallPackageToEnvironmentRequestSchema = lazySchema(() => z.object({ - packageVersionId: z.string().uuid().optional() - .describe('Exact package version UUID to install (preferred)'), - packageManifestId: z.string().optional() - .describe('Package manifest ID (reverse-domain, e.g. com.acme.crm) — resolved to version UUID'), - version: z.string().optional().describe('Version string (defaults to latest published)'), - allowDraft: z.boolean().default(false) - .describe('Allow installing a draft version (dev/sandbox environments only)'), - settings: z.record(z.string(), z.unknown()).optional() - .describe('Installation-time configuration settings'), - withSampleData: z.boolean().optional().default(false) - .describe('Replay the package seed datasets on next kernel cold-start'), - enableOnInstall: z.boolean().default(true) - .describe('Activate the package immediately after install'), - installedBy: z.string().optional().describe('User ID of the installer'), -}).describe('Install a package version into a specific environment') - .refine( - data => data.packageVersionId != null || data.packageManifestId != null, - { message: 'Either packageVersionId or packageManifestId must be provided' } - )); - -export type InstallPackageToEnvironmentRequest = z.input; -/** Post-parse shape of {@link InstallPackageToEnvironmentRequest} — defaults applied, transforms run (ADR-0122). */ -export type InstallPackageToEnvironmentRequestParsed = z.infer; - -/** - * Request body for upgrading a package installation. - */ -export const UpgradeEnvironmentPackageRequestSchema = lazySchema(() => z.object({ - targetPackageVersionId: z.string().uuid().optional() - .describe('Target package version UUID (preferred)'), - targetVersion: z.string().optional() - .describe('Target version string (defaults to latest published)'), - allowDraft: z.boolean().default(false) - .describe('Allow upgrading to a draft version'), - upgradedBy: z.string().optional().describe('User ID performing the upgrade'), -}).describe('Upgrade a package installation to a newer version')); - -export type UpgradeEnvironmentPackageRequest = z.input; -/** Post-parse shape of {@link UpgradeEnvironmentPackageRequest} — defaults applied, transforms run (ADR-0122). */ -export type UpgradeEnvironmentPackageRequestParsed = z.infer; - -/** - * Request body for rolling back a package installation. - */ -export const RollbackEnvironmentPackageRequestSchema = lazySchema(() => z.object({ - targetPackageVersionId: z.string().uuid() - .describe('Package version UUID to roll back to'), - rolledBackBy: z.string().optional().describe('User ID performing the rollback'), -}).describe('Roll back a package installation to a specific older version')); - -export type RollbackEnvironmentPackageRequest = z.input; - -// --------------------------------------------------------------------------- -// Response schemas -// --------------------------------------------------------------------------- - -/** - * Response from `GET /cloud/environments/:environmentId/packages`. - */ -export const ListEnvironmentPackagesResponseSchema = lazySchema(() => z.object({ - packages: z.array(EnvironmentPackageInstallationSchema) - .describe('Packages installed in this environment'), - total: z.number().describe('Total count'), -}).describe('List of packages installed in an environment')); - -export type ListEnvironmentPackagesResponse = z.input; -/** Post-parse shape of {@link ListEnvironmentPackagesResponse} — defaults applied, transforms run (ADR-0122). */ -export type ListEnvironmentPackagesResponseParsed = z.infer; diff --git a/packages/spec/src/cloud/environment.test.ts b/packages/spec/src/cloud/environment.test.ts deleted file mode 100644 index 2c0b4d5947..0000000000 --- a/packages/spec/src/cloud/environment.test.ts +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { describe, it, expect } from 'vitest'; -import { - EnvironmentSchema, - EnvironmentStatusSchema, - EnvironmentCredentialSchema, - EnvironmentCredentialStatusSchema, - EnvironmentMemberSchema, - EnvironmentRoleSchema, - ProvisionEnvironmentRequestSchema, - ProvisionEnvironmentResponseSchema, - ProvisionOrganizationRequestSchema, -} from './environment.zod'; -describe('EnvironmentStatusSchema', () => { - it('accepts lifecycle statuses including migrating', () => { - for (const s of [ - 'provisioning', - 'active', - 'suspended', - 'archived', - 'failed', - 'migrating', - ]) { - expect(() => EnvironmentStatusSchema.parse(s)).not.toThrow(); - } - }); -}); - -describe('EnvironmentSchema', () => { - const base = { - id: '550e8400-e29b-41d4-a716-446655440000', - organizationId: 'org_1', - displayName: 'Production', - isDefault: true, - plan: 'pro' as const, - status: 'active' as const, - createdBy: 'user_1', - createdAt: '2026-04-19T00:00:00.000Z', - updatedAt: '2026-04-19T00:00:00.000Z', - }; - - it('parses a valid environment', () => { - expect(() => EnvironmentSchema.parse(base)).not.toThrow(); - }); - - it('rejects a non-UUID id', () => { - expect(() => EnvironmentSchema.parse({ ...base, id: 'not-a-uuid' })).toThrow(); - }); - - it('defaults isDefault to false when omitted', () => { - const { isDefault: _d, ...rest } = base; - const parsed = EnvironmentSchema.parse(rest); - expect(parsed.isDefault).toBe(false); - }); - - it('does not define a slug, envType, or region field', () => { - const parsed = EnvironmentSchema.parse(base); - expect((parsed as any).slug).toBeUndefined(); - expect((parsed as any).envType).toBeUndefined(); - expect((parsed as any).region).toBeUndefined(); - }); - - it('defaults visibility to private', () => { - const parsed = EnvironmentSchema.parse(base); - expect(parsed.visibility).toBe('private'); - }); - - it('accepts pre-computed consoleUrl and apiBaseUrl', () => { - const parsed = EnvironmentSchema.parse({ - ...base, - hostname: 'acme-prod.objectstack.app', - consoleUrl: 'https://acme-prod.objectstack.app/_console', - apiBaseUrl: 'https://acme-prod.objectstack.app/api/v1', - }); - expect(parsed.consoleUrl).toBe('https://acme-prod.objectstack.app/_console'); - expect(parsed.apiBaseUrl).toBe('https://acme-prod.objectstack.app/api/v1'); - }); -}); - -describe('EnvironmentCredentialSchema', () => { - it('parses a valid active credential', () => { - const cred = EnvironmentCredentialSchema.parse({ - id: '550e8400-e29b-41d4-a716-446655440000', - environmentId: '550e8400-e29b-41d4-a716-446655440001', - secretCiphertext: 'ciphertext', - encryptionKeyId: 'kms-key-1', - createdAt: '2026-04-19T00:00:00.000Z', - }); - expect(cred.status).toBe('active'); - expect(cred.authorization).toBe('full_access'); - }); - - it('rejects unknown status', () => { - expect(() => - EnvironmentCredentialSchema.parse({ - id: '550e8400-e29b-41d4-a716-446655440000', - environmentId: '550e8400-e29b-41d4-a716-446655440001', - secretCiphertext: 'ciphertext', - encryptionKeyId: 'kms-key-1', - createdAt: '2026-04-19T00:00:00.000Z', - status: 'bogus', - }), - ).toThrow(); - }); - - it('accepts the full rotation status set', () => { - for (const s of ['active', 'rotating', 'revoked']) { - expect(() => EnvironmentCredentialStatusSchema.parse(s)).not.toThrow(); - } - }); -}); - -describe('EnvironmentMemberSchema', () => { - it('accepts canonical roles', () => { - for (const r of ['owner', 'admin', 'maker', 'reader', 'guest']) { - expect(() => EnvironmentRoleSchema.parse(r)).not.toThrow(); - } - }); - - it('parses a valid member row', () => { - expect(() => - EnvironmentMemberSchema.parse({ - id: '550e8400-e29b-41d4-a716-446655440000', - environmentId: '550e8400-e29b-41d4-a716-446655440001', - userId: 'user_1', - role: 'admin', - invitedBy: 'user_0', - createdAt: '2026-04-19T00:00:00.000Z', - updatedAt: '2026-04-19T00:00:00.000Z', - }), - ).not.toThrow(); - }); -}); - -describe('ProvisionEnvironmentRequestSchema', () => { - it('accepts a minimal request (only organizationId + displayName + createdBy)', () => { - expect(() => - ProvisionEnvironmentRequestSchema.parse({ - organizationId: 'org_1', - displayName: 'Alice dev', - createdBy: 'user_1', - }), - ).not.toThrow(); - }); - - it('rejects a request missing displayName', () => { - expect(() => - ProvisionEnvironmentRequestSchema.parse({ - organizationId: 'org_1', - createdBy: 'user_1', - }), - ).toThrow(); - }); - - it('rejects an empty displayName', () => { - expect(() => - ProvisionEnvironmentRequestSchema.parse({ - organizationId: 'org_1', - displayName: '', - createdBy: 'user_1', - }), - ).toThrow(); - }); -}); - -describe('ProvisionEnvironmentResponseSchema — hostnameAssignment', () => { - const environment = { - id: '550e8400-e29b-41d4-a716-446655440000', - organizationId: 'org_1', - displayName: 'Alice dev', - isDefault: false, - plan: 'pro' as const, - status: 'active' as const, - createdBy: 'user_1', - createdAt: '2026-04-19T00:00:00.000Z', - updatedAt: '2026-04-19T00:00:00.000Z', - hostname: 'alice-dev-9f3a.objectstack.app', - }; - const credential = { - id: '550e8400-e29b-41d4-a716-446655440001', - environmentId: '550e8400-e29b-41d4-a716-446655440000', - secretCiphertext: 'ciphertext', - encryptionKeyId: 'kms-key-1', - createdAt: '2026-04-19T00:00:00.000Z', - }; - const base = { environment, credential, durationMs: 1234 }; - - it('parses a response WITHOUT hostnameAssignment (no rename happened)', () => { - const parsed = ProvisionEnvironmentResponseSchema.parse(base); - expect(parsed.hostnameAssignment).toBeUndefined(); - }); - - it('parses a response WITH hostnameAssignment and preserves both hostnames', () => { - const parsed = ProvisionEnvironmentResponseSchema.parse({ - ...base, - hostnameAssignment: { - requestedHostname: 'alice-dev.objectstack.app', - assignedHostname: 'alice-dev-9f3a.objectstack.app', - }, - }); - expect(parsed.hostnameAssignment).toEqual({ - requestedHostname: 'alice-dev.objectstack.app', - assignedHostname: 'alice-dev-9f3a.objectstack.app', - }); - }); - - it('rejects hostnameAssignment missing assignedHostname', () => { - expect(() => - ProvisionEnvironmentResponseSchema.parse({ - ...base, - hostnameAssignment: { requestedHostname: 'alice-dev.objectstack.app' }, - }), - ).toThrow(); - }); - - it('rejects hostnameAssignment missing requestedHostname', () => { - expect(() => - ProvisionEnvironmentResponseSchema.parse({ - ...base, - hostnameAssignment: { assignedHostname: 'alice-dev-9f3a.objectstack.app' }, - }), - ).toThrow(); - }); - - it('rejects non-string hostnames inside hostnameAssignment', () => { - expect(() => - ProvisionEnvironmentResponseSchema.parse({ - ...base, - hostnameAssignment: { requestedHostname: 'a.objectstack.app', assignedHostname: 42 }, - }), - ).toThrow(); - }); - - it('rejects a non-object hostnameAssignment', () => { - expect(() => - ProvisionEnvironmentResponseSchema.parse({ - ...base, - hostnameAssignment: 'alice-dev-9f3a.objectstack.app', - }), - ).toThrow(); - }); - - // Why the field has to be declared HERE and not extended on in the control - // plane: an undeclared sibling key is stripped by `z.object`, so a - // cloud-local rename receipt would silently evaporate on the way out. - it('strips an undeclared sibling key — the reason this field is declared in spec', () => { - const parsed = ProvisionEnvironmentResponseSchema.parse({ - ...base, - renamedHostname: 'alice-dev-9f3a.objectstack.app', - }); - expect((parsed as Record).renamedHostname).toBeUndefined(); - expect(Object.keys(parsed)).not.toContain('renamedHostname'); - }); -}); - -describe('ProvisionOrganizationRequestSchema', () => { - it('applies default defaultEnvironmentDisplayName', () => { - const parsed = ProvisionOrganizationRequestSchema.parse({ - organizationId: 'org_1', - createdBy: 'user_1', - }); - expect(parsed.defaultEnvironmentDisplayName).toBe('Production'); - }); -}); diff --git a/packages/spec/src/cloud/environment.zod.ts b/packages/spec/src/cloud/environment.zod.ts deleted file mode 100644 index d4e6bed9e7..0000000000 --- a/packages/spec/src/cloud/environment.zod.ts +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { z } from 'zod'; -import { TenantPlanSchema } from './tenant.zod'; -import { lazySchema } from '../shared/lazy-schema'; - -/** - * # Environment Protocol (runtime container) - * - * An **Environment** is the runtime container of an organization's data. - * It owns a physically isolated database, a canonical hostname, a plan/quota - * tier, and per-environment RBAC. An organization may own many environments - * (dev/test/prod/sandbox/preview/…) — exactly one is marked `is_default`. - * - * This file defines the Control-Plane schemas for the `sys_environment`, - * `sys_environment_credential` and `sys_environment_member` tables. Business - * data lives in each environment's own database — those data-plane DBs hold - * no system tables. - * - * See ADR-0006 v4: `sys_project` was renamed to `sys_environment`; the - * separate dev-workspace `Project` concept introduced in v3 has been - * dropped — user code is now modelled as an implicit `sys_package` with - * a per-org `manifest_id` (see ADR-0003), so a single package + version - * + installation model serves both Marketplace apps and user projects. - * - * Split of concerns: - * - **Control Plane**: `sys_environment` (includes physical DB addressing), - * `sys_package_installation` (with `environment_id`), `sys_environment_credential`, - * `sys_environment_member`, `sys_metadata` (on the metadata tables, `environment_id` - * is deprecated in favor of `organization_id` — ADR-0006 v4). - * - **Data Plane**: each environment DB contains only business objects - * (account, task, …). No system tables, no `environment_id` columns. - */ - -// --------------------------------------------------------------------------- -// Environment registry -// --------------------------------------------------------------------------- - -/** - * Environment categorical tag — canonical buckets per industry convention - * (Salesforce, Power Platform, ServiceNow all use this taxonomy). - * - * NOTE: As of ADR-0006 v3 the `sys_environment` row does not persist this tag - * as a dedicated column. It remains in the protocol as a typed advisory used - * by Studio badges, provisioning policies and SDK helpers; deployments that - * need to persist it should write it into `metadata.env_type`. - * - * ⚠️ **This is NOT the enum a discovery response advertises.** - * `DiscoverySchema.environment` (`api/discovery.zod.ts`) is a deliberately - * coarser THREE-member enum — `production` / `sandbox` / `development` — that - * answers "am I talking to production?", not "which environment is this". The - * three are a strict subset of the seven here, and `resolveDiscoveryEnvironment` - * folds the other four onto them (#4828): `test` → `development`; `staging`, - * `preview` and `trial` → `sandbox`, the enum's provisioned pre-production - * member. So a `staging` value that is first-class on this taxonomy is REJECTED - * by `DiscoveryEnvironmentSchema`; do not carry a value from here onto a - * discovery response without going through that resolver. The subset relation is - * pinned in `api/discovery-environment-subset.pin.test.ts` so neither enum can - * drift out of it silently (#5676). - * - * ⚠️ **Adding a member here is a decision over there too** (#6287). The fold - * table is typed `Record`, so a new - * bucket does not compile until someone says which of the three coarse postures - * it advertises. That is on purpose: before #6287 `preview` and `trial` reached - * `development` through a `??` fallback instead of a decision, and a new bucket - * would have joined them silently — including a production-side one, which is - * the dangerous direction (#5673). - */ -export const EnvironmentTypeSchema = lazySchema(() => z - .enum(['production', 'sandbox', 'development', 'test', 'staging', 'preview', 'trial']) - .describe('Environment categorical tag (prod/sandbox/dev/test/…)')); - -export type EnvironmentType = z.input; - -/** - * Environment lifecycle status. - * - * Transitions go through dedicated status-machine actions - * (`suspend_environment` / `resume_environment` / `archive_environment` / …) — - * direct field edits are blocked at the object layer. - */ -export const EnvironmentStatusSchema = lazySchema(() => z - .enum(['provisioning', 'active', 'suspended', 'archived', 'failed', 'migrating']) - .describe('Environment lifecycle status')); - -export type EnvironmentStatus = z.input; - -/** - * Backend driver registry — keys used by the data-plane driver factory. - * Kept open-ended (`z.string()`) so third-party drivers can register new - * backends without a core release. - */ -export const EnvironmentDriverSchema = lazySchema(() => z - .string() - .min(1) - .describe('Data-plane driver key (e.g. `turso`, `libsql`, `sqlite`, `postgres`)')); - -export type EnvironmentDriver = z.input; - -/** - * Public exposure of an environment's compiled artifacts. - * - * - `private` (default) — every read requires authentication. - * - `unlisted` — `/pub/v1/environments/:id/artifact?commit=` works (no enumeration). - * - `public` — full listing + download via `/pub/v1/environments/:id/*`. - */ -export const EnvironmentVisibilitySchema = lazySchema(() => z - .enum(['private', 'unlisted', 'public']) - .describe('Public exposure of this environment artifacts (private | unlisted | public).')); - -export type EnvironmentVisibility = z.input; - -/** - * Environment — one logical runtime of an organization's data. - * - * Physical database connection info is stored directly on this row so a - * single lookup gives both logical and physical addressing. Environments are - * addressable by `id` (UUID) and by `hostname` (URL-unique). - */ -export const EnvironmentSchema = lazySchema(() => z.object({ - /** UUID of the environment (stable, never reused). */ - id: z.string().uuid().describe('UUID of the environment (stable, never reused)'), - - /** Organization that owns this environment. */ - organizationId: z.string().describe('Organization that owns this environment'), - - /** Display name shown in Studio and APIs. */ - displayName: z.string().describe('Display name shown in Studio and APIs'), - - /** - * Whether this is the organization's **default** environment. - * Exactly one per org carries `true`. - */ - isDefault: z.boolean().default(false).describe('Whether this is the default environment for the organization'), - - /** Whether this is a system environment (platform infrastructure, not user data). */ - isSystem: z.boolean().default(false).describe('Whether this is a system environment (platform infrastructure, not user data)'), - - /** Plan tier applied to this environment for quota/billing enforcement. */ - plan: TenantPlanSchema.default('free').describe('Plan tier for this environment'), - - /** Environment lifecycle status. Driven by status-machine actions. */ - status: EnvironmentStatusSchema.default('provisioning').describe('Environment lifecycle status'), - - /** User ID that created the environment. */ - createdBy: z.string().describe('User ID that created the environment'), - - /** Creation timestamp (ISO-8601). */ - createdAt: z.string().datetime().describe('Creation timestamp (ISO-8601)'), - - /** Last update timestamp (ISO-8601). */ - updatedAt: z.string().datetime().describe('Last update timestamp (ISO-8601)'), - - // ── Physical database addressing ── - - /** Full connection URL (e.g. `libsql://env-.turso.io`, `postgres://…`). Set after provisioning. */ - databaseUrl: z.string().url().optional().describe('Full connection URL for the environment database'), - - /** Data-plane driver key. */ - databaseDriver: EnvironmentDriverSchema.optional().describe('Data-plane driver key (turso, libsql, sqlite, memory, postgres)'), - - /** Storage quota in megabytes. */ - storageLimitMb: z.number().int().positive().optional().describe('Storage quota in megabytes'), - - /** When the physical database was provisioned. */ - provisionedAt: z.string().datetime().optional().describe('Provisioning timestamp (ISO-8601)'), - - /** Free-form metadata (feature flags, tags, …). */ - metadata: z.record(z.string(), z.unknown()).optional().describe('Free-form metadata'), - - /** - * Canonical hostname for this environment (e.g. `acme-dev.objectstack.app` or `api.acme.com`). - * UNIQUE. Auto-set on creation; can be overridden for custom domains via the - * `change_hostname` action. Used for environment resolution via hostname matching. - */ - hostname: z - .string() - .optional() - .describe( - 'Canonical hostname for this environment. UNIQUE. Auto-set on creation; can be overridden for custom domains.', - ), - - /** - * Pre-computed clickable URL into this environment's admin Console. - * Auto-derived from `hostname` at provisioning time so detail pages can - * render a real `` link without view-render template substitution. - */ - consoleUrl: z.string().url().optional().describe('Pre-computed admin Console URL for this environment'), - - /** - * Pre-computed REST API base URL for this environment. - * Auto-derived from `hostname` at provisioning time. - */ - apiBaseUrl: z.string().url().optional().describe('Pre-computed REST API base URL for this environment'), - - /** - * Public exposure of this environment's compiled artifacts. - */ - visibility: EnvironmentVisibilitySchema.optional().default('private') - .describe('Public exposure of this environment artifacts (private | unlisted | public).'), -})); - -export type Environment = z.input; -/** Post-parse shape of {@link Environment} — defaults applied, transforms run (ADR-0122). */ -export type EnvironmentParsed = z.infer; - -// --------------------------------------------------------------------------- -// Credential (rotatable) -// --------------------------------------------------------------------------- - -/** - * Credential lifecycle status — used during rotation. - */ -export const EnvironmentCredentialStatusSchema = lazySchema(() => z - .enum(['active', 'rotating', 'revoked']) - .describe('Credential lifecycle status')); - -export type EnvironmentCredentialStatus = z.input; - -/** - * Encrypted credential for an environment's database. - * - * Modeled as a separate row so credentials can be rotated independently of - * the parent environment (`status = 'rotating'` allows two active credentials - * during a rollover window). - */ -export const EnvironmentCredentialSchema = lazySchema(() => z.object({ - /** UUID of the credential. */ - id: z.string().uuid().describe('UUID of the credential'), - - /** Environment this credential authorizes. */ - environmentId: z.string().uuid().describe('Environment this credential authorizes'), - - /** Encrypted auth token or secret (ciphertext). */ - secretCiphertext: z.string().describe('Encrypted auth token or secret (ciphertext)'), - - /** KMS/encryption key ID that produced `secretCiphertext`. */ - encryptionKeyId: z.string().describe('Encryption key ID used to encrypt the secret'), - - /** Authorization scope (e.g. `full_access`, `read_only`). */ - authorization: z - .enum(['full_access', 'read_only']) - .default('full_access') - .describe('Authorization scope for this credential'), - - /** Credential lifecycle status. */ - status: EnvironmentCredentialStatusSchema.default('active').describe('Credential lifecycle status'), - - /** Credential creation timestamp. */ - createdAt: z.string().datetime().describe('Creation timestamp (ISO-8601)'), - - /** Optional expiry — after this timestamp the credential must be rotated. */ - expiresAt: z.string().datetime().optional().describe('Optional expiry timestamp'), - - /** Timestamp when the credential was revoked (null while active). */ - revokedAt: z.string().datetime().optional().describe('Revocation timestamp (if revoked)'), -})); - -export type EnvironmentCredential = z.input; -/** Post-parse shape of {@link EnvironmentCredential} — defaults applied, transforms run (ADR-0122). */ -export type EnvironmentCredentialParsed = z.infer; - -// --------------------------------------------------------------------------- -// Environment-scoped RBAC -// --------------------------------------------------------------------------- - -/** - * Per-environment role assigned to a user/service principal. - */ -export const EnvironmentRoleSchema = lazySchema(() => z - .enum(['owner', 'admin', 'maker', 'reader', 'guest']) - .describe('Per-environment role')); - -export type EnvironmentRole = z.input; - -/** - * Environment membership — grants a user access to a specific environment. - * - * Unique by `(environmentId, userId)`. - */ -export const EnvironmentMemberSchema = lazySchema(() => z.object({ - /** UUID of the membership. */ - id: z.string().uuid().describe('UUID of the membership'), - - /** Environment this membership grants access to. */ - environmentId: z.string().uuid().describe('Environment this membership grants access to'), - - /** User ID (references `user` in the control plane). */ - userId: z.string().describe('User ID'), - - /** Per-environment role. */ - role: EnvironmentRoleSchema.describe('Per-environment role'), - - /** User ID of the member who invited / granted this membership. */ - invitedBy: z.string().describe('User ID that granted this membership'), - - /** Creation timestamp. */ - createdAt: z.string().datetime().describe('Creation timestamp (ISO-8601)'), - - /** Last update timestamp. */ - updatedAt: z.string().datetime().describe('Last update timestamp (ISO-8601)'), -})); - -export type EnvironmentMember = z.input; - -// --------------------------------------------------------------------------- -// Provisioning requests / responses -// --------------------------------------------------------------------------- - -/** - * Request to provision a new environment for an organization. - * - * Backed by `EnvironmentProvisioningService.provisionEnvironment` which - * atomically allocates the physical database, mints a credential, and - * inserts the `sys_environment` row. - */ -export const ProvisionEnvironmentRequestSchema = lazySchema(() => z.object({ - organizationId: z.string().describe('Organization that will own the new environment'), - displayName: z.string().min(1).describe('Display name shown in Studio and APIs'), - driver: EnvironmentDriverSchema.optional().describe('Driver key (defaults to provisioning service config)'), - plan: TenantPlanSchema.optional().describe('Plan tier'), - storageLimitMb: z.number().int().positive().optional().describe('Storage quota in megabytes'), - isDefault: z.boolean().optional().describe('Mark as the organization default environment'), - createdBy: z.string().describe('User ID that initiated the provisioning'), - metadata: z.record(z.string(), z.unknown()).optional().describe('Free-form metadata'), - hostname: z.string().optional().describe('Canonical hostname (auto-generated if omitted)'), - templateId: z.string().optional().describe( - 'Starter package to seed into the new environment on first provisioning (e.g. "crm", "todo"). Defaults to "blank".', - ), - visibility: EnvironmentVisibilitySchema.optional().default('private').describe( - 'Public exposure of this environment artifacts. private = auth required for every read (default); ' - + 'unlisted = downloadable when commit id is known; public = listed and freely downloadable via /pub/v1/environments/:id/*.', - ), -})); - -export type ProvisionEnvironmentRequest = z.input; -/** Post-parse shape of {@link ProvisionEnvironmentRequest} — defaults applied, transforms run (ADR-0122). */ -export type ProvisionEnvironmentRequestParsed = z.infer; - -/** - * Response of a successful environment provisioning call. - */ -export const ProvisionEnvironmentResponseSchema = lazySchema(() => z.object({ - environment: EnvironmentSchema.describe('Provisioned environment (includes database addressing)'), - credential: EnvironmentCredentialSchema.describe('Freshly-minted credential for the environment DB'), - durationMs: z.number().describe('Total provisioning duration in milliseconds'), - warnings: z.array(z.string()).optional().describe('Non-fatal warnings emitted during provisioning'), - /** - * Loud rename receipt: the control plane auto-renames a colliding hostname - * (canonical hostnames are UNIQUE) by appending a short suffix instead of - * failing the call. Present ONLY when that rename actually happened — a - * provisioning call that got the hostname it asked for omits this key - * entirely, so `hostnameAssignment !== undefined` is itself the signal. - * - * Declared here rather than in the control plane so the fact survives - * `z.object` stripping and reaches generated provisioning clients, which - * are built from this protocol's published surface (`api-surface.json`). - * It is deliberately NOT carried in the free-form `metadata` bag: a caller - * must not be able to suppress or forge a trust signal the server emits. - */ - hostnameAssignment: z.object({ - requestedHostname: z - .string() - .describe('Hostname the caller asked for (explicitly, or as auto-derived from displayName)'), - assignedHostname: z - .string() - .describe('Hostname actually assigned after the collision-avoiding rename; equals `environment.hostname`'), - }) - .optional() - .describe( - 'Populated ONLY when the control plane auto-renamed the requested hostname to avoid a ' - + 'collision. Absent means the requested hostname was assigned unchanged — never read ' - + 'absence as "unknown".', - ), -})); - -export type ProvisionEnvironmentResponse = z.input; -/** Post-parse shape of {@link ProvisionEnvironmentResponse} — defaults applied, transforms run (ADR-0122). */ -export type ProvisionEnvironmentResponseParsed = z.infer; - -/** - * Request to bootstrap a brand-new organization — allocates the default - * environment (and its DB) in one atomic call. - */ -export const ProvisionOrganizationRequestSchema = lazySchema(() => z.object({ - organizationId: z.string().describe('Organization being bootstrapped'), - defaultEnvironmentDisplayName: z - .string() - .min(1) - .default('Production') - .describe('Display name for the default environment'), - driver: EnvironmentDriverSchema.optional().describe('Driver key'), - plan: TenantPlanSchema.optional().describe('Plan tier'), - storageLimitMb: z.number().int().positive().optional().describe('Storage quota in megabytes'), - createdBy: z.string().describe('User ID that initiated provisioning'), - metadata: z.record(z.string(), z.unknown()).optional().describe('Free-form metadata'), -})); - -export type ProvisionOrganizationRequest = z.input; -/** Post-parse shape of {@link ProvisionOrganizationRequest} — defaults applied, transforms run (ADR-0122). */ -export type ProvisionOrganizationRequestParsed = z.infer; - -/** - * Response of a successful organization bootstrap. - */ -export const ProvisionOrganizationResponseSchema = lazySchema(() => z.object({ - defaultEnvironment: ProvisionEnvironmentResponseSchema.describe('Default environment that was created'), - durationMs: z.number().describe('Total bootstrap duration in milliseconds'), - warnings: z.array(z.string()).optional().describe('Non-fatal warnings'), -})); - -export type ProvisionOrganizationResponse = z.input; -/** Post-parse shape of {@link ProvisionOrganizationResponse} — defaults applied, transforms run (ADR-0122). */ -export type ProvisionOrganizationResponseParsed = z.infer; diff --git a/packages/spec/src/cloud/index.ts b/packages/spec/src/cloud/index.ts deleted file mode 100644 index 99b59fb8e8..0000000000 --- a/packages/spec/src/cloud/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -/** - * Cloud Protocol - * - * Cloud-specific protocols for the ObjectStack SaaS platform. - * These schemas define the contract for cloud services like: - * - Marketplace (listing, publishing, review, search, install) - * - Developer Portal (developer registration, API keys, publishing analytics) - * - Marketplace Administration (review workflow, curation, governance) - * - App Store (customer experience: reviews, recommendations, subscriptions) - * - Multi-Tenancy (tenant registry, provisioning, routing) - * - Future: Composer, Space, Hub Federation - */ -export * from './marketplace.zod'; -export * from './developer-portal.zod'; -export * from './marketplace-admin.zod'; -export * from './app-store.zod'; -export * from './tenant.zod'; -export * from './environment.zod'; -export * from './environment-package.zod'; -export * from './package.zod'; -export * from './package-l10n'; -export * from './package-version.zod'; -export * from './environment-artifact.zod'; -export * from './template-manifest.zod'; diff --git a/packages/spec/src/cloud/marketplace-admin.test.ts b/packages/spec/src/cloud/marketplace-admin.test.ts deleted file mode 100644 index 7510dd7f4e..0000000000 --- a/packages/spec/src/cloud/marketplace-admin.test.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { - ReviewCriterionSchema, - ReviewDecisionSchema, - RejectionReasonSchema, - SubmissionReviewSchema, - FeaturedListingSchema, - CuratedCollectionSchema, - PolicyViolationTypeSchema, - PolicyActionSchema, - MarketplaceHealthMetricsSchema, - TrendingListingSchema, -} from './marketplace-admin.zod'; - -describe('ReviewCriterionSchema', () => { - it('should accept a required criterion', () => { - const criterion = { - id: 'sec-001', - category: 'security' as const, - description: 'No known vulnerabilities in dependencies', - }; - const parsed = ReviewCriterionSchema.parse(criterion); - expect(parsed.required).toBe(true); - }); - - it('should accept a completed criterion', () => { - const criterion = { - id: 'ux-001', - category: 'ux' as const, - description: 'Follows ObjectStack UI guidelines', - required: false, - passed: true, - notes: 'Clean UI, follows design system', - }; - const parsed = ReviewCriterionSchema.parse(criterion); - expect(parsed.passed).toBe(true); - }); - - it('should accept all criterion categories', () => { - const categories = [ - 'security', 'performance', 'quality', 'ux', - 'documentation', 'policy', 'compatibility', - ]; - categories.forEach(category => { - const criterion = { - id: `test-${category}`, - category, - description: `Test ${category}`, - }; - expect(() => ReviewCriterionSchema.parse(criterion)).not.toThrow(); - }); - }); -}); - -describe('ReviewDecisionSchema', () => { - it('should accept all decisions', () => { - const decisions = ['approved', 'rejected', 'changes-requested']; - decisions.forEach(decision => { - expect(() => ReviewDecisionSchema.parse(decision)).not.toThrow(); - }); - }); -}); - -describe('RejectionReasonSchema', () => { - it('should accept all rejection reasons', () => { - const reasons = [ - 'security-vulnerability', 'policy-violation', 'quality-below-standard', - 'misleading-metadata', 'incompatible', 'duplicate', - 'insufficient-documentation', 'other', - ]; - reasons.forEach(reason => { - expect(() => RejectionReasonSchema.parse(reason)).not.toThrow(); - }); - }); -}); - -describe('SubmissionReviewSchema', () => { - it('should accept minimal review (in-progress)', () => { - const review = { - id: 'review-001', - submissionId: 'sub-001', - reviewerId: 'admin-001', - startedAt: '2025-06-01T10:00:00Z', - }; - const parsed = SubmissionReviewSchema.parse(review); - expect(parsed.decision).toBeUndefined(); - }); - - it('should accept approved review with criteria', () => { - const review = { - id: 'review-001', - submissionId: 'sub-001', - reviewerId: 'admin-001', - decision: 'approved' as const, - criteria: [ - { id: 'sec-001', category: 'security' as const, description: 'No vulnerabilities', passed: true }, - { id: 'qual-001', category: 'quality' as const, description: 'Code quality', passed: true }, - ], - feedback: 'Looks great! Approved for publishing.', - startedAt: '2025-06-01T10:00:00Z', - completedAt: '2025-06-01T14:00:00Z', - }; - const parsed = SubmissionReviewSchema.parse(review); - expect(parsed.criteria).toHaveLength(2); - }); - - it('should accept rejected review with reasons', () => { - const review = { - id: 'review-002', - submissionId: 'sub-002', - reviewerId: 'admin-001', - decision: 'rejected' as const, - rejectionReasons: ['security-vulnerability', 'insufficient-documentation'], - feedback: '## Issues Found\n\n1. Critical CVE in lodash dependency\n2. Missing API documentation', - internalNotes: 'Publisher notified via email', - startedAt: '2025-06-01T10:00:00Z', - completedAt: '2025-06-01T11:30:00Z', - }; - const parsed = SubmissionReviewSchema.parse(review); - expect(parsed.rejectionReasons).toHaveLength(2); - expect(parsed.decision).toBe('rejected'); - }); -}); - -describe('FeaturedListingSchema', () => { - it('should accept minimal featured listing', () => { - const featured = { - listingId: 'listing-001', - startDate: '2025-06-01T00:00:00Z', - }; - const parsed = FeaturedListingSchema.parse(featured); - expect(parsed.active).toBe(true); - expect(parsed.priority).toBe(0); - }); - - it('should accept full featured listing', () => { - const featured = { - listingId: 'listing-001', - priority: 1, - bannerUrl: 'https://marketplace.objectstack.io/banners/crm.png', - editorialNote: 'Best CRM of the month', - startDate: '2025-06-01T00:00:00Z', - endDate: '2025-06-30T23:59:59Z', - active: true, - }; - const parsed = FeaturedListingSchema.parse(featured); - expect(parsed.editorialNote).toBe('Best CRM of the month'); - }); -}); - -describe('CuratedCollectionSchema', () => { - it('should accept collection with listings', () => { - const collection = { - id: 'col-001', - name: 'Best for Small Business', - description: 'Curated apps perfect for small businesses', - coverImageUrl: 'https://marketplace.objectstack.io/covers/smb.png', - listingIds: ['listing-001', 'listing-002', 'listing-003'], - published: true, - sortOrder: 1, - createdBy: 'admin-001', - createdAt: '2025-06-01T00:00:00Z', - }; - const parsed = CuratedCollectionSchema.parse(collection); - expect(parsed.listingIds).toHaveLength(3); - expect(parsed.published).toBe(true); - }); - - it('should require at least one listing', () => { - const collection = { - id: 'col-001', - name: 'Empty Collection', - listingIds: [], - }; - expect(() => CuratedCollectionSchema.parse(collection)).toThrow(); - }); -}); - -describe('PolicyViolationTypeSchema', () => { - it('should accept all violation types', () => { - const types = [ - 'malware', 'data-harvesting', 'spam', 'copyright', - 'inappropriate-content', 'terms-of-service', 'security-risk', 'abandoned', - ]; - types.forEach(type => { - expect(() => PolicyViolationTypeSchema.parse(type)).not.toThrow(); - }); - }); -}); - -describe('PolicyActionSchema', () => { - it('should accept a warning action', () => { - const action = { - id: 'action-001', - listingId: 'listing-005', - violationType: 'spam' as const, - action: 'warning' as const, - reason: 'Listing description contains misleading claims about features', - actionBy: 'admin-001', - actionAt: '2025-06-15T10:00:00Z', - }; - const parsed = PolicyActionSchema.parse(action); - expect(parsed.resolved).toBe(false); - }); - - it('should accept a takedown action with resolution', () => { - const action = { - id: 'action-002', - listingId: 'listing-010', - violationType: 'malware' as const, - action: 'takedown' as const, - reason: 'Malicious code detected in v1.2.0', - actionBy: 'admin-002', - actionAt: '2025-06-15T10:00:00Z', - resolution: 'Publisher removed malicious code, re-submitted clean version', - resolved: true, - }; - const parsed = PolicyActionSchema.parse(action); - expect(parsed.resolved).toBe(true); - }); - - it('should accept all enforcement actions', () => { - const actions = ['warning', 'suspend', 'takedown', 'restrict']; - actions.forEach(a => { - const action = { - id: 'action-001', - listingId: 'listing-001', - violationType: 'terms-of-service' as const, - action: a, - reason: 'Test', - actionBy: 'admin-001', - actionAt: '2025-06-15T10:00:00Z', - }; - expect(() => PolicyActionSchema.parse(action)).not.toThrow(); - }); - }); -}); - -describe('MarketplaceHealthMetricsSchema', () => { - it('should accept health metrics', () => { - const metrics = { - totalListings: 250, - totalPublishers: 80, - verifiedPublishers: 45, - totalInstalls: 150000, - averageReviewTime: 48.5, - pendingReviews: 12, - snapshotAt: '2025-06-15T00:00:00Z', - }; - const parsed = MarketplaceHealthMetricsSchema.parse(metrics); - expect(parsed.totalListings).toBe(250); - expect(parsed.pendingReviews).toBe(12); - }); - - it('should accept metrics with breakdowns', () => { - const metrics = { - totalListings: 250, - listingsByStatus: { - published: 200, - draft: 30, - 'in-review': 12, - suspended: 8, - }, - listingsByCategory: { - crm: 40, - erp: 25, - analytics: 35, - }, - totalPublishers: 80, - verifiedPublishers: 45, - totalInstalls: 150000, - pendingReviews: 12, - listingsByPricing: { - free: 120, - freemium: 50, - subscription: 60, - paid: 20, - }, - snapshotAt: '2025-06-15T00:00:00Z', - }; - const parsed = MarketplaceHealthMetricsSchema.parse(metrics); - expect(parsed.listingsByCategory?.crm).toBe(40); - }); -}); - -describe('TrendingListingSchema', () => { - it('should accept trending listing', () => { - const trending = { - listingId: 'listing-001', - rank: 1, - trendScore: 95.5, - installVelocity: 120.3, - period: '7d', - }; - const parsed = TrendingListingSchema.parse(trending); - expect(parsed.rank).toBe(1); - expect(parsed.trendScore).toBe(95.5); - }); -}); diff --git a/packages/spec/src/cloud/marketplace-admin.zod.ts b/packages/spec/src/cloud/marketplace-admin.zod.ts deleted file mode 100644 index b25e810f4c..0000000000 --- a/packages/spec/src/cloud/marketplace-admin.zod.ts +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { z } from 'zod'; - -/** - * # Marketplace Administration Protocol - * - * Defines schemas for the platform (Cloud) side of marketplace operations. - * Covers the administrative workflows for managing and governing the marketplace. - * - * ## Architecture Alignment - * - **Salesforce AppExchange Admin**: Security review, ISV monitoring, partner management - * - **Apple App Store Connect Review**: Human review process, guidelines, rejection reasons - * - **Google Play Console**: Policy enforcement, quality gates, content moderation - * - * ## Key Concepts - * - **Review Process**: Structured workflow for submission review (automated + manual) - * - **Curation**: Featured apps, curated collections, editorial picks - * - **Governance**: Policy enforcement, takedown, compliance - * - **Platform Analytics**: Marketplace health, trending, abuse detection - */ - -// ========================================== -// Review Process -// ========================================== - -/** - * Review Criteria — checklist items for human reviewers - */ -import { lazySchema } from '../shared/lazy-schema'; -export const ReviewCriterionSchema = lazySchema(() => z.object({ - /** Criterion identifier */ - id: z.string().describe('Criterion ID'), - - /** Category of criterion */ - category: z.enum([ - 'security', // Security best practices - 'performance', // Performance / resource usage - 'quality', // Code quality / best practices - 'ux', // User experience standards - 'documentation', // Documentation completeness - 'policy', // Policy compliance (no malware, GDPR, etc.) - 'compatibility', // Platform compatibility - ]), - - /** Description of what to check */ - description: z.string(), - - /** Whether this criterion must pass for approval */ - required: z.boolean().default(true), - - /** Pass/fail result */ - passed: z.boolean().optional(), - - /** Reviewer notes for this criterion */ - notes: z.string().optional(), -})); - -/** - * Review Decision - */ -export const ReviewDecisionSchema = lazySchema(() => z.enum([ - 'approved', // Approved for publishing - 'rejected', // Rejected (with reasons) - 'changes-requested', // Needs changes before re-review -])); - -/** - * Rejection Reason Category - */ -export const RejectionReasonSchema = lazySchema(() => z.enum([ - 'security-vulnerability', // Security issues found - 'policy-violation', // Violates marketplace policy - 'quality-below-standard', // Does not meet quality bar - 'misleading-metadata', // Listing info doesn't match functionality - 'incompatible', // Incompatible with current platform - 'duplicate', // Duplicate of existing listing - 'insufficient-documentation', // Inadequate documentation - 'other', // Other reason (see notes) -])); - -/** - * Submission Review Schema - * - * The review record attached to a package submission. - */ -export const SubmissionReviewSchema = lazySchema(() => z.object({ - /** Review ID */ - id: z.string().describe('Review ID'), - - /** Submission ID being reviewed */ - submissionId: z.string().describe('Submission being reviewed'), - - /** Reviewer user ID */ - reviewerId: z.string().describe('Platform reviewer ID'), - - /** Review decision */ - decision: ReviewDecisionSchema.optional().describe('Final decision'), - - /** Review criteria checklist */ - criteria: z.array(ReviewCriterionSchema).optional() - .describe('Review checklist results'), - - /** Rejection reasons (if rejected) */ - rejectionReasons: z.array(RejectionReasonSchema).optional(), - - /** Detailed feedback for the developer */ - feedback: z.string().optional().describe('Detailed review feedback (Markdown)'), - - /** Internal notes (not visible to developer) */ - internalNotes: z.string().optional().describe('Internal reviewer notes'), - - /** Review started timestamp */ - startedAt: z.string().datetime().optional(), - - /** Review completed timestamp */ - completedAt: z.string().datetime().optional(), -})); - -// ========================================== -// Curation: Featured & Collections -// ========================================== - -/** - * Featured Listing — promoted on marketplace homepage - */ -export const FeaturedListingSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string().describe('Featured listing ID'), - - /** Featured position/priority (lower = higher priority) */ - priority: z.number().int().min(0).default(0), - - /** Featured banner image URL */ - bannerUrl: z.string().url().optional(), - - /** Featured reason / editorial note */ - editorialNote: z.string().optional(), - - /** Start date for featured period */ - startDate: z.string().datetime(), - - /** End date for featured period */ - endDate: z.string().datetime().optional(), - - /** Whether currently active */ - active: z.boolean().default(true), -})); - -/** - * Curated Collection — a themed group of listings - */ -export const CuratedCollectionSchema = lazySchema(() => z.object({ - /** Collection unique identifier */ - id: z.string().describe('Collection ID'), - - /** Collection display name */ - name: z.string().describe('Collection name'), - - /** Collection description */ - description: z.string().optional(), - - /** Cover image URL */ - coverImageUrl: z.string().url().optional(), - - /** Listing IDs in this collection (ordered) */ - listingIds: z.array(z.string()).min(1).describe('Ordered listing IDs'), - - /** Whether publicly visible */ - published: z.boolean().default(false), - - /** Sort order for display among collections */ - sortOrder: z.number().int().min(0).default(0), - - /** Created by (admin user ID) */ - createdBy: z.string().optional(), - - /** Created at */ - createdAt: z.string().datetime().optional(), - - /** Updated at */ - updatedAt: z.string().datetime().optional(), -})); - -// ========================================== -// Governance & Policy -// ========================================== - -/** - * Policy Violation Type - */ -export const PolicyViolationTypeSchema = lazySchema(() => z.enum([ - 'malware', // Malicious software - 'data-harvesting', // Unauthorized data collection - 'spam', // Spammy or misleading content - 'copyright', // Copyright/IP infringement - 'inappropriate-content', // Inappropriate or offensive content - 'terms-of-service', // General ToS violation - 'security-risk', // Unresolved critical security issues - 'abandoned', // Abandoned / no longer maintained -])); - -/** - * Policy Action — enforcement action on a listing - */ -export const PolicyActionSchema = lazySchema(() => z.object({ - /** Action ID */ - id: z.string().describe('Action ID'), - - /** Listing ID */ - listingId: z.string().describe('Target listing ID'), - - /** Violation type */ - violationType: PolicyViolationTypeSchema, - - /** Action taken */ - action: z.enum([ - 'warning', // Warning to publisher - 'suspend', // Temporarily suspend listing - 'takedown', // Permanently remove listing - 'restrict', // Restrict new installs (existing users keep access) - ]), - - /** Detailed reason */ - reason: z.string().describe('Explanation of the violation'), - - /** Admin user who took the action */ - actionBy: z.string().describe('Admin user ID'), - - /** Timestamp */ - actionAt: z.string().datetime(), - - /** Resolution notes (if resolved) */ - resolution: z.string().optional(), - - /** Whether resolved */ - resolved: z.boolean().default(false), -})); - -// ========================================== -// Platform Analytics -// ========================================== - -/** - * Marketplace Health Metrics — overall platform statistics - */ -export const MarketplaceHealthMetricsSchema = lazySchema(() => z.object({ - /** Total number of published listings */ - totalListings: z.number().int().min(0), - - /** Listings by status breakdown (partial — only non-zero statuses) */ - listingsByStatus: z.record(z.string(), z.number().int().min(0)).optional(), - - /** Listings by category breakdown (partial — only non-zero categories) */ - listingsByCategory: z.record(z.string(), z.number().int().min(0)).optional(), - - /** Total registered publishers */ - totalPublishers: z.number().int().min(0), - - /** Verified publishers count */ - verifiedPublishers: z.number().int().min(0), - - /** Total installs across all listings (all time) */ - totalInstalls: z.number().int().min(0), - - /** Average time from submission to review completion (hours) */ - averageReviewTime: z.number().min(0).optional(), - - /** Pending review queue size */ - pendingReviews: z.number().int().min(0), - - /** Listings by pricing model (partial — only non-zero models) */ - listingsByPricing: z.record(z.string(), z.number().int().min(0)).optional(), - - /** Snapshot timestamp */ - snapshotAt: z.string().datetime(), -})); - -/** - * Trending Listing — computed from recent activity - */ -export const TrendingListingSchema = lazySchema(() => z.object({ - /** Listing ID */ - listingId: z.string(), - - /** Trending rank (1 = most trending) */ - rank: z.number().int().min(1), - - /** Trend score (computed from velocity of installs, ratings, page views) */ - trendScore: z.number().min(0), - - /** Install velocity (installs per day over measurement period) */ - installVelocity: z.number().min(0), - - /** Measurement period (e.g., "7d", "30d") */ - period: z.string(), -})); - -// ========================================== -// Export Types -// ========================================== - -export type ReviewCriterion = z.input; -/** Post-parse shape of {@link ReviewCriterion} — defaults applied, transforms run (ADR-0122). */ -export type ReviewCriterionParsed = z.infer; -export type ReviewDecision = z.input; -export type RejectionReason = z.input; -export type SubmissionReview = z.input; -/** Post-parse shape of {@link SubmissionReview} — defaults applied, transforms run (ADR-0122). */ -export type SubmissionReviewParsed = z.infer; -export type FeaturedListing = z.input; -/** Post-parse shape of {@link FeaturedListing} — defaults applied, transforms run (ADR-0122). */ -export type FeaturedListingParsed = z.infer; -export type CuratedCollection = z.input; -/** Post-parse shape of {@link CuratedCollection} — defaults applied, transforms run (ADR-0122). */ -export type CuratedCollectionParsed = z.infer; -export type PolicyViolationType = z.input; -export type PolicyAction = z.input; -/** Post-parse shape of {@link PolicyAction} — defaults applied, transforms run (ADR-0122). */ -export type PolicyActionParsed = z.infer; -export type MarketplaceHealthMetrics = z.input; -export type TrendingListing = z.input; diff --git a/packages/spec/src/cloud/tenant.test.ts b/packages/spec/src/cloud/tenant.test.ts deleted file mode 100644 index 8742134be8..0000000000 --- a/packages/spec/src/cloud/tenant.test.ts +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { describe, it, expect } from 'vitest'; -import { TenantPlanSchema } from './tenant.zod'; - -import { - EXPORT_ENTRY_POINTS, - exportNamesOf, - holdersOf, - maybeOriginOf, - originFileOf, - originOf, - originsOf, -} from '../../scripts/lib/export-origins-testkit'; -// ─── [#4739] `TenantPlan(Schema)` has ONE declaration — ./cloud ────────────── -// -// `./cloud` and `./system` both exported a `TenantPlan` + `TenantPlanSchema`, -// for two different declarations (the #4411 trap — which vocabulary a consumer -// got depended on the import path): -// -// cloud/tenant.zod.ts → 5-value plan tier (free / starter / pro / -// enterprise / custom) — the LIVE declaration: embedded in -// `EnvironmentSchema.plan`, `TenantContextSchema.plan`, -// `ProvisionTenantRequestSchema.plan`, and consumed by the cloud repo's -// service-tenant through those schemas. -// system/provisioning.zod.ts (removed) → 3-value subset (free / pro / -// enterprise) embedded only in `TenantProvisioningRequest/Result` — a -// provisioning protocol with zero implementations and zero importers in -// any repo (objectstack / cloud / objectui), superseded by the cloud -// `Provision*` family. Its companion contracts `IProvisioningService` and -// `ITenantRouter` (./contracts) were equally declared-only and retired in -// the same change. -// -// Maintainer ruling on #4739 (ledger #4535 C16): route B — delete the -// system-side provisioning family, cloud keeps the name. NOT a re-export -// convergence: the ruling is that the name LEAVES ./system entirely, so a -// future `export { TenantPlanSchema } from '../cloud/...'` in ./system is a -// forbidden route even though the dual-source gate (symbol identity) would -// not flag it — the uniqueness pin below catches exactly that (S2 sabotage). -// -// #4642 established that a compile-time conditional-type pin in this package -// was a no-op until #5286 (tsconfig excluded `**/*.test.ts`; vitest never enables -// `typecheck`), so the load-bearing pin is the compiler-API test below, with -// anti-vacuity guards; sabotage-verified in the PR. -describe('[#4739] `TenantPlan(Schema)` resolves to the ./cloud declaration everywhere', () => { - it('resolves the export surface: only ./cloud declares `TenantPlan(Schema)`; the provisioning family is gone', () => { - // Anti-vacuity: the baseline must cover the real surface. (This used to - // enumerate package.json's exports map and build its own `ts.createProgram` - // right here; `export-origins/` IS that resolution, computed once at build - // time and checked in — #4796.) - expect(EXPORT_ENTRY_POINTS).toContain('./cloud'); - expect(EXPORT_ENTRY_POINTS).toContain('./system'); - expect(EXPORT_ENTRY_POINTS).toContain('./contracts'); - expect(EXPORT_ENTRY_POINTS.length).toBeGreaterThan(10); - - // 1. The removed side: `./system` still has a non-trivial surface — so - // the `not.toContain` cannot pass by resolving nothing — and no longer - // names any of the provisioning family, while its surviving - // multi-tenant neighbours stand. - const systemNames = exportNamesOf('./system'); - expect(systemNames.length, './system must export a non-trivial surface').toBeGreaterThan(100); - for (const gone of [ - 'TenantPlan', 'TenantPlanSchema', - 'TenantRegion', 'TenantRegionSchema', - 'TenantProvisioningStatus', 'TenantProvisioningStatusEnum', - 'ProvisioningStep', 'ProvisioningStepSchema', - 'TenantProvisioningRequest', 'TenantProvisioningRequestSchema', - 'TenantProvisioningResult', 'TenantProvisioningResultSchema', - ]) { - expect(systemNames, `./system must not name ${gone}`).not.toContain(gone); - } - expect(systemNames).toContain('TenantSchema'); - expect(systemNames).toContain('TenantIsolationLevel'); - - // 2. The removed contracts: `./contracts` keeps its surface but the - // declared-only provisioning pair is gone. - const contractsNames = exportNamesOf('./contracts'); - expect(contractsNames.length, './contracts must export a non-trivial surface').toBeGreaterThan(50); - for (const gone of ['IProvisioningService', 'ITenantRouter', 'ResolvedTenantContext']) { - expect(contractsNames, `./contracts must not name ${gone}`).not.toContain(gone); - } - expect(contractsNames).toContain('ISchemaDiffService'); - - // 3. The surviving side: `./cloud` exports the const and its inferred - // type, declared in cloud/tenant.zod.ts. - expect(maybeOriginOf('./cloud', 'TenantPlanSchema'), './cloud must export `TenantPlanSchema`').toBeDefined(); - expect(maybeOriginOf('./cloud', 'TenantPlan'), './cloud must export `TenantPlan`').toBeDefined(); - expect(originFileOf('./cloud', 'TenantPlanSchema')).toBe('src/cloud/tenant.zod.ts'); - expect(originFileOf('./cloud', 'TenantPlan')).toBe('src/cloud/tenant.zod.ts'); - - // 4. Uniqueness — the dual-source pin proper: across EVERY public entry, - // an export named `TenantPlan` / `TenantPlanSchema` must resolve to - // that ONE cloud declaration — and `./system` must not be a holder at - // all, so even a same-symbol re-export (invisible to the dual-source - // gate) violates the ruling and turns this red. - for (const name of ['TenantPlan', 'TenantPlanSchema'] as const) { - expect( - originsOf(name), - `every entry must resolve \`${name}\` to the cloud declaration`, - ).toEqual([originOf('./cloud', name)]); - expect(holdersOf(name)).toContain('./cloud'); - expect(holdersOf(name)).not.toContain('./system'); - } - - // 5. The retired contract interfaces exist in NO entry any more. - for (const gone of ['IProvisioningService', 'ITenantRouter', 'ResolvedTenantContext']) { - expect(holdersOf(gone), `no entry may name ${gone}`).toEqual([]); - } - }); - - it('keeps the runtime namespaces consistent with the compiler view', async () => { - const cloud = await import('./index'); - const system = await import('../system/index'); - expect('TenantPlanSchema' in cloud).toBe(true); - expect('TenantPlanSchema' in system).toBe(false); - expect('TenantProvisioningRequestSchema' in system).toBe(false); - expect('TenantProvisioningResultSchema' in system).toBe(false); - expect('TenantRegionSchema' in system).toBe(false); - expect('ProvisioningStepSchema' in system).toBe(false); - }); - - it('what the name now unambiguously means: the cloud declaration, opaque (objectstack#7513)', () => { - // The former 5-value enum is a strict subset of "any string" — still - // accepted, but no longer the boundary of what's valid. - for (const plan of ['free', 'starter', 'pro', 'enterprise', 'custom']) { - expect(() => TenantPlanSchema.parse(plan)).not.toThrow(); - } - // `starter` / `custom` are the values the deleted 3-value system subset - // rejected: their acceptance proves the survivor is the cloud declaration, - // not the provisioning one. - expect(TenantPlanSchema.parse('starter')).toBe('starter'); - }); - - // ─── [objectstack#7513] opaque widening — cloud#1216's measured "no reader - // outside the cloud distribution branches on plan values" ──────────────── - // - // Flips (does not delete) the pre-#7513 pin that asserted the enum's closed - // set. That pin protected the CLOSED-SET boundary; this one protects the - // NEW contract's substance: any string is accepted (the cloud distribution - // owns the vocabulary, not this schema), and the schema's own `.describe()` - // still states that ownership so a reader who only sees the generated - // reference docs (not this source file) gets the same fact. - describe('[objectstack#7513] TenantPlanSchema is an opaque string, not a closed enum', () => { - it('accepts values the retired enum would have rejected — the widening is real', () => { - // `solo` is one of the CLOUD distribution's own vocabulary values - // (`packages/objectos-runtime/src/plan-entitlements.ts` in the cloud - // repo) — exactly the kind of value this widening exists to accept - // without a spec-side edit. - expect(() => TenantPlanSchema.parse('solo')).not.toThrow(); - expect(TenantPlanSchema.parse('solo')).toBe('solo'); - // Arbitrary/unknown strings — the vocabulary is cloud config, not a - // spec-enumerated set, so nothing here is "invalid" on shape grounds. - expect(() => TenantPlanSchema.parse('anything-the-cloud-distribution-declares')).not.toThrow(); - // The empty string is accepted too — free-tier fallback is a cloud-side - // normalization convention, not a spec-level rejection or default. - expect(() => TenantPlanSchema.parse('')).not.toThrow(); - }); - - it('still rejects non-string shapes — opaque means "any string", not "any value"', () => { - expect(() => TenantPlanSchema.parse(42)).toThrow(); - expect(() => TenantPlanSchema.parse(null)).toThrow(); - expect(() => TenantPlanSchema.parse(undefined)).toThrow(); - expect(() => TenantPlanSchema.parse({ plan: 'free' })).toThrow(); - }); - - it('the describe() states the ownership + convention, for readers who only see generated docs', () => { - const description = TenantPlanSchema.description; - expect(description, 'TenantPlanSchema must carry a .describe()').toBeDefined(); - // Ownership statement (ask #1): vocabulary is control-plane config, - // owned by the cloud distribution — not protocol. - expect(description).toMatch(/control-plane config/); - expect(description).toMatch(/cloud distribution/); - expect(description).toMatch(/not protocol/); - // Empty/unknown ⇒ free tier convention (ask #2) — one sentence worth - // keeping, not enforced by this schema. - expect(description).toMatch(/free tier/); - }); - }); -}); diff --git a/packages/spec/src/cloud/tenant.zod.ts b/packages/spec/src/cloud/tenant.zod.ts deleted file mode 100644 index 57153b5cdb..0000000000 --- a/packages/spec/src/cloud/tenant.zod.ts +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. - -import { z } from 'zod'; - -/** - * Multi-Tenant Architecture Schema - * - * Defines the schema for managing multi-tenant architecture with: - * - Global control plane: Single database for auth, org management, tenant registry - * - Tenant data plane: Isolated databases per organization (UUID-based naming) - * - * Design decisions: - * - Database naming: {uuid}.turso.io (not org-slug, since slugs can be modified) - * - Each tenant has its own Turso database for complete data isolation - * - Global database stores user auth, organizations, and tenant metadata - */ - -/** - * Tenant Database Status - */ -import { lazySchema } from '../shared/lazy-schema'; -export const TenantDatabaseStatusSchema = lazySchema(() => z.enum([ - 'provisioning', // Database is being created - 'active', // Database is active and accepting connections - 'suspended', // Database is suspended (read-only or inaccessible) - 'archived', // Database is archived (data preserved but not accessible) - 'failed', // Provisioning or migration failed -])); - -export type TenantDatabaseStatus = z.input; - -/** - * Tenant Plan Identifier - * - * An **opaque** plan/tier identifier (ruling: cloud#1216, executed on the - * spec side by objectstack#7513). The vocabulary — which strings exist, what - * each one unlocks — is control-plane **config owned by the cloud - * distribution**, not protocol: this schema does not enumerate it and never - * has runtime knowledge of it. Widened from a closed 5-value enum - * (`free`/`starter`/`pro`/`enterprise`/`custom`) after measuring that no - * reader outside the cloud distribution branches on the value — framework - * and console treat it as a pass-through string; only the cloud - * distribution's own entitlement modules (e.g. `isFreePlan`, - * `planAllowsAiStudio`) interpret specific values, and they own that - * interpretation independently of this schema. - * - * Convention (not enforced here): as of the cloud#1380 ruling (2026-08-16, - * landed in cloud PR #1417, merged 2026-08-17), an empty or unrecognized - * value folds to the free tier on **both** cloud-side mirrors (the - * control-plane `planKey` reader and the tenant-runtime `isFreePlan` - * reader). The fold happens at the **entitlement layer**, not in - * normalization: `sys_environment.plan` keeps the raw value (case-normalized - * only), so an unrecognized tier stays distinguishable from the free tier to - * any reader, log line, or operator — cloud#1389's red line is normalize the - * spelling, never the vocabulary. Spec accepts any string, including the - * empty one — the free-tier fallback is a cloud-side entitlement decision, - * not a spec-level default. - * - * The two mirrors' vocabularies are **not** merged into one list: cloud#1380 - * lands A over a copy of the vocabulary, pinned to the source by an - * element-for-element equality guard. Unifying them is cloud#1418 (ruled, - * not yet landed) — and even once it lands, a SHA-pinned image can still - * predate a vocabulary entry, so the two lists can disagree either way. - * - * The fold's premise is operational, not structural: new plan tiers are - * minted rarely, and images roll before a new tier goes on sale. If that - * discipline changes, this premise changes with it (see the cloud - * distribution's `isFreePlan` docstring, which carries the same premise). - */ -export const TenantPlanSchema = lazySchema(() => z.string().describe( - 'Opaque plan/tier identifier. The vocabulary is control-plane config owned by the ' - + 'cloud distribution, not protocol — this schema accepts any string and does not ' - + 'enumerate valid values. Convention: an empty or unrecognized value is treated as ' - + 'the free tier by cloud-side readers (not enforced by this schema).', -)); - -export type TenantPlan = z.input; - -/** - * Tenant Database Registry Entry - * - * Tracks each tenant's dedicated database instance. - * Stored in the global control plane database. - * - * @deprecated v4.x shim — superseded by the environment-per-database - * isolation model introduced in v4.1. New code should use - * {@link EnvironmentSchema} + {@link EnvironmentDatabaseSchema} + - * {@link DatabaseCredentialSchema} from `./environment.zod`. This schema - * (and the `sys_tenant_database` table) will be removed in v5.0. - * See `docs/adr/0002-environment-database-isolation.md`. - */ -export const TenantDatabaseSchema = lazySchema(() => z.object({ - /** - * Unique tenant database identifier (UUID) - */ - id: z.string().uuid().describe('Unique tenant database identifier (UUID)'), - - /** - * Organization ID (foreign key to sys_organization) - */ - organizationId: z.string().describe('Organization ID (foreign key to sys_organization)'), - - /** - * Database name (UUID-based for immutability) - * Example: "550e8400-e29b-41d4-a716-446655440000" - */ - databaseName: z.string().describe('Database name (UUID-based)'), - - /** - * Full database URL - * Example: "libsql://550e8400-e29b-41d4-a716-446655440000.turso.io" - */ - databaseUrl: z.string().url().describe('Full database URL'), - - /** - * Encrypted tenant-specific auth token - */ - authToken: z.string().describe('Encrypted tenant-specific auth token'), - - /** - * Database provisioning and runtime status - */ - status: TenantDatabaseStatusSchema.default('provisioning').describe('Database status'), - - /** - * Deployment region - * Example: "us-east-1", "eu-west-1", "ap-southeast-1" - */ - region: z.string().describe('Deployment region'), - - /** - * Tenant plan tier - */ - plan: TenantPlanSchema.default('free').describe('Tenant plan tier'), - - /** - * Storage limit in megabytes - */ - storageLimitMb: z.number().int().positive().describe('Storage limit in megabytes'), - - /** - * Database creation timestamp - */ - createdAt: z.string().datetime().describe('Database creation timestamp'), - - /** - * Last update timestamp - */ - updatedAt: z.string().datetime().describe('Last update timestamp'), - - /** - * Last accessed timestamp (for usage tracking) - */ - lastAccessedAt: z.string().datetime().optional().describe('Last accessed timestamp'), - - /** - * Custom tenant configuration - * Can store additional metadata like feature flags, quotas, etc. - */ - metadata: z.record(z.string(), z.unknown()).optional().describe('Custom tenant configuration'), -})); - -export type TenantDatabase = z.input; -/** Post-parse shape of {@link TenantDatabase} — defaults applied, transforms run (ADR-0122). */ -export type TenantDatabaseParsed = z.infer; - -/** - * Package Installation Status - */ -export const PackageInstallationStatusSchema = lazySchema(() => z.enum([ - 'installing', // Package is being installed - 'active', // Package is active and running - 'disabled', // Package is disabled (soft delete) - 'uninstalling', // Package is being uninstalled - 'failed', // Installation failed -])); - -export type PackageInstallationStatus = z.input; - -/** - * Package Installation Record - * - * Tracks which packages are installed in which tenant. - * Stored in the global control plane database. - */ -export const PackageInstallationSchema = lazySchema(() => z.object({ - /** - * Unique installation identifier - */ - id: z.string().uuid().describe('Unique installation identifier'), - - /** - * Tenant database ID (foreign key to tenant_database) - */ - tenantId: z.string().uuid().describe('Tenant database ID'), - - /** - * Package identifier - * Example: "@objectstack/crm", "@acme/custom-plugin" - */ - packageId: z.string().describe('Package identifier'), - - /** - * Installed package version (semver) - */ - version: z.string().describe('Installed package version'), - - /** - * Installation status - */ - status: PackageInstallationStatusSchema.default('installing').describe('Installation status'), - - /** - * Installation timestamp - */ - installedAt: z.string().datetime().describe('Installation timestamp'), - - /** - * User ID who installed the package - */ - installedBy: z.string().describe('User ID who installed the package'), - - /** - * Package-specific configuration - */ - config: z.record(z.string(), z.unknown()).optional().describe('Package-specific configuration'), - - /** - * Last update timestamp - */ - updatedAt: z.string().datetime().describe('Last update timestamp'), -})); - -export type PackageInstallation = z.input; -/** Post-parse shape of {@link PackageInstallation} — defaults applied, transforms run (ADR-0122). */ -export type PackageInstallationParsed = z.infer; - -/** - * Tenant Context - * - * Runtime context containing current tenant information. - * Extracted from request (subdomain, header, JWT claim, etc.) - */ -export const TenantContextSchema = lazySchema(() => z.object({ - /** - * Current tenant database ID - */ - tenantId: z.string().uuid().describe('Current tenant database ID'), - - /** - * Current organization ID - */ - organizationId: z.string().describe('Current organization ID'), - - /** - * Organization slug (for display purposes) - */ - organizationSlug: z.string().optional().describe('Organization slug'), - - /** - * Tenant database URL - */ - databaseUrl: z.string().url().describe('Tenant database URL'), - - /** - * Tenant plan tier - */ - plan: TenantPlanSchema.describe('Tenant plan tier'), - - /** - * Custom tenant metadata - */ - metadata: z.record(z.string(), z.unknown()).optional().describe('Custom tenant metadata'), -})); - -export type TenantContext = z.input; - -/** - * Tenant Identification Source - * - * How the tenant was identified from the request - */ -export const TenantIdentificationSourceSchema = lazySchema(() => z.enum([ - 'subdomain', // Extracted from subdomain (e.g., acme.objectstack.app) - 'custom_domain', // Extracted from custom domain (e.g., app.acme.com) - 'header', // Extracted from X-Tenant-ID header - 'jwt_claim', // Extracted from JWT organizationId claim - 'session', // Extracted from session data - 'default', // Default/fallback tenant -])); - -export type TenantIdentificationSource = z.input; - -/** - * Tenant Routing Configuration - * - * Configuration for tenant identification and routing - */ -export const TenantRoutingConfigSchema = lazySchema(() => z.object({ - /** - * Enable multi-tenant mode - */ - enabled: z.boolean().default(false).describe('Enable multi-tenant mode'), - - /** - * Tenant identification strategy (in order of precedence) - */ - identificationSources: z.array(TenantIdentificationSourceSchema) - .default(['subdomain', 'header', 'jwt_claim']) - .describe('Tenant identification strategy (in order of precedence)'), - - /** - * Default tenant ID (for single-tenant deployments or fallback) - */ - defaultTenantId: z.string().uuid().optional().describe('Default tenant ID'), - - /** - * Subdomain pattern for tenant extraction - * Example: "{tenant}.objectstack.app" - */ - subdomainPattern: z.string().optional().describe('Subdomain pattern for tenant extraction'), - - /** - * Custom domain mapping - * Maps custom domains to tenant IDs - * Example: { "app.acme.com": "550e8400-e29b-41d4-a716-446655440000" } - */ - customDomainMapping: z.record(z.string(), z.string().uuid()).optional() - .describe('Custom domain to tenant ID mapping'), - - /** - * Header name for tenant ID - */ - tenantHeaderName: z.string().default('X-Tenant-ID').describe('Header name for tenant ID'), - - /** - * JWT claim name for organization ID - */ - jwtOrganizationClaim: z.string().default('organizationId') - .describe('JWT claim name for organization ID'), -})); - -export type TenantRoutingConfig = z.input; -/** Post-parse shape of {@link TenantRoutingConfig} — defaults applied, transforms run (ADR-0122). */ -export type TenantRoutingConfigParsed = z.infer; - -/** - * Tenant Provisioning Request - * - * Request to provision a new tenant database - */ -export const ProvisionTenantRequestSchema = lazySchema(() => z.object({ - /** - * Organization ID to provision database for - */ - organizationId: z.string().describe('Organization ID'), - - /** - * Deployment region preference - */ - region: z.string().optional().describe('Deployment region preference'), - - /** - * Tenant plan tier - */ - plan: TenantPlanSchema.default('free').describe('Tenant plan tier'), - - /** - * Storage limit in megabytes - */ - storageLimitMb: z.number().int().positive().optional().describe('Storage limit in megabytes'), - - /** - * Custom tenant metadata - */ - metadata: z.record(z.string(), z.unknown()).optional().describe('Custom tenant metadata'), -})); - -export type ProvisionTenantRequest = z.input; -/** Post-parse shape of {@link ProvisionTenantRequest} — defaults applied, transforms run (ADR-0122). */ -export type ProvisionTenantRequestParsed = z.infer; - -/** - * Tenant Provisioning Response - * - * Result of tenant provisioning operation - */ -export const ProvisionTenantResponseSchema = lazySchema(() => z.object({ - /** - * Provisioned tenant database - */ - tenant: TenantDatabaseSchema.describe('Provisioned tenant database'), - - /** - * Provisioning duration in milliseconds - */ - durationMs: z.number().describe('Provisioning duration in milliseconds'), - - /** - * Any warnings or notes from provisioning - */ - warnings: z.array(z.string()).optional().describe('Provisioning warnings'), -})); - -export type ProvisionTenantResponse = z.input; -/** Post-parse shape of {@link ProvisionTenantResponse} — defaults applied, transforms run (ADR-0122). */ -export type ProvisionTenantResponseParsed = z.infer; diff --git a/packages/spec/src/contracts/index.ts b/packages/spec/src/contracts/index.ts index cfcde455e8..a67dc8167a 100644 --- a/packages/spec/src/contracts/index.ts +++ b/packages/spec/src/contracts/index.ts @@ -65,8 +65,9 @@ export * from './embedder.js'; // contracts had zero implementations and zero call sites in any repo // (objectstack / cloud / objectui) — declared-only fiction over the // system-side provisioning family retired in the same change (#4535 C16). -// The living provisioning contract is the `Provision*` family in -// `@objectstack/spec/cloud`, consumed by the cloud services (service-tenant). +// The living provisioning contract is the `Provision*` family — declared in +// `@objectstack/spec/cloud` until #16325, and since then in the cloud repo +// itself, beside the services that consume it (service-tenant). export * from './schema-diff-service.js'; export * from './external-datasource-service.js'; export * from './deploy-pipeline-service.js'; diff --git a/packages/spec/src/kernel/package-dependency-dual-source.test.ts b/packages/spec/src/kernel/package-dependency-dual-source.test.ts index 271329249f..4825e2a43f 100644 --- a/packages/spec/src/kernel/package-dependency-dual-source.test.ts +++ b/packages/spec/src/kernel/package-dependency-dual-source.test.ts @@ -14,7 +14,8 @@ import { // Before this change `PackageDependency` / `PackageDependencySchema` were each // exported by TWO entry points for TWO different declarations: // -// ./cloud — the DECLARATION form an author writes into a package manifest: +// ./cloud — since #16325 ./marketplace — the DECLARATION form an author +// writes into a package manifest: // `{ packageId, versionRange, optional }`, embedded in // `PackageManifestSchema.dependencies[]` → `sys_package_version.manifest_json`; // ./kernel — the RESOLVER form the dependency resolver walks: @@ -28,7 +29,10 @@ import { // key defaulted or missing: the #4411 trap in its most dangerous form (ADR-0104 // silent-strip class). Two concepts, not two spellings ⇒ ADR-0112 D9(a), route // ruled by the maintainer on #4741: the KERNEL side is renamed -// `ResolvedPackageDependency(Schema)`, the cloud side keeps the bare name. +// `ResolvedPackageDependency(Schema)`, the cloud side keeps the bare name +// (the package-format half of `./cloud` moved to `./marketplace` at #16325; +// the owner below is that entry, same declaration, same file under its new +// directory). // `RENAMED_DEFS` carries `kernel/PackageDependency` → // `kernel/ResolvedPackageDependency` (4 authorable keys, all four still // present under the new def ⇒ zero tombstone, zero ADR-0087 conversion). @@ -37,7 +41,7 @@ import { // a no-op until #5286 (tsconfig excluded `**/*.test.ts`; vitest never enables `typecheck`), // so the load-bearing pin is the compiler-API test below, with anti-vacuity // guards. Sabotage-verified in the PR: S1 resurrecting the old kernel const, -// and S2 re-exporting the cloud declaration from ./kernel under the bare name +// and S2 re-exporting the marketplace declaration from ./kernel under the bare name // (green to the dual-source gate — one declaration, many entries — but a lie // to anyone reading `./kernel`, and independently rejected at BUILD time by // RENAMED_DEFS invariant 3, "the source def is still emitted"). @@ -47,7 +51,7 @@ describe('[#4741] PackageDependency dual-source retirement (C7)', () => { // enumerate package.json's exports map and build its own `ts.createProgram` // right here; `export-origins/` IS that resolution, computed once at build // time and checked in — #4796.) - for (const needed of ['./cloud', './kernel']) { + for (const needed of ['./marketplace', './kernel']) { expect(EXPORT_ENTRY_POINTS, `exports map must include ${needed}`).toContain(needed); } expect(EXPORT_ENTRY_POINTS.length).toBeGreaterThan(10); @@ -87,7 +91,7 @@ describe('[#4741] PackageDependency dual-source retirement (C7)', () => { } // 3. The bare `PackageDependency(Schema)` now has exactly ONE owner: - // ./cloud, declared in cloud/package-version.zod.ts. Not merely "the + // ./marketplace, declared in marketplace/package-version.zod.ts. Not merely "the // same declaration everywhere" — NO other entry may export the bare name // at all. A re-export from ./kernel would share the declaration (green // to the dual-source gate, which judges by symbol identity) while @@ -97,14 +101,14 @@ describe('[#4741] PackageDependency dual-source retirement (C7)', () => { // the symbol itself is honest. Exact equality, not a subset check. for (const name of ['PackageDependencySchema', 'PackageDependency']) { const holders = holderOriginsOf(name); - expect(holders.map((h) => h.sub), `${name} must be owned by ./cloud alone`).toEqual(['./cloud']); - expect(originFile(holders[0].origin)).toBe('src/cloud/package-version.zod.ts'); + expect(holders.map((h) => h.sub), `${name} must be owned by ./marketplace alone`).toEqual(['./marketplace']); + expect(originFile(holders[0].origin)).toBe('src/marketplace/package-version.zod.ts'); } }); it('keeps the runtime namespaces consistent with the compiler view', async () => { const kernel = await import('./index'); - const cloud = await import('../cloud/index'); + const marketplace = await import('../marketplace/index'); // Renamed-away side — the old const is gone from ./kernel at runtime too. expect('PackageDependencySchema' in kernel, 'kernel must not export PackageDependencySchema').toBe(false); @@ -128,15 +132,15 @@ describe('[#4741] PackageDependency dual-source retirement (C7)', () => { // The namespace object published for SBOM / conflict reporting follows the // rename — it must not keep handing out the resolver schema under the name - // this change gave back to ./cloud. + // this change gave back to ./cloud (./marketplace since #16325). expect('PackageDependency' in kernel.PluginSecurityProtocol).toBe(false); expect(kernel.PluginSecurityProtocol.ResolvedPackageDependency).toBe( kernel.ResolvedPackageDependencySchema, ); - // cloud side — untouched shape, and still the manifest declaration form. - expect('PackageDependencySchema' in cloud).toBe(true); - const declared = cloud.PackageDependencySchema.parse({ + // marketplace side — untouched shape, and still the manifest declaration form. + expect('PackageDependencySchema' in marketplace).toBe(true); + const declared = marketplace.PackageDependencySchema.parse({ packageId: 'com.objectstack.core', versionRange: '^1.0.0', }); @@ -149,7 +153,7 @@ describe('[#4741] PackageDependency dual-source retirement (C7)', () => { it('proves the two shapes were never interchangeable — the silent-strip trap', async () => { const { ResolvedPackageDependencySchema } = await import('./plugin-security.zod'); - const { PackageDependencySchema } = await import('../cloud/package-version.zod'); + const { PackageDependencySchema } = await import('../marketplace/package-version.zod'); // Zero shared keys: this is WHY the name had to move rather than converge. // If a future edit ever makes the key sets overlap, this assertion fails diff --git a/packages/spec/src/kernel/plugin-security.zod.ts b/packages/spec/src/kernel/plugin-security.zod.ts index d4812c01b5..8d38e0df53 100644 --- a/packages/spec/src/kernel/plugin-security.zod.ts +++ b/packages/spec/src/kernel/plugin-security.zod.ts @@ -319,8 +319,9 @@ export type SecurityPolicyParsed = z.infer; * `PluginSecurityProtocol` publishes for SBOM/conflict reporting. It carries * the resolution outcome (`resolvedVersion`) alongside the constraint. * - * Do NOT confuse it with `PackageDependency` from `@objectstack/spec/cloud` - * (`cloud/package-version.zod.ts`), which is the DECLARATION-side shape an + * Do NOT confuse it with `PackageDependency` from `@objectstack/spec/marketplace` + * (`marketplace/package-version.zod.ts`; `@objectstack/spec/cloud` until + * #16325), which is the DECLARATION-side shape an * author writes into a package manifest (`packageId` / `versionRange` / * `optional`). Until #4741 both were named `PackageDependency` and the two * key sets are entirely disjoint, so which type a consumer got depended on diff --git a/packages/spec/src/marketplace/index.ts b/packages/spec/src/marketplace/index.ts new file mode 100644 index 0000000000..5fbfb0f389 --- /dev/null +++ b/packages/spec/src/marketplace/index.ts @@ -0,0 +1,28 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Marketplace Protocol — the package & marketplace FORMAT. + * + * What a package author needs to describe, version, localise and publish a + * package, and what the marketplace answers with: + * - Package identity and translations (`package.zod`) + * - Immutable package versions and their manifest declarations (`package-version.zod`) + * - Listing, submission, review, search and install request/response shapes (`marketplace.zod`) + * - The listing-localisation resolver shared by every surface (`package-l10n`) + * - The on-disk `objectstack.manifest.json` template descriptor (`template-manifest.zod`) + * + * Until #16325 these five modules lived under `./cloud` beside the cloud + * control plane's own row contracts (environments, tenants, the developer + * portal, marketplace administration, the app store). Those contracts are not + * an open-source protocol — their producer and their consumers both live in + * the closed cloud repo — so they left `@objectstack/spec` with the `./cloud` + * subpath (maintainer direction, verbatim: 「我一直觉得 cloud 的协议应该放在云端, + * 没必要开源」). This half stays, because a package author needs it: the + * open-source CLI's `os package publish` path speaks `CreatePackageRequestSchema`, + * and `api/package-api.zod.ts` builds on `ArtifactReferenceSchema`. + */ +export * from './marketplace.zod'; +export * from './package.zod'; +export * from './package-l10n'; +export * from './package-version.zod'; +export * from './template-manifest.zod'; diff --git a/packages/spec/src/cloud/marketplace.test.ts b/packages/spec/src/marketplace/marketplace.test.ts similarity index 100% rename from packages/spec/src/cloud/marketplace.test.ts rename to packages/spec/src/marketplace/marketplace.test.ts diff --git a/packages/spec/src/cloud/marketplace.zod.ts b/packages/spec/src/marketplace/marketplace.zod.ts similarity index 100% rename from packages/spec/src/cloud/marketplace.zod.ts rename to packages/spec/src/marketplace/marketplace.zod.ts diff --git a/packages/spec/src/cloud/package-l10n.test.ts b/packages/spec/src/marketplace/package-l10n.test.ts similarity index 100% rename from packages/spec/src/cloud/package-l10n.test.ts rename to packages/spec/src/marketplace/package-l10n.test.ts diff --git a/packages/spec/src/cloud/package-l10n.ts b/packages/spec/src/marketplace/package-l10n.ts similarity index 100% rename from packages/spec/src/cloud/package-l10n.ts rename to packages/spec/src/marketplace/package-l10n.ts diff --git a/packages/spec/src/cloud/package-namespace.test.ts b/packages/spec/src/marketplace/package-namespace.test.ts similarity index 100% rename from packages/spec/src/cloud/package-namespace.test.ts rename to packages/spec/src/marketplace/package-namespace.test.ts diff --git a/packages/spec/src/cloud/package-version.zod.ts b/packages/spec/src/marketplace/package-version.zod.ts similarity index 100% rename from packages/spec/src/cloud/package-version.zod.ts rename to packages/spec/src/marketplace/package-version.zod.ts diff --git a/packages/spec/src/cloud/package.zod.ts b/packages/spec/src/marketplace/package.zod.ts similarity index 98% rename from packages/spec/src/cloud/package.zod.ts rename to packages/spec/src/marketplace/package.zod.ts index b5679e5458..da445ccd42 100644 --- a/packages/spec/src/cloud/package.zod.ts +++ b/packages/spec/src/marketplace/package.zod.ts @@ -13,7 +13,9 @@ import { z } from 'zod'; * Architecture: * - `sys_package` — identity (one row per logical package) * - `sys_package_version` — immutable release snapshots (see package-version.zod.ts) - * - `sys_package_installation` — env ↔ version pairing (see environment-package.zod.ts) + * - `sys_package_installation` — env ↔ version pairing; a cloud control-plane row, + * declared in the cloud repo since #16325 (it left `@objectstack/spec` with the + * `./cloud` subpath) * * See `docs/adr/0003-package-as-first-class-citizen.md` for the full rationale. */ diff --git a/packages/spec/src/cloud/template-manifest-id.test.ts b/packages/spec/src/marketplace/template-manifest-id.test.ts similarity index 100% rename from packages/spec/src/cloud/template-manifest-id.test.ts rename to packages/spec/src/marketplace/template-manifest-id.test.ts diff --git a/packages/spec/src/cloud/template-manifest.zod.ts b/packages/spec/src/marketplace/template-manifest.zod.ts similarity index 100% rename from packages/spec/src/cloud/template-manifest.zod.ts rename to packages/spec/src/marketplace/template-manifest.zod.ts diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__AnalyticsTimeRange.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AnalyticsTimeRange.ts new file mode 100644 index 0000000000..c5dd13369e --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AnalyticsTimeRange.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/AnalyticsTimeRange'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppDiscoveryRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppDiscoveryRequest.ts new file mode 100644 index 0000000000..f64ba6e9ac --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppDiscoveryRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/AppDiscoveryRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppDiscoveryResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppDiscoveryResponse.ts new file mode 100644 index 0000000000..9f12c706a8 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppDiscoveryResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/AppDiscoveryResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppSubscription.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppSubscription.ts new file mode 100644 index 0000000000..926a76801c --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__AppSubscription.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/AppSubscription'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__CreateListingRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__CreateListingRequest.ts new file mode 100644 index 0000000000..05de7e2842 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__CreateListingRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/CreateListingRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__CuratedCollection.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__CuratedCollection.ts new file mode 100644 index 0000000000..1a612807fd --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__CuratedCollection.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/CuratedCollection'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__Environment.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__Environment.ts new file mode 100644 index 0000000000..f1c449f85e --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__Environment.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/Environment'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentCredential.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentCredential.ts new file mode 100644 index 0000000000..3e1ab08e89 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentCredential.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentCredential'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentCredentialStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentCredentialStatus.ts new file mode 100644 index 0000000000..24de2bfb8f --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentCredentialStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentCredentialStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentDriver.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentDriver.ts new file mode 100644 index 0000000000..730472d764 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentDriver.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentDriver'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentMember.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentMember.ts new file mode 100644 index 0000000000..dab83bc084 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentMember.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentMember'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentPackageInstallation.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentPackageInstallation.ts new file mode 100644 index 0000000000..f53626a5bc --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentPackageInstallation.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentPackageInstallation'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentPackageStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentPackageStatus.ts new file mode 100644 index 0000000000..2fbd3390bf --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentPackageStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentPackageStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentRole.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentRole.ts new file mode 100644 index 0000000000..958c10a4d6 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentRole.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentRole'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentStatus.ts new file mode 100644 index 0000000000..f8bbefb907 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentVisibility.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentVisibility.ts new file mode 100644 index 0000000000..1a933ccbf5 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__EnvironmentVisibility.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/EnvironmentVisibility'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__FeaturedListing.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__FeaturedListing.ts new file mode 100644 index 0000000000..4df1225ef8 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__FeaturedListing.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/FeaturedListing'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__InstallPackageToEnvironmentRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__InstallPackageToEnvironmentRequest.ts new file mode 100644 index 0000000000..8118d330af --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__InstallPackageToEnvironmentRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/InstallPackageToEnvironmentRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__InstalledAppSummary.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__InstalledAppSummary.ts new file mode 100644 index 0000000000..d584fe0ecf --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__InstalledAppSummary.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/InstalledAppSummary'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListEnvironmentPackagesResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListEnvironmentPackagesResponse.ts new file mode 100644 index 0000000000..e1a1934fb7 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListEnvironmentPackagesResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ListEnvironmentPackagesResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListInstalledAppsRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListInstalledAppsRequest.ts new file mode 100644 index 0000000000..568afc768a --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListInstalledAppsRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ListInstalledAppsRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListInstalledAppsResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListInstalledAppsResponse.ts new file mode 100644 index 0000000000..932e24950c --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListInstalledAppsResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ListInstalledAppsResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListReviewsRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListReviewsRequest.ts new file mode 100644 index 0000000000..c122500ec6 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListReviewsRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ListReviewsRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListReviewsResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListReviewsResponse.ts new file mode 100644 index 0000000000..17fd3cde15 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListReviewsResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ListReviewsResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListingActionRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListingActionRequest.ts new file mode 100644 index 0000000000..1e5950d1c0 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ListingActionRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ListingActionRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__MarketplaceHealthMetrics.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__MarketplaceHealthMetrics.ts new file mode 100644 index 0000000000..d28551e6b1 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__MarketplaceHealthMetrics.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/MarketplaceHealthMetrics'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PackageInstallation.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PackageInstallation.ts new file mode 100644 index 0000000000..b37df96f5d --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PackageInstallation.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PackageInstallation'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PackageInstallationStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PackageInstallationStatus.ts new file mode 100644 index 0000000000..f8fceb4cc1 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PackageInstallationStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PackageInstallationStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PolicyAction.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PolicyAction.ts new file mode 100644 index 0000000000..9d012df034 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PolicyAction.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PolicyAction'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PolicyViolationType.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PolicyViolationType.ts new file mode 100644 index 0000000000..d02bf37b03 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PolicyViolationType.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PolicyViolationType'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionEnvironmentRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionEnvironmentRequest.ts new file mode 100644 index 0000000000..3cff196ac2 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionEnvironmentRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ProvisionEnvironmentRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionEnvironmentResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionEnvironmentResponse.ts new file mode 100644 index 0000000000..60a863e77d --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionEnvironmentResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ProvisionEnvironmentResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionOrganizationRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionOrganizationRequest.ts new file mode 100644 index 0000000000..30780ea47b --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionOrganizationRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ProvisionOrganizationRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionOrganizationResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionOrganizationResponse.ts new file mode 100644 index 0000000000..eab7a11bf7 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionOrganizationResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ProvisionOrganizationResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionTenantRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionTenantRequest.ts new file mode 100644 index 0000000000..aca2302135 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionTenantRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ProvisionTenantRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionTenantResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionTenantResponse.ts new file mode 100644 index 0000000000..58294876a7 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ProvisionTenantResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ProvisionTenantResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublisherProfile.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublisherProfile.ts new file mode 100644 index 0000000000..17b1084dee --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublisherProfile.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PublisherProfile'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublishingAnalyticsRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublishingAnalyticsRequest.ts new file mode 100644 index 0000000000..9355c9d405 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublishingAnalyticsRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PublishingAnalyticsRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublishingAnalyticsResponse.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublishingAnalyticsResponse.ts new file mode 100644 index 0000000000..f2712a1db9 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__PublishingAnalyticsResponse.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/PublishingAnalyticsResponse'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__RecommendationReason.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RecommendationReason.ts new file mode 100644 index 0000000000..ce29a9776c --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RecommendationReason.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/RecommendationReason'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__RecommendedApp.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RecommendedApp.ts new file mode 100644 index 0000000000..638f0265b1 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RecommendedApp.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/RecommendedApp'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__RejectionReason.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RejectionReason.ts new file mode 100644 index 0000000000..7d75335993 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RejectionReason.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/RejectionReason'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReleaseChannel.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReleaseChannel.ts new file mode 100644 index 0000000000..30b16719e0 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReleaseChannel.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ReleaseChannel'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewCriterion.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewCriterion.ts new file mode 100644 index 0000000000..a55cb1e87c --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewCriterion.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ReviewCriterion'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewDecision.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewDecision.ts new file mode 100644 index 0000000000..a0ff85de74 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewDecision.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ReviewDecision'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewModerationStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewModerationStatus.ts new file mode 100644 index 0000000000..68f77c410a --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__ReviewModerationStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/ReviewModerationStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__RollbackEnvironmentPackageRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RollbackEnvironmentPackageRequest.ts new file mode 100644 index 0000000000..ab9a841d58 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__RollbackEnvironmentPackageRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/RollbackEnvironmentPackageRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubmissionReview.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubmissionReview.ts new file mode 100644 index 0000000000..06909bc9e3 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubmissionReview.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/SubmissionReview'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubmitReviewRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubmitReviewRequest.ts new file mode 100644 index 0000000000..8dc192e849 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubmitReviewRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/SubmitReviewRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubscriptionStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubscriptionStatus.ts new file mode 100644 index 0000000000..7259919852 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__SubscriptionStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/SubscriptionStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantContext.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantContext.ts new file mode 100644 index 0000000000..548d8b7926 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantContext.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TenantContext'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantDatabase.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantDatabase.ts new file mode 100644 index 0000000000..3ad1801cf8 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantDatabase.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TenantDatabase'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantDatabaseStatus.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantDatabaseStatus.ts new file mode 100644 index 0000000000..5a689e85cd --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantDatabaseStatus.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TenantDatabaseStatus'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantIdentificationSource.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantIdentificationSource.ts new file mode 100644 index 0000000000..1fbd710b33 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantIdentificationSource.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TenantIdentificationSource'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantPlan.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantPlan.ts new file mode 100644 index 0000000000..6b277efc5c --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantPlan.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TenantPlan'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantRoutingConfig.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantRoutingConfig.ts new file mode 100644 index 0000000000..ed1c2777a7 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TenantRoutingConfig.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TenantRoutingConfig'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TimeSeriesPoint.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TimeSeriesPoint.ts new file mode 100644 index 0000000000..571f83e0a8 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TimeSeriesPoint.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TimeSeriesPoint'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__TrendingListing.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TrendingListing.ts new file mode 100644 index 0000000000..4890b278e8 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__TrendingListing.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/TrendingListing'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__UpdateListingRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__UpdateListingRequest.ts new file mode 100644 index 0000000000..e6c6867693 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__UpdateListingRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/UpdateListingRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__UpgradeEnvironmentPackageRequest.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__UpgradeEnvironmentPackageRequest.ts new file mode 100644 index 0000000000..9955632816 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__UpgradeEnvironmentPackageRequest.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/UpgradeEnvironmentPackageRequest'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__UserReview.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__UserReview.ts new file mode 100644 index 0000000000..b3c7087808 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__UserReview.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/UserReview'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.cloud__VersionRelease.ts b/packages/spec/src/migrations/entries/retired-defs/18.cloud__VersionRelease.ts new file mode 100644 index 0000000000..dd4644d0b9 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.cloud__VersionRelease.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath +// (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are +// the cloud repo's own declarations, not an open-source protocol). Prescription: the +// `cloud-subpath-retired` semantic entry of this major. +export const entry = 'cloud/VersionRelease'; diff --git a/packages/spec/src/migrations/entries/semantic/18.cloud-subpath-retired.ts b/packages/spec/src/migrations/entries/semantic/18.cloud-subpath-retired.ts new file mode 100644 index 0000000000..a4cae6ccd0 --- /dev/null +++ b/packages/spec/src/migrations/entries/semantic/18.cloud-subpath-retired.ts @@ -0,0 +1,54 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import type { SemanticMigration } from '../../types.js'; + +export const entry: SemanticMigration = { + id: 'cloud-subpath-retired', + surface: + '`@objectstack/spec/cloud` — the whole published subpath (`packages/spec/src/cloud/`, ' + + '11 modules, 94 JSON-Schema defs): the cloud control plane\'s own contracts ' + + '(`environment.zod`, `environment-package.zod`, `tenant.zod`, `developer-portal.zod`, ' + + '`marketplace-admin.zod`, `app-store.zod` — 62 defs) and the package & marketplace ' + + 'format (`package.zod`, `package-version.zod`, `marketplace.zod`, `package-l10n`, ' + + '`template-manifest.zod` — 30 defs)', + replacement: + 'Two answers, by owner. (1) The package & marketplace FORMAT moved unchanged to ' + + '`@objectstack/spec/marketplace` (`packages/spec/src/marketplace/`): rewrite the import ' + + 'path — `import { PackageSchema } from \'@objectstack/spec/cloud\'` becomes ' + + '`from \'@objectstack/spec/marketplace\'` — and nothing else; every def, key and JSON ' + + 'Schema is byte-identical under its new `$id` category (`RENAMED_DEFS`, 32 entries). ' + + '`EnvironmentType(Schema)` — the 7-member taxonomy the discovery fold table is total ' + + 'over — is re-declared in `@objectstack/spec/api` (`api/discovery.zod.ts`); the ' + + 'environment-artifact envelope was only ever a re-export and is imported from ' + + '`@objectstack/spec/system`. (2) The cloud control plane\'s contracts have NO ' + + 'open-source replacement: `environment.zod` and `tenant.zod` are re-declared in the ' + + 'cloud repo beside their producer (objectstack-ai/cloud#2037), and `developer-portal.zod`, ' + + '`marketplace-admin.zod`, `app-store.zod`, `environment-package.zod` are deleted outright — ' + + 'zero consumers in any repo (maintainer ruling on #16526, option A). Recoverable from git ' + + 'history at `d5d8d50db` if a declaration is ever wanted again; that is a new card in the ' + + 'cloud repo, not a re-import.', + reason: + 'Maintainer direction (2026-09-06, verbatim, untranslated): 「我一直觉得 cloud 的协议应该放在云端,' + + '没必要开源」; ruled option B "cut by owner" on #16325 (director batch #62, 2026-09-07, 「同意」). ' + + 'The control-plane schemas\' producer and every consumer live in the closed cloud repo — the ' + + 'open-source tree read exactly one type from them (`EnvironmentType`, for the discovery fold ' + + 'table). Leaving them published made the obvious-looking binding of `client.environments.*` ' + + 'to a camelCase `Environment` row compile and read `undefined` at runtime against a ' + + 'snake_case wire (#11925 / #12036); with the declarations gone the mis-binding is ' + + 'structurally impossible rather than warned about in a docblock. No alias and no ' + + 'deprecation window, per the standing 2026-08-27 ruling 「项目在创业阶段,用户也很少,短期不考虑渐进。」. ' + + 'Not losslessly convertible: an import path is TypeScript source, not a metadata document ' + + '`objectstack migrate meta` can rewrite.', + acceptanceCriteria: + 'No code imports anything from `@objectstack/spec/cloud` — the specifier is not an `exports` ' + + 'key and every such import fails to resolve (TS2307) after upgrade. Package-format consumers ' + + 'resolve the same symbols from `@objectstack/spec/marketplace` (pinned by resolved symbol ' + + 'identity in `kernel/package-dependency-dual-source.test.ts` and ' + + '`system/environment-artifact.test.ts`). `api/discovery-environment-subset.pin.test.ts` ' + + 'still proves DiscoveryEnvironment ⊂ EnvironmentType against the re-declared enum. No ' + + 'metadata document needs editing: the 509 `cloud/*` authorable-surface baseline keys are ' + + 'discharged by the deletion gate\'s own proofs — 30 defs carried by declared rename, 62 by ' + + 'whole-def retirement (`RETIRED_DEFS_BY_MAJOR[18]`) — not by a tombstone an author could hit. ' + + '⚠️ Runtime behaviour is deliberately UNCHANGED: `os package publish`, the marketplace routes ' + + 'and the metadata plugin\'s artifact ingest parse byte-identically before and after.', +}; diff --git a/packages/spec/src/migrations/registry.ts b/packages/spec/src/migrations/registry.ts index 635b99bf4f..bdea38356a 100644 --- a/packages/spec/src/migrations/registry.ts +++ b/packages/spec/src/migrations/registry.ts @@ -6321,6 +6321,56 @@ const step18: MigrationStep = { + 'MEASURED, and a `catch` there that swallowed this method\'s rejection is now dead ' + 'code that this entry is the only notice of.', }, + { + id: 'cloud-subpath-retired', + surface: + '`@objectstack/spec/cloud` — the whole published subpath (`packages/spec/src/cloud/`, ' + + '11 modules, 94 JSON-Schema defs): the cloud control plane\'s own contracts ' + + '(`environment.zod`, `environment-package.zod`, `tenant.zod`, `developer-portal.zod`, ' + + '`marketplace-admin.zod`, `app-store.zod` — 62 defs) and the package & marketplace ' + + 'format (`package.zod`, `package-version.zod`, `marketplace.zod`, `package-l10n`, ' + + '`template-manifest.zod` — 30 defs)', + replacement: + 'Two answers, by owner. (1) The package & marketplace FORMAT moved unchanged to ' + + '`@objectstack/spec/marketplace` (`packages/spec/src/marketplace/`): rewrite the import ' + + 'path — `import { PackageSchema } from \'@objectstack/spec/cloud\'` becomes ' + + '`from \'@objectstack/spec/marketplace\'` — and nothing else; every def, key and JSON ' + + 'Schema is byte-identical under its new `$id` category (`RENAMED_DEFS`, 32 entries). ' + + '`EnvironmentType(Schema)` — the 7-member taxonomy the discovery fold table is total ' + + 'over — is re-declared in `@objectstack/spec/api` (`api/discovery.zod.ts`); the ' + + 'environment-artifact envelope was only ever a re-export and is imported from ' + + '`@objectstack/spec/system`. (2) The cloud control plane\'s contracts have NO ' + + 'open-source replacement: `environment.zod` and `tenant.zod` are re-declared in the ' + + 'cloud repo beside their producer (objectstack-ai/cloud#2037), and `developer-portal.zod`, ' + + '`marketplace-admin.zod`, `app-store.zod`, `environment-package.zod` are deleted outright — ' + + 'zero consumers in any repo (maintainer ruling on #16526, option A). Recoverable from git ' + + 'history at `d5d8d50db` if a declaration is ever wanted again; that is a new card in the ' + + 'cloud repo, not a re-import.', + reason: + 'Maintainer direction (2026-09-06, verbatim, untranslated): 「我一直觉得 cloud 的协议应该放在云端,' + + '没必要开源」; ruled option B "cut by owner" on #16325 (director batch #62, 2026-09-07, 「同意」). ' + + 'The control-plane schemas\' producer and every consumer live in the closed cloud repo — the ' + + 'open-source tree read exactly one type from them (`EnvironmentType`, for the discovery fold ' + + 'table). Leaving them published made the obvious-looking binding of `client.environments.*` ' + + 'to a camelCase `Environment` row compile and read `undefined` at runtime against a ' + + 'snake_case wire (#11925 / #12036); with the declarations gone the mis-binding is ' + + 'structurally impossible rather than warned about in a docblock. No alias and no ' + + 'deprecation window, per the standing 2026-08-27 ruling 「项目在创业阶段,用户也很少,短期不考虑渐进。」. ' + + 'Not losslessly convertible: an import path is TypeScript source, not a metadata document ' + + '`objectstack migrate meta` can rewrite.', + acceptanceCriteria: + 'No code imports anything from `@objectstack/spec/cloud` — the specifier is not an `exports` ' + + 'key and every such import fails to resolve (TS2307) after upgrade. Package-format consumers ' + + 'resolve the same symbols from `@objectstack/spec/marketplace` (pinned by resolved symbol ' + + 'identity in `kernel/package-dependency-dual-source.test.ts` and ' + + '`system/environment-artifact.test.ts`). `api/discovery-environment-subset.pin.test.ts` ' + + 'still proves DiscoveryEnvironment ⊂ EnvironmentType against the re-declared enum. No ' + + 'metadata document needs editing: the 509 `cloud/*` authorable-surface baseline keys are ' + + 'discharged by the deletion gate\'s own proofs — 30 defs carried by declared rename, 62 by ' + + 'whole-def retirement (`RETIRED_DEFS_BY_MAJOR[18]`) — not by a tombstone an author could hit. ' + + '⚠️ Runtime behaviour is deliberately UNCHANGED: `os package publish`, the marketplace routes ' + + 'and the metadata plugin\'s artifact ingest parse byte-identically before and after.', + }, { id: 'cluster-driver-dangling-values-removed', surface: 'kernel.cluster.driver (ClusterDriverSchema, kernel/cluster.zod.ts) ' @@ -13407,6 +13457,316 @@ export const RETIRED_DEFS_BY_MAJOR: Readonly> // (`packages/runtime/src/route-ledger.ts`). See // `18.api__RestApiEndpoint__handlerStatus.ts` for the retirement record. 'api/RouteCoverageReport', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/AnalyticsTimeRange', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/AppDiscoveryRequest', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/AppDiscoveryResponse', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/AppSubscription', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/CreateListingRequest', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/CuratedCollection', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/Environment', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentCredential', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentCredentialStatus', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentDriver', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentMember', + // #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentPackageInstallation', + // #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentPackageStatus', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentRole', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentStatus', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/EnvironmentVisibility', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/FeaturedListing', + // #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/InstallPackageToEnvironmentRequest', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/InstalledAppSummary', + // #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ListEnvironmentPackagesResponse', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ListInstalledAppsRequest', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ListInstalledAppsResponse', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ListReviewsRequest', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ListReviewsResponse', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ListingActionRequest', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/MarketplaceHealthMetrics', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PackageInstallation', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PackageInstallationStatus', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PolicyAction', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PolicyViolationType', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ProvisionEnvironmentRequest', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ProvisionEnvironmentResponse', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ProvisionOrganizationRequest', + // #16325 — `cloud/environment.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ProvisionOrganizationResponse', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ProvisionTenantRequest', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ProvisionTenantResponse', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PublisherProfile', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PublishingAnalyticsRequest', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/PublishingAnalyticsResponse', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/RecommendationReason', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/RecommendedApp', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/RejectionReason', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ReleaseChannel', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ReviewCriterion', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ReviewDecision', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/ReviewModerationStatus', + // #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/RollbackEnvironmentPackageRequest', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/SubmissionReview', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/SubmitReviewRequest', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/SubscriptionStatus', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TenantContext', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TenantDatabase', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TenantDatabaseStatus', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TenantIdentificationSource', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TenantPlan', + // #16325 — `cloud/tenant.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TenantRoutingConfig', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TimeSeriesPoint', + // #16325 — `cloud/marketplace-admin.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/TrendingListing', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/UpdateListingRequest', + // #16325 — `cloud/environment-package.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/UpgradeEnvironmentPackageRequest', + // #16325 — `cloud/app-store.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/UserReview', + // #16325 — `cloud/developer-portal.zod.ts` left `@objectstack/spec` with the `./cloud` subpath + // (maintainer ruling, option B "cut by owner": the cloud control plane's contracts are + // the cloud repo's own declarations, not an open-source protocol). Prescription: the + // `cloud-subpath-retired` semantic entry of this major. + 'cloud/VersionRelease', // #8715 — identity/identity.zod.ts `ApiKeySchema`, retired whole (ADR-0049 // enforce-or-remove; maintainer ruling 2026-08-15, disposition B: delete). // The schema documented better-auth's `apiKey` PLUGIN shape — a plugin this diff --git a/packages/spec/src/system/environment-artifact.test.ts b/packages/spec/src/system/environment-artifact.test.ts index d395a8ec6f..e1935f63ab 100644 --- a/packages/spec/src/system/environment-artifact.test.ts +++ b/packages/spec/src/system/environment-artifact.test.ts @@ -39,9 +39,17 @@ import { // Maintainer ruling on #4740 (ledger #4535 C10): route A′ — converge on the // live wire shape as the SINGLE declaration in ./system, with ./cloud // re-exporting it (zero migration for the live consumers). Unlike C16 -// (#4739), the re-export is the SANCTIONED route here: both entries must -// keep the name, but must resolve it to the ONE ./system declaration. A -// fresh declaration on ./cloud is the forbidden route (S2 sabotage below). +// (#4739), the re-export was the SANCTIONED route here: both entries had to +// keep the name, but had to resolve it to the ONE ./system declaration. A +// fresh declaration on ./cloud was the forbidden route (S2 sabotage below). +// +// #16325 removed the `./cloud` subpath altogether (the cloud control plane's +// contracts are the cloud repo's, not an open-source protocol), which takes +// the re-exporting side with it. What survives is the STRONGER form of the +// same ruling: `./system` is the one declaration AND the one holder — no +// other entry may name the envelope at all, re-export or fresh declaration +// alike. The cloud repo's two former import sites already read +// `@objectstack/spec/system` (step 1 of the chain, cloud#2037). // // #4642 established that a compile-time conditional-type pin in this package // was a no-op until #5286 (tsconfig excluded `**/*.test.ts`; vitest never enables @@ -61,13 +69,16 @@ const RETIRED_V0_FAMILY = [ ] as const; describe('[#4740] `EnvironmentArtifact(Schema)` resolves to the ./system declaration everywhere', () => { - it('resolves the export surface: one declaration in ./system, ./cloud re-exports it, the v0 family is gone', () => { + it('resolves the export surface: one declaration in ./system, no other entry names it, the v0 family is gone', () => { // Anti-vacuity: the baseline must cover the real surface. (This used to // enumerate package.json's exports map and build its own `ts.createProgram` // right here; `export-origins/` IS that resolution, computed once at build // time and checked in — #4796.) - expect(EXPORT_ENTRY_POINTS).toContain('./cloud'); expect(EXPORT_ENTRY_POINTS).toContain('./system'); + expect(EXPORT_ENTRY_POINTS).toContain('./marketplace'); + // [#16325] The subpath that used to re-export the envelope is gone; the + // holder check below is what replaced the re-export half of this pin. + expect(EXPORT_ENTRY_POINTS).not.toContain('./cloud'); expect(EXPORT_ENTRY_POINTS.length).toBeGreaterThan(10); // 1. The surviving declaration: `./system` exports the envelope, declared @@ -89,22 +100,20 @@ describe('[#4740] `EnvironmentArtifact(Schema)` resolves to the ./system declara canonical[name] = originOf('./system', name); } - // 2. The re-exporting side: `./cloud` keeps every pre-#4740 name, but - // each resolves to the SAME ./system declaration — the sanctioned - // route A′. A fresh cloud-side declaration flips this red (S2). + // 2. The ONLY holder (#16325): `./system` is the one entry that names the + // envelope at all. Until #16325 this limb asserted that `./cloud` + // re-exported every name to the same declaration (route A′); with that + // subpath gone the sanctioned re-export has no host, and any entry that + // starts naming the envelope again — re-export or fresh declaration — + // flips this red. Exact equality, not a subset check. for (const name of names) { - expect(maybeOriginOf('./cloud', name), `./cloud must keep exporting \`${name}\``).toBeDefined(); - expect( - originOf('./cloud', name), - `./cloud must resolve \`${name}\` to the ./system declaration`, - ).toBe(canonical[name]); + expect(holdersOf(name), `only ./system may export \`${name}\``).toEqual(['./system']); } - // `Sha256Digest(Schema)` moved with the declaration; ./cloud keeps it by - // re-export too. + // `Sha256Digest(Schema)` moved with the declaration and has the same one + // holder. for (const name of ['Sha256Digest', 'Sha256DigestSchema']) { expect(maybeOriginOf('./system', name), `./system must export \`${name}\``).toBeDefined(); - expect(maybeOriginOf('./cloud', name), `./cloud must keep exporting \`${name}\``).toBeDefined(); - expect(originOf('./cloud', name)).toBe(originOf('./system', name)); + expect(holdersOf(name), `only ./system may export \`${name}\``).toEqual(['./system']); expect(originFileOf('./system', name)).toBe('src/system/environment-artifact.zod.ts'); } @@ -125,14 +134,12 @@ describe('[#4740] `EnvironmentArtifact(Schema)` resolves to the ./system declara } }); - it('keeps the runtime namespaces consistent with the compiler view', async () => { - const cloud = await import('../cloud/index'); + it('keeps the runtime namespace consistent with the compiler view', async () => { const system = await import('./index'); - // Re-export means the very same binding, not a lookalike. - expect(cloud.EnvironmentArtifactSchema).toBe(system.EnvironmentArtifactSchema); - expect(cloud.Sha256DigestSchema).toBe(system.Sha256DigestSchema); + // The runtime binding IS the declaration this file imports — not a lookalike. + expect(system.EnvironmentArtifactSchema).toBe(EnvironmentArtifactSchema); + expect(system.Sha256DigestSchema).toBe(Sha256DigestSchema); for (const gone of RETIRED_V0_FAMILY) { - expect(gone in cloud, `cloud must not export ${gone}`).toBe(false); expect(gone in system, `system must not export ${gone}`).toBe(false); } }); diff --git a/packages/spec/src/system/environment-artifact.zod.ts b/packages/spec/src/system/environment-artifact.zod.ts index cea5caa47d..a04b137948 100644 --- a/packages/spec/src/system/environment-artifact.zod.ts +++ b/packages/spec/src/system/environment-artifact.zod.ts @@ -10,10 +10,12 @@ import { PluginPermissionsSchema } from '../kernel/manifest.zod'; * # Environment Artifact Envelope * * THE single declaration of the environment artifact envelope (#4740, - * #4535 C10 — maintainer route A′). `@objectstack/spec/cloud` re-exports - * this file; both entry points resolve to these exact symbols, so the - * chosen entry point can never change the shape a consumer gets (the - * #4411 dual-source trap, closed for this name). + * #4535 C10 — maintainer route A′). `@objectstack/spec/system` is now its + * ONLY entry point: `@objectstack/spec/cloud` re-exported this file until + * #16325 removed that subpath, and no other entry has ever declared or + * re-exported the name, so the chosen entry point can never change the + * shape a consumer gets (the #4411 dual-source trap, closed for this name — + * pinned by `holdersOf` in `./environment-artifact.test.ts`). * * Describes the response shape of * `GET /api/v1/cloud/environments/:environmentId/artifact` — the assembled diff --git a/packages/spec/src/system/index.ts b/packages/spec/src/system/index.ts index 2fd3fa3dd9..0fc0f4ce99 100644 --- a/packages/spec/src/system/index.ts +++ b/packages/spec/src/system/index.ts @@ -142,9 +142,11 @@ export * from './registry-config.zod'; // TenantProvisioningResult) was declared-only — zero implementations and zero // importers across objectstack / cloud / objectui — and its // `TenantPlan(Schema)` collided with the live declaration in `./cloud`. The -// living provisioning surface is the `Provision*` family in -// `@objectstack/spec/cloud` (cloud/tenant.zod.ts, cloud/environment.zod.ts), -// which the cloud services actually consume. +// living provisioning surface is the `Provision*` family — declared in +// `@objectstack/spec/cloud` until #16325, and since then in the cloud repo +// itself, beside the services that consume it (the `./cloud` subpath is gone; +// `./tenant-provisioning-family-retired.test.ts` keeps this side's half of +// the #4739 ruling pinned). export * from './deploy-bundle.zod'; export * from './app-install.zod'; export * from './environment-artifact.zod'; diff --git a/packages/spec/src/system/tenant-provisioning-family-retired.test.ts b/packages/spec/src/system/tenant-provisioning-family-retired.test.ts new file mode 100644 index 0000000000..332be5d376 --- /dev/null +++ b/packages/spec/src/system/tenant-provisioning-family-retired.test.ts @@ -0,0 +1,96 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import { describe, it, expect } from 'vitest'; + +import { + EXPORT_ENTRY_POINTS, + exportNamesOf, + holdersOf, +} from '../../scripts/lib/export-origins-testkit'; +// ─── [#4739] the system-side provisioning family stays retired ────────────── +// +// `./cloud` and `./system` both exported a `TenantPlan` + `TenantPlanSchema` +// for two different declarations (the #4411 trap — which vocabulary a consumer +// got depended on the import path). Maintainer ruling on #4739 (ledger #4535 +// C16): route B — delete the system-side provisioning family +// (`system/provisioning.zod.ts`: TenantPlan / TenantRegion / +// TenantProvisioningStatus / ProvisioningStep / TenantProvisioningRequest / +// TenantProvisioningResult) and its declared-only contracts +// (`IProvisioningService` / `ITenantRouter` / `ResolvedTenantContext` in +// `./contracts`); the cloud side keeps the name. +// +// That pin lived in `cloud/tenant.test.ts` beside the surviving declaration. +// #16325 then removed the `./cloud` subpath itself — the cloud control plane's +// contracts, `tenant.zod.ts` included, are the cloud repo's own declarations +// now, not an open-source protocol — so the "cloud keeps the name" half of the +// ruling is no longer this package's to pin. The half that IS still this +// package's is kept here: `./system` and `./contracts` must not re-grow the +// retired family, and — the new fact — `TenantPlan(Schema)` is named by NO +// entry of `@objectstack/spec` at all. A `./system` re-export of anything +// called `TenantPlan` was the forbidden route under #4739 and is still +// forbidden; it now has nothing left to re-export from. +// +// #4642 established that a compile-time conditional-type pin in this package +// was a no-op until #5286 (tsconfig excluded `**/*.test.ts`; vitest never enables +// `typecheck`), so the load-bearing pin is the export-origins test below, with +// anti-vacuity guards. +describe('[#4739 / #16325] the system-side provisioning family stays retired, and `TenantPlan` has left the package', () => { + it('resolves the export surface: ./system and ./contracts name none of the retired family', () => { + // Anti-vacuity: the baseline must cover the real surface (`export-origins/` + // IS the resolution, computed at build time and checked in — #4796). + expect(EXPORT_ENTRY_POINTS).toContain('./system'); + expect(EXPORT_ENTRY_POINTS).toContain('./contracts'); + expect(EXPORT_ENTRY_POINTS).not.toContain('./cloud'); + expect(EXPORT_ENTRY_POINTS.length).toBeGreaterThan(10); + + // 1. `./system` still has a non-trivial surface — so the `not.toContain` + // cannot pass by resolving nothing — and names none of the provisioning + // family, while its surviving multi-tenant neighbours stand. + const systemNames = exportNamesOf('./system'); + expect(systemNames.length, './system must export a non-trivial surface').toBeGreaterThan(100); + for (const gone of [ + 'TenantPlan', 'TenantPlanSchema', + 'TenantRegion', 'TenantRegionSchema', + 'TenantProvisioningStatus', 'TenantProvisioningStatusEnum', + 'ProvisioningStep', 'ProvisioningStepSchema', + 'TenantProvisioningRequest', 'TenantProvisioningRequestSchema', + 'TenantProvisioningResult', 'TenantProvisioningResultSchema', + ]) { + expect(systemNames, `./system must not name ${gone}`).not.toContain(gone); + } + expect(systemNames).toContain('TenantSchema'); + expect(systemNames).toContain('TenantIsolationLevel'); + + // 2. `./contracts` keeps its surface but the declared-only provisioning + // pair is gone. + const contractsNames = exportNamesOf('./contracts'); + expect(contractsNames.length, './contracts must export a non-trivial surface').toBeGreaterThan(50); + for (const gone of ['IProvisioningService', 'ITenantRouter', 'ResolvedTenantContext']) { + expect(contractsNames, `./contracts must not name ${gone}`).not.toContain(gone); + } + expect(contractsNames).toContain('ISchemaDiffService'); + + // 3. Across EVERY public entry: nothing names the retired contracts, and — + // since #16325 — nothing names `TenantPlan(Schema)` either. The cloud + // declaration that used to be the one legitimate holder left with the + // `./cloud` subpath; a holder reappearing anywhere is a second + // declaration of a name this package no longer owns. + for (const gone of [ + 'IProvisioningService', 'ITenantRouter', 'ResolvedTenantContext', + 'TenantPlan', 'TenantPlanSchema', + ]) { + expect(holdersOf(gone), `no entry may name ${gone}`).toEqual([]); + } + }); + + it('keeps the runtime namespace consistent with the compiler view', async () => { + const system = await import('./index'); + // Anti-vacuity: the namespace probed is real and non-trivial. + expect('TenantSchema' in system).toBe(true); + expect('TenantPlanSchema' in system).toBe(false); + expect('TenantProvisioningRequestSchema' in system).toBe(false); + expect('TenantProvisioningResultSchema' in system).toBe(false); + expect('TenantRegionSchema' in system).toBe(false); + expect('ProvisioningStepSchema' in system).toBe(false); + }); +}); diff --git a/packages/spec/src/type-alias-convention.pin.test.ts b/packages/spec/src/type-alias-convention.pin.test.ts index 0f02049470..98b0651556 100644 --- a/packages/spec/src/type-alias-convention.pin.test.ts +++ b/packages/spec/src/type-alias-convention.pin.test.ts @@ -119,16 +119,10 @@ import type * as M41 from './automation/node-executor.zod.js'; import type * as M42 from './automation/state-machine.zod.js'; import type * as M43 from './automation/time-relative-trigger.zod.js'; import type * as M44 from './automation/webhook.zod.js'; -import type * as M45 from './cloud/app-store.zod.js'; -import type * as M46 from './cloud/developer-portal.zod.js'; -import type * as M47 from './cloud/environment-package.zod.js'; -import type * as M48 from './cloud/environment.zod.js'; -import type * as M49 from './cloud/marketplace-admin.zod.js'; -import type * as M50 from './cloud/marketplace.zod.js'; -import type * as M51 from './cloud/package-version.zod.js'; -import type * as M52 from './cloud/package.zod.js'; -import type * as M53 from './cloud/template-manifest.zod.js'; -import type * as M54 from './cloud/tenant.zod.js'; +import type * as M50 from './marketplace/marketplace.zod.js'; +import type * as M51 from './marketplace/package-version.zod.js'; +import type * as M52 from './marketplace/package.zod.js'; +import type * as M53 from './marketplace/template-manifest.zod.js'; import type * as M55 from './data/analytics.zod.js'; import type * as M56 from './data/data-engine.zod.js'; import type * as M57 from './data/datasource.zod.js'; @@ -275,7 +269,7 @@ import type * as M184 from './shared/value-domain.zod.js'; import type * as M185 from './shared/epoch.zod.js'; // --------------------------------------------------------------------------- -// 811 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. +// 782 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 @@ -389,6 +383,8 @@ export type Iso67 = Assert, export type Iso68 = Assert, z.infer< typeof M17.WellKnownCapabilitiesSchema > >>; export type Iso69 = Assert, z.infer< typeof M17.CapabilityDescriptorSchema > >>; export type Iso70 = Assert, z.infer< typeof M17.DiscoverySchema > >>; +// [#16325] `EnvironmentTypeSchema` moved here from cloud/environment.zod.ts (was Iso262). +export type Iso871 = Assert, z.infer< typeof M17.EnvironmentTypeSchema > >>; export type Iso71 = Assert, z.infer< typeof M17.ApiRoutesSchema > >>; export type Iso72 = Assert, z.infer< typeof M17.ServiceInfoSchema > >>; export type Iso73 = Assert, z.infer< typeof M17.RouteHealthEntrySchema > >>; @@ -635,42 +631,7 @@ export type Iso247 = Assert, // automation/webhook.zod.ts export type Iso248 = Assert, z.infer< typeof M44.WebhookTriggerType > >>; -// cloud/app-store.zod.ts -export type Iso249 = Assert, z.infer< typeof M45.ReviewModerationStatusSchema > >>; -export type Iso250 = Assert, z.infer< typeof M45.SubmitReviewRequestSchema > >>; -export type Iso251 = Assert, z.infer< typeof M45.RecommendationReasonSchema > >>; -export type Iso252 = Assert, z.infer< typeof M45.RecommendedAppSchema > >>; -export type Iso253 = Assert, z.infer< typeof M45.AppDiscoveryResponseSchema > >>; -export type Iso254 = Assert, z.infer< typeof M45.SubscriptionStatusSchema > >>; - -// cloud/developer-portal.zod.ts -export type Iso255 = Assert, z.infer< typeof M46.ReleaseChannelSchema > >>; -export type Iso256 = Assert, z.infer< typeof M46.UpdateListingRequestSchema > >>; -export type Iso257 = Assert, z.infer< typeof M46.ListingActionRequestSchema > >>; -export type Iso258 = Assert, z.infer< typeof M46.AnalyticsTimeRangeSchema > >>; -export type Iso259 = Assert, z.infer< typeof M46.TimeSeriesPointSchema > >>; - -// cloud/environment-package.zod.ts -export type Iso260 = Assert, z.infer< typeof M47.EnvironmentPackageStatusSchema > >>; -export type Iso261 = Assert, z.infer< typeof M47.RollbackEnvironmentPackageRequestSchema > >>; - -// cloud/environment.zod.ts -export type Iso262 = Assert, z.infer< typeof M48.EnvironmentTypeSchema > >>; -export type Iso263 = Assert, z.infer< typeof M48.EnvironmentStatusSchema > >>; -export type Iso264 = Assert, z.infer< typeof M48.EnvironmentDriverSchema > >>; -export type Iso265 = Assert, z.infer< typeof M48.EnvironmentVisibilitySchema > >>; -export type Iso266 = Assert, z.infer< typeof M48.EnvironmentCredentialStatusSchema > >>; -export type Iso267 = Assert, z.infer< typeof M48.EnvironmentRoleSchema > >>; -export type Iso268 = Assert, z.infer< typeof M48.EnvironmentMemberSchema > >>; - -// cloud/marketplace-admin.zod.ts -export type Iso269 = Assert, z.infer< typeof M49.ReviewDecisionSchema > >>; -export type Iso270 = Assert, z.infer< typeof M49.RejectionReasonSchema > >>; -export type Iso271 = Assert, z.infer< typeof M49.PolicyViolationTypeSchema > >>; -export type Iso272 = Assert, z.infer< typeof M49.MarketplaceHealthMetricsSchema > >>; -export type Iso273 = Assert, z.infer< typeof M49.TrendingListingSchema > >>; - -// cloud/marketplace.zod.ts +// marketplace/marketplace.zod.ts export type Iso274 = Assert, z.infer< typeof M50.ArtifactDownloadResponseSchema > >>; export type Iso275 = Assert, z.infer< typeof M50.PublisherVerificationSchema > >>; export type Iso276 = Assert, z.infer< typeof M50.MarketplaceCategorySchema > >>; @@ -678,13 +639,13 @@ export type Iso277 = Assert, z.inf export type Iso278 = Assert, z.infer< typeof M50.PricingModelSchema > >>; export type Iso279 = Assert, z.infer< typeof M50.MarketplaceInstallResponseSchema > >>; -// cloud/package-version.zod.ts +// marketplace/package-version.zod.ts export type Iso280 = Assert, z.infer< typeof M51.PackageVersionStatusSchema > >>; export type Iso281 = Assert, z.infer< typeof M51.CreatePackageVersionRequestSchema > >>; export type Iso282 = Assert, z.infer< typeof M51.UpdatePackageVersionRequestSchema > >>; export type Iso283 = Assert, z.infer< typeof M51.PublishPackageVersionRequestSchema > >>; -// cloud/package.zod.ts +// marketplace/package.zod.ts export type Iso284 = Assert, z.infer< typeof M52.PackageVisibilitySchema > >>; export type Iso285 = Assert, z.infer< typeof M52.PackageCategorySchema > >>; export type Iso286 = Assert, z.infer< typeof M52.PackagePublisherSchema > >>; @@ -694,16 +655,9 @@ export type Iso289 = Assert, export type Iso290 = Assert, z.infer< typeof M52.CreatePackageRequestSchema > >>; export type Iso291 = Assert, z.infer< typeof M52.UpdatePackageRequestSchema > >>; -// cloud/template-manifest.zod.ts +// marketplace/template-manifest.zod.ts export type Iso292 = Assert, z.infer< typeof M53.TemplateManifestSchema > >>; -// cloud/tenant.zod.ts -export type Iso293 = Assert, z.infer< typeof M54.TenantDatabaseStatusSchema > >>; -export type Iso294 = Assert, z.infer< typeof M54.TenantPlanSchema > >>; -export type Iso295 = Assert, z.infer< typeof M54.PackageInstallationStatusSchema > >>; -export type Iso296 = Assert, z.infer< typeof M54.TenantContextSchema > >>; -export type Iso297 = Assert, z.infer< typeof M54.TenantIdentificationSourceSchema > >>; - // data/analytics.zod.ts export type Iso298 = Assert, z.infer< typeof M55.MetricSchema > >>; export type Iso299 = Assert, z.infer< typeof M55.DimensionSchema > >>; @@ -1692,7 +1646,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 811 isomorphic pins', () => { + it('still declares all 782 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 @@ -2188,7 +2142,17 @@ describe('ADR-0122 type-alias convention', () => { // left the isomorphic family the way ADR-0122 prescribes: the `XParsed` // alias declared, the pin deleted. -4 converted to `XParsed` pairs; the // Iso numbers stay vacant (ids are claims about pins, not positions). - expect(pins).toHaveLength(811); + // + // 811 -> 782 is #16325, the `./cloud` subpath leaving `@objectstack/spec` + // (maintainer ruling, option B "cut by owner"): the six control-plane + // modules — `cloud/app-store` (6 pins), `developer-portal` (5), + // `environment-package` (2), `environment` (7), `marketplace-admin` (5), + // `tenant` (5) — left with their 30 pins (module slots M45–M49 and M54 are + // vacant), and `EnvironmentTypeSchema` moved with its only open-source + // reader to `api/discovery.zod.ts` (M17), where it is pinned again as + // `Iso871`. The four package-format modules (M50–M53) moved to + // `marketplace/` and kept their pins. -30 + 1. + expect(pins).toHaveLength(782); // The count is stated in PROSE twice as well — this case's title and the // section header above the pin list — and until #6605 nothing read either diff --git a/packages/spec/tsup.config.ts b/packages/spec/tsup.config.ts index 62b24aceb3..0d7bb9b4de 100644 --- a/packages/spec/tsup.config.ts +++ b/packages/spec/tsup.config.ts @@ -83,7 +83,7 @@ const entries = [ 'src/contracts/index.ts', 'src/integration/index.ts', 'src/studio/index.ts', - 'src/cloud/index.ts', + 'src/marketplace/index.ts', 'src/qa/index.ts', 'src/identity/index.ts', 'src/shared/index.ts', @@ -117,7 +117,6 @@ const browserConditionedEntries = [ 'src/data/index.ts', 'src/system/index.ts', 'src/kernel/index.ts', - 'src/cloud/index.ts', ]; /** diff --git a/packages/spec/unemitted-schemas.baseline.json b/packages/spec/unemitted-schemas.baseline.json index 0110a311b0..8370b39756 100644 --- a/packages/spec/unemitted-schemas.baseline.json +++ b/packages/spec/unemitted-schemas.baseline.json @@ -45,10 +45,6 @@ "cause": "function", "reason": "The union of all four `functions` entry shapes. Its first member IS the bare `z.function()` above, and #16431 (a)'s per-branch projection does drop that member — measured: 1 branch pruned — but the union still does not publish, because the member behind it is FlowFunctionDeclarationSchema, whose required `handler` is itself a live callable. An unprojectable node in a PROPERTY position is not droppable: every document the declaration accepts has that key, so publishing the record without it would describe a shape no runtime value has. Both lowered members are plain JSON and would publish on their own; what this entry now records is a union that cannot be projected while one of its branches requires a callable." }, - "Cloud.EnvironmentArtifactSchema": { - "cause": "function", - "reason": "Re-export of System.EnvironmentArtifactSchema (system/environment-artifact.zod.ts) — see that entry. Both export names are recorded because the ratchet is keyed by EXPORT, which is the unit that reaches or fails to reach a published surface." - }, "Data.DataEngineContractSchema": { "cause": "function", "reason": "The engine method contract — `find`/`findOne`/`insert`/`update`/`delete` are `z.function()` members. A CODE interface implemented by an engine, never a document anyone authors or transmits, so no reader loses a reference page." diff --git a/scripts/check-system-context-census.mjs b/scripts/check-system-context-census.mjs index ea04d0415a..2b21f55e70 100644 --- a/scripts/check-system-context-census.mjs +++ b/scripts/check-system-context-census.mjs @@ -403,11 +403,9 @@ export const NON_READ_ANCHORS = [ symbol: 'isSystem', why: 'EmailTemplate.isSystem -- unrelated metadata field', }, - { - file: 'packages/spec/src/cloud/environment.zod.ts', - symbol: 'isSystem', - why: 'Environment.isSystem -- unrelated metadata field', - }, + // `Environment.isSystem` (`packages/spec/src/cloud/environment.zod.ts`) was the + // fourth row until #16325 removed the `@objectstack/spec/cloud` subpath; the + // declaration lives in the cloud repo now and is outside this census. // ── The `sys_` name-prefix family, cited to keep it apart from the flag ────── { file: 'packages/runtime/src/action-execution.ts',