diff --git a/.changeset/example-apps-spec-input-types.md b/.changeset/example-apps-spec-input-types.md new file mode 100644 index 0000000000..6251865776 --- /dev/null +++ b/.changeset/example-apps-spec-input-types.md @@ -0,0 +1,5 @@ +--- +"@objectstack/spec": patch +--- + +Add `*Input` authoring-type aliases (`DatasourceInput`, `ConnectorInput`, `SharingRuleInput`, `JobInput`, `WebhookInput`, `EmailTemplateDefinitionInput`, `RoleInput`, `PermissionSetInput`, `ObjectExtensionInput`) alongside the existing `FieldInput`/`ActionInput`/`ReportInput`/`PortalInput` convention. These are `z.input` aliases so authored literals keep `.default()` fields optional and accept CEL/Expression string shorthands — matching how `defineX()` helpers already accept input. No runtime change. diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5ec270dc45..a84ddd8222 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -46,5 +46,16 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Type check + - name: Type check (@objectstack/spec) run: pnpm --filter @objectstack/spec exec tsc --noEmit + + # Example apps are AI-authoring reference templates; a red typecheck is a + # bad signal to copy from. tsup transpiles them without a full typecheck, + # so build alone will not catch type drift — typecheck them explicitly. + # They import from built workspace packages, so the packages must be built + # first for cross-package type resolution to succeed. + - name: Build workspace packages + run: pnpm exec turbo run build --filter='./packages/*' + + - name: Type check example apps + run: pnpm --filter './examples/*' run typecheck diff --git a/examples/app-crm/src/actions/convert-lead.action.ts b/examples/app-crm/src/actions/convert-lead.action.ts index 91045a4a81..970cecf78b 100644 --- a/examples/app-crm/src/actions/convert-lead.action.ts +++ b/examples/app-crm/src/actions/convert-lead.action.ts @@ -1,15 +1,14 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { UI } from '@objectstack/spec'; +import type * as UI from '@objectstack/spec/ui'; /** * Row-level action on crm_lead — launches the Convert Lead screen flow wizard. * Shown as a button in the lead list row menu and in the lead record header. */ -export const ConvertLeadAction: UI.Action = { +export const ConvertLeadAction: UI.ActionInput = { name: 'crm_convert_lead', label: 'Convert Lead', - description: 'Open the Convert Lead wizard to create an Opportunity from this Lead.', icon: 'ArrowRightCircle', objectName: 'crm_lead', type: 'flow', diff --git a/examples/app-crm/src/actions/park-lead.action.ts b/examples/app-crm/src/actions/park-lead.action.ts index e481a987d5..62d35ab7b1 100644 --- a/examples/app-crm/src/actions/park-lead.action.ts +++ b/examples/app-crm/src/actions/park-lead.action.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { UI } from '@objectstack/spec'; +import type * as UI from '@objectstack/spec/ui'; /** * Row-level action on crm_lead — reassign the lead's owner. @@ -11,10 +11,9 @@ import type { UI } from '@objectstack/spec'; * UndoManager — Ctrl+Z works too). Prompts for the new owner via one param * (pre-filled with "Triage Queue"). */ -export const ParkLeadAction: UI.Action = { +export const ParkLeadAction: UI.ActionInput = { name: 'crm_park_lead', label: 'Reassign Lead', - description: 'Reassign this lead to a new owner (undoable).', icon: 'UserPlus', objectName: 'crm_lead', // `type: 'api'` with a non-URL target routes to the console runtime's generic diff --git a/examples/app-crm/src/agents/sales-assistant.agent.ts b/examples/app-crm/src/agents/sales-assistant.agent.ts index d4d69d50ae..30040152d9 100644 --- a/examples/app-crm/src/agents/sales-assistant.agent.ts +++ b/examples/app-crm/src/agents/sales-assistant.agent.ts @@ -42,7 +42,6 @@ export const DealManagementSkill = defineSkill({ export const SalesAssistantAgent = defineAgent({ name: 'crm_sales_assistant', label: 'Sales Assistant', - description: 'AI assistant that helps sales reps manage their pipeline.', role: 'You are a helpful sales operations assistant for a CRM system.', instructions: 'Help sales reps find contacts, update opportunities, and summarise their pipeline. Always be concise and ask before making destructive changes.', diff --git a/examples/app-crm/src/analytics/crm.cube.ts b/examples/app-crm/src/analytics/crm.cube.ts index 5f1b525bcb..cda2a47672 100644 --- a/examples/app-crm/src/analytics/crm.cube.ts +++ b/examples/app-crm/src/analytics/crm.cube.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Cube } from '@objectstack/spec'; +import type { Cube } from '@objectstack/spec/data'; /** * Opportunity Pipeline Cube — revenue metrics broken down by stage, diff --git a/examples/app-crm/src/api/crm-endpoints.ts b/examples/app-crm/src/api/crm-endpoints.ts index 386e20b5b9..fbd1797054 100644 --- a/examples/app-crm/src/api/crm-endpoints.ts +++ b/examples/app-crm/src/api/crm-endpoints.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { ApiEndpoint } from '@objectstack/spec'; +import type { ApiEndpoint } from '@objectstack/spec/api'; /** * Custom REST endpoint — exposes pipeline summary metrics. diff --git a/examples/app-crm/src/connectors/crm-connectors.ts b/examples/app-crm/src/connectors/crm-connectors.ts index 078d93fb31..a732f63c26 100644 --- a/examples/app-crm/src/connectors/crm-connectors.ts +++ b/examples/app-crm/src/connectors/crm-connectors.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Connector } from '@objectstack/spec'; +import type { ConnectorInput } from '@objectstack/spec/integration'; /** * HubSpot connector — sync contacts and deals bi-directionally. * Uses OAuth2 for authentication; actual credentials come from environment. */ -export const HubSpotConnector: Connector = { +export const HubSpotConnector: ConnectorInput = { name: 'hubspot_crm', label: 'HubSpot CRM', type: 'saas', @@ -91,7 +91,7 @@ export const HubSpotConnector: Connector = { /** * Slack connector — post notifications to channels. */ -export const SlackConnector: Connector = { +export const SlackConnector: ConnectorInput = { name: 'slack_notifications', label: 'Slack', type: 'api', diff --git a/examples/app-crm/src/data/crm-mappings.ts b/examples/app-crm/src/data/crm-mappings.ts index a0f3722de2..d92a182c3c 100644 --- a/examples/app-crm/src/data/crm-mappings.ts +++ b/examples/app-crm/src/data/crm-mappings.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Mapping } from '@objectstack/spec'; +import type { Mapping } from '@objectstack/spec/data'; /** * CSV import mapping for bulk lead upload. diff --git a/examples/app-crm/src/datasources/crm.datasource.ts b/examples/app-crm/src/datasources/crm.datasource.ts index b01c31720d..7c41686bf9 100644 --- a/examples/app-crm/src/datasources/crm.datasource.ts +++ b/examples/app-crm/src/datasources/crm.datasource.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Datasource } from '@objectstack/spec'; +import type { DatasourceInput } from '@objectstack/spec/data'; /** * Primary CRM datasource — in-memory SQLite for the example. * In production, swap `driver` to 'postgres' and supply real `config`. */ -export const CrmDatasource: Datasource = { +export const CrmDatasource: DatasourceInput = { name: 'crm_primary', label: 'CRM Primary Database', driver: 'sqlite', @@ -23,7 +23,7 @@ export const CrmDatasource: Datasource = { /** * Read-replica for analytics queries — demonstrates datasource routing. */ -export const CrmAnalyticsDatasource: Datasource = { +export const CrmAnalyticsDatasource: DatasourceInput = { name: 'crm_analytics', label: 'CRM Analytics Read Replica', driver: 'sqlite', diff --git a/examples/app-crm/src/emails/deal-won.email.ts b/examples/app-crm/src/emails/deal-won.email.ts index 36e6a31dff..d24fbce3c3 100644 --- a/examples/app-crm/src/emails/deal-won.email.ts +++ b/examples/app-crm/src/emails/deal-won.email.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { EmailTemplateDefinition } from '@objectstack/spec/system'; +import type { EmailTemplateDefinitionInput } from '@objectstack/spec/system'; /** * Sent when an opportunity moves to Closed Won. * Referenced by the `notify_owner_deal_won` workflow action. */ -export const DealWonEmail: EmailTemplateDefinition = { +export const DealWonEmail: EmailTemplateDefinitionInput = { name: 'crm.deal_won', label: 'Deal Won — Owner Congrats', category: 'workflow', diff --git a/examples/app-crm/src/emails/lead-follow-up.email.ts b/examples/app-crm/src/emails/lead-follow-up.email.ts index 0d1c566a94..c6e2fb2066 100644 --- a/examples/app-crm/src/emails/lead-follow-up.email.ts +++ b/examples/app-crm/src/emails/lead-follow-up.email.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { EmailTemplateDefinition } from '@objectstack/spec/system'; +import type { EmailTemplateDefinitionInput } from '@objectstack/spec/system'; /** * Follow-up nudge sent by the Stale Opportunity workflow when no * activity has been logged on a Lead for the configured threshold. */ -export const LeadFollowUpEmail: EmailTemplateDefinition = { +export const LeadFollowUpEmail: EmailTemplateDefinitionInput = { name: 'crm.lead_followup', label: 'Lead — Follow-Up Reminder', category: 'notification', diff --git a/examples/app-crm/src/emails/welcome.email.ts b/examples/app-crm/src/emails/welcome.email.ts index 15f03de3dd..923049fd94 100644 --- a/examples/app-crm/src/emails/welcome.email.ts +++ b/examples/app-crm/src/emails/welcome.email.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { EmailTemplateDefinition } from '@objectstack/spec/system'; +import type { EmailTemplateDefinitionInput } from '@objectstack/spec/system'; /** * Welcome email sent to a Contact after it's added to the CRM. * Demonstrates marketing-category templates with a clear CTA. */ -export const WelcomeEmail: EmailTemplateDefinition = { +export const WelcomeEmail: EmailTemplateDefinitionInput = { name: 'crm.welcome', label: 'Welcome — New Contact', category: 'marketing', diff --git a/examples/app-crm/src/extensions/contact.extension.ts b/examples/app-crm/src/extensions/contact.extension.ts index d28161c050..67e84e3d3e 100644 --- a/examples/app-crm/src/extensions/contact.extension.ts +++ b/examples/app-crm/src/extensions/contact.extension.ts @@ -1,13 +1,13 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { ObjectExtension } from '@objectstack/spec'; +import type { ObjectExtensionInput } from '@objectstack/spec/data'; /** * Extends the built-in crm_contact object with social-media fields. * Demonstrates ObjectExtension — additive fields without re-declaring the * whole object schema. */ -export const ContactExtension: ObjectExtension = { +export const ContactExtension: ObjectExtensionInput = { extend: 'crm_contact', label: 'Contact (CRM Extended)', fields: { diff --git a/examples/app-crm/src/jobs/crm-jobs.ts b/examples/app-crm/src/jobs/crm-jobs.ts index 4aa9afdc06..05fc33f8a8 100644 --- a/examples/app-crm/src/jobs/crm-jobs.ts +++ b/examples/app-crm/src/jobs/crm-jobs.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Job } from '@objectstack/spec'; +import type { JobInput } from '@objectstack/spec/system'; /** * Nightly lead-scoring job — recomputes `lead_score` for all open leads. * Handler key 'scoreLeads' must be registered in defineStack({ functions }). */ -export const LeadScoringJob: Job = { +export const LeadScoringJob: JobInput = { name: 'crm_lead_scoring', label: 'Nightly Lead Score Refresh', description: 'Recalculates lead_score for all open leads using engagement signals.', @@ -28,7 +28,7 @@ export const LeadScoringJob: Job = { /** * Weekly pipeline report — aggregates deal data and emails managers. */ -export const PipelineReportJob: Job = { +export const PipelineReportJob: JobInput = { name: 'crm_pipeline_report', label: 'Weekly Pipeline Report', description: 'Generates and emails weekly pipeline summary to sales managers.', @@ -51,7 +51,7 @@ export const PipelineReportJob: Job = { * Daily renewal reminder sweep — kicks off renewal_reminder_flow for * opportunities nearing contract expiry. */ -export const RenewalSweepJob: Job = { +export const RenewalSweepJob: JobInput = { name: 'crm_renewal_sweep', label: 'Daily Renewal Reminder Sweep', description: 'Scans contracts expiring within 30 days and enqueues reminder flows.', diff --git a/examples/app-crm/src/pages/welcome.page.ts b/examples/app-crm/src/pages/welcome.page.ts index 5395e2893c..a1f9bd1e96 100644 --- a/examples/app-crm/src/pages/welcome.page.ts +++ b/examples/app-crm/src/pages/welcome.page.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { UI } from '@objectstack/spec'; +import type * as UI from '@objectstack/spec/ui'; /** * Example custom page — a CRM landing page. diff --git a/examples/app-crm/src/portals/customer.portal.ts b/examples/app-crm/src/portals/customer.portal.ts index 639a726a46..356f9e536e 100644 --- a/examples/app-crm/src/portals/customer.portal.ts +++ b/examples/app-crm/src/portals/customer.portal.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Portal } from '@objectstack/spec'; +import type { Portal } from '@objectstack/spec/ui'; /** * Customer Self-Service Portal — external users can view their account, diff --git a/examples/app-crm/src/reports/sales-by-stage.report.ts b/examples/app-crm/src/reports/sales-by-stage.report.ts index 2c61cc9103..e4f2a45ccb 100644 --- a/examples/app-crm/src/reports/sales-by-stage.report.ts +++ b/examples/app-crm/src/reports/sales-by-stage.report.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { UI } from '@objectstack/spec'; +import type * as UI from '@objectstack/spec/ui'; /** * Example report — total opportunity amount grouped by stage. @@ -11,7 +11,7 @@ import type { UI } from '@objectstack/spec'; * its "grouped by stage" label), so both forms compute the same number and the * reconciliation harness can verify them. */ -export const SalesByStageReport: UI.Report = { +export const SalesByStageReport: UI.ReportInput = { name: 'crm_sales_by_stage', label: 'Sales by Stage', description: 'Total opportunity amount grouped by sales stage.', diff --git a/examples/app-crm/src/security/crm-policy.ts b/examples/app-crm/src/security/crm-policy.ts index ec402e9dd5..f5c1102e14 100644 --- a/examples/app-crm/src/security/crm-policy.ts +++ b/examples/app-crm/src/security/crm-policy.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Policy } from '@objectstack/spec'; +import type { Policy } from '@objectstack/spec/security'; /** * Default CRM security policy applied to all users. diff --git a/examples/app-crm/src/security/sales-roles.ts b/examples/app-crm/src/security/sales-roles.ts index d684a12005..4984005a94 100644 --- a/examples/app-crm/src/security/sales-roles.ts +++ b/examples/app-crm/src/security/sales-roles.ts @@ -1,25 +1,26 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Identity, Security } from '@objectstack/spec'; +import type * as Identity from '@objectstack/spec/identity'; +import type * as Security from '@objectstack/spec/security'; /** * Example roles — a small sales hierarchy. */ -export const SalesRepRole: Identity.Role = { +export const SalesRepRole: Identity.RoleInput = { name: 'sales_rep', label: 'Sales Representative', description: 'Front-line sales representative.', }; -export const SalesManagerRole: Identity.Role = { +export const SalesManagerRole: Identity.RoleInput = { name: 'sales_manager', label: 'Sales Manager', description: 'Manages a team of sales reps.', - parentRole: 'sales_rep', + parent: 'sales_rep', }; /** Referenced by the Discount Approval second step. */ -export const FinanceApproverRole: Identity.Role = { +export const FinanceApproverRole: Identity.RoleInput = { name: 'finance_approver', label: 'Finance Approver', description: 'Finance team member authorised to approve discounts above 30%.', @@ -30,10 +31,9 @@ export const FinanceApproverRole: Identity.Role = { * * Note: `objects` is a Record keyed by object name, not an array. */ -export const SalesUserPermissionSet: Security.PermissionSet = { +export const SalesUserPermissionSet: Security.PermissionSetInput = { name: 'crm_sales_user', label: 'CRM Sales User', - description: 'Standard CRUD on CRM objects for sales team members.', isProfile: false, objects: { crm_account: { allowRead: true, allowCreate: true, allowEdit: true, allowDelete: false }, @@ -52,10 +52,9 @@ export const SalesUserPermissionSet: Security.PermissionSet = { * `crm_lead` (not a short `lead`). INSERT-only — guests can never read, edit, or * delete any record. */ -export const GuestPortalProfile: Security.PermissionSet = { +export const GuestPortalProfile: Security.PermissionSetInput = { name: 'guest_portal', label: 'Guest (Public Forms)', - description: 'Anonymous Web-to-Lead submitters — INSERT-only on crm_lead.', isProfile: true, objects: { crm_lead: { allowRead: false, allowCreate: true, allowEdit: false, allowDelete: false }, diff --git a/examples/app-crm/src/security/sharing-rules.ts b/examples/app-crm/src/security/sharing-rules.ts index 6428db18ec..2e49b44a2f 100644 --- a/examples/app-crm/src/security/sharing-rules.ts +++ b/examples/app-crm/src/security/sharing-rules.ts @@ -1,12 +1,12 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { SharingRule } from '@objectstack/spec'; +import type { SharingRuleInput } from '@objectstack/spec/security'; /** * Criteria-based sharing: share high-value opportunities (amount > 100000) * with the Sales Manager role so managers always have read access to big deals. */ -export const HighValueOpportunitySharingRule: SharingRule = { +export const HighValueOpportunitySharingRule: SharingRuleInput = { type: 'criteria', name: 'share_high_value_opps_with_managers', label: 'High-Value Deals → Sales Managers', @@ -25,7 +25,7 @@ export const HighValueOpportunitySharingRule: SharingRule = { * Owner-based sharing: leads owned by a Sales Rep are shared read-only * with their manager so managers can coach on individual pipelines. */ -export const RepLeadSharingRule: SharingRule = { +export const RepLeadSharingRule: SharingRuleInput = { type: 'owner', name: 'share_rep_leads_with_manager', label: "Rep's Leads → Manager (read-only)", @@ -47,7 +47,7 @@ export const RepLeadSharingRule: SharingRule = { * Criteria-based: share activities linked to won deals with the whole * Sales team so everyone can learn from successful engagement patterns. */ -export const WonDealActivitySharingRule: SharingRule = { +export const WonDealActivitySharingRule: SharingRuleInput = { type: 'criteria', name: 'share_won_deal_activities', label: 'Won-Deal Activities → All Sales', diff --git a/examples/app-crm/src/themes/crm.theme.ts b/examples/app-crm/src/themes/crm.theme.ts index 89dba3ac2f..925408fbba 100644 --- a/examples/app-crm/src/themes/crm.theme.ts +++ b/examples/app-crm/src/themes/crm.theme.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Theme } from '@objectstack/spec'; +import type { Theme } from '@objectstack/spec/ui'; /** * Default CRM brand theme — light mode with professional blue palette. diff --git a/examples/app-crm/src/translations/crm.translation.ts b/examples/app-crm/src/translations/crm.translation.ts index 3deb922151..6326f6447e 100644 --- a/examples/app-crm/src/translations/crm.translation.ts +++ b/examples/app-crm/src/translations/crm.translation.ts @@ -1,6 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { TranslationBundle } from '@objectstack/spec'; +import type { TranslationBundle } from '@objectstack/spec/system'; /** * CRM translation bundle — English + Simplified Chinese. diff --git a/examples/app-crm/src/webhooks/crm-webhooks.ts b/examples/app-crm/src/webhooks/crm-webhooks.ts index df5b5988e3..0499a8ef6b 100644 --- a/examples/app-crm/src/webhooks/crm-webhooks.ts +++ b/examples/app-crm/src/webhooks/crm-webhooks.ts @@ -1,11 +1,11 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. -import type { Webhook } from '@objectstack/spec'; +import type { WebhookInput } from '@objectstack/spec/automation'; /** * Notify external CRM bus whenever an opportunity is created or updated. */ -export const OpportunityChangedWebhook: Webhook = { +export const OpportunityChangedWebhook: WebhookInput = { name: 'crm_opportunity_changed', label: 'Opportunity Created / Updated', object: 'crm_opportunity', @@ -37,7 +37,7 @@ export const OpportunityChangedWebhook: Webhook = { /** * Notify Slack channel when a deal is won. */ -export const DealWonSlackWebhook: Webhook = { +export const DealWonSlackWebhook: WebhookInput = { name: 'crm_deal_won_slack', label: 'Deal Won → Slack', object: 'crm_opportunity', diff --git a/examples/app-todo/package.json b/examples/app-todo/package.json index 10727083ff..c9961e939b 100644 --- a/examples/app-todo/package.json +++ b/examples/app-todo/package.json @@ -40,6 +40,7 @@ "@objectstack/cli": "workspace:*", "ai": "^6.0.205", "tsx": "^4.22.4", - "typescript": "^6.0.3" + "typescript": "^6.0.3", + "vitest": "^4.1.9" } } diff --git a/examples/app-todo/src/objects/task.hook.ts b/examples/app-todo/src/objects/task.hook.ts index 9baee48f2d..781eb3e519 100644 --- a/examples/app-todo/src/objects/task.hook.ts +++ b/examples/app-todo/src/objects/task.hook.ts @@ -18,7 +18,7 @@ const taskHook: Hook = { input.status = 'not_started'; } // Validation - if (input.subject && input.subject.includes('spam')) { + if (typeof input.subject === 'string' && input.subject.includes('spam')) { throw new Error('Spam tasks are not allowed'); } } diff --git a/examples/app-todo/src/objects/task.object.ts b/examples/app-todo/src/objects/task.object.ts index 8f38592aea..012fa89fd8 100644 --- a/examples/app-todo/src/objects/task.object.ts +++ b/examples/app-todo/src/objects/task.object.ts @@ -157,8 +157,6 @@ export const Task = ObjectSchema.create({ category_color: Field.color({ label: 'Category Color', - colorFormat: 'hex', - presetColors: ['#EF4444', '#F59E0B', '#10B981', '#3B82F6', '#8B5CF6'], }), }, diff --git a/packages/spec/src/automation/webhook.zod.ts b/packages/spec/src/automation/webhook.zod.ts index aa5fbd3ef9..d7681ac398 100644 --- a/packages/spec/src/automation/webhook.zod.ts +++ b/packages/spec/src/automation/webhook.zod.ts @@ -141,4 +141,6 @@ export const WebhookReceiverSchema = lazySchema(() => z.object({ })); export type Webhook = z.infer; +/** Authoring input for {@link Webhook} — defaulted fields are optional. */ +export type WebhookInput = z.input; export type WebhookReceiver = z.infer; diff --git a/packages/spec/src/data/datasource.zod.ts b/packages/spec/src/data/datasource.zod.ts index ee5c592285..899127c886 100644 --- a/packages/spec/src/data/datasource.zod.ts +++ b/packages/spec/src/data/datasource.zod.ts @@ -257,4 +257,6 @@ export const DatasourceSchema = lazySchema(() => z.object({ })); export type Datasource = z.infer; +/** Authoring input for {@link Datasource} — defaulted fields are optional. */ +export type DatasourceInput = z.input; export type DatasourceCapabilitiesType = z.infer; diff --git a/packages/spec/src/data/object.zod.ts b/packages/spec/src/data/object.zod.ts index a36a1f23e6..1a88cb83d3 100644 --- a/packages/spec/src/data/object.zod.ts +++ b/packages/spec/src/data/object.zod.ts @@ -999,3 +999,5 @@ export const ObjectExtensionSchema = lazySchema(() => z.object({ })); export type ObjectExtension = z.infer; +/** Authoring input for {@link ObjectExtension} — defaulted fields are optional. */ +export type ObjectExtensionInput = z.input; diff --git a/packages/spec/src/identity/role.zod.ts b/packages/spec/src/identity/role.zod.ts index 69e01facc3..2d481eb609 100644 --- a/packages/spec/src/identity/role.zod.ts +++ b/packages/spec/src/identity/role.zod.ts @@ -43,3 +43,5 @@ export const RoleSchema = lazySchema(() => z.object({ })); export type Role = z.infer; +/** Authoring input for {@link Role} — defaulted fields are optional. */ +export type RoleInput = z.input; diff --git a/packages/spec/src/integration/connector.zod.ts b/packages/spec/src/integration/connector.zod.ts index f5b6bcd414..8a33979d1f 100644 --- a/packages/spec/src/integration/connector.zod.ts +++ b/packages/spec/src/integration/connector.zod.ts @@ -628,3 +628,5 @@ export const ConnectorSchema = lazySchema(() => z.object({ })); export type Connector = z.infer; +/** Authoring input for {@link Connector} — defaulted fields are optional. */ +export type ConnectorInput = z.input; diff --git a/packages/spec/src/security/permission.zod.ts b/packages/spec/src/security/permission.zod.ts index df2b7340f3..059f158021 100644 --- a/packages/spec/src/security/permission.zod.ts +++ b/packages/spec/src/security/permission.zod.ts @@ -172,5 +172,7 @@ export const PermissionSetSchema = lazySchema(() => z.object({ })); export type PermissionSet = z.infer; +/** Authoring input for {@link PermissionSet} — defaulted fields are optional. */ +export type PermissionSetInput = z.input; export type ObjectPermission = z.infer; export type FieldPermission = z.infer; diff --git a/packages/spec/src/security/sharing.zod.ts b/packages/spec/src/security/sharing.zod.ts index 688d21b191..291158f026 100644 --- a/packages/spec/src/security/sharing.zod.ts +++ b/packages/spec/src/security/sharing.zod.ts @@ -108,5 +108,7 @@ export const SharingRuleSchema = lazySchema(() => z.discriminatedUnion('type', [ ])); export type SharingRule = z.infer; +/** Authoring input for {@link SharingRule} — defaulted fields are optional. */ +export type SharingRuleInput = z.input; export type CriteriaSharingRule = z.infer; export type OwnerSharingRule = z.infer; diff --git a/packages/spec/src/system/email-template.zod.ts b/packages/spec/src/system/email-template.zod.ts index 7577a4f5ce..65dd0fe183 100644 --- a/packages/spec/src/system/email-template.zod.ts +++ b/packages/spec/src/system/email-template.zod.ts @@ -133,3 +133,5 @@ function EmailAddressInlineSchema() { } export type EmailTemplateDefinition = z.infer; +/** Authoring input for {@link EmailTemplateDefinition} — defaulted fields are optional. */ +export type EmailTemplateDefinitionInput = z.input; diff --git a/packages/spec/src/system/job.zod.ts b/packages/spec/src/system/job.zod.ts index 9a4a30aef5..52053b745d 100644 --- a/packages/spec/src/system/job.zod.ts +++ b/packages/spec/src/system/job.zod.ts @@ -93,6 +93,8 @@ export const JobSchema = lazySchema(() => z.object({ })); export type Job = z.infer; +/** Authoring input for {@link Job} — defaulted fields are optional. */ +export type JobInput = z.input; /** * Type-safe factory for declaring background jobs in metadata-as-code. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dafa4d8b66..7607fa3425 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,6 +192,9 @@ importers: typescript: specifier: ^6.0.3 version: 6.0.3 + vitest: + specifier: ^4.1.9 + version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.9)(happy-dom@20.10.2)(msw@2.14.6(@types/node@25.9.3)(typescript@6.0.3))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) packages/adapters/express: dependencies: