@builder.io/ai-utils 0.109.1 → 0.110.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.109.1",
3
+ "version": "0.110.0",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
package/src/codegen.d.ts CHANGED
@@ -4424,6 +4424,8 @@ export interface WorkspaceFolder {
4424
4424
  * Optional, so older CLIs/configs that ignore it stay compatible.
4425
4425
  */
4426
4426
  templateRepoUrl?: string;
4427
+ /** Local-cluster testing only: branch or tag of `templateRepoUrl` to clone. Absent means its default branch. */
4428
+ templateRef?: string;
4427
4429
  repoName?: string;
4428
4430
  resetGit?: boolean;
4429
4431
  /**
package/src/projects.d.ts CHANGED
@@ -1963,6 +1963,8 @@ export interface Project {
1963
1963
  templateId?: string | null;
1964
1964
  /** @internal Read-only source repo cloned to bootstrap the project. Immutable. Absent for non-template projects. Distinct from `repoUrl`, which is always the real push remote. */
1965
1965
  templateRepoUrl?: string;
1966
+ /** @internal Local-cluster testing only: the branch or tag of `templateRepoUrl` to clone instead of its default branch. Ignored once the real remote is seeded. */
1967
+ templateRef?: string;
1966
1968
  /** Local filesystem path for desktop-app projects. */
1967
1969
  localPath?: string | null;
1968
1970
  /** The state of the project. Use `isProjectDeleted()` helper for backwards-compatible checks. */
@@ -2252,6 +2254,8 @@ export interface CreateProjectOptions {
2252
2254
  useInternalHost?: boolean;
2253
2255
  /** @internal Read-only source repo cloned to bootstrap the project. Carried through to Firestore. */
2254
2256
  templateRepoUrl?: string;
2257
+ /** @internal Local-cluster testing only: branch or tag of `templateRepoUrl` to clone. Carried through to Firestore. */
2258
+ templateRef?: string;
2255
2259
  /** @internal First-class hosting config copied from the template. Carried through to Firestore. */
2256
2260
  hosting?: ProjectHosting;
2257
2261
  /** @internal When true, provision the internalHost repo eagerly at creation. Hardcoded true for v0. */
@@ -2275,6 +2279,11 @@ export declare const GetProjectsQuerySchema: z.ZodObject<{
2275
2279
  limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
2276
2280
  }, z.core.$strip>;
2277
2281
  export type GetProjectsQuery = z.infer<typeof GetProjectsQuerySchema>;
2282
+ /**
2283
+ * A plain branch or tag name. It becomes an argument to `git clone -b`, so
2284
+ * anything that could be read as an option or a path escape is rejected.
2285
+ */
2286
+ export declare const TemplateRefSchema: z.ZodString;
2278
2287
  /**
2279
2288
  * Request body for `POST /projects/create`. Identity/credentials come from the
2280
2289
  * authenticated request context, never the body.
@@ -2290,6 +2299,7 @@ export declare const CreateProjectRequestSchema: z.ZodObject<{
2290
2299
  name: z.ZodString;
2291
2300
  initialMessage: z.ZodOptional<z.ZodString>;
2292
2301
  designSystems: z.ZodOptional<z.ZodArray<z.ZodString>>;
2302
+ templateRef: z.ZodOptional<z.ZodString>;
2293
2303
  }, z.core.$strip>;
2294
2304
  export type CreateProjectRequest = z.infer<typeof CreateProjectRequestSchema>;
2295
2305
  export interface BuilderMyContext {
package/src/projects.js CHANGED
@@ -1107,6 +1107,20 @@ export const GetProjectsQuerySchema = z.object({
1107
1107
  /** At most this many projects, counted after access, hidden and DSI filtering. */
1108
1108
  limit: z.coerce.number().int().min(1).max(1000).optional(),
1109
1109
  });
