siteplane 0.1.64 → 0.1.66

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/dist/index.js CHANGED
@@ -631,6 +631,7 @@ var bookingPublicConfigSchema = z9.object({
631
631
  settings: z9.object({
632
632
  slotIntervalMinutes: z9.number().int().positive(),
633
633
  minLeadMinutes: z9.number().int().min(0),
634
+ minCancelLeadMinutes: z9.number().int().min(0),
634
635
  maxAdvanceDays: z9.number().int().min(1),
635
636
  requirePhone: z9.boolean(),
636
637
  collectNote: z9.boolean(),
@@ -839,7 +840,7 @@ var bookingManifestSchema = z9.object({
839
840
  siteId: z9.string().trim().min(1),
840
841
  siteKeyPrefix: z9.string().startsWith("bk_pub_"),
841
842
  bookingPageSlug: z9.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).min(2).max(64),
842
- embedMode: z9.enum(["script", "web_component", "iframe"]).optional(),
843
+ integration: z9.literal("rewrite").optional(),
843
844
  productionOrigin: z9.string().url().optional()
844
845
  }).passthrough();
845
846
  var secretManifestKeys = /* @__PURE__ */ new Set([
@@ -2242,117 +2243,63 @@ function collectRedactedBookingKeys(input, prefix = "") {
2242
2243
  }
2243
2244
 
2244
2245
  // ../cli/dist/booking/static-scan.js
2246
+ import ts2 from "typescript";
2245
2247
  function scanBookingSourceFiles(files, input) {
2246
- const embeds = files.flatMap(scanBookingEmbedFile);
2247
- const findings = embeds.map(createEmbedFoundIssue);
2248
- const hardErrors = embeds.length === 0 ? [
2249
- {
2250
- code: "booking_scan.embed_missing",
2251
- message: "No Siteplane Booking embed script, web component or iframe was found.",
2248
+ const findings = [];
2249
+ const hardErrors = [];
2250
+ const warnings = [];
2251
+ for (const file of files) {
2252
+ let visit2 = function(node) {
2253
+ if (ts2.isCallExpression(node) && ts2.isIdentifier(node.expression) && node.expression.text === "withSiteplane") {
2254
+ const options = node.arguments[1];
2255
+ const booking = options && property(options, "booking");
2256
+ const site = booking && property(booking, "site");
2257
+ if (site && ts2.isStringLiteralLike(site)) {
2258
+ const issue = {
2259
+ code: site.text === input.siteId ? "booking_scan.integration_found" : "booking_scan.site_mismatch",
2260
+ 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.",
2261
+ filePath: file.filePath
2262
+ };
2263
+ (site.text === input.siteId ? findings : hardErrors).push(issue);
2264
+ }
2265
+ }
2266
+ ts2.forEachChild(node, visit2);
2267
+ };
2268
+ var visit = visit2;
2269
+ const source = ts2.createSourceFile(file.filePath, file.sourceText, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
2270
+ visit2(source);
2271
+ }
2272
+ if (!findings.length && !hardErrors.length)
2273
+ hardErrors.push({
2274
+ code: "booking_scan.integration_missing",
2275
+ message: "Could not verify withSiteplane(nextConfig, { booking: { site: <site-id> } }). Include next.config.ts in the scan and use a literal Site ID.",
2276
+ filePath: "next.config.ts"
2277
+ });
2278
+ if (input.productionOrigin && !files.some((file) => file.sourceText.includes(input.productionOrigin)))
2279
+ warnings.push({
2280
+ code: "booking_scan.origin_not_detected",
2281
+ message: "Verify the public booking address and its allowed origins in Siteplane settings.",
2252
2282
  filePath: "siteplane.booking.json"
2253
- }
2254
- ] : [];
2255
- const warnings = [
2256
- ...createPageSlugWarnings(embeds, input.bookingPageSlug),
2257
- ...createOriginWarnings(files, input.productionOrigin)
2258
- ];
2259
- const selectedEmbed = selectManifestEmbed(embeds);
2260
- const manifest = bookingManifestSchema.parse({
2261
- schemaVersion: 1,
2262
- siteId: input.siteId,
2263
- siteKeyPrefix: input.siteKeyPrefix,
2264
- bookingPageSlug: selectedEmbed?.pageSlug ?? input.bookingPageSlug,
2265
- ...selectedEmbed ? { embedMode: selectedEmbed.embedMode } : {},
2266
- ...input.productionOrigin ? { productionOrigin: input.productionOrigin } : {}
2267
- });
2283
+ });
2268
2284
  return {
2269
- manifest,
2285
+ manifest: bookingManifestSchema.parse({
2286
+ schemaVersion: 1,
2287
+ ...input,
2288
+ integration: "rewrite"
2289
+ }),
2270
2290
  findings,
2271
2291
  hardErrors,
2272
2292
  warnings,
2273
2293
  suggestions: []
2274
2294
  };
2275
2295
  }
2276
- function scanBookingEmbedFile(file) {
2277
- const embeds = [];
2278
- const source = file.sourceText;
2279
- if (/\/embed\/booking\.js/u.test(source)) {
2280
- embeds.push({
2281
- filePath: file.filePath,
2282
- embedMode: "script"
2283
- });
2296
+ function property(node, name2) {
2297
+ if (!ts2.isObjectLiteralExpression(node))
2298
+ return;
2299
+ for (const item of node.properties) {
2300
+ if (ts2.isPropertyAssignment(item) && (ts2.isIdentifier(item.name) || ts2.isStringLiteral(item.name)) && item.name.text === name2)
2301
+ return item.initializer;
2284
2302
  }
2285
- if (/<siteplane-booking\b/u.test(source)) {
2286
- const pageSlug = readAttributeValue(source, "booking-page-slug");
2287
- embeds.push({
2288
- filePath: file.filePath,
2289
- embedMode: "web_component",
2290
- ...pageSlug ? { pageSlug } : {}
2291
- });
2292
- }
2293
- for (const match of source.matchAll(/<iframe\b[^>]*>/giu)) {
2294
- const tag = match[0];
2295
- const src = readAttributeValue(tag, "src");
2296
- const pageSlug = src ? readBookingPageSlug(src) : void 0;
2297
- if (/data-siteplane-booking/u.test(tag) || pageSlug !== void 0) {
2298
- embeds.push({
2299
- filePath: file.filePath,
2300
- embedMode: "iframe",
2301
- ...pageSlug ? { pageSlug } : {}
2302
- });
2303
- }
2304
- }
2305
- return embeds;
2306
- }
2307
- function createEmbedFoundIssue(embed) {
2308
- return {
2309
- code: "booking_scan.embed_found",
2310
- message: "Siteplane Booking embed was found.",
2311
- filePath: embed.filePath,
2312
- embedMode: embed.embedMode,
2313
- ...embed.pageSlug ? { pageSlug: embed.pageSlug } : {}
2314
- };
2315
- }
2316
- function createPageSlugWarnings(embeds, expectedSlug) {
2317
- return embeds.filter((embed) => embed.pageSlug && embed.pageSlug !== expectedSlug).map((embed) => {
2318
- const pageSlug = embed.pageSlug;
2319
- return {
2320
- code: "booking_scan.page_slug_mismatch",
2321
- message: `Booking embed references page slug ${pageSlug}, but the manifest is configured for ${expectedSlug}.`,
2322
- filePath: embed.filePath,
2323
- embedMode: embed.embedMode,
2324
- ...pageSlug ? { pageSlug } : {}
2325
- };
2326
- });
2327
- }
2328
- function createOriginWarnings(files, productionOrigin) {
2329
- if (!productionOrigin) {
2330
- return [];
2331
- }
2332
- if (files.some((file) => file.sourceText.includes(productionOrigin))) {
2333
- return [];
2334
- }
2335
- return [
2336
- {
2337
- code: "booking_scan.origin_not_detected",
2338
- message: "The configured production origin was not found statically; verify it is registered as an allowed Booking origin in Siteplane.",
2339
- filePath: "siteplane.booking.json"
2340
- }
2341
- ];
2342
- }
2343
- function selectManifestEmbed(embeds) {
2344
- return embeds.find((embed) => embed.embedMode === "web_component") ?? embeds.find((embed) => embed.embedMode === "iframe") ?? embeds[0];
2345
- }
2346
- function readAttributeValue(source, attributeName) {
2347
- const escapedName = escapeRegExp(attributeName);
2348
- const match = new RegExp(`${escapedName}\\s*=\\s*["']([^"']+)["']`, "iu").exec(source);
2349
- return match?.[1];
2350
- }
2351
- function readBookingPageSlug(value) {
2352
- return /\/book\/([a-z0-9]+(?:-[a-z0-9]+)*)(?:[/?#]|$)/u.exec(value)?.[1];
2353
- }
2354
- function escapeRegExp(value) {
2355
- return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
2356
2303
  }
2357
2304
 
2358
2305
  // ../cli/dist/commands/analytics/check.js
@@ -2455,10 +2402,17 @@ var errorSchema = z30.object({
2455
2402
  import { randomUUID } from "crypto";
2456
2403
 
2457
2404
  // ../cli/dist/commands/booking/check.js
2458
- import { readFile as readFile4 } from "fs/promises";
2405
+ import { dirname as dirname4, join as join2 } from "path";
2406
+ import { access, readFile as readFile4 } from "fs/promises";
2459
2407
  async function bookingCheckCommand(input) {
2460
2408
  const validatedManifest = await readBookingManifestFile(input.manifestPath);
2461
- const sourceFiles = await readSourceFiles(input.sourceFilePaths);
2409
+ const configs = (await Promise.all(["next.config.ts", "next.config.js", "next.config.mjs"].map(async (name2) => {
2410
+ const path = join2(dirname4(input.manifestPath), name2);
2411
+ return await access(path).then(() => path, () => null);
2412
+ }))).filter((path) => path !== null);
2413
+ const sourceFiles = await readSourceFiles([
2414
+ .../* @__PURE__ */ new Set([...input.sourceFilePaths, ...configs])
2415
+ ]);
2462
2416
  const scanInput = {
2463
2417
  siteId: validatedManifest.manifest.siteId,
2464
2418
  siteKeyPrefix: validatedManifest.manifest.siteKeyPrefix,
@@ -2499,7 +2453,7 @@ function createBoundaryErrors(validation) {
2499
2453
 
2500
2454
  // ../cli/dist/commands/booking/init.js
2501
2455
  import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
2502
- import { dirname as dirname4, join as join2 } from "path";
2456
+ import { dirname as dirname5, join as join3 } from "path";
2503
2457
  async function bookingInitCommand(input) {
2504
2458
  const manifest = {
2505
2459
  schemaVersion: 1,
@@ -2508,7 +2462,7 @@ async function bookingInitCommand(input) {
2508
2462
  bookingPageSlug: input.bookingPageSlug,
2509
2463
  ...input.productionOrigin ? { productionOrigin: input.productionOrigin } : {}
2510
2464
  };
2511
- const manifestPath = join2(input.projectDir, "siteplane.booking.json");
2465
+ const manifestPath = join3(input.projectDir, "siteplane.booking.json");
2512
2466
  const artifacts = createBookingArtifacts(input.agentClient);
2513
2467
  await writeBookingManifestFile(manifestPath, manifest);
2514
2468
  for (const artifact of artifacts) {
@@ -2548,16 +2502,18 @@ function createBookingArtifacts(agentClient) {
2548
2502
  return artifacts;
2549
2503
  }
2550
2504
  async function writeProjectFile(projectDir, relativePath, contents) {
2551
- const path = join2(projectDir, relativePath);
2552
- await mkdir4(dirname4(path), { recursive: true });
2505
+ const path = join3(projectDir, relativePath);
2506
+ await mkdir4(dirname5(path), { recursive: true });
2553
2507
  await writeFile4(path, contents, "utf8");
2554
2508
  }
2555
2509
  var bookingRulesTemplate = `# Siteplane Booking Rules
2556
2510
 
2557
2511
  - Do not change layout, copy, styling, animation or business logic while adding Booking.
2558
- - Add only the Siteplane Booking embed script and a booking iframe or web component.
2559
- - Use the configured booking page slug from siteplane.booking.json.
2560
- - Register the production website origin in Siteplane before testing cross-origin embeds.
2512
+ - Integrate /booking on the customer domain through withSiteplane(nextConfig, { booking: { site: "<site-id>" } }); use the immutable Site ID supplied by Siteplane.
2513
+ - Use a normal <a href="/booking"> link, not next/link, an iframe or an embed script.
2514
+ - Preserve existing rewrites. Booking-only must not require Editor setup or siteplane.config.json.
2515
+ - 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.
2516
+ - Preserve customer CSP and middleware; explain required Siteplane/Stripe permissions and exclude /booking from customer middleware.
2561
2517
  - Do not write setup tokens, project CLI tokens or private keys into source files.
2562
2518
  - Run npx siteplane booking check, npx siteplane booking sync and npx siteplane booking test after setup.
2563
2519
  - booking test stays in test_mode; live booking only starts after explicit dashboard activation.
@@ -2565,7 +2521,7 @@ var bookingRulesTemplate = `# Siteplane Booking Rules
2565
2521
  function bookingSkillTemplate(agentName) {
2566
2522
  return `# Siteplane Booking Skill
2567
2523
 
2568
- Use this skill in ${agentName} before adding Siteplane Booking embeds.
2524
+ Use this skill in ${agentName} before integrating Siteplane Booking at /booking.
2569
2525
 
2570
2526
  ${bookingRulesTemplate}`;
2571
2527
  }
@@ -2640,9 +2596,9 @@ function requireContentExportScope(scopes) {
2640
2596
  }
2641
2597
 
2642
2598
  // ../cli/dist/config/project-config.js
2643
- import { access, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
2599
+ import { access as access2, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
2644
2600
  import { randomUUID as randomUUID2 } from "crypto";
2645
- import { join as join3 } from "path";
2601
+ import { join as join4 } from "path";
2646
2602
  import { z as z31 } from "zod";
2647
2603
  var siteplaneProjectConfigSchema = z31.object({
2648
2604
  version: z31.literal(2),
@@ -2658,7 +2614,7 @@ var siteplaneProjectConfigSchema = z31.object({
2658
2614
  fieldContractHash: z31.string().regex(/^sha256:[0-9a-f]{64}$/iu).optional()
2659
2615
  }).strict();
2660
2616
  async function readProjectPackageJson(projectDir) {
2661
- return JSON.parse(await readFile5(join3(projectDir, "package.json"), "utf8"));
2617
+ return JSON.parse(await readFile5(join4(projectDir, "package.json"), "utf8"));
2662
2618
  }
2663
2619
  async function detectNextProject(projectDir) {
2664
2620
  const packageJson = await readProjectPackageJson(projectDir).catch(() => null);
@@ -2671,7 +2627,7 @@ async function detectNextProject(projectDir) {
2671
2627
  "next.config.ts"
2672
2628
  ]) {
2673
2629
  try {
2674
- await access(join3(projectDir, fileName));
2630
+ await access2(join4(projectDir, fileName));
2675
2631
  return true;
2676
2632
  } catch {
2677
2633
  }
@@ -2679,13 +2635,13 @@ async function detectNextProject(projectDir) {
2679
2635
  return false;
2680
2636
  }
2681
2637
  async function writeProjectConfig(projectDir, config) {
2682
- const path = join3(projectDir, "siteplane.config.json");
2638
+ const path = join4(projectDir, "siteplane.config.json");
2683
2639
  const parsed = siteplaneProjectConfigSchema.parse(config);
2684
2640
  await writeJsonAtomically(path, parsed, 420);
2685
2641
  return path;
2686
2642
  }
2687
2643
  async function readProjectConfig(projectDir) {
2688
- return siteplaneProjectConfigSchema.parse(JSON.parse(await readFile5(join3(projectDir, "siteplane.config.json"), "utf8")));
2644
+ return siteplaneProjectConfigSchema.parse(JSON.parse(await readFile5(join4(projectDir, "siteplane.config.json"), "utf8")));
2689
2645
  }
2690
2646
  async function writeJsonAtomically(path, value, mode) {
2691
2647
  const temporaryPath = `${path}.${randomUUID2()}.tmp`;
@@ -2713,7 +2669,7 @@ async function writeJsonAtomically(path, value, mode) {
2713
2669
  import { execFile } from "child_process";
2714
2670
  import { randomUUID as randomUUID3 } from "crypto";
2715
2671
  import { chmod as chmod2, lstat, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
2716
- import { dirname as dirname5, join as join4, relative } from "path";
2672
+ import { dirname as dirname6, join as join5, relative } from "path";
2717
2673
  import { promisify } from "util";
2718
2674
  import { z as z32 } from "zod";
2719
2675
  var localSetupInstallationSchema = z32.object({
@@ -2738,7 +2694,7 @@ var localSetupCredentialsSchema = z32.union([
2738
2694
  z32.object({ installation: localSetupInstallationSchema }).strict()
2739
2695
  ]);
2740
2696
  async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
2741
- const path = join4(projectDir, ".siteplane/credentials.json");
2697
+ const path = join5(projectDir, ".siteplane/credentials.json");
2742
2698
  await assertCredentialFilesystemSafe(projectDir);
2743
2699
  const isTrackedFile = options.isTrackedFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "ls-files"));
2744
2700
  const isIgnoredFile = options.isIgnoredFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "check-ignore"));
@@ -2753,8 +2709,8 @@ async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
2753
2709
  async function assertCredentialFilesystemSafe(projectDir) {
2754
2710
  for (const [path, directory, mode] of [
2755
2711
  [projectDir, true, null],
2756
- [join4(projectDir, ".siteplane"), true, 448],
2757
- [join4(projectDir, ".siteplane/credentials.json"), false, 384]
2712
+ [join5(projectDir, ".siteplane"), true, 448],
2713
+ [join5(projectDir, ".siteplane/credentials.json"), false, 384]
2758
2714
  ]) {
2759
2715
  const stat = await lstat(path).catch((error) => {
2760
2716
  if (error.code === "ENOENT")
@@ -2777,7 +2733,7 @@ async function writeLocalCredentials(projectDir, credentials, options = {}) {
2777
2733
  async function writeLocalSetupCredentials(projectDir, credentials, options = {}) {
2778
2734
  const path = await assertLocalCredentialsPathSafe(projectDir, options);
2779
2735
  const parsed = localSetupCredentialsSchema.parse(credentials);
2780
- await mkdir5(dirname5(path), { recursive: true, mode: 448 });
2736
+ await mkdir5(dirname6(path), { recursive: true, mode: 448 });
2781
2737
  await writeCredentialsAtomically(path, parsed);
2782
2738
  return path;
2783
2739
  }
@@ -2790,7 +2746,7 @@ async function readLocalCredentials(projectDir) {
2790
2746
  }
2791
2747
  async function readLocalSetupCredentials(projectDir) {
2792
2748
  await assertCredentialFilesystemSafe(projectDir);
2793
- return localSetupCredentialsSchema.parse(JSON.parse(await readFile6(join4(projectDir, ".siteplane/credentials.json"), "utf8")));
2749
+ return localSetupCredentialsSchema.parse(JSON.parse(await readFile6(join5(projectDir, ".siteplane/credentials.json"), "utf8")));
2794
2750
  }
2795
2751
  async function writeCredentialsAtomically(path, credentials) {
2796
2752
  const temporaryPath = `${path}.${randomUUID3()}.tmp`;
@@ -2808,7 +2764,7 @@ async function writeCredentialsAtomically(path, credentials) {
2808
2764
  try {
2809
2765
  await rename2(temporaryPath, path);
2810
2766
  await chmod2(path, 384);
2811
- const directory = await open2(dirname5(path), "r");
2767
+ const directory = await open2(dirname6(path), "r");
2812
2768
  try {
2813
2769
  await directory.sync();
2814
2770
  } finally {
@@ -2831,8 +2787,8 @@ async function gitPathMatches(projectDir, path, command) {
2831
2787
  }
2832
2788
 
2833
2789
  // ../cli/dist/commands/init.js
2834
- import { access as access3 } from "fs/promises";
2835
- import { join as join7, relative as relative3 } from "path";
2790
+ import { access as access4 } from "fs/promises";
2791
+ import { join as join8, relative as relative3 } from "path";
2836
2792
  import { z as z35 } from "zod";
2837
2793
 
2838
2794
  // ../cli/dist/commands/setup-preflight.js
@@ -2844,7 +2800,7 @@ import { parse as parseYaml } from "yaml";
2844
2800
  // ../cli/dist/config/installed-package.js
2845
2801
  import { createRequire } from "module";
2846
2802
  import { readFile as readFile7 } from "fs/promises";
2847
- import { join as join5 } from "path";
2803
+ import { join as join6 } from "path";
2848
2804
  import { z as z33 } from "zod";
2849
2805
  var packageSchema = z33.object({
2850
2806
  name: z33.string().optional(),
@@ -2852,10 +2808,10 @@ var packageSchema = z33.object({
2852
2808
  peerDependencies: z33.record(z33.string(), z33.string()).optional()
2853
2809
  });
2854
2810
  async function readInstalledPackage(projectDir, name2) {
2855
- const require2 = createRequire(join5(projectDir, "package.json"));
2811
+ const require2 = createRequire(join6(projectDir, "package.json"));
2856
2812
  for (const directory of require2.resolve.paths(name2) ?? []) {
2857
2813
  try {
2858
- return packageSchema.parse(JSON.parse(await readFile7(join5(directory, name2, "package.json"), "utf8")));
2814
+ return packageSchema.parse(JSON.parse(await readFile7(join6(directory, name2, "package.json"), "utf8")));
2859
2815
  } catch (error) {
2860
2816
  if (error.code !== "ENOENT")
2861
2817
  throw error;
@@ -2865,8 +2821,8 @@ async function readInstalledPackage(projectDir, name2) {
2865
2821
  }
2866
2822
 
2867
2823
  // ../cli/dist/commands/setup-preflight.js
2868
- import { access as access2, readFile as readFile8, realpath, readdir, readlink } from "fs/promises";
2869
- import { dirname as dirname6, join as join6, relative as relative2, resolve, sep } from "path";
2824
+ import { access as access3, readFile as readFile8, realpath, readdir, readlink } from "fs/promises";
2825
+ import { dirname as dirname7, join as join7, relative as relative2, resolve, sep } from "path";
2870
2826
  import { z as z34 } from "zod";
2871
2827
 
2872
2828
  // ../cli/dist/commands/setup-process.js
@@ -2993,15 +2949,15 @@ var vercelProjectSchema = z34.object({
2993
2949
  productionBranch: z34.string().optional()
2994
2950
  }).nullable().optional()
2995
2951
  });
2996
- var exists = async (path) => access2(path).then(() => true, () => false);
2952
+ var exists = async (path) => access3(path).then(() => true, () => false);
2997
2953
  var fail = (code, message) => {
2998
2954
  throw new SetupFailure(code, message);
2999
2955
  };
3000
2956
  var stable = (version2, major) => new RegExp(`^${major}\\.\\d+\\.\\d+$`, "u").test(version2);
3001
2957
  async function inspectSetupLocalProject(projectDir) {
3002
2958
  const projectDirectory = await realpath(resolve(projectDir));
3003
- const manifest = manifestSchema.parse(JSON.parse(await readFile8(join6(projectDirectory, "package.json"), "utf8")));
3004
- const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(join6(projectDirectory, path)) ? path : null))).filter((path) => path !== null);
2959
+ const manifest = manifestSchema.parse(JSON.parse(await readFile8(join7(projectDirectory, "package.json"), "utf8")));
2960
+ const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(join7(projectDirectory, path)) ? path : null))).filter((path) => path !== null);
3005
2961
  if (apps.length !== 1)
3006
2962
  fail("ambiguous_app_directory", "Select one Next.js App Router application with exactly one app/ or src/app/ directory.");
3007
2963
  const repositoryRoot = (await setupProcess("git", ["rev-parse", "--show-toplevel"], {
@@ -3015,8 +2971,8 @@ async function inspectSetupLocalProject(projectDir) {
3015
2971
  fail("git_submodule_conflict", "The repository contains Git submodules. Resolve the explicit deployment source boundary before setup; the CLI will not copy external repositories.");
3016
2972
  if (!entry.startsWith("120000 "))
3017
2973
  continue;
3018
- const path = join6(repositoryRoot, entry.slice(entry.indexOf(" ") + 1));
3019
- const target = resolve(dirname6(path), await readlink(path));
2974
+ const path = join7(repositoryRoot, entry.slice(entry.indexOf(" ") + 1));
2975
+ const target = resolve(dirname7(path), await readlink(path));
3020
2976
  const bound = relative2(repositoryRoot, target);
3021
2977
  if (bound.startsWith("..") || bound.startsWith(sep))
3022
2978
  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.");
@@ -3032,10 +2988,10 @@ async function inspectSetupLocalProject(projectDir) {
3032
2988
  ];
3033
2989
  let locks = [];
3034
2990
  for (; ; ) {
3035
- locks = (await Promise.all(lockNames.map(async (name3) => await exists(join6(lockfileRoot, name3)) ? name3 : null))).filter((name3) => name3 !== null);
3036
- if (locks.length || lockfileRoot === repositoryRoot || dirname6(lockfileRoot) === lockfileRoot)
2991
+ locks = (await Promise.all(lockNames.map(async (name3) => await exists(join7(lockfileRoot, name3)) ? name3 : null))).filter((name3) => name3 !== null);
2992
+ if (locks.length || lockfileRoot === repositoryRoot || dirname7(lockfileRoot) === lockfileRoot)
3037
2993
  break;
3038
- lockfileRoot = dirname6(lockfileRoot);
2994
+ lockfileRoot = dirname7(lockfileRoot);
3039
2995
  }
3040
2996
  if (locks.length > 1)
3041
2997
  fail("conflicting_lockfiles", "Resolve conflicting package-manager lockfiles before setup; Siteplane does not replace them.");
@@ -3044,9 +3000,9 @@ async function inspectSetupLocalProject(projectDir) {
3044
3000
  const lockName = locks[0];
3045
3001
  if (!["package-lock.json", "pnpm-lock.yaml"].includes(lockName))
3046
3002
  fail("unsupported_package_manager", "This setup supports npm 10 or pnpm 9/10 with their canonical lockfile.");
3047
- const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(join6(lockfileRoot, "package.json"), "utf8")));
3003
+ const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(join7(lockfileRoot, "package.json"), "utf8")));
3048
3004
  if (lockfileRoot !== projectDirectory) {
3049
- const workspaceFile = join6(lockfileRoot, "pnpm-workspace.yaml");
3005
+ const workspaceFile = join7(lockfileRoot, "pnpm-workspace.yaml");
3050
3006
  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([
3051
3007
  z34.array(z34.string()),
3052
3008
  z34.object({ packages: z34.array(z34.string()) }).transform((value) => value.packages)
@@ -3055,14 +3011,14 @@ async function inspectSetupLocalProject(projectDir) {
3055
3011
  if (!workspace.some((pattern) => !pattern.startsWith("!") && minimatch(selected, pattern)) || workspace.some((pattern) => pattern.startsWith("!") && minimatch(selected, pattern.slice(1))))
3056
3012
  fail("unbound_workspace_app", "The selected application is excluded from the canonical lockfile's workspace packages. Select its actual application root.");
3057
3013
  }
3058
- for (let ancestor = dirname6(lockfileRoot); ancestor.startsWith(repositoryRoot + sep) || ancestor === repositoryRoot; ancestor = dirname6(ancestor)) {
3059
- const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(join6(ancestor, name3))));
3014
+ for (let ancestor = dirname7(lockfileRoot); ancestor.startsWith(repositoryRoot + sep) || ancestor === repositoryRoot; ancestor = dirname7(ancestor)) {
3015
+ const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(join7(ancestor, name3))));
3060
3016
  if (ancestorLocks.some(Boolean))
3061
3017
  fail("ambiguous_lockfile_root", "Both the selected package and its repository ancestors contain lockfiles. Select one canonical workspace resolution before setup.");
3062
3018
  if (ancestor === repositoryRoot)
3063
3019
  break;
3064
3020
  }
3065
- const lockText = await readFile8(join6(lockfileRoot, lockName), "utf8");
3021
+ const lockText = await readFile8(join7(lockfileRoot, lockName), "utf8");
3066
3022
  const npmLock = lockName === "package-lock.json" ? z34.object({
3067
3023
  lockfileVersion: z34.number(),
3068
3024
  packages: z34.record(z34.string(), z34.object({
@@ -3115,9 +3071,9 @@ async function inspectSetupLocalProject(projectDir) {
3115
3071
  fail("lockfile_format_conflict", "The canonical lockfile format does not match npm 10 or pnpm 9/10.");
3116
3072
  const sourceConflicts = [];
3117
3073
  for (const file of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
3118
- if (!await exists(join6(projectDirectory, file)))
3074
+ if (!await exists(join7(projectDirectory, file)))
3119
3075
  continue;
3120
- const source = await readFile8(join6(projectDirectory, file), "utf8");
3076
+ const source = await readFile8(join7(projectDirectory, file), "utf8");
3121
3077
  if (/output\s*:\s*['"]export['"]/u.test(source))
3122
3078
  sourceConflicts.push("static_export");
3123
3079
  if (/\bbasePath\s*:/u.test(source))
@@ -3137,11 +3093,11 @@ async function inspectSetupLocalProject(projectDir) {
3137
3093
  "src/proxy.ts",
3138
3094
  "src/proxy.js"
3139
3095
  ]) {
3140
- if (await exists(join6(projectDirectory, name3))) {
3096
+ if (await exists(join7(projectDirectory, name3))) {
3141
3097
  sourceConflicts.push(`inspect_routing:${name3}`);
3142
- if (await readlink(join6(projectDirectory, name3)).catch(() => null))
3098
+ if (await readlink(join7(projectDirectory, name3)).catch(() => null))
3143
3099
  continue;
3144
- const policySource = await readFile8(join6(projectDirectory, name3), "utf8");
3100
+ const policySource = await readFile8(join7(projectDirectory, name3), "utf8");
3145
3101
  if (/Content-Security-Policy|img-src|default-src/iu.test(policySource))
3146
3102
  sourceConflicts.push(`inspect_image_csp:${name3}`);
3147
3103
  }
@@ -3150,7 +3106,7 @@ async function inspectSetupLocalProject(projectDir) {
3150
3106
  for (const entry of await readdir(directory, { withFileTypes: true })) {
3151
3107
  if (entry.isSymbolicLink() || ["node_modules", ".git", ".next", ".siteplane", ".vercel"].includes(entry.name))
3152
3108
  continue;
3153
- const path = join6(directory, entry.name);
3109
+ const path = join7(directory, entry.name);
3154
3110
  if (entry.isDirectory()) {
3155
3111
  await inspectSource(path);
3156
3112
  continue;
@@ -3170,7 +3126,7 @@ async function inspectSetupLocalProject(projectDir) {
3170
3126
  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.`);
3171
3127
  }
3172
3128
  }
3173
- await inspectSource(join6(projectDirectory, apps[0]));
3129
+ await inspectSource(join7(projectDirectory, apps[0]));
3174
3130
  const gitRead = async (args) => setupProcess("git", args, { cwd: projectDirectory }).then((value) => value.trim(), () => null);
3175
3131
  return {
3176
3132
  projectDirectory,
@@ -3182,7 +3138,7 @@ async function inspectSetupLocalProject(projectDir) {
3182
3138
  nodeVersion: process.versions.node,
3183
3139
  packageManager: { name: name2, version: localVersion, declared },
3184
3140
  lockfile: {
3185
- path: relative2(repositoryRoot, join6(lockfileRoot, lockName)),
3141
+ path: relative2(repositoryRoot, join7(lockfileRoot, lockName)),
3186
3142
  format,
3187
3143
  sha256: createHash2("sha256").update(lockText).digest("hex")
3188
3144
  },
@@ -3201,14 +3157,14 @@ async function setupPreflightCommand(input) {
3201
3157
  local = await inspectSetupLocalProject(input.projectDir);
3202
3158
  await assertLocalCredentialsPathSafe(input.projectDir);
3203
3159
  let linkDirectory = local.projectDirectory;
3204
- while (!await exists(join6(linkDirectory, ".vercel/project.json")) && linkDirectory !== local.repositoryRoot && dirname6(linkDirectory) !== linkDirectory)
3205
- linkDirectory = dirname6(linkDirectory);
3206
- if (!await exists(join6(linkDirectory, ".vercel/project.json")))
3160
+ while (!await exists(join7(linkDirectory, ".vercel/project.json")) && linkDirectory !== local.repositoryRoot && dirname7(linkDirectory) !== linkDirectory)
3161
+ linkDirectory = dirname7(linkDirectory);
3162
+ if (!await exists(join7(linkDirectory, ".vercel/project.json")))
3207
3163
  fail("vercel_project_not_linked", "Link this application to its intended Vercel project before setup; Siteplane will not guess a target.");
3208
3164
  const linked = z34.object({
3209
3165
  projectId: z34.string().regex(/^prj_[A-Za-z0-9]+$/u),
3210
3166
  orgId: z34.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u)
3211
- }).parse(JSON.parse(await readFile8(join6(linkDirectory, ".vercel/project.json"), "utf8")));
3167
+ }).parse(JSON.parse(await readFile8(join7(linkDirectory, ".vercel/project.json"), "utf8")));
3212
3168
  const project = vercelProjectSchema.parse(await setupVercelApi(linkDirectory, `/v9/projects/${linked.projectId}?teamId=${linked.orgId}`));
3213
3169
  if (project.id !== linked.projectId || project.accountId !== linked.orgId)
3214
3170
  fail("vercel_identity_conflict", "The provider project does not match the locally linked project and team.");
@@ -3346,7 +3302,7 @@ var bootstrapResponseSchema = z35.object({
3346
3302
  }).strict();
3347
3303
  async function bootstrapProjectConnection(input) {
3348
3304
  const fetcher = input.fetcher ?? fetch;
3349
- const existing = await access3(join7(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3305
+ const existing = await access4(join8(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3350
3306
  const response = await fetcher(`${input.apiBaseUrl.replace(/\/$/, "")}/api/cli/setup/bootstrap`, {
3351
3307
  method: "POST",
3352
3308
  signal: AbortSignal.timeout(2e4),
@@ -3377,10 +3333,10 @@ async function acknowledgeBootstrapResponse(input) {
3377
3333
  }
3378
3334
  }
3379
3335
  async function persistSiteSetupBootstrap(input, bootstrap, appDirectory, installation) {
3380
- const previous = await access3(join7(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3336
+ const previous = await access4(join8(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3381
3337
  if (previous && (previous.siteId !== bootstrap.siteId || previous.runId !== bootstrap.runId || previous.publicSiteKeyId !== bootstrap.publicSiteKeyId || previous.publicSiteKey !== bootstrap.publicSiteKey))
3382
3338
  throw new Error("The grant does not match this local Siteplane run. Preserve this directory and choose the correct owner connection.");
3383
- const previousCredentials = previous ? await access3(join7(input.projectDir, ".siteplane/credentials.json")).then(() => readLocalSetupCredentials(input.projectDir), () => null) : null;
3339
+ const previousCredentials = previous ? await access4(join8(input.projectDir, ".siteplane/credentials.json")).then(() => readLocalSetupCredentials(input.projectDir), () => null) : null;
3384
3340
  const credentialsPath = await writeLocalCredentials(input.projectDir, {
3385
3341
  ...previousCredentials && "adminSession" in previousCredentials && previousCredentials.adminSession ? { adminSession: previousCredentials.adminSession } : {},
3386
3342
  ...previousCredentials && "claimReceipt" in previousCredentials && previousCredentials.claimReceipt ? { claimReceipt: previousCredentials.claimReceipt } : {},
@@ -3433,7 +3389,7 @@ async function persistFeatureBootstrap(input, bootstrap) {
3433
3389
  throw new Error("Siteplane credentials could not be verified.");
3434
3390
  }
3435
3391
  return {
3436
- configPath: join7(input.projectDir, "siteplane.config.json"),
3392
+ configPath: join8(input.projectDir, "siteplane.config.json"),
3437
3393
  credentialsPath
3438
3394
  };
3439
3395
  }
@@ -3456,7 +3412,7 @@ function readErrorMessage(payload) {
3456
3412
 
3457
3413
  // ../cli/dist/commands/scan.js
3458
3414
  import { readdir as readdir2 } from "fs/promises";
3459
- import { extname, join as join8 } from "path";
3415
+ import { extname, join as join9 } from "path";
3460
3416
  var defaultScanRoots = ["app", "src", "pages", "components", "lib"];
3461
3417
  var excludedDirectories = /* @__PURE__ */ new Set([
3462
3418
  ".git",
@@ -3474,14 +3430,14 @@ async function resolveScanFilePaths(filePaths, options = {}) {
3474
3430
  return filePaths;
3475
3431
  }
3476
3432
  const projectDir = options.projectDir ?? process.cwd();
3477
- const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join8(projectDir, root))));
3433
+ const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join9(projectDir, root))));
3478
3434
  return [...new Set(discovered.flat())].sort();
3479
3435
  }
3480
3436
  async function collectSourceFiles(directory) {
3481
3437
  const entries = await readdir2(directory, { withFileTypes: true }).catch(() => []);
3482
3438
  const files = [];
3483
3439
  for (const entry of entries) {
3484
- const entryPath = join8(directory, entry.name);
3440
+ const entryPath = join9(directory, entry.name);
3485
3441
  if (entry.isDirectory()) {
3486
3442
  if (!excludedDirectories.has(entry.name)) {
3487
3443
  files.push(...await collectSourceFiles(entryPath));
@@ -3502,7 +3458,7 @@ import { promisify as promisify2 } from "util";
3502
3458
  import { z as z36 } from "zod";
3503
3459
 
3504
3460
  // ../cli/dist/scan/next-source-scan.js
3505
- import ts2 from "typescript";
3461
+ import ts3 from "typescript";
3506
3462
  import { isAbsolute, relative as relative4 } from "path";
3507
3463
  var legacyEditableComponentPrefix = "Editable";
3508
3464
  var editableComponentNames = new Set(["Image", "Text", "LongText", "Link"].map((name2) => `${legacyEditableComponentPrefix}${name2}`));
@@ -3629,8 +3585,8 @@ async function readGitRevision(projectDir) {
3629
3585
 
3630
3586
  // ../cli/dist/commands/setup-start.js
3631
3587
  import { randomBytes, randomUUID as randomUUID4 } from "crypto";
3632
- import { access as access4 } from "fs/promises";
3633
- import { join as join9, relative as relative5 } from "path";
3588
+ import { access as access5 } from "fs/promises";
3589
+ import { join as join10, relative as relative5 } from "path";
3634
3590
  import { z as z37 } from "zod";
3635
3591
  var bootstrapResponseSchema2 = z37.object({
3636
3592
  ok: z37.literal(true),
@@ -3648,10 +3604,10 @@ var responseSchema2 = z38.object({
3648
3604
  }).strict();
3649
3605
 
3650
3606
  // ../cli/dist/commands/setup-prepare.js
3651
- import { access as access5, lstat as lstat2, mkdir as mkdir6, open as open3, readFile as readFile10, rename as rename3, rm as rm3 } from "fs/promises";
3607
+ 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";
3652
3608
  import { randomUUID as randomUUID5 } from "crypto";
3653
- import { dirname as dirname7, join as join10, relative as relative6, sep as sep2 } from "path";
3654
- import ts3 from "typescript";
3609
+ import { dirname as dirname8, join as join11, relative as relative6, sep as sep2 } from "path";
3610
+ import ts4 from "typescript";
3655
3611
 
3656
3612
  // ../cli/dist/commands/setup-lock.js
3657
3613
  import { randomUUID as randomUUID6 } from "crypto";
@@ -3664,7 +3620,7 @@ var ownerSchema = z39.object({ pid: z39.number().int().positive(), nonce: z39.st
3664
3620
  import { createHash as createHash3 } from "crypto";
3665
3621
  import { execFile as execFile3 } from "child_process";
3666
3622
  import { lstat as lstat4, readFile as readFile12, writeFile as writeFile5, mkdir as mkdir8 } from "fs/promises";
3667
- import { dirname as dirname8, isAbsolute as isAbsolute2, join as join11, relative as relative7, resolve as resolve3, sep as sep3 } from "path";
3623
+ import { dirname as dirname9, isAbsolute as isAbsolute2, join as join12, relative as relative7, resolve as resolve3, sep as sep3 } from "path";
3668
3624
  import { isDeepStrictEqual, promisify as promisify3 } from "util";
3669
3625
  import { z as z40 } from "zod";
3670
3626
  var execute = promisify3(execFile3);
@@ -3704,15 +3660,15 @@ async function writeBuildProvenance(checkout, revision) {
3704
3660
  if (entry.mode !== "120000")
3705
3661
  continue;
3706
3662
  const { readlink: readlink2 } = await import("fs/promises");
3707
- const path = join11(checkout, entry.path);
3708
- const target2 = resolve3(dirname8(path), await readlink2(path));
3663
+ const path = join12(checkout, entry.path);
3664
+ const target2 = resolve3(dirname9(path), await readlink2(path));
3709
3665
  const bound = relative7(checkout, target2);
3710
3666
  if (bound.startsWith("..") || isAbsolute2(bound))
3711
3667
  throw new Error("A tracked symbolic link escapes the committed upload; resolve that source boundary before deployment.");
3712
3668
  }
3713
3669
  const providerConfigurations = await Promise.all(entries.filter((entry) => /(?:^|\/)vercel\.json$/u.test(entry.path)).map(async (entry) => ({
3714
3670
  path: entry.path,
3715
- source: await readFile12(join11(checkout, entry.path), "utf8")
3671
+ source: await readFile12(join12(checkout, entry.path), "utf8")
3716
3672
  })));
3717
3673
  const record = schema.parse({
3718
3674
  version: 2,
@@ -3721,16 +3677,16 @@ async function writeBuildProvenance(checkout, revision) {
3721
3677
  entries,
3722
3678
  providerConfigurations
3723
3679
  });
3724
- const target = join11(checkout, name);
3725
- await mkdir8(dirname8(target), { recursive: true, mode: 448 });
3680
+ const target = join12(checkout, name);
3681
+ await mkdir8(dirname9(target), { recursive: true, mode: 448 });
3726
3682
  await writeFile5(target, JSON.stringify(record), { flag: "wx", mode: 384 });
3727
3683
  }
3728
3684
 
3729
3685
  // ../cli/dist/commands/setup-deploy.js
3730
3686
  import { createHash as createHash4, randomBytes as randomBytes2, randomUUID as randomUUID7 } from "crypto";
3731
- import { access as access6, mkdir as mkdir9, mkdtemp, rm as rm5, writeFile as writeFile6 } from "fs/promises";
3687
+ import { access as access7, mkdir as mkdir9, mkdtemp, rm as rm5, writeFile as writeFile6 } from "fs/promises";
3732
3688
  import { tmpdir } from "os";
3733
- import { join as join12 } from "path";
3689
+ import { join as join13 } from "path";
3734
3690
  import { z as z41 } from "zod";
3735
3691
  var envSchema = z41.object({
3736
3692
  id: z41.string(),