@builder.io/ai-utils 0.106.0 → 0.108.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 +1 -1
- package/src/codegen.d.ts +13 -0
- package/src/codegen.js +19 -1
- package/src/common-schemas.d.ts +5 -0
- package/src/common-schemas.js +12 -0
- package/src/credits.d.ts +10 -0
- package/src/credits.js +9 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/organization.d.ts +1 -0
- package/src/projects.d.ts +90 -1
- package/src/projects.js +115 -1
- package/src/projects.spec.d.ts +1 -0
- package/src/projects.spec.js +40 -0
- package/src/projects.test.js +87 -1
- package/src/single-tenancy.d.ts +17 -4
- package/src/single-tenancy.js +10 -3
package/package.json
CHANGED
package/src/codegen.d.ts
CHANGED
|
@@ -125,12 +125,22 @@ export declare const ReadToolInputSchema: z.ZodObject<{
|
|
|
125
125
|
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
126
126
|
}, z.core.$strip>;
|
|
127
127
|
export type ReadToolInput = z.infer<typeof ReadToolInputSchema>;
|
|
128
|
+
/** Image files the Read tool returns as image content instead of rejecting as binary. */
|
|
129
|
+
declare const READ_TOOL_IMAGE_MEDIA_TYPES: {
|
|
130
|
+
readonly ".png": "image/png";
|
|
131
|
+
readonly ".jpg": "image/jpeg";
|
|
132
|
+
readonly ".jpeg": "image/jpeg";
|
|
133
|
+
readonly ".gif": "image/gif";
|
|
134
|
+
readonly ".webp": "image/webp";
|
|
135
|
+
};
|
|
136
|
+
export declare function readToolImageMediaType(filePath: string): (typeof READ_TOOL_IMAGE_MEDIA_TYPES)[keyof typeof READ_TOOL_IMAGE_MEDIA_TYPES] | undefined;
|
|
128
137
|
export declare const GlobSearchToolInputSchema: z.ZodObject<{
|
|
129
138
|
pattern: z.ZodString;
|
|
130
139
|
}, z.core.$strip>;
|
|
131
140
|
export type GlobSearchToolInput = z.infer<typeof GlobSearchToolInputSchema>;
|
|
132
141
|
export declare const GrepSearchToolInputSchema: z.ZodObject<{
|
|
133
142
|
query: z.ZodString;
|
|
143
|
+
node_modules_path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
134
144
|
include_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
135
145
|
exclude_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
136
146
|
case_sensitive: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
@@ -1506,6 +1516,7 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
|
|
|
1506
1516
|
}, z.core.$strip>;
|
|
1507
1517
|
Grep: z.ZodObject<{
|
|
1508
1518
|
query: z.ZodString;
|
|
1519
|
+
node_modules_path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1509
1520
|
include_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1510
1521
|
exclude_glob: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1511
1522
|
case_sensitive: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
@@ -4497,6 +4508,8 @@ export interface FusionConfig {
|
|
|
4497
4508
|
branchFriendlyName?: string;
|
|
4498
4509
|
sessionId?: string;
|
|
4499
4510
|
browserAutomationInstructions?: string;
|
|
4511
|
+
/** Start a headed Chromium in the container, driven from scripts over DevTools. */
|
|
4512
|
+
branchBrowser?: boolean;
|
|
4500
4513
|
/** Whether this branch is for a code review - affects enabled agents and tools */
|
|
4501
4514
|
branchType?: BranchType;
|
|
4502
4515
|
/**
|
package/src/codegen.js
CHANGED
|
@@ -128,9 +128,24 @@ export const ReadToolInputSchema = z
|
|
|
128
128
|
}),
|
|
129
129
|
})
|
|
130
130
|
.meta({ title: "ReadToolInput" });
|
|
131
|
+
/** Image files the Read tool returns as image content instead of rejecting as binary. */
|
|
132
|
+
const READ_TOOL_IMAGE_MEDIA_TYPES = {
|
|
133
|
+
".png": "image/png",
|
|
134
|
+
".jpg": "image/jpeg",
|
|
135
|
+
".jpeg": "image/jpeg",
|
|
136
|
+
".gif": "image/gif",
|
|
137
|
+
".webp": "image/webp",
|
|
138
|
+
};
|
|
139
|
+
export function readToolImageMediaType(filePath) {
|
|
140
|
+
const lower = filePath.toLowerCase();
|
|
141
|
+
const ext = lower.slice(lower.lastIndexOf("."));
|
|
142
|
+
return READ_TOOL_IMAGE_MEDIA_TYPES[ext];
|
|
143
|
+
}
|
|
131
144
|
export const GlobSearchToolInputSchema = z
|
|
132
145
|
.object({
|
|
133
|
-
pattern: z.string().meta({
|
|
146
|
+
pattern: z.string().meta({
|
|
147
|
+
description: "The pattern to search for. node_modules and dist folders are skipped unless the pattern starts with a path inside node_modules (e.g. 'node_modules/@tabler/icons-react/**/*.d.ts').",
|
|
148
|
+
}),
|
|
134
149
|
})
|
|
135
150
|
.meta({ title: "GlobSearchToolInput" });
|
|
136
151
|
export const GrepSearchToolInputSchema = z
|
|
@@ -138,6 +153,9 @@ export const GrepSearchToolInputSchema = z
|
|
|
138
153
|
query: z.string().meta({
|
|
139
154
|
description: 'A string literal or a JavaScript-flavored regex to search for in all project files. Only escape special characters such as {} and () in string literals to avoid confusion with regex patterns (e.g. "import \\{ foo \\}"). Avoid over-escaping as that will cause errors. Do NOT use inline regex flags like (?i) or (?s) — they are not supported. The search is case-insensitive by default; use the case_sensitive parameter to control this.',
|
|
140
155
|
}),
|
|
156
|
+
node_modules_path: z.string().nullish().meta({
|
|
157
|
+
description: "Searches an installed package instead of the project. node_modules and dist folders are skipped by default; set this to a directory or file inside node_modules (e.g. 'node_modules/@tabler/icons-react') to search that package, including its dist folder and .d.ts files.",
|
|
158
|
+
}),
|
|
141
159
|
include_glob: z.string().nullish().meta({
|
|
142
160
|
description: "An optional single glob pattern to include only specific files (e.g. '**/*.(ts|tsx)' for all TypeScript files)",
|
|
143
161
|
}),
|
package/src/common-schemas.d.ts
CHANGED
|
@@ -7,6 +7,11 @@ export declare const EnvironmentVariableSchema: z.ZodObject<{
|
|
|
7
7
|
explanation: z.ZodOptional<z.ZodString>;
|
|
8
8
|
}, z.core.$strip>;
|
|
9
9
|
export type EnvironmentVariable = z.infer<typeof EnvironmentVariableSchema>;
|
|
10
|
+
export declare const NETLIFY_PRODUCTION_ENV_VALUE_MAX_LENGTH = 5000;
|
|
11
|
+
export declare function getOversizedProductionEnvVar(entries: ReadonlyArray<EnvironmentVariable> | undefined): {
|
|
12
|
+
key: string;
|
|
13
|
+
length: number;
|
|
14
|
+
} | undefined;
|
|
10
15
|
export declare const SetupMiseDependencySchema: z.ZodObject<{
|
|
11
16
|
key: z.ZodString;
|
|
12
17
|
type: z.ZodLiteral<"mise">;
|
package/src/common-schemas.js
CHANGED
|
@@ -19,6 +19,18 @@ export const EnvironmentVariableSchema = z
|
|
|
19
19
|
}),
|
|
20
20
|
})
|
|
21
21
|
.meta({ title: "EnvironmentVariable" });
|
|
22
|
+
export const NETLIFY_PRODUCTION_ENV_VALUE_MAX_LENGTH = 5000;
|
|
23
|
+
export function getOversizedProductionEnvVar(entries) {
|
|
24
|
+
for (const entry of entries !== null && entries !== void 0 ? entries : []) {
|
|
25
|
+
const key = entry.key.trim();
|
|
26
|
+
if (key &&
|
|
27
|
+
!entry.placeholder &&
|
|
28
|
+
entry.value.length > NETLIFY_PRODUCTION_ENV_VALUE_MAX_LENGTH) {
|
|
29
|
+
return { key, length: entry.value.length };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
22
34
|
export const SetupMiseDependencySchema = z
|
|
23
35
|
.object({
|
|
24
36
|
key: z.string(),
|
package/src/credits.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const BuilderReferralInfoResponseSchema: z.ZodObject<{
|
|
3
|
+
eligible: z.ZodBoolean;
|
|
4
|
+
inviteUrl: z.ZodNullable<z.ZodURL>;
|
|
5
|
+
creditsPerReferral: z.ZodNumber;
|
|
6
|
+
completedReferrals: z.ZodNumber;
|
|
7
|
+
pendingReferrals: z.ZodNumber;
|
|
8
|
+
creditsEarned: z.ZodNumber;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export type BuilderReferralInfoResponse = z.infer<typeof BuilderReferralInfoResponseSchema>;
|
package/src/credits.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const BuilderReferralInfoResponseSchema = z.object({
|
|
3
|
+
eligible: z.boolean(),
|
|
4
|
+
inviteUrl: z.url().nullable(),
|
|
5
|
+
creditsPerReferral: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
6
|
+
completedReferrals: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
7
|
+
pendingReferrals: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
8
|
+
creditsEarned: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
9
|
+
});
|
package/src/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export * from "./single-tenancy.js";
|
|
|
22
22
|
export * from "./design-systems.js";
|
|
23
23
|
export * from "./editor-ai.js";
|
|
24
24
|
export * from "./realtime.js";
|
|
25
|
+
export * from "./credits.js";
|
|
25
26
|
export * from "./embeddings.js";
|
|
26
27
|
export * from "./system-one.js";
|
|
27
28
|
export * from "./mcp-servers.js";
|
package/src/index.js
CHANGED
|
@@ -22,6 +22,7 @@ export * from "./single-tenancy.js";
|
|
|
22
22
|
export * from "./design-systems.js";
|
|
23
23
|
export * from "./editor-ai.js";
|
|
24
24
|
export * from "./realtime.js";
|
|
25
|
+
export * from "./credits.js";
|
|
25
26
|
export * from "./embeddings.js";
|
|
26
27
|
export * from "./system-one.js";
|
|
27
28
|
export * from "./mcp-servers.js";
|
package/src/organization.d.ts
CHANGED
|
@@ -355,6 +355,7 @@ export interface FeatureMap {
|
|
|
355
355
|
performanceInfrastructure?: boolean;
|
|
356
356
|
previewPasswordProtection?: boolean;
|
|
357
357
|
siteAccessControl?: boolean;
|
|
358
|
+
hostingCustomDomain?: boolean;
|
|
358
359
|
publicPreviews?: boolean;
|
|
359
360
|
privacyMode?: boolean;
|
|
360
361
|
usageInsights?: boolean;
|
package/src/projects.d.ts
CHANGED
|
@@ -472,7 +472,13 @@ export declare const ProjectSkillSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
472
472
|
url: z.ZodString;
|
|
473
473
|
}, z.core.$strip>]>;
|
|
474
474
|
export type ProjectSkill = z.infer<typeof ProjectSkillSchema>;
|
|
475
|
-
export
|
|
475
|
+
export declare const FusionExecutionEnvironmentSchema: z.ZodEnum<{
|
|
476
|
+
cloud: "cloud";
|
|
477
|
+
"cloud-v2": "cloud-v2";
|
|
478
|
+
"container-less": "container-less";
|
|
479
|
+
containerized: "containerized";
|
|
480
|
+
}>;
|
|
481
|
+
export type FusionExecutionEnvironment = z.infer<typeof FusionExecutionEnvironmentSchema>;
|
|
476
482
|
export type AgentType = "setup-project" | "project-configuration" | "org-agent" | "code-review-orchestrator" | "design-system-indexer" | "repo-indexer" | "builder-publish-integration";
|
|
477
483
|
export interface PartialBranchData {
|
|
478
484
|
name?: string;
|
|
@@ -725,6 +731,19 @@ export interface NewBranch extends BranchSharedData, RequiredBranchSharedData {
|
|
|
725
731
|
*/
|
|
726
732
|
export type Branch = NewBranch | LegacyBranch;
|
|
727
733
|
export declare const checkIsNewBranch: (branch: Branch) => branch is NewBranch;
|
|
734
|
+
/** Identifies a single branch by its project and branch name. */
|
|
735
|
+
export declare const BranchIdentifierSchema: z.ZodObject<{
|
|
736
|
+
projectId: z.ZodString;
|
|
737
|
+
branchName: z.ZodString;
|
|
738
|
+
}, z.core.$strip>;
|
|
739
|
+
export type BranchIdentifier = z.infer<typeof BranchIdentifierSchema>;
|
|
740
|
+
/** Query params for `DELETE /projects/branches`. */
|
|
741
|
+
export declare const DeleteBranchOptionsSchema: z.ZodObject<{
|
|
742
|
+
projectId: z.ZodString;
|
|
743
|
+
branchName: z.ZodString;
|
|
744
|
+
hard: z.ZodDefault<z.ZodCodec<z.ZodString, z.ZodBoolean>>;
|
|
745
|
+
}, z.core.$strip>;
|
|
746
|
+
export type DeleteBranchOptions = z.input<typeof DeleteBranchOptionsSchema>;
|
|
728
747
|
/**
|
|
729
748
|
* Request options for `GET /projects/branches/list`. Owner/org scope comes from
|
|
730
749
|
* the authenticated request context; `ownerId` here is a superuser-only override.
|
|
@@ -829,6 +848,11 @@ export declare const ShapeOptionSchema: z.ZodObject<{
|
|
|
829
848
|
designSystemName: z.ZodString;
|
|
830
849
|
}, z.core.$strip>], "kind">>>;
|
|
831
850
|
}, z.core.$strip>>;
|
|
851
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
852
|
+
delegate: "delegate";
|
|
853
|
+
"figma-link": "figma-link";
|
|
854
|
+
upload: "upload";
|
|
855
|
+
}>>;
|
|
832
856
|
}, z.core.$strip>;
|
|
833
857
|
export type ShapeOption = z.infer<typeof ShapeOptionSchema>;
|
|
834
858
|
export declare const ShapeQuestionSchema: z.ZodObject<{
|
|
@@ -853,14 +877,32 @@ export declare const ShapeQuestionSchema: z.ZodObject<{
|
|
|
853
877
|
designSystemName: z.ZodString;
|
|
854
878
|
}, z.core.$strip>], "kind">>>;
|
|
855
879
|
}, z.core.$strip>>;
|
|
880
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
881
|
+
delegate: "delegate";
|
|
882
|
+
"figma-link": "figma-link";
|
|
883
|
+
upload: "upload";
|
|
884
|
+
}>>;
|
|
856
885
|
}, z.core.$strip>>;
|
|
857
886
|
guessOptionId: z.ZodOptional<z.ZodString>;
|
|
858
887
|
}, z.core.$strip>;
|
|
859
888
|
export type ShapeQuestion = z.infer<typeof ShapeQuestionSchema>;
|
|
889
|
+
/**
|
|
890
|
+
* The link in canonical form, or undefined when it is not an https link to a
|
|
891
|
+
* file on figma.com. Deliberately strict: the result is written into the
|
|
892
|
+
* user's repo and handed to the agent as a requirement.
|
|
893
|
+
*/
|
|
894
|
+
export declare function parseFigmaFileUrl(value: string): string | undefined;
|
|
895
|
+
/**
|
|
896
|
+
* The first Figma file link in `text`, canonicalized by `parseFigmaFileUrl`.
|
|
897
|
+
* Bare and `http:` mentions count as https; trailing punctuation is dropped.
|
|
898
|
+
*/
|
|
899
|
+
export declare function findFigmaFileUrl(text: string): string | undefined;
|
|
900
|
+
export declare function mentionsFigmaFileUrl(text: string): boolean;
|
|
860
901
|
export declare const ShapeAnswerSchema: z.ZodObject<{
|
|
861
902
|
questionId: z.ZodString;
|
|
862
903
|
optionId: z.ZodOptional<z.ZodString>;
|
|
863
904
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
905
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
864
906
|
designSystemName: z.ZodOptional<z.ZodString>;
|
|
865
907
|
skipped: z.ZodBoolean;
|
|
866
908
|
delegated: z.ZodBoolean;
|
|
@@ -878,6 +920,7 @@ export declare const ShapeAnswerInputSchema: z.ZodObject<{
|
|
|
878
920
|
questionId: z.ZodString;
|
|
879
921
|
optionId: z.ZodOptional<z.ZodString>;
|
|
880
922
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
923
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
881
924
|
}, z.core.$strip>;
|
|
882
925
|
export type ShapeAnswerInput = z.infer<typeof ShapeAnswerInputSchema>;
|
|
883
926
|
export declare const GetShapeQuestionnaireOptionsSchema: z.ZodObject<{
|
|
@@ -893,6 +936,7 @@ export declare const SubmitShapeAnswersOptionsSchema: z.ZodObject<{
|
|
|
893
936
|
questionId: z.ZodString;
|
|
894
937
|
optionId: z.ZodOptional<z.ZodString>;
|
|
895
938
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
939
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
896
940
|
}, z.core.$strip>>;
|
|
897
941
|
}, z.core.$strip>;
|
|
898
942
|
export type SubmitShapeAnswersOptions = z.infer<typeof SubmitShapeAnswersOptionsSchema>;
|
|
@@ -968,6 +1012,11 @@ export declare const ShapeSessionSchema: z.ZodObject<{
|
|
|
968
1012
|
designSystemName: z.ZodString;
|
|
969
1013
|
}, z.core.$strip>], "kind">>>;
|
|
970
1014
|
}, z.core.$strip>>;
|
|
1015
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
1016
|
+
delegate: "delegate";
|
|
1017
|
+
"figma-link": "figma-link";
|
|
1018
|
+
upload: "upload";
|
|
1019
|
+
}>>;
|
|
971
1020
|
}, z.core.$strip>>;
|
|
972
1021
|
guessOptionId: z.ZodOptional<z.ZodString>;
|
|
973
1022
|
}, z.core.$strip>>;
|
|
@@ -976,6 +1025,7 @@ export declare const ShapeSessionSchema: z.ZodObject<{
|
|
|
976
1025
|
questionId: z.ZodString;
|
|
977
1026
|
optionId: z.ZodOptional<z.ZodString>;
|
|
978
1027
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
1028
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
979
1029
|
designSystemName: z.ZodOptional<z.ZodString>;
|
|
980
1030
|
skipped: z.ZodBoolean;
|
|
981
1031
|
delegated: z.ZodBoolean;
|
|
@@ -1041,6 +1091,11 @@ export declare const ShapeSessionDocSchema: z.ZodObject<{
|
|
|
1041
1091
|
designSystemName: z.ZodString;
|
|
1042
1092
|
}, z.core.$strip>], "kind">>>;
|
|
1043
1093
|
}, z.core.$strip>>;
|
|
1094
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
1095
|
+
delegate: "delegate";
|
|
1096
|
+
"figma-link": "figma-link";
|
|
1097
|
+
upload: "upload";
|
|
1098
|
+
}>>;
|
|
1044
1099
|
}, z.core.$strip>>;
|
|
1045
1100
|
guessOptionId: z.ZodOptional<z.ZodString>;
|
|
1046
1101
|
}, z.core.$strip>>;
|
|
@@ -1049,6 +1104,7 @@ export declare const ShapeSessionDocSchema: z.ZodObject<{
|
|
|
1049
1104
|
questionId: z.ZodString;
|
|
1050
1105
|
optionId: z.ZodOptional<z.ZodString>;
|
|
1051
1106
|
designSystemId: z.ZodOptional<z.ZodString>;
|
|
1107
|
+
figmaUrl: z.ZodOptional<z.ZodString>;
|
|
1052
1108
|
designSystemName: z.ZodOptional<z.ZodString>;
|
|
1053
1109
|
skipped: z.ZodBoolean;
|
|
1054
1110
|
delegated: z.ZodBoolean;
|
|
@@ -1434,6 +1490,7 @@ export declare const ProjectSettingsSchema: z.ZodObject<{
|
|
|
1434
1490
|
instructions: z.ZodOptional<z.ZodString>;
|
|
1435
1491
|
authUser: z.ZodOptional<z.ZodString>;
|
|
1436
1492
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
1493
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
1437
1494
|
}, z.core.$strip>>;
|
|
1438
1495
|
prReviewer: z.ZodOptional<z.ZodObject<{
|
|
1439
1496
|
enabled: z.ZodBoolean;
|
|
@@ -1771,6 +1828,7 @@ export declare const ProjectSettingsExternalSchema: z.ZodObject<{
|
|
|
1771
1828
|
instructions: z.ZodOptional<z.ZodString>;
|
|
1772
1829
|
authUser: z.ZodOptional<z.ZodString>;
|
|
1773
1830
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
1831
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
1774
1832
|
}, z.core.$strip>>;
|
|
1775
1833
|
prReviewer: z.ZodOptional<z.ZodObject<{
|
|
1776
1834
|
enabled: z.ZodBoolean;
|
|
@@ -2982,6 +3040,7 @@ export declare const UpdateProjectOptionsSchema: z.ZodObject<{
|
|
|
2982
3040
|
instructions: z.ZodOptional<z.ZodString>;
|
|
2983
3041
|
authUser: z.ZodOptional<z.ZodString>;
|
|
2984
3042
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
3043
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
2985
3044
|
}, z.core.$strip>>>;
|
|
2986
3045
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
2987
3046
|
enabled: z.ZodBoolean;
|
|
@@ -3692,6 +3751,8 @@ export declare const HostingDomainSchema: z.ZodObject<{
|
|
|
3692
3751
|
routeError: z.ZodOptional<z.ZodString>;
|
|
3693
3752
|
routeErrorAt: z.ZodOptional<z.ZodNumber>;
|
|
3694
3753
|
servingConfirmedAt: z.ZodOptional<z.ZodNumber>;
|
|
3754
|
+
certIssue: z.ZodOptional<z.ZodString>;
|
|
3755
|
+
certIssueAt: z.ZodOptional<z.ZodNumber>;
|
|
3695
3756
|
createdBy: z.ZodString;
|
|
3696
3757
|
}, z.core.$strip>;
|
|
3697
3758
|
export type HostingDomain = z.infer<typeof HostingDomainSchema>;
|
|
@@ -3931,6 +3992,24 @@ export declare const EnsureMainBranchExistsOptionsSchema: z.ZodObject<{
|
|
|
3931
3992
|
branchName: z.ZodString;
|
|
3932
3993
|
}, z.core.$strip>;
|
|
3933
3994
|
export type EnsureMainBranchExistsOptions = z.infer<typeof EnsureMainBranchExistsOptionsSchema>;
|
|
3995
|
+
/** Request body for `POST /projects/ensure-fusion-config`. */
|
|
3996
|
+
export declare const EnsureFusionConfigParamsSchema: z.ZodObject<{
|
|
3997
|
+
projectId: z.ZodString;
|
|
3998
|
+
branchName: z.ZodString;
|
|
3999
|
+
includeBackupMetadata: z.ZodOptional<z.ZodBoolean>;
|
|
4000
|
+
volumeMountPath: z.ZodOptional<z.ZodString>;
|
|
4001
|
+
isLocal: z.ZodOptional<z.ZodBoolean>;
|
|
4002
|
+
nativeApp: z.ZodOptional<z.ZodBoolean>;
|
|
4003
|
+
miseLocationPath: z.ZodOptional<z.ZodString>;
|
|
4004
|
+
_useNI: z.ZodOptional<z.ZodBoolean>;
|
|
4005
|
+
fusionEnvironment: z.ZodOptional<z.ZodEnum<{
|
|
4006
|
+
cloud: "cloud";
|
|
4007
|
+
"cloud-v2": "cloud-v2";
|
|
4008
|
+
"container-less": "container-less";
|
|
4009
|
+
containerized: "containerized";
|
|
4010
|
+
}>>;
|
|
4011
|
+
}, z.core.$strip>;
|
|
4012
|
+
export type EnsureFusionConfigParams = z.infer<typeof EnsureFusionConfigParamsSchema>;
|
|
3934
4013
|
/**
|
|
3935
4014
|
* `settings.environmentVariables` is stored with **plaintext** secret values;
|
|
3936
4015
|
* secrets are masked before this shape leaves ai-services, same as
|
|
@@ -4274,6 +4353,7 @@ export declare const ProjectTemplateSchema: z.ZodObject<{
|
|
|
4274
4353
|
instructions: z.ZodOptional<z.ZodString>;
|
|
4275
4354
|
authUser: z.ZodOptional<z.ZodString>;
|
|
4276
4355
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
4356
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
4277
4357
|
}, z.core.$strip>>>;
|
|
4278
4358
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
4279
4359
|
enabled: z.ZodBoolean;
|
|
@@ -4699,6 +4779,7 @@ export declare const ProjectTemplateOverridesSchema: z.ZodObject<{
|
|
|
4699
4779
|
instructions: z.ZodOptional<z.ZodString>;
|
|
4700
4780
|
authUser: z.ZodOptional<z.ZodString>;
|
|
4701
4781
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
4782
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
4702
4783
|
}, z.core.$strip>>>;
|
|
4703
4784
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
4704
4785
|
enabled: z.ZodBoolean;
|
|
@@ -5092,6 +5173,7 @@ export declare const CreateProjectTemplateFromProjectOptionsSchema: z.ZodPipe<z.
|
|
|
5092
5173
|
instructions: z.ZodOptional<z.ZodString>;
|
|
5093
5174
|
authUser: z.ZodOptional<z.ZodString>;
|
|
5094
5175
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
5176
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
5095
5177
|
}, z.core.$strip>>>;
|
|
5096
5178
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
5097
5179
|
enabled: z.ZodBoolean;
|
|
@@ -5468,6 +5550,7 @@ export declare const CreateProjectTemplateFromProjectOptionsSchema: z.ZodPipe<z.
|
|
|
5468
5550
|
instructions: z.ZodOptional<z.ZodString>;
|
|
5469
5551
|
authUser: z.ZodOptional<z.ZodString>;
|
|
5470
5552
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
5553
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
5471
5554
|
}, z.core.$strip>>>;
|
|
5472
5555
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
5473
5556
|
enabled: z.ZodBoolean;
|
|
@@ -5740,6 +5823,7 @@ export declare const CreateProjectTemplateFromProjectOptionsSchema: z.ZodPipe<z.
|
|
|
5740
5823
|
instructions?: string | undefined;
|
|
5741
5824
|
authUser?: string | undefined;
|
|
5742
5825
|
authPassword?: string | undefined;
|
|
5826
|
+
branchBrowser?: boolean | undefined;
|
|
5743
5827
|
} | undefined;
|
|
5744
5828
|
prReviewer?: {
|
|
5745
5829
|
enabled: boolean;
|
|
@@ -6008,6 +6092,7 @@ export declare const CreateProjectTemplateFromProjectOptionsSchema: z.ZodPipe<z.
|
|
|
6008
6092
|
instructions?: string | undefined;
|
|
6009
6093
|
authUser?: string | undefined;
|
|
6010
6094
|
authPassword?: string | undefined;
|
|
6095
|
+
branchBrowser?: boolean | undefined;
|
|
6011
6096
|
} | undefined;
|
|
6012
6097
|
prReviewer?: {
|
|
6013
6098
|
enabled: boolean;
|
|
@@ -6270,6 +6355,7 @@ export declare const CreateProjectTemplateFromProjectOptionsSchema: z.ZodPipe<z.
|
|
|
6270
6355
|
instructions?: string | undefined;
|
|
6271
6356
|
authUser?: string | undefined;
|
|
6272
6357
|
authPassword?: string | undefined;
|
|
6358
|
+
branchBrowser?: boolean | undefined;
|
|
6273
6359
|
} | undefined;
|
|
6274
6360
|
prReviewer?: {
|
|
6275
6361
|
enabled: boolean;
|
|
@@ -6693,6 +6779,7 @@ export declare const ListProjectTemplatesResponseSchema: z.ZodObject<{
|
|
|
6693
6779
|
instructions: z.ZodOptional<z.ZodString>;
|
|
6694
6780
|
authUser: z.ZodOptional<z.ZodString>;
|
|
6695
6781
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
6782
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
6696
6783
|
}, z.core.$strip>>>;
|
|
6697
6784
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
6698
6785
|
enabled: z.ZodBoolean;
|
|
@@ -7113,6 +7200,7 @@ export declare const UpdateProjectTemplateOptionsSchema: z.ZodObject<{
|
|
|
7113
7200
|
instructions: z.ZodOptional<z.ZodString>;
|
|
7114
7201
|
authUser: z.ZodOptional<z.ZodString>;
|
|
7115
7202
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
7203
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
7116
7204
|
}, z.core.$strip>>>;
|
|
7117
7205
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
7118
7206
|
enabled: z.ZodBoolean;
|
|
@@ -7525,6 +7613,7 @@ export declare const UpdateProjectTemplateResponseSchema: z.ZodObject<{
|
|
|
7525
7613
|
instructions: z.ZodOptional<z.ZodString>;
|
|
7526
7614
|
authUser: z.ZodOptional<z.ZodString>;
|
|
7527
7615
|
authPassword: z.ZodOptional<z.ZodString>;
|
|
7616
|
+
branchBrowser: z.ZodOptional<z.ZodBoolean>;
|
|
7528
7617
|
}, z.core.$strip>>>;
|
|
7529
7618
|
prReviewer: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
7530
7619
|
enabled: z.ZodBoolean;
|
package/src/projects.js
CHANGED
|
@@ -200,9 +200,27 @@ export const ProjectSkillSchema = z
|
|
|
200
200
|
ProjectSkillUrlSchema,
|
|
201
201
|
])
|
|
202
202
|
.meta({ title: "ProjectSkill" });
|
|
203
|
+
export const FusionExecutionEnvironmentSchema = z.enum([
|
|
204
|
+
"containerized",
|
|
205
|
+
"container-less",
|
|
206
|
+
"cloud",
|
|
207
|
+
"cloud-v2",
|
|
208
|
+
]);
|
|
203
209
|
export const checkIsNewBranch = (branch) => {
|
|
204
210
|
return "projectId" in branch;
|
|
205
211
|
};
|
|
212
|
+
/** Identifies a single branch by its project and branch name. */
|
|
213
|
+
export const BranchIdentifierSchema = z.object({
|
|
214
|
+
projectId: z.string().min(1),
|
|
215
|
+
branchName: z.string().min(1),
|
|
216
|
+
});
|
|
217
|
+
/** Query params for `DELETE /projects/branches`. */
|
|
218
|
+
export const DeleteBranchOptionsSchema = z.object({
|
|
219
|
+
...BranchIdentifierSchema.shape,
|
|
220
|
+
hard: z.stringbool().default(false).meta({
|
|
221
|
+
description: 'Permanently delete the branch instead of soft-deleting it ("true" / "false").',
|
|
222
|
+
}),
|
|
223
|
+
});
|
|
206
224
|
/**
|
|
207
225
|
* Request options for `GET /projects/branches/list`. Owner/org scope comes from
|
|
208
226
|
* the authenticated request context; `ownerId` here is a superuser-only override.
|
|
@@ -310,6 +328,11 @@ export const ShapeOptionSchema = z.object({
|
|
|
310
328
|
id: z.string(),
|
|
311
329
|
label: z.string(),
|
|
312
330
|
effect: ShapeOptionEffectSchema.optional(),
|
|
331
|
+
/**
|
|
332
|
+
* How the client renders an option that is not a plain choice. Absent means
|
|
333
|
+
* a choice when `effect` is set, delegation otherwise.
|
|
334
|
+
*/
|
|
335
|
+
kind: z.enum(["upload", "delegate", "figma-link"]).optional(),
|
|
313
336
|
});
|
|
314
337
|
export const ShapeQuestionSchema = z.object({
|
|
315
338
|
id: z.string(),
|
|
@@ -318,10 +341,57 @@ export const ShapeQuestionSchema = z.object({
|
|
|
318
341
|
options: z.array(ShapeOptionSchema),
|
|
319
342
|
guessOptionId: z.string().optional(),
|
|
320
343
|
});
|
|
344
|
+
/** Figma paths that name a file, which is what the Builder Design tools read. */
|
|
345
|
+
const FIGMA_FILE_PATH = /^\/(?:design|file|proto|board|slides|make)\/[A-Za-z0-9]+/;
|
|
346
|
+
/**
|
|
347
|
+
* The link in canonical form, or undefined when it is not an https link to a
|
|
348
|
+
* file on figma.com. Deliberately strict: the result is written into the
|
|
349
|
+
* user's repo and handed to the agent as a requirement.
|
|
350
|
+
*/
|
|
351
|
+
export function parseFigmaFileUrl(value) {
|
|
352
|
+
let url;
|
|
353
|
+
try {
|
|
354
|
+
url = new URL(value.trim());
|
|
355
|
+
}
|
|
356
|
+
catch (_a) {
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
const isFigmaHost = url.hostname === "figma.com" || url.hostname === "www.figma.com";
|
|
360
|
+
if (url.protocol !== "https:" ||
|
|
361
|
+
!isFigmaHost ||
|
|
362
|
+
url.port ||
|
|
363
|
+
url.username ||
|
|
364
|
+
url.password ||
|
|
365
|
+
!FIGMA_FILE_PATH.test(url.pathname)) {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
return url.href;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Lenient on purpose: users paste bare links, so any mention counts. Not one
|
|
372
|
+
* inside another URL's path or after an `@`, which would name a different host.
|
|
373
|
+
*/
|
|
374
|
+
const FIGMA_FILE_MENTION = /(?:^|[^a-z0-9.\/@-])(?:https?:\/\/)?((?:www\.)?figma\.com\/(?:design|file|proto|board|slides|make)\/[a-z0-9]+[^\s<>()[\]{}"'`]*)/i;
|
|
375
|
+
/**
|
|
376
|
+
* The first Figma file link in `text`, canonicalized by `parseFigmaFileUrl`.
|
|
377
|
+
* Bare and `http:` mentions count as https; trailing punctuation is dropped.
|
|
378
|
+
*/
|
|
379
|
+
export function findFigmaFileUrl(text) {
|
|
380
|
+
var _a;
|
|
381
|
+
const mention = (_a = FIGMA_FILE_MENTION.exec(text)) === null || _a === void 0 ? void 0 : _a[1];
|
|
382
|
+
if (!mention)
|
|
383
|
+
return undefined;
|
|
384
|
+
return parseFigmaFileUrl(`https://${mention.replace(/[.,;:!?]+$/, "")}`);
|
|
385
|
+
}
|
|
386
|
+
export function mentionsFigmaFileUrl(text) {
|
|
387
|
+
return findFigmaFileUrl(text) !== undefined;
|
|
388
|
+
}
|
|
321
389
|
export const ShapeAnswerSchema = z.object({
|
|
322
390
|
questionId: z.string(),
|
|
323
391
|
optionId: z.string().optional(),
|
|
324
392
|
designSystemId: z.string().optional(),
|
|
393
|
+
/** Set only for the Figma link option, canonicalized by `parseFigmaFileUrl`. */
|
|
394
|
+
figmaUrl: z.string().optional(),
|
|
325
395
|
/**
|
|
326
396
|
* Server-resolved from `designSystemId` against the caller's accessible
|
|
327
397
|
* design systems. `settings.designSystems` is matched by name downstream, so
|
|
@@ -338,6 +408,7 @@ const ShapeAnswerInputBaseSchema = ShapeAnswerSchema.pick({
|
|
|
338
408
|
questionId: true,
|
|
339
409
|
optionId: true,
|
|
340
410
|
designSystemId: true,
|
|
411
|
+
figmaUrl: true,
|
|
341
412
|
skipped: true,
|
|
342
413
|
delegated: true,
|
|
343
414
|
});
|
|
@@ -354,6 +425,14 @@ export const ShapeAnswerInputSchema = z.object({
|
|
|
354
425
|
.trim()
|
|
355
426
|
.min(1)
|
|
356
427
|
.optional(),
|
|
428
|
+
figmaUrl: ShapeAnswerInputBaseSchema.shape.figmaUrl
|
|
429
|
+
.unwrap()
|
|
430
|
+
.trim()
|
|
431
|
+
.max(2048)
|
|
432
|
+
.refine((value) => parseFigmaFileUrl(value) !== undefined, {
|
|
433
|
+
message: "Must be a link to a Figma file",
|
|
434
|
+
})
|
|
435
|
+
.optional(),
|
|
357
436
|
});
|
|
358
437
|
export const GetShapeQuestionnaireOptionsSchema = z.object({
|
|
359
438
|
projectId: z.string().trim().min(1),
|
|
@@ -777,6 +856,9 @@ export const ProjectSettingsSchema = z
|
|
|
777
856
|
authPassword: z.string().optional().meta({
|
|
778
857
|
description: "Password for sites requiring authentication.",
|
|
779
858
|
}),
|
|
859
|
+
branchBrowser: z.boolean().optional().meta({
|
|
860
|
+
description: "Run a headed Chrome inside every cloud branch container, which the agent drives from scripts over DevTools.",
|
|
861
|
+
}),
|
|
780
862
|
})
|
|
781
863
|
.optional()
|
|
782
864
|
.meta({
|
|
@@ -2022,7 +2104,13 @@ export const HostingDomainSchema = z.object({
|
|
|
2022
2104
|
description: "When `routeError` was last set.",
|
|
2023
2105
|
}),
|
|
2024
2106
|
servingConfirmedAt: z.number().optional().meta({
|
|
2025
|
-
description: "When the domain was confirmed serving over HTTPS: stamped by the serving-check loop once `https://<domain>/` answers over TLS through a Builder route (or by a healthy route recreate on deploy/repair). Definitive 'serving confirmed' signal for the UI's third setup step, distinct from cert issuance (`status: active`).",
|
|
2107
|
+
description: "When the domain was confirmed serving over HTTPS: stamped by the serving-check loop once `https://<domain>/` answers over TLS through a Builder route (or by a healthy route recreate on deploy/repair on an `active` domain). Definitive 'serving confirmed' signal for the UI's third setup step, distinct from cert issuance (`status: active`). Never set while `provisioning`.",
|
|
2108
|
+
}),
|
|
2109
|
+
certIssue: z.string().optional().meta({
|
|
2110
|
+
description: "Non-fatal, user-facing reason Google's latest certificate domain-authorization attempt failed while the domain is `provisioning` (e.g. the `_acme-challenge` CNAME wasn't found). Google keeps retrying, so `status` stays `provisioning`; this drives a warning on the HTTPS step instead of a silent spinner. Cleared when an attempt stops failing or the cert is issued.",
|
|
2111
|
+
}),
|
|
2112
|
+
certIssueAt: z.number().optional().meta({
|
|
2113
|
+
description: "When `certIssue` was last set.",
|
|
2026
2114
|
}),
|
|
2027
2115
|
createdBy: z.string(),
|
|
2028
2116
|
});
|
|
@@ -2205,6 +2293,32 @@ export const EnsureMainBranchExistsOptionsSchema = z.object({
|
|
|
2205
2293
|
description: "Branch whose head ref seeds the main branch when it doesn't exist yet. No-op for non-internalHost projects.",
|
|
2206
2294
|
}),
|
|
2207
2295
|
});
|
|
2296
|
+
/** Request body for `POST /projects/ensure-fusion-config`. */
|
|
2297
|
+
export const EnsureFusionConfigParamsSchema = z.object({
|
|
2298
|
+
projectId: z.string().min(1),
|
|
2299
|
+
branchName: z.string().min(1),
|
|
2300
|
+
includeBackupMetadata: z.boolean().optional().meta({
|
|
2301
|
+
description: "Whether to include backup metadata in the fusion config. This involves checking backup data and generating download URLs. Defaults to false.",
|
|
2302
|
+
}),
|
|
2303
|
+
volumeMountPath: z.string().optional().meta({
|
|
2304
|
+
description: 'Volume mount path for the container. Defaults to "/app" if not specified.',
|
|
2305
|
+
}),
|
|
2306
|
+
isLocal: z.boolean().optional().meta({
|
|
2307
|
+
description: "Flag for local execution mode. When true, adjusts paths for local execution (e.g., ./workspace instead of /app/workspace).",
|
|
2308
|
+
}),
|
|
2309
|
+
nativeApp: z.boolean().optional().meta({
|
|
2310
|
+
description: "Flag for native app projects. When true, adds nativeApp: true to fusion config.",
|
|
2311
|
+
}),
|
|
2312
|
+
miseLocationPath: z.string().optional().meta({
|
|
2313
|
+
description: "Path to mise installation. Provided by client from desktop app system info.",
|
|
2314
|
+
}),
|
|
2315
|
+
_useNI: z.boolean().optional().meta({
|
|
2316
|
+
description: "Flag to use NI for package management. When true, uses NI for package management. Defaults to true.",
|
|
2317
|
+
}),
|
|
2318
|
+
fusionEnvironment: FusionExecutionEnvironmentSchema.optional().meta({
|
|
2319
|
+
description: "Fusion environment type override. When not provided, the environment is resolved from branch/project settings.",
|
|
2320
|
+
}),
|
|
2321
|
+
});
|
|
2208
2322
|
/**
|
|
2209
2323
|
* `settings.environmentVariables` is stored with **plaintext** secret values;
|
|
2210
2324
|
* secrets are masked before this shape leaves ai-services, same as
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { DeleteBranchOptionsSchema, EnsureFusionConfigParamsSchema, } from "./projects.js";
|
|
3
|
+
describe("DeleteBranchOptionsSchema", () => {
|
|
4
|
+
const ids = { projectId: "p1", branchName: "main" };
|
|
5
|
+
it("defaults hard to false", () => {
|
|
6
|
+
expect(DeleteBranchOptionsSchema.parse(ids)).toEqual({
|
|
7
|
+
...ids,
|
|
8
|
+
hard: false,
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
it("parses hard from its query-string form", () => {
|
|
12
|
+
expect(DeleteBranchOptionsSchema.parse({ ...ids, hard: "true" }).hard).toBe(true);
|
|
13
|
+
expect(DeleteBranchOptionsSchema.parse({ ...ids, hard: "false" }).hard).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
it("rejects a hard value that isn't a boolean string", () => {
|
|
16
|
+
expect(DeleteBranchOptionsSchema.safeParse({ ...ids, hard: "maybe" }).success).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it("requires a non-empty projectId and branchName", () => {
|
|
19
|
+
expect(DeleteBranchOptionsSchema.safeParse({}).success).toBe(false);
|
|
20
|
+
expect(DeleteBranchOptionsSchema.safeParse({ projectId: "", branchName: "main" })
|
|
21
|
+
.success).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("EnsureFusionConfigParamsSchema", () => {
|
|
25
|
+
const ids = { projectId: "p1", branchName: "main" };
|
|
26
|
+
it("accepts just the identifiers", () => {
|
|
27
|
+
expect(EnsureFusionConfigParamsSchema.parse(ids)).toEqual(ids);
|
|
28
|
+
});
|
|
29
|
+
it("requires a non-empty projectId and branchName", () => {
|
|
30
|
+
expect(EnsureFusionConfigParamsSchema.safeParse({ ...ids, projectId: "" })
|
|
31
|
+
.success).toBe(false);
|
|
32
|
+
expect(EnsureFusionConfigParamsSchema.safeParse({ projectId: "p1" }).success).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it("rejects an unknown fusionEnvironment", () => {
|
|
35
|
+
expect(EnsureFusionConfigParamsSchema.safeParse({
|
|
36
|
+
...ids,
|
|
37
|
+
fusionEnvironment: "mainframe",
|
|
38
|
+
}).success).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
package/src/projects.test.js
CHANGED
|
@@ -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, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, SubmitShapeAnswersOptionsSchema, } from "./projects";
|
|
2
|
+
import { AGENT_NATIVE_STARTER_REPO, 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" });
|
|
@@ -112,6 +112,92 @@ describe("guided onboarding project settings", () => {
|
|
|
112
112
|
answers: [],
|
|
113
113
|
})).toThrow();
|
|
114
114
|
});
|
|
115
|
+
it("accepts a Figma file link on an answer and rejects anything else", () => {
|
|
116
|
+
var _a, _b;
|
|
117
|
+
const submit = (figmaUrl) => SubmitShapeAnswersOptionsSchema.safeParse({
|
|
118
|
+
projectId: "project-1",
|
|
119
|
+
questionnaireId: "questionnaire-1",
|
|
120
|
+
answers: [
|
|
121
|
+
{
|
|
122
|
+
questionId: "visual-style",
|
|
123
|
+
optionId: "figma-link",
|
|
124
|
+
figmaUrl,
|
|
125
|
+
skipped: false,
|
|
126
|
+
delegated: false,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
expect((_b = (_a = submit(" https://www.figma.com/design/AbC123/App ").data) === null || _a === void 0 ? void 0 : _a.answers[0]) === null || _b === void 0 ? void 0 : _b.figmaUrl).toBe("https://www.figma.com/design/AbC123/App");
|
|
131
|
+
expect(submit("https://example.com/design/AbC123").success).toBe(false);
|
|
132
|
+
expect(submit("").success).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe("parseFigmaFileUrl", () => {
|
|
136
|
+
it.each([
|
|
137
|
+
"https://www.figma.com/design/AbC123/My-App?node-id=1-2",
|
|
138
|
+
"https://figma.com/file/AbC123/Old-Style",
|
|
139
|
+
" https://www.figma.com/proto/AbC123/Flow ",
|
|
140
|
+
])("accepts %s", (value) => {
|
|
141
|
+
expect(parseFigmaFileUrl(value)).toBe(new URL(value.trim()).href);
|
|
142
|
+
});
|
|
143
|
+
it.each([
|
|
144
|
+
"",
|
|
145
|
+
"not a url",
|
|
146
|
+
"http://www.figma.com/design/AbC123/My-App",
|
|
147
|
+
"https://evil.com/figma.com/design/AbC123",
|
|
148
|
+
"https://www.figma.com.evil.com/design/AbC123",
|
|
149
|
+
"https://www.figma.com/community/file/123",
|
|
150
|
+
"https://www.figma.com/design/",
|
|
151
|
+
"https://user:pass@www.figma.com/design/AbC123",
|
|
152
|
+
"https://www.figma.com:8443/design/AbC123",
|
|
153
|
+
"javascript:alert(1)",
|
|
154
|
+
])("rejects %j", (value) => {
|
|
155
|
+
expect(parseFigmaFileUrl(value)).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("mentionsFigmaFileUrl", () => {
|
|
159
|
+
it.each([
|
|
160
|
+
"Build this https://www.figma.com/design/AbC123/My-App please",
|
|
161
|
+
"from figma.com/file/AbC123",
|
|
162
|
+
"(https://figma.com/proto/AbC123)",
|
|
163
|
+
])("finds a link in %j", (text) => {
|
|
164
|
+
expect(mentionsFigmaFileUrl(text)).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
it.each([
|
|
167
|
+
"Make it look like our Figma mockups",
|
|
168
|
+
"https://notfigma.com/design/AbC123",
|
|
169
|
+
"https://www.figma.com/community",
|
|
170
|
+
"https://evil.com/figma.com/design/AbC123",
|
|
171
|
+
"https://evil.com/?next=//figma.com/design/AbC123",
|
|
172
|
+
"user@figma.com/design/AbC123",
|
|
173
|
+
])("finds nothing in %j", (text) => {
|
|
174
|
+
expect(mentionsFigmaFileUrl(text)).toBe(false);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe("findFigmaFileUrl", () => {
|
|
178
|
+
it.each([
|
|
179
|
+
[
|
|
180
|
+
"Build this https://www.figma.com/design/AbC123/App?node-id=1-2.",
|
|
181
|
+
"https://www.figma.com/design/AbC123/App?node-id=1-2",
|
|
182
|
+
],
|
|
183
|
+
[
|
|
184
|
+
"from figma.com/file/AbC123/Old, thanks",
|
|
185
|
+
"https://figma.com/file/AbC123/Old",
|
|
186
|
+
],
|
|
187
|
+
[
|
|
188
|
+
"(http://www.figma.com/proto/AbC123/Flow)",
|
|
189
|
+
"https://www.figma.com/proto/AbC123/Flow",
|
|
190
|
+
],
|
|
191
|
+
[
|
|
192
|
+
"first https://www.figma.com/design/One/A then https://www.figma.com/design/Two/B",
|
|
193
|
+
"https://www.figma.com/design/One/A",
|
|
194
|
+
],
|
|
195
|
+
])("reads the link out of %j", (text, expected) => {
|
|
196
|
+
expect(findFigmaFileUrl(text)).toBe(expected);
|
|
197
|
+
});
|
|
198
|
+
it("finds nothing without a file link", () => {
|
|
199
|
+
expect(findFigmaFileUrl("Make it like our Figma mockups")).toBeUndefined();
|
|
200
|
+
});
|
|
115
201
|
});
|
|
116
202
|
describe("matchesAgentNativeStarter", () => {
|
|
117
203
|
it("matches when repoName is the starter", () => {
|
package/src/single-tenancy.d.ts
CHANGED
|
@@ -56,7 +56,13 @@ export interface PrivateLinkEndpoint {
|
|
|
56
56
|
*/
|
|
57
57
|
export interface VpcAwsPrivateLink extends VpcConnectionBase {
|
|
58
58
|
type: "aws-privatelink";
|
|
59
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* The region the customer's Endpoint Service lives in, as embedded in each
|
|
61
|
+
* `endpoints[].serviceName`. May differ from {@link BUILDER_AWS_REGION}: the
|
|
62
|
+
* interface endpoints always live in Builder's region and reach a remote
|
|
63
|
+
* service via cross-region PrivateLink (`service_region` in aws-vpc-module).
|
|
64
|
+
* Every endpoint in one config shares this region.
|
|
65
|
+
*/
|
|
60
66
|
awsRegion: string;
|
|
61
67
|
endpoints: PrivateLinkEndpoint[];
|
|
62
68
|
/**
|
|
@@ -219,11 +225,18 @@ export interface SingleTenancyDerivedNames {
|
|
|
219
225
|
privateLinkEndpointIps?: Record<string, string[]>;
|
|
220
226
|
}
|
|
221
227
|
/**
|
|
222
|
-
* The
|
|
223
|
-
*
|
|
224
|
-
* Service in another region is
|
|
228
|
+
* The region Builder's PrivateLink interface endpoints run in. Keep in sync with
|
|
229
|
+
* the `aws` provider region in packages/terraform/main.tf. A customer's Endpoint
|
|
230
|
+
* Service in another region is still reachable via cross-region PrivateLink (the
|
|
231
|
+
* endpoint names it through `service_region`); this constant is only the
|
|
232
|
+
* *consumer* region where our endpoints and their pinned IPs live.
|
|
225
233
|
*/
|
|
226
234
|
export declare const BUILDER_AWS_REGION = "us-east-1";
|
|
235
|
+
/**
|
|
236
|
+
* AWS region id (e.g. `us-east-1`, `eu-west-2`, `ap-southeast-3`). Used to
|
|
237
|
+
* validate a config's declared service region for cross-region PrivateLink.
|
|
238
|
+
*/
|
|
239
|
+
export declare const AWS_REGION_RE: RegExp;
|
|
227
240
|
/**
|
|
228
241
|
* AWS-generated VPC Endpoint Service name: `com.amazonaws.vpce.<region>.vpce-svc-<id>`.
|
|
229
242
|
* The id is 8 or 17 hex chars — AWS resource ids are never a length in between.
|
package/src/single-tenancy.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
4
|
-
* Service in another region is
|
|
2
|
+
* The region Builder's PrivateLink interface endpoints run in. Keep in sync with
|
|
3
|
+
* the `aws` provider region in packages/terraform/main.tf. A customer's Endpoint
|
|
4
|
+
* Service in another region is still reachable via cross-region PrivateLink (the
|
|
5
|
+
* endpoint names it through `service_region`); this constant is only the
|
|
6
|
+
* *consumer* region where our endpoints and their pinned IPs live.
|
|
5
7
|
*/
|
|
6
8
|
export const BUILDER_AWS_REGION = "us-east-1";
|
|
9
|
+
/**
|
|
10
|
+
* AWS region id (e.g. `us-east-1`, `eu-west-2`, `ap-southeast-3`). Used to
|
|
11
|
+
* validate a config's declared service region for cross-region PrivateLink.
|
|
12
|
+
*/
|
|
13
|
+
export const AWS_REGION_RE = /^[a-z]{2}-[a-z]+-\d$/;
|
|
7
14
|
/**
|
|
8
15
|
* AWS-generated VPC Endpoint Service name: `com.amazonaws.vpce.<region>.vpce-svc-<id>`.
|
|
9
16
|
* The id is 8 or 17 hex chars — AWS resource ids are never a length in between.
|