siteplane 0.1.64 → 0.1.65
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 +13 -0
- package/dist/bin/siteplane.js +214 -258
- package/dist/index.js +134 -178
- package/dist/next.d.ts +10 -0
- package/dist/next.js +171 -108
- package/package.json +1 -1
package/dist/bin/siteplane.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/bin/run-siteplane.ts
|
|
4
4
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
5
|
-
import { access as
|
|
6
|
-
import { join as
|
|
5
|
+
import { access as access8, readFile as readFile13 } from "fs/promises";
|
|
6
|
+
import { join as join14, resolve as resolve4 } from "path";
|
|
7
7
|
|
|
8
8
|
// ../cli/dist/analytics/manifest.js
|
|
9
9
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -692,6 +692,7 @@ var bookingPublicConfigSchema = z9.object({
|
|
|
692
692
|
settings: z9.object({
|
|
693
693
|
slotIntervalMinutes: z9.number().int().positive(),
|
|
694
694
|
minLeadMinutes: z9.number().int().min(0),
|
|
695
|
+
minCancelLeadMinutes: z9.number().int().min(0),
|
|
695
696
|
maxAdvanceDays: z9.number().int().min(1),
|
|
696
697
|
requirePhone: z9.boolean(),
|
|
697
698
|
collectNote: z9.boolean(),
|
|
@@ -900,7 +901,7 @@ var bookingManifestSchema = z9.object({
|
|
|
900
901
|
siteId: z9.string().trim().min(1),
|
|
901
902
|
siteKeyPrefix: z9.string().startsWith("bk_pub_"),
|
|
902
903
|
bookingPageSlug: z9.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).min(2).max(64),
|
|
903
|
-
|
|
904
|
+
integration: z9.literal("rewrite").optional(),
|
|
904
905
|
productionOrigin: z9.string().url().optional()
|
|
905
906
|
}).passthrough();
|
|
906
907
|
var secretManifestKeys = /* @__PURE__ */ new Set([
|
|
@@ -2876,117 +2877,63 @@ function collectRedactedBookingKeys(input, prefix = "") {
|
|
|
2876
2877
|
}
|
|
2877
2878
|
|
|
2878
2879
|
// ../cli/dist/booking/static-scan.js
|
|
2880
|
+
import ts2 from "typescript";
|
|
2879
2881
|
function scanBookingSourceFiles(files, input) {
|
|
2880
|
-
const
|
|
2881
|
-
const
|
|
2882
|
-
const
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2882
|
+
const findings = [];
|
|
2883
|
+
const hardErrors = [];
|
|
2884
|
+
const warnings = [];
|
|
2885
|
+
for (const file of files) {
|
|
2886
|
+
let visit2 = function(node) {
|
|
2887
|
+
if (ts2.isCallExpression(node) && ts2.isIdentifier(node.expression) && node.expression.text === "withSiteplane") {
|
|
2888
|
+
const options = node.arguments[1];
|
|
2889
|
+
const booking = options && property(options, "booking");
|
|
2890
|
+
const site = booking && property(booking, "site");
|
|
2891
|
+
if (site && ts2.isStringLiteralLike(site)) {
|
|
2892
|
+
const issue = {
|
|
2893
|
+
code: site.text === input.siteId ? "booking_scan.integration_found" : "booking_scan.site_mismatch",
|
|
2894
|
+
message: site.text === input.siteId ? "Booking /booking rewrite configured for this Site ID." : "The Booking wrapper uses a different Site ID; use the Site ID supplied by Siteplane.",
|
|
2895
|
+
filePath: file.filePath
|
|
2896
|
+
};
|
|
2897
|
+
(site.text === input.siteId ? findings : hardErrors).push(issue);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
ts2.forEachChild(node, visit2);
|
|
2901
|
+
};
|
|
2902
|
+
var visit = visit2;
|
|
2903
|
+
const source = ts2.createSourceFile(file.filePath, file.sourceText, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
|
|
2904
|
+
visit2(source);
|
|
2905
|
+
}
|
|
2906
|
+
if (!findings.length && !hardErrors.length)
|
|
2907
|
+
hardErrors.push({
|
|
2908
|
+
code: "booking_scan.integration_missing",
|
|
2909
|
+
message: "Could not verify withSiteplane(nextConfig, { booking: { site: <site-id> } }). Include next.config.ts in the scan and use a literal Site ID.",
|
|
2910
|
+
filePath: "next.config.ts"
|
|
2911
|
+
});
|
|
2912
|
+
if (input.productionOrigin && !files.some((file) => file.sourceText.includes(input.productionOrigin)))
|
|
2913
|
+
warnings.push({
|
|
2914
|
+
code: "booking_scan.origin_not_detected",
|
|
2915
|
+
message: "Verify the public booking address and its allowed origins in Siteplane settings.",
|
|
2886
2916
|
filePath: "siteplane.booking.json"
|
|
2887
|
-
}
|
|
2888
|
-
] : [];
|
|
2889
|
-
const warnings = [
|
|
2890
|
-
...createPageSlugWarnings(embeds, input.bookingPageSlug),
|
|
2891
|
-
...createOriginWarnings(files, input.productionOrigin)
|
|
2892
|
-
];
|
|
2893
|
-
const selectedEmbed = selectManifestEmbed(embeds);
|
|
2894
|
-
const manifest = bookingManifestSchema.parse({
|
|
2895
|
-
schemaVersion: 1,
|
|
2896
|
-
siteId: input.siteId,
|
|
2897
|
-
siteKeyPrefix: input.siteKeyPrefix,
|
|
2898
|
-
bookingPageSlug: selectedEmbed?.pageSlug ?? input.bookingPageSlug,
|
|
2899
|
-
...selectedEmbed ? { embedMode: selectedEmbed.embedMode } : {},
|
|
2900
|
-
...input.productionOrigin ? { productionOrigin: input.productionOrigin } : {}
|
|
2901
|
-
});
|
|
2917
|
+
});
|
|
2902
2918
|
return {
|
|
2903
|
-
manifest
|
|
2919
|
+
manifest: bookingManifestSchema.parse({
|
|
2920
|
+
schemaVersion: 1,
|
|
2921
|
+
...input,
|
|
2922
|
+
integration: "rewrite"
|
|
2923
|
+
}),
|
|
2904
2924
|
findings,
|
|
2905
2925
|
hardErrors,
|
|
2906
2926
|
warnings,
|
|
2907
2927
|
suggestions: []
|
|
2908
2928
|
};
|
|
2909
2929
|
}
|
|
2910
|
-
function
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
embedMode: "script"
|
|
2917
|
-
});
|
|
2918
|
-
}
|
|
2919
|
-
if (/<siteplane-booking\b/u.test(source)) {
|
|
2920
|
-
const pageSlug = readAttributeValue(source, "booking-page-slug");
|
|
2921
|
-
embeds.push({
|
|
2922
|
-
filePath: file.filePath,
|
|
2923
|
-
embedMode: "web_component",
|
|
2924
|
-
...pageSlug ? { pageSlug } : {}
|
|
2925
|
-
});
|
|
2926
|
-
}
|
|
2927
|
-
for (const match of source.matchAll(/<iframe\b[^>]*>/giu)) {
|
|
2928
|
-
const tag = match[0];
|
|
2929
|
-
const src = readAttributeValue(tag, "src");
|
|
2930
|
-
const pageSlug = src ? readBookingPageSlug(src) : void 0;
|
|
2931
|
-
if (/data-siteplane-booking/u.test(tag) || pageSlug !== void 0) {
|
|
2932
|
-
embeds.push({
|
|
2933
|
-
filePath: file.filePath,
|
|
2934
|
-
embedMode: "iframe",
|
|
2935
|
-
...pageSlug ? { pageSlug } : {}
|
|
2936
|
-
});
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
return embeds;
|
|
2940
|
-
}
|
|
2941
|
-
function createEmbedFoundIssue(embed) {
|
|
2942
|
-
return {
|
|
2943
|
-
code: "booking_scan.embed_found",
|
|
2944
|
-
message: "Siteplane Booking embed was found.",
|
|
2945
|
-
filePath: embed.filePath,
|
|
2946
|
-
embedMode: embed.embedMode,
|
|
2947
|
-
...embed.pageSlug ? { pageSlug: embed.pageSlug } : {}
|
|
2948
|
-
};
|
|
2949
|
-
}
|
|
2950
|
-
function createPageSlugWarnings(embeds, expectedSlug) {
|
|
2951
|
-
return embeds.filter((embed) => embed.pageSlug && embed.pageSlug !== expectedSlug).map((embed) => {
|
|
2952
|
-
const pageSlug = embed.pageSlug;
|
|
2953
|
-
return {
|
|
2954
|
-
code: "booking_scan.page_slug_mismatch",
|
|
2955
|
-
message: `Booking embed references page slug ${pageSlug}, but the manifest is configured for ${expectedSlug}.`,
|
|
2956
|
-
filePath: embed.filePath,
|
|
2957
|
-
embedMode: embed.embedMode,
|
|
2958
|
-
...pageSlug ? { pageSlug } : {}
|
|
2959
|
-
};
|
|
2960
|
-
});
|
|
2961
|
-
}
|
|
2962
|
-
function createOriginWarnings(files, productionOrigin) {
|
|
2963
|
-
if (!productionOrigin) {
|
|
2964
|
-
return [];
|
|
2965
|
-
}
|
|
2966
|
-
if (files.some((file) => file.sourceText.includes(productionOrigin))) {
|
|
2967
|
-
return [];
|
|
2930
|
+
function property(node, name2) {
|
|
2931
|
+
if (!ts2.isObjectLiteralExpression(node))
|
|
2932
|
+
return;
|
|
2933
|
+
for (const item of node.properties) {
|
|
2934
|
+
if (ts2.isPropertyAssignment(item) && (ts2.isIdentifier(item.name) || ts2.isStringLiteral(item.name)) && item.name.text === name2)
|
|
2935
|
+
return item.initializer;
|
|
2968
2936
|
}
|
|
2969
|
-
return [
|
|
2970
|
-
{
|
|
2971
|
-
code: "booking_scan.origin_not_detected",
|
|
2972
|
-
message: "The configured production origin was not found statically; verify it is registered as an allowed Booking origin in Siteplane.",
|
|
2973
|
-
filePath: "siteplane.booking.json"
|
|
2974
|
-
}
|
|
2975
|
-
];
|
|
2976
|
-
}
|
|
2977
|
-
function selectManifestEmbed(embeds) {
|
|
2978
|
-
return embeds.find((embed) => embed.embedMode === "web_component") ?? embeds.find((embed) => embed.embedMode === "iframe") ?? embeds[0];
|
|
2979
|
-
}
|
|
2980
|
-
function readAttributeValue(source, attributeName) {
|
|
2981
|
-
const escapedName = escapeRegExp(attributeName);
|
|
2982
|
-
const match = new RegExp(`${escapedName}\\s*=\\s*["']([^"']+)["']`, "iu").exec(source);
|
|
2983
|
-
return match?.[1];
|
|
2984
|
-
}
|
|
2985
|
-
function readBookingPageSlug(value) {
|
|
2986
|
-
return /\/book\/([a-z0-9]+(?:-[a-z0-9]+)*)(?:[/?#]|$)/u.exec(value)?.[1];
|
|
2987
|
-
}
|
|
2988
|
-
function escapeRegExp(value) {
|
|
2989
|
-
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
2990
2937
|
}
|
|
2991
2938
|
|
|
2992
2939
|
// ../cli/dist/commands/analytics/check.js
|
|
@@ -3392,10 +3339,17 @@ async function analyticsTestCommand(input) {
|
|
|
3392
3339
|
}
|
|
3393
3340
|
|
|
3394
3341
|
// ../cli/dist/commands/booking/check.js
|
|
3395
|
-
import {
|
|
3342
|
+
import { dirname as dirname4, join as join2 } from "path";
|
|
3343
|
+
import { access, readFile as readFile4 } from "fs/promises";
|
|
3396
3344
|
async function bookingCheckCommand(input) {
|
|
3397
3345
|
const validatedManifest = await readBookingManifestFile(input.manifestPath);
|
|
3398
|
-
const
|
|
3346
|
+
const configs = (await Promise.all(["next.config.ts", "next.config.js", "next.config.mjs"].map(async (name2) => {
|
|
3347
|
+
const path = join2(dirname4(input.manifestPath), name2);
|
|
3348
|
+
return await access(path).then(() => path, () => null);
|
|
3349
|
+
}))).filter((path) => path !== null);
|
|
3350
|
+
const sourceFiles = await readSourceFiles2([
|
|
3351
|
+
.../* @__PURE__ */ new Set([...input.sourceFilePaths, ...configs])
|
|
3352
|
+
]);
|
|
3399
3353
|
const scanInput = {
|
|
3400
3354
|
siteId: validatedManifest.manifest.siteId,
|
|
3401
3355
|
siteKeyPrefix: validatedManifest.manifest.siteKeyPrefix,
|
|
@@ -3436,7 +3390,7 @@ function createBoundaryErrors2(validation) {
|
|
|
3436
3390
|
|
|
3437
3391
|
// ../cli/dist/commands/booking/init.js
|
|
3438
3392
|
import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
|
|
3439
|
-
import { dirname as
|
|
3393
|
+
import { dirname as dirname5, join as join3 } from "path";
|
|
3440
3394
|
async function bookingInitCommand(input) {
|
|
3441
3395
|
const manifest = {
|
|
3442
3396
|
schemaVersion: 1,
|
|
@@ -3445,7 +3399,7 @@ async function bookingInitCommand(input) {
|
|
|
3445
3399
|
bookingPageSlug: input.bookingPageSlug,
|
|
3446
3400
|
...input.productionOrigin ? { productionOrigin: input.productionOrigin } : {}
|
|
3447
3401
|
};
|
|
3448
|
-
const manifestPath =
|
|
3402
|
+
const manifestPath = join3(input.projectDir, "siteplane.booking.json");
|
|
3449
3403
|
const artifacts = createBookingArtifacts(input.agentClient);
|
|
3450
3404
|
await writeBookingManifestFile(manifestPath, manifest);
|
|
3451
3405
|
for (const artifact of artifacts) {
|
|
@@ -3485,16 +3439,18 @@ function createBookingArtifacts(agentClient) {
|
|
|
3485
3439
|
return artifacts;
|
|
3486
3440
|
}
|
|
3487
3441
|
async function writeProjectFile2(projectDir, relativePath, contents) {
|
|
3488
|
-
const path =
|
|
3489
|
-
await mkdir4(
|
|
3442
|
+
const path = join3(projectDir, relativePath);
|
|
3443
|
+
await mkdir4(dirname5(path), { recursive: true });
|
|
3490
3444
|
await writeFile4(path, contents, "utf8");
|
|
3491
3445
|
}
|
|
3492
3446
|
var bookingRulesTemplate = `# Siteplane Booking Rules
|
|
3493
3447
|
|
|
3494
3448
|
- Do not change layout, copy, styling, animation or business logic while adding Booking.
|
|
3495
|
-
-
|
|
3496
|
-
- Use
|
|
3497
|
-
-
|
|
3449
|
+
- Integrate /booking on the customer domain through withSiteplane(nextConfig, { booking: { site: "<site-id>" } }); use the immutable Site ID supplied by Siteplane.
|
|
3450
|
+
- Use a normal <a href="/booking"> link, not next/link, an iframe or an embed script.
|
|
3451
|
+
- Preserve existing rewrites. Booking-only must not require Editor setup or siteplane.config.json.
|
|
3452
|
+
- Configure the public booking address in Siteplane; register its origin and call https://siteplane.io/api/booking/* directly with CORS, without a raw public key.
|
|
3453
|
+
- Preserve customer CSP and middleware; explain required Siteplane/Stripe permissions and exclude /booking from customer middleware.
|
|
3498
3454
|
- Do not write setup tokens, project CLI tokens or private keys into source files.
|
|
3499
3455
|
- Run npx siteplane booking check, npx siteplane booking sync and npx siteplane booking test after setup.
|
|
3500
3456
|
- booking test stays in test_mode; live booking only starts after explicit dashboard activation.
|
|
@@ -3502,7 +3458,7 @@ var bookingRulesTemplate = `# Siteplane Booking Rules
|
|
|
3502
3458
|
function bookingSkillTemplate(agentName) {
|
|
3503
3459
|
return `# Siteplane Booking Skill
|
|
3504
3460
|
|
|
3505
|
-
Use this skill in ${agentName} before
|
|
3461
|
+
Use this skill in ${agentName} before integrating Siteplane Booking at /booking.
|
|
3506
3462
|
|
|
3507
3463
|
${bookingRulesTemplate}`;
|
|
3508
3464
|
}
|
|
@@ -3556,9 +3512,9 @@ async function bookingTestCommand(input) {
|
|
|
3556
3512
|
}
|
|
3557
3513
|
|
|
3558
3514
|
// ../cli/dist/config/project-config.js
|
|
3559
|
-
import { access, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
|
|
3515
|
+
import { access as access2, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
|
|
3560
3516
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3561
|
-
import { join as
|
|
3517
|
+
import { join as join4 } from "path";
|
|
3562
3518
|
import { z as z31 } from "zod";
|
|
3563
3519
|
var siteplaneProjectConfigSchema = z31.object({
|
|
3564
3520
|
version: z31.literal(2),
|
|
@@ -3574,7 +3530,7 @@ var siteplaneProjectConfigSchema = z31.object({
|
|
|
3574
3530
|
fieldContractHash: z31.string().regex(/^sha256:[0-9a-f]{64}$/iu).optional()
|
|
3575
3531
|
}).strict();
|
|
3576
3532
|
async function readProjectPackageJson(projectDir) {
|
|
3577
|
-
return JSON.parse(await readFile5(
|
|
3533
|
+
return JSON.parse(await readFile5(join4(projectDir, "package.json"), "utf8"));
|
|
3578
3534
|
}
|
|
3579
3535
|
async function detectNextProject(projectDir) {
|
|
3580
3536
|
const packageJson = await readProjectPackageJson(projectDir).catch(() => null);
|
|
@@ -3587,7 +3543,7 @@ async function detectNextProject(projectDir) {
|
|
|
3587
3543
|
"next.config.ts"
|
|
3588
3544
|
]) {
|
|
3589
3545
|
try {
|
|
3590
|
-
await
|
|
3546
|
+
await access2(join4(projectDir, fileName));
|
|
3591
3547
|
return true;
|
|
3592
3548
|
} catch {
|
|
3593
3549
|
}
|
|
@@ -3595,13 +3551,13 @@ async function detectNextProject(projectDir) {
|
|
|
3595
3551
|
return false;
|
|
3596
3552
|
}
|
|
3597
3553
|
async function writeProjectConfig(projectDir, config) {
|
|
3598
|
-
const path =
|
|
3554
|
+
const path = join4(projectDir, "siteplane.config.json");
|
|
3599
3555
|
const parsed = siteplaneProjectConfigSchema.parse(config);
|
|
3600
3556
|
await writeJsonAtomically(path, parsed, 420);
|
|
3601
3557
|
return path;
|
|
3602
3558
|
}
|
|
3603
3559
|
async function readProjectConfig(projectDir) {
|
|
3604
|
-
return siteplaneProjectConfigSchema.parse(JSON.parse(await readFile5(
|
|
3560
|
+
return siteplaneProjectConfigSchema.parse(JSON.parse(await readFile5(join4(projectDir, "siteplane.config.json"), "utf8")));
|
|
3605
3561
|
}
|
|
3606
3562
|
async function writeJsonAtomically(path, value, mode) {
|
|
3607
3563
|
const temporaryPath = `${path}.${randomUUID2()}.tmp`;
|
|
@@ -3629,7 +3585,7 @@ async function writeJsonAtomically(path, value, mode) {
|
|
|
3629
3585
|
import { execFile } from "child_process";
|
|
3630
3586
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3631
3587
|
import { chmod as chmod2, lstat, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
|
|
3632
|
-
import { dirname as
|
|
3588
|
+
import { dirname as dirname6, join as join5, relative } from "path";
|
|
3633
3589
|
import { promisify } from "util";
|
|
3634
3590
|
import { z as z32 } from "zod";
|
|
3635
3591
|
var localSetupInstallationSchema = z32.object({
|
|
@@ -3654,7 +3610,7 @@ var localSetupCredentialsSchema = z32.union([
|
|
|
3654
3610
|
z32.object({ installation: localSetupInstallationSchema }).strict()
|
|
3655
3611
|
]);
|
|
3656
3612
|
async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
|
|
3657
|
-
const path =
|
|
3613
|
+
const path = join5(projectDir, ".siteplane/credentials.json");
|
|
3658
3614
|
await assertCredentialFilesystemSafe(projectDir);
|
|
3659
3615
|
const isTrackedFile = options.isTrackedFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "ls-files"));
|
|
3660
3616
|
const isIgnoredFile = options.isIgnoredFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "check-ignore"));
|
|
@@ -3669,8 +3625,8 @@ async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
|
|
|
3669
3625
|
async function assertCredentialFilesystemSafe(projectDir) {
|
|
3670
3626
|
for (const [path, directory, mode] of [
|
|
3671
3627
|
[projectDir, true, null],
|
|
3672
|
-
[
|
|
3673
|
-
[
|
|
3628
|
+
[join5(projectDir, ".siteplane"), true, 448],
|
|
3629
|
+
[join5(projectDir, ".siteplane/credentials.json"), false, 384]
|
|
3674
3630
|
]) {
|
|
3675
3631
|
const stat = await lstat(path).catch((error) => {
|
|
3676
3632
|
if (error.code === "ENOENT")
|
|
@@ -3693,7 +3649,7 @@ async function writeLocalCredentials(projectDir, credentials, options = {}) {
|
|
|
3693
3649
|
async function writeLocalSetupCredentials(projectDir, credentials, options = {}) {
|
|
3694
3650
|
const path = await assertLocalCredentialsPathSafe(projectDir, options);
|
|
3695
3651
|
const parsed = localSetupCredentialsSchema.parse(credentials);
|
|
3696
|
-
await mkdir5(
|
|
3652
|
+
await mkdir5(dirname6(path), { recursive: true, mode: 448 });
|
|
3697
3653
|
await writeCredentialsAtomically(path, parsed);
|
|
3698
3654
|
return path;
|
|
3699
3655
|
}
|
|
@@ -3706,7 +3662,7 @@ async function readLocalCredentials(projectDir) {
|
|
|
3706
3662
|
}
|
|
3707
3663
|
async function readLocalSetupCredentials(projectDir) {
|
|
3708
3664
|
await assertCredentialFilesystemSafe(projectDir);
|
|
3709
|
-
return localSetupCredentialsSchema.parse(JSON.parse(await readFile6(
|
|
3665
|
+
return localSetupCredentialsSchema.parse(JSON.parse(await readFile6(join5(projectDir, ".siteplane/credentials.json"), "utf8")));
|
|
3710
3666
|
}
|
|
3711
3667
|
async function writeCredentialsAtomically(path, credentials) {
|
|
3712
3668
|
const temporaryPath = `${path}.${randomUUID3()}.tmp`;
|
|
@@ -3724,7 +3680,7 @@ async function writeCredentialsAtomically(path, credentials) {
|
|
|
3724
3680
|
try {
|
|
3725
3681
|
await rename2(temporaryPath, path);
|
|
3726
3682
|
await chmod2(path, 384);
|
|
3727
|
-
const directory = await open2(
|
|
3683
|
+
const directory = await open2(dirname6(path), "r");
|
|
3728
3684
|
try {
|
|
3729
3685
|
await directory.sync();
|
|
3730
3686
|
} finally {
|
|
@@ -3747,8 +3703,8 @@ async function gitPathMatches(projectDir, path, command) {
|
|
|
3747
3703
|
}
|
|
3748
3704
|
|
|
3749
3705
|
// ../cli/dist/commands/init.js
|
|
3750
|
-
import { access as
|
|
3751
|
-
import { join as
|
|
3706
|
+
import { access as access4 } from "fs/promises";
|
|
3707
|
+
import { join as join8, relative as relative3 } from "path";
|
|
3752
3708
|
import { z as z35 } from "zod";
|
|
3753
3709
|
|
|
3754
3710
|
// ../cli/dist/commands/setup-preflight.js
|
|
@@ -3760,7 +3716,7 @@ import { parse as parseYaml } from "yaml";
|
|
|
3760
3716
|
// ../cli/dist/config/installed-package.js
|
|
3761
3717
|
import { createRequire } from "module";
|
|
3762
3718
|
import { readFile as readFile7 } from "fs/promises";
|
|
3763
|
-
import { join as
|
|
3719
|
+
import { join as join6 } from "path";
|
|
3764
3720
|
import { z as z33 } from "zod";
|
|
3765
3721
|
var packageSchema = z33.object({
|
|
3766
3722
|
name: z33.string().optional(),
|
|
@@ -3768,10 +3724,10 @@ var packageSchema = z33.object({
|
|
|
3768
3724
|
peerDependencies: z33.record(z33.string(), z33.string()).optional()
|
|
3769
3725
|
});
|
|
3770
3726
|
async function readInstalledPackage(projectDir, name2) {
|
|
3771
|
-
const require2 = createRequire(
|
|
3727
|
+
const require2 = createRequire(join6(projectDir, "package.json"));
|
|
3772
3728
|
for (const directory of require2.resolve.paths(name2) ?? []) {
|
|
3773
3729
|
try {
|
|
3774
|
-
return packageSchema.parse(JSON.parse(await readFile7(
|
|
3730
|
+
return packageSchema.parse(JSON.parse(await readFile7(join6(directory, name2, "package.json"), "utf8")));
|
|
3775
3731
|
} catch (error) {
|
|
3776
3732
|
if (error.code !== "ENOENT")
|
|
3777
3733
|
throw error;
|
|
@@ -3783,7 +3739,7 @@ async function assertExactSetupPackages(projectDir, packages) {
|
|
|
3783
3739
|
const manifest = z33.object({
|
|
3784
3740
|
dependencies: z33.record(z33.string(), z33.string()).optional(),
|
|
3785
3741
|
devDependencies: z33.record(z33.string(), z33.string()).optional()
|
|
3786
|
-
}).parse(JSON.parse(await readFile7(
|
|
3742
|
+
}).parse(JSON.parse(await readFile7(join6(projectDir, "package.json"), "utf8")));
|
|
3787
3743
|
for (const [name2, version2] of [
|
|
3788
3744
|
["siteplane", packages.siteplane],
|
|
3789
3745
|
["@siteplane/runtime-next", packages.runtimeNext],
|
|
@@ -3797,8 +3753,8 @@ async function assertExactSetupPackages(projectDir, packages) {
|
|
|
3797
3753
|
}
|
|
3798
3754
|
|
|
3799
3755
|
// ../cli/dist/commands/setup-preflight.js
|
|
3800
|
-
import { access as
|
|
3801
|
-
import { dirname as
|
|
3756
|
+
import { access as access3, readFile as readFile8, realpath, readdir, readlink } from "fs/promises";
|
|
3757
|
+
import { dirname as dirname7, join as join7, relative as relative2, resolve, sep } from "path";
|
|
3802
3758
|
import { z as z34 } from "zod";
|
|
3803
3759
|
|
|
3804
3760
|
// ../cli/dist/commands/setup-process.js
|
|
@@ -3925,15 +3881,15 @@ var vercelProjectSchema = z34.object({
|
|
|
3925
3881
|
productionBranch: z34.string().optional()
|
|
3926
3882
|
}).nullable().optional()
|
|
3927
3883
|
});
|
|
3928
|
-
var exists = async (path) =>
|
|
3884
|
+
var exists = async (path) => access3(path).then(() => true, () => false);
|
|
3929
3885
|
var fail = (code, message) => {
|
|
3930
3886
|
throw new SetupFailure(code, message);
|
|
3931
3887
|
};
|
|
3932
3888
|
var stable = (version2, major) => new RegExp(`^${major}\\.\\d+\\.\\d+$`, "u").test(version2);
|
|
3933
3889
|
async function inspectSetupLocalProject(projectDir) {
|
|
3934
3890
|
const projectDirectory = await realpath(resolve(projectDir));
|
|
3935
|
-
const manifest = manifestSchema.parse(JSON.parse(await readFile8(
|
|
3936
|
-
const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(
|
|
3891
|
+
const manifest = manifestSchema.parse(JSON.parse(await readFile8(join7(projectDirectory, "package.json"), "utf8")));
|
|
3892
|
+
const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(join7(projectDirectory, path)) ? path : null))).filter((path) => path !== null);
|
|
3937
3893
|
if (apps.length !== 1)
|
|
3938
3894
|
fail("ambiguous_app_directory", "Select one Next.js App Router application with exactly one app/ or src/app/ directory.");
|
|
3939
3895
|
const repositoryRoot = (await setupProcess("git", ["rev-parse", "--show-toplevel"], {
|
|
@@ -3947,8 +3903,8 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
3947
3903
|
fail("git_submodule_conflict", "The repository contains Git submodules. Resolve the explicit deployment source boundary before setup; the CLI will not copy external repositories.");
|
|
3948
3904
|
if (!entry.startsWith("120000 "))
|
|
3949
3905
|
continue;
|
|
3950
|
-
const path =
|
|
3951
|
-
const target = resolve(
|
|
3906
|
+
const path = join7(repositoryRoot, entry.slice(entry.indexOf(" ") + 1));
|
|
3907
|
+
const target = resolve(dirname7(path), await readlink(path));
|
|
3952
3908
|
const bound = relative2(repositoryRoot, target);
|
|
3953
3909
|
if (bound.startsWith("..") || bound.startsWith(sep))
|
|
3954
3910
|
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.");
|
|
@@ -3964,10 +3920,10 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
3964
3920
|
];
|
|
3965
3921
|
let locks = [];
|
|
3966
3922
|
for (; ; ) {
|
|
3967
|
-
locks = (await Promise.all(lockNames.map(async (name3) => await exists(
|
|
3968
|
-
if (locks.length || lockfileRoot === repositoryRoot ||
|
|
3923
|
+
locks = (await Promise.all(lockNames.map(async (name3) => await exists(join7(lockfileRoot, name3)) ? name3 : null))).filter((name3) => name3 !== null);
|
|
3924
|
+
if (locks.length || lockfileRoot === repositoryRoot || dirname7(lockfileRoot) === lockfileRoot)
|
|
3969
3925
|
break;
|
|
3970
|
-
lockfileRoot =
|
|
3926
|
+
lockfileRoot = dirname7(lockfileRoot);
|
|
3971
3927
|
}
|
|
3972
3928
|
if (locks.length > 1)
|
|
3973
3929
|
fail("conflicting_lockfiles", "Resolve conflicting package-manager lockfiles before setup; Siteplane does not replace them.");
|
|
@@ -3976,9 +3932,9 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
3976
3932
|
const lockName = locks[0];
|
|
3977
3933
|
if (!["package-lock.json", "pnpm-lock.yaml"].includes(lockName))
|
|
3978
3934
|
fail("unsupported_package_manager", "This setup supports npm 10 or pnpm 9/10 with their canonical lockfile.");
|
|
3979
|
-
const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(
|
|
3935
|
+
const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(join7(lockfileRoot, "package.json"), "utf8")));
|
|
3980
3936
|
if (lockfileRoot !== projectDirectory) {
|
|
3981
|
-
const workspaceFile =
|
|
3937
|
+
const workspaceFile = join7(lockfileRoot, "pnpm-workspace.yaml");
|
|
3982
3938
|
const workspace = lockName === "pnpm-lock.yaml" && await exists(workspaceFile) ? z34.object({ packages: z34.array(z34.string()) }).parse(parseYaml(await readFile8(workspaceFile, "utf8"))).packages : z34.union([
|
|
3983
3939
|
z34.array(z34.string()),
|
|
3984
3940
|
z34.object({ packages: z34.array(z34.string()) }).transform((value) => value.packages)
|
|
@@ -3987,14 +3943,14 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
3987
3943
|
if (!workspace.some((pattern) => !pattern.startsWith("!") && minimatch(selected, pattern)) || workspace.some((pattern) => pattern.startsWith("!") && minimatch(selected, pattern.slice(1))))
|
|
3988
3944
|
fail("unbound_workspace_app", "The selected application is excluded from the canonical lockfile's workspace packages. Select its actual application root.");
|
|
3989
3945
|
}
|
|
3990
|
-
for (let ancestor =
|
|
3991
|
-
const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(
|
|
3946
|
+
for (let ancestor = dirname7(lockfileRoot); ancestor.startsWith(repositoryRoot + sep) || ancestor === repositoryRoot; ancestor = dirname7(ancestor)) {
|
|
3947
|
+
const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(join7(ancestor, name3))));
|
|
3992
3948
|
if (ancestorLocks.some(Boolean))
|
|
3993
3949
|
fail("ambiguous_lockfile_root", "Both the selected package and its repository ancestors contain lockfiles. Select one canonical workspace resolution before setup.");
|
|
3994
3950
|
if (ancestor === repositoryRoot)
|
|
3995
3951
|
break;
|
|
3996
3952
|
}
|
|
3997
|
-
const lockText = await readFile8(
|
|
3953
|
+
const lockText = await readFile8(join7(lockfileRoot, lockName), "utf8");
|
|
3998
3954
|
const npmLock = lockName === "package-lock.json" ? z34.object({
|
|
3999
3955
|
lockfileVersion: z34.number(),
|
|
4000
3956
|
packages: z34.record(z34.string(), z34.object({
|
|
@@ -4047,9 +4003,9 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
4047
4003
|
fail("lockfile_format_conflict", "The canonical lockfile format does not match npm 10 or pnpm 9/10.");
|
|
4048
4004
|
const sourceConflicts = [];
|
|
4049
4005
|
for (const file of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
|
|
4050
|
-
if (!await exists(
|
|
4006
|
+
if (!await exists(join7(projectDirectory, file)))
|
|
4051
4007
|
continue;
|
|
4052
|
-
const source = await readFile8(
|
|
4008
|
+
const source = await readFile8(join7(projectDirectory, file), "utf8");
|
|
4053
4009
|
if (/output\s*:\s*['"]export['"]/u.test(source))
|
|
4054
4010
|
sourceConflicts.push("static_export");
|
|
4055
4011
|
if (/\bbasePath\s*:/u.test(source))
|
|
@@ -4069,11 +4025,11 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
4069
4025
|
"src/proxy.ts",
|
|
4070
4026
|
"src/proxy.js"
|
|
4071
4027
|
]) {
|
|
4072
|
-
if (await exists(
|
|
4028
|
+
if (await exists(join7(projectDirectory, name3))) {
|
|
4073
4029
|
sourceConflicts.push(`inspect_routing:${name3}`);
|
|
4074
|
-
if (await readlink(
|
|
4030
|
+
if (await readlink(join7(projectDirectory, name3)).catch(() => null))
|
|
4075
4031
|
continue;
|
|
4076
|
-
const policySource = await readFile8(
|
|
4032
|
+
const policySource = await readFile8(join7(projectDirectory, name3), "utf8");
|
|
4077
4033
|
if (/Content-Security-Policy|img-src|default-src/iu.test(policySource))
|
|
4078
4034
|
sourceConflicts.push(`inspect_image_csp:${name3}`);
|
|
4079
4035
|
}
|
|
@@ -4082,7 +4038,7 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
4082
4038
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
4083
4039
|
if (entry.isSymbolicLink() || ["node_modules", ".git", ".next", ".siteplane", ".vercel"].includes(entry.name))
|
|
4084
4040
|
continue;
|
|
4085
|
-
const path =
|
|
4041
|
+
const path = join7(directory, entry.name);
|
|
4086
4042
|
if (entry.isDirectory()) {
|
|
4087
4043
|
await inspectSource(path);
|
|
4088
4044
|
continue;
|
|
@@ -4102,7 +4058,7 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
4102
4058
|
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.`);
|
|
4103
4059
|
}
|
|
4104
4060
|
}
|
|
4105
|
-
await inspectSource(
|
|
4061
|
+
await inspectSource(join7(projectDirectory, apps[0]));
|
|
4106
4062
|
const gitRead = async (args) => setupProcess("git", args, { cwd: projectDirectory }).then((value) => value.trim(), () => null);
|
|
4107
4063
|
return {
|
|
4108
4064
|
projectDirectory,
|
|
@@ -4114,7 +4070,7 @@ async function inspectSetupLocalProject(projectDir) {
|
|
|
4114
4070
|
nodeVersion: process.versions.node,
|
|
4115
4071
|
packageManager: { name: name2, version: localVersion, declared },
|
|
4116
4072
|
lockfile: {
|
|
4117
|
-
path: relative2(repositoryRoot,
|
|
4073
|
+
path: relative2(repositoryRoot, join7(lockfileRoot, lockName)),
|
|
4118
4074
|
format,
|
|
4119
4075
|
sha256: createHash2("sha256").update(lockText).digest("hex")
|
|
4120
4076
|
},
|
|
@@ -4133,14 +4089,14 @@ async function setupPreflightCommand(input) {
|
|
|
4133
4089
|
local = await inspectSetupLocalProject(input.projectDir);
|
|
4134
4090
|
await assertLocalCredentialsPathSafe(input.projectDir);
|
|
4135
4091
|
let linkDirectory = local.projectDirectory;
|
|
4136
|
-
while (!await exists(
|
|
4137
|
-
linkDirectory =
|
|
4138
|
-
if (!await exists(
|
|
4092
|
+
while (!await exists(join7(linkDirectory, ".vercel/project.json")) && linkDirectory !== local.repositoryRoot && dirname7(linkDirectory) !== linkDirectory)
|
|
4093
|
+
linkDirectory = dirname7(linkDirectory);
|
|
4094
|
+
if (!await exists(join7(linkDirectory, ".vercel/project.json")))
|
|
4139
4095
|
fail("vercel_project_not_linked", "Link this application to its intended Vercel project before setup; Siteplane will not guess a target.");
|
|
4140
4096
|
const linked = z34.object({
|
|
4141
4097
|
projectId: z34.string().regex(/^prj_[A-Za-z0-9]+$/u),
|
|
4142
4098
|
orgId: z34.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u)
|
|
4143
|
-
}).parse(JSON.parse(await readFile8(
|
|
4099
|
+
}).parse(JSON.parse(await readFile8(join7(linkDirectory, ".vercel/project.json"), "utf8")));
|
|
4144
4100
|
const project = vercelProjectSchema.parse(await setupVercelApi(linkDirectory, `/v9/projects/${linked.projectId}?teamId=${linked.orgId}`));
|
|
4145
4101
|
if (project.id !== linked.projectId || project.accountId !== linked.orgId)
|
|
4146
4102
|
fail("vercel_identity_conflict", "The provider project does not match the locally linked project and team.");
|
|
@@ -4278,7 +4234,7 @@ var bootstrapResponseSchema = z35.object({
|
|
|
4278
4234
|
}).strict();
|
|
4279
4235
|
async function bootstrapProjectConnection(input) {
|
|
4280
4236
|
const fetcher = input.fetcher ?? fetch;
|
|
4281
|
-
const existing = await
|
|
4237
|
+
const existing = await access4(join8(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
|
|
4282
4238
|
const response = await fetcher(`${input.apiBaseUrl.replace(/\/$/, "")}/api/cli/setup/bootstrap`, {
|
|
4283
4239
|
method: "POST",
|
|
4284
4240
|
signal: AbortSignal.timeout(2e4),
|
|
@@ -4309,10 +4265,10 @@ async function acknowledgeBootstrapResponse(input) {
|
|
|
4309
4265
|
}
|
|
4310
4266
|
}
|
|
4311
4267
|
async function persistSiteSetupBootstrap(input, bootstrap, appDirectory, installation) {
|
|
4312
|
-
const previous = await
|
|
4268
|
+
const previous = await access4(join8(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
|
|
4313
4269
|
if (previous && (previous.siteId !== bootstrap.siteId || previous.runId !== bootstrap.runId || previous.publicSiteKeyId !== bootstrap.publicSiteKeyId || previous.publicSiteKey !== bootstrap.publicSiteKey))
|
|
4314
4270
|
throw new Error("The grant does not match this local Siteplane run. Preserve this directory and choose the correct owner connection.");
|
|
4315
|
-
const previousCredentials = previous ? await
|
|
4271
|
+
const previousCredentials = previous ? await access4(join8(input.projectDir, ".siteplane/credentials.json")).then(() => readLocalSetupCredentials(input.projectDir), () => null) : null;
|
|
4316
4272
|
const credentialsPath = await writeLocalCredentials(input.projectDir, {
|
|
4317
4273
|
...previousCredentials && "adminSession" in previousCredentials && previousCredentials.adminSession ? { adminSession: previousCredentials.adminSession } : {},
|
|
4318
4274
|
...previousCredentials && "claimReceipt" in previousCredentials && previousCredentials.claimReceipt ? { claimReceipt: previousCredentials.claimReceipt } : {},
|
|
@@ -4365,7 +4321,7 @@ async function persistFeatureBootstrap(input, bootstrap) {
|
|
|
4365
4321
|
throw new Error("Siteplane credentials could not be verified.");
|
|
4366
4322
|
}
|
|
4367
4323
|
return {
|
|
4368
|
-
configPath:
|
|
4324
|
+
configPath: join8(input.projectDir, "siteplane.config.json"),
|
|
4369
4325
|
credentialsPath
|
|
4370
4326
|
};
|
|
4371
4327
|
}
|
|
@@ -4388,7 +4344,7 @@ function readErrorMessage(payload) {
|
|
|
4388
4344
|
|
|
4389
4345
|
// ../cli/dist/commands/scan.js
|
|
4390
4346
|
import { readdir as readdir2 } from "fs/promises";
|
|
4391
|
-
import { extname, join as
|
|
4347
|
+
import { extname, join as join9 } from "path";
|
|
4392
4348
|
var defaultScanRoots = ["app", "src", "pages", "components", "lib"];
|
|
4393
4349
|
var excludedDirectories = /* @__PURE__ */ new Set([
|
|
4394
4350
|
".git",
|
|
@@ -4406,14 +4362,14 @@ async function resolveScanFilePaths(filePaths, options = {}) {
|
|
|
4406
4362
|
return filePaths;
|
|
4407
4363
|
}
|
|
4408
4364
|
const projectDir = options.projectDir ?? process.cwd();
|
|
4409
|
-
const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(
|
|
4365
|
+
const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join9(projectDir, root))));
|
|
4410
4366
|
return [...new Set(discovered.flat())].sort();
|
|
4411
4367
|
}
|
|
4412
4368
|
async function collectSourceFiles(directory) {
|
|
4413
4369
|
const entries = await readdir2(directory, { withFileTypes: true }).catch(() => []);
|
|
4414
4370
|
const files = [];
|
|
4415
4371
|
for (const entry of entries) {
|
|
4416
|
-
const entryPath =
|
|
4372
|
+
const entryPath = join9(directory, entry.name);
|
|
4417
4373
|
if (entry.isDirectory()) {
|
|
4418
4374
|
if (!excludedDirectories.has(entry.name)) {
|
|
4419
4375
|
files.push(...await collectSourceFiles(entryPath));
|
|
@@ -4434,7 +4390,7 @@ import { promisify as promisify2 } from "util";
|
|
|
4434
4390
|
import { z as z36 } from "zod";
|
|
4435
4391
|
|
|
4436
4392
|
// ../cli/dist/scan/next-source-scan.js
|
|
4437
|
-
import
|
|
4393
|
+
import ts3 from "typescript";
|
|
4438
4394
|
import { isAbsolute, relative as relative4 } from "path";
|
|
4439
4395
|
var eventPreviewHandlerMissingMessage = "Event preview fields must consume preview values with useSiteplanePreviewText from @siteplane/runtime-next/client or a siteplane:preview-value-applied listener.";
|
|
4440
4396
|
var valueCallUnusedMessage = "Siteplane value calls must feed rendered content. Assign or await the returned value and render that value instead of ignoring the call.";
|
|
@@ -4590,10 +4546,10 @@ function scanSourceFile2(file, fields, hardErrors) {
|
|
|
4590
4546
|
const eventPreviewComponentPropUsages = [];
|
|
4591
4547
|
const eventPreviewConsumerFieldIds = /* @__PURE__ */ new Set();
|
|
4592
4548
|
let hasGenericEventPreviewConsumer = false;
|
|
4593
|
-
const sourceFile =
|
|
4549
|
+
const sourceFile = ts3.createSourceFile(file.filePath, file.sourceText, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
|
|
4594
4550
|
function visit(node, currentComponentName) {
|
|
4595
4551
|
const nextComponentName = getFunctionComponentName(node) ?? currentComponentName;
|
|
4596
|
-
if (
|
|
4552
|
+
if (ts3.isJsxSelfClosingElement(node) || ts3.isJsxOpeningElement(node)) {
|
|
4597
4553
|
const componentName = getJsxTagName2(node.tagName);
|
|
4598
4554
|
if (editableComponentNames.has(componentName)) {
|
|
4599
4555
|
hardErrors.push({
|
|
@@ -4604,7 +4560,7 @@ function scanSourceFile2(file, fields, hardErrors) {
|
|
|
4604
4560
|
}
|
|
4605
4561
|
collectEventPreviewComponentPropUsages(node, eventPreviewAttrVariables, eventPreviewComponentPropUsages, file);
|
|
4606
4562
|
}
|
|
4607
|
-
if (
|
|
4563
|
+
if (ts3.isCallExpression(node)) {
|
|
4608
4564
|
collectAttrsCall(node, attrFieldIds, attrRouteRefs, eventPreviewAttrs, eventPreviewAttrVariables, directAttrs, file);
|
|
4609
4565
|
collectUnusedValueCallError(node, hardErrors, file);
|
|
4610
4566
|
const extractedFields = extractFunctionFields(node, file);
|
|
@@ -4628,7 +4584,7 @@ function scanSourceFile2(file, fields, hardErrors) {
|
|
|
4628
4584
|
if (isGenericEventPreviewConsumerReference(node)) {
|
|
4629
4585
|
hasGenericEventPreviewConsumer = true;
|
|
4630
4586
|
}
|
|
4631
|
-
|
|
4587
|
+
ts3.forEachChild(node, (child) => visit(child, nextComponentName));
|
|
4632
4588
|
}
|
|
4633
4589
|
visit(sourceFile);
|
|
4634
4590
|
markMissingAttrsWarnings(fieldsInFile, attrFieldIds, attrRouteRefs);
|
|
@@ -4655,7 +4611,7 @@ function collectUnusedValueCallError(node, hardErrors, file) {
|
|
|
4655
4611
|
});
|
|
4656
4612
|
}
|
|
4657
4613
|
function getSiteplaneValueFunctionName(node) {
|
|
4658
|
-
if (!
|
|
4614
|
+
if (!ts3.isPropertyAccessExpression(node.expression)) {
|
|
4659
4615
|
return void 0;
|
|
4660
4616
|
}
|
|
4661
4617
|
if (node.expression.expression.getText() !== "siteplane") {
|
|
@@ -4668,16 +4624,16 @@ function getSiteplaneValueFunctionName(node) {
|
|
|
4668
4624
|
return void 0;
|
|
4669
4625
|
}
|
|
4670
4626
|
function isIgnoredValueCall(node) {
|
|
4671
|
-
if (
|
|
4627
|
+
if (ts3.isVoidExpression(node.parent)) {
|
|
4672
4628
|
return true;
|
|
4673
4629
|
}
|
|
4674
|
-
if (
|
|
4630
|
+
if (ts3.isExpressionStatement(node.parent)) {
|
|
4675
4631
|
return true;
|
|
4676
4632
|
}
|
|
4677
|
-
return
|
|
4633
|
+
return ts3.isAwaitExpression(node.parent) && ts3.isExpressionStatement(node.parent.parent);
|
|
4678
4634
|
}
|
|
4679
4635
|
function extractFunctionFields(node, file) {
|
|
4680
|
-
if (!
|
|
4636
|
+
if (!ts3.isPropertyAccessExpression(node.expression)) {
|
|
4681
4637
|
return [];
|
|
4682
4638
|
}
|
|
4683
4639
|
if (node.expression.expression.getText() !== "siteplane") {
|
|
@@ -4815,7 +4771,7 @@ function createFallbackHash(fieldType, fallback) {
|
|
|
4815
4771
|
}
|
|
4816
4772
|
}
|
|
4817
4773
|
function collectAttrsCall(node, attrFieldIds, attrRouteRefs, eventPreviewAttrs, eventPreviewAttrVariables, directAttrs, file) {
|
|
4818
|
-
if (!
|
|
4774
|
+
if (!ts3.isPropertyAccessExpression(node.expression)) {
|
|
4819
4775
|
return;
|
|
4820
4776
|
}
|
|
4821
4777
|
if (node.expression.expression.getText() !== "siteplane" || node.expression.name.text !== "attrs") {
|
|
@@ -4844,7 +4800,7 @@ function collectAttrsCall(node, attrFieldIds, attrRouteRefs, eventPreviewAttrs,
|
|
|
4844
4800
|
}
|
|
4845
4801
|
return;
|
|
4846
4802
|
}
|
|
4847
|
-
if (firstArg &&
|
|
4803
|
+
if (firstArg && ts3.isIdentifier(firstArg) && typeof secondArg === "string") {
|
|
4848
4804
|
attrRouteRefs.add(`${firstArg.text}:${secondArg}`);
|
|
4849
4805
|
}
|
|
4850
4806
|
}
|
|
@@ -4881,7 +4837,7 @@ function hasEventPreviewStrategy(options) {
|
|
|
4881
4837
|
return !!options && typeof options === "object" && !Array.isArray(options) && options.previewStrategy === "event";
|
|
4882
4838
|
}
|
|
4883
4839
|
function isGenericEventPreviewConsumerReference(node) {
|
|
4884
|
-
return (
|
|
4840
|
+
return (ts3.isStringLiteral(node) || ts3.isNoSubstitutionTemplateLiteral(node)) && node.text === "siteplane:preview-value-applied";
|
|
4885
4841
|
}
|
|
4886
4842
|
function getPreviewHookFieldId(node, eventPreviewAttrVariables) {
|
|
4887
4843
|
const firstArg = getUseSiteplanePreviewTextFirstArg(node);
|
|
@@ -4892,7 +4848,7 @@ function getPreviewHookFieldId(node, eventPreviewAttrVariables) {
|
|
|
4892
4848
|
if (typeof directFieldId === "string") {
|
|
4893
4849
|
return directFieldId;
|
|
4894
4850
|
}
|
|
4895
|
-
if (
|
|
4851
|
+
if (ts3.isIdentifier(firstArg)) {
|
|
4896
4852
|
return eventPreviewAttrVariables.get(firstArg.text);
|
|
4897
4853
|
}
|
|
4898
4854
|
return void 0;
|
|
@@ -4902,16 +4858,16 @@ function getPreviewHookPropName(node, eventPreviewAttrVariables) {
|
|
|
4902
4858
|
if (!firstArg) {
|
|
4903
4859
|
return void 0;
|
|
4904
4860
|
}
|
|
4905
|
-
if (
|
|
4861
|
+
if (ts3.isIdentifier(firstArg) && !eventPreviewAttrVariables.has(firstArg.text)) {
|
|
4906
4862
|
return firstArg.text;
|
|
4907
4863
|
}
|
|
4908
|
-
if (
|
|
4864
|
+
if (ts3.isPropertyAccessExpression(firstArg) && ts3.isIdentifier(firstArg.expression)) {
|
|
4909
4865
|
return firstArg.name.text;
|
|
4910
4866
|
}
|
|
4911
4867
|
return void 0;
|
|
4912
4868
|
}
|
|
4913
4869
|
function getUseSiteplanePreviewTextFirstArg(node) {
|
|
4914
|
-
if (
|
|
4870
|
+
if (ts3.isIdentifier(node.expression) && node.expression.text === "useSiteplanePreviewText") {
|
|
4915
4871
|
return node.arguments[0];
|
|
4916
4872
|
}
|
|
4917
4873
|
return void 0;
|
|
@@ -4992,39 +4948,39 @@ function staticExpressionValue2(expression) {
|
|
|
4992
4948
|
if (!expression) {
|
|
4993
4949
|
return void 0;
|
|
4994
4950
|
}
|
|
4995
|
-
if (
|
|
4951
|
+
if (ts3.isStringLiteral(expression) || ts3.isNoSubstitutionTemplateLiteral(expression)) {
|
|
4996
4952
|
return expression.text;
|
|
4997
4953
|
}
|
|
4998
|
-
if (
|
|
4954
|
+
if (ts3.isNumericLiteral(expression)) {
|
|
4999
4955
|
return Number(expression.text);
|
|
5000
4956
|
}
|
|
5001
|
-
if (expression.kind ===
|
|
4957
|
+
if (expression.kind === ts3.SyntaxKind.TrueKeyword) {
|
|
5002
4958
|
return true;
|
|
5003
4959
|
}
|
|
5004
|
-
if (expression.kind ===
|
|
4960
|
+
if (expression.kind === ts3.SyntaxKind.FalseKeyword) {
|
|
5005
4961
|
return false;
|
|
5006
4962
|
}
|
|
5007
|
-
if (
|
|
4963
|
+
if (ts3.isObjectLiteralExpression(expression)) {
|
|
5008
4964
|
return readObjectLiteral(expression);
|
|
5009
4965
|
}
|
|
5010
4966
|
return void 0;
|
|
5011
4967
|
}
|
|
5012
4968
|
function readObjectLiteral(expression) {
|
|
5013
4969
|
const value = {};
|
|
5014
|
-
for (const
|
|
5015
|
-
if (!
|
|
4970
|
+
for (const property2 of expression.properties) {
|
|
4971
|
+
if (!ts3.isPropertyAssignment(property2)) {
|
|
5016
4972
|
continue;
|
|
5017
4973
|
}
|
|
5018
|
-
const name2 = getPropertyName(
|
|
4974
|
+
const name2 = getPropertyName(property2.name);
|
|
5019
4975
|
if (!name2) {
|
|
5020
4976
|
continue;
|
|
5021
4977
|
}
|
|
5022
|
-
value[name2] = staticExpressionValue2(
|
|
4978
|
+
value[name2] = staticExpressionValue2(property2.initializer);
|
|
5023
4979
|
}
|
|
5024
4980
|
return value;
|
|
5025
4981
|
}
|
|
5026
4982
|
function getPropertyName(name2) {
|
|
5027
|
-
if (
|
|
4983
|
+
if (ts3.isIdentifier(name2) || ts3.isStringLiteral(name2)) {
|
|
5028
4984
|
return name2.text;
|
|
5029
4985
|
}
|
|
5030
4986
|
return null;
|
|
@@ -5034,12 +4990,12 @@ function collectEventPreviewComponentPropUsages(node, eventPreviewAttrVariables,
|
|
|
5034
4990
|
if (!isComponentName(componentName)) {
|
|
5035
4991
|
return;
|
|
5036
4992
|
}
|
|
5037
|
-
for (const
|
|
5038
|
-
if (!
|
|
4993
|
+
for (const property2 of node.attributes.properties) {
|
|
4994
|
+
if (!ts3.isJsxAttribute(property2)) {
|
|
5039
4995
|
continue;
|
|
5040
4996
|
}
|
|
5041
|
-
const propName = getJsxAttributeName(
|
|
5042
|
-
const fieldId = getJsxFieldIdValue(
|
|
4997
|
+
const propName = getJsxAttributeName(property2.name);
|
|
4998
|
+
const fieldId = getJsxFieldIdValue(property2.initializer, eventPreviewAttrVariables);
|
|
5043
4999
|
if (!propName || !fieldId || !isFieldId(fieldId)) {
|
|
5044
5000
|
continue;
|
|
5045
5001
|
}
|
|
@@ -5052,7 +5008,7 @@ function collectEventPreviewComponentPropUsages(node, eventPreviewAttrVariables,
|
|
|
5052
5008
|
}
|
|
5053
5009
|
}
|
|
5054
5010
|
function getJsxAttributeName(name2) {
|
|
5055
|
-
if (
|
|
5011
|
+
if (ts3.isIdentifier(name2)) {
|
|
5056
5012
|
return name2.text;
|
|
5057
5013
|
}
|
|
5058
5014
|
return void 0;
|
|
@@ -5061,19 +5017,19 @@ function getJsxFieldIdValue(initializer, eventPreviewAttrVariables) {
|
|
|
5061
5017
|
if (!initializer) {
|
|
5062
5018
|
return void 0;
|
|
5063
5019
|
}
|
|
5064
|
-
if (
|
|
5020
|
+
if (ts3.isStringLiteral(initializer)) {
|
|
5065
5021
|
return initializer.text;
|
|
5066
5022
|
}
|
|
5067
|
-
if (
|
|
5023
|
+
if (ts3.isJsxExpression(initializer) && initializer.expression && ts3.isIdentifier(initializer.expression)) {
|
|
5068
5024
|
return eventPreviewAttrVariables.get(initializer.expression.text);
|
|
5069
5025
|
}
|
|
5070
5026
|
return void 0;
|
|
5071
5027
|
}
|
|
5072
5028
|
function getFunctionComponentName(node) {
|
|
5073
|
-
if (
|
|
5029
|
+
if (ts3.isFunctionDeclaration(node) && node.name && isComponentName(node.name.text)) {
|
|
5074
5030
|
return node.name.text;
|
|
5075
5031
|
}
|
|
5076
|
-
if (
|
|
5032
|
+
if (ts3.isVariableDeclaration(node) && ts3.isIdentifier(node.name) && isComponentName(node.name.text) && node.initializer && (ts3.isArrowFunction(node.initializer) || ts3.isFunctionExpression(node.initializer))) {
|
|
5077
5033
|
return node.name.text;
|
|
5078
5034
|
}
|
|
5079
5035
|
return void 0;
|
|
@@ -5083,10 +5039,10 @@ function isComponentName(name2) {
|
|
|
5083
5039
|
}
|
|
5084
5040
|
function getAssignedVariableName(node) {
|
|
5085
5041
|
let current = node;
|
|
5086
|
-
while (
|
|
5042
|
+
while (ts3.isAwaitExpression(current.parent)) {
|
|
5087
5043
|
current = current.parent;
|
|
5088
5044
|
}
|
|
5089
|
-
if (
|
|
5045
|
+
if (ts3.isVariableDeclaration(current.parent) && ts3.isIdentifier(current.parent.name)) {
|
|
5090
5046
|
return current.parent.name.text;
|
|
5091
5047
|
}
|
|
5092
5048
|
return void 0;
|
|
@@ -5334,8 +5290,8 @@ async function siteSetupActivityCommand(input) {
|
|
|
5334
5290
|
|
|
5335
5291
|
// ../cli/dist/commands/setup-start.js
|
|
5336
5292
|
import { randomBytes, randomUUID as randomUUID4 } from "crypto";
|
|
5337
|
-
import { access as
|
|
5338
|
-
import { join as
|
|
5293
|
+
import { access as access5 } from "fs/promises";
|
|
5294
|
+
import { join as join10, relative as relative5 } from "path";
|
|
5339
5295
|
import { z as z37 } from "zod";
|
|
5340
5296
|
var bootstrapResponseSchema2 = z37.object({
|
|
5341
5297
|
ok: z37.literal(true),
|
|
@@ -5344,8 +5300,8 @@ var bootstrapResponseSchema2 = z37.object({
|
|
|
5344
5300
|
async function setupStartCommand(input) {
|
|
5345
5301
|
await assertLocalCredentialsPathSafe(input.projectDir, input);
|
|
5346
5302
|
const [hasConfig, hasCredentials] = await Promise.all([
|
|
5347
|
-
exists2(
|
|
5348
|
-
exists2(
|
|
5303
|
+
exists2(join10(input.projectDir, "siteplane.config.json")),
|
|
5304
|
+
exists2(join10(input.projectDir, ".siteplane/credentials.json"))
|
|
5349
5305
|
]);
|
|
5350
5306
|
if (hasConfig && !hasCredentials) {
|
|
5351
5307
|
throw new SetupFailure("local_credentials_missing", "This project has Siteplane configuration but no local credentials. Restore its credentials or explicitly start a new installation; public site identifiers cannot recover access.");
|
|
@@ -5456,7 +5412,7 @@ function result(status, siteId, runId) {
|
|
|
5456
5412
|
}
|
|
5457
5413
|
async function exists2(path) {
|
|
5458
5414
|
try {
|
|
5459
|
-
await
|
|
5415
|
+
await access5(path);
|
|
5460
5416
|
return true;
|
|
5461
5417
|
} catch (error) {
|
|
5462
5418
|
if (error.code === "ENOENT")
|
|
@@ -5551,13 +5507,13 @@ async function setupReviewCommand(input) {
|
|
|
5551
5507
|
}
|
|
5552
5508
|
|
|
5553
5509
|
// ../cli/dist/commands/setup-prepare.js
|
|
5554
|
-
import { access as
|
|
5510
|
+
import { access as access6, lstat as lstat2, mkdir as mkdir6, open as open3, readFile as readFile10, rename as rename3, rm as rm3 } from "fs/promises";
|
|
5555
5511
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5556
|
-
import { dirname as
|
|
5557
|
-
import
|
|
5558
|
-
var exists3 = async (path) =>
|
|
5512
|
+
import { dirname as dirname8, join as join11, relative as relative6, sep as sep2 } from "path";
|
|
5513
|
+
import ts4 from "typescript";
|
|
5514
|
+
var exists3 = async (path) => access6(path).then(() => true, () => false);
|
|
5559
5515
|
var importPath = (from, target) => {
|
|
5560
|
-
const path = relative6(
|
|
5516
|
+
const path = relative6(dirname8(from), target).split(sep2).join("/");
|
|
5561
5517
|
return path.startsWith(".") ? path : `./${path}`;
|
|
5562
5518
|
};
|
|
5563
5519
|
async function setupPrepareCommand(input) {
|
|
@@ -5579,18 +5535,18 @@ async function setupPrepareCommand(input) {
|
|
|
5579
5535
|
message: "The verified setup is available for owner review; no preparation writes are needed."
|
|
5580
5536
|
};
|
|
5581
5537
|
const directory = preflight.local.projectDirectory;
|
|
5582
|
-
const app =
|
|
5583
|
-
const layouts = (await Promise.all(["layout.tsx", "layout.jsx", "layout.js"].map(async (name2) => await exists3(
|
|
5538
|
+
const app = join11(directory, preflight.local.appDirectory);
|
|
5539
|
+
const layouts = (await Promise.all(["layout.tsx", "layout.jsx", "layout.js"].map(async (name2) => await exists3(join11(app, name2)) ? join11(app, name2) : null))).filter((path) => path !== null);
|
|
5584
5540
|
if (layouts.length !== 1)
|
|
5585
5541
|
throw new SetupFailure("layout_integration_conflict", "Select one root layout and mount the Siteplane preview bridge there; preserve existing providers and rendering.");
|
|
5586
5542
|
const layoutPath = layouts[0];
|
|
5587
5543
|
const typed = layoutPath.endsWith(".tsx");
|
|
5588
5544
|
const routeExtension = typed ? "ts" : "js";
|
|
5589
|
-
const bridgePath =
|
|
5545
|
+
const bridgePath = join11(app, "_siteplane", `bridge.${typed ? "tsx" : "jsx"}`);
|
|
5590
5546
|
const portal = task.site.portalPath;
|
|
5591
5547
|
if (!/^\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(portal))
|
|
5592
5548
|
throw new SetupFailure("portal_route_conflict", "The selected portal path is not a supported single route segment.");
|
|
5593
|
-
const adminRoot =
|
|
5549
|
+
const adminRoot = join11(app, portal.slice(1));
|
|
5594
5550
|
for (const name2 of [
|
|
5595
5551
|
"page.tsx",
|
|
5596
5552
|
"page.jsx",
|
|
@@ -5598,12 +5554,12 @@ async function setupPrepareCommand(input) {
|
|
|
5598
5554
|
"route.ts",
|
|
5599
5555
|
"route.js"
|
|
5600
5556
|
]) {
|
|
5601
|
-
if (await exists3(
|
|
5557
|
+
if (await exists3(join11(adminRoot, name2)))
|
|
5602
5558
|
throw new SetupFailure("portal_route_conflict", "The selected admin path already belongs to the website. Choose an unused editor path in Siteplane.");
|
|
5603
5559
|
}
|
|
5604
|
-
const configPath =
|
|
5605
|
-
const adminPath =
|
|
5606
|
-
const revalidationPath =
|
|
5560
|
+
const configPath = join11(directory, "siteplane.config.json");
|
|
5561
|
+
const adminPath = join11(adminRoot, "[[...siteplane]]", `route.${routeExtension}`);
|
|
5562
|
+
const revalidationPath = join11(app, "api/siteplane/revalidate", `route.${routeExtension}`);
|
|
5607
5563
|
const commonOptions = `siteId: config.siteId,
|
|
5608
5564
|
publicRuntimeKeyId: config.publicSiteKeyId,
|
|
5609
5565
|
fieldContractHash: process.env.SITEPLANE_BUILD_FIELD_CONTRACT_HASH${typed ? "!" : ""},
|
|
@@ -5660,12 +5616,12 @@ export default function SiteplaneBridge() {
|
|
|
5660
5616
|
]);
|
|
5661
5617
|
const layoutSource = await readFile10(layoutPath, "utf8");
|
|
5662
5618
|
if (!/import\s+SiteplaneBridge\s+from\s+["']\.\/_siteplane\/bridge["']/u.test(layoutSource)) {
|
|
5663
|
-
const ast =
|
|
5619
|
+
const ast = ts4.createSourceFile(layoutPath, layoutSource, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
5664
5620
|
const closingBodies = [];
|
|
5665
5621
|
const visit = (node) => {
|
|
5666
|
-
if (
|
|
5622
|
+
if (ts4.isJsxClosingElement(node) && node.tagName.getText(ast) === "body")
|
|
5667
5623
|
closingBodies.push(node.getStart(ast));
|
|
5668
|
-
|
|
5624
|
+
ts4.forEachChild(node, visit);
|
|
5669
5625
|
};
|
|
5670
5626
|
visit(ast);
|
|
5671
5627
|
if (closingBodies.length !== 1)
|
|
@@ -5673,7 +5629,7 @@ export default function SiteplaneBridge() {
|
|
|
5673
5629
|
const point = closingBodies[0];
|
|
5674
5630
|
let importPoint = 0;
|
|
5675
5631
|
for (const statement of ast.statements) {
|
|
5676
|
-
if (!
|
|
5632
|
+
if (!ts4.isExpressionStatement(statement) || !ts4.isStringLiteral(statement.expression))
|
|
5677
5633
|
break;
|
|
5678
5634
|
importPoint = statement.end;
|
|
5679
5635
|
}
|
|
@@ -5681,21 +5637,21 @@ export default function SiteplaneBridge() {
|
|
|
5681
5637
|
import SiteplaneBridge from "./_siteplane/bridge";
|
|
5682
5638
|
${layoutSource.slice(importPoint, point)}<SiteplaneBridge />${layoutSource.slice(point)}`);
|
|
5683
5639
|
}
|
|
5684
|
-
const configs = (await Promise.all(["next.config.ts", "next.config.mjs", "next.config.js"].map(async (name2) => await exists3(
|
|
5640
|
+
const configs = (await Promise.all(["next.config.ts", "next.config.mjs", "next.config.js"].map(async (name2) => await exists3(join11(directory, name2)) ? join11(directory, name2) : null))).filter((path) => path !== null);
|
|
5685
5641
|
if (configs.length > 1)
|
|
5686
5642
|
throw new SetupFailure("next_config_conflict", "Choose one existing Next.js configuration before setup.");
|
|
5687
|
-
const nextPath = configs[0] ??
|
|
5643
|
+
const nextPath = configs[0] ?? join11(directory, "next.config.mjs");
|
|
5688
5644
|
const nextSource = configs.length ? await readFile10(nextPath, "utf8") : "export default {};\n";
|
|
5689
5645
|
if (!/\bwithSiteplane\s*\(/u.test(nextSource)) {
|
|
5690
|
-
const ast =
|
|
5691
|
-
const exported = ast.statements.filter(
|
|
5646
|
+
const ast = ts4.createSourceFile(nextPath, nextSource, ts4.ScriptTarget.Latest, true);
|
|
5647
|
+
const exported = ast.statements.filter(ts4.isExportAssignment);
|
|
5692
5648
|
if (exported.length !== 1 || exported[0].isExportEquals)
|
|
5693
5649
|
throw new SetupFailure("next_config_conflict", "Wrap the existing default Next.js configuration with withSiteplane from siteplane/next, preserving its existing options.");
|
|
5694
5650
|
const expression = exported[0].expression;
|
|
5695
5651
|
files.set(nextPath, `import { withSiteplane } from "siteplane/next";
|
|
5696
5652
|
${nextSource.slice(0, expression.getStart(ast))}withSiteplane(${expression.getText(ast)})${nextSource.slice(expression.end)}`);
|
|
5697
5653
|
}
|
|
5698
|
-
const guidePath =
|
|
5654
|
+
const guidePath = join11(directory, ".siteplane/setup-guide-v2.md");
|
|
5699
5655
|
files.set(guidePath, `# Siteplane setup task v2
|
|
5700
5656
|
|
|
5701
5657
|
${task.goal}
|
|
@@ -5723,7 +5679,7 @@ Run setup context for the current user instructions and authorized modules. Keep
|
|
|
5723
5679
|
return null;
|
|
5724
5680
|
throw error;
|
|
5725
5681
|
}));
|
|
5726
|
-
const packageManifest = JSON.parse(await readFile10(
|
|
5682
|
+
const packageManifest = JSON.parse(await readFile10(join11(directory, "package.json"), "utf8"));
|
|
5727
5683
|
const pm = preflight.local.packageManager;
|
|
5728
5684
|
const command = (args) => setupProcess("npx", ["--yes", "--package", `${pm.name}@${pm.version}`, pm.name, ...args], {
|
|
5729
5685
|
cwd: directory,
|
|
@@ -5774,7 +5730,7 @@ Run setup context for the current user instructions and authorized modules. Keep
|
|
|
5774
5730
|
throw new SetupFailure("source_changed_during_prepare", "The source changed while dependencies were installing. Preserve the concurrent edit and reconcile it before retrying preparation.");
|
|
5775
5731
|
if (current === content)
|
|
5776
5732
|
continue;
|
|
5777
|
-
await mkdir6(
|
|
5733
|
+
await mkdir6(dirname8(path), {
|
|
5778
5734
|
recursive: true,
|
|
5779
5735
|
mode: path.includes(`${sep2}.siteplane${sep2}`) ? 448 : 493
|
|
5780
5736
|
});
|
|
@@ -5819,7 +5775,7 @@ async function assertSourcePath(root, target) {
|
|
|
5819
5775
|
for (const part of relative6(root, target).split(sep2)) {
|
|
5820
5776
|
if (part === "..")
|
|
5821
5777
|
throw new SetupFailure("unsafe_source_path", "The prepared file is outside the selected application.");
|
|
5822
|
-
current =
|
|
5778
|
+
current = join11(current, part);
|
|
5823
5779
|
const stat = await lstat2(current).catch((error) => {
|
|
5824
5780
|
if (error.code === "ENOENT")
|
|
5825
5781
|
return null;
|
|
@@ -5897,7 +5853,7 @@ function locked() {
|
|
|
5897
5853
|
import { createHash as createHash3 } from "crypto";
|
|
5898
5854
|
import { execFile as execFile3 } from "child_process";
|
|
5899
5855
|
import { lstat as lstat4, readFile as readFile12, writeFile as writeFile5, mkdir as mkdir8 } from "fs/promises";
|
|
5900
|
-
import { dirname as
|
|
5856
|
+
import { dirname as dirname9, isAbsolute as isAbsolute2, join as join12, relative as relative7, resolve as resolve3, sep as sep3 } from "path";
|
|
5901
5857
|
import { isDeepStrictEqual, promisify as promisify3 } from "util";
|
|
5902
5858
|
import { z as z40 } from "zod";
|
|
5903
5859
|
var execute = promisify3(execFile3);
|
|
@@ -5937,15 +5893,15 @@ async function writeBuildProvenance(checkout, revision) {
|
|
|
5937
5893
|
if (entry.mode !== "120000")
|
|
5938
5894
|
continue;
|
|
5939
5895
|
const { readlink: readlink2 } = await import("fs/promises");
|
|
5940
|
-
const path =
|
|
5941
|
-
const target2 = resolve3(
|
|
5896
|
+
const path = join12(checkout, entry.path);
|
|
5897
|
+
const target2 = resolve3(dirname9(path), await readlink2(path));
|
|
5942
5898
|
const bound = relative7(checkout, target2);
|
|
5943
5899
|
if (bound.startsWith("..") || isAbsolute2(bound))
|
|
5944
5900
|
throw new Error("A tracked symbolic link escapes the committed upload; resolve that source boundary before deployment.");
|
|
5945
5901
|
}
|
|
5946
5902
|
const providerConfigurations = await Promise.all(entries.filter((entry) => /(?:^|\/)vercel\.json$/u.test(entry.path)).map(async (entry) => ({
|
|
5947
5903
|
path: entry.path,
|
|
5948
|
-
source: await readFile12(
|
|
5904
|
+
source: await readFile12(join12(checkout, entry.path), "utf8")
|
|
5949
5905
|
})));
|
|
5950
5906
|
const record = schema.parse({
|
|
5951
5907
|
version: 2,
|
|
@@ -5954,16 +5910,16 @@ async function writeBuildProvenance(checkout, revision) {
|
|
|
5954
5910
|
entries,
|
|
5955
5911
|
providerConfigurations
|
|
5956
5912
|
});
|
|
5957
|
-
const target =
|
|
5958
|
-
await mkdir8(
|
|
5913
|
+
const target = join12(checkout, name);
|
|
5914
|
+
await mkdir8(dirname9(target), { recursive: true, mode: 448 });
|
|
5959
5915
|
await writeFile5(target, JSON.stringify(record), { flag: "wx", mode: 384 });
|
|
5960
5916
|
}
|
|
5961
5917
|
|
|
5962
5918
|
// ../cli/dist/commands/setup-deploy.js
|
|
5963
5919
|
import { createHash as createHash4, randomBytes as randomBytes2, randomUUID as randomUUID7 } from "crypto";
|
|
5964
|
-
import { access as
|
|
5920
|
+
import { access as access7, mkdir as mkdir9, mkdtemp, rm as rm5, writeFile as writeFile6 } from "fs/promises";
|
|
5965
5921
|
import { tmpdir } from "os";
|
|
5966
|
-
import { join as
|
|
5922
|
+
import { join as join13 } from "path";
|
|
5967
5923
|
import { z as z41 } from "zod";
|
|
5968
5924
|
var envSchema = z41.object({
|
|
5969
5925
|
id: z41.string(),
|
|
@@ -6029,7 +5985,7 @@ var PROVIDER_RESUME_READBACK_TIMEOUT_MS = 12e4;
|
|
|
6029
5985
|
async function setupDeployCommand(input, deps = defaults) {
|
|
6030
5986
|
let record = null;
|
|
6031
5987
|
try {
|
|
6032
|
-
if (!await
|
|
5988
|
+
if (!await access7(join13(input.projectDir, "siteplane.config.json")).then(() => true, () => false) || !await access7(join13(input.projectDir, ".siteplane/credentials.json")).then(() => true, () => false))
|
|
6033
5989
|
fail2("local_connection_missing", "Open this site's setup and choose Replace local connection, then initialize this folder with its new one-time grant.");
|
|
6034
5990
|
await assertLocalCredentialsPathSafe(input.projectDir);
|
|
6035
5991
|
const config = await readProjectConfig(input.projectDir);
|
|
@@ -6335,7 +6291,7 @@ async function setupDeployCommand(input, deps = defaults) {
|
|
|
6335
6291
|
], { cwd: local.projectDirectory, input: body, timeoutMs: 3e4 });
|
|
6336
6292
|
}
|
|
6337
6293
|
} else {
|
|
6338
|
-
const upload = await mkdtemp(
|
|
6294
|
+
const upload = await mkdtemp(join13(tmpdir(), "siteplane-setup-upload-"));
|
|
6339
6295
|
try {
|
|
6340
6296
|
await processCommand("git", [
|
|
6341
6297
|
"clone",
|
|
@@ -6349,11 +6305,11 @@ async function setupDeployCommand(input, deps = defaults) {
|
|
|
6349
6305
|
cwd: upload
|
|
6350
6306
|
});
|
|
6351
6307
|
await deps.writeBuildProvenance(upload, revision);
|
|
6352
|
-
await mkdir9(
|
|
6308
|
+
await mkdir9(join13(upload, ".vercel"), {
|
|
6353
6309
|
recursive: true,
|
|
6354
6310
|
mode: 448
|
|
6355
6311
|
});
|
|
6356
|
-
await writeFile6(
|
|
6312
|
+
await writeFile6(join13(upload, ".vercel/project.json"), JSON.stringify({
|
|
6357
6313
|
projectId: provider.projectId,
|
|
6358
6314
|
orgId: provider.teamId
|
|
6359
6315
|
}), { mode: 384 });
|
|
@@ -6539,7 +6495,7 @@ function required(code, message) {
|
|
|
6539
6495
|
// src/bin/run-siteplane.ts
|
|
6540
6496
|
async function runSiteplaneCli(args, dependencies = createDefaultDependencies()) {
|
|
6541
6497
|
const writes = args[0] === "init" || args[0] === "analytics" && args[1] === "init" || args[0] === "setup" && (["start", "apply", "prepare", "deploy"].includes(args[1] ?? "") || args[1] === "claim" && args[2] === "confirm");
|
|
6542
|
-
const missingDeploy = args[0] === "setup" && args[1] === "deploy" && !await
|
|
6498
|
+
const missingDeploy = args[0] === "setup" && args[1] === "deploy" && !await access8(join14(dependencies.cwd(), "siteplane.config.json")).then(
|
|
6543
6499
|
() => true,
|
|
6544
6500
|
() => false
|
|
6545
6501
|
);
|
|
@@ -6621,7 +6577,7 @@ async function runAnalyticsCommand(args, dependencies) {
|
|
|
6621
6577
|
siteId: projectConfig.siteId,
|
|
6622
6578
|
...readOptionalVercelAutomationBypassSecret(dependencies.env)
|
|
6623
6579
|
};
|
|
6624
|
-
const manifestPath =
|
|
6580
|
+
const manifestPath = join14(projectDir, "siteplane.analytics.json");
|
|
6625
6581
|
if (subcommand === "init") {
|
|
6626
6582
|
const { rawPublicKey } = await dependencies.commands.analyticsPrepareCommand({
|
|
6627
6583
|
config
|
|
@@ -6653,18 +6609,18 @@ async function runAnalyticsCommand(args, dependencies) {
|
|
|
6653
6609
|
projectDir
|
|
6654
6610
|
}
|
|
6655
6611
|
);
|
|
6656
|
-
const artifactFilePaths = [
|
|
6612
|
+
const artifactFilePaths = [join14(projectDir, ".siteplane/analytics.md")];
|
|
6657
6613
|
const cspFilePaths = await existingPaths([
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6614
|
+
join14(projectDir, "next.config.js"),
|
|
6615
|
+
join14(projectDir, "next.config.mjs"),
|
|
6616
|
+
join14(projectDir, "next.config.ts"),
|
|
6617
|
+
join14(projectDir, "middleware.ts"),
|
|
6618
|
+
join14(projectDir, "src/middleware.ts")
|
|
6663
6619
|
]);
|
|
6664
6620
|
const check = await dependencies.commands.analyticsCheckCommand({
|
|
6665
6621
|
manifestPath,
|
|
6666
6622
|
sourceFilePaths,
|
|
6667
|
-
packageJsonPath:
|
|
6623
|
+
packageJsonPath: join14(projectDir, "package.json"),
|
|
6668
6624
|
cspFilePaths,
|
|
6669
6625
|
artifactFilePaths
|
|
6670
6626
|
});
|
|
@@ -6855,7 +6811,7 @@ async function runSetupCommand(args, dependencies) {
|
|
|
6855
6811
|
async function runBookingCommand(args, dependencies) {
|
|
6856
6812
|
const [subcommand, ...subcommandArgs] = args;
|
|
6857
6813
|
const projectDir = dependencies.cwd();
|
|
6858
|
-
const manifestPath =
|
|
6814
|
+
const manifestPath = join14(projectDir, "siteplane.booking.json");
|
|
6859
6815
|
if (subcommand === "init") {
|
|
6860
6816
|
const siteId = readRequiredOption(subcommandArgs, "--site-id");
|
|
6861
6817
|
const siteKeyPrefix = readRequiredOption(
|
|
@@ -7053,7 +7009,7 @@ async function existingPaths(paths) {
|
|
|
7053
7009
|
const existing = [];
|
|
7054
7010
|
for (const path of paths) {
|
|
7055
7011
|
try {
|
|
7056
|
-
await
|
|
7012
|
+
await access8(path);
|
|
7057
7013
|
existing.push(path);
|
|
7058
7014
|
} catch {
|
|
7059
7015
|
}
|