@builder.io/ai-utils 0.64.0 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/ai-utils",
3
- "version": "0.64.0",
3
+ "version": "0.66.0",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
package/src/codegen.d.ts CHANGED
@@ -2,7 +2,8 @@ import { z } from "zod";
2
2
  import type { Options as PrettierOptions } from "prettier";
3
3
  import type { Attachment, ContentMessageItemToolResult } from "./messages";
4
4
  import type { BuilderContent } from "./completion";
5
- import type { ForcedBackup, SetupDependency, GitDiagnostics } from "./projects";
5
+ import { type EnvironmentVariable, type SetupDependency } from "./common-schemas";
6
+ import type { ForcedBackup, GitDiagnostics } from "./projects";
6
7
  import type { Feature } from "./features";
7
8
  import type { CpuKind, BranchType } from "./projects";
8
9
  export declare const GitSnapshotSchema: z.ZodString;
@@ -816,14 +817,6 @@ export declare const ExitToolInputSchema: z.ZodObject<{
816
817
  projectDescription: z.ZodOptional<z.ZodString>;
817
818
  }, z.core.$strip>;
818
819
  export type ExitToolInput = z.infer<typeof ExitToolInputSchema>;
819
- export declare const EnvironmentVariableSchema: z.ZodObject<{
820
- key: z.ZodString;
821
- value: z.ZodString;
822
- isSecret: z.ZodBoolean;
823
- placeholder: z.ZodOptional<z.ZodBoolean>;
824
- explanation: z.ZodOptional<z.ZodString>;
825
- }, z.core.$strip>;
826
- export type EnvironmentVariable = z.infer<typeof EnvironmentVariableSchema>;
827
820
  export declare const ProposedConfigSchema: z.ZodObject<{
828
821
  id: z.ZodString;
829
822
  projectId: z.ZodString;
package/src/codegen.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { AttachmentSchema, ContentMessageItemToolResultSchema, } from "./messages";
3
3
  import { UserContextSchema } from "./mapping";
4
- import { SetupDependencySchema } from "./projects";
4
+ import { EnvironmentVariableSchema, SetupDependencySchema, } from "./common-schemas";
5
5
  export const GitSnapshotSchema = z.string().meta({
6
6
  title: "GitSnapshot",
7
7
  description: "Multi-repo git snapshot. Format: 'folder:hash,folder:hash' " +
@@ -906,19 +906,6 @@ const ProposedQuestionSchema = z.object({
906
906
  .meta({ description: "Placeholder text for text-type questions" }),
907
907
  options: z.array(LabelOptionSchema).optional(),
908
908
  });
909
- export const EnvironmentVariableSchema = z
910
- .object({
911
- key: z.string(),
912
- value: z.string(),
913
- isSecret: z.boolean(),
914
- placeholder: z.boolean().optional().meta({
915
- description: "If true, indicates this is a placeholder value that needs user replacement",
916
- }),
917
- explanation: z.string().optional().meta({
918
- description: "Explanation of why this env var is needed and what value the user should provide",
919
- }),
920
- })
921
- .meta({ title: "EnvironmentVariable" });
922
909
  const ProposedConfigurationSchema = z.object({
923
910
  setupCommand: z.object({
924
911
  value: z.string().optional(),
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ export declare const EnvironmentVariableSchema: z.ZodObject<{
3
+ key: z.ZodString;
4
+ value: z.ZodString;
5
+ isSecret: z.ZodBoolean;
6
+ placeholder: z.ZodOptional<z.ZodBoolean>;
7
+ explanation: z.ZodOptional<z.ZodString>;
8
+ }, z.core.$strip>;
9
+ export type EnvironmentVariable = z.infer<typeof EnvironmentVariableSchema>;
10
+ export declare const SetupMiseDependencySchema: z.ZodObject<{
11
+ key: z.ZodString;
12
+ type: z.ZodLiteral<"mise">;
13
+ tool: z.ZodString;
14
+ version: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>;
16
+ export type SetupMiseDependency = z.infer<typeof SetupMiseDependencySchema>;
17
+ export declare const SetupScriptDependencySchema: z.ZodObject<{
18
+ key: z.ZodString;
19
+ type: z.ZodLiteral<"script">;
20
+ name: z.ZodString;
21
+ script: z.ZodString;
22
+ }, z.core.$strip>;
23
+ export type SetupScriptDependency = z.infer<typeof SetupScriptDependencySchema>;
24
+ export declare const SetupDependencySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
25
+ key: z.ZodString;
26
+ type: z.ZodLiteral<"mise">;
27
+ tool: z.ZodString;
28
+ version: z.ZodOptional<z.ZodString>;
29
+ }, z.core.$strip>, z.ZodObject<{
30
+ key: z.ZodString;
31
+ type: z.ZodLiteral<"script">;
32
+ name: z.ZodString;
33
+ script: z.ZodString;
34
+ }, z.core.$strip>], "type">;
35
+ export type SetupDependency = z.infer<typeof SetupDependencySchema>;
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ // ============================================================================
3
+ // Shared leaf schemas
4
+ //
5
+ // These schemas defined here to break runtime dependency cycle which would
6
+ // surface as "Cannot access '<Schema>' before initialization" depending on
7
+ // evaluation order. Keep this module dependency-free (zod only).
8
+ // ============================================================================
9
+ export const EnvironmentVariableSchema = z
10
+ .object({
11
+ key: z.string(),
12
+ value: z.string(),
13
+ isSecret: z.boolean(),
14
+ placeholder: z.boolean().optional().meta({
15
+ description: "If true, indicates this is a placeholder value that needs user replacement",
16
+ }),
17
+ explanation: z.string().optional().meta({
18
+ description: "Explanation of why this env var is needed and what value the user should provide",
19
+ }),
20
+ })
21
+ .meta({ title: "EnvironmentVariable" });
22
+ export const SetupMiseDependencySchema = z
23
+ .object({
24
+ key: z.string(),
25
+ type: z.literal("mise"),
26
+ tool: z.string(),
27
+ version: z.string().optional(),
28
+ })
29
+ .meta({ title: "SetupMiseDependency" });
30
+ export const SetupScriptDependencySchema = z
31
+ .object({
32
+ key: z.string(),
33
+ type: z.literal("script"),
34
+ name: z.string(),
35
+ script: z.string(),
36
+ })
37
+ .meta({ title: "SetupScriptDependency" });
38
+ export const SetupDependencySchema = z
39
+ .discriminatedUnion("type", [
40
+ SetupMiseDependencySchema,
41
+ SetupScriptDependencySchema,
42
+ ])
43
+ .meta({ title: "SetupDependency" });
@@ -6,6 +6,11 @@ export interface GenerateDesignSystemFormFields {
6
6
  * the uploaded `.fig` filenames.
7
7
  */
8
8
  projectName?: string;
9
+ /**
10
+ * Optional map of filename → page/frame GUIDs to restrict indexing.
11
+ * GUIDs are file-local, so they must be scoped per attachment.
12
+ */
13
+ selection?: Record<string, string[]>;
9
14
  }
10
15
  export interface GenerateDesignSystemRequest extends GenerateDesignSystemFormFields {
11
16
  /**
@@ -34,5 +39,6 @@ export declare const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 1;
34
39
  */
35
40
  export declare const generateDesignSystemBodySchema: z.ZodObject<{
36
41
  projectName: z.ZodOptional<z.ZodString>;
42
+ selection: z.ZodOptional<z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>>;
37
43
  }, z.core.$strip>;
38
44
  export type GenerateDesignSystemBody = z.infer<typeof generateDesignSystemBodySchema>;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- export const GENERATE_DESIGN_SYSTEM_MAX_FILE_BYTES = 100 * 1024 * 1024;
2
+ export const GENERATE_DESIGN_SYSTEM_MAX_FILE_BYTES = 200 * 1024 * 1024;
3
3
  export const GENERATE_DESIGN_SYSTEM_MAX_ATTACHMENTS = 50;
4
4
  export const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 1;
5
5
  /**
@@ -11,4 +11,19 @@ export const GENERATE_DESIGN_SYSTEM_MIN_ATTACHMENTS = 1;
11
11
  */
12
12
  export const generateDesignSystemBodySchema = z.object({
13
13
  projectName: z.string().trim().min(1).max(200).optional(),
14
+ selection: z
15
+ .preprocess((v) => {
16
+ if (typeof v !== "string")
17
+ return v;
18
+ const trimmed = v.trim();
19
+ if (!trimmed)
20
+ return undefined;
21
+ try {
22
+ return JSON.parse(trimmed);
23
+ }
24
+ catch (_a) {
25
+ return v;
26
+ }
27
+ }, z.record(z.string(), z.array(z.string().min(1)).max(10000)))
28
+ .optional(),
14
29
  });
package/src/events.d.ts CHANGED
@@ -804,6 +804,52 @@ export declare const ProjectSnapshotFailedV1: {
804
804
  eventName: "project.snapshot.failed";
805
805
  version: "1";
806
806
  };
807
+ /**
808
+ * Internal event used to poll whether a VolumeSnapshot has become ready
809
+ * without blocking a Pub/Sub handler for up to 10 minutes.
810
+ * The consumer (`handleSnapshotReadyCheckV1`) checks once, then either
811
+ * finalises (ready / timeout) or re-emits this event — each message
812
+ * completes in seconds.
813
+ */
814
+ export type ProjectSnapshotReadyCheckV1 = FusionEventVariant<"project.snapshot.ready.check", {
815
+ projectId: string;
816
+ triggerEventId: string;
817
+ snapshotName: string;
818
+ gitSha: string;
819
+ /** Pod start time — used to compute durationMs in ProjectSnapshotCreatedV1. */
820
+ startedAtMs: number;
821
+ /** When the VolumeSnapshot was created — used to compute the readiness timeout. */
822
+ capturedAtMs: number;
823
+ timeoutMs: number;
824
+ }, {
825
+ projectId: string;
826
+ }, 1>;
827
+ export declare const ProjectSnapshotReadyCheckV1: {
828
+ eventName: "project.snapshot.ready.check";
829
+ version: "1";
830
+ };
831
+ /**
832
+ * Internal event used to poll a snapshot pod's status without blocking a
833
+ * Pub/Sub handler for 45 minutes. The consumer (`handleSnapshotPodWatchV1`)
834
+ * checks the pod once, then either finalises the snapshot (terminal state) or
835
+ * re-emits this event (still running) — each message completes in seconds.
836
+ */
837
+ export type ProjectSnapshotPodWatchV1 = FusionEventVariant<"project.snapshot.pod.watch", {
838
+ projectId: string;
839
+ triggerEventId: string;
840
+ namespace: string;
841
+ podName: string;
842
+ source: "pr.merged" | "project.snapshot.refresh";
843
+ gitSha?: string;
844
+ startedAtMs: number;
845
+ timeoutMs: number;
846
+ }, {
847
+ projectId: string;
848
+ }, 1>;
849
+ export declare const ProjectSnapshotPodWatchV1: {
850
+ eventName: "project.snapshot.pod.watch";
851
+ version: "1";
852
+ };
807
853
  export type VideoRecordingCompletedV1 = FusionEventVariant<"video.recording.completed", {
808
854
  recordingId: string;
809
855
  videoUrl: string;
@@ -921,7 +967,7 @@ export declare const ClientDevtoolsToolResultV1: {
921
967
  eventName: "client.devtools.tool.result";
922
968
  version: "1";
923
969
  };
924
- export type FusionEvent = ClientDevtoolsSessionStartedEvent | ClientDevtoolsSessionIdleEventV1 | ClientDevtoolsToolCallRequestV1 | ClientDevtoolsToolCallV1 | ClientDevtoolsToolResultV1 | FusionProjectCreatedV1 | SetupAgentCompletedV1 | GitPrMergedV1 | GitPrCreatedV1 | GitPrClosedV1 | ForceSetupAgentV1 | ClawMessageSentV1 | CodegenCompletionV1 | CodegenUserPromptV1 | GitWebhooksRegisterV1 | FusionProjectSettingsUpdatedV1 | VideoRecordingCompletedV1 | TimelineRecordingReadyV1 | FusionBranchCreatedV1 | FusionContainerStartedV1 | FusionContainerFailedV1 | FusionBranchFailedV1 | BotMentionExternalPrV1 | ReviewSubmittedV1 | PrReviewRequestedV1 | ProjectSnapshotRefreshV1 | ProjectSnapshotCapturedV1 | ProjectSnapshotCreatedV1 | ProjectSnapshotFailedV1;
970
+ export type FusionEvent = ClientDevtoolsSessionStartedEvent | ClientDevtoolsSessionIdleEventV1 | ClientDevtoolsToolCallRequestV1 | ClientDevtoolsToolCallV1 | ClientDevtoolsToolResultV1 | FusionProjectCreatedV1 | SetupAgentCompletedV1 | GitPrMergedV1 | GitPrCreatedV1 | GitPrClosedV1 | ForceSetupAgentV1 | ClawMessageSentV1 | CodegenCompletionV1 | CodegenUserPromptV1 | GitWebhooksRegisterV1 | FusionProjectSettingsUpdatedV1 | VideoRecordingCompletedV1 | TimelineRecordingReadyV1 | FusionBranchCreatedV1 | FusionContainerStartedV1 | FusionContainerFailedV1 | FusionBranchFailedV1 | BotMentionExternalPrV1 | ReviewSubmittedV1 | PrReviewRequestedV1 | ProjectSnapshotRefreshV1 | ProjectSnapshotCapturedV1 | ProjectSnapshotCreatedV1 | ProjectSnapshotFailedV1 | ProjectSnapshotReadyCheckV1 | ProjectSnapshotPodWatchV1;
925
971
  export interface ModelPermissionRequiredEvent {
926
972
  type: "assistant.model.permission.required";
927
973
  data: {
package/src/events.js CHANGED
@@ -90,6 +90,14 @@ export const ProjectSnapshotFailedV1 = {
90
90
  eventName: "project.snapshot.failed",
91
91
  version: "1",
92
92
  };
93
+ export const ProjectSnapshotReadyCheckV1 = {
94
+ eventName: "project.snapshot.ready.check",
95
+ version: "1",
96
+ };
97
+ export const ProjectSnapshotPodWatchV1 = {
98
+ eventName: "project.snapshot.pod.watch",
99
+ version: "1",
100
+ };
93
101
  export const VideoRecordingCompletedV1 = {
94
102
  eventName: "video.recording.completed",
95
103
  version: "1",
package/src/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./events.js";
3
3
  export * from "./messages.js";
4
4
  export * from "./settings.js";
5
5
  export * from "./mapping.js";
6
+ export * from "./common-schemas.js";
6
7
  export * from "./codegen.js";
7
8
  export * from "./diff-hunks.js";
8
9
  export * from "./projects.js";
package/src/index.js CHANGED
@@ -3,6 +3,7 @@ export * from "./events.js";
3
3
  export * from "./messages.js";
4
4
  export * from "./settings.js";
5
5
  export * from "./mapping.js";
6
+ export * from "./common-schemas.js";
6
7
  export * from "./codegen.js";
7
8
  export * from "./diff-hunks.js";
8
9
  export * from "./projects.js";
@@ -1,4 +1,5 @@
1
- import type { EnvironmentVariable, PrivacyMode, ReviewEffort } from "./codegen";
1
+ import type { PrivacyMode, ReviewEffort } from "./codegen";
2
+ import type { EnvironmentVariable } from "./common-schemas";
2
3
  export interface GithubEnterpriseSetupValue {
3
4
  host: string;
4
5
  clientId: string;
package/src/projects.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ConnectivityErrorCode, CheckType, LikelyCause } from "./connectivity/types.js";
3
- import type { FileOverride, EnvironmentVariable, LaunchServerState, LaunchServerStatus, BranchBackup, CommitMode, CustomInstruction, CustomAgentDefinition, GitSnapshot, AutoPushMode, GenerateUserMessage, CodeGenToolMap, GenerateCompletionStep, ReviewEffort } from "./codegen";
3
+ import { type EnvironmentVariable, type SetupDependency } from "./common-schemas";
4
+ import type { FileOverride, LaunchServerState, LaunchServerStatus, BranchBackup, CommitMode, CustomInstruction, CustomAgentDefinition, GitSnapshot, AutoPushMode, GenerateUserMessage, CodeGenToolMap, GenerateCompletionStep, ReviewEffort } from "./codegen";
4
5
  import type { FallbackTokensPrivate } from "./organization";
5
6
  /**
6
7
  * Temporary type for date fields during migration.
@@ -328,32 +329,6 @@ export type ShutdownResponse = {
328
329
  export type ShutdownResponseSerialized = Omit<ShutdownResponse, "error"> & {
329
330
  error?: string;
330
331
  };
331
- export declare const SetupMiseDependencySchema: z.ZodObject<{
332
- key: z.ZodString;
333
- type: z.ZodLiteral<"mise">;
334
- tool: z.ZodString;
335
- version: z.ZodOptional<z.ZodString>;
336
- }, z.core.$strip>;
337
- export type SetupMiseDependency = z.infer<typeof SetupMiseDependencySchema>;
338
- export declare const SetupScriptDependencySchema: z.ZodObject<{
339
- key: z.ZodString;
340
- type: z.ZodLiteral<"script">;
341
- name: z.ZodString;
342
- script: z.ZodString;
343
- }, z.core.$strip>;
344
- export type SetupScriptDependency = z.infer<typeof SetupScriptDependencySchema>;
345
- export declare const SetupDependencySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
346
- key: z.ZodString;
347
- type: z.ZodLiteral<"mise">;
348
- tool: z.ZodString;
349
- version: z.ZodOptional<z.ZodString>;
350
- }, z.core.$strip>, z.ZodObject<{
351
- key: z.ZodString;
352
- type: z.ZodLiteral<"script">;
353
- name: z.ZodString;
354
- script: z.ZodString;
355
- }, z.core.$strip>], "type">;
356
- export type SetupDependency = z.infer<typeof SetupDependencySchema>;
357
332
  export type FusionExecutionEnvironment = "containerized" | "container-less" | "cloud" | "cloud-v2";
358
333
  export type AgentType = "setup-project" | "project-configuration" | "org-agent" | "code-review-orchestrator" | "design-system-indexer" | "builder-publish-integration";
359
334
  export interface PartialBranchData {
@@ -889,6 +864,8 @@ export interface Project {
889
864
  userInitiatedAutoSetup?: boolean;
890
865
  /** When true, automatically apply verified setup configuration when the setup agent completes */
891
866
  autoApplySetup?: boolean;
867
+ /** Settings related to Fusion fist class hosting */
868
+ hosting?: ProjectHosting;
892
869
  }
893
870
  /**
894
871
  * Get the state of a branch, checking `state` first and falling back to `deleted` for backwards compatibility.
@@ -1235,4 +1212,106 @@ export interface ShouldDeletePodResponse {
1235
1212
  reason: "branch_inactive" | "force_delete_flag" | "project_not_found" | "branch_not_found" | "ok" | "error";
1236
1213
  error?: string;
1237
1214
  }
1215
+ /**
1216
+ * Deploy lifecycle status:
1217
+ * - queued - inital state although we don't currently queue deploys per se
1218
+ * - building — deploy pod is running `npm run build`
1219
+ * - uploading — build succeeded; artifacts being uploaded to GCS (transient,
1220
+ * between `client.devtools.build.completed` and `client.devtools.build.uploaded`)
1221
+ * - deploying — queue handler is pushing artifacts to Netlify + updating Envoy HTTPRoute
1222
+ * - live — terminal: site is serving traffic
1223
+ * - failed — terminal: see `error` for the one-line reason
1224
+ */
1225
+ export declare const DeployStatusSchema: z.ZodEnum<{
1226
+ building: "building";
1227
+ deploying: "deploying";
1228
+ failed: "failed";
1229
+ live: "live";
1230
+ queued: "queued";
1231
+ uploading: "uploading";
1232
+ }>;
1233
+ export type DeployStatus = z.infer<typeof DeployStatusSchema>;
1234
+ export declare const ProjectHostingBuildConfigSchema: z.ZodObject<{
1235
+ buildCommand: z.ZodOptional<z.ZodString>;
1236
+ nodeVersion: z.ZodOptional<z.ZodString>;
1237
+ }, z.core.$strip>;
1238
+ export type ProjectHostingBuildConfig = z.infer<typeof ProjectHostingBuildConfigSchema>;
1239
+ /**
1240
+ * Hosting configuration for a project, stored at `projects/{projectId}.hosting`.
1241
+ */
1242
+ export declare const ProjectHostingSchema: z.ZodObject<{
1243
+ enabled: z.ZodOptional<z.ZodBoolean>;
1244
+ slug: z.ZodOptional<z.ZodString>;
1245
+ netlifySiteId: z.ZodOptional<z.ZodString>;
1246
+ netlifySiteName: z.ZodOptional<z.ZodString>;
1247
+ url: z.ZodOptional<z.ZodString>;
1248
+ buildConfig: z.ZodOptional<z.ZodObject<{
1249
+ buildCommand: z.ZodOptional<z.ZodString>;
1250
+ nodeVersion: z.ZodOptional<z.ZodString>;
1251
+ }, z.core.$strip>>;
1252
+ environment: z.ZodOptional<z.ZodArray<z.ZodObject<{
1253
+ key: z.ZodString;
1254
+ value: z.ZodString;
1255
+ isSecret: z.ZodBoolean;
1256
+ placeholder: z.ZodOptional<z.ZodBoolean>;
1257
+ explanation: z.ZodOptional<z.ZodString>;
1258
+ }, z.core.$strip>>>;
1259
+ lastDeployId: z.ZodOptional<z.ZodString>;
1260
+ lastDeployAt: z.ZodOptional<z.ZodNumber>;
1261
+ lastDeployStatus: z.ZodOptional<z.ZodEnum<{
1262
+ building: "building";
1263
+ deploying: "deploying";
1264
+ failed: "failed";
1265
+ live: "live";
1266
+ queued: "queued";
1267
+ uploading: "uploading";
1268
+ }>>;
1269
+ customDomain: z.ZodOptional<z.ZodString>;
1270
+ customDomainVerified: z.ZodOptional<z.ZodBoolean>;
1271
+ autoDeploy: z.ZodOptional<z.ZodBoolean>;
1272
+ }, z.core.$strip>;
1273
+ export type ProjectHosting = z.infer<typeof ProjectHostingSchema>;
1274
+ /**
1275
+ * A single deploy record, stored at `deploys/{deployId}`. The Deploy.id is the document key.
1276
+ */
1277
+ export declare const DeploySchema: z.ZodObject<{
1278
+ id: z.ZodString;
1279
+ projectId: z.ZodString;
1280
+ ownerId: z.ZodString;
1281
+ checkoutBranch: z.ZodOptional<z.ZodString>;
1282
+ deployBranchId: z.ZodOptional<z.ZodString>;
1283
+ status: z.ZodEnum<{
1284
+ building: "building";
1285
+ deploying: "deploying";
1286
+ failed: "failed";
1287
+ live: "live";
1288
+ queued: "queued";
1289
+ uploading: "uploading";
1290
+ }>;
1291
+ netlifyDeployId: z.ZodOptional<z.ZodString>;
1292
+ url: z.ZodOptional<z.ZodString>;
1293
+ error: z.ZodOptional<z.ZodString>;
1294
+ createdAt: z.ZodNumber;
1295
+ completedAt: z.ZodOptional<z.ZodNumber>;
1296
+ triggeredBy: z.ZodString;
1297
+ }, z.core.$strip>;
1298
+ export type Deploy = z.infer<typeof DeploySchema>;
1299
+ /**
1300
+ * Permanent slug reservation, stored at `hosting-slugs/{slug}` (slug is the document key).
1301
+ *
1302
+ * Created on first publish via the atomic Firestore transaction in
1303
+ * `POST /projects/hosting/reserve-slug`. Never deleted (URL hijacking protection).
1304
+ *
1305
+ * "Is this URL currently live?" is NOT a property of this doc. It's answered by the
1306
+ * presence of the per-slug `HTTPRoute` in Envoy Gateway (the source of truth for routing)
1307
+ * and/or by `project.hosting.netlifySiteId` (set on publish, cleared on unpublish). The
1308
+ * slug doc exists purely to enforce uniqueness and own the permanent reservation.
1309
+ */
1310
+ export declare const HostingSlugSchema: z.ZodObject<{
1311
+ projectId: z.ZodString;
1312
+ ownerId: z.ZodString;
1313
+ createdAt: z.ZodNumber;
1314
+ createdBy: z.ZodString;
1315
+ }, z.core.$strip>;
1316
+ export type HostingSlug = z.infer<typeof HostingSlugSchema>;
1238
1317
  export {};
package/src/projects.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { EnvironmentVariableSchema, } from "./common-schemas";
2
3
  /**
3
4
  * Detect git provider from a repository URL (HTTPS or SSH).
4
5
  * Used by both error diagnostics and connectivity checks for consistent provider labeling.
@@ -37,28 +38,6 @@ export const STARTER_REPO = "BuilderIO/fusion-starter";
37
38
  export const DSI_PREVIEW_REPO = "BuilderIO/dsi-starter";
38
39
  export const EXAMPLE_OR_STARTER_REPOS = [...EXAMPLE_REPOS, STARTER_REPO];
39
40
  export const EXAMPLE_OR_STARTER_REPOS_URLS = EXAMPLE_OR_STARTER_REPOS.map((repo) => `https://github.com/${repo}`);
40
- export const SetupMiseDependencySchema = z
41
- .object({
42
- key: z.string(),
43
- type: z.literal("mise"),
44
- tool: z.string(),
45
- version: z.string().optional(),
46
- })
47
- .meta({ title: "SetupMiseDependency" });
48
- export const SetupScriptDependencySchema = z
49
- .object({
50
- key: z.string(),
51
- type: z.literal("script"),
52
- name: z.string(),
53
- script: z.string(),
54
- })
55
- .meta({ title: "SetupScriptDependency" });
56
- export const SetupDependencySchema = z
57
- .discriminatedUnion("type", [
58
- SetupMiseDependencySchema,
59
- SetupScriptDependencySchema,
60
- ])
61
- .meta({ title: "SetupDependency" });
62
41
  export const checkIsNewBranch = (branch) => {
63
42
  return "projectId" in branch;
64
43
  };
@@ -185,3 +164,124 @@ export function parseExitPlanMode(chunk) {
185
164
  }
186
165
  return null;
187
166
  }
167
+ // ============================================================================
168
+ // First-class Hosting
169
+ // ============================================================================
170
+ /**
171
+ * Deploy lifecycle status:
172
+ * - queued - inital state although we don't currently queue deploys per se
173
+ * - building — deploy pod is running `npm run build`
174
+ * - uploading — build succeeded; artifacts being uploaded to GCS (transient,
175
+ * between `client.devtools.build.completed` and `client.devtools.build.uploaded`)
176
+ * - deploying — queue handler is pushing artifacts to Netlify + updating Envoy HTTPRoute
177
+ * - live — terminal: site is serving traffic
178
+ * - failed — terminal: see `error` for the one-line reason
179
+ */
180
+ export const DeployStatusSchema = z.enum([
181
+ "queued",
182
+ "building",
183
+ "uploading",
184
+ "deploying",
185
+ "live",
186
+ "failed",
187
+ ]);
188
+ export const ProjectHostingBuildConfigSchema = z.object({
189
+ buildCommand: z.string().optional(),
190
+ nodeVersion: z.string().optional(),
191
+ });
192
+ /**
193
+ * Hosting configuration for a project, stored at `projects/{projectId}.hosting`.
194
+ */
195
+ export const ProjectHostingSchema = z.object({
196
+ enabled: z.boolean().optional().meta({
197
+ description: "Whether hosting is enabled for this project or not.",
198
+ }),
199
+ slug: z.string().optional().meta({
200
+ description: 'e.g. "my-cool-app" — set once on first publish, immutable',
201
+ }),
202
+ netlifySiteId: z.string().optional().meta({
203
+ description: "Netlify site ID for management API calls; cleared on unpublish, set again on re-publish",
204
+ }),
205
+ netlifySiteName: z.string().optional().meta({
206
+ description: "<name> in <name>.netlify.app — the upstream the HTTPRoute filter rewrites Host to; cleared on unpublish",
207
+ }),
208
+ url: z.string().optional().meta({
209
+ description: '"https://my-cool-app.builder.cloud" — derived from slug',
210
+ }),
211
+ buildConfig: ProjectHostingBuildConfigSchema.optional(),
212
+ /**
213
+ * Hosting-build environment variables. Separate from `project.settings.environmentVariables`
214
+ * (which feeds the dev pod) so users can set different values for dev vs production —
215
+ * mirrors the Vercel/Netlify split between development and production env scopes.
216
+ *
217
+ * Reuses `EnvironmentVariableSchema`, including the `isSecret: boolean` flag. Stored in
218
+ * plaintext in Firestore, masked on the read path before responses leave ai-services
219
+ * (see "Secret handling" in the hosting spec).
220
+ */
221
+ environment: z.array(EnvironmentVariableSchema).optional().meta({
222
+ description: "Production environment variables set when we deploy",
223
+ }),
224
+ lastDeployId: z.string().optional(),
225
+ lastDeployAt: z.number().optional(),
226
+ lastDeployStatus: DeployStatusSchema.optional(),
227
+ customDomain: z.string().optional(),
228
+ customDomainVerified: z.boolean().optional(),
229
+ autoDeploy: z
230
+ .boolean()
231
+ .optional()
232
+ .meta({ description: "auto-deploy on push/merge" }),
233
+ });
234
+ /**
235
+ * A single deploy record, stored at `deploys/{deployId}`. The Deploy.id is the document key.
236
+ */
237
+ export const DeploySchema = z.object({
238
+ id: z.string(),
239
+ projectId: z.string(),
240
+ ownerId: z.string(),
241
+ checkoutBranch: z
242
+ .string()
243
+ .optional()
244
+ .meta({
245
+ description: 'The git ref that was deployed (always "main" in v0/v1; the feature branch ' +
246
+ "for row 2 in v2). This is the value passed as `checkoutBranch` when the " +
247
+ "deploy pod was created.",
248
+ }),
249
+ deployBranchId: z
250
+ .string()
251
+ .optional()
252
+ .meta({
253
+ description: 'ID of the ephemeral hidden deploy branch (`type: "deploy"`) that ran the ' +
254
+ "build. Cleared after the pod terminates so historical Deploy docs don't " +
255
+ "hold references to garbage-collected branch state.",
256
+ }),
257
+ status: DeployStatusSchema,
258
+ netlifyDeployId: z.string().optional(),
259
+ url: z.string().optional(),
260
+ error: z.string().optional().meta({
261
+ description: "Single human-readable line on failure; raw build logs not surfaced in v0",
262
+ }),
263
+ createdAt: z.number(),
264
+ completedAt: z.number().optional(),
265
+ triggeredBy: z.string().meta({
266
+ description: 'user ID for manual publish, or "auto-deploy" (v1)',
267
+ }),
268
+ });
269
+ /**
270
+ * Permanent slug reservation, stored at `hosting-slugs/{slug}` (slug is the document key).
271
+ *
272
+ * Created on first publish via the atomic Firestore transaction in
273
+ * `POST /projects/hosting/reserve-slug`. Never deleted (URL hijacking protection).
274
+ *
275
+ * "Is this URL currently live?" is NOT a property of this doc. It's answered by the
276
+ * presence of the per-slug `HTTPRoute` in Envoy Gateway (the source of truth for routing)
277
+ * and/or by `project.hosting.netlifySiteId` (set on publish, cleared on unpublish). The
278
+ * slug doc exists purely to enforce uniqueness and own the permanent reservation.
279
+ */
280
+ export const HostingSlugSchema = z.object({
281
+ projectId: z.string(),
282
+ ownerId: z.string(),
283
+ createdAt: z.number(),
284
+ createdBy: z.string().meta({
285
+ description: "user ID of the user who first clicked Publish on the project",
286
+ }),
287
+ });