mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
* fix(deploy): honour target for Cloudflare Pages branch and URL selection (#4483) - deployToCloudflarePages: add optional target ('preview'|'production', default 'production') - Branch derivation: preview→'preview', production/omitted→'main' - URL selection: preview uses per-deploy alias; production uses production root - routes/deploy.ts: read target from request body (default 'production'), pass to deployToCloudflarePages, persist actual target (not hardcoded 'preview') - db.ts normalizeDeployment: read target from DB row instead of hardcoding 'preview' - contracts: widen target fields to 'preview'|'production'; add target to DeployProjectFileRequest * test(deploy): type FormData branch capture as string | undefined (#4483) The Phase-1 branch-capture objects were typed `{ branch?: string }` but assigned `string | undefined`, which fails `tsc` under `exactOptionalPropertyTypes`. Type the field as `branch: string | undefined` so the daemon typecheck gate passes; assertions are unchanged. * fix(deploy): reject invalid deploy target with HTTP 400 (#4576) The deploy route coerced any non-'preview' target to 'production', so a malformed value (typo, empty string, wrong case) silently published to the production Cloudflare branch instead of a gated preview. Validate the supplied target up front and return 400 for anything outside preview|production; an omitted target still defaults to production (non-breaking). Addresses review feedback on #4576 / #4483. * feat(deploy): add `od deploy` CLI subcommand with --target (#4483) Land the CLI surface for the preview/production deploy capability so it is not API-only. `od deploy <projectId> --file <name> [--target preview| production] [--provider vercel-self|cloudflare-pages] [--cf-zone-id] [--cf-zone-name] [--cf-domain-prefix] [--json] [--daemon-url]` POSTs to the same `/api/projects/:id/deploy` endpoint the web UI uses, with local validation of `--target` before any request (omitted target = no key, server defaults to production). Addresses the surface-closure review feedback on #4576 by shipping the embeddability (CLI) surface alongside the API contract. The human web-UI preview/production selector remains tracked as a follow-up in #4577. Tests: apps/daemon/tests/cli-deploy.test.ts (11 cases, written test-first). * feat(deploy): add web UI target selector for Cloudflare Pages deploys Closes the web-UI surface gap PerishCode flagged on #4576: deploy target (preview/production) had HTTP + od CLI support but no way to choose it from the deploy modal. Adds a target <select> to the Cloudflare Pages deploy panel, defaulted to Preview, threaded through deployProjectFile's new optional target argument and forwarded in the deploy POST body. References #4576. * fix(deploy): reject vercel-self target=production instead of silently deploying preview POST /api/projects/:id/deploy resolved the requested target but only threaded it into deployToCloudflarePages(); deployToVercel() never received it and always behaved as preview. A caller explicitly requesting target=production against the Vercel provider was silently deployed as preview with no error (Codex P2 finding on PR #4576). Real Vercel production-target support is out of scope for this PR, so reject the explicit request with 400 BAD_REQUEST instead. The guard gates on the raw requested value, not the resolved target, so an omitted target (which defaults to 'production' for Cloudflare Pages parity) keeps deploying Vercel as preview exactly as before. * fix(web): default Cloudflare Pages deploy target to production The deploy target selector defaulted to 'preview', both in its initial useState and when syncing from the (currently placeholder, always-'preview') GET /api/deploy/config response. A user who opened the Cloudflare Pages deploy modal and clicked Deploy without touching the selector silently deployed to preview instead of production, contradicting the daemon's documented default for an omitted target and pre-PR behavior. Default both sites to 'production'; explicit user selection of either target is untouched. FileViewer.deploy-target.test.tsx covers the default and both explicit selections. Fixes #4483
651 lines
20 KiB
TypeScript
651 lines
20 KiB
TypeScript
import type { ChatMessage, ChatRunStatus, ChatSessionMode } from './chat.js';
|
|
import type { OrchestratorWorkspace } from './workspaces.js';
|
|
import type {
|
|
ProjectContextConnectorRef,
|
|
ProjectContextMcpServerRef,
|
|
ProjectContextPluginRef,
|
|
} from './context.js';
|
|
|
|
export type ProjectKind =
|
|
| 'prototype'
|
|
| 'deck'
|
|
| 'template'
|
|
| 'other'
|
|
| 'brand'
|
|
| 'image'
|
|
| 'video'
|
|
| 'audio';
|
|
|
|
export type MediaAspect = '1:1' | '16:9' | '9:16' | '4:3' | '3:4';
|
|
|
|
export type ProjectPlatform =
|
|
| 'auto'
|
|
| 'responsive'
|
|
| 'web-desktop'
|
|
| 'mobile-ios'
|
|
| 'mobile-android'
|
|
| 'tablet'
|
|
| 'desktop-app';
|
|
|
|
export type AudioKind = 'music' | 'speech' | 'sfx';
|
|
|
|
export type ProjectDisplayStatus =
|
|
| 'not_started'
|
|
| 'queued'
|
|
| 'running'
|
|
| 'awaiting_input'
|
|
| 'succeeded'
|
|
// Terminal-but-not-really-done: the latest run stamped `succeeded` yet ended
|
|
// with unfinished declared work (a non-`completed` TodoWrite task, or a
|
|
// max_tokens truncation). Kept distinct from `succeeded` so the project pill
|
|
// never reads "Completed" for a run whose work is not actually finished
|
|
// (#1247 / #1060).
|
|
| 'incomplete'
|
|
| 'failed'
|
|
| 'canceled';
|
|
|
|
export interface ProjectStatusInfo {
|
|
value: ProjectDisplayStatus;
|
|
updatedAt?: number;
|
|
runId?: string;
|
|
}
|
|
|
|
export interface PromptTemplateMetadataSource {
|
|
repo: string;
|
|
license: string;
|
|
author?: string;
|
|
url?: string;
|
|
}
|
|
|
|
// Subset of a curated PromptTemplate kept on the project so the agent can
|
|
// reference it on every turn without re-reading the gallery file. The
|
|
// `prompt` field is the (possibly user-edited) body — when the user tunes
|
|
// it in the New Project panel before clicking Create, those edits land
|
|
// here and become authoritative for the system prompt.
|
|
export interface PromptTemplateMetadata {
|
|
id: string;
|
|
surface: 'image' | 'video';
|
|
title: string;
|
|
prompt: string;
|
|
summary?: string;
|
|
category?: string;
|
|
tags?: string[];
|
|
model?: string;
|
|
aspect?: MediaAspect;
|
|
source?: PromptTemplateMetadataSource;
|
|
}
|
|
|
|
export type DesignSystemReviewDecision = 'looks-good' | 'needs-work';
|
|
|
|
export type DesignSystemReviewTaskStatus = 'queued' | 'sent' | 'failed';
|
|
|
|
export interface DesignSystemReviewAgentTask {
|
|
status: DesignSystemReviewTaskStatus;
|
|
prompt: string;
|
|
queuedAt: string;
|
|
sentAt?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export interface DesignSystemReviewEntry {
|
|
decision: DesignSystemReviewDecision;
|
|
updatedAt: string;
|
|
feedback?: string;
|
|
files?: string[];
|
|
agentTask?: DesignSystemReviewAgentTask;
|
|
}
|
|
|
|
export interface ProjectMetadata {
|
|
kind: ProjectKind;
|
|
// `live-artifact`: the data-backed live dashboard flow (drives the
|
|
// live-artifact skill/system-prompt path). `web-clone`: website reproduction
|
|
// projects from the Home `Website clone` card — stored as prototypes so they
|
|
// keep prototype preview behavior, but the intent routes the `example-web-clone`
|
|
// scenario plugin and splits them into their own `web_clone` analytics kind.
|
|
// `document`: resume/report/PDF projects from the Home `document` card — an
|
|
// analytics-only discriminator (no product behavior keys off it) so a created
|
|
// `other`-kind project reports `project_kind: 'document'` instead of generic
|
|
// `other`. `webgl-experience` and `worker-visualizer`: the powered-preview
|
|
// GPU / off-main-thread scenario cards — analytics-only discriminators for the
|
|
// powered-artifact chips.
|
|
intent?: 'live-artifact' | 'web-clone' | 'document' | 'webgl-experience' | 'worker-visualizer';
|
|
fidelity?: 'wireframe' | 'high-fidelity';
|
|
speakerNotes?: boolean;
|
|
slideCount?: string;
|
|
animations?: boolean;
|
|
includeLandingPage?: boolean;
|
|
includeOsWidgets?: boolean;
|
|
templateId?: string;
|
|
templateLabel?: string;
|
|
// Template/gallery duplication provenance. Unlike examplePrompt, this path
|
|
// creates a project by copying existing files and does not launch an agent.
|
|
duplicatedFromPluginId?: string;
|
|
duplicatedFromPluginEntry?: string;
|
|
/** Primary target surface selected at project creation. */
|
|
platform?: ProjectPlatform;
|
|
// Tracks whether the visible name was typed by the user or generated by
|
|
// the create flow. First-prompt auto-naming may only replace generated
|
|
// names so named imports/templates stay stable across conversations.
|
|
nameSource?: 'generated' | 'prompt' | 'agent' | 'user';
|
|
/** Concrete delivery surfaces the artifact must account for. `responsive` is a web breakpoint target, not a native app expansion. */
|
|
platformTargets?: ProjectPlatform[];
|
|
inspirationDesignSystemIds?: string[];
|
|
importedFrom?: 'claude-design' | 'folder' | string;
|
|
entryFile?: string;
|
|
sourceFileName?: string;
|
|
// Folder-import (#597): when set, the project's files live under this
|
|
// absolute path instead of .od/projects/<id>/. OD reads and writes
|
|
// directly inside the user's folder. Stored as the realpath() result so
|
|
// symlinks can't redirect writes after import time.
|
|
baseDir?: string;
|
|
// Project library location that owns baseDir when the project was created
|
|
// under a configured project location root.
|
|
projectLocationId?: string;
|
|
// PR #974: marker stamped by the daemon's HMAC-gated import handler
|
|
// when a folder import passed the desktop-main-process trust gate.
|
|
// Only set on folder-imported projects (`baseDir` set) and only when
|
|
// the import request carried a valid `X-OD-Desktop-Import-Token`
|
|
// signed with the secret the desktop main process registered with the
|
|
// daemon at startup. The desktop `shell.openPath` IPC refuses to
|
|
// forward folder-imported projects whose metadata lacks this marker,
|
|
// so a renderer cannot launder an attacker-chosen baseDir into a
|
|
// file-manager reveal even if a future codepath inadvertently lets
|
|
// it set `baseDir` outside the trusted flow. Privileged: rejected
|
|
// by `POST /api/projects` and `PATCH /api/projects/:id`.
|
|
fromTrustedPicker?: true;
|
|
// Externally prepared scratch workspace provenance. OD may read/write
|
|
// metadata.baseDir, but source authority and writeback stay outside OD.
|
|
orchestratorWorkspace?: OrchestratorWorkspace;
|
|
// Hint stamped by the Home composer working-directory chip. It records
|
|
// where the user wanted the project to live without granting write access
|
|
// to that path; actual filesystem roots still use baseDir/import flows.
|
|
userWorkingDir?: string;
|
|
imageModel?: string;
|
|
imageAspect?: MediaAspect;
|
|
imageStyle?: string;
|
|
videoModel?: string;
|
|
videoLength?: number;
|
|
videoAspect?: MediaAspect;
|
|
audioKind?: AudioKind;
|
|
audioModel?: string;
|
|
audioDuration?: number;
|
|
voice?: string;
|
|
// Curated prompt template the user picked in the image/video tab of the
|
|
// New Project panel. Treated by the system-prompt composer as a stylistic
|
|
// and structural reference for the generation request.
|
|
promptTemplate?: PromptTemplateMetadata;
|
|
// Absolute paths to local code folders the agent can read via --add-dir.
|
|
linkedDirs?: string[];
|
|
// Batch/API-created projects can opt out of the initial discovery form so
|
|
// the first agent turn builds immediately from the submitted brief.
|
|
skipDiscoveryBrief?: boolean;
|
|
// Set when the user submits an unmodified curated example prompt from the
|
|
// gallery. Skips discovery AND requests full-quality direct generation,
|
|
// treating the curated title/brief as the complete creative brief. Honored
|
|
// by both the daemon and contracts (API/BYOK) system-prompt composers so the
|
|
// feature is not mode-dependent.
|
|
examplePrompt?: boolean;
|
|
examplePromptTitle?: string;
|
|
examplePromptBrief?: Record<string, string>;
|
|
// Plugins selected through @ mentions on Home. These are additive
|
|
// context references; the explicit "Use plugin" snapshot, when present,
|
|
// remains the primary executable plugin for the run.
|
|
contextPlugins?: ProjectContextPluginRef[];
|
|
contextMcpServers?: ProjectContextMcpServerRef[];
|
|
contextConnectors?: ProjectContextConnectorRef[];
|
|
// Stored on design-system projects so the review overview can remember
|
|
// which generated sections were accepted or sent back for another pass.
|
|
designSystemReview?: Record<string, DesignSystemReviewEntry>;
|
|
// Stored on brand extraction projects so the Brands library, project list,
|
|
// and design-system picker can all point back to the same source kit.
|
|
brandId?: string;
|
|
brandSourceUrl?: string;
|
|
brandDesignSystemId?: string;
|
|
// Stored on design-system projects created from an existing project so the
|
|
// generated workspace can point back to the source evidence it duplicated.
|
|
sourceProjectId?: string;
|
|
sourceProjectName?: string;
|
|
// AI-optimize (deep enrichment) state for a programmatically-extracted DS.
|
|
// `programmatic` (or unset) = fast pass only; `ai_refined` = a user-triggered
|
|
// enrichment run completed successfully. Lets analytics compare the two
|
|
// cohorts' retention/usage (tracking spec C15 / §6).
|
|
enrichmentStatus?: 'programmatic' | 'ai_refined';
|
|
enrichmentCompletedAt?: number;
|
|
}
|
|
|
|
export interface Project {
|
|
id: string;
|
|
name: string;
|
|
skillId: string | null;
|
|
designSystemId: string | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
status?: ProjectStatusInfo;
|
|
pendingPrompt?: string;
|
|
metadata?: ProjectMetadata;
|
|
// Plan §3.A1 / spec §11.5 — set when the project was created with a
|
|
// plugin pinned (e.g. via PluginLoopHome on the web entry). Lets the
|
|
// UI hide the in-composer plugin rail and render the active plugin
|
|
// as context on user messages instead of re-prompting the user to
|
|
// pick a plugin they already selected.
|
|
appliedPluginSnapshotId?: string;
|
|
customInstructions?: string;
|
|
}
|
|
|
|
export interface ProjectTemplate {
|
|
id: string;
|
|
name: string;
|
|
sourceProjectId?: string;
|
|
files: Array<{ name: string; content: string }>;
|
|
description?: string;
|
|
createdAt: number;
|
|
}
|
|
|
|
export interface ProjectBrowserWorkspaceTab {
|
|
id: string;
|
|
insertAfter?: string | null;
|
|
label: string;
|
|
title?: string;
|
|
url?: string;
|
|
iconUrl?: string;
|
|
}
|
|
|
|
export interface ProjectTabsState {
|
|
tabs: string[];
|
|
active: string | null;
|
|
browserTabs?: ProjectBrowserWorkspaceTab[];
|
|
hasSavedState?: boolean;
|
|
updatedAt?: number;
|
|
}
|
|
|
|
export interface Conversation {
|
|
id: string;
|
|
projectId: string;
|
|
title: string | null;
|
|
sessionMode?: ChatSessionMode;
|
|
messageCount?: number;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
totalDurationMs?: number;
|
|
latestRun?: {
|
|
status: ChatRunStatus;
|
|
startedAt?: number;
|
|
endedAt?: number;
|
|
durationMs?: number;
|
|
};
|
|
}
|
|
|
|
export interface CreateProjectRequest {
|
|
name: string;
|
|
/** Optional project library location id. Omit or use `default` for .od/projects. */
|
|
projectLocationId?: string;
|
|
skillId?: string | null;
|
|
designSystemId?: string | null;
|
|
pendingPrompt?: string;
|
|
metadata?: ProjectMetadata;
|
|
pluginId?: string;
|
|
appliedPluginSnapshotId?: string;
|
|
pluginInputs?: Record<string, unknown>;
|
|
/** Session mode for the default conversation seeded with the project. */
|
|
conversationMode?: ChatSessionMode;
|
|
customInstructions?: string;
|
|
/** Persisted to metadata.skipDiscoveryBrief for automated project runs. */
|
|
skipDiscoveryBrief?: boolean;
|
|
}
|
|
|
|
export interface UpdateProjectRequest {
|
|
name?: string;
|
|
skillId?: string | null;
|
|
designSystemId?: string | null;
|
|
pendingPrompt?: string | null;
|
|
metadata?: ProjectMetadata | null;
|
|
customInstructions?: string | null;
|
|
}
|
|
|
|
export interface ProjectsResponse {
|
|
projects: Project[];
|
|
}
|
|
|
|
export interface ProjectResponse {
|
|
project: Project;
|
|
}
|
|
|
|
// Response body for `GET /api/projects/:id`. Carries the same `project`
|
|
// payload as `ProjectResponse` plus a derived `resolvedDir` so the web
|
|
// client can address the on-disk working directory directly (e.g. for
|
|
// `shell.openPath` from the desktop bridge). For folder-imported projects
|
|
// `resolvedDir === metadata.baseDir`; for native projects it is
|
|
// `path.join(<daemon projects root>, project.id)`. Computed server-side via
|
|
// `resolveProjectDir(...)` so the web client never reconstructs the path.
|
|
export interface ProjectDetailResponse extends ProjectResponse {
|
|
resolvedDir: string;
|
|
}
|
|
|
|
export interface CreateProjectResponse extends ProjectResponse {
|
|
conversationId?: string;
|
|
appliedPluginSnapshotId?: string;
|
|
}
|
|
|
|
export interface CreateDesignSystemProjectFromProjectRequest {
|
|
name?: string;
|
|
pendingPrompt?: string;
|
|
}
|
|
|
|
export interface CreateDesignSystemProjectFromProjectResponse extends ProjectResponse {
|
|
conversationId: string;
|
|
designSystemId: string;
|
|
copiedFiles: string[];
|
|
}
|
|
|
|
export interface DuplicateProjectRequest {
|
|
name?: string;
|
|
}
|
|
|
|
export interface DuplicateProjectResponse extends ProjectResponse {
|
|
conversationId: string;
|
|
copiedFiles: string[];
|
|
}
|
|
|
|
export interface ProjectLocation {
|
|
id: string;
|
|
name: string;
|
|
path: string;
|
|
builtIn?: boolean;
|
|
}
|
|
|
|
export interface ProjectLocationsResponse {
|
|
locations: ProjectLocation[];
|
|
removedProjectIds?: string[];
|
|
}
|
|
|
|
export interface UpdateProjectLocationsRequest {
|
|
locations: Array<{ id?: string; name?: string; path: string }>;
|
|
}
|
|
|
|
export interface ProjectManifest {
|
|
schemaVersion: 1;
|
|
id: string;
|
|
name: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
skillId?: string | null;
|
|
designSystemId?: string | null;
|
|
}
|
|
|
|
export interface ScanProjectLocationsResponse {
|
|
scanned: number;
|
|
imported: Project[];
|
|
existing: string[];
|
|
skipped: Array<{ path: string; reason: string }>;
|
|
}
|
|
|
|
// POST /api/import/folder — create a project rooted at an existing local
|
|
// folder. The submitted baseDir is stored as the project's metadata.baseDir
|
|
// (after realpath canonicalization) and OD reads/writes directly inside it.
|
|
// The user owns version control; OD does not snapshot or copy.
|
|
export interface ImportFolderRequest {
|
|
baseDir: string;
|
|
name?: string;
|
|
skillId?: string | null;
|
|
designSystemId?: string | null;
|
|
orchestratorWorkspace?: OrchestratorWorkspace;
|
|
}
|
|
|
|
export interface ImportFolderResponse {
|
|
project: Project;
|
|
conversationId: string;
|
|
entryFile: string | null;
|
|
}
|
|
|
|
export interface ReplaceProjectWorkingDirRequest {
|
|
baseDir: string;
|
|
orchestratorWorkspace?: OrchestratorWorkspace;
|
|
}
|
|
|
|
export interface ReplaceProjectWorkingDirResponse {
|
|
project: Project;
|
|
baseDir: string;
|
|
entryFile: string | null;
|
|
}
|
|
|
|
export interface ConversationsResponse {
|
|
conversations: Conversation[];
|
|
}
|
|
|
|
export interface ConversationResponse {
|
|
conversation: Conversation;
|
|
}
|
|
|
|
export interface CreateConversationRequest {
|
|
title?: string | null;
|
|
sessionMode?: ChatSessionMode;
|
|
/**
|
|
* Seed the new conversation with another conversation's context by copying
|
|
* its messages. The source must belong to the same project; a missing or
|
|
* foreign id is ignored and an empty conversation is created. Powers the
|
|
* "Side Chat" launcher, which forks the current chat's context into a new
|
|
* conversation.
|
|
*/
|
|
seedFromConversationId?: string | null;
|
|
/**
|
|
* When paired with `seedFromConversationId`, copy only source messages up to
|
|
* and including this message. Used by the chat "Fork" action so the new
|
|
* conversation resumes from a specific assistant turn instead of inheriting
|
|
* future follow-ups from the source conversation.
|
|
*/
|
|
forkAfterMessageId?: string | null;
|
|
/**
|
|
* Client-supplied snapshot of the messages to seed the fork with, in order,
|
|
* up to and including the fork point. When present, the daemon copies these
|
|
* instead of reading the source conversation from the database by id. This
|
|
* makes "Fork" resilient to a fork point that was never persisted — e.g. an
|
|
* assistant turn whose run errored or had its connection reset before the
|
|
* message reached the database. Without it, such a fork would 404 on
|
|
* `forkAfterMessageId` and silently fail. When absent, the daemon falls back
|
|
* to copying from `seedFromConversationId` (the original Side Chat path).
|
|
*/
|
|
seedMessages?: ChatMessage[];
|
|
}
|
|
|
|
export interface UpdateConversationRequest {
|
|
title?: string | null;
|
|
sessionMode?: ChatSessionMode;
|
|
}
|
|
|
|
export interface MessagesResponse {
|
|
messages: ChatMessage[];
|
|
}
|
|
|
|
export type DeployProviderId = 'vercel-self' | 'cloudflare-pages';
|
|
export type DeploymentStatus =
|
|
| 'deploying'
|
|
| 'preparing-link'
|
|
| 'ready'
|
|
| 'link-delayed'
|
|
| 'protected'
|
|
| 'failed';
|
|
|
|
export interface CloudflarePagesConfigHints {
|
|
lastZoneId?: string;
|
|
lastZoneName?: string;
|
|
lastDomainPrefix?: string;
|
|
}
|
|
|
|
export interface CloudflarePagesZoneInfo {
|
|
id: string;
|
|
name: string;
|
|
status?: string;
|
|
type?: string;
|
|
}
|
|
|
|
export interface CloudflarePagesZonesResponse {
|
|
zones: CloudflarePagesZoneInfo[];
|
|
cloudflarePages?: CloudflarePagesConfigHints;
|
|
}
|
|
|
|
export interface CloudflarePagesDeploySelection {
|
|
zoneId: string;
|
|
zoneName: string;
|
|
domainPrefix: string;
|
|
}
|
|
|
|
export type DeploymentLinkStatus =
|
|
| 'ready'
|
|
| 'link-delayed'
|
|
| 'protected'
|
|
| 'failed';
|
|
|
|
export interface DeploymentLinkInfo {
|
|
url: string;
|
|
status: DeploymentLinkStatus;
|
|
statusMessage?: string;
|
|
reachableAt?: number;
|
|
}
|
|
|
|
export type CloudflarePagesDnsStatus =
|
|
| 'skipped'
|
|
| 'created'
|
|
| 'reused'
|
|
| 'unmarked'
|
|
| 'patched'
|
|
| 'conflict'
|
|
| 'failed';
|
|
|
|
export type CloudflarePagesDomainStatus =
|
|
| 'skipped'
|
|
| 'pending'
|
|
| 'active'
|
|
| 'conflict'
|
|
| 'failed';
|
|
|
|
export type CloudflarePagesCustomDomainStatus =
|
|
| 'pending'
|
|
| 'ready'
|
|
| 'conflict'
|
|
| 'failed';
|
|
|
|
export type CloudflarePagesDnsOwnership = 'marked' | 'unmarked' | 'external';
|
|
|
|
export interface CloudflarePagesCustomDomainInfo {
|
|
hostname: string;
|
|
url: string;
|
|
zoneId: string;
|
|
zoneName: string;
|
|
domainPrefix: string;
|
|
status: CloudflarePagesCustomDomainStatus;
|
|
statusMessage?: string;
|
|
errorCode?: string;
|
|
errorMessage?: string;
|
|
dnsStatus?: CloudflarePagesDnsStatus;
|
|
dnsRecordId?: string;
|
|
dnsOwnership?: CloudflarePagesDnsOwnership;
|
|
domainStatus?: CloudflarePagesDomainStatus;
|
|
pagesDomainStatus?: string;
|
|
validationData?: unknown;
|
|
verificationData?: unknown;
|
|
}
|
|
|
|
export interface CloudflarePagesDeploymentInfo {
|
|
projectName: string;
|
|
pagesDev: DeploymentLinkInfo;
|
|
customDomain?: CloudflarePagesCustomDomainInfo;
|
|
}
|
|
|
|
export interface DeployConfigResponse {
|
|
providerId: DeployProviderId;
|
|
configured: boolean;
|
|
tokenMask: string;
|
|
teamId: string;
|
|
teamSlug: string;
|
|
accountId?: string;
|
|
projectName?: string;
|
|
cloudflarePages?: CloudflarePagesConfigHints;
|
|
target: 'preview' | 'production';
|
|
}
|
|
|
|
export interface UpdateDeployConfigRequest {
|
|
providerId?: DeployProviderId;
|
|
token?: string;
|
|
teamId?: string;
|
|
teamSlug?: string;
|
|
accountId?: string;
|
|
projectName?: string;
|
|
cloudflarePages?: CloudflarePagesConfigHints;
|
|
}
|
|
|
|
export interface DeploymentInfo {
|
|
id: string;
|
|
projectId: string;
|
|
fileName: string;
|
|
providerId: DeployProviderId;
|
|
url: string;
|
|
deploymentId?: string;
|
|
deploymentCount: number;
|
|
target: 'preview' | 'production';
|
|
status: DeploymentStatus;
|
|
statusMessage?: string;
|
|
reachableAt?: number;
|
|
cloudflarePages?: CloudflarePagesDeploymentInfo;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface ProjectDeploymentsResponse {
|
|
deployments: DeploymentInfo[];
|
|
}
|
|
|
|
export interface DeployProjectFileRequest {
|
|
fileName: string;
|
|
providerId?: DeployProviderId;
|
|
cloudflarePages?: CloudflarePagesDeploySelection;
|
|
target?: 'preview' | 'production';
|
|
}
|
|
|
|
export interface DeployProjectFileResponse extends DeploymentInfo {}
|
|
|
|
export interface CheckDeploymentLinkResponse extends DeploymentInfo {}
|
|
|
|
// Preflight inspects the file set that would be uploaded for a deploy
|
|
// without sending anything to the provider. Lets the UI show file count,
|
|
// total size, and warnings before the user pays the network round-trip.
|
|
|
|
export type DeployPreflightWarningCode =
|
|
| 'broken-reference'
|
|
| 'invalid-reference'
|
|
| 'large-asset'
|
|
| 'large-bundle'
|
|
| 'large-html'
|
|
| 'external-script'
|
|
| 'external-stylesheet'
|
|
| 'no-doctype'
|
|
| 'no-viewport';
|
|
|
|
export interface DeployPreflightWarning {
|
|
code: DeployPreflightWarningCode;
|
|
message: string;
|
|
path?: string;
|
|
url?: string;
|
|
size?: number;
|
|
}
|
|
|
|
export interface DeployPreflightFile {
|
|
path: string;
|
|
size: number;
|
|
mime: string;
|
|
sourcePath: string;
|
|
}
|
|
|
|
export interface DeployPreflightRequest {
|
|
fileName: string;
|
|
providerId?: DeployProviderId;
|
|
}
|
|
|
|
export interface DeployPreflightResponse {
|
|
providerId: DeployProviderId;
|
|
entry: string;
|
|
files: DeployPreflightFile[];
|
|
totalFiles: number;
|
|
totalBytes: number;
|
|
warnings: DeployPreflightWarning[];
|
|
}
|