1110
+ /**
1111
+ * A plain branch or tag name. It becomes an argument to `git clone -b`, so
1112
+ * anything that could be read as an option or a path escape is rejected.
1113
+ */
1114
+ export const TemplateRefSchema = z
1115
+ .string()
1116
+ .max(255)
1117
+ .regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/)
1118
+ .refine((ref) => !ref.includes(".."), {
1119
+ message: "templateRef must not contain '..'",
1120
+ })
1121
+ .meta({
1122
+ description: "Local-cluster testing only: branch or tag of the template repo to clone. Rejected unless the service runs against a local cluster.",
1123
+ });
1110
1124
  /**
1111
1125
  * Request body for `POST /projects/create`. Identity/credentials come from the
1112
1126
  * authenticated request context, never the body.
@@ -1118,6 +1132,8 @@ export const CreateProjectRequestSchema = z.object({
1118
1132
  initialMessage: z.string().optional(),
1119
1133
  /** Design system ids to seed into project settings at creation. */
1120
1134
  designSystems: z.array(z.string()).optional(),
1135
+ /** Local-cluster testing only: branch or tag of the template repo to clone. Template source only. */
1136
+ templateRef: TemplateRefSchema.optional(),
1121
1137
  });
1122
1138
  export function resolveBranchIsPublic(isPublic, defaultBranchType) {
1123
1139
  if (isPublic !== undefined)
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { AGENT_NATIVE_STARTER_REPO, getAgentNativeRootPackageJsonWriteError, getManagedDatabasePackageJsonError, getProjectState, GetShapeQuestionnaireOptionsSchema, InitialPromptSchema, isProjectDeleted, matchesAgentNativeStarter, findFigmaFileUrl, mentionsFigmaFileUrl, parseFigmaFileUrl, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, SubmitShapeAnswersOptionsSchema, } from "./projects";
2
+ import { AGENT_NATIVE_STARTER_REPO, CreateProjectRequestSchema, TemplateRefSchema, getAgentNativeRootPackageJsonWriteError, getManagedDatabasePackageJsonError, getProjectState, GetShapeQuestionnaireOptionsSchema, InitialPromptSchema, isProjectDeleted, matchesAgentNativeStarter, findFigmaFileUrl, mentionsFigmaFileUrl, parseFigmaFileUrl, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, SubmitShapeAnswersOptionsSchema, } from "./projects";
3
3
  describe("project hosting schemas", () => {
4
4
  it("accepts the canonical published branch route", () => {
5
5
  expect(ProjectHostingSchema.parse({ publishedBranchId: "branch-live" })).toEqual({ publishedBranchId: "branch-live" });
@@ -294,3 +294,37 @@ describe("getProjectState", () => {
294
294
  expect(isProjectDeleted(project({ deleted: false }))).toBe(false);
295
295
  });
296
296
  });
297
+ describe("TemplateRefSchema", () => {
298
+ it.each(["main", "eval/kyle/faster-start", "v1.2.3", "release_2026.10"])("accepts the branch or tag name %s", (ref) => {
299
+ expect(TemplateRefSchema.safeParse(ref).success).toBe(true);
300
+ });
301
+ it.each([
302
+ "",
303
+ "-b",
304
+ "--upload-pack=evil",
305
+ "../escape",
306
+ "a/../b",
307
+ "has space",
308
+ "semi;colon",
309
+ "a".repeat(256),
310
+ ])("rejects %j", (ref) => {
311
+ expect(TemplateRefSchema.safeParse(ref).success).toBe(false);
312
+ });
313
+ });
314
+ describe("CreateProjectRequestSchema templateRef", () => {
315
+ const base = {
316
+ source: { kind: "template", templateId: "agent-native-starter" },
317
+ name: "p",
318
+ };
319
+ it("is optional", () => {
320
+ expect(CreateProjectRequestSchema.parse(base).templateRef).toBeUndefined();
321
+ });
322
+ it("carries a valid ref through", () => {
323
+ expect(CreateProjectRequestSchema.parse({ ...base, templateRef: "eval/x" })
324
+ .templateRef).toBe("eval/x");
325
+ });
326
+ it("rejects an invalid ref", () => {
327
+ expect(CreateProjectRequestSchema.safeParse({ ...base, templateRef: "--x" })
328
+ .success).toBe(false);
329
+ });
330
+ });