siteplane 0.1.41 → 0.1.43
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/README.md +30 -1
- package/dist/bin/siteplane.js +2033 -417
- package/dist/index.js +1280 -363
- package/dist/next.js +1464 -382
- package/package.json +4 -1
package/dist/next.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// src/next.ts
|
|
2
|
-
import { execFile as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { execFile as execFile4 } from "child_process";
|
|
3
|
+
import { createHash as createHash5 } from "crypto";
|
|
4
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
5
|
+
import { dirname as dirname9, join as join12, resolve as resolve4 } from "path";
|
|
6
|
+
import { promisify as promisify4 } from "util";
|
|
6
7
|
|
|
7
8
|
// ../cli/dist/analytics/manifest.js
|
|
8
9
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -822,7 +823,7 @@ var bookingManifestSchema = z8.object({
|
|
|
822
823
|
var BOOKING_CREATE_PAYLOAD_LIMIT_BYTES = 16 * 1024;
|
|
823
824
|
|
|
824
825
|
// ../shared/dist/bridge-protocol.js
|
|
825
|
-
import { z as
|
|
826
|
+
import { z as z16 } from "zod";
|
|
826
827
|
|
|
827
828
|
// ../shared/dist/field-id.js
|
|
828
829
|
import { z as z9 } from "zod";
|
|
@@ -869,21 +870,70 @@ var imageValueSchema = z11.object({
|
|
|
869
870
|
]).optional()
|
|
870
871
|
});
|
|
871
872
|
|
|
873
|
+
// ../shared/dist/setup-deployment.js
|
|
874
|
+
import { z as z12 } from "zod";
|
|
875
|
+
var version = z12.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u);
|
|
876
|
+
var hash = z12.string().regex(/^sha256:[0-9a-f]{64}$/u);
|
|
877
|
+
var setupDeploymentRecordSchema = z12.object({
|
|
878
|
+
version: z12.literal(1),
|
|
879
|
+
operationId: z12.string().uuid(),
|
|
880
|
+
provider: z12.literal("vercel"),
|
|
881
|
+
projectId: z12.string().regex(/^prj_[A-Za-z0-9]+$/u),
|
|
882
|
+
teamId: z12.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u),
|
|
883
|
+
origin: z12.string().url().refine((value) => {
|
|
884
|
+
const url = new URL(value);
|
|
885
|
+
return url.protocol === "https:" && url.origin === value && !url.username && !url.password;
|
|
886
|
+
}),
|
|
887
|
+
deploymentId: z12.string().regex(/^dpl_[A-Za-z0-9]+$/u).nullable(),
|
|
888
|
+
revision: z12.string().regex(/^[0-9a-f]{40}$/u),
|
|
889
|
+
fieldContractHash: hash,
|
|
890
|
+
packages: z12.object({ siteplane: version, runtimeNext: version }).strict(),
|
|
891
|
+
configurationFingerprint: hash,
|
|
892
|
+
adminSecretGeneration: z12.string().uuid(),
|
|
893
|
+
revalidationGeneration: z12.number().int().positive(),
|
|
894
|
+
startedAt: z12.string().datetime(),
|
|
895
|
+
environmentWrittenAt: z12.string().datetime().nullable(),
|
|
896
|
+
deployRequestedAt: z12.string().datetime().nullable(),
|
|
897
|
+
deadline: z12.string().datetime(),
|
|
898
|
+
phase: z12.enum([
|
|
899
|
+
"planned",
|
|
900
|
+
"environment_written",
|
|
901
|
+
"deploy_requested",
|
|
902
|
+
"deployed",
|
|
903
|
+
"verified",
|
|
904
|
+
"failed"
|
|
905
|
+
]),
|
|
906
|
+
build: z12.object({
|
|
907
|
+
node: version,
|
|
908
|
+
packageManager: z12.enum(["npm", "pnpm"]),
|
|
909
|
+
packageManagerVersion: version,
|
|
910
|
+
lockfileHash: hash
|
|
911
|
+
}).strict().nullable()
|
|
912
|
+
}).strict();
|
|
913
|
+
var setupDeploymentInputSchema = z12.discriminatedUnion("action", [
|
|
914
|
+
z12.object({ action: z12.literal("read") }).strict(),
|
|
915
|
+
z12.object({
|
|
916
|
+
action: z12.literal("record"),
|
|
917
|
+
expectedOperationId: z12.string().uuid().nullable(),
|
|
918
|
+
record: setupDeploymentRecordSchema
|
|
919
|
+
}).strict()
|
|
920
|
+
]);
|
|
921
|
+
|
|
872
922
|
// ../shared/dist/site-setup.js
|
|
873
|
-
import { z as
|
|
923
|
+
import { z as z15 } from "zod";
|
|
874
924
|
|
|
875
925
|
// ../shared/dist/site-field-contract.js
|
|
876
|
-
import { z as
|
|
926
|
+
import { z as z14 } from "zod";
|
|
877
927
|
|
|
878
928
|
// ../shared/dist/fallback-hash.js
|
|
879
|
-
import { z as
|
|
929
|
+
import { z as z13 } from "zod";
|
|
880
930
|
var SAFE_REPRESENTATION_REASONS = [
|
|
881
931
|
"asset_import_rewritten",
|
|
882
932
|
"relative_url_normalized",
|
|
883
933
|
"line_endings_normalized",
|
|
884
934
|
"image_value_serialized"
|
|
885
935
|
];
|
|
886
|
-
var safeRepresentationReasonSchema =
|
|
936
|
+
var safeRepresentationReasonSchema = z13.enum(SAFE_REPRESENTATION_REASONS);
|
|
887
937
|
function canonicalizeFallbackValue(input) {
|
|
888
938
|
const fieldType = fieldTypeSchema.parse(input.fieldType);
|
|
889
939
|
if (input.safeRepresentationReason !== void 0) {
|
|
@@ -919,10 +969,10 @@ function createCanonicalFallbackHash(input) {
|
|
|
919
969
|
const payload = stableJsonStringify(canonical);
|
|
920
970
|
return `sha256:${sha256Hex(payload)}`;
|
|
921
971
|
}
|
|
922
|
-
var linkFallbackSchema =
|
|
923
|
-
href:
|
|
924
|
-
label:
|
|
925
|
-
target:
|
|
972
|
+
var linkFallbackSchema = z13.object({
|
|
973
|
+
href: z13.string().trim().min(1),
|
|
974
|
+
label: z13.string().trim().min(1).optional(),
|
|
975
|
+
target: z13.enum(["_self", "_blank"]).optional()
|
|
926
976
|
}).passthrough();
|
|
927
977
|
function normalizeLineEndings(value) {
|
|
928
978
|
return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
@@ -1100,67 +1150,67 @@ var SHA256_CONSTANTS = [
|
|
|
1100
1150
|
// ../shared/dist/site-field-contract.js
|
|
1101
1151
|
var fieldContractVersion = "1.0.0";
|
|
1102
1152
|
var scannerContractVersion = "1.0.0";
|
|
1103
|
-
var siteFieldStatusSchema =
|
|
1104
|
-
var semanticVersionSchema =
|
|
1105
|
-
var siteFieldRouteKeySchema =
|
|
1106
|
-
var repositoryRelativePosixPathSchema =
|
|
1107
|
-
var sourceMappingSchema =
|
|
1108
|
-
kind:
|
|
1153
|
+
var siteFieldStatusSchema = z14.enum(["hidden", "active"]);
|
|
1154
|
+
var semanticVersionSchema = z14.string().regex(/^\d+\.\d+\.\d+$/u);
|
|
1155
|
+
var siteFieldRouteKeySchema = z14.string().trim().refine((value) => value === "$global" || value.startsWith("/") && !value.includes("?") && !value.includes("#") && (value === "/" || !value.endsWith("/")), "Route keys must be canonical paths or $global.");
|
|
1156
|
+
var repositoryRelativePosixPathSchema = z14.string().trim().min(1).refine((value) => !value.startsWith("/") && !value.includes("\\") && !/^[a-z]:/iu.test(value) && !value.split("/").includes(".."), "Source paths must be repository-relative POSIX paths.");
|
|
1157
|
+
var sourceMappingSchema = z14.object({
|
|
1158
|
+
kind: z14.literal("function"),
|
|
1109
1159
|
filePath: repositoryRelativePosixPathSchema,
|
|
1110
|
-
exportName:
|
|
1111
|
-
sourcePath:
|
|
1160
|
+
exportName: z14.string().trim().min(1).optional(),
|
|
1161
|
+
sourcePath: z14.string().trim().min(1).optional(),
|
|
1112
1162
|
editTarget: fieldIdSchema.optional()
|
|
1113
1163
|
}).strict();
|
|
1114
|
-
var domMappingSchema =
|
|
1115
|
-
attribute:
|
|
1116
|
-
previewStrategy:
|
|
1164
|
+
var domMappingSchema = z14.object({
|
|
1165
|
+
attribute: z14.literal("data-siteplane-field-id"),
|
|
1166
|
+
previewStrategy: z14.enum(["dom", "event"])
|
|
1117
1167
|
}).strict();
|
|
1118
|
-
var fieldBaseSchema =
|
|
1168
|
+
var fieldBaseSchema = z14.object({
|
|
1119
1169
|
fieldId: fieldIdSchema,
|
|
1120
1170
|
routeKey: siteFieldRouteKeySchema,
|
|
1121
1171
|
source: sourceMappingSchema,
|
|
1122
1172
|
dom: domMappingSchema.optional()
|
|
1123
1173
|
}).strict();
|
|
1124
|
-
var linkFallbackSchema2 =
|
|
1125
|
-
href:
|
|
1126
|
-
label:
|
|
1127
|
-
target:
|
|
1174
|
+
var linkFallbackSchema2 = z14.object({
|
|
1175
|
+
href: z14.string().trim().min(1),
|
|
1176
|
+
label: z14.string().trim().min(1).optional(),
|
|
1177
|
+
target: z14.enum(["_self", "_blank"]).optional()
|
|
1128
1178
|
}).strict();
|
|
1129
|
-
var imageFallbackSchema =
|
|
1130
|
-
src:
|
|
1131
|
-
alt:
|
|
1132
|
-
width:
|
|
1133
|
-
height:
|
|
1134
|
-
crop:
|
|
1135
|
-
x:
|
|
1136
|
-
y:
|
|
1137
|
-
zoom:
|
|
1138
|
-
aspectRatio:
|
|
1179
|
+
var imageFallbackSchema = z14.object({
|
|
1180
|
+
src: z14.string().trim().min(1),
|
|
1181
|
+
alt: z14.string().trim().max(300),
|
|
1182
|
+
width: z14.number().int().positive().optional(),
|
|
1183
|
+
height: z14.number().int().positive().optional(),
|
|
1184
|
+
crop: z14.object({
|
|
1185
|
+
x: z14.number().min(0).max(100),
|
|
1186
|
+
y: z14.number().min(0).max(100),
|
|
1187
|
+
zoom: z14.number().min(1).max(4),
|
|
1188
|
+
aspectRatio: z14.number().positive().max(10)
|
|
1139
1189
|
}).strict().optional()
|
|
1140
1190
|
}).strict();
|
|
1141
|
-
var siteFieldContractFieldSchema =
|
|
1191
|
+
var siteFieldContractFieldSchema = z14.discriminatedUnion("fieldType", [
|
|
1142
1192
|
fieldBaseSchema.extend({
|
|
1143
|
-
fieldType:
|
|
1144
|
-
fallback:
|
|
1193
|
+
fieldType: z14.literal("text"),
|
|
1194
|
+
fallback: z14.string()
|
|
1145
1195
|
}),
|
|
1146
1196
|
fieldBaseSchema.extend({
|
|
1147
|
-
fieldType:
|
|
1148
|
-
fallback:
|
|
1197
|
+
fieldType: z14.literal("longText"),
|
|
1198
|
+
fallback: z14.string()
|
|
1149
1199
|
}),
|
|
1150
1200
|
fieldBaseSchema.extend({
|
|
1151
|
-
fieldType:
|
|
1201
|
+
fieldType: z14.literal("link"),
|
|
1152
1202
|
fallback: linkFallbackSchema2
|
|
1153
1203
|
}),
|
|
1154
1204
|
fieldBaseSchema.extend({
|
|
1155
|
-
fieldType:
|
|
1205
|
+
fieldType: z14.literal("image"),
|
|
1156
1206
|
fallback: imageFallbackSchema
|
|
1157
1207
|
})
|
|
1158
1208
|
]);
|
|
1159
|
-
var siteFieldContractV1Schema =
|
|
1160
|
-
version:
|
|
1209
|
+
var siteFieldContractV1Schema = z14.object({
|
|
1210
|
+
version: z14.literal(1),
|
|
1161
1211
|
fieldContractVersion: semanticVersionSchema,
|
|
1162
1212
|
scannerContractVersion: semanticVersionSchema,
|
|
1163
|
-
fields:
|
|
1213
|
+
fields: z14.array(siteFieldContractFieldSchema)
|
|
1164
1214
|
}).strict().superRefine((contract, context) => {
|
|
1165
1215
|
const seen = /* @__PURE__ */ new Set();
|
|
1166
1216
|
for (const [index, field] of contract.fields.entries()) {
|
|
@@ -1220,55 +1270,20 @@ var SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH = 2e3;
|
|
|
1220
1270
|
var SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES = 8e3;
|
|
1221
1271
|
var CONTINUE_SITE_SETUP_ITEMS_MAX_BYTES = 32 * 1024;
|
|
1222
1272
|
var CONTINUE_SITE_SETUP_HTTP_BODY_MAX_BYTES = 64 * 1024;
|
|
1223
|
-
var siteSetupRunStatusSchema =
|
|
1224
|
-
var siteSetupRunModeSchema =
|
|
1225
|
-
var siteSetupErrorCodeSchema =
|
|
1226
|
-
var
|
|
1227
|
-
contractVersion: z14.literal("siteplane.setup-task.v1"),
|
|
1228
|
-
workflow: z14.enum(["initial_setup", "structure_update"]),
|
|
1229
|
-
goal: z14.string().min(1),
|
|
1230
|
-
modules: z14.tuple([z14.literal("visual_editor")]),
|
|
1231
|
-
packages: z14.object({
|
|
1232
|
-
siteplane: z14.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
|
|
1233
|
-
runtimeNext: z14.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
|
|
1234
|
-
}).strict(),
|
|
1235
|
-
communication: z14.object({
|
|
1236
|
-
beforeSourceChanges: z14.string().min(1),
|
|
1237
|
-
updates: z14.array(z14.string().min(1)).min(1),
|
|
1238
|
-
blocker: z14.string().min(1)
|
|
1239
|
-
}).strict(),
|
|
1240
|
-
discovery: z14.object({
|
|
1241
|
-
inspectPublicRoutes: z14.boolean(),
|
|
1242
|
-
contentKinds: z14.array(z14.enum(["text", "longText", "link", "image"])).min(1),
|
|
1243
|
-
rules: z14.array(z14.string().min(1)).min(1)
|
|
1244
|
-
}).strict(),
|
|
1245
|
-
steps: z14.array(z14.object({
|
|
1246
|
-
id: z14.enum([
|
|
1247
|
-
"inspect_repository",
|
|
1248
|
-
"install_packages",
|
|
1249
|
-
"instrument_fields",
|
|
1250
|
-
"apply_contract",
|
|
1251
|
-
"deploy_production",
|
|
1252
|
-
"verify_deployment"
|
|
1253
|
-
]),
|
|
1254
|
-
instruction: z14.string().min(1)
|
|
1255
|
-
}).strict()).length(6),
|
|
1256
|
-
completion: z14.object({
|
|
1257
|
-
verifiedStatus: z14.literal("ready_for_review"),
|
|
1258
|
-
instruction: z14.string().min(1)
|
|
1259
|
-
}).strict()
|
|
1260
|
-
}).strict();
|
|
1261
|
-
var editorFieldSchema = z14.object({
|
|
1273
|
+
var siteSetupRunStatusSchema = z15.enum(SITE_SETUP_RUN_STATUSES);
|
|
1274
|
+
var siteSetupRunModeSchema = z15.enum(SITE_SETUP_RUN_MODES);
|
|
1275
|
+
var siteSetupErrorCodeSchema = z15.enum(SITE_SETUP_ERROR_CODES);
|
|
1276
|
+
var editorFieldSchema = z15.object({
|
|
1262
1277
|
fieldId: fieldIdSchema,
|
|
1263
|
-
label:
|
|
1264
|
-
subsection:
|
|
1265
|
-
description:
|
|
1266
|
-
required:
|
|
1267
|
-
maxLength:
|
|
1278
|
+
label: z15.string().trim().min(1),
|
|
1279
|
+
subsection: z15.string().trim().min(1).optional(),
|
|
1280
|
+
description: z15.string().trim().min(1).optional(),
|
|
1281
|
+
required: z15.boolean().optional(),
|
|
1282
|
+
maxLength: z15.number().int().positive().optional()
|
|
1268
1283
|
}).strict();
|
|
1269
|
-
var editorSectionSchema =
|
|
1270
|
-
label:
|
|
1271
|
-
fields:
|
|
1284
|
+
var editorSectionSchema = z15.object({
|
|
1285
|
+
label: z15.string().trim().min(1),
|
|
1286
|
+
fields: z15.array(editorFieldSchema).min(1)
|
|
1272
1287
|
}).strict().superRefine((section, context) => {
|
|
1273
1288
|
const closedSubsections = /* @__PURE__ */ new Set();
|
|
1274
1289
|
let currentSubsection;
|
|
@@ -1287,10 +1302,10 @@ var editorSectionSchema = z14.object({
|
|
|
1287
1302
|
}
|
|
1288
1303
|
}
|
|
1289
1304
|
});
|
|
1290
|
-
var editorRouteSchema =
|
|
1305
|
+
var editorRouteSchema = z15.object({
|
|
1291
1306
|
routeKey: siteFieldRouteKeySchema,
|
|
1292
|
-
label:
|
|
1293
|
-
sections:
|
|
1307
|
+
label: z15.string().trim().min(1),
|
|
1308
|
+
sections: z15.array(editorSectionSchema).min(1)
|
|
1294
1309
|
}).strict().superRefine((route, context) => {
|
|
1295
1310
|
const sections = /* @__PURE__ */ new Set();
|
|
1296
1311
|
for (const [index, section] of route.sections.entries()) {
|
|
@@ -1304,9 +1319,9 @@ var editorRouteSchema = z14.object({
|
|
|
1304
1319
|
sections.add(section.label);
|
|
1305
1320
|
}
|
|
1306
1321
|
});
|
|
1307
|
-
var editorDefinitionV1Schema =
|
|
1308
|
-
version:
|
|
1309
|
-
routes:
|
|
1322
|
+
var editorDefinitionV1Schema = z15.object({
|
|
1323
|
+
version: z15.literal(1),
|
|
1324
|
+
routes: z15.array(editorRouteSchema).min(1)
|
|
1310
1325
|
}).strict().superRefine((definition, context) => {
|
|
1311
1326
|
const routes = /* @__PURE__ */ new Set();
|
|
1312
1327
|
const fields = /* @__PURE__ */ new Set();
|
|
@@ -1344,7 +1359,7 @@ var editorDefinitionV1Schema = z14.object({
|
|
|
1344
1359
|
var forbiddenControlOrBidi = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
|
|
1345
1360
|
var forbiddenOwnerNoteControlOrBidi = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
|
|
1346
1361
|
var unsafeLocator = /<\/?[a-z][^>]*>|\b(?:javascript|data:text\/html)\s*:|\bon[a-z]+\s*=/iu;
|
|
1347
|
-
var renderedPathSchema =
|
|
1362
|
+
var renderedPathSchema = z15.string().trim().transform((value) => value !== "/" ? value.replace(/\/+$/u, "") : value).superRefine((value, context) => {
|
|
1348
1363
|
if (!value.startsWith("/") || value === "$global" || value.includes("?") || value.includes("#")) {
|
|
1349
1364
|
context.addIssue({
|
|
1350
1365
|
code: "custom",
|
|
@@ -1354,7 +1369,7 @@ var renderedPathSchema = z14.string().trim().transform((value) => value !== "/"
|
|
|
1354
1369
|
addSafeByteIssues(value, CONTINUE_SITE_SETUP_RENDERED_PATH_MAX_BYTES, "renderedPath", context);
|
|
1355
1370
|
});
|
|
1356
1371
|
function normalizedSafeTextSchema(maxBytes, label) {
|
|
1357
|
-
return
|
|
1372
|
+
return z15.string().transform((value) => value.trim().replace(new RegExp("\\p{White_Space}+", "gu"), " ")).pipe(z15.string().min(1)).superRefine((value, context) => {
|
|
1358
1373
|
addSafeByteIssues(value, maxBytes, label, context);
|
|
1359
1374
|
if (label === "locatorHint" && unsafeLocator.test(value)) {
|
|
1360
1375
|
context.addIssue({
|
|
@@ -1371,12 +1386,12 @@ var correctionItemBase = {
|
|
|
1371
1386
|
requestedLabel: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_LABEL_MAX_BYTES, "requestedLabel").optional(),
|
|
1372
1387
|
requestedSection: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_SECTION_MAX_BYTES, "requestedSection").optional(),
|
|
1373
1388
|
requestedSubsection: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_SUBSECTION_MAX_BYTES, "requestedSubsection").optional(),
|
|
1374
|
-
requestedSortOrder:
|
|
1389
|
+
requestedSortOrder: z15.number().int().nonnegative().optional()
|
|
1375
1390
|
};
|
|
1376
|
-
var setupCorrectionItemSchema =
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1391
|
+
var setupCorrectionItemSchema = z15.discriminatedUnion("kind", [
|
|
1392
|
+
z15.object({ kind: z15.literal("text"), ...correctionItemBase }).strict(),
|
|
1393
|
+
z15.object({ kind: z15.literal("link"), ...correctionItemBase }).strict(),
|
|
1394
|
+
z15.object({ kind: z15.literal("image"), ...correctionItemBase }).strict()
|
|
1380
1395
|
]).superRefine((item, context) => {
|
|
1381
1396
|
if (item.requestedSubsection && !item.requestedSection) {
|
|
1382
1397
|
context.addIssue({
|
|
@@ -1386,7 +1401,7 @@ var setupCorrectionItemSchema = z14.discriminatedUnion("kind", [
|
|
|
1386
1401
|
});
|
|
1387
1402
|
}
|
|
1388
1403
|
});
|
|
1389
|
-
var setupCorrectionItemsSchema =
|
|
1404
|
+
var setupCorrectionItemsSchema = z15.array(setupCorrectionItemSchema).max(CONTINUE_SITE_SETUP_MAX_ITEMS).superRefine((items, context) => {
|
|
1390
1405
|
const bytes = utf8Bytes(stableJsonStringify(items));
|
|
1391
1406
|
if (bytes > CONTINUE_SITE_SETUP_ITEMS_MAX_BYTES) {
|
|
1392
1407
|
context.addIssue({
|
|
@@ -1395,7 +1410,7 @@ var setupCorrectionItemsSchema = z14.array(setupCorrectionItemSchema).max(CONTIN
|
|
|
1395
1410
|
});
|
|
1396
1411
|
}
|
|
1397
1412
|
});
|
|
1398
|
-
var siteSetupOwnerEditabilityNoteSchema =
|
|
1413
|
+
var siteSetupOwnerEditabilityNoteSchema = z15.string().max(SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH).superRefine((value, context) => {
|
|
1399
1414
|
if (utf8Bytes(value) > SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES) {
|
|
1400
1415
|
context.addIssue({
|
|
1401
1416
|
code: "custom",
|
|
@@ -1409,27 +1424,190 @@ var siteSetupOwnerEditabilityNoteSchema = z14.string().trim().max(SITE_SETUP_OWN
|
|
|
1409
1424
|
});
|
|
1410
1425
|
}
|
|
1411
1426
|
});
|
|
1412
|
-
var
|
|
1427
|
+
var SITE_SETUP_MODULE_SCOPES = {
|
|
1428
|
+
editing: ["setup:read", "setup:write"],
|
|
1429
|
+
analytics: [
|
|
1430
|
+
"analytics:setup",
|
|
1431
|
+
"analytics:sync",
|
|
1432
|
+
"analytics:test",
|
|
1433
|
+
"analytics:readiness",
|
|
1434
|
+
"analytics:agent_instructions",
|
|
1435
|
+
"analytics:public_key_read"
|
|
1436
|
+
]
|
|
1437
|
+
};
|
|
1438
|
+
var siteSetupModulesSchema = z15.array(z15.enum(["editing", "analytics"])).min(1).max(2).refine((modules) => modules[0] === "editing" && (modules.length === 1 || modules[1] === "analytics"), "Choose Editing with optional Analytics.");
|
|
1439
|
+
function siteSetupScopes(modules) {
|
|
1440
|
+
return modules.flatMap((module) => [...SITE_SETUP_MODULE_SCOPES[module]]);
|
|
1441
|
+
}
|
|
1442
|
+
function hasExactSiteSetupScopes(scopes, modules) {
|
|
1443
|
+
const matches = (expected) => scopes.length === expected.length && expected.every((scope) => scopes.includes(scope));
|
|
1444
|
+
return modules ? matches(siteSetupScopes(modules)) : matches(siteSetupScopes(["editing"])) || matches(siteSetupScopes(["editing", "analytics"]));
|
|
1445
|
+
}
|
|
1446
|
+
var siteSetupActivityInputSchema = z15.object({
|
|
1447
|
+
phase: z15.enum([
|
|
1448
|
+
"inspecting",
|
|
1449
|
+
"integrating",
|
|
1450
|
+
"deploying",
|
|
1451
|
+
"verifying",
|
|
1452
|
+
"repairing"
|
|
1453
|
+
]),
|
|
1454
|
+
textId: z15.enum([
|
|
1455
|
+
"inspecting",
|
|
1456
|
+
"integrating",
|
|
1457
|
+
"deploying",
|
|
1458
|
+
"verifying",
|
|
1459
|
+
"repairing"
|
|
1460
|
+
])
|
|
1461
|
+
}).strict().refine((value) => value.phase === value.textId, "Activity text must describe its phase.");
|
|
1462
|
+
var nextActionFields = {
|
|
1463
|
+
actor: z15.enum(["agent", "user", "siteplane"]),
|
|
1464
|
+
boundary: z15.enum([
|
|
1465
|
+
"source",
|
|
1466
|
+
"environment",
|
|
1467
|
+
"deployment",
|
|
1468
|
+
"verification",
|
|
1469
|
+
"authorization",
|
|
1470
|
+
"review"
|
|
1471
|
+
]),
|
|
1472
|
+
precondition: z15.string().min(1).max(1e3),
|
|
1473
|
+
instruction: z15.string().min(1).max(2e3),
|
|
1474
|
+
expectedEvidence: z15.string().min(1).max(1e3)
|
|
1475
|
+
};
|
|
1476
|
+
var siteSetupNextActionSchema = z15.discriminatedUnion("kind", [
|
|
1477
|
+
z15.object({
|
|
1478
|
+
...nextActionFields,
|
|
1479
|
+
kind: z15.literal("run_command"),
|
|
1480
|
+
command: z15.string().min(1).max(500)
|
|
1481
|
+
}).strict(),
|
|
1482
|
+
z15.object({ ...nextActionFields, kind: z15.literal("agent_edit") }).strict(),
|
|
1483
|
+
z15.object({ ...nextActionFields, kind: z15.literal("needs_user_action") }).strict(),
|
|
1484
|
+
z15.object({ ...nextActionFields, kind: z15.literal("wait") }).strict(),
|
|
1485
|
+
z15.object({ ...nextActionFields, kind: z15.literal("done") }).strict()
|
|
1486
|
+
]);
|
|
1487
|
+
var siteSetupTaskRunSchema = z15.object({
|
|
1488
|
+
runId: z15.string().uuid(),
|
|
1489
|
+
mode: siteSetupRunModeSchema,
|
|
1490
|
+
status: siteSetupRunStatusSchema,
|
|
1491
|
+
fieldContractHash: z15.string().nullable(),
|
|
1492
|
+
deploymentOrigin: z15.string().url().nullable(),
|
|
1493
|
+
deploymentRevision: z15.string().nullable(),
|
|
1494
|
+
publicRuntimeKeyId: z15.string().uuid().nullable(),
|
|
1495
|
+
reviewVersion: z15.string().nullable()
|
|
1496
|
+
}).strict();
|
|
1497
|
+
var siteSetupTaskProgressSchema = z15.object({
|
|
1498
|
+
progressStage: z15.enum([
|
|
1499
|
+
"waiting_for_connection",
|
|
1500
|
+
"agent_connected",
|
|
1501
|
+
"project_context_loaded",
|
|
1502
|
+
"fields_prepared",
|
|
1503
|
+
"deployment_verification",
|
|
1504
|
+
"ready_for_review",
|
|
1505
|
+
"action_required",
|
|
1506
|
+
"completed"
|
|
1507
|
+
]),
|
|
1508
|
+
lastVerifiedAt: z15.string().datetime().nullable(),
|
|
1509
|
+
lastActivityAt: z15.string().datetime(),
|
|
1510
|
+
activitySource: z15.enum(["user", "server", "agent"]),
|
|
1511
|
+
activityPhase: siteSetupActivityInputSchema.shape.phase.nullable(),
|
|
1512
|
+
activityTextId: siteSetupActivityInputSchema.shape.textId.nullable()
|
|
1513
|
+
}).strict();
|
|
1514
|
+
var siteSetupTaskSchema = z15.object({
|
|
1515
|
+
contractVersion: z15.literal("siteplane.setup-task.v2"),
|
|
1516
|
+
workflow: z15.enum(["initial_setup", "structure_update"]),
|
|
1517
|
+
goal: z15.string().min(1),
|
|
1518
|
+
modules: siteSetupModulesSchema,
|
|
1519
|
+
authorizationVersion: z15.number().int().positive(),
|
|
1520
|
+
authorizedScopes: z15.array(z15.string()).min(2),
|
|
1521
|
+
site: z15.object({
|
|
1522
|
+
siteId: z15.string().uuid(),
|
|
1523
|
+
portalPath: z15.string(),
|
|
1524
|
+
adminOrigin: z15.string().url()
|
|
1525
|
+
}).strict().nullable(),
|
|
1526
|
+
run: siteSetupTaskRunSchema.nullable(),
|
|
1527
|
+
progress: siteSetupTaskProgressSchema.nullable(),
|
|
1528
|
+
deployment: setupDeploymentRecordSchema.nullable(),
|
|
1529
|
+
revalidationGeneration: z15.number().int().positive(),
|
|
1530
|
+
assignment: z15.literal("owned"),
|
|
1531
|
+
deadline: z15.string().datetime().nullable(),
|
|
1532
|
+
userInstructions: z15.object({
|
|
1533
|
+
text: siteSetupOwnerEditabilityNoteSchema,
|
|
1534
|
+
source: z15.literal("user"),
|
|
1535
|
+
trust: z15.literal("untrusted")
|
|
1536
|
+
}).strict(),
|
|
1537
|
+
corrections: setupCorrectionItemsSchema,
|
|
1538
|
+
contentSelectionSummary: z15.object({
|
|
1539
|
+
text: siteSetupOwnerEditabilityNoteSchema,
|
|
1540
|
+
source: z15.literal("agent"),
|
|
1541
|
+
trust: z15.literal("untrusted")
|
|
1542
|
+
}).strict().nullable(),
|
|
1543
|
+
environmentBindings: z15.array(z15.object({
|
|
1544
|
+
name: z15.string().regex(/^[A-Z][A-Z0-9_]+$/u),
|
|
1545
|
+
source: z15.string().min(1),
|
|
1546
|
+
sensitivity: z15.enum(["public", "secret"]),
|
|
1547
|
+
usage: z15.enum(["build", "server", "build_and_server"]),
|
|
1548
|
+
evidence: z15.string().min(1)
|
|
1549
|
+
}).strict()),
|
|
1550
|
+
nextAction: siteSetupNextActionSchema,
|
|
1551
|
+
error: z15.object({
|
|
1552
|
+
code: z15.string().regex(/^[a-z0-9_.]+$/u).max(160),
|
|
1553
|
+
boundary: nextActionFields.boundary,
|
|
1554
|
+
responsibleActor: nextActionFields.actor,
|
|
1555
|
+
retryable: z15.boolean(),
|
|
1556
|
+
retryAfter: z15.number().int().nonnegative().nullable(),
|
|
1557
|
+
requestId: z15.string().regex(/^[A-Za-z0-9_-]+$/u).max(128)
|
|
1558
|
+
}).strict().nullable(),
|
|
1559
|
+
packages: z15.object({
|
|
1560
|
+
siteplane: z15.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
|
|
1561
|
+
runtimeNext: z15.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
|
|
1562
|
+
}).strict(),
|
|
1563
|
+
communication: z15.object({
|
|
1564
|
+
beforeSourceChanges: z15.string().min(1),
|
|
1565
|
+
updates: z15.array(z15.string().min(1)).min(1),
|
|
1566
|
+
blocker: z15.string().min(1)
|
|
1567
|
+
}).strict(),
|
|
1568
|
+
discovery: z15.object({
|
|
1569
|
+
inspectPublicRoutes: z15.boolean(),
|
|
1570
|
+
contentKinds: z15.array(z15.enum(["text", "longText", "link", "image"])).min(1),
|
|
1571
|
+
rules: z15.array(z15.string().min(1)).min(1)
|
|
1572
|
+
}).strict(),
|
|
1573
|
+
steps: z15.array(z15.object({
|
|
1574
|
+
id: z15.enum([
|
|
1575
|
+
"inspect_repository",
|
|
1576
|
+
"install_packages",
|
|
1577
|
+
"instrument_fields",
|
|
1578
|
+
"apply_contract",
|
|
1579
|
+
"deploy_production",
|
|
1580
|
+
"verify_deployment"
|
|
1581
|
+
]),
|
|
1582
|
+
instruction: z15.string().min(1)
|
|
1583
|
+
}).strict()).length(6),
|
|
1584
|
+
completion: z15.object({
|
|
1585
|
+
verifiedStatus: z15.literal("ready_for_review"),
|
|
1586
|
+
instruction: z15.string().min(1)
|
|
1587
|
+
}).strict()
|
|
1588
|
+
}).strict().refine((task) => hasExactSiteSetupScopes(task.authorizedScopes, task.modules), "Task scopes must exactly match its modules.");
|
|
1589
|
+
var canonicalHashSchema = z15.string().regex(/^sha256:[0-9a-f]{64}$/iu);
|
|
1413
1590
|
var deploymentRevisionSchema = normalizedSafeTextSchema(256, "deploymentRevision");
|
|
1414
|
-
var continueSiteSetupInputSchema =
|
|
1415
|
-
siteId:
|
|
1416
|
-
runId:
|
|
1591
|
+
var continueSiteSetupInputSchema = z15.object({
|
|
1592
|
+
siteId: z15.string().uuid(),
|
|
1593
|
+
runId: z15.string().uuid(),
|
|
1417
1594
|
expectedFieldContractHash: canonicalHashSchema,
|
|
1418
1595
|
expectedDeploymentRevision: deploymentRevisionSchema,
|
|
1419
1596
|
correctionItems: setupCorrectionItemsSchema,
|
|
1420
1597
|
ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema.optional()
|
|
1421
1598
|
}).strict();
|
|
1422
|
-
var saveSiteSetupOwnerNoteInputSchema =
|
|
1423
|
-
siteId:
|
|
1424
|
-
runId:
|
|
1599
|
+
var saveSiteSetupOwnerNoteInputSchema = z15.object({
|
|
1600
|
+
siteId: z15.string().uuid(),
|
|
1601
|
+
runId: z15.string().uuid(),
|
|
1425
1602
|
expectedFieldContractHash: canonicalHashSchema,
|
|
1426
1603
|
expectedDeploymentRevision: deploymentRevisionSchema,
|
|
1427
1604
|
ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema
|
|
1428
1605
|
}).strict();
|
|
1429
|
-
var siteSetupContextInputSchema =
|
|
1430
|
-
var siteSetupApplyInputSchema =
|
|
1606
|
+
var siteSetupContextInputSchema = z15.object({}).strict();
|
|
1607
|
+
var siteSetupApplyInputSchema = z15.object({
|
|
1431
1608
|
fieldContract: siteFieldContractV1Schema,
|
|
1432
|
-
editorDefinition: editorDefinitionV1Schema
|
|
1609
|
+
editorDefinition: editorDefinitionV1Schema,
|
|
1610
|
+
contentSelectionSummary: siteSetupOwnerEditabilityNoteSchema.refine((text) => text.trim().length > 0, "Describe the selected content, important exclusions and any open gaps.")
|
|
1433
1611
|
}).strict().superRefine((input, context) => {
|
|
1434
1612
|
const contractRoutesByFieldId = new Map(input.fieldContract.fields.map((field) => [
|
|
1435
1613
|
field.fieldId,
|
|
@@ -1493,37 +1671,37 @@ var siteSetupApplyInputSchema = z14.object({
|
|
|
1493
1671
|
}
|
|
1494
1672
|
}
|
|
1495
1673
|
});
|
|
1496
|
-
var siteSetupVerifyInputSchema =
|
|
1497
|
-
deploymentUrl:
|
|
1674
|
+
var siteSetupVerifyInputSchema = z15.object({
|
|
1675
|
+
deploymentUrl: z15.string().url().refine((value) => value.startsWith("https://")),
|
|
1498
1676
|
deploymentRevision: deploymentRevisionSchema,
|
|
1499
|
-
wait:
|
|
1677
|
+
wait: z15.boolean().optional()
|
|
1500
1678
|
}).strict();
|
|
1501
|
-
var siteSetupEvidenceInputSchema =
|
|
1502
|
-
siteId:
|
|
1503
|
-
runId:
|
|
1679
|
+
var siteSetupEvidenceInputSchema = z15.object({
|
|
1680
|
+
siteId: z15.string().uuid(),
|
|
1681
|
+
runId: z15.string().uuid(),
|
|
1504
1682
|
expectedFieldContractHash: canonicalHashSchema,
|
|
1505
|
-
expectedDeploymentOrigin:
|
|
1683
|
+
expectedDeploymentOrigin: z15.string().url().refine((value) => value.startsWith("https://")),
|
|
1506
1684
|
expectedDeploymentRevision: deploymentRevisionSchema,
|
|
1507
|
-
publicRuntimeKeyId:
|
|
1685
|
+
publicRuntimeKeyId: z15.string().uuid(),
|
|
1508
1686
|
bridgeSessionId: normalizedSafeTextSchema(256, "bridgeSessionId"),
|
|
1509
|
-
observations:
|
|
1687
|
+
observations: z15.array(z15.object({
|
|
1510
1688
|
fieldId: fieldIdSchema,
|
|
1511
1689
|
routeKey: siteFieldRouteKeySchema,
|
|
1512
1690
|
renderedPath: renderedPathSchema,
|
|
1513
|
-
targetResolved:
|
|
1514
|
-
previewAck:
|
|
1691
|
+
targetResolved: z15.boolean(),
|
|
1692
|
+
previewAck: z15.boolean()
|
|
1515
1693
|
}).strict().refine((value) => !value.previewAck || value.targetResolved, "Preview ACK requires a resolved target.")).min(1).max(200)
|
|
1516
1694
|
}).strict();
|
|
1517
|
-
var completeSiteSetupInputSchema =
|
|
1518
|
-
siteId:
|
|
1519
|
-
runId:
|
|
1695
|
+
var completeSiteSetupInputSchema = z15.object({
|
|
1696
|
+
siteId: z15.string().uuid(),
|
|
1697
|
+
runId: z15.string().uuid(),
|
|
1520
1698
|
expectedFieldContractHash: canonicalHashSchema,
|
|
1521
1699
|
expectedDeploymentRevision: deploymentRevisionSchema,
|
|
1522
1700
|
expectedReadyFingerprint: canonicalHashSchema
|
|
1523
1701
|
}).strict();
|
|
1524
|
-
var refreshSiteSetupDeploymentInputSchema =
|
|
1525
|
-
siteId:
|
|
1526
|
-
deploymentUrl:
|
|
1702
|
+
var refreshSiteSetupDeploymentInputSchema = z15.object({
|
|
1703
|
+
siteId: z15.string().uuid(),
|
|
1704
|
+
deploymentUrl: z15.string().url().refine((value) => value.startsWith("https://")),
|
|
1527
1705
|
deploymentRevision: deploymentRevisionSchema
|
|
1528
1706
|
}).strict();
|
|
1529
1707
|
function addSafeByteIssues(value, maxBytes, label, context) {
|
|
@@ -1546,34 +1724,34 @@ function utf8Bytes(value) {
|
|
|
1546
1724
|
|
|
1547
1725
|
// ../shared/dist/bridge-protocol.js
|
|
1548
1726
|
var BRIDGE_PROTOCOL_VERSION = 2;
|
|
1549
|
-
var bridgeRectSchema =
|
|
1550
|
-
x:
|
|
1551
|
-
y:
|
|
1552
|
-
width:
|
|
1553
|
-
height:
|
|
1727
|
+
var bridgeRectSchema = z16.object({
|
|
1728
|
+
x: z16.number(),
|
|
1729
|
+
y: z16.number(),
|
|
1730
|
+
width: z16.number().nonnegative(),
|
|
1731
|
+
height: z16.number().nonnegative()
|
|
1554
1732
|
});
|
|
1555
|
-
var previewTextValueSchema =
|
|
1556
|
-
fieldType:
|
|
1557
|
-
value:
|
|
1733
|
+
var previewTextValueSchema = z16.object({
|
|
1734
|
+
fieldType: z16.enum(["text", "longText"]),
|
|
1735
|
+
value: z16.string()
|
|
1558
1736
|
});
|
|
1559
|
-
var previewLinkValueSchema =
|
|
1560
|
-
fieldType:
|
|
1561
|
-
value:
|
|
1562
|
-
href:
|
|
1563
|
-
label:
|
|
1737
|
+
var previewLinkValueSchema = z16.object({
|
|
1738
|
+
fieldType: z16.literal("link"),
|
|
1739
|
+
value: z16.object({
|
|
1740
|
+
href: z16.string().trim().min(1),
|
|
1741
|
+
label: z16.string().trim().min(1).optional()
|
|
1564
1742
|
})
|
|
1565
1743
|
});
|
|
1566
|
-
var previewImageValueSchema =
|
|
1567
|
-
fieldType:
|
|
1744
|
+
var previewImageValueSchema = z16.object({
|
|
1745
|
+
fieldType: z16.literal("image"),
|
|
1568
1746
|
value: imageValueSchema
|
|
1569
1747
|
});
|
|
1570
|
-
var bridgePreviewValueSchema =
|
|
1748
|
+
var bridgePreviewValueSchema = z16.discriminatedUnion("fieldType", [
|
|
1571
1749
|
previewTextValueSchema,
|
|
1572
1750
|
previewLinkValueSchema,
|
|
1573
1751
|
previewImageValueSchema
|
|
1574
1752
|
]);
|
|
1575
|
-
var fieldSelectionModeSchema =
|
|
1576
|
-
var fieldBridgeMissingContentActionSchema =
|
|
1753
|
+
var fieldSelectionModeSchema = z16.enum(["replace", "range", "toggle"]);
|
|
1754
|
+
var fieldBridgeMissingContentActionSchema = z16.enum([
|
|
1577
1755
|
"add",
|
|
1578
1756
|
"select",
|
|
1579
1757
|
"remove"
|
|
@@ -1592,77 +1770,77 @@ var FIELD_BRIDGE_MESSAGE_TYPES = [
|
|
|
1592
1770
|
"siteplane:field-bridge:preview-scrolled",
|
|
1593
1771
|
"siteplane:field-bridge:error"
|
|
1594
1772
|
];
|
|
1595
|
-
var canonicalFieldContractHashSchema =
|
|
1596
|
-
var bridgeSectionSchema =
|
|
1597
|
-
var realRenderedPathSchema =
|
|
1598
|
-
var fieldBridgeIdentitySchema =
|
|
1599
|
-
publicRuntimeKeyId:
|
|
1773
|
+
var canonicalFieldContractHashSchema = z16.string().regex(/^sha256:[0-9a-f]{64}$/u);
|
|
1774
|
+
var bridgeSectionSchema = z16.string().trim().min(1).max(256);
|
|
1775
|
+
var realRenderedPathSchema = z16.string().trim().refine((value) => value.startsWith("/") && value !== "$global" && !value.includes("?") && !value.includes("#"), "A field bridge rendered path must be a real canonical path.");
|
|
1776
|
+
var fieldBridgeIdentitySchema = z16.object({
|
|
1777
|
+
publicRuntimeKeyId: z16.string().uuid(),
|
|
1600
1778
|
fieldContractHash: canonicalFieldContractHashSchema,
|
|
1601
|
-
deploymentRevision:
|
|
1779
|
+
deploymentRevision: z16.string().trim().min(1).max(256)
|
|
1602
1780
|
}).strict();
|
|
1603
|
-
var fieldBridgeBaseSchema =
|
|
1604
|
-
version:
|
|
1605
|
-
type:
|
|
1606
|
-
siteId:
|
|
1607
|
-
sessionId:
|
|
1608
|
-
publicRuntimeKeyId:
|
|
1781
|
+
var fieldBridgeBaseSchema = z16.object({
|
|
1782
|
+
version: z16.literal(BRIDGE_PROTOCOL_VERSION),
|
|
1783
|
+
type: z16.enum(FIELD_BRIDGE_MESSAGE_TYPES),
|
|
1784
|
+
siteId: z16.string().uuid(),
|
|
1785
|
+
sessionId: z16.string().trim().min(1),
|
|
1786
|
+
publicRuntimeKeyId: z16.string().uuid(),
|
|
1609
1787
|
fieldContractHash: canonicalFieldContractHashSchema,
|
|
1610
|
-
deploymentRevision:
|
|
1611
|
-
requestId:
|
|
1612
|
-
sentAt:
|
|
1788
|
+
deploymentRevision: z16.string().trim().min(1).max(256),
|
|
1789
|
+
requestId: z16.string().trim().min(1),
|
|
1790
|
+
sentAt: z16.string().datetime()
|
|
1613
1791
|
}).strict();
|
|
1614
|
-
var fieldBridgeFieldSchema =
|
|
1792
|
+
var fieldBridgeFieldSchema = z16.object({
|
|
1615
1793
|
fieldId: fieldIdSchema,
|
|
1616
1794
|
fieldType: fieldTypeSchema,
|
|
1617
1795
|
routeKey: siteFieldRouteKeySchema,
|
|
1618
1796
|
renderedPath: realRenderedPathSchema,
|
|
1619
|
-
sourcePath:
|
|
1797
|
+
sourcePath: z16.string().trim().min(1).optional(),
|
|
1620
1798
|
editTarget: fieldIdSchema,
|
|
1621
1799
|
rect: bridgeRectSchema,
|
|
1622
|
-
targetResolved:
|
|
1800
|
+
targetResolved: z16.literal(true),
|
|
1623
1801
|
currentValue: bridgePreviewValueSchema.optional()
|
|
1624
1802
|
}).strict();
|
|
1625
1803
|
var fieldBridgeInitMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1626
|
-
type:
|
|
1627
|
-
payload:
|
|
1628
|
-
adminOrigin:
|
|
1629
|
-
customerOrigin:
|
|
1804
|
+
type: z16.literal("siteplane:field-bridge:init"),
|
|
1805
|
+
payload: z16.object({
|
|
1806
|
+
adminOrigin: z16.string().url(),
|
|
1807
|
+
customerOrigin: z16.string().url(),
|
|
1630
1808
|
renderedPath: realRenderedPathSchema
|
|
1631
1809
|
}).strict()
|
|
1632
1810
|
});
|
|
1633
1811
|
var fieldBridgeReadyMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1634
|
-
type:
|
|
1635
|
-
payload:
|
|
1812
|
+
type: z16.literal("siteplane:field-bridge:ready"),
|
|
1813
|
+
payload: z16.object({
|
|
1636
1814
|
renderedPath: realRenderedPathSchema,
|
|
1637
|
-
fieldCount:
|
|
1638
|
-
capabilities:
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1815
|
+
fieldCount: z16.number().int().nonnegative(),
|
|
1816
|
+
capabilities: z16.tuple([
|
|
1817
|
+
z16.literal("field_selection"),
|
|
1818
|
+
z16.literal("preview_values"),
|
|
1819
|
+
z16.literal("field_evidence"),
|
|
1820
|
+
z16.literal("visual_field_control")
|
|
1643
1821
|
])
|
|
1644
1822
|
}).strict()
|
|
1645
1823
|
});
|
|
1646
1824
|
var fieldBridgeFieldsMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1647
|
-
type:
|
|
1648
|
-
payload:
|
|
1825
|
+
type: z16.literal("siteplane:field-bridge:fields"),
|
|
1826
|
+
payload: z16.object({
|
|
1649
1827
|
renderedPath: realRenderedPathSchema,
|
|
1650
|
-
fields:
|
|
1828
|
+
fields: z16.array(fieldBridgeFieldSchema)
|
|
1651
1829
|
}).strict()
|
|
1652
1830
|
});
|
|
1653
1831
|
var fieldBridgeSelectFieldMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1654
|
-
type:
|
|
1655
|
-
payload:
|
|
1832
|
+
type: z16.literal("siteplane:field-bridge:select-field"),
|
|
1833
|
+
payload: z16.object({
|
|
1656
1834
|
fieldId: fieldIdSchema,
|
|
1657
1835
|
selectionMode: fieldSelectionModeSchema
|
|
1658
1836
|
}).strict()
|
|
1659
1837
|
});
|
|
1660
1838
|
var fieldBridgeSetSelectedFieldMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1661
|
-
type:
|
|
1662
|
-
payload:
|
|
1663
|
-
fieldIds:
|
|
1839
|
+
type: z16.literal("siteplane:field-bridge:set-selected-field"),
|
|
1840
|
+
payload: z16.object({
|
|
1841
|
+
fieldIds: z16.array(fieldIdSchema).max(200),
|
|
1664
1842
|
primaryFieldId: fieldIdSchema.nullable(),
|
|
1665
|
-
scrollIntoView:
|
|
1843
|
+
scrollIntoView: z16.boolean().optional()
|
|
1666
1844
|
}).strict().superRefine((value, context) => {
|
|
1667
1845
|
if (value.fieldIds.length > 0 && value.primaryFieldId === null) {
|
|
1668
1846
|
context.addIssue({
|
|
@@ -1681,58 +1859,58 @@ var fieldBridgeSetSelectedFieldMessageSchema = fieldBridgeBaseSchema.extend({
|
|
|
1681
1859
|
})
|
|
1682
1860
|
});
|
|
1683
1861
|
var fieldBridgeApplyPreviewValuesMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1684
|
-
type:
|
|
1685
|
-
payload:
|
|
1862
|
+
type: z16.literal("siteplane:field-bridge:apply-preview-values"),
|
|
1863
|
+
payload: z16.object({ values: z16.record(fieldIdSchema, bridgePreviewValueSchema) }).strict()
|
|
1686
1864
|
});
|
|
1687
1865
|
var fieldBridgeTestPreviewValuesMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1688
|
-
type:
|
|
1689
|
-
payload:
|
|
1866
|
+
type: z16.literal("siteplane:field-bridge:test-preview-values"),
|
|
1867
|
+
payload: z16.object({ fieldIds: z16.array(fieldIdSchema).min(1).max(200) }).strict()
|
|
1690
1868
|
});
|
|
1691
1869
|
var fieldBridgePreviewAckMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1692
|
-
type:
|
|
1693
|
-
payload:
|
|
1694
|
-
ackRequestId:
|
|
1695
|
-
kind:
|
|
1870
|
+
type: z16.literal("siteplane:field-bridge:preview-ack"),
|
|
1871
|
+
payload: z16.object({
|
|
1872
|
+
ackRequestId: z16.string().trim().min(1),
|
|
1873
|
+
kind: z16.enum(["apply", "test"]),
|
|
1696
1874
|
renderedPath: realRenderedPathSchema,
|
|
1697
|
-
fieldIds:
|
|
1875
|
+
fieldIds: z16.array(fieldIdSchema).max(200)
|
|
1698
1876
|
}).strict()
|
|
1699
1877
|
});
|
|
1700
1878
|
var fieldBridgeSetVisualControlStateMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1701
|
-
type:
|
|
1702
|
-
payload:
|
|
1703
|
-
enabled:
|
|
1704
|
-
fieldProximityEnabled:
|
|
1705
|
-
pendingKeys:
|
|
1706
|
-
activeFieldIds:
|
|
1707
|
-
fieldSections:
|
|
1708
|
-
selectedPending:
|
|
1709
|
-
key:
|
|
1710
|
-
locatorHint:
|
|
1879
|
+
type: z16.literal("siteplane:field-bridge:set-visual-control-state"),
|
|
1880
|
+
payload: z16.object({
|
|
1881
|
+
enabled: z16.boolean(),
|
|
1882
|
+
fieldProximityEnabled: z16.boolean(),
|
|
1883
|
+
pendingKeys: z16.array(z16.string().trim().min(1).max(2048)).max(50),
|
|
1884
|
+
activeFieldIds: z16.array(fieldIdSchema),
|
|
1885
|
+
fieldSections: z16.record(fieldIdSchema, bridgeSectionSchema),
|
|
1886
|
+
selectedPending: z16.array(z16.object({
|
|
1887
|
+
key: z16.string().trim().min(1).max(2048),
|
|
1888
|
+
locatorHint: z16.string().trim().min(1).max(2048)
|
|
1711
1889
|
}).strict()).max(50),
|
|
1712
|
-
scrollPendingIntoView:
|
|
1890
|
+
scrollPendingIntoView: z16.boolean().optional()
|
|
1713
1891
|
}).strict()
|
|
1714
1892
|
});
|
|
1715
1893
|
var fieldBridgeMissingContentMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1716
|
-
type:
|
|
1717
|
-
payload:
|
|
1894
|
+
type: z16.literal("siteplane:field-bridge:missing-content"),
|
|
1895
|
+
payload: z16.object({
|
|
1718
1896
|
action: fieldBridgeMissingContentActionSchema,
|
|
1719
1897
|
item: setupCorrectionItemSchema,
|
|
1720
1898
|
suggestedSection: bridgeSectionSchema.optional()
|
|
1721
1899
|
}).strict()
|
|
1722
1900
|
});
|
|
1723
1901
|
var fieldBridgePreviewScrolledMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1724
|
-
type:
|
|
1725
|
-
payload:
|
|
1902
|
+
type: z16.literal("siteplane:field-bridge:preview-scrolled"),
|
|
1903
|
+
payload: z16.object({ renderedPath: realRenderedPathSchema }).strict()
|
|
1726
1904
|
});
|
|
1727
1905
|
var fieldBridgeErrorMessageSchema = fieldBridgeBaseSchema.extend({
|
|
1728
|
-
type:
|
|
1729
|
-
payload:
|
|
1730
|
-
code:
|
|
1731
|
-
message:
|
|
1732
|
-
recoverable:
|
|
1906
|
+
type: z16.literal("siteplane:field-bridge:error"),
|
|
1907
|
+
payload: z16.object({
|
|
1908
|
+
code: z16.string().trim().min(1),
|
|
1909
|
+
message: z16.string().trim().min(1),
|
|
1910
|
+
recoverable: z16.boolean().default(false)
|
|
1733
1911
|
}).strict()
|
|
1734
1912
|
});
|
|
1735
|
-
var fieldBridgeMessageSchema =
|
|
1913
|
+
var fieldBridgeMessageSchema = z16.discriminatedUnion("type", [
|
|
1736
1914
|
fieldBridgeInitMessageSchema,
|
|
1737
1915
|
fieldBridgeReadyMessageSchema,
|
|
1738
1916
|
fieldBridgeFieldsMessageSchema,
|
|
@@ -1748,51 +1926,51 @@ var fieldBridgeMessageSchema = z15.discriminatedUnion("type", [
|
|
|
1748
1926
|
]);
|
|
1749
1927
|
|
|
1750
1928
|
// ../shared/dist/commands.js
|
|
1751
|
-
import { z as
|
|
1929
|
+
import { z as z18 } from "zod";
|
|
1752
1930
|
|
|
1753
1931
|
// ../shared/dist/errors.js
|
|
1754
|
-
import { z as
|
|
1932
|
+
import { z as z17 } from "zod";
|
|
1755
1933
|
var UI_ERROR_CATEGORIES = [
|
|
1756
1934
|
"site_member",
|
|
1757
1935
|
"workspace_member",
|
|
1758
1936
|
"internal"
|
|
1759
1937
|
];
|
|
1760
|
-
var uiErrorCategorySchema =
|
|
1761
|
-
var commandErrorPayloadSchema =
|
|
1762
|
-
code:
|
|
1763
|
-
message:
|
|
1938
|
+
var uiErrorCategorySchema = z17.enum(UI_ERROR_CATEGORIES);
|
|
1939
|
+
var commandErrorPayloadSchema = z17.object({
|
|
1940
|
+
code: z17.string().min(1),
|
|
1941
|
+
message: z17.string().min(1),
|
|
1764
1942
|
category: uiErrorCategorySchema,
|
|
1765
|
-
details:
|
|
1943
|
+
details: z17.record(z17.string(), z17.unknown()).optional()
|
|
1766
1944
|
});
|
|
1767
1945
|
|
|
1768
1946
|
// ../shared/dist/commands.js
|
|
1769
|
-
var commandSuccessSchema =
|
|
1770
|
-
ok:
|
|
1771
|
-
data:
|
|
1947
|
+
var commandSuccessSchema = z18.object({
|
|
1948
|
+
ok: z18.literal(true),
|
|
1949
|
+
data: z18.unknown()
|
|
1772
1950
|
});
|
|
1773
|
-
var commandErrorSchema =
|
|
1774
|
-
ok:
|
|
1951
|
+
var commandErrorSchema = z18.object({
|
|
1952
|
+
ok: z18.literal(false),
|
|
1775
1953
|
error: commandErrorPayloadSchema
|
|
1776
1954
|
});
|
|
1777
|
-
var commandResultSchema =
|
|
1955
|
+
var commandResultSchema = z18.discriminatedUnion("ok", [
|
|
1778
1956
|
commandSuccessSchema,
|
|
1779
1957
|
commandErrorSchema
|
|
1780
1958
|
]);
|
|
1781
1959
|
|
|
1782
1960
|
// ../shared/dist/editor-settings.js
|
|
1783
|
-
import { z as
|
|
1784
|
-
var editorColorSchemeSchema =
|
|
1961
|
+
import { z as z19 } from "zod";
|
|
1962
|
+
var editorColorSchemeSchema = z19.enum([
|
|
1785
1963
|
"paper",
|
|
1786
1964
|
"slate",
|
|
1787
1965
|
"siteplane",
|
|
1788
1966
|
"bloom"
|
|
1789
1967
|
]);
|
|
1790
1968
|
var editorColorSchemes = editorColorSchemeSchema.options;
|
|
1791
|
-
var editorColorModeSchema =
|
|
1969
|
+
var editorColorModeSchema = z19.enum(["light", "dark"]);
|
|
1792
1970
|
var editorColorModes = editorColorModeSchema.options;
|
|
1793
1971
|
|
|
1794
1972
|
// ../shared/dist/site-slug.js
|
|
1795
|
-
import { z as
|
|
1973
|
+
import { z as z20 } from "zod";
|
|
1796
1974
|
var SITE_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1797
1975
|
var RESERVED_SITE_SLUGS = /* @__PURE__ */ new Set([
|
|
1798
1976
|
"account",
|
|
@@ -1809,31 +1987,31 @@ var RESERVED_SITE_SLUGS = /* @__PURE__ */ new Set([
|
|
|
1809
1987
|
"support",
|
|
1810
1988
|
"workspace"
|
|
1811
1989
|
]);
|
|
1812
|
-
var siteSlugSchema =
|
|
1990
|
+
var siteSlugSchema = z20.string().regex(SITE_SLUG_PATTERN, "Invalid site slug").refine((value) => !RESERVED_SITE_SLUGS.has(value), "Reserved site slug");
|
|
1813
1991
|
|
|
1814
1992
|
// ../shared/dist/entitlements.js
|
|
1815
|
-
import { z as
|
|
1816
|
-
var entitlementSnapshotSchema =
|
|
1817
|
-
planKey:
|
|
1818
|
-
sitesLimit:
|
|
1819
|
-
siteMembersPerSiteLimit:
|
|
1820
|
-
customAdminDomainsEnabled:
|
|
1821
|
-
agentMcpEnabled:
|
|
1822
|
-
emailNotificationsEnabled:
|
|
1823
|
-
analyticsEnabled:
|
|
1824
|
-
analyticsSitesLimit:
|
|
1825
|
-
analyticsPortalPerformanceEnabled:
|
|
1826
|
-
analyticsMonthlyReportsEnabled:
|
|
1827
|
-
analyticsAiSummaryEnabled:
|
|
1828
|
-
analyticsRawEventRetentionDays:
|
|
1829
|
-
analyticsMonthlyEventLimit:
|
|
1830
|
-
bookingEnabled:
|
|
1831
|
-
bookingSitesLimit:
|
|
1832
|
-
bookingPortalManagementEnabled:
|
|
1833
|
-
bookingResourcesPerSiteLimit:
|
|
1834
|
-
bookingServicesPerSiteLimit:
|
|
1835
|
-
bookingMonthlyBookingsLimit:
|
|
1836
|
-
bookingRemindersEnabled:
|
|
1993
|
+
import { z as z21 } from "zod";
|
|
1994
|
+
var entitlementSnapshotSchema = z21.object({
|
|
1995
|
+
planKey: z21.string().trim().min(1),
|
|
1996
|
+
sitesLimit: z21.number().int().positive(),
|
|
1997
|
+
siteMembersPerSiteLimit: z21.number().int().positive(),
|
|
1998
|
+
customAdminDomainsEnabled: z21.boolean(),
|
|
1999
|
+
agentMcpEnabled: z21.boolean(),
|
|
2000
|
+
emailNotificationsEnabled: z21.boolean(),
|
|
2001
|
+
analyticsEnabled: z21.boolean(),
|
|
2002
|
+
analyticsSitesLimit: z21.number().int().min(0),
|
|
2003
|
+
analyticsPortalPerformanceEnabled: z21.boolean(),
|
|
2004
|
+
analyticsMonthlyReportsEnabled: z21.boolean(),
|
|
2005
|
+
analyticsAiSummaryEnabled: z21.boolean(),
|
|
2006
|
+
analyticsRawEventRetentionDays: z21.number().int().min(1).max(ANALYTICS_RETENTION_DEFAULTS.maxRawEventRetentionDaysWithoutAdr),
|
|
2007
|
+
analyticsMonthlyEventLimit: z21.number().int().min(0),
|
|
2008
|
+
bookingEnabled: z21.boolean().default(false),
|
|
2009
|
+
bookingSitesLimit: z21.number().int().min(0).default(0),
|
|
2010
|
+
bookingPortalManagementEnabled: z21.boolean().default(false),
|
|
2011
|
+
bookingResourcesPerSiteLimit: z21.number().int().min(0).default(0),
|
|
2012
|
+
bookingServicesPerSiteLimit: z21.number().int().min(0).default(0),
|
|
2013
|
+
bookingMonthlyBookingsLimit: z21.number().int().min(0).default(0),
|
|
2014
|
+
bookingRemindersEnabled: z21.boolean().default(false)
|
|
1837
2015
|
});
|
|
1838
2016
|
var EARLY_ACCESS_PLAN = {
|
|
1839
2017
|
planKey: "early_access_2026",
|
|
@@ -1859,7 +2037,7 @@ var EARLY_ACCESS_PLAN = {
|
|
|
1859
2037
|
};
|
|
1860
2038
|
|
|
1861
2039
|
// ../shared/dist/readiness.js
|
|
1862
|
-
import { z as
|
|
2040
|
+
import { z as z22 } from "zod";
|
|
1863
2041
|
var READINESS_CHECK_KEYS = [
|
|
1864
2042
|
"agent_instructions_installed",
|
|
1865
2043
|
"runtime_package_connected",
|
|
@@ -1874,19 +2052,19 @@ var READINESS_STATUSES = [
|
|
|
1874
2052
|
"failing",
|
|
1875
2053
|
"warning"
|
|
1876
2054
|
];
|
|
1877
|
-
var readinessCheckKeySchema =
|
|
1878
|
-
var readinessStatusSchema =
|
|
2055
|
+
var readinessCheckKeySchema = z22.enum(READINESS_CHECK_KEYS);
|
|
2056
|
+
var readinessStatusSchema = z22.enum(READINESS_STATUSES);
|
|
1879
2057
|
|
|
1880
2058
|
// ../shared/dist/site.js
|
|
1881
|
-
import { z as
|
|
2059
|
+
import { z as z23 } from "zod";
|
|
1882
2060
|
var SITE_STATUSES = [
|
|
1883
2061
|
"setup",
|
|
1884
2062
|
"active",
|
|
1885
2063
|
"disabled",
|
|
1886
2064
|
"archived"
|
|
1887
2065
|
];
|
|
1888
|
-
var siteStatusSchema =
|
|
1889
|
-
var websiteUrlSchema =
|
|
2066
|
+
var siteStatusSchema = z23.enum(SITE_STATUSES);
|
|
2067
|
+
var websiteUrlSchema = z23.string().trim().url().refine((value) => value.startsWith("https://") || value.startsWith("http://"), "Website URL must use http or https");
|
|
1890
2068
|
|
|
1891
2069
|
// ../cli/dist/analytics/static-scan.js
|
|
1892
2070
|
import ts from "typescript";
|
|
@@ -1924,16 +2102,16 @@ ${analyticsRulesTemplate}`;
|
|
|
1924
2102
|
import { createHash } from "crypto";
|
|
1925
2103
|
|
|
1926
2104
|
// ../cli/dist/commands/analytics/public-key.js
|
|
1927
|
-
import { z as
|
|
1928
|
-
var responseSchema =
|
|
1929
|
-
ok:
|
|
1930
|
-
data:
|
|
1931
|
-
rawPublicKey:
|
|
2105
|
+
import { z as z24 } from "zod";
|
|
2106
|
+
var responseSchema = z24.object({
|
|
2107
|
+
ok: z24.literal(true),
|
|
2108
|
+
data: z24.object({
|
|
2109
|
+
rawPublicKey: z24.string().regex(/^pk_siteplane_[A-Za-z0-9_-]{16}_[A-Za-z0-9_-]{43}$/)
|
|
1932
2110
|
})
|
|
1933
2111
|
});
|
|
1934
|
-
var errorResponseSchema =
|
|
1935
|
-
error:
|
|
1936
|
-
code:
|
|
2112
|
+
var errorResponseSchema = z24.object({
|
|
2113
|
+
error: z24.object({
|
|
2114
|
+
code: z24.string().regex(/^[a-z][a-z0-9_.-]+$/u)
|
|
1937
2115
|
})
|
|
1938
2116
|
});
|
|
1939
2117
|
|
|
@@ -1967,14 +2145,22 @@ ${bookingRulesTemplate}`;
|
|
|
1967
2145
|
import { access, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
|
|
1968
2146
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1969
2147
|
import { join as join3 } from "path";
|
|
1970
|
-
import { z as
|
|
1971
|
-
var siteplaneProjectConfigSchema =
|
|
1972
|
-
version:
|
|
1973
|
-
apiBaseUrl:
|
|
1974
|
-
siteId:
|
|
1975
|
-
publicSiteKeyId:
|
|
1976
|
-
publicSiteKey:
|
|
1977
|
-
|
|
2148
|
+
import { z as z25 } from "zod";
|
|
2149
|
+
var siteplaneProjectConfigSchema = z25.object({
|
|
2150
|
+
version: z25.literal(2),
|
|
2151
|
+
apiBaseUrl: z25.string().url(),
|
|
2152
|
+
siteId: z25.string().uuid(),
|
|
2153
|
+
publicSiteKeyId: z25.string().uuid(),
|
|
2154
|
+
publicSiteKey: z25.string().trim().min(1),
|
|
2155
|
+
runId: z25.string().uuid(),
|
|
2156
|
+
appDirectory: z25.string().min(1),
|
|
2157
|
+
taskContractVersion: z25.literal("siteplane.setup-task.v2"),
|
|
2158
|
+
adminProtocolVersion: z25.literal(2),
|
|
2159
|
+
packages: z25.object({
|
|
2160
|
+
siteplane: z25.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
|
|
2161
|
+
runtimeNext: z25.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
|
|
2162
|
+
}).strict(),
|
|
2163
|
+
fieldContractHash: z25.string().regex(/^sha256:[0-9a-f]{64}$/iu).optional()
|
|
1978
2164
|
}).strict();
|
|
1979
2165
|
async function readProjectConfig(projectDir) {
|
|
1980
2166
|
return siteplaneProjectConfigSchema.parse(JSON.parse(await readFile5(join3(projectDir, "siteplane.config.json"), "utf8")));
|
|
@@ -1983,45 +2169,545 @@ async function readProjectConfig(projectDir) {
|
|
|
1983
2169
|
// ../cli/dist/config/credentials.js
|
|
1984
2170
|
import { execFile } from "child_process";
|
|
1985
2171
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1986
|
-
import { chmod as chmod2, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
|
|
2172
|
+
import { chmod as chmod2, lstat, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
|
|
1987
2173
|
import { dirname as dirname5, join as join4, relative } from "path";
|
|
1988
2174
|
import { promisify } from "util";
|
|
1989
|
-
import { z as
|
|
1990
|
-
var siteplaneCredentialsSchema =
|
|
1991
|
-
accessToken:
|
|
1992
|
-
siteRevalidationSecret:
|
|
2175
|
+
import { z as z26 } from "zod";
|
|
2176
|
+
var siteplaneCredentialsSchema = z26.object({
|
|
2177
|
+
accessToken: z26.string().trim().min(1),
|
|
2178
|
+
siteRevalidationSecret: z26.string().trim().min(1),
|
|
2179
|
+
adminSession: z26.object({
|
|
2180
|
+
secret: z26.string().regex(/^[A-Za-z0-9_-]{43}$/u),
|
|
2181
|
+
generation: z26.string().uuid()
|
|
2182
|
+
}).strict().optional()
|
|
1993
2183
|
}).strict();
|
|
2184
|
+
async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
|
|
2185
|
+
const path = join4(projectDir, ".siteplane/credentials.json");
|
|
2186
|
+
await assertCredentialFilesystemSafe(projectDir);
|
|
2187
|
+
const isTrackedFile = options.isTrackedFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "ls-files"));
|
|
2188
|
+
const isIgnoredFile = options.isIgnoredFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "check-ignore"));
|
|
2189
|
+
if (await isTrackedFile(path)) {
|
|
2190
|
+
throw new Error("Refusing to write Siteplane credentials into a tracked file.");
|
|
2191
|
+
}
|
|
2192
|
+
if (!await isIgnoredFile(path)) {
|
|
2193
|
+
throw new Error("Add .siteplane/credentials.json to .gitignore before running Siteplane init.");
|
|
2194
|
+
}
|
|
2195
|
+
return path;
|
|
2196
|
+
}
|
|
2197
|
+
async function assertCredentialFilesystemSafe(projectDir) {
|
|
2198
|
+
for (const [path, directory, mode] of [
|
|
2199
|
+
[projectDir, true, null],
|
|
2200
|
+
[join4(projectDir, ".siteplane"), true, 448],
|
|
2201
|
+
[join4(projectDir, ".siteplane/credentials.json"), false, 384]
|
|
2202
|
+
]) {
|
|
2203
|
+
const stat = await lstat(path).catch((error) => {
|
|
2204
|
+
if (error.code === "ENOENT")
|
|
2205
|
+
return null;
|
|
2206
|
+
throw error;
|
|
2207
|
+
});
|
|
2208
|
+
if (!stat)
|
|
2209
|
+
continue;
|
|
2210
|
+
if (stat.isSymbolicLink() || (directory ? !stat.isDirectory() : !stat.isFile())) {
|
|
2211
|
+
throw new Error("Siteplane credential paths must not contain symlinks or unexpected file types.");
|
|
2212
|
+
}
|
|
2213
|
+
if (mode !== null && (stat.mode & 511) !== mode) {
|
|
2214
|
+
throw new Error(`Siteplane credential ${directory ? "directory" : "file"} permissions must be ${mode.toString(8)} before setup.`);
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
async function readLocalCredentials(projectDir) {
|
|
2219
|
+
await assertCredentialFilesystemSafe(projectDir);
|
|
2220
|
+
return siteplaneCredentialsSchema.parse(JSON.parse(await readFile6(join4(projectDir, ".siteplane/credentials.json"), "utf8")));
|
|
2221
|
+
}
|
|
1994
2222
|
var execFileAsync = promisify(execFile);
|
|
2223
|
+
async function gitPathMatches(projectDir, path, command) {
|
|
2224
|
+
const args = command === "check-ignore" ? ["check-ignore", "--quiet", relative(projectDir, path)] : ["ls-files", "--error-unmatch", relative(projectDir, path)];
|
|
2225
|
+
try {
|
|
2226
|
+
await execFileAsync("git", args, { cwd: projectDir });
|
|
2227
|
+
return true;
|
|
2228
|
+
} catch {
|
|
2229
|
+
return false;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
1995
2232
|
|
|
1996
2233
|
// ../cli/dist/commands/init.js
|
|
2234
|
+
import { access as access3 } from "fs/promises";
|
|
2235
|
+
import { join as join7, relative as relative3 } from "path";
|
|
2236
|
+
import { z as z29 } from "zod";
|
|
2237
|
+
|
|
2238
|
+
// ../cli/dist/commands/setup-preflight.js
|
|
2239
|
+
import { createHash as createHash2 } from "crypto";
|
|
2240
|
+
import semver from "semver";
|
|
2241
|
+
import { minimatch } from "minimatch";
|
|
2242
|
+
import { parse as parseYaml } from "yaml";
|
|
2243
|
+
|
|
2244
|
+
// ../cli/dist/config/installed-package.js
|
|
2245
|
+
import { createRequire } from "module";
|
|
2246
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
1997
2247
|
import { join as join5 } from "path";
|
|
1998
|
-
import { z as
|
|
1999
|
-
var
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2248
|
+
import { z as z27 } from "zod";
|
|
2249
|
+
var packageSchema = z27.object({
|
|
2250
|
+
name: z27.string().optional(),
|
|
2251
|
+
version: z27.string(),
|
|
2252
|
+
peerDependencies: z27.record(z27.string(), z27.string()).optional()
|
|
2253
|
+
});
|
|
2254
|
+
async function readInstalledPackage(projectDir, name2) {
|
|
2255
|
+
const require2 = createRequire(join5(projectDir, "package.json"));
|
|
2256
|
+
for (const directory of require2.resolve.paths(name2) ?? []) {
|
|
2257
|
+
try {
|
|
2258
|
+
return packageSchema.parse(JSON.parse(await readFile7(join5(directory, name2, "package.json"), "utf8")));
|
|
2259
|
+
} catch (error) {
|
|
2260
|
+
if (error.code !== "ENOENT")
|
|
2261
|
+
throw error;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
throw new Error(`Install ${name2} with the canonical package manager before setup.`);
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
// ../cli/dist/commands/setup-preflight.js
|
|
2268
|
+
import { access as access2, readFile as readFile8, realpath, readdir, readlink } from "fs/promises";
|
|
2269
|
+
import { dirname as dirname6, join as join6, relative as relative2, resolve, sep } from "path";
|
|
2270
|
+
import { z as z28 } from "zod";
|
|
2271
|
+
|
|
2272
|
+
// ../cli/dist/commands/setup-process.js
|
|
2273
|
+
import { spawn } from "child_process";
|
|
2274
|
+
var SetupFailure = class extends Error {
|
|
2275
|
+
code;
|
|
2276
|
+
constructor(code, message) {
|
|
2277
|
+
super(message);
|
|
2278
|
+
this.code = code;
|
|
2279
|
+
}
|
|
2280
|
+
};
|
|
2281
|
+
async function setupProcess(binary, args, options) {
|
|
2282
|
+
return new Promise((resolve5, reject) => {
|
|
2283
|
+
const child = spawn(binary, args, {
|
|
2284
|
+
cwd: options.cwd,
|
|
2285
|
+
env: process.env,
|
|
2286
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
2287
|
+
});
|
|
2288
|
+
const chunks = [];
|
|
2289
|
+
const errors = [];
|
|
2290
|
+
let errorBytes = 0;
|
|
2291
|
+
let bytes = 0;
|
|
2292
|
+
let exceeded = false;
|
|
2293
|
+
const timer = setTimeout(() => {
|
|
2294
|
+
exceeded = true;
|
|
2295
|
+
child.kill("SIGKILL");
|
|
2296
|
+
}, options.timeoutMs ?? 12e4);
|
|
2297
|
+
const capture = (chunk) => {
|
|
2298
|
+
bytes += chunk.length;
|
|
2299
|
+
if (bytes > 4 * 1024 * 1024) {
|
|
2300
|
+
exceeded = true;
|
|
2301
|
+
child.kill("SIGKILL");
|
|
2302
|
+
} else
|
|
2303
|
+
chunks.push(chunk);
|
|
2304
|
+
};
|
|
2305
|
+
child.stdout.on("data", capture);
|
|
2306
|
+
child.stderr.on("data", (chunk) => {
|
|
2307
|
+
errorBytes += chunk.length;
|
|
2308
|
+
if (errorBytes <= 4 * 1024 * 1024)
|
|
2309
|
+
errors.push(chunk);
|
|
2310
|
+
else {
|
|
2311
|
+
exceeded = true;
|
|
2312
|
+
child.kill("SIGKILL");
|
|
2313
|
+
}
|
|
2314
|
+
});
|
|
2315
|
+
child.on("error", () => {
|
|
2316
|
+
clearTimeout(timer);
|
|
2317
|
+
reject(new SetupFailure("local_tool_unavailable", `${binary} could not be started. Check the local installation and access.`));
|
|
2318
|
+
});
|
|
2319
|
+
child.on("close", (code) => {
|
|
2320
|
+
clearTimeout(timer);
|
|
2321
|
+
if (exceeded)
|
|
2322
|
+
reject(new SetupFailure("provider_timeout", "The operation exceeded its time or response limit; inspect the existing operation before retrying."));
|
|
2323
|
+
else if (code !== 0) {
|
|
2324
|
+
const diagnostic = Buffer.concat([...chunks, ...errors]).toString("utf8");
|
|
2325
|
+
if (/\b(?:401|403|unauthorized|forbidden|not authenticated|not authorized|login required|E401|E403)\b/iu.test(diagnostic))
|
|
2326
|
+
reject(new SetupFailure("provider_access_denied", `${binary} denied access. Restore the existing local login and project/package permissions before retrying.`));
|
|
2327
|
+
else if (/\b(?:ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|ECONNREFUSED|429|502|503|504)\b/iu.test(diagnostic))
|
|
2328
|
+
reject(new SetupFailure("provider_transport_failed", `${binary} could not reach its provider. Inspect the existing operation before retrying.`));
|
|
2329
|
+
else
|
|
2330
|
+
reject(new SetupFailure("local_command_failed", `${binary} failed. Check its local login, permissions and project configuration.`));
|
|
2331
|
+
} else
|
|
2332
|
+
resolve5(Buffer.concat(options.includeStderr ? [...chunks, ...errors] : chunks).toString("utf8"));
|
|
2333
|
+
});
|
|
2334
|
+
child.stdin.on("error", () => {
|
|
2335
|
+
});
|
|
2336
|
+
child.stdin.end(options.input);
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
async function setupVercelApi(cwd, endpoint, body, method, options) {
|
|
2340
|
+
const args = ["api", endpoint, "--raw"];
|
|
2341
|
+
if (body !== void 0)
|
|
2342
|
+
args.push("--method", method ?? "POST", "--input", "-");
|
|
2343
|
+
else if (method)
|
|
2344
|
+
args.push("--method", method);
|
|
2345
|
+
let output = "";
|
|
2346
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
2347
|
+
const remaining = (options?.deadline ?? Date.now() + 3e4) - Date.now();
|
|
2348
|
+
if (remaining <= 0)
|
|
2349
|
+
throw new SetupFailure("provider_deadline_exceeded", "The provider deadline expired; inspect the recorded operation before continuing.");
|
|
2350
|
+
try {
|
|
2351
|
+
output = await setupProcess("vercel", args, {
|
|
2352
|
+
cwd,
|
|
2353
|
+
timeoutMs: Math.min(3e4, remaining),
|
|
2354
|
+
...body === void 0 ? {} : { input: JSON.stringify(body) }
|
|
2355
|
+
});
|
|
2356
|
+
break;
|
|
2357
|
+
} catch (error) {
|
|
2358
|
+
if (!(error instanceof SetupFailure) || error.code !== "provider_transport_failed" || attempt === 2)
|
|
2359
|
+
throw error;
|
|
2360
|
+
await new Promise((resolve5) => setTimeout(resolve5, Math.min(1e3 * 2 ** attempt, Math.max(0, (options?.deadline ?? Date.now() + 2e3) - Date.now()))));
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
try {
|
|
2364
|
+
return JSON.parse(output);
|
|
2365
|
+
} catch {
|
|
2366
|
+
throw new SetupFailure("invalid_provider_response", "Vercel did not return valid JSON for the bound project.");
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// ../cli/dist/commands/setup-preflight.js
|
|
2371
|
+
var manifestSchema = z28.object({
|
|
2372
|
+
packageManager: z28.string().optional(),
|
|
2373
|
+
engines: z28.object({ node: z28.string().optional() }).optional(),
|
|
2374
|
+
dependencies: z28.record(z28.string(), z28.string()).optional(),
|
|
2375
|
+
devDependencies: z28.record(z28.string(), z28.string()).optional(),
|
|
2376
|
+
scripts: z28.record(z28.string(), z28.string()).optional(),
|
|
2377
|
+
workspaces: z28.unknown().optional()
|
|
2378
|
+
});
|
|
2379
|
+
var vercelProjectSchema = z28.object({
|
|
2380
|
+
id: z28.string(),
|
|
2381
|
+
accountId: z28.string(),
|
|
2382
|
+
name: z28.string(),
|
|
2383
|
+
nodeVersion: z28.string().nullable().optional(),
|
|
2384
|
+
rootDirectory: z28.string().nullable().optional(),
|
|
2385
|
+
framework: z28.string().nullable().optional(),
|
|
2386
|
+
installCommand: z28.string().nullable().optional(),
|
|
2387
|
+
buildCommand: z28.string().nullable().optional(),
|
|
2388
|
+
link: z28.object({
|
|
2389
|
+
type: z28.string(),
|
|
2390
|
+
repo: z28.string().optional(),
|
|
2391
|
+
repoId: z28.union([z28.string(), z28.number()]).optional(),
|
|
2392
|
+
org: z28.string().optional(),
|
|
2393
|
+
productionBranch: z28.string().optional()
|
|
2394
|
+
}).nullable().optional()
|
|
2395
|
+
});
|
|
2396
|
+
var exists = async (path) => access2(path).then(() => true, () => false);
|
|
2397
|
+
var fail = (code, message) => {
|
|
2398
|
+
throw new SetupFailure(code, message);
|
|
2399
|
+
};
|
|
2400
|
+
var stable = (version2, major) => new RegExp(`^${major}\\.\\d+\\.\\d+$`, "u").test(version2);
|
|
2401
|
+
async function inspectSetupLocalProject(projectDir) {
|
|
2402
|
+
const projectDirectory = await realpath(resolve(projectDir));
|
|
2403
|
+
const manifest = manifestSchema.parse(JSON.parse(await readFile8(join6(projectDirectory, "package.json"), "utf8")));
|
|
2404
|
+
const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(join6(projectDirectory, path)) ? path : null))).filter((path) => path !== null);
|
|
2405
|
+
if (apps.length !== 1)
|
|
2406
|
+
fail("ambiguous_app_directory", "Select one Next.js App Router application with exactly one app/ or src/app/ directory.");
|
|
2407
|
+
const repositoryRoot = (await setupProcess("git", ["rev-parse", "--show-toplevel"], {
|
|
2408
|
+
cwd: projectDirectory
|
|
2409
|
+
})).trim();
|
|
2410
|
+
const tracked = await setupProcess("git", ["ls-files", "--stage", "-z"], {
|
|
2411
|
+
cwd: repositoryRoot
|
|
2412
|
+
});
|
|
2413
|
+
for (const entry of tracked.split("\0").filter(Boolean)) {
|
|
2414
|
+
if (entry.startsWith("160000 "))
|
|
2415
|
+
fail("git_submodule_conflict", "The repository contains Git submodules. Resolve the explicit deployment source boundary before setup; the CLI will not copy external repositories.");
|
|
2416
|
+
if (!entry.startsWith("120000 "))
|
|
2417
|
+
continue;
|
|
2418
|
+
const path = join6(repositoryRoot, entry.slice(entry.indexOf(" ") + 1));
|
|
2419
|
+
const target = resolve(dirname6(path), await readlink(path));
|
|
2420
|
+
const bound = relative2(repositoryRoot, target);
|
|
2421
|
+
if (bound.startsWith("..") || bound.startsWith(sep))
|
|
2422
|
+
fail("external_symlink_conflict", "A tracked symbolic link points outside this repository. Resolve that source boundary before setup; local external files cannot enter a deployment.");
|
|
2423
|
+
}
|
|
2424
|
+
let lockfileRoot = projectDirectory;
|
|
2425
|
+
const lockNames = [
|
|
2426
|
+
"package-lock.json",
|
|
2427
|
+
"npm-shrinkwrap.json",
|
|
2428
|
+
"pnpm-lock.yaml",
|
|
2429
|
+
"yarn.lock",
|
|
2430
|
+
"bun.lock",
|
|
2431
|
+
"bun.lockb"
|
|
2432
|
+
];
|
|
2433
|
+
let locks = [];
|
|
2434
|
+
for (; ; ) {
|
|
2435
|
+
locks = (await Promise.all(lockNames.map(async (name3) => await exists(join6(lockfileRoot, name3)) ? name3 : null))).filter((name3) => name3 !== null);
|
|
2436
|
+
if (locks.length || lockfileRoot === repositoryRoot || dirname6(lockfileRoot) === lockfileRoot)
|
|
2437
|
+
break;
|
|
2438
|
+
lockfileRoot = dirname6(lockfileRoot);
|
|
2439
|
+
}
|
|
2440
|
+
if (locks.length > 1)
|
|
2441
|
+
fail("conflicting_lockfiles", "Resolve conflicting package-manager lockfiles before setup; Siteplane does not replace them.");
|
|
2442
|
+
if (!locks.length)
|
|
2443
|
+
fail("lockfile_missing", "Install the existing application with its chosen package manager to create one canonical lockfile.");
|
|
2444
|
+
const lockName = locks[0];
|
|
2445
|
+
if (!["package-lock.json", "pnpm-lock.yaml"].includes(lockName))
|
|
2446
|
+
fail("unsupported_package_manager", "This setup supports npm 10 or pnpm 9/10 with their canonical lockfile.");
|
|
2447
|
+
const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(join6(lockfileRoot, "package.json"), "utf8")));
|
|
2448
|
+
if (lockfileRoot !== projectDirectory) {
|
|
2449
|
+
const workspaceFile = join6(lockfileRoot, "pnpm-workspace.yaml");
|
|
2450
|
+
const workspace = lockName === "pnpm-lock.yaml" && await exists(workspaceFile) ? z28.object({ packages: z28.array(z28.string()) }).parse(parseYaml(await readFile8(workspaceFile, "utf8"))).packages : z28.union([
|
|
2451
|
+
z28.array(z28.string()),
|
|
2452
|
+
z28.object({ packages: z28.array(z28.string()) }).transform((value) => value.packages)
|
|
2453
|
+
]).parse(rootManifest.workspaces);
|
|
2454
|
+
const selected = relative2(lockfileRoot, projectDirectory).split(sep).join("/");
|
|
2455
|
+
if (!workspace.some((pattern) => !pattern.startsWith("!") && minimatch(selected, pattern)) || workspace.some((pattern) => pattern.startsWith("!") && minimatch(selected, pattern.slice(1))))
|
|
2456
|
+
fail("unbound_workspace_app", "The selected application is excluded from the canonical lockfile's workspace packages. Select its actual application root.");
|
|
2457
|
+
}
|
|
2458
|
+
for (let ancestor = dirname6(lockfileRoot); ancestor.startsWith(repositoryRoot + sep) || ancestor === repositoryRoot; ancestor = dirname6(ancestor)) {
|
|
2459
|
+
const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(join6(ancestor, name3))));
|
|
2460
|
+
if (ancestorLocks.some(Boolean))
|
|
2461
|
+
fail("ambiguous_lockfile_root", "Both the selected package and its repository ancestors contain lockfiles. Select one canonical workspace resolution before setup.");
|
|
2462
|
+
if (ancestor === repositoryRoot)
|
|
2463
|
+
break;
|
|
2464
|
+
}
|
|
2465
|
+
const lockText = await readFile8(join6(lockfileRoot, lockName), "utf8");
|
|
2466
|
+
const npmLock = lockName === "package-lock.json" ? z28.object({
|
|
2467
|
+
lockfileVersion: z28.number(),
|
|
2468
|
+
packages: z28.record(z28.string(), z28.object({
|
|
2469
|
+
version: z28.string().optional(),
|
|
2470
|
+
peerDependencies: z28.record(z28.string(), z28.string()).optional()
|
|
2471
|
+
})).optional()
|
|
2472
|
+
}).parse(JSON.parse(lockText)) : null;
|
|
2473
|
+
async function version2(name3) {
|
|
2474
|
+
try {
|
|
2475
|
+
return (await readInstalledPackage(projectDirectory, name3)).version;
|
|
2476
|
+
} catch {
|
|
2477
|
+
const resolved = npmLock?.packages?.[`node_modules/${name3}`]?.version;
|
|
2478
|
+
if (resolved)
|
|
2479
|
+
return resolved;
|
|
2480
|
+
return fail("dependencies_not_installed", `Install the existing ${name3} dependency using the canonical lockfile before setup.`);
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
const [nextVersion, reactVersion, reactDomVersion] = await Promise.all([
|
|
2484
|
+
version2("next"),
|
|
2485
|
+
version2("react"),
|
|
2486
|
+
version2("react-dom")
|
|
2487
|
+
]);
|
|
2488
|
+
if (!stable(nextVersion, 16))
|
|
2489
|
+
fail("unsupported_next_version", "Setup supports stable Next.js 16 App Router projects. Framework migration requires a separate owner decision.");
|
|
2490
|
+
if (!stable(reactVersion, 19) || reactDomVersion !== reactVersion)
|
|
2491
|
+
fail("react_version_conflict", "Use the same stable React 19/react-dom version compatible with the installed Next.js peers.");
|
|
2492
|
+
if (!stable(process.versions.node, 22))
|
|
2493
|
+
fail("unsupported_node_version", "Run setup under Node.js 22; this does not change your framework or package-manager versions.");
|
|
2494
|
+
const nextMetadata = await readInstalledPackage(projectDirectory, "next").catch(() => npmLock?.packages?.["node_modules/next"] ?? null);
|
|
2495
|
+
const peers = nextMetadata?.peerDependencies;
|
|
2496
|
+
if (!peers?.react || !peers["react-dom"])
|
|
2497
|
+
fail("next_peer_metadata_missing", "Install the locked Next.js dependency before setup so its actual React peer requirements can be checked.");
|
|
2498
|
+
if (!semver.satisfies(reactVersion, peers.react) || !semver.satisfies(reactDomVersion, peers["react-dom"]))
|
|
2499
|
+
fail("react_peer_conflict", "The installed React pair does not satisfy the installed Next.js peer requirements. Choose a compatible pair explicitly.");
|
|
2500
|
+
if (manifest.engines?.node && !semver.satisfies(process.versions.node, manifest.engines.node))
|
|
2501
|
+
fail("node_engine_conflict", "The selected application's Node engine declaration excludes the active supported Node.js 22 runtime.");
|
|
2502
|
+
const name2 = lockName === "package-lock.json" ? "npm" : "pnpm";
|
|
2503
|
+
const declared = rootManifest.packageManager ?? manifest.packageManager ?? null;
|
|
2504
|
+
if (rootManifest.packageManager && manifest.packageManager && rootManifest.packageManager !== manifest.packageManager)
|
|
2505
|
+
fail("package_manager_conflict", "Application and workspace packageManager declarations disagree.");
|
|
2506
|
+
if (declared && !new RegExp(`^${name2}@\\d+\\.\\d+\\.\\d+$`, "u").test(declared))
|
|
2507
|
+
fail("package_manager_conflict", "Declare an exact supported npm/pnpm packageManager version matching the canonical lockfile.");
|
|
2508
|
+
const localVersion = (await setupProcess(declared ? "npx" : name2, declared ? ["--yes", declared, "--version"] : ["--version"], { cwd: lockfileRoot })).trim();
|
|
2509
|
+
if (!(name2 === "npm" ? stable(localVersion, 10) : stable(localVersion, 9) || stable(localVersion, 10)))
|
|
2510
|
+
fail("unsupported_package_manager_version", "Use npm 10 or pnpm 9/10; other versions are outside the initial setup support range.");
|
|
2511
|
+
if (declared && declared !== `${name2}@${localVersion}`)
|
|
2512
|
+
fail("package_manager_conflict", "The actual local package-manager version differs from the project's exact packageManager declaration. Select the declared tool without rewriting the lockfile.");
|
|
2513
|
+
const format = npmLock ? String(npmLock.lockfileVersion) : /^lockfileVersion:\s*['"]?([\d.]+)/mu.exec(lockText)?.[1];
|
|
2514
|
+
if (name2 === "npm" && format !== "3" || name2 === "pnpm" && format !== "9.0" && format !== "9")
|
|
2515
|
+
fail("lockfile_format_conflict", "The canonical lockfile format does not match npm 10 or pnpm 9/10.");
|
|
2516
|
+
const sourceConflicts = [];
|
|
2517
|
+
for (const file of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
|
|
2518
|
+
if (!await exists(join6(projectDirectory, file)))
|
|
2519
|
+
continue;
|
|
2520
|
+
const source = await readFile8(join6(projectDirectory, file), "utf8");
|
|
2521
|
+
if (/output\s*:\s*['"]export['"]/u.test(source))
|
|
2522
|
+
sourceConflicts.push("static_export");
|
|
2523
|
+
if (/\bbasePath\s*:/u.test(source))
|
|
2524
|
+
sourceConflicts.push("base_path");
|
|
2525
|
+
}
|
|
2526
|
+
if (sourceConflicts.length)
|
|
2527
|
+
fail("unsupported_server_configuration", "Resolve static export/basePath configuration explicitly; Siteplane requires its server-side admin and revalidation handlers.");
|
|
2528
|
+
for (const name3 of [
|
|
2529
|
+
"middleware.ts",
|
|
2530
|
+
"middleware.js",
|
|
2531
|
+
"proxy.ts",
|
|
2532
|
+
"proxy.js",
|
|
2533
|
+
"src/middleware.ts",
|
|
2534
|
+
"src/middleware.js",
|
|
2535
|
+
"src/proxy.ts",
|
|
2536
|
+
"src/proxy.js"
|
|
2537
|
+
]) {
|
|
2538
|
+
if (await exists(join6(projectDirectory, name3)))
|
|
2539
|
+
sourceConflicts.push(`inspect_routing:${name3}`);
|
|
2540
|
+
}
|
|
2541
|
+
async function inspectSource(directory) {
|
|
2542
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
2543
|
+
if (entry.isSymbolicLink() || ["node_modules", ".git", ".next", ".siteplane", ".vercel"].includes(entry.name))
|
|
2544
|
+
continue;
|
|
2545
|
+
const path = join6(directory, entry.name);
|
|
2546
|
+
if (entry.isDirectory()) {
|
|
2547
|
+
await inspectSource(path);
|
|
2548
|
+
continue;
|
|
2549
|
+
}
|
|
2550
|
+
if (!/\.[cm]?[jt]sx?$/u.test(entry.name))
|
|
2551
|
+
continue;
|
|
2552
|
+
const source = await readFile8(path, "utf8");
|
|
2553
|
+
if (/from\s*["']next\/image["']/u.test(source))
|
|
2554
|
+
sourceConflicts.push(`inspect_image_policy:${relative2(projectDirectory, path)}`);
|
|
2555
|
+
if (/\b(?:Cookiebot|OneTrust|cookieyes|consentManager|cookieConsent)\b/iu.test(source))
|
|
2556
|
+
sourceConflicts.push(`inspect_existing_consent:${relative2(projectDirectory, path)}`);
|
|
2557
|
+
if (/from\s*["']next\/image["']/u.test(source) && semver.lt(nextVersion, "16.3.3"))
|
|
2558
|
+
fail("next_security_advisory", `Next.js ${nextVersion} uses image optimization affected by the August 2026 AVIF advisory. Review https://nextjs.org/blog/august-2026-security-release and explicitly update the affected dependency before setup; no framework upgrade was performed.`);
|
|
2559
|
+
if (/["']use server["']/u.test(source) && semver.lt(nextVersion, "16.2.11"))
|
|
2560
|
+
fail("next_security_advisory", `Next.js ${nextVersion} contains Server Actions affected by the July 2026 advisory. Review https://nextjs.org/blog/july-2026-security-release and explicitly update the affected dependency before setup.`);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
await inspectSource(join6(projectDirectory, apps[0]));
|
|
2564
|
+
const gitRead = async (args) => setupProcess("git", args, { cwd: projectDirectory }).then((value) => value.trim(), () => null);
|
|
2565
|
+
return {
|
|
2566
|
+
projectDirectory,
|
|
2567
|
+
repositoryRoot,
|
|
2568
|
+
lockfileRoot,
|
|
2569
|
+
appDirectory: apps[0],
|
|
2570
|
+
nextVersion,
|
|
2571
|
+
reactVersion,
|
|
2572
|
+
nodeVersion: process.versions.node,
|
|
2573
|
+
packageManager: { name: name2, version: localVersion, declared },
|
|
2574
|
+
lockfile: {
|
|
2575
|
+
path: relative2(repositoryRoot, join6(lockfileRoot, lockName)),
|
|
2576
|
+
format,
|
|
2577
|
+
sha256: createHash2("sha256").update(lockText).digest("hex")
|
|
2578
|
+
},
|
|
2579
|
+
git: {
|
|
2580
|
+
branch: await gitRead(["branch", "--show-current"]),
|
|
2581
|
+
revision: await gitRead(["rev-parse", "HEAD"]),
|
|
2582
|
+
remote: safeGitRemote(await gitRead(["remote", "get-url", "origin"])),
|
|
2583
|
+
changes: (await gitRead(["status", "--porcelain=v1", "--untracked-files=all"]))?.split("\n").filter(Boolean) ?? []
|
|
2584
|
+
},
|
|
2585
|
+
sourceConflicts
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
async function setupPreflightCommand(input) {
|
|
2589
|
+
let local;
|
|
2590
|
+
try {
|
|
2591
|
+
local = await inspectSetupLocalProject(input.projectDir);
|
|
2592
|
+
await assertLocalCredentialsPathSafe(input.projectDir);
|
|
2593
|
+
let linkDirectory = local.projectDirectory;
|
|
2594
|
+
while (!await exists(join6(linkDirectory, ".vercel/project.json")) && linkDirectory !== local.repositoryRoot && dirname6(linkDirectory) !== linkDirectory)
|
|
2595
|
+
linkDirectory = dirname6(linkDirectory);
|
|
2596
|
+
if (!await exists(join6(linkDirectory, ".vercel/project.json")))
|
|
2597
|
+
fail("vercel_project_not_linked", "Link this application to its intended Vercel project before setup; Siteplane will not guess a target.");
|
|
2598
|
+
const linked = z28.object({
|
|
2599
|
+
projectId: z28.string().regex(/^prj_[A-Za-z0-9]+$/u),
|
|
2600
|
+
orgId: z28.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u)
|
|
2601
|
+
}).parse(JSON.parse(await readFile8(join6(linkDirectory, ".vercel/project.json"), "utf8")));
|
|
2602
|
+
const project = vercelProjectSchema.parse(await setupVercelApi(linkDirectory, `/v9/projects/${linked.projectId}?teamId=${linked.orgId}`));
|
|
2603
|
+
if (project.id !== linked.projectId || project.accountId !== linked.orgId)
|
|
2604
|
+
fail("vercel_identity_conflict", "The provider project does not match the locally linked project and team.");
|
|
2605
|
+
const expectedRoot = relative2(local.repositoryRoot, local.projectDirectory).split(sep).join("/");
|
|
2606
|
+
if ((project.rootDirectory ?? "") !== expectedRoot)
|
|
2607
|
+
fail("vercel_root_conflict", "Vercel Root Directory and the selected local app must identify the same application.");
|
|
2608
|
+
if (project.nodeVersion !== "22.x" || project.framework !== "nextjs")
|
|
2609
|
+
fail("vercel_framework_conflict", "The bound Vercel project must use Next.js with Node.js 22 before setup.");
|
|
2610
|
+
if (project.link && project.link.productionBranch !== local.git.branch)
|
|
2611
|
+
fail("vercel_production_branch_conflict", "The local branch differs from the bound Vercel Production branch.");
|
|
2612
|
+
if (project.link?.repo && project.link.org && !local.git.remote?.replace(/\.git$/u, "").endsWith(`${project.link.org}/${project.link.repo}`))
|
|
2613
|
+
fail("vercel_git_conflict", "The local origin repository differs from the Vercel Git connection.");
|
|
2614
|
+
const env = z28.object({
|
|
2615
|
+
envs: z28.array(z28.object({
|
|
2616
|
+
key: z28.string(),
|
|
2617
|
+
value: z28.string().optional(),
|
|
2618
|
+
target: z28.array(z28.string()).optional()
|
|
2619
|
+
}))
|
|
2620
|
+
}).parse(await setupVercelApi(linkDirectory, `/v10/projects/${linked.projectId}/env?teamId=${linked.orgId}`));
|
|
2621
|
+
const corepack = env.envs.some((item) => item.key === "ENABLE_EXPERIMENTAL_COREPACK" && item.value === "1" && item.target?.includes("production"));
|
|
2622
|
+
const install = project.installCommand ?? null;
|
|
2623
|
+
const selected = corepack ? "corepack" : install ? "install_override" : "automatic";
|
|
2624
|
+
if (local.packageManager.declared && selected === "automatic")
|
|
2625
|
+
fail("vercel_package_manager_pin_unconfirmed", "This project declares an exact packageManager but Vercel automatic selection does not bind that version. Enable its supported Corepack selection or set an exact install AND build override in the existing project, then rerun preflight. No package, lockfile or provider setting was changed.");
|
|
2626
|
+
if (install && /\b(?:yarn|bun)\b/u.test(install))
|
|
2627
|
+
fail("vercel_package_manager_conflict", "The Vercel install override selects an unsupported package manager.");
|
|
2628
|
+
const overridePin = install ? /\b(npm|pnpm)@(\d+\.\d+\.\d+)\b/u.exec(install) : null;
|
|
2629
|
+
if (overridePin && overridePin[1] !== local.packageManager.name)
|
|
2630
|
+
fail("vercel_package_manager_conflict", "The provider override selects a different package manager than the canonical lockfile.");
|
|
2631
|
+
const overrideFamily = install ? /(?:^|[;&|]\s*)(npm|pnpm)\s+(?:ci|install)\b/u.exec(install)?.[1] : null;
|
|
2632
|
+
if (overrideFamily && overrideFamily !== local.packageManager.name)
|
|
2633
|
+
fail("vercel_package_manager_conflict", "The provider install command conflicts with the canonical lockfile.");
|
|
2634
|
+
if (overridePin && local.packageManager.declared && `${overridePin[1]}@${overridePin[2]}` !== local.packageManager.declared)
|
|
2635
|
+
fail("vercel_package_manager_conflict", "The Vercel install override conflicts with the exact packageManager declaration.");
|
|
2636
|
+
return {
|
|
2637
|
+
status: "ready",
|
|
2638
|
+
local,
|
|
2639
|
+
provider: {
|
|
2640
|
+
projectId: project.id,
|
|
2641
|
+
teamId: project.accountId,
|
|
2642
|
+
name: project.name,
|
|
2643
|
+
rootDirectory: expectedRoot,
|
|
2644
|
+
nodeVersion: project.nodeVersion,
|
|
2645
|
+
git: project.link,
|
|
2646
|
+
installCommand: install,
|
|
2647
|
+
buildCommand: project.buildCommand ?? null,
|
|
2648
|
+
packageManagerSelection: selected,
|
|
2649
|
+
declaredPackageManager: local.packageManager.declared,
|
|
2650
|
+
observedPackageManager: null
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
} catch (error) {
|
|
2654
|
+
return {
|
|
2655
|
+
status: "action_required",
|
|
2656
|
+
code: error instanceof SetupFailure ? error.code : "invalid_local_project",
|
|
2657
|
+
message: error instanceof SetupFailure ? error.message : "The selected project or provider response could not be validated. Check the application manifest and local project access.",
|
|
2658
|
+
...local ? { local } : {}
|
|
2659
|
+
};
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
function safeGitRemote(value) {
|
|
2663
|
+
if (!value)
|
|
2664
|
+
return null;
|
|
2665
|
+
if (!value.includes("://"))
|
|
2666
|
+
return value;
|
|
2667
|
+
try {
|
|
2668
|
+
const url = new URL(value);
|
|
2669
|
+
url.username = "";
|
|
2670
|
+
url.password = "";
|
|
2671
|
+
url.search = "";
|
|
2672
|
+
url.hash = "";
|
|
2673
|
+
return url.toString().replace(/\/$/u, "");
|
|
2674
|
+
} catch {
|
|
2675
|
+
return null;
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
// ../cli/dist/commands/init.js
|
|
2680
|
+
var siteSetupBootstrapDataSchema = z29.object({
|
|
2681
|
+
credentialPurpose: z29.literal("site_setup"),
|
|
2682
|
+
apiBaseUrl: z29.string().url(),
|
|
2683
|
+
siteId: z29.string().uuid(),
|
|
2684
|
+
publicSiteKeyId: z29.string().uuid(),
|
|
2685
|
+
publicSiteKey: z29.string().trim().min(1),
|
|
2686
|
+
accessToken: z29.string().trim().min(1),
|
|
2687
|
+
siteRevalidationSecret: z29.string().regex(/^[A-Za-z0-9_-]{43}$/u),
|
|
2688
|
+
runId: z29.string().uuid(),
|
|
2689
|
+
packages: z29.object({
|
|
2690
|
+
siteplane: z29.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u),
|
|
2691
|
+
runtimeNext: z29.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
|
|
2692
|
+
}).strict()
|
|
2007
2693
|
}).strict();
|
|
2008
|
-
var featureBootstrapDataSchema =
|
|
2009
|
-
credentialPurpose:
|
|
2010
|
-
apiBaseUrl:
|
|
2011
|
-
siteId:
|
|
2012
|
-
accessToken:
|
|
2694
|
+
var featureBootstrapDataSchema = z29.object({
|
|
2695
|
+
credentialPurpose: z29.enum(["analytics", "booking"]),
|
|
2696
|
+
apiBaseUrl: z29.string().url(),
|
|
2697
|
+
siteId: z29.string().uuid(),
|
|
2698
|
+
accessToken: z29.string().trim().min(1)
|
|
2013
2699
|
}).strict();
|
|
2014
|
-
var bootstrapResponseSchema =
|
|
2015
|
-
ok:
|
|
2016
|
-
data:
|
|
2700
|
+
var bootstrapResponseSchema = z29.object({
|
|
2701
|
+
ok: z29.literal(true),
|
|
2702
|
+
data: z29.discriminatedUnion("credentialPurpose", [
|
|
2017
2703
|
siteSetupBootstrapDataSchema,
|
|
2018
2704
|
featureBootstrapDataSchema
|
|
2019
2705
|
])
|
|
2020
2706
|
}).strict();
|
|
2021
2707
|
|
|
2022
2708
|
// ../cli/dist/commands/scan.js
|
|
2023
|
-
import { readdir } from "fs/promises";
|
|
2024
|
-
import { extname, join as
|
|
2709
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
2710
|
+
import { extname, join as join8 } from "path";
|
|
2025
2711
|
var defaultScanRoots = ["app", "src", "pages", "components", "lib"];
|
|
2026
2712
|
var excludedDirectories = /* @__PURE__ */ new Set([
|
|
2027
2713
|
".git",
|
|
@@ -2039,14 +2725,14 @@ async function resolveScanFilePaths(filePaths, options = {}) {
|
|
|
2039
2725
|
return filePaths;
|
|
2040
2726
|
}
|
|
2041
2727
|
const projectDir = options.projectDir ?? process.cwd();
|
|
2042
|
-
const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(
|
|
2728
|
+
const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join8(projectDir, root))));
|
|
2043
2729
|
return [...new Set(discovered.flat())].sort();
|
|
2044
2730
|
}
|
|
2045
2731
|
async function collectSourceFiles(directory) {
|
|
2046
|
-
const entries = await
|
|
2732
|
+
const entries = await readdir2(directory, { withFileTypes: true }).catch(() => []);
|
|
2047
2733
|
const files = [];
|
|
2048
2734
|
for (const entry of entries) {
|
|
2049
|
-
const entryPath =
|
|
2735
|
+
const entryPath = join8(directory, entry.name);
|
|
2050
2736
|
if (entry.isDirectory()) {
|
|
2051
2737
|
if (!excludedDirectories.has(entry.name)) {
|
|
2052
2738
|
files.push(...await collectSourceFiles(entryPath));
|
|
@@ -2062,17 +2748,17 @@ async function collectSourceFiles(directory) {
|
|
|
2062
2748
|
|
|
2063
2749
|
// ../cli/dist/commands/site-setup.js
|
|
2064
2750
|
import { execFile as execFile2 } from "child_process";
|
|
2065
|
-
import { readFile as
|
|
2751
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
2066
2752
|
import { promisify as promisify2 } from "util";
|
|
2067
|
-
import { z as
|
|
2753
|
+
import { z as z30 } from "zod";
|
|
2068
2754
|
|
|
2069
2755
|
// ../cli/dist/scan/next-source-scan.js
|
|
2070
2756
|
import ts2 from "typescript";
|
|
2071
|
-
import { isAbsolute, relative as
|
|
2757
|
+
import { isAbsolute, relative as relative4 } from "path";
|
|
2072
2758
|
var eventPreviewHandlerMissingMessage = "Event preview fields must consume preview values with useSiteplanePreviewText from @siteplane/runtime-next/client or a siteplane:preview-value-applied listener.";
|
|
2073
2759
|
var valueCallUnusedMessage = "Siteplane value calls must feed rendered content. Assign or await the returned value and render that value instead of ignoring the call.";
|
|
2074
2760
|
var legacyEditableComponentPrefix = "Editable";
|
|
2075
|
-
var editableComponentNames = new Set(["Image", "Text", "LongText", "Link"].map((
|
|
2761
|
+
var editableComponentNames = new Set(["Image", "Text", "LongText", "Link"].map((name2) => `${legacyEditableComponentPrefix}${name2}`));
|
|
2076
2762
|
var functionTypeByName = {
|
|
2077
2763
|
text: "text",
|
|
2078
2764
|
longText: "longText",
|
|
@@ -2610,17 +3296,17 @@ function readObjectLiteral(expression) {
|
|
|
2610
3296
|
if (!ts2.isPropertyAssignment(property)) {
|
|
2611
3297
|
continue;
|
|
2612
3298
|
}
|
|
2613
|
-
const
|
|
2614
|
-
if (!
|
|
3299
|
+
const name2 = getPropertyName(property.name);
|
|
3300
|
+
if (!name2) {
|
|
2615
3301
|
continue;
|
|
2616
3302
|
}
|
|
2617
|
-
value[
|
|
3303
|
+
value[name2] = staticExpressionValue(property.initializer);
|
|
2618
3304
|
}
|
|
2619
3305
|
return value;
|
|
2620
3306
|
}
|
|
2621
|
-
function getPropertyName(
|
|
2622
|
-
if (ts2.isIdentifier(
|
|
2623
|
-
return
|
|
3307
|
+
function getPropertyName(name2) {
|
|
3308
|
+
if (ts2.isIdentifier(name2) || ts2.isStringLiteral(name2)) {
|
|
3309
|
+
return name2.text;
|
|
2624
3310
|
}
|
|
2625
3311
|
return null;
|
|
2626
3312
|
}
|
|
@@ -2646,9 +3332,9 @@ function collectEventPreviewComponentPropUsages(node, eventPreviewAttrVariables,
|
|
|
2646
3332
|
});
|
|
2647
3333
|
}
|
|
2648
3334
|
}
|
|
2649
|
-
function getJsxAttributeName(
|
|
2650
|
-
if (ts2.isIdentifier(
|
|
2651
|
-
return
|
|
3335
|
+
function getJsxAttributeName(name2) {
|
|
3336
|
+
if (ts2.isIdentifier(name2)) {
|
|
3337
|
+
return name2.text;
|
|
2652
3338
|
}
|
|
2653
3339
|
return void 0;
|
|
2654
3340
|
}
|
|
@@ -2673,8 +3359,8 @@ function getFunctionComponentName(node) {
|
|
|
2673
3359
|
}
|
|
2674
3360
|
return void 0;
|
|
2675
3361
|
}
|
|
2676
|
-
function isComponentName(
|
|
2677
|
-
return /^[A-Z]/.test(
|
|
3362
|
+
function isComponentName(name2) {
|
|
3363
|
+
return /^[A-Z]/.test(name2);
|
|
2678
3364
|
}
|
|
2679
3365
|
function getAssignedVariableName(node) {
|
|
2680
3366
|
let current = node;
|
|
@@ -2722,7 +3408,7 @@ function inferRouteHint(filePath) {
|
|
|
2722
3408
|
return route ? `/${route}` : "/";
|
|
2723
3409
|
}
|
|
2724
3410
|
function toRepositoryRelativePosixPath(filePath, projectRoot) {
|
|
2725
|
-
const path = isAbsolute(filePath) ?
|
|
3411
|
+
const path = isAbsolute(filePath) ? relative4(projectRoot, filePath) : filePath;
|
|
2726
3412
|
return path.replaceAll("\\", "/");
|
|
2727
3413
|
}
|
|
2728
3414
|
function isPositionalFieldReference(value) {
|
|
@@ -2731,54 +3417,354 @@ function isPositionalFieldReference(value) {
|
|
|
2731
3417
|
|
|
2732
3418
|
// ../cli/dist/commands/site-setup.js
|
|
2733
3419
|
var execFileAsync2 = promisify2(execFile2);
|
|
2734
|
-
var safeErrorSchema =
|
|
2735
|
-
code:
|
|
2736
|
-
message:
|
|
3420
|
+
var safeErrorSchema = z30.object({
|
|
3421
|
+
code: z30.string().trim().min(1),
|
|
3422
|
+
message: z30.string().trim().min(1)
|
|
2737
3423
|
}).passthrough();
|
|
2738
|
-
var errorResponseSchema2 =
|
|
2739
|
-
var contextDataSchema =
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
"ready_for_review"
|
|
2750
|
-
]),
|
|
2751
|
-
fieldContractHash: z27.string().nullable(),
|
|
2752
|
-
deploymentOrigin: z27.string().nullable(),
|
|
2753
|
-
deploymentRevision: z27.string().nullable(),
|
|
2754
|
-
errorCode: z27.string().nullable(),
|
|
2755
|
-
errorMessage: z27.string().nullable()
|
|
2756
|
-
}),
|
|
2757
|
-
structureHandoff: z27.object({
|
|
2758
|
-
pendingFields: z27.array(setupCorrectionItemSchema).max(50),
|
|
2759
|
-
ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema
|
|
2760
|
-
}).strict().nullable(),
|
|
2761
|
-
allowedTasks: z27.array(z27.string()),
|
|
2762
|
-
requiredEnvironmentNames: z27.array(z27.string())
|
|
3424
|
+
var errorResponseSchema2 = z30.object({ ok: z30.literal(false), error: safeErrorSchema }).passthrough();
|
|
3425
|
+
var contextDataSchema = z30.object({ task: siteSetupTaskSchema }).strict();
|
|
3426
|
+
var contextResponseSchema = z30.object({ ok: z30.literal(true), data: contextDataSchema }).strict();
|
|
3427
|
+
var applyDataSchema = z30.object({
|
|
3428
|
+
status: z30.enum(["applied", "ready_for_review"]),
|
|
3429
|
+
runId: z30.string().uuid().optional(),
|
|
3430
|
+
contractVersionId: z30.string().uuid().optional(),
|
|
3431
|
+
fieldContractHash: z30.string().regex(/^sha256:[0-9a-f]{64}$/u),
|
|
3432
|
+
editorDefinitionHash: z30.string().regex(/^sha256:[0-9a-f]{64}$/u).optional(),
|
|
3433
|
+
fieldCount: z30.number().int().nonnegative().optional(),
|
|
3434
|
+
routeCount: z30.number().int().nonnegative().optional()
|
|
2763
3435
|
}).strict();
|
|
2764
|
-
var
|
|
2765
|
-
var
|
|
2766
|
-
status:
|
|
2767
|
-
runId:
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
editorDefinitionHash: z27.string().regex(/^sha256:[0-9a-f]{64}$/u).optional(),
|
|
2771
|
-
fieldCount: z27.number().int().nonnegative().optional(),
|
|
2772
|
-
routeCount: z27.number().int().nonnegative().optional()
|
|
3436
|
+
var applyResponseSchema = z30.object({ ok: z30.literal(true), data: applyDataSchema }).strict();
|
|
3437
|
+
var verifyDataSchema = z30.object({
|
|
3438
|
+
status: z30.literal("ready_for_review"),
|
|
3439
|
+
runId: z30.string().uuid().optional(),
|
|
3440
|
+
deploymentOrigin: z30.string().url().optional(),
|
|
3441
|
+
deploymentRevision: z30.string().optional()
|
|
2773
3442
|
}).strict();
|
|
2774
|
-
var
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
3443
|
+
var verifyResponseSchema = z30.object({ ok: z30.literal(true), data: verifyDataSchema }).strict();
|
|
3444
|
+
async function siteSetupContextCommand(input) {
|
|
3445
|
+
const response = await postSiteSetup(input, "context", {});
|
|
3446
|
+
const parsed = contextResponseSchema.safeParse(response.payload);
|
|
3447
|
+
if (response.ok && parsed.success) {
|
|
3448
|
+
return { status: "ok", ...parsed.data.data };
|
|
3449
|
+
}
|
|
3450
|
+
return actionRequired(response.payload, "Siteplane setup context is unavailable.");
|
|
3451
|
+
}
|
|
3452
|
+
async function siteSetupVerifyCommand(input) {
|
|
3453
|
+
const resolveSourceFiles = input.resolveSourceFiles ?? resolveScanFilePaths;
|
|
3454
|
+
const readSourceFile = input.readSourceFile ?? ((path) => readFile9(path, "utf8"));
|
|
3455
|
+
const paths = await resolveSourceFiles([], { projectDir: input.projectDir });
|
|
3456
|
+
const sources = await Promise.all(paths.map(readSourceFile));
|
|
3457
|
+
if (!sources.some(hasMountedFieldRuntimeBridge)) {
|
|
3458
|
+
return {
|
|
3459
|
+
status: "action_required",
|
|
3460
|
+
code: "missing_field_runtime_bridge",
|
|
3461
|
+
message: "Mount FieldRuntimeBridge from @siteplane/runtime-next/client before deployment verification."
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3464
|
+
const deploymentRevision = await (input.readRevision ?? readGitRevision)(input.projectDir);
|
|
3465
|
+
const response = await postSiteSetup(input, "verify", {
|
|
3466
|
+
deploymentUrl: input.deploymentUrl,
|
|
3467
|
+
deploymentRevision,
|
|
3468
|
+
...input.wait ? { wait: true } : {}
|
|
3469
|
+
});
|
|
3470
|
+
const parsed = verifyResponseSchema.safeParse(response.payload);
|
|
3471
|
+
if (response.ok && parsed.success) {
|
|
3472
|
+
return parsed.data.data;
|
|
3473
|
+
}
|
|
3474
|
+
return actionRequired(response.payload, "Siteplane deployment verification failed.");
|
|
3475
|
+
}
|
|
3476
|
+
function hasMountedFieldRuntimeBridge(source) {
|
|
3477
|
+
return /from\s+["']@siteplane\/runtime-next(?:\/client)?["']/u.test(source) && /<FieldRuntimeBridge(?:\s|\/|>)/u.test(source);
|
|
3478
|
+
}
|
|
3479
|
+
async function postSiteSetup(input, operation, body) {
|
|
3480
|
+
const [config, credentials] = await Promise.all([
|
|
3481
|
+
readProjectConfig(input.projectDir),
|
|
3482
|
+
readLocalCredentials(input.projectDir)
|
|
3483
|
+
]);
|
|
3484
|
+
try {
|
|
3485
|
+
const response = await (input.fetcher ?? fetch)(`${config.apiBaseUrl.replace(/\/$/u, "")}/api/cli/setup/${operation}`, {
|
|
3486
|
+
method: "POST",
|
|
3487
|
+
signal: AbortSignal.timeout(Math.max(1, Math.min(2e4, (input.deadline ?? Date.now() + 2e4) - Date.now()))),
|
|
3488
|
+
headers: {
|
|
3489
|
+
authorization: `Bearer ${credentials.accessToken}`,
|
|
3490
|
+
"content-type": "application/json",
|
|
3491
|
+
...input.vercelAutomationBypassSecret?.trim() ? {
|
|
3492
|
+
"x-vercel-protection-bypass": input.vercelAutomationBypassSecret.trim()
|
|
3493
|
+
} : {}
|
|
3494
|
+
},
|
|
3495
|
+
body: JSON.stringify(body)
|
|
3496
|
+
});
|
|
3497
|
+
const payload = await response.json().catch(() => null);
|
|
3498
|
+
return { ok: response.ok, payload };
|
|
3499
|
+
} catch {
|
|
3500
|
+
return {
|
|
3501
|
+
ok: false,
|
|
3502
|
+
payload: {
|
|
3503
|
+
ok: false,
|
|
3504
|
+
error: {
|
|
3505
|
+
code: "site_setup.transport_failed",
|
|
3506
|
+
message: "The setup request was not acknowledged. Reload the existing task before retrying; no credential values are included."
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
};
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
function actionRequired(payload, fallbackMessage) {
|
|
3513
|
+
const parsed = errorResponseSchema2.safeParse(payload);
|
|
3514
|
+
return parsed.success ? {
|
|
3515
|
+
status: "action_required",
|
|
3516
|
+
code: parsed.data.error.code,
|
|
3517
|
+
message: parsed.data.error.message
|
|
3518
|
+
} : {
|
|
3519
|
+
status: "action_required",
|
|
3520
|
+
code: "invalid_server_response",
|
|
3521
|
+
message: fallbackMessage
|
|
3522
|
+
};
|
|
3523
|
+
}
|
|
3524
|
+
async function readGitRevision(projectDir) {
|
|
3525
|
+
const { stdout } = await execFileAsync2("git", ["rev-parse", "HEAD"], {
|
|
3526
|
+
cwd: projectDir,
|
|
3527
|
+
encoding: "utf8"
|
|
3528
|
+
});
|
|
3529
|
+
const revision = stdout.trim();
|
|
3530
|
+
if (!revision) {
|
|
3531
|
+
throw new Error("A committed Git revision is required before setup verify.");
|
|
3532
|
+
}
|
|
3533
|
+
return revision;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
// ../cli/dist/commands/setup-prepare.js
|
|
3537
|
+
import { access as access4, lstat as lstat2, mkdir as mkdir6, open as open3, readFile as readFile10, rename as rename3, rm as rm3 } from "fs/promises";
|
|
3538
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
3539
|
+
import { dirname as dirname7, join as join9, relative as relative5, sep as sep2 } from "path";
|
|
3540
|
+
import ts3 from "typescript";
|
|
3541
|
+
|
|
3542
|
+
// ../cli/dist/commands/setup-lock.js
|
|
3543
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
3544
|
+
import { lstat as lstat3, mkdir as mkdir7, open as open4, readFile as readFile11, rm as rm4, rmdir } from "fs/promises";
|
|
3545
|
+
import { resolve as resolve2 } from "path";
|
|
3546
|
+
import { z as z31 } from "zod";
|
|
3547
|
+
var ownerSchema = z31.object({ pid: z31.number().int().positive(), nonce: z31.string().uuid() }).strict();
|
|
3548
|
+
|
|
3549
|
+
// ../cli/dist/config/build-provenance.js
|
|
3550
|
+
import { createHash as createHash3 } from "crypto";
|
|
3551
|
+
import { execFile as execFile3 } from "child_process";
|
|
3552
|
+
import { lstat as lstat4, readFile as readFile12, writeFile as writeFile5, mkdir as mkdir8 } from "fs/promises";
|
|
3553
|
+
import { dirname as dirname8, isAbsolute as isAbsolute2, join as join10, relative as relative6, resolve as resolve3, sep as sep3 } from "path";
|
|
3554
|
+
import { isDeepStrictEqual, promisify as promisify3 } from "util";
|
|
3555
|
+
import { z as z32 } from "zod";
|
|
3556
|
+
var execute = promisify3(execFile3);
|
|
3557
|
+
var name = ".siteplane/build-source.json";
|
|
3558
|
+
var oid = z32.string().regex(/^[0-9a-f]{40}$/u);
|
|
3559
|
+
var entrySchema = z32.object({
|
|
3560
|
+
path: z32.string().min(1).max(4096),
|
|
3561
|
+
mode: z32.enum(["100644", "100755", "120000"]),
|
|
3562
|
+
oid
|
|
3563
|
+
}).strict();
|
|
3564
|
+
var schema = z32.object({
|
|
3565
|
+
version: z32.literal(2),
|
|
3566
|
+
revision: oid,
|
|
3567
|
+
commit: z32.string().min(1).max(1048576),
|
|
3568
|
+
entries: z32.array(entrySchema).min(1).max(1e5),
|
|
3569
|
+
providerConfigurations: z32.array(z32.object({
|
|
3570
|
+
path: z32.string().max(4096).regex(/(?:^|\/)vercel\.json$/u),
|
|
3571
|
+
source: z32.string().max(1048576)
|
|
3572
|
+
}).strict()).max(1e3)
|
|
2780
3573
|
}).strict();
|
|
2781
|
-
var
|
|
3574
|
+
var gitHash = (type, content) => createHash3("sha1").update(`${type} ${content.length}\0`).update(content).digest("hex");
|
|
3575
|
+
async function writeBuildProvenance(checkout, revision) {
|
|
3576
|
+
const commit = (await execute("git", ["cat-file", "commit", revision], {
|
|
3577
|
+
cwd: checkout,
|
|
3578
|
+
maxBuffer: 1048576
|
|
3579
|
+
})).stdout;
|
|
3580
|
+
const tree = (await execute("git", ["ls-tree", "-rz", "--full-tree", revision], {
|
|
3581
|
+
cwd: checkout,
|
|
3582
|
+
maxBuffer: 16777216
|
|
3583
|
+
})).stdout;
|
|
3584
|
+
const entries = tree.split("\0").filter(Boolean).map((line) => {
|
|
3585
|
+
const match = /^(100644|100755|120000) blob ([0-9a-f]{40})\t([\s\S]+)$/u.exec(line);
|
|
3586
|
+
if (!match)
|
|
3587
|
+
throw new Error("Git submodules or unsupported tracked objects need an explicit deployment configuration.");
|
|
3588
|
+
return { path: match[3], mode: match[1], oid: match[2] };
|
|
3589
|
+
});
|
|
3590
|
+
for (const entry of entries) {
|
|
3591
|
+
if (entry.mode !== "120000")
|
|
3592
|
+
continue;
|
|
3593
|
+
const { readlink: readlink2 } = await import("fs/promises");
|
|
3594
|
+
const path = join10(checkout, entry.path);
|
|
3595
|
+
const target2 = resolve3(dirname8(path), await readlink2(path));
|
|
3596
|
+
const bound = relative6(checkout, target2);
|
|
3597
|
+
if (bound.startsWith("..") || isAbsolute2(bound))
|
|
3598
|
+
throw new Error("A tracked symbolic link escapes the committed upload; resolve that source boundary before deployment.");
|
|
3599
|
+
}
|
|
3600
|
+
const providerConfigurations = await Promise.all(entries.filter((entry) => /(?:^|\/)vercel\.json$/u.test(entry.path)).map(async (entry) => ({
|
|
3601
|
+
path: entry.path,
|
|
3602
|
+
source: await readFile12(join10(checkout, entry.path), "utf8")
|
|
3603
|
+
})));
|
|
3604
|
+
const record = schema.parse({
|
|
3605
|
+
version: 2,
|
|
3606
|
+
revision,
|
|
3607
|
+
commit,
|
|
3608
|
+
entries,
|
|
3609
|
+
providerConfigurations
|
|
3610
|
+
});
|
|
3611
|
+
const target = join10(checkout, name);
|
|
3612
|
+
await mkdir8(dirname8(target), { recursive: true, mode: 448 });
|
|
3613
|
+
await writeFile5(target, JSON.stringify(record), { flag: "wx", mode: 384 });
|
|
3614
|
+
}
|
|
3615
|
+
async function readBuildProvenance(projectDirectory) {
|
|
3616
|
+
let root = resolve3(projectDirectory);
|
|
3617
|
+
let raw = null;
|
|
3618
|
+
for (; ; ) {
|
|
3619
|
+
raw = await readFile12(join10(root, name), "utf8").catch((error) => {
|
|
3620
|
+
if (error.code === "ENOENT")
|
|
3621
|
+
return null;
|
|
3622
|
+
throw error;
|
|
3623
|
+
});
|
|
3624
|
+
if (raw !== null || dirname8(root) === root)
|
|
3625
|
+
break;
|
|
3626
|
+
root = dirname8(root);
|
|
3627
|
+
}
|
|
3628
|
+
if (raw === null)
|
|
3629
|
+
return null;
|
|
3630
|
+
if (Buffer.byteLength(raw) > 16777216)
|
|
3631
|
+
throw new Error("Build provenance is oversized.");
|
|
3632
|
+
const record = schema.parse(JSON.parse(raw));
|
|
3633
|
+
if (gitHash("commit", Buffer.from(record.commit)) !== record.revision)
|
|
3634
|
+
throw new Error("The build revision is not the supplied Git commit.");
|
|
3635
|
+
const expectedTree = /^tree ([0-9a-f]{40})\n/u.exec(record.commit)?.[1];
|
|
3636
|
+
if (treeHash(record.entries) !== expectedTree)
|
|
3637
|
+
throw new Error("The build file inventory does not belong to this Git commit.");
|
|
3638
|
+
const bound = new Map(record.entries.map((entry) => [entry.path, entry]));
|
|
3639
|
+
const configurations = /* @__PURE__ */ new Map();
|
|
3640
|
+
for (const config of record.providerConfigurations) {
|
|
3641
|
+
const entry = bound.get(config.path);
|
|
3642
|
+
if (!entry || entry.mode === "120000" || configurations.has(config.path) || gitHash("blob", Buffer.from(config.source)) !== entry.oid)
|
|
3643
|
+
throw new Error("The original provider configuration is not bound to the Git commit.");
|
|
3644
|
+
configurations.set(config.path, config.source);
|
|
3645
|
+
}
|
|
3646
|
+
if (record.entries.some((entry) => /(?:^|\/)vercel\.json$/u.test(entry.path) && !configurations.has(entry.path)))
|
|
3647
|
+
throw new Error("The committed provider configuration is missing from the build provenance.");
|
|
3648
|
+
const appRelative = relative6(root, projectDirectory).split(sep3).join("/");
|
|
3649
|
+
if (!bound.has(appRelative ? `${appRelative}/package.json` : "package.json"))
|
|
3650
|
+
throw new Error("The selected app is not part of the committed upload.");
|
|
3651
|
+
for (const entry of record.entries) {
|
|
3652
|
+
const path = join10(root, entry.path);
|
|
3653
|
+
const stat = await lstat4(path).catch((error) => {
|
|
3654
|
+
if (error.code === "ENOENT")
|
|
3655
|
+
return null;
|
|
3656
|
+
throw error;
|
|
3657
|
+
});
|
|
3658
|
+
if (!stat)
|
|
3659
|
+
continue;
|
|
3660
|
+
if (stat.isSymbolicLink()) {
|
|
3661
|
+
const { readlink: readlink2 } = await import("fs/promises");
|
|
3662
|
+
if (entry.mode !== "120000" || gitHash("blob", Buffer.from(await readlink2(path))) !== entry.oid)
|
|
3663
|
+
throw new Error("A deployed symbolic link differs from the commit.");
|
|
3664
|
+
} else {
|
|
3665
|
+
const contents = stat.isFile() ? await readFile12(path) : null;
|
|
3666
|
+
if (contents && entry.mode !== "120000" && gitHash("blob", contents) === entry.oid)
|
|
3667
|
+
continue;
|
|
3668
|
+
const original = configurations.get(entry.path);
|
|
3669
|
+
if (contents && original && entry.mode !== "120000") {
|
|
3670
|
+
try {
|
|
3671
|
+
const object = z32.record(z32.string(), z32.unknown());
|
|
3672
|
+
const actual = object.parse(JSON.parse(contents.toString("utf8")));
|
|
3673
|
+
const expected = object.parse(JSON.parse(original));
|
|
3674
|
+
if (!Object.hasOwn(expected, "version") && actual.version === 2)
|
|
3675
|
+
delete actual.version;
|
|
3676
|
+
if (!Object.hasOwn(expected, "name") && typeof actual.name === "string" && /^[a-z0-9][a-z0-9._-]{0,99}$/iu.test(actual.name))
|
|
3677
|
+
delete actual.name;
|
|
3678
|
+
if (isDeepStrictEqual(actual, expected))
|
|
3679
|
+
continue;
|
|
3680
|
+
} catch {
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
throw new Error(`A deployed file ${JSON.stringify(entry.path).slice(0, 260)} differs from the committed upload.`);
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
return record.revision;
|
|
3687
|
+
}
|
|
3688
|
+
function treeHash(entries) {
|
|
3689
|
+
const root = /* @__PURE__ */ new Map();
|
|
3690
|
+
for (const entry of entries) {
|
|
3691
|
+
const parts = entry.path.split("/");
|
|
3692
|
+
if (parts.some((part) => !part || part === "." || part === ".." || part.includes("\0") || part.includes("\\")))
|
|
3693
|
+
throw new Error("Unsafe Git inventory path.");
|
|
3694
|
+
let tree = root;
|
|
3695
|
+
for (const part of parts.slice(0, -1)) {
|
|
3696
|
+
let child = tree.get(part);
|
|
3697
|
+
if (!child) {
|
|
3698
|
+
child = /* @__PURE__ */ new Map();
|
|
3699
|
+
tree.set(part, child);
|
|
3700
|
+
}
|
|
3701
|
+
if (!(child instanceof Map))
|
|
3702
|
+
throw new Error("Conflicting Git inventory path.");
|
|
3703
|
+
tree = child;
|
|
3704
|
+
}
|
|
3705
|
+
const leaf = parts.at(-1);
|
|
3706
|
+
if (tree.has(leaf))
|
|
3707
|
+
throw new Error("Duplicate Git inventory path.");
|
|
3708
|
+
tree.set(leaf, { mode: entry.mode, oid: entry.oid });
|
|
3709
|
+
}
|
|
3710
|
+
const hash2 = (tree) => {
|
|
3711
|
+
const sorted = [...tree].sort(([a, av], [b, bv]) => Buffer.compare(Buffer.from(a + (av instanceof Map ? "/" : "")), Buffer.from(b + (bv instanceof Map ? "/" : ""))));
|
|
3712
|
+
return gitHash("tree", Buffer.concat(sorted.map(([path, value]) => Buffer.concat([
|
|
3713
|
+
Buffer.from(`${value instanceof Map ? "40000" : value.mode} ${path}\0`),
|
|
3714
|
+
Buffer.from(value instanceof Map ? hash2(value) : value.oid, "hex")
|
|
3715
|
+
]))));
|
|
3716
|
+
};
|
|
3717
|
+
return hash2(root);
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
// ../cli/dist/commands/setup-deploy.js
|
|
3721
|
+
import { createHash as createHash4, randomBytes, randomUUID as randomUUID6 } from "crypto";
|
|
3722
|
+
import { access as access5, mkdir as mkdir9, mkdtemp, rm as rm5, writeFile as writeFile6 } from "fs/promises";
|
|
3723
|
+
import { tmpdir } from "os";
|
|
3724
|
+
import { join as join11 } from "path";
|
|
3725
|
+
import { z as z33 } from "zod";
|
|
3726
|
+
var envSchema = z33.object({
|
|
3727
|
+
id: z33.string(),
|
|
3728
|
+
key: z33.string(),
|
|
3729
|
+
target: z33.array(z33.string()),
|
|
3730
|
+
type: z33.string(),
|
|
3731
|
+
comment: z33.string().optional(),
|
|
3732
|
+
updatedAt: z33.number().optional()
|
|
3733
|
+
});
|
|
3734
|
+
var deploymentSchema = z33.object({
|
|
3735
|
+
id: z33.string(),
|
|
3736
|
+
projectId: z33.string(),
|
|
3737
|
+
ownerId: z33.string().optional(),
|
|
3738
|
+
target: z33.string().nullable(),
|
|
3739
|
+
readyState: z33.string(),
|
|
3740
|
+
createdAt: z33.number(),
|
|
3741
|
+
url: z33.string(),
|
|
3742
|
+
meta: z33.record(z33.string(), z33.unknown()).optional(),
|
|
3743
|
+
gitSource: z33.object({ sha: z33.string().optional() }).nullable().optional()
|
|
3744
|
+
});
|
|
3745
|
+
var buildProofSchema = z33.object({
|
|
3746
|
+
node: z33.string(),
|
|
3747
|
+
packageManager: z33.enum(["npm", "pnpm"]),
|
|
3748
|
+
packageManagerVersion: z33.string(),
|
|
3749
|
+
lockfileHash: z33.string(),
|
|
3750
|
+
revision: z33.string(),
|
|
3751
|
+
fieldContractHash: z33.string(),
|
|
3752
|
+
siteplane: z33.string(),
|
|
3753
|
+
runtimeNext: z33.string(),
|
|
3754
|
+
next: z33.string(),
|
|
3755
|
+
react: z33.string()
|
|
3756
|
+
}).strict();
|
|
3757
|
+
var defaults = {
|
|
3758
|
+
preflight: setupPreflightCommand,
|
|
3759
|
+
context: siteSetupContextCommand,
|
|
3760
|
+
api: setupVercelApi,
|
|
3761
|
+
process: setupProcess,
|
|
3762
|
+
verify: siteSetupVerifyCommand,
|
|
3763
|
+
post: postSiteSetup,
|
|
3764
|
+
writeBuildProvenance,
|
|
3765
|
+
now: Date.now,
|
|
3766
|
+
pause: (milliseconds) => new Promise((resolve5) => setTimeout(resolve5, milliseconds))
|
|
3767
|
+
};
|
|
2782
3768
|
|
|
2783
3769
|
// src/next.ts
|
|
2784
3770
|
var SiteplaneNextContractError = class extends Error {
|
|
@@ -2790,14 +3776,14 @@ var SiteplaneNextContractError = class extends Error {
|
|
|
2790
3776
|
code;
|
|
2791
3777
|
};
|
|
2792
3778
|
async function scanNextProjectFieldContract(projectDir) {
|
|
2793
|
-
const resolvedProjectDir =
|
|
3779
|
+
const resolvedProjectDir = resolve4(projectDir);
|
|
2794
3780
|
const filePaths = await resolveScanFilePaths([], {
|
|
2795
3781
|
projectDir: resolvedProjectDir
|
|
2796
3782
|
});
|
|
2797
3783
|
const files = await Promise.all(
|
|
2798
3784
|
filePaths.map(async (filePath) => ({
|
|
2799
3785
|
filePath,
|
|
2800
|
-
sourceText: await
|
|
3786
|
+
sourceText: await readFile13(filePath, "utf8")
|
|
2801
3787
|
}))
|
|
2802
3788
|
);
|
|
2803
3789
|
const result = scanNextSourceFilesToSiteFieldContract(files, {
|
|
@@ -2830,15 +3816,32 @@ async function withSiteplane(nextConfig, options = {}) {
|
|
|
2830
3816
|
"The instrumented source no longer matches siteplane.config.json. Run siteplane setup apply again."
|
|
2831
3817
|
);
|
|
2832
3818
|
}
|
|
2833
|
-
const
|
|
2834
|
-
|
|
3819
|
+
const checkoutRevision = await readGitRevision2(projectDir) || await readBuildProvenance(projectDir) || (process.env.VERCEL === "1" ? process.env.VERCEL_GIT_COMMIT_SHA?.trim() : "");
|
|
3820
|
+
const requestedRevision = options.buildRevision?.trim() || process.env.SITEPLANE_BUILD_REVISION?.trim();
|
|
3821
|
+
if (!checkoutRevision || !/^[0-9a-f]{40}$/u.test(checkoutRevision))
|
|
2835
3822
|
throw new SiteplaneNextContractError(
|
|
2836
3823
|
"missing_build_revision",
|
|
2837
|
-
"
|
|
3824
|
+
"Build from the committed Git checkout with provider Git metadata; an arbitrary revision override is insufficient."
|
|
3825
|
+
);
|
|
3826
|
+
if (requestedRevision && requestedRevision !== checkoutRevision)
|
|
3827
|
+
throw new SiteplaneNextContractError(
|
|
3828
|
+
"build_revision_conflict",
|
|
3829
|
+
"SITEPLANE_BUILD_REVISION does not match the actual build checkout. Deploy the applied commit with its current configuration."
|
|
3830
|
+
);
|
|
3831
|
+
const buildRevision = checkoutRevision;
|
|
3832
|
+
if (process.env.VERCEL === "1")
|
|
3833
|
+
await emitBuildProof(
|
|
3834
|
+
projectDir,
|
|
3835
|
+
config.packages,
|
|
3836
|
+
buildRevision,
|
|
3837
|
+
scan.fieldContractHash
|
|
2838
3838
|
);
|
|
2839
|
-
}
|
|
2840
3839
|
return {
|
|
2841
3840
|
...nextConfig,
|
|
3841
|
+
headers: async () => frameHeaders(
|
|
3842
|
+
await nextConfig.headers?.() ?? [],
|
|
3843
|
+
new URL(config.apiBaseUrl).origin
|
|
3844
|
+
),
|
|
2842
3845
|
env: {
|
|
2843
3846
|
...nextConfig.env ?? {},
|
|
2844
3847
|
SITEPLANE_BUILD_FIELD_CONTRACT_HASH: scan.fieldContractHash,
|
|
@@ -2847,8 +3850,8 @@ async function withSiteplane(nextConfig, options = {}) {
|
|
|
2847
3850
|
}
|
|
2848
3851
|
};
|
|
2849
3852
|
}
|
|
2850
|
-
var execFileAsync3 =
|
|
2851
|
-
async function
|
|
3853
|
+
var execFileAsync3 = promisify4(execFile4);
|
|
3854
|
+
async function readGitRevision2(projectDir) {
|
|
2852
3855
|
try {
|
|
2853
3856
|
const result = await execFileAsync3("git", ["rev-parse", "HEAD"], {
|
|
2854
3857
|
cwd: projectDir
|
|
@@ -2858,6 +3861,85 @@ async function readGitRevision(projectDir) {
|
|
|
2858
3861
|
return "";
|
|
2859
3862
|
}
|
|
2860
3863
|
}
|
|
3864
|
+
function frameHeaders(rules, adminOrigin) {
|
|
3865
|
+
const policy = `frame-ancestors 'self' ${adminOrigin}`;
|
|
3866
|
+
const prepared = rules.map((rule) => ({
|
|
3867
|
+
...rule,
|
|
3868
|
+
headers: rule.headers.map((header) => {
|
|
3869
|
+
if (header.key.toLowerCase() === "x-frame-options" && /^(DENY|SAMEORIGIN)$/iu.test(header.value.trim()))
|
|
3870
|
+
throw new SiteplaneNextContractError(
|
|
3871
|
+
"frame_policy_conflict",
|
|
3872
|
+
"The existing X-Frame-Options blocks the Siteplane preview. Reconcile that explicit website policy with the canonical admin origin."
|
|
3873
|
+
);
|
|
3874
|
+
if (header.key.toLowerCase() !== "content-security-policy") return header;
|
|
3875
|
+
const ancestors = /(?:^|;)\s*frame-ancestors\s+([^;]+)/iu.exec(
|
|
3876
|
+
header.value
|
|
3877
|
+
)?.[1];
|
|
3878
|
+
if (ancestors && (!ancestors.split(/\s+/u).includes(adminOrigin) || ancestors.includes("*")))
|
|
3879
|
+
throw new SiteplaneNextContractError(
|
|
3880
|
+
"frame_policy_conflict",
|
|
3881
|
+
"Keep the existing CSP directives and explicitly allow only the canonical Siteplane admin origin in frame-ancestors."
|
|
3882
|
+
);
|
|
3883
|
+
return {
|
|
3884
|
+
...header,
|
|
3885
|
+
value: ancestors ? header.value : `${header.value.replace(/;\s*$/u, "")}; ${policy}`
|
|
3886
|
+
};
|
|
3887
|
+
})
|
|
3888
|
+
}));
|
|
3889
|
+
return [
|
|
3890
|
+
{
|
|
3891
|
+
source: "/:path*",
|
|
3892
|
+
headers: [{ key: "Content-Security-Policy", value: policy }]
|
|
3893
|
+
},
|
|
3894
|
+
...prepared
|
|
3895
|
+
];
|
|
3896
|
+
}
|
|
3897
|
+
async function emitBuildProof(projectDir, packages, revision, fieldContractHash) {
|
|
3898
|
+
const [cli, runtime, next, react] = await Promise.all(
|
|
3899
|
+
["siteplane", "@siteplane/runtime-next", "next", "react"].map(
|
|
3900
|
+
(name2) => readInstalledPackage(projectDir, name2)
|
|
3901
|
+
)
|
|
3902
|
+
);
|
|
3903
|
+
if (cli.version !== packages.siteplane || runtime.version !== packages.runtimeNext)
|
|
3904
|
+
throw new SiteplaneNextContractError(
|
|
3905
|
+
"build_identity_missing",
|
|
3906
|
+
"The provider installed different Siteplane package versions than the task requires."
|
|
3907
|
+
);
|
|
3908
|
+
const executable = process.env.npm_execpath;
|
|
3909
|
+
if (!executable)
|
|
3910
|
+
throw new SiteplaneNextContractError(
|
|
3911
|
+
"build_identity_missing",
|
|
3912
|
+
"Run the provider build through the selected npm/pnpm executable so its actual version can be verified."
|
|
3913
|
+
);
|
|
3914
|
+
const packageManager = /pnpm/iu.test(executable) ? "pnpm" : "npm";
|
|
3915
|
+
const packageManagerVersion = (await execFileAsync3(process.execPath, [executable, "--version"], {
|
|
3916
|
+
cwd: projectDir
|
|
3917
|
+
})).stdout.trim();
|
|
3918
|
+
let directory = resolve4(projectDir);
|
|
3919
|
+
let lock = null;
|
|
3920
|
+
while (true) {
|
|
3921
|
+
lock = await readFile13(
|
|
3922
|
+
join12(
|
|
3923
|
+
directory,
|
|
3924
|
+
packageManager === "npm" ? "package-lock.json" : "pnpm-lock.yaml"
|
|
3925
|
+
),
|
|
3926
|
+
"utf8"
|
|
3927
|
+
).catch((error) => {
|
|
3928
|
+
if (error.code === "ENOENT") return null;
|
|
3929
|
+
throw error;
|
|
3930
|
+
});
|
|
3931
|
+
if (lock !== null || dirname9(directory) === directory) break;
|
|
3932
|
+
directory = dirname9(directory);
|
|
3933
|
+
}
|
|
3934
|
+
if (!lock)
|
|
3935
|
+
throw new SiteplaneNextContractError(
|
|
3936
|
+
"build_identity_missing",
|
|
3937
|
+
"The provider build is missing the selected canonical lockfile."
|
|
3938
|
+
);
|
|
3939
|
+
console.info(
|
|
3940
|
+
`SITEPLANE_BUILD_PROOF=${JSON.stringify({ node: process.versions.node, packageManager, packageManagerVersion, lockfileHash: `sha256:${createHash5("sha256").update(lock).digest("hex")}`, revision, fieldContractHash, siteplane: cli.version, runtimeNext: runtime.version, next: next.version, react: react.version })}`
|
|
3941
|
+
);
|
|
3942
|
+
}
|
|
2861
3943
|
export {
|
|
2862
3944
|
SiteplaneNextContractError,
|
|
2863
3945
|
scanNextProjectFieldContract,
|