siteplane 0.1.67 → 0.2.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3742 +1,138 @@
1
- // ../cli/dist/analytics/manifest.js
2
- import { mkdir, readFile, writeFile } from "fs/promises";
3
- import { dirname } from "path";
4
-
5
- // ../shared/dist/actors.js
6
- import { z } from "zod";
7
- var ACTOR_TYPES = ["workspace_member", "site_member", "agent", "setup_guest", "system"];
8
- var actorTypeSchema = z.enum(ACTOR_TYPES);
9
-
10
- // ../shared/dist/analytics-defaults.js
11
- var ANALYTICS_BATCH_LIMITS = {
12
- maxEventsPerRequest: 50,
13
- maxJsonBodyBytes: 64 * 1024,
14
- maxPropertiesJsonBytes: 8 * 1024
15
- };
16
- var ANALYTICS_RETENTION_DEFAULTS = {
17
- enabledRawEventRetentionDays: 30,
18
- higherTierRawEventRetentionDays: 90,
19
- maxRawEventRetentionDaysWithoutAdr: 180,
20
- diagnosticsRetentionDays: 30,
21
- rateLimitBucketRetentionDays: 2,
22
- lateEventWindowHours: 72
1
+ import {
2
+ loadSiteValues
3
+ } from "./chunk-YDCNEIOB.js";
4
+ import "./chunk-KZ3AQ6OA.js";
5
+
6
+ // src/index.ts
7
+ import { cache } from "react";
8
+
9
+ // ../shared/dist/field-values.js
10
+ var FIELD_VALUE_LIMITS = {
11
+ text: 256,
12
+ longText: 5e4,
13
+ linkLabel: 256,
14
+ linkHref: 2048,
15
+ imageSrc: 2048,
16
+ imageAlt: 300,
17
+ imageSize: 1e5
23
18
  };
24
-
25
- // ../shared/dist/analytics-booking.js
26
- import { z as z2 } from "zod";
27
- var bookingProviders = ["treatwell", "beautinda", "other"];
28
- var bookingAttributionModes = [
29
- "outbound_click_and_utm",
30
- "provider_redirect",
31
- "provider_reported",
32
- "manual_import",
33
- "verified_webhook"
34
- ];
35
- var bookingSignalSources = [
36
- "outbound_click",
37
- "provider_redirect",
38
- "provider_reported",
39
- "manual_import",
40
- "verified_webhook"
41
- ];
42
- var bookingAttributionConfidences = [
43
- "provider_redirect",
44
- "provider_reported",
45
- "manual_import",
46
- "verified_webhook"
47
- ];
48
- var bookingProviderSchema = z2.enum(bookingProviders);
49
- var bookingAttributionModeSchema = z2.enum(bookingAttributionModes);
50
- var bookingSignalSourceSchema = z2.enum(bookingSignalSources);
51
- var bookingAttributionConfidenceSchema = z2.enum(bookingAttributionConfidences);
52
- var bookingProviderHintSchema = z2.object({
53
- bookingProvider: bookingProviderSchema,
54
- bookingUrlHost: z2.string().min(1).max(253),
55
- bookingAttributionMode: bookingAttributionModeSchema,
56
- utmContent: z2.string().min(1).max(200).optional(),
57
- successCondition: z2.literal("redirect_status=succeeded").optional()
58
- }).superRefine((hint, context) => {
59
- if (hint.successCondition !== void 0 && hint.bookingAttributionMode !== "provider_redirect") {
60
- context.addIssue({
61
- code: "custom",
62
- message: "successCondition is allowed only for provider_redirect booking hints.",
63
- path: ["successCondition"]
64
- });
65
- }
66
- });
67
-
68
- // ../shared/dist/analytics-contract.js
69
- import { z as z3 } from "zod";
70
- var ANALYTICS_CONTRACT_VERSION = "analytics-contract.v1";
71
- var ANALYTICS_CONTRACT_HASH = "sha256:a91bddcc3c5e4196933b0335d03eaf41ff929cb736bdd694fe54d07ab52dada1";
72
- var ANALYTICS_IMPORT_SCHEMA_VERSION = "analytics-provider-import.v1";
73
- var analyticsImportTargetIdSchema = z3.string().min(1).max(120).regex(/^[a-zA-Z][a-zA-Z0-9]*(?:[._-][a-zA-Z0-9]+)*$/u);
74
- var analyticsProviderImportRowSchema = z3.object({
75
- targetId: analyticsImportTargetIdSchema,
76
- occurredAt: z3.string().datetime({ offset: true }),
77
- attributionConfidence: z3.enum(["provider_reported", "manual_import"]),
78
- providerEventId: z3.string().trim().min(1).max(160).optional(),
79
- idempotencyKey: z3.string().trim().min(1).max(160).optional()
80
- }).strict().superRefine((row, context) => {
81
- if (!row.providerEventId && !row.idempotencyKey) {
82
- context.addIssue({
83
- code: "custom",
84
- message: "Each import row requires providerEventId or idempotencyKey.",
85
- path: ["providerEventId"]
86
- });
87
- }
88
- });
89
- var analyticsProviderImportSchema = z3.object({
90
- schemaVersion: z3.literal(ANALYTICS_IMPORT_SCHEMA_VERSION),
91
- provider: z3.enum(["treatwell", "beautinda", "other"]),
92
- sourceName: z3.string().trim().min(1).max(160).optional(),
93
- rows: z3.array(analyticsProviderImportRowSchema).min(1).max(1e3)
94
- }).strict();
95
-
96
- // ../shared/dist/analytics-config.js
97
- import { z as z4 } from "zod";
98
- var ANALYTICS_CONFIG_LEASE_MS = 6e4;
99
- var analyticsMeasurementConfigSchema = z4.object({
100
- version: z4.literal(1),
101
- installationGeneration: z4.number().int().positive(),
102
- configRevision: z4.number().int().positive(),
103
- effectiveSiteMode: z4.enum(["disabled", "session_only", "full_analytics"]),
104
- measurementEnabled: z4.boolean(),
105
- issuedAt: z4.string().datetime({ offset: true }),
106
- expiresAt: z4.string().datetime({ offset: true })
107
- }).strict().superRefine((config, context) => {
108
- const lifetime = Date.parse(config.expiresAt) - Date.parse(config.issuedAt);
109
- if (lifetime <= 0 || lifetime > ANALYTICS_CONFIG_LEASE_MS) {
110
- context.addIssue({
111
- code: "custom",
112
- path: ["expiresAt"],
113
- message: "Measurement permission must expire within 60 seconds."
114
- });
115
- }
116
- if (config.measurementEnabled !== (config.effectiveSiteMode !== "disabled")) {
117
- context.addIssue({
118
- code: "custom",
119
- path: ["measurementEnabled"],
120
- message: "Measurement permission must match the effective site mode."
121
- });
19
+ var linkKeys = ["href", "label"];
20
+ var fallbackImageKeys = ["src", "alt", "width", "height"];
21
+ var contentImageKeys = ["assetId", "src", "alt", "width", "height"];
22
+ var asciiBlank = /^[ \t\n\v\f\r]*$/u;
23
+ var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
24
+ var webAddress = /^https?:\/\/[^/?#@]+(?:[/?#].*)?$/isu;
25
+ function fieldValueProblem(type, value, origin) {
26
+ switch (type) {
27
+ case "text":
28
+ case "longText":
29
+ if (typeof value !== "string")
30
+ return "not_text";
31
+ return codePoints(value) > FIELD_VALUE_LIMITS[type] ? "too_long" : null;
32
+ case "link":
33
+ return linkProblem(value);
34
+ case "image":
35
+ return imageProblem(value, origin);
36
+ }
37
+ }
38
+ function readFieldValue(type, value) {
39
+ const rendered = type === "link" ? pick(value, linkKeys) : type === "image" ? pick(value, fallbackImageKeys) : value;
40
+ return fieldValueProblem(type, rendered, "fallback") === null ? rendered : null;
41
+ }
42
+ function linkProblem(value) {
43
+ if (!isRecord(value))
44
+ return "not_object";
45
+ if (hasUnknownKey(value, linkKeys))
46
+ return "unknown_key";
47
+ if (!isHref(value.href))
48
+ return "href_invalid";
49
+ if (typeof value.label !== "string" || asciiBlank.test(value.label))
50
+ return "label_missing";
51
+ return codePoints(value.label) > FIELD_VALUE_LIMITS.linkLabel ? "label_too_long" : null;
52
+ }
53
+ function imageProblem(value, origin) {
54
+ if (!isRecord(value))
55
+ return "not_object";
56
+ if (hasUnknownKey(value, origin === "content" ? contentImageKeys : fallbackImageKeys))
57
+ return "unknown_key";
58
+ if (origin === "content" && (typeof value.assetId !== "string" || !uuidPattern.test(value.assetId))) {
59
+ return "asset_missing";
60
+ }
61
+ if (!isImageSource(value.src))
62
+ return "src_invalid";
63
+ if (typeof value.alt !== "string" || codePoints(value.alt) > FIELD_VALUE_LIMITS.imageAlt)
64
+ return "alt_invalid";
65
+ const sizeRequired = origin === "content";
66
+ for (const size of [value.width, value.height]) {
67
+ if (size === void 0 ? sizeRequired : !isImageSize(size))
68
+ return "size_invalid";
122
69
  }
123
- });
124
-
125
- // ../shared/dist/analytics-events.js
126
- import { z as z5 } from "zod";
127
- var ANALYTICS_SCHEMA_VERSION = "analytics.v1";
128
- var analyticsSessionIdSchema = z5.string().regex(/^cpa_s_[a-f0-9]{32}$/u);
129
- var analyticsVisitorIdSchema = z5.string().regex(/^cpa_v_[a-f0-9]{32}$/u);
130
- var analyticsPersistedIdentityHashSchema = z5.string().regex(/^[a-f0-9]{64}$/u);
131
- var analyticsEventNames = [
132
- "page_view",
133
- "section_view",
134
- "cta_click",
135
- "outbound_click",
136
- "email_click",
137
- "phone_click",
138
- "file_download",
139
- "form_start",
140
- "form_submit",
141
- "form_error",
142
- "lead_created",
143
- "checkout_started",
144
- "conversion",
145
- "checkout_completed",
146
- "payment_succeeded",
147
- "subscription_started",
148
- "purchase_completed",
149
- "trial_started"
150
- ];
151
- var serverOnlyAnalyticsEvents = [
152
- "checkout_completed",
153
- "payment_succeeded",
154
- "subscription_started",
155
- "purchase_completed",
156
- "trial_started"
157
- ];
158
- var analyticsEventSources = [
159
- "browser",
160
- "server",
161
- "test",
162
- "editor_preview",
163
- "system"
164
- ];
165
- var analyticsIngestionChannels = [
166
- "browser_collector",
167
- "server_sdk",
168
- "provider_endpoint",
169
- "provider_import",
170
- "test",
171
- "editor_preview",
172
- "system_job"
173
- ];
174
- var analyticsTargetTypes = [
175
- "cta",
176
- "form",
177
- "section",
178
- "file",
179
- "link",
180
- "conversion",
181
- "server_conversion"
182
- ];
183
- var analyticsDataAttributeEvents = [
184
- "cta_click",
185
- "outbound_click",
186
- "email_click",
187
- "phone_click",
188
- "file_download",
189
- "section_view",
190
- "checkout_started",
191
- "form"
192
- ];
193
- var analyticsDeviceTypes = [
194
- "desktop",
195
- "tablet",
196
- "mobile",
197
- "unknown"
198
- ];
199
- var analyticsBotClassifications = [
200
- "normal",
201
- "known_bot",
202
- "suspicious",
203
- "invalid"
204
- ];
205
- var analyticsValidityStatuses = [
206
- "accepted",
207
- "rejected",
208
- "ignored"
209
- ];
210
- var analyticsEventNameSchema = z5.enum(analyticsEventNames);
211
- var serverOnlyAnalyticsEventSchema = z5.enum(serverOnlyAnalyticsEvents);
212
- var analyticsEventSourceSchema = z5.enum(analyticsEventSources);
213
- var analyticsIngestionChannelSchema = z5.enum(analyticsIngestionChannels);
214
- var analyticsTargetTypeSchema = z5.enum(analyticsTargetTypes);
215
- var analyticsDataAttributeEventSchema = z5.enum(analyticsDataAttributeEvents);
216
- var analyticsDeviceTypeSchema = z5.enum(analyticsDeviceTypes);
217
- var analyticsBotClassificationSchema = z5.enum(analyticsBotClassifications);
218
- var analyticsValidityStatusSchema = z5.enum(analyticsValidityStatuses);
219
- var analyticsPropertiesSchema = z5.record(z5.string(), z5.unknown());
220
- var analyticsTimestampSchema = z5.string().datetime({ offset: true });
221
- var analyticsBrowserEventSchema = z5.object({
222
- eventId: z5.string().min(1).max(160),
223
- installationGeneration: z5.number().int().positive().optional(),
224
- measurementMode: z5.enum(["session_only", "full_analytics"]).optional(),
225
- eventName: analyticsEventNameSchema,
226
- eventSource: analyticsEventSourceSchema.optional().default("browser"),
227
- targetId: z5.string().min(1).max(160).optional(),
228
- targetType: analyticsTargetTypeSchema.optional(),
229
- visitorId: analyticsVisitorIdSchema.optional(),
230
- sessionId: analyticsSessionIdSchema,
231
- idempotencyKey: z5.string().min(1).max(240).optional(),
232
- occurredAt: analyticsTimestampSchema,
233
- pageUrl: z5.string().url().max(2048).optional(),
234
- pagePath: z5.string().min(1).max(1024).optional(),
235
- routeTemplate: z5.string().min(1).max(1024).optional(),
236
- referrer: z5.string().url().max(2048).optional(),
237
- utmSource: z5.string().min(1).max(200).optional(),
238
- utmMedium: z5.string().min(1).max(200).optional(),
239
- utmCampaign: z5.string().min(1).max(200).optional(),
240
- utmContent: z5.string().min(1).max(200).optional(),
241
- utmTerm: z5.string().min(1).max(200).optional(),
242
- deviceType: analyticsDeviceTypeSchema.optional(),
243
- browserName: z5.string().min(1).max(120).optional(),
244
- osName: z5.string().min(1).max(120).optional(),
245
- country: z5.string().min(1).max(80).optional(),
246
- region: z5.string().min(1).max(120).optional(),
247
- properties: analyticsPropertiesSchema.optional().default({})
248
- }).superRefine((event, context) => {
249
- if (isServerOnlyAnalyticsEvent(event.eventName)) {
250
- context.addIssue({
251
- code: "custom",
252
- message: "Browser analytics payloads cannot contain server-only events.",
253
- path: ["eventName"]
254
- });
255
- }
256
- if (event.eventSource === "server" || event.eventSource === "system") {
257
- context.addIssue({
258
- code: "custom",
259
- message: "Browser analytics payloads cannot use server/system sources.",
260
- path: ["eventSource"]
261
- });
262
- }
263
- if (event.targetType === "server_conversion") {
264
- context.addIssue({
265
- code: "custom",
266
- message: "Browser analytics payloads cannot use server conversion targets.",
267
- path: ["targetType"]
268
- });
269
- }
270
- });
271
- var analyticsBrowserEventPayloadSchema = z5.object({
272
- siteKey: z5.string().min(1),
273
- schemaVersion: z5.literal(ANALYTICS_SCHEMA_VERSION),
274
- mode: z5.enum(["live", "test"]).optional().default("live"),
275
- events: z5.array(analyticsBrowserEventSchema).min(1).max(50)
276
- });
277
- var analyticsNormalizedEventBaseSchema = z5.object({
278
- site_id: z5.string().uuid(),
279
- event_id: z5.string().min(1).max(160),
280
- schema_version: z5.literal(ANALYTICS_SCHEMA_VERSION),
281
- event_name: analyticsEventNameSchema,
282
- event_source: analyticsEventSourceSchema,
283
- ingestion_channel: analyticsIngestionChannelSchema,
284
- target_id: z5.string().min(1).max(160).nullable().optional(),
285
- target_type: analyticsTargetTypeSchema.nullable().optional(),
286
- dedupe_key: z5.string().regex(/^analytics_dedupe_v1_[a-f0-9]{64}$/u).nullable().optional(),
287
- idempotency_key: z5.string().min(1).max(240).nullable().optional(),
288
- bot_classification: analyticsBotClassificationSchema,
289
- validity_status: analyticsValidityStatusSchema,
290
- rejection_reason: z5.string().min(1).max(240).nullable().optional(),
291
- occurred_at: analyticsTimestampSchema,
292
- received_at: analyticsTimestampSchema,
293
- page_url: z5.string().url().max(2048).nullable().optional(),
294
- page_path: z5.string().min(1).max(1024).nullable().optional(),
295
- route_template: z5.string().min(1).max(1024).nullable().optional(),
296
- referrer: z5.string().url().max(2048).nullable().optional(),
297
- utm_source: z5.string().min(1).max(200).nullable().optional(),
298
- utm_medium: z5.string().min(1).max(200).nullable().optional(),
299
- utm_campaign: z5.string().min(1).max(200).nullable().optional(),
300
- utm_content: z5.string().min(1).max(200).nullable().optional(),
301
- utm_term: z5.string().min(1).max(200).nullable().optional(),
302
- country: z5.string().min(1).max(80).nullable().optional(),
303
- region: z5.string().min(1).max(120).nullable().optional(),
304
- device_type: analyticsDeviceTypeSchema,
305
- browser_name: z5.string().min(1).max(120).nullable().optional(),
306
- os_name: z5.string().min(1).max(120).nullable().optional(),
307
- provider: z5.string().min(1).max(120).nullable().optional(),
308
- provider_event_id: z5.string().min(1).max(240).nullable().optional(),
309
- properties: analyticsPropertiesSchema
310
- });
311
- var analyticsRawNormalizedEventSchema = analyticsNormalizedEventBaseSchema.extend({
312
- visitor_id: analyticsVisitorIdSchema.nullable().optional(),
313
- session_id: analyticsSessionIdSchema.nullable().optional()
314
- });
315
- var analyticsNormalizedEventSchema = analyticsNormalizedEventBaseSchema.extend({
316
- visitor_id: analyticsPersistedIdentityHashSchema.nullable().optional(),
317
- session_id: analyticsPersistedIdentityHashSchema.nullable().optional()
318
- });
319
- function isServerOnlyAnalyticsEvent(eventName) {
320
- return serverOnlyAnalyticsEvents.includes(eventName);
70
+ return null;
321
71
  }
322
-
323
- // ../shared/dist/analytics-manifest.js
324
- import { z as z6 } from "zod";
325
- var analyticsTargetIdSchema = z6.string().min(1).max(120).regex(/^[a-zA-Z][a-zA-Z0-9]*(?:[._-][a-zA-Z0-9]+)*$/u, {
326
- message: "Analytics target IDs must be stable identifiers without whitespace or visible copy."
327
- });
328
- var analyticsManifestRecordSchema = z6.record(z6.string(), z6.unknown());
329
- var analyticsFormPurposes = [
330
- "contact",
331
- "lead",
332
- "newsletter",
333
- "search",
334
- "login",
335
- "other"
336
- ];
337
- var analyticsFormPurposeSchema = z6.enum(analyticsFormPurposes);
338
- var analyticsManifestRouteSchema = z6.object({
339
- path: z6.string().min(1).max(1024),
340
- pageType: z6.string().min(1).max(120).optional(),
341
- label: z6.string().min(1).max(200).optional()
342
- }).passthrough();
343
- var analyticsManifestTargetSchema = z6.object({
344
- id: analyticsTargetIdSchema,
345
- type: analyticsTargetTypeSchema,
346
- event: analyticsEventNameSchema.optional(),
347
- events: z6.array(analyticsEventNameSchema).min(1).max(20).optional(),
348
- route: z6.string().min(1).max(1024).optional(),
349
- label: z6.string().min(1).max(200).optional(),
350
- description: z6.string().min(1).max(1e3).optional(),
351
- autoActive: z6.boolean().optional(),
352
- sourceHints: analyticsManifestRecordSchema.optional()
353
- }).passthrough().superRefine((target, context) => {
354
- if (target.event === void 0 && target.events === void 0) {
355
- context.addIssue({
356
- code: "custom",
357
- message: "Analytics targets require event or events.",
358
- path: ["event"]
359
- });
360
- }
361
- if (target.event !== void 0 && target.events !== void 0) {
362
- context.addIssue({
363
- code: "custom",
364
- message: "Analytics targets must use event or events, never both.",
365
- path: ["events"]
366
- });
367
- }
368
- if (target.type === "form" && !analyticsFormPurposeSchema.safeParse(target.sourceHints?.formPurpose).success) {
369
- context.addIssue({
370
- code: "custom",
371
- message: "Analytics form targets require a typed sourceHints.formPurpose.",
372
- path: ["sourceHints", "formPurpose"]
373
- });
374
- }
375
- });
376
- var analyticsManifestSchema = z6.object({
377
- schemaVersion: z6.literal(ANALYTICS_SCHEMA_VERSION),
378
- siteId: z6.string().min(1),
379
- siteKeyRef: z6.string().regex(/^env:[A-Z][A-Z0-9_]*$/u, {
380
- message: "siteKeyRef must be an environment-variable reference."
381
- }),
382
- siteKeyLookup: z6.string().regex(/^pk_siteplane_[A-Za-z0-9_-]{16}$/),
383
- routes: z6.array(analyticsManifestRouteSchema),
384
- targets: z6.array(analyticsManifestTargetSchema),
385
- metadata: analyticsManifestRecordSchema.optional(),
386
- siteKey: z6.string().optional(),
387
- secretKey: z6.string().optional(),
388
- rawKey: z6.string().optional(),
389
- token: z6.string().optional(),
390
- accessToken: z6.string().optional()
391
- }).passthrough().superRefine((manifest, context) => {
392
- const targetIds = /* @__PURE__ */ new Set();
393
- for (const [index, target] of manifest.targets.entries()) {
394
- if (targetIds.has(target.id)) {
395
- context.addIssue({
396
- code: "custom",
397
- message: `Duplicate analytics target ID: ${target.id}`,
398
- path: ["targets", index, "id"]
399
- });
400
- }
401
- targetIds.add(target.id);
402
- }
403
- for (const issue of findUnsafeSecretReferences(manifest)) {
404
- context.addIssue({
405
- code: "custom",
406
- message: "Raw secret material is not allowed in analytics manifests.",
407
- path: issue
408
- });
409
- }
410
- });
411
- var secretValuePattern = /(?:\bsk_(?:live|test)_|\bcpb_|\bpmt_(?:pc|setup|cli)_|\bservice_role\b|bearer\s+[a-z0-9._~-]+)/iu;
412
- function findUnsafeSecretReferences(value, path = []) {
413
- if (Array.isArray(value)) {
414
- return value.flatMap((item, index) => findUnsafeSecretReferences(item, [...path, index]));
415
- }
416
- if (!isPlainRecord(value)) {
417
- return [];
418
- }
419
- return Object.entries(value).flatMap(([key, childValue]) => {
420
- const childPath = [...path, key];
421
- const referenceLikeKey = /(?:ref|lookup|prefix)$/iu.test(key);
422
- const unsafeHere = referenceLikeKey && typeof childValue === "string" && secretValuePattern.test(childValue);
423
- return [
424
- ...unsafeHere ? [childPath] : [],
425
- ...findUnsafeSecretReferences(childValue, childPath)
426
- ];
427
- });
72
+ function isHref(value) {
73
+ if (!isAddressText(value, FIELD_VALUE_LIMITS.linkHref))
74
+ return false;
75
+ return isSitePath(value) || value.startsWith("#") || webAddress.test(value) || /^mailto:.+$/isu.test(value) || /^tel:\+?[0-9][0-9().-]*$/iu.test(value);
428
76
  }
429
- function isPlainRecord(value) {
430
- return typeof value === "object" && value !== null;
77
+ function isImageSource(value) {
78
+ return isAddressText(value, FIELD_VALUE_LIMITS.imageSrc) && (isSitePath(value) || webAddress.test(value));
431
79
  }
432
-
433
- // ../shared/dist/analytics-metrics.js
434
- import { z as z7 } from "zod";
435
- var analyticsVisitorQualities = ["exact", "estimated"];
436
- var analyticsVisitorQualitySchema = z7.enum(analyticsVisitorQualities);
437
- var analyticsKpiKeys = [
438
- "pageViews",
439
- "sessions",
440
- "visitors",
441
- "estimatedVisitors",
442
- "inquiries",
443
- "leads",
444
- "conversions",
445
- "conversionRate",
446
- "inquiryRate"
447
- ];
448
- var analyticsKpiKeySchema = z7.enum(analyticsKpiKeys);
449
-
450
- // ../shared/dist/analytics-privacy.js
451
- var serverPropertySchemas = {
452
- lead_created: {
453
- conversionId: "identifier",
454
- formId: "identifier",
455
- formType: "enum",
456
- customerRef: "identifier"
457
- },
458
- conversion: {
459
- conversionId: "identifier",
460
- conversionType: "enum",
461
- attributionConfidence: "enum",
462
- bookingSignalSource: "enum",
463
- bookingProvider: "enum",
464
- redirectStatus: "enum",
465
- importId: "identifier"
466
- },
467
- checkout_completed: revenuePropertySchema(),
468
- payment_succeeded: revenuePropertySchema(),
469
- subscription_started: revenuePropertySchema(),
470
- purchase_completed: revenuePropertySchema(),
471
- trial_started: revenuePropertySchema()
472
- };
473
- function revenuePropertySchema() {
474
- return {
475
- conversionId: "identifier",
476
- checkoutId: "identifier",
477
- customerRef: "identifier",
478
- amount: "amount",
479
- currency: "enum",
480
- planId: "identifier",
481
- productId: "identifier"
482
- };
80
+ function isSitePath(value) {
81
+ return value.startsWith("/") && !value.startsWith("//");
483
82
  }
484
-
485
- // ../shared/dist/assets.js
486
- import { z as z8 } from "zod";
487
- var ASSET_STAGES = ["staging", "final", "deleted"];
488
- var ASSET_VISIBILITIES = ["private", "public", "deleted"];
489
- var ASSET_USAGE_ENTITY_TYPES = [
490
- "branding",
491
- "draft",
492
- "change_set",
493
- "published_value"
494
- ];
495
- var assetStageSchema = z8.enum(ASSET_STAGES);
496
- var assetVisibilitySchema = z8.enum(ASSET_VISIBILITIES);
497
- var assetUsageEntityTypeSchema = z8.enum(ASSET_USAGE_ENTITY_TYPES);
498
- var brandingAccentColorSchema = z8.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/);
499
-
500
- // ../shared/dist/booking-contracts.js
501
- import { z as z9 } from "zod";
502
- var bookingStatuses = [
503
- "pending_payment",
504
- "confirmed",
505
- "payment_expired",
506
- "cancelled",
507
- "no_show"
508
- ];
509
- var bookingPaymentStatuses = [
510
- "payment_not_required",
511
- "checkout_open",
512
- "processing",
513
- "succeeded",
514
- "failed",
515
- "cancelled",
516
- "expired"
517
- ];
518
- var bookingAccountReadinessStatuses = [
519
- "not_started",
520
- "setup_required",
521
- "under_review",
522
- "payments_ready",
523
- "payouts_restricted",
524
- "payments_restricted",
525
- "deactivated"
526
- ];
527
- var bookingRefundStatuses = [
528
- "none",
529
- "pending",
530
- "partially_refunded",
531
- "refunded",
532
- "failed"
533
- ];
534
- var bookingDisputeStatuses = [
535
- "none",
536
- "needs_response",
537
- "under_review",
538
- "won",
539
- "lost"
540
- ];
541
- var bookingPaymentModes = [
542
- "onsite_only",
543
- "online_required",
544
- "customer_choice"
545
- ];
546
- var bookingPaymentCollectionTypes = [
547
- "full_amount",
548
- "deposit_percent"
549
- ];
550
- var bookingResourceKinds = [
551
- "person",
552
- "room",
553
- "equipment",
554
- "other"
555
- ];
556
- var bookingStatusSchema = z9.enum(bookingStatuses);
557
- var bookingPaymentStatusSchema = z9.enum(bookingPaymentStatuses);
558
- var bookingAccountReadinessStatusSchema = z9.enum(bookingAccountReadinessStatuses);
559
- var bookingRefundStatusSchema = z9.enum(bookingRefundStatuses);
560
- var bookingDisputeStatusSchema = z9.enum(bookingDisputeStatuses);
561
- var bookingPaymentModeSchema = z9.enum(bookingPaymentModes);
562
- var bookingPaymentCollectionTypeSchema = z9.enum(bookingPaymentCollectionTypes);
563
- var bookingPaymentCollectionSchema = z9.discriminatedUnion("type", [
564
- z9.object({ type: z9.literal("full_amount") }).strict(),
565
- z9.object({
566
- type: z9.literal("deposit_percent"),
567
- depositPercent: z9.number().int().min(10).max(90)
568
- }).strict()
569
- ]);
570
- var bookingPaymentChoices = ["onsite", "online"];
571
- var bookingPaymentChoiceSchema = z9.enum(bookingPaymentChoices);
572
- var bookingPaymentSnapshotSchema = z9.object({
573
- snapshotId: z9.string().uuid(),
574
- snapshotVersion: z9.number().int().positive(),
575
- currency: z9.literal("EUR"),
576
- totalAmountCents: z9.number().int().min(0),
577
- onlineAmountCents: z9.number().int().min(0),
578
- onsiteRemainderCents: z9.number().int().min(0),
579
- maxStripeRefundAmountCents: z9.number().int().min(0)
580
- }).strict().superRefine((snapshot, context) => {
581
- if (snapshot.onlineAmountCents + snapshot.onsiteRemainderCents !== snapshot.totalAmountCents) {
582
- context.addIssue({
583
- code: "custom",
584
- message: "Payment snapshot amounts must add up to the total amount."
585
- });
586
- }
587
- if (snapshot.maxStripeRefundAmountCents > snapshot.onlineAmountCents) {
588
- context.addIssue({
589
- code: "custom",
590
- message: "Stripe refund basis cannot exceed the online amount."
591
- });
592
- }
593
- });
594
- var bookingServiceVariantSchema = z9.object({
595
- id: z9.string().uuid(),
596
- name: z9.string().trim().min(1).max(120),
597
- durationMinutes: z9.number().int().min(1).max(1440),
598
- priceCents: z9.number().int().min(0).nullable()
599
- }).strict();
600
- var bookingServiceVariantsSchema = z9.array(bookingServiceVariantSchema).min(1).max(20);
601
- var isoDateSchema = z9.string().regex(/^\d{4}-\d{2}-\d{2}$/);
602
- var utcDateTimeSchema = z9.string().datetime();
603
- var bookingLocalTimeSchema = z9.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/);
604
- var bookingAvailabilityIntervalsSchema = z9.array(z9.object({
605
- start: bookingLocalTimeSchema,
606
- end: bookingLocalTimeSchema
607
- }).strict().refine((interval) => interval.end > interval.start)).superRefine((intervals, context) => {
608
- const sorted = [...intervals].sort((left, right) => left.start.localeCompare(right.start));
609
- for (let index = 1; index < sorted.length; index += 1) {
610
- if (sorted[index].start < sorted[index - 1].end) {
611
- context.addIssue({
612
- code: "custom",
613
- message: "Booking availability intervals must not overlap."
614
- });
615
- return;
616
- }
83
+ function isAddressText(value, maxLength) {
84
+ if (typeof value !== "string" || value.length === 0 || codePoints(value) > maxLength)
85
+ return false;
86
+ for (const character of value) {
87
+ const code = character.codePointAt(0);
88
+ if (code <= 32 || code === 127 || character === "\\")
89
+ return false;
617
90
  }
618
- });
619
- var bookingPublicConfigSchema = z9.object({
620
- site: z9.object({
621
- displayName: z9.string().trim().min(1),
622
- timezone: z9.string().trim().min(1),
623
- locale: z9.string().trim().min(2),
624
- bookingPageSlug: z9.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).min(2).max(64),
625
- privacyUrl: z9.string().url().nullable()
626
- }),
627
- branding: z9.object({
628
- logoUrl: z9.string().url().nullable(),
629
- accentColor: z9.string().trim().min(1).nullable()
630
- }),
631
- settings: z9.object({
632
- slotIntervalMinutes: z9.number().int().positive(),
633
- minLeadMinutes: z9.number().int().min(0),
634
- minCancelLeadMinutes: z9.number().int().min(0),
635
- maxAdvanceDays: z9.number().int().min(1),
636
- requirePhone: z9.boolean(),
637
- collectNote: z9.boolean(),
638
- confirmationMessage: z9.string().nullable()
639
- }),
640
- /** Freitexte des Salons, im Kassen-Schritt vor der Bestaetigung sichtbar. */
641
- policies: z9.object({
642
- cancellation: z9.string().nullable(),
643
- lateArrival: z9.string().nullable()
644
- }),
645
- payment: z9.object({
646
- mode: bookingPaymentModeSchema,
647
- collection: bookingPaymentCollectionSchema,
648
- onlinePaymentsReady: z9.boolean()
649
- }).strict(),
650
- serviceCategories: z9.array(z9.object({
651
- id: z9.string().uuid(),
652
- name: z9.string().trim().min(1),
653
- sortOrder: z9.number().int()
654
- })),
655
- serviceSubcategories: z9.array(z9.object({
656
- id: z9.string().uuid(),
657
- categoryId: z9.string().uuid(),
658
- name: z9.string().trim().min(1),
659
- sortOrder: z9.number().int()
660
- })),
661
- services: z9.array(z9.object({
662
- id: z9.string().trim().min(1),
663
- name: z9.string().trim().min(1),
664
- durationMinutes: z9.number().int().positive(),
665
- priceCents: z9.number().int().min(0).nullable(),
666
- currency: z9.string().regex(/^[A-Z]{3}$/),
667
- description: z9.string().nullable(),
668
- categoryId: z9.string().uuid(),
669
- subcategoryId: z9.string().uuid().nullable(),
670
- variants: bookingServiceVariantsSchema,
671
- allowsAnyResource: z9.boolean(),
672
- sortOrder: z9.number().int()
673
- })),
674
- resources: z9.array(z9.object({
675
- id: z9.string().trim().min(1),
676
- name: z9.string().trim().min(1),
677
- kind: z9.enum(bookingResourceKinds)
678
- })),
679
- serviceResources: z9.array(z9.object({
680
- serviceId: z9.string().trim().min(1),
681
- resourceId: z9.string().trim().min(1)
682
- }))
683
- });
684
- var bookingItemSchema = z9.object({
685
- serviceId: z9.string().trim().min(1),
686
- variantId: z9.string().trim().min(1)
687
- }).strict();
688
- var bookingItemsSchema = z9.array(bookingItemSchema).min(1).max(10);
689
- function parseBookingItemsParam(value) {
690
- const items = value.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "").map((entry) => {
691
- const [serviceId, variantId, ...rest] = entry.split(":");
692
- return serviceId && variantId && rest.length === 0 ? { serviceId, variantId } : null;
693
- });
694
- return items.every((item) => item !== null) ? items : null;
91
+ return true;
695
92
  }
696
- var bookingSlotsQuerySchema = z9.object({
697
- items: z9.preprocess((value) => typeof value === "string" ? parseBookingItemsParam(value) : value, bookingItemsSchema),
698
- resourceId: z9.string().trim().min(1).optional(),
699
- fromDate: isoDateSchema,
700
- toDate: isoDateSchema
701
- });
702
- var bookingSlotsResponseSchema = z9.object({
703
- timezone: z9.string().trim().min(1),
704
- items: bookingItemsSchema,
705
- // Reine Behandlungsdauer ohne Puffer: das UI zeigt damit die Terminspanne,
706
- // ohne selbst rechnen zu muessen.
707
- totalDurationMinutes: z9.number().int().min(1),
708
- mode: z9.enum(["any", "resource"]),
709
- slots: z9.array(z9.object({
710
- startUtc: utcDateTimeSchema,
711
- resourceId: z9.string().trim().min(1).optional()
712
- }))
713
- });
714
- var bookingAvailabilityQuerySchema = z9.object({
715
- items: z9.preprocess((value) => typeof value === "string" ? parseBookingItemsParam(value) : value, bookingItemsSchema),
716
- resourceId: z9.string().trim().min(1).optional(),
717
- fromDate: isoDateSchema,
718
- toDate: isoDateSchema
719
- });
720
- var bookingAvailabilityResponseSchema = z9.object({
721
- timezone: z9.string().trim().min(1),
722
- totalDurationMinutes: z9.number().int().min(1),
723
- days: z9.array(z9.object({
724
- date: isoDateSchema,
725
- hasSlots: z9.boolean()
726
- })),
727
- /** Erster Tag mit Slot ab `fromDate`, auch ausserhalb des Fensters. */
728
- nextAvailableDate: isoDateSchema.nullable()
729
- });
730
- var bookingPublicErrorCodes = [
731
- "slot_unavailable",
732
- "validation_error",
733
- "origin_not_allowed",
734
- "invalid_key",
735
- "rate_limited",
736
- "payment_required",
737
- "payment_unavailable",
738
- "payment_amount_too_small",
739
- "already_cancelled",
740
- "too_late",
741
- "not_found"
742
- ];
743
- var bookingPublicErrorSchema = z9.object({
744
- error: z9.enum(bookingPublicErrorCodes),
745
- message: z9.string().optional(),
746
- requestId: z9.string().optional()
747
- }).strict();
748
- var bookingCreateRequestSchema = z9.object({
749
- items: bookingItemsSchema,
750
- resourceId: z9.string().min(1).nullable(),
751
- startUtc: utcDateTimeSchema,
752
- customer: z9.object({
753
- name: z9.string().min(1).max(120),
754
- email: z9.string().email().max(254),
755
- phone: z9.string().max(32).optional(),
756
- note: z9.string().max(1e3).optional()
757
- }).strict(),
758
- hp: z9.string().optional(),
759
- clientToken: z9.string().uuid(),
760
- paymentChoice: bookingPaymentChoiceSchema,
761
- // Werbe-Einwilligung. Bestaetigung, Erinnerung und Storno-Link sind davon
762
- // unabhaengig und werden immer versendet.
763
- consent: z9.object({
764
- marketingEmail: z9.boolean(),
765
- marketingSms: z9.boolean()
766
- }).strict().optional()
767
- }).strict();
768
- var bookingPublicPaymentResponseSchema = z9.object({
769
- clientSecret: z9.string().min(1),
770
- stripeAccountId: z9.string().startsWith("acct_")
771
- }).strict();
772
- var bookingCreateResponseSchema = z9.union([
773
- z9.object({
774
- status: z9.literal("confirmed"),
775
- booking: z9.object({
776
- id: z9.string().min(1),
777
- startUtc: utcDateTimeSchema,
778
- endUtc: utcDateTimeSchema,
779
- timezone: z9.string().trim().min(1),
780
- serviceName: z9.string().trim().min(1),
781
- resourceName: z9.string().trim().min(1)
782
- }).strict(),
783
- manageUrl: z9.string().url(),
784
- confirmationMessage: z9.string().nullable()
785
- }).strict(),
786
- z9.object({
787
- status: z9.literal("pending_payment"),
788
- bookingId: z9.string().min(1),
789
- holdExpiresAt: utcDateTimeSchema,
790
- payment: bookingPublicPaymentResponseSchema,
791
- statusToken: z9.string().min(20),
792
- manageUrl: z9.string().url().optional()
793
- }).strict(),
794
- bookingPublicErrorSchema
795
- ]);
796
- var bookingStatusResponseSchema = z9.object({
797
- bookingStatus: bookingStatusSchema,
798
- paymentStatus: bookingPaymentStatusSchema,
799
- refundStatus: bookingRefundStatusSchema,
800
- disputeStatus: bookingDisputeStatusSchema,
801
- holdExpiresAt: utcDateTimeSchema.nullable()
802
- }).strict();
803
- var bookingCancelRequestSchema = z9.object({
804
- token: z9.string().min(20)
805
- });
806
- var bookingCancelResponseSchema = z9.union([
807
- z9.object({
808
- status: z9.enum(["cancelled", "already_cancelled", "too_late", "not_found"])
809
- }),
810
- bookingPublicErrorSchema
811
- ]);
812
- var bookingMoveErrorCodes = [
813
- "slot_unavailable",
814
- "booking_not_movable",
815
- "not_found"
816
- ];
817
- var bookingMoveRequestSchema = z9.object({
818
- bookingId: z9.string().uuid(),
819
- newStartUtc: utcDateTimeSchema,
820
- newResourceId: z9.string().uuid().optional(),
821
- notifyCustomer: z9.boolean().default(false),
822
- reason: z9.string().max(500).optional()
823
- });
824
- var bookingMoveResponseSchema = z9.union([
825
- z9.object({
826
- status: z9.literal("moved"),
827
- bookingId: z9.string().uuid(),
828
- startUtc: utcDateTimeSchema,
829
- endUtc: utcDateTimeSchema,
830
- resourceId: z9.string().uuid()
831
- }),
832
- z9.object({
833
- error: z9.enum(bookingMoveErrorCodes),
834
- message: z9.string().optional(),
835
- requestId: z9.string().optional()
836
- })
837
- ]);
838
- var bookingManifestSchema = z9.object({
839
- schemaVersion: z9.number().int().positive(),
840
- siteId: z9.string().trim().min(1),
841
- bookingPageSlug: z9.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).min(2).max(64),
842
- integration: z9.literal("rewrite").optional(),
843
- productionOrigin: z9.string().url().optional()
844
- }).passthrough();
845
- var secretManifestKeys = /* @__PURE__ */ new Set([
846
- "siteKey",
847
- "rawKey",
848
- "token",
849
- "accessToken"
850
- ]);
851
- function redactBookingManifest(value) {
852
- if (Array.isArray(value)) {
853
- return value.map((item) => redactBookingManifest(item));
854
- }
855
- if (value && typeof value === "object") {
856
- return Object.fromEntries(Object.entries(value).filter(([key]) => !secretManifestKeys.has(key)).map(([key, item]) => [key, redactBookingManifest(item)]));
857
- }
858
- return value;
93
+ function isImageSize(value) {
94
+ return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= FIELD_VALUE_LIMITS.imageSize;
859
95
  }
860
-
861
- // ../shared/dist/booking-defaults.js
862
- var BOOKING_CREATE_PAYLOAD_LIMIT_BYTES = 16 * 1024;
863
-
864
- // ../shared/dist/bridge-protocol.js
865
- import { z as z17 } from "zod";
866
-
867
- // ../shared/dist/field-id.js
868
- import { z as z10 } from "zod";
869
- var FIELD_ID_PATTERN = /^[a-z][a-z0-9_-]*(\.[a-z][a-z0-9_-]*)+$/;
870
- var fieldIdSchema = z10.string().regex(FIELD_ID_PATTERN, "Invalid field id");
871
-
872
- // ../shared/dist/field-types.js
873
- import { z as z11 } from "zod";
874
- var FIELD_TYPES = ["text", "longText", "image", "link"];
875
- var fieldTypeSchema = z11.enum(FIELD_TYPES);
876
-
877
- // ../shared/dist/image-value.js
878
- import { z as z12 } from "zod";
879
- var SUPPORTED_IMAGE_CONTENT_TYPES = [
880
- "image/jpeg",
881
- "image/png",
882
- "image/webp",
883
- "image/avif"
884
- ];
885
- var maxImageUploadBytes = 10 * 1024 * 1024;
886
- var largeImageWarningBytes = 2 * 1024 * 1024;
887
- var imageContentTypeSchema = z12.enum(SUPPORTED_IMAGE_CONTENT_TYPES);
888
- var imageCropSchema = z12.object({
889
- x: z12.number().min(0).max(100),
890
- y: z12.number().min(0).max(100),
891
- zoom: z12.number().min(1).max(4),
892
- aspectRatio: z12.number().positive().max(10)
893
- });
894
- var imageValueSchema = z12.object({
895
- src: z12.string().trim().min(1),
896
- alt: z12.string().trim().min(1).max(300),
897
- width: z12.number().int().positive().optional(),
898
- height: z12.number().int().positive().optional(),
899
- crop: imageCropSchema.optional(),
900
- assetId: z12.string().uuid().optional(),
901
- finalStorageProvider: z12.enum([
902
- "repo_static_assets",
903
- "repo_handoff",
904
- "site_owned_storage",
905
- "siteplane_managed_fallback"
906
- ]).optional()
907
- });
908
-
909
- // ../shared/dist/setup-deployment.js
910
- import { z as z13 } from "zod";
911
- var version = z13.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u);
912
- var siteSetupPackagesSchema = z13.object({
913
- siteplane: version,
914
- runtimeNext: version,
915
- analytics: version.optional()
916
- }).strict();
917
- var hash = z13.string().regex(/^sha256:[0-9a-f]{64}$/u);
918
- var setupDeploymentRecordSchema = z13.object({
919
- version: z13.literal(1),
920
- operationId: z13.string().uuid(),
921
- provider: z13.literal("vercel"),
922
- projectId: z13.string().regex(/^prj_[A-Za-z0-9]+$/u),
923
- teamId: z13.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u),
924
- origin: z13.string().url().refine((value) => {
925
- const url = new URL(value);
926
- return url.protocol === "https:" && url.origin === value && !url.username && !url.password;
927
- }),
928
- deploymentId: z13.string().regex(/^dpl_[A-Za-z0-9]+$/u).nullable(),
929
- revision: z13.string().regex(/^[0-9a-f]{40}$/u),
930
- fieldContractHash: hash,
931
- packages: siteSetupPackagesSchema,
932
- configurationFingerprint: hash,
933
- adminSecretGeneration: z13.string().uuid(),
934
- revalidationGeneration: z13.number().int().positive(),
935
- startedAt: z13.string().datetime(),
936
- environmentWrittenAt: z13.string().datetime().nullable(),
937
- deployRequestedAt: z13.string().datetime().nullable(),
938
- deadline: z13.string().datetime(),
939
- phase: z13.enum([
940
- "planned",
941
- "environment_written",
942
- "deploy_requested",
943
- "deployed",
944
- "verified",
945
- "failed"
946
- ]),
947
- build: z13.object({
948
- node: version,
949
- packageManager: z13.enum(["npm", "pnpm"]),
950
- packageManagerVersion: version,
951
- lockfileHash: hash
952
- }).strict().nullable()
953
- }).strict();
954
- var setupDeploymentInputSchema = z13.discriminatedUnion("action", [
955
- z13.object({ action: z13.literal("read") }).strict(),
956
- z13.object({
957
- action: z13.literal("record"),
958
- expectedOperationId: z13.string().uuid().nullable(),
959
- record: setupDeploymentRecordSchema
960
- }).strict()
961
- ]);
962
-
963
- // ../shared/dist/site-setup.js
964
- import { z as z16 } from "zod";
965
-
966
- // ../shared/dist/site-field-contract.js
967
- import { z as z15 } from "zod";
968
-
969
- // ../shared/dist/fallback-hash.js
970
- import { z as z14 } from "zod";
971
- var SAFE_REPRESENTATION_REASONS = [
972
- "asset_import_rewritten",
973
- "relative_url_normalized",
974
- "line_endings_normalized",
975
- "image_value_serialized"
976
- ];
977
- var safeRepresentationReasonSchema = z14.enum(SAFE_REPRESENTATION_REASONS);
978
- var linkFallbackSchema = z14.object({
979
- href: z14.string().trim().min(1),
980
- label: z14.string().trim().min(1).optional(),
981
- target: z14.enum(["_self", "_blank"]).optional()
982
- }).passthrough();
983
- function stableJsonStringify(value) {
984
- return JSON.stringify(sortObjectKeys(value));
96
+ function hasUnknownKey(value, keys) {
97
+ return Object.keys(value).some((key) => !keys.includes(key));
985
98
  }
986
- function sortObjectKeys(value) {
987
- if (Array.isArray(value)) {
988
- return value.map(sortObjectKeys);
989
- }
990
- if (!value || typeof value !== "object") {
99
+ function pick(value, keys) {
100
+ if (!isRecord(value))
991
101
  return value;
992
- }
993
- return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entryValue]) => [key, sortObjectKeys(entryValue)]));
994
- }
995
-
996
- // ../shared/dist/site-field-contract.js
997
- var siteFieldStatusSchema = z15.enum(["hidden", "active"]);
998
- var semanticVersionSchema = z15.string().regex(/^\d+\.\d+\.\d+$/u);
999
- var siteFieldRouteKeySchema = z15.string().trim().refine((value) => value === "$global" || value.startsWith("/") && !value.includes("?") && !value.includes("#") && (value === "/" || !value.endsWith("/")), "Route keys must be canonical paths or $global.");
1000
- var repositoryRelativePosixPathSchema = z15.string().trim().min(1).refine((value) => !value.startsWith("/") && !value.includes("\\") && !/^[a-z]:/iu.test(value) && !value.split("/").includes(".."), "Source paths must be repository-relative POSIX paths.");
1001
- var sourceMappingSchema = z15.object({
1002
- kind: z15.literal("function"),
1003
- filePath: repositoryRelativePosixPathSchema,
1004
- exportName: z15.string().trim().min(1).optional(),
1005
- sourcePath: z15.string().trim().min(1).optional(),
1006
- editTarget: fieldIdSchema.optional()
1007
- }).strict();
1008
- var domMappingSchema = z15.object({
1009
- attribute: z15.literal("data-siteplane-field-id"),
1010
- previewStrategy: z15.enum(["dom", "event"])
1011
- }).strict();
1012
- var fieldBaseSchema = z15.object({
1013
- fieldId: fieldIdSchema,
1014
- routeKey: siteFieldRouteKeySchema,
1015
- source: sourceMappingSchema,
1016
- dom: domMappingSchema.optional()
1017
- }).strict();
1018
- var linkFallbackSchema2 = z15.object({
1019
- href: z15.string().trim().min(1),
1020
- label: z15.string().trim().min(1).optional(),
1021
- target: z15.enum(["_self", "_blank"]).optional()
1022
- }).strict();
1023
- var imageFallbackSchema = z15.object({
1024
- src: z15.string().trim().min(1),
1025
- alt: z15.string().trim().max(300),
1026
- width: z15.number().int().positive().optional(),
1027
- height: z15.number().int().positive().optional(),
1028
- crop: z15.object({
1029
- x: z15.number().min(0).max(100),
1030
- y: z15.number().min(0).max(100),
1031
- zoom: z15.number().min(1).max(4),
1032
- aspectRatio: z15.number().positive().max(10)
1033
- }).strict().optional()
1034
- }).strict();
1035
- var siteFieldContractFieldSchema = z15.discriminatedUnion("fieldType", [
1036
- fieldBaseSchema.extend({
1037
- fieldType: z15.literal("text"),
1038
- fallback: z15.string()
1039
- }),
1040
- fieldBaseSchema.extend({
1041
- fieldType: z15.literal("longText"),
1042
- fallback: z15.string()
1043
- }),
1044
- fieldBaseSchema.extend({
1045
- fieldType: z15.literal("link"),
1046
- fallback: linkFallbackSchema2
1047
- }),
1048
- fieldBaseSchema.extend({
1049
- fieldType: z15.literal("image"),
1050
- fallback: imageFallbackSchema
1051
- })
1052
- ]);
1053
- var siteFieldContractV1Schema = z15.object({
1054
- version: z15.literal(1),
1055
- fieldContractVersion: semanticVersionSchema,
1056
- scannerContractVersion: semanticVersionSchema,
1057
- fields: z15.array(siteFieldContractFieldSchema)
1058
- }).strict().superRefine((contract, context) => {
1059
- const seen = /* @__PURE__ */ new Set();
1060
- for (const [index, field] of contract.fields.entries()) {
1061
- if (seen.has(field.fieldId)) {
1062
- context.addIssue({
1063
- code: "custom",
1064
- message: `Duplicate field id: ${field.fieldId}`,
1065
- path: ["fields", index, "fieldId"]
1066
- });
1067
- }
1068
- seen.add(field.fieldId);
1069
- }
1070
- });
1071
-
1072
- // ../shared/dist/site-setup.js
1073
- var SITE_SETUP_RUN_STATUSES = [
1074
- "waiting_for_agent",
1075
- "working",
1076
- "action_required",
1077
- "ready_for_review",
1078
- "completed"
1079
- ];
1080
- var SITE_SETUP_RUN_MODES = ["initial", "update"];
1081
- var SITE_SETUP_ERROR_CODES = [
1082
- "action_required",
1083
- "deployment_evidence_required",
1084
- "field_contract_scan_failed",
1085
- "invalid_editor_definition",
1086
- "invalid_field_contract",
1087
- "missing_build_revision",
1088
- "missing_field_contract",
1089
- "review_locked",
1090
- "stale_deployment_contract",
1091
- "stale_field_contract",
1092
- "stale_setup_review",
1093
- "update_required"
1094
- ];
1095
- var CONTINUE_SITE_SETUP_MAX_ITEMS = 50;
1096
- var CONTINUE_SITE_SETUP_RENDERED_PATH_MAX_BYTES = 512;
1097
- var CONTINUE_SITE_SETUP_VISIBLE_VALUE_MAX_BYTES = 256;
1098
- var CONTINUE_SITE_SETUP_LOCATOR_HINT_MAX_BYTES = 512;
1099
- var CONTINUE_SITE_SETUP_REQUESTED_LABEL_MAX_BYTES = 120;
1100
- var CONTINUE_SITE_SETUP_REQUESTED_SECTION_MAX_BYTES = 120;
1101
- var CONTINUE_SITE_SETUP_REQUESTED_SUBSECTION_MAX_BYTES = 120;
1102
- var SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH = 2e3;
1103
- var SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES = 8e3;
1104
- var CONTINUE_SITE_SETUP_ITEMS_MAX_BYTES = 32 * 1024;
1105
- var CONTINUE_SITE_SETUP_HTTP_BODY_MAX_BYTES = 64 * 1024;
1106
- var siteSetupRunStatusSchema = z16.enum(SITE_SETUP_RUN_STATUSES);
1107
- var siteSetupRunModeSchema = z16.enum(SITE_SETUP_RUN_MODES);
1108
- var siteSetupErrorCodeSchema = z16.enum(SITE_SETUP_ERROR_CODES);
1109
- var editorFieldSchema = z16.object({
1110
- fieldId: fieldIdSchema,
1111
- label: z16.string().trim().min(1),
1112
- subsection: z16.string().trim().min(1).optional(),
1113
- description: z16.string().trim().min(1).optional(),
1114
- required: z16.boolean().optional(),
1115
- maxLength: z16.number().int().positive().optional()
1116
- }).strict();
1117
- var editorSectionSchema = z16.object({
1118
- label: z16.string().trim().min(1),
1119
- fields: z16.array(editorFieldSchema).min(1)
1120
- }).strict().superRefine((section, context) => {
1121
- const closedSubsections = /* @__PURE__ */ new Set();
1122
- let currentSubsection;
1123
- for (const [index, field] of section.fields.entries()) {
1124
- if (field.subsection === currentSubsection)
1125
- continue;
1126
- if (currentSubsection)
1127
- closedSubsections.add(currentSubsection);
1128
- currentSubsection = field.subsection;
1129
- if (currentSubsection && closedSubsections.has(currentSubsection)) {
1130
- context.addIssue({
1131
- code: "custom",
1132
- message: `Subgroup fields must stay contiguous: ${currentSubsection}`,
1133
- path: ["fields", index, "subsection"]
1134
- });
1135
- }
1136
- }
1137
- });
1138
- var editorRouteSchema = z16.object({
1139
- routeKey: siteFieldRouteKeySchema,
1140
- previewPath: z16.string().trim().refine((path) => path.startsWith("/") && !path.startsWith("//") && !/[\\\[\]?#\s]/u.test(path) && (path === "/" || !path.endsWith("/")), "previewPath must be a concrete same-site path, for example /services/consultation.").optional(),
1141
- label: z16.string().trim().min(1),
1142
- sections: z16.array(editorSectionSchema).min(1)
1143
- }).strict().superRefine((route, context) => {
1144
- if (route.routeKey.includes("[") && !route.previewPath) {
1145
- context.addIssue({
1146
- code: "custom",
1147
- path: ["previewPath"],
1148
- message: "Dynamic editor routes need a previewPath for an existing page; keep the canonical routeKey unchanged."
1149
- });
1150
- }
1151
- const sections = /* @__PURE__ */ new Set();
1152
- for (const [index, section] of route.sections.entries()) {
1153
- if (sections.has(section.label)) {
1154
- context.addIssue({
1155
- code: "custom",
1156
- message: `Duplicate section label: ${section.label}`,
1157
- path: ["sections", index, "label"]
1158
- });
1159
- }
1160
- sections.add(section.label);
1161
- }
1162
- });
1163
- var editorDefinitionV1Schema = z16.object({
1164
- version: z16.literal(1),
1165
- routes: z16.array(editorRouteSchema).min(1)
1166
- }).strict().superRefine((definition, context) => {
1167
- const routes = /* @__PURE__ */ new Set();
1168
- const fields = /* @__PURE__ */ new Set();
1169
- for (const [routeIndex, route] of definition.routes.entries()) {
1170
- if (routes.has(route.routeKey)) {
1171
- context.addIssue({
1172
- code: "custom",
1173
- message: `Duplicate route key: ${route.routeKey}`,
1174
- path: ["routes", routeIndex, "routeKey"]
1175
- });
1176
- }
1177
- routes.add(route.routeKey);
1178
- for (const [sectionIndex, section] of route.sections.entries()) {
1179
- for (const [fieldIndex, field] of section.fields.entries()) {
1180
- if (fields.has(field.fieldId)) {
1181
- context.addIssue({
1182
- code: "custom",
1183
- message: `Duplicate editor field id: ${field.fieldId}`,
1184
- path: [
1185
- "routes",
1186
- routeIndex,
1187
- "sections",
1188
- sectionIndex,
1189
- "fields",
1190
- fieldIndex,
1191
- "fieldId"
1192
- ]
1193
- });
1194
- }
1195
- fields.add(field.fieldId);
1196
- }
1197
- }
1198
- }
1199
- });
1200
- var forbiddenControlOrBidi = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
1201
- var forbiddenOwnerNoteControlOrBidi = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
1202
- var unsafeLocator = /<\/?[a-z][^>]*>|\b(?:javascript|data:text\/html)\s*:|\bon[a-z]+\s*=/iu;
1203
- var renderedPathSchema = z16.string().trim().transform((value) => value !== "/" ? value.replace(/\/+$/u, "") : value).superRefine((value, context) => {
1204
- if (!value.startsWith("/") || value === "$global" || value.includes("?") || value.includes("#")) {
1205
- context.addIssue({
1206
- code: "custom",
1207
- message: "renderedPath must be a canonical real path."
1208
- });
1209
- }
1210
- addSafeByteIssues(value, CONTINUE_SITE_SETUP_RENDERED_PATH_MAX_BYTES, "renderedPath", context);
1211
- });
1212
- function normalizedSafeTextSchema(maxBytes, label) {
1213
- return z16.string().transform((value) => value.trim().replace(new RegExp("\\p{White_Space}+", "gu"), " ")).pipe(z16.string().min(1)).superRefine((value, context) => {
1214
- addSafeByteIssues(value, maxBytes, label, context);
1215
- if (label === "locatorHint" && unsafeLocator.test(value)) {
1216
- context.addIssue({
1217
- code: "custom",
1218
- message: "locatorHint contains unsafe markup or executable content."
1219
- });
1220
- }
1221
- });
1222
- }
1223
- var correctionItemBase = {
1224
- renderedPath: renderedPathSchema,
1225
- visibleValue: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_VISIBLE_VALUE_MAX_BYTES, "visibleValue"),
1226
- locatorHint: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_LOCATOR_HINT_MAX_BYTES, "locatorHint"),
1227
- requestedLabel: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_LABEL_MAX_BYTES, "requestedLabel").optional(),
1228
- requestedSection: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_SECTION_MAX_BYTES, "requestedSection").optional(),
1229
- requestedSubsection: normalizedSafeTextSchema(CONTINUE_SITE_SETUP_REQUESTED_SUBSECTION_MAX_BYTES, "requestedSubsection").optional(),
1230
- requestedSortOrder: z16.number().int().nonnegative().optional()
1231
- };
1232
- var setupCorrectionItemSchema = z16.discriminatedUnion("kind", [
1233
- z16.object({ kind: z16.literal("text"), ...correctionItemBase }).strict(),
1234
- z16.object({ kind: z16.literal("link"), ...correctionItemBase }).strict(),
1235
- z16.object({ kind: z16.literal("image"), ...correctionItemBase }).strict()
1236
- ]).superRefine((item, context) => {
1237
- if (item.requestedSubsection && !item.requestedSection) {
1238
- context.addIssue({
1239
- code: "custom",
1240
- message: "requestedSubsection requires requestedSection.",
1241
- path: ["requestedSubsection"]
1242
- });
1243
- }
1244
- });
1245
- var setupCorrectionItemsSchema = z16.array(setupCorrectionItemSchema).max(CONTINUE_SITE_SETUP_MAX_ITEMS).superRefine((items, context) => {
1246
- const bytes = utf8Bytes(stableJsonStringify(items));
1247
- if (bytes > CONTINUE_SITE_SETUP_ITEMS_MAX_BYTES) {
1248
- context.addIssue({
1249
- code: "custom",
1250
- message: "Correction items exceed the 32 KiB canonical payload limit."
1251
- });
1252
- }
1253
- });
1254
- var siteSetupOwnerEditabilityNoteSchema = z16.string().max(SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_LENGTH).superRefine((value, context) => {
1255
- if (utf8Bytes(value) > SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES) {
1256
- context.addIssue({
1257
- code: "custom",
1258
- message: `ownerEditabilityNote exceeds ${SITE_SETUP_OWNER_EDITABILITY_NOTE_MAX_BYTES} UTF-8 bytes.`
1259
- });
1260
- }
1261
- if (forbiddenOwnerNoteControlOrBidi.test(value)) {
1262
- context.addIssue({
1263
- code: "custom",
1264
- message: "ownerEditabilityNote contains a forbidden control or bidi character."
1265
- });
1266
- }
1267
- });
1268
- var SITE_SETUP_MODULE_SCOPES = {
1269
- editing: ["setup:read", "setup:write"],
1270
- analytics: [
1271
- "analytics:setup",
1272
- "analytics:sync",
1273
- "analytics:test",
1274
- "analytics:readiness",
1275
- "analytics:agent_instructions",
1276
- "analytics:public_key_read"
1277
- ]
1278
- };
1279
- var siteSetupModulesSchema = z16.array(z16.enum(["editing", "analytics"])).min(1).max(2).refine((modules) => modules[0] === "editing" && (modules.length === 1 || modules[1] === "analytics"), "Choose Editing with optional Analytics.");
1280
- function siteSetupScopes(modules) {
1281
- return modules.flatMap((module) => [...SITE_SETUP_MODULE_SCOPES[module]]);
1282
- }
1283
- function hasExactSiteSetupScopes(scopes, modules) {
1284
- const matches = (expected) => scopes.length === expected.length && expected.every((scope) => scopes.includes(scope));
1285
- return modules ? matches(siteSetupScopes(modules)) : matches(siteSetupScopes(["editing"])) || matches(siteSetupScopes(["editing", "analytics"]));
1286
- }
1287
- var siteSetupActivityInputSchema = z16.object({
1288
- phase: z16.enum([
1289
- "inspecting",
1290
- "integrating",
1291
- "deploying",
1292
- "verifying",
1293
- "repairing"
1294
- ]),
1295
- textId: z16.enum([
1296
- "inspecting",
1297
- "integrating",
1298
- "deploying",
1299
- "verifying",
1300
- "repairing"
1301
- ])
1302
- }).strict().refine((value) => value.phase === value.textId, "Activity text must describe its phase.");
1303
- var nextActionFields = {
1304
- actor: z16.enum(["agent", "user", "siteplane"]),
1305
- boundary: z16.enum([
1306
- "source",
1307
- "environment",
1308
- "deployment",
1309
- "verification",
1310
- "authorization",
1311
- "review"
1312
- ]),
1313
- precondition: z16.string().min(1).max(1e3),
1314
- instruction: z16.string().min(1).max(2e3),
1315
- expectedEvidence: z16.string().min(1).max(1e3)
1316
- };
1317
- var siteSetupNextActionSchema = z16.discriminatedUnion("kind", [
1318
- z16.object({
1319
- ...nextActionFields,
1320
- kind: z16.literal("run_command"),
1321
- command: z16.string().min(1).max(500)
1322
- }).strict(),
1323
- z16.object({ ...nextActionFields, kind: z16.literal("agent_edit") }).strict(),
1324
- z16.object({ ...nextActionFields, kind: z16.literal("needs_user_action") }).strict(),
1325
- z16.object({ ...nextActionFields, kind: z16.literal("wait") }).strict(),
1326
- z16.object({ ...nextActionFields, kind: z16.literal("done") }).strict()
1327
- ]);
1328
- var siteSetupTaskRunSchema = z16.object({
1329
- runId: z16.string().uuid(),
1330
- mode: siteSetupRunModeSchema,
1331
- status: siteSetupRunStatusSchema,
1332
- fieldContractHash: z16.string().nullable(),
1333
- deploymentOrigin: z16.string().url().nullable(),
1334
- deploymentRevision: z16.string().nullable(),
1335
- publicRuntimeKeyId: z16.string().uuid().nullable(),
1336
- reviewVersion: z16.number().int().positive()
1337
- }).strict();
1338
- var siteSetupTaskProgressSchema = z16.object({
1339
- progressStage: z16.enum([
1340
- "waiting_for_connection",
1341
- "agent_connected",
1342
- "project_context_loaded",
1343
- "fields_prepared",
1344
- "deployment_verification",
1345
- "ready_for_review",
1346
- "action_required",
1347
- "completed"
1348
- ]),
1349
- lastVerifiedAt: z16.string().datetime().nullable(),
1350
- lastActivityAt: z16.string().datetime(),
1351
- activitySource: z16.enum(["user", "server", "agent"]),
1352
- activityPhase: siteSetupActivityInputSchema.shape.phase.nullable(),
1353
- activityTextId: siteSetupActivityInputSchema.shape.textId.nullable()
1354
- }).strict();
1355
- var siteSetupTaskSchema = z16.object({
1356
- contractVersion: z16.literal("siteplane.setup-task.v2"),
1357
- workflow: z16.enum(["initial_setup", "structure_update"]),
1358
- goal: z16.string().min(1),
1359
- modules: siteSetupModulesSchema,
1360
- authorizationVersion: z16.number().int().positive(),
1361
- authorizedScopes: z16.array(z16.string()).min(2),
1362
- site: z16.object({
1363
- siteId: z16.string().uuid(),
1364
- portalPath: z16.string(),
1365
- adminOrigin: z16.string().url()
1366
- }).strict().nullable(),
1367
- run: siteSetupTaskRunSchema.nullable(),
1368
- progress: siteSetupTaskProgressSchema.nullable(),
1369
- deployment: setupDeploymentRecordSchema.nullable(),
1370
- revalidationGeneration: z16.number().int().positive(),
1371
- assignment: z16.enum(["owned", "provisional", "claimed"]),
1372
- deadline: z16.string().datetime().nullable(),
1373
- userInstructions: z16.object({
1374
- text: siteSetupOwnerEditabilityNoteSchema,
1375
- source: z16.literal("user"),
1376
- trust: z16.literal("untrusted")
1377
- }).strict(),
1378
- corrections: setupCorrectionItemsSchema,
1379
- contentSelectionSummary: z16.object({
1380
- text: siteSetupOwnerEditabilityNoteSchema,
1381
- source: z16.literal("agent"),
1382
- trust: z16.literal("untrusted")
1383
- }).strict().nullable(),
1384
- environmentBindings: z16.array(z16.object({
1385
- name: z16.string().regex(/^[A-Z][A-Z0-9_]+$/u),
1386
- source: z16.string().min(1),
1387
- sensitivity: z16.enum(["public", "secret"]),
1388
- usage: z16.enum(["build", "server", "build_and_server"]),
1389
- evidence: z16.string().min(1)
1390
- }).strict()),
1391
- nextAction: siteSetupNextActionSchema,
1392
- error: z16.object({
1393
- code: z16.string().regex(/^[a-z0-9_.]+$/u).max(160),
1394
- boundary: nextActionFields.boundary,
1395
- responsibleActor: nextActionFields.actor,
1396
- retryable: z16.boolean(),
1397
- retryAfter: z16.number().int().nonnegative().nullable(),
1398
- requestId: z16.string().regex(/^[A-Za-z0-9_-]+$/u).max(128)
1399
- }).strict().nullable(),
1400
- packages: siteSetupPackagesSchema,
1401
- communication: z16.object({
1402
- beforeSourceChanges: z16.string().min(1),
1403
- updates: z16.array(z16.string().min(1)).min(1),
1404
- blocker: z16.string().min(1)
1405
- }).strict(),
1406
- discovery: z16.object({
1407
- inspectPublicRoutes: z16.boolean(),
1408
- contentKinds: z16.array(z16.enum(["text", "longText", "link", "image"])).min(1),
1409
- rules: z16.array(z16.string().min(1)).min(1)
1410
- }).strict(),
1411
- steps: z16.array(z16.object({
1412
- id: z16.enum([
1413
- "inspect_repository",
1414
- "install_packages",
1415
- "instrument_fields",
1416
- "apply_contract",
1417
- "deploy_production",
1418
- "verify_deployment"
1419
- ]),
1420
- instruction: z16.string().min(1)
1421
- }).strict()).length(6),
1422
- completion: z16.object({
1423
- verifiedStatus: z16.literal("ready_for_review"),
1424
- instruction: z16.string().min(1)
1425
- }).strict()
1426
- }).strict().refine((task) => hasExactSiteSetupScopes(task.authorizedScopes, task.modules), "Task scopes must exactly match its modules.").refine((task) => task.modules.includes("analytics") === (task.packages.analytics !== void 0), "The Analytics package pin must be present exactly when Analytics is selected.");
1427
- var canonicalHashSchema = z16.string().regex(/^sha256:[0-9a-f]{64}$/iu);
1428
- var deploymentRevisionSchema = normalizedSafeTextSchema(256, "deploymentRevision");
1429
- var continueSiteSetupInputSchema = z16.object({
1430
- siteId: z16.string().uuid(),
1431
- runId: z16.string().uuid(),
1432
- expectedReviewVersion: z16.number().int().positive(),
1433
- mutationId: z16.string().uuid(),
1434
- intent: z16.enum(["continue_review", "correct_completed_review"]),
1435
- expectedFieldContractHash: canonicalHashSchema,
1436
- expectedDeploymentRevision: deploymentRevisionSchema,
1437
- correctionItems: setupCorrectionItemsSchema,
1438
- ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema.optional()
1439
- }).strict();
1440
- var saveSiteSetupOwnerNoteInputSchema = z16.object({
1441
- siteId: z16.string().uuid(),
1442
- runId: z16.string().uuid(),
1443
- expectedReviewVersion: z16.number().int().positive(),
1444
- expectedFieldContractHash: canonicalHashSchema,
1445
- expectedDeploymentRevision: deploymentRevisionSchema,
1446
- ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema
1447
- }).strict();
1448
- var setupReviewPreferenceSelectionSchema = z16.object({
1449
- analyticsMode: z16.enum(["disabled", "session_only"]).nullable(),
1450
- assetTargetType: z16.enum(["repo_static_assets", "siteplane_managed_fallback"]).nullable(),
1451
- assetTargetId: z16.string().uuid().nullable()
1452
- }).strict().refine((value) => value.assetTargetType !== null || value.assetTargetId === null, {
1453
- message: "An asset target requires its delivery type."
1454
- });
1455
- var setupReviewPreferencesSchema = setupReviewPreferenceSelectionSchema.safeExtend({
1456
- managedHostingApproved: z16.boolean()
1457
- });
1458
- var saveSetupReviewPreferencesInputSchema = z16.object({
1459
- siteId: z16.string().uuid(),
1460
- runId: z16.string().uuid(),
1461
- expectedReviewVersion: z16.number().int().positive(),
1462
- preferences: setupReviewPreferenceSelectionSchema
1463
- }).strict();
1464
- var siteSetupContextInputSchema = z16.object({}).strict();
1465
- var siteSetupApplyInputSchema = z16.object({
1466
- fieldContract: siteFieldContractV1Schema,
1467
- editorDefinition: editorDefinitionV1Schema,
1468
- contentSelectionSummary: siteSetupOwnerEditabilityNoteSchema.refine((text) => text.trim().length > 0, "Describe the selected content, important exclusions and any open gaps.")
1469
- }).strict().superRefine((input, context) => {
1470
- const contractRoutesByFieldId = new Map(input.fieldContract.fields.map((field) => [
1471
- field.fieldId,
1472
- field.routeKey
1473
- ]));
1474
- const definitionFieldIds = /* @__PURE__ */ new Set();
1475
- for (const [routeIndex, route] of input.editorDefinition.routes.entries()) {
1476
- for (const [sectionIndex, section] of route.sections.entries()) {
1477
- for (const [fieldIndex, field] of section.fields.entries()) {
1478
- const fieldPath = [
1479
- "editorDefinition",
1480
- "routes",
1481
- routeIndex,
1482
- "sections",
1483
- sectionIndex,
1484
- "fields",
1485
- fieldIndex,
1486
- "fieldId"
1487
- ];
1488
- const contractRouteKey = contractRoutesByFieldId.get(field.fieldId);
1489
- const contractField = input.fieldContract.fields.find((candidate) => candidate.fieldId === field.fieldId);
1490
- definitionFieldIds.add(field.fieldId);
1491
- if (!contractRouteKey) {
1492
- context.addIssue({
1493
- code: "custom",
1494
- message: `Unknown editor field id: ${field.fieldId}`,
1495
- path: fieldPath
1496
- });
1497
- } else if (contractRouteKey !== route.routeKey) {
1498
- context.addIssue({
1499
- code: "custom",
1500
- message: `Editor field ${field.fieldId} must use route ${contractRouteKey}.`,
1501
- path: fieldPath
1502
- });
1503
- } else if (field.maxLength !== void 0 && contractField?.fieldType !== "text" && contractField?.fieldType !== "longText") {
1504
- context.addIssue({
1505
- code: "custom",
1506
- message: `maxLength is not supported for ${contractField?.fieldType ?? "unknown"} fields.`,
1507
- path: [
1508
- "editorDefinition",
1509
- "routes",
1510
- routeIndex,
1511
- "sections",
1512
- sectionIndex,
1513
- "fields",
1514
- fieldIndex,
1515
- "maxLength"
1516
- ]
1517
- });
1518
- }
1519
- }
1520
- }
1521
- }
1522
- for (const field of input.fieldContract.fields) {
1523
- if (!definitionFieldIds.has(field.fieldId)) {
1524
- context.addIssue({
1525
- code: "custom",
1526
- message: `Missing editor field id: ${field.fieldId}`,
1527
- path: ["editorDefinition", "routes"]
1528
- });
1529
- }
1530
- }
1531
- });
1532
- var siteSetupVerifyInputSchema = z16.object({
1533
- deploymentUrl: z16.string().url().refine((value) => value.startsWith("https://")),
1534
- deploymentRevision: deploymentRevisionSchema,
1535
- wait: z16.boolean().optional()
1536
- }).strict();
1537
- var siteSetupEvidenceInputSchema = z16.object({
1538
- siteId: z16.string().uuid(),
1539
- runId: z16.string().uuid(),
1540
- expectedFieldContractHash: canonicalHashSchema,
1541
- expectedDeploymentOrigin: z16.string().url().refine((value) => value.startsWith("https://")),
1542
- expectedDeploymentRevision: deploymentRevisionSchema,
1543
- publicRuntimeKeyId: z16.string().uuid(),
1544
- bridgeSessionId: normalizedSafeTextSchema(256, "bridgeSessionId"),
1545
- observations: z16.array(z16.object({
1546
- fieldId: fieldIdSchema,
1547
- fieldType: fieldTypeSchema,
1548
- routeKey: siteFieldRouteKeySchema,
1549
- renderedPath: renderedPathSchema,
1550
- targetResolved: z16.boolean(),
1551
- previewAck: z16.boolean()
1552
- }).strict().refine((value) => !value.previewAck || value.targetResolved, "Preview ACK requires a resolved target.")).min(1).max(200)
1553
- }).strict();
1554
- var completeSetupReviewInputSchema = z16.object({
1555
- siteId: z16.string().uuid(),
1556
- runId: z16.string().uuid(),
1557
- expectedReviewVersion: z16.number().int().positive(),
1558
- expectedFieldContractHash: canonicalHashSchema,
1559
- expectedDeploymentRevision: deploymentRevisionSchema,
1560
- expectedReadyFingerprint: canonicalHashSchema
1561
- }).strict();
1562
- var activateSiteSetupInputSchema = z16.object({
1563
- siteId: z16.string().uuid(),
1564
- runId: z16.string().uuid(),
1565
- expectedReviewVersion: z16.number().int().positive(),
1566
- expectedSnapshotHash: canonicalHashSchema
1567
- }).strict();
1568
- var refreshSiteSetupDeploymentInputSchema = z16.object({
1569
- siteId: z16.string().uuid(),
1570
- deploymentUrl: z16.string().url().refine((value) => value.startsWith("https://")),
1571
- deploymentRevision: deploymentRevisionSchema
1572
- }).strict();
1573
- function addSafeByteIssues(value, maxBytes, label, context) {
1574
- if (utf8Bytes(value) > maxBytes) {
1575
- context.addIssue({
1576
- code: "custom",
1577
- message: `${label} exceeds ${maxBytes} UTF-8 bytes.`
1578
- });
1579
- }
1580
- if (forbiddenControlOrBidi.test(value)) {
1581
- context.addIssue({
1582
- code: "custom",
1583
- message: `${label} contains a forbidden control or bidi character.`
1584
- });
1585
- }
1586
- }
1587
- function utf8Bytes(value) {
1588
- return new TextEncoder().encode(value).byteLength;
1589
- }
1590
- var setupActivationApprovalSchema = z16.object({
1591
- reviewVersion: z16.number().int().positive(),
1592
- snapshotHash: canonicalHashSchema,
1593
- analytics: z16.object({
1594
- status: z16.enum(["active", "skipped"]),
1595
- reviewVersion: z16.number().int().positive(),
1596
- generation: z16.number().int().nonnegative()
1597
- }).optional()
1598
- });
1599
- var activateSetupModulesInputSchema = activateSiteSetupInputSchema.extend({
1600
- analytics: z16.discriminatedUnion("decision", [
1601
- z16.object({ decision: z16.literal("pending") }).strict(),
1602
- z16.object({
1603
- decision: z16.literal("enable"),
1604
- readinessTestRunId: z16.string().regex(/^analytics_owner_[0-9a-f-]{36}$/u),
1605
- expectedInstallationGeneration: z16.number().int().positive(),
1606
- measurementApproved: z16.literal(true)
1607
- }).strict(),
1608
- z16.object({
1609
- decision: z16.literal("skip"),
1610
- expectedInstallationGeneration: z16.number().int().nonnegative(),
1611
- continueWithoutAnalytics: z16.literal(true)
1612
- }).strict()
1613
- ])
1614
- }).strict();
1615
-
1616
- // ../shared/dist/bridge-protocol.js
1617
- var BRIDGE_PROTOCOL_VERSION = 2;
1618
- var bridgeRectSchema = z17.object({
1619
- x: z17.number(),
1620
- y: z17.number(),
1621
- width: z17.number().nonnegative(),
1622
- height: z17.number().nonnegative()
1623
- });
1624
- var previewTextValueSchema = z17.object({
1625
- fieldType: z17.enum(["text", "longText"]),
1626
- value: z17.string()
1627
- });
1628
- var previewLinkValueSchema = z17.object({
1629
- fieldType: z17.literal("link"),
1630
- value: z17.object({
1631
- href: z17.string().trim().min(1),
1632
- label: z17.string().trim().min(1).optional()
1633
- })
1634
- });
1635
- var previewImageValueSchema = z17.object({
1636
- fieldType: z17.literal("image"),
1637
- value: imageValueSchema
1638
- });
1639
- var bridgePreviewValueSchema = z17.discriminatedUnion("fieldType", [
1640
- previewTextValueSchema,
1641
- previewLinkValueSchema,
1642
- previewImageValueSchema
1643
- ]);
1644
- var fieldSelectionModeSchema = z17.enum(["replace", "range", "toggle"]);
1645
- var fieldBridgeMissingContentActionSchema = z17.enum([
1646
- "add",
1647
- "select",
1648
- "remove"
1649
- ]);
1650
- var FIELD_BRIDGE_MESSAGE_TYPES = [
1651
- "siteplane:field-bridge:init",
1652
- "siteplane:field-bridge:ready",
1653
- "siteplane:field-bridge:fields",
1654
- "siteplane:field-bridge:select-field",
1655
- "siteplane:field-bridge:set-selected-field",
1656
- "siteplane:field-bridge:apply-preview-values",
1657
- "siteplane:field-bridge:test-preview-values",
1658
- "siteplane:field-bridge:preview-ack",
1659
- "siteplane:field-bridge:set-visual-control-state",
1660
- "siteplane:field-bridge:missing-content",
1661
- "siteplane:field-bridge:preview-scrolled",
1662
- "siteplane:field-bridge:analytics-probe",
1663
- "siteplane:field-bridge:analytics-probe-result",
1664
- "siteplane:field-bridge:error"
1665
- ];
1666
- var canonicalFieldContractHashSchema = z17.string().regex(/^sha256:[0-9a-f]{64}$/u);
1667
- var bridgeSectionSchema = z17.string().trim().min(1).max(256);
1668
- var realRenderedPathSchema = z17.string().trim().refine((value) => value.startsWith("/") && value !== "$global" && !value.includes("?") && !value.includes("#"), "A field bridge rendered path must be a real canonical path.");
1669
- var fieldBridgeIdentitySchema = z17.object({
1670
- publicRuntimeKeyId: z17.string().uuid(),
1671
- fieldContractHash: canonicalFieldContractHashSchema,
1672
- deploymentRevision: z17.string().trim().min(1).max(256)
1673
- }).strict();
1674
- var setupPreviewAccessSchema = z17.object({
1675
- capability: z17.string().regex(/^v1\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]{43}$/u).max(4096),
1676
- expiresAt: z17.string().datetime()
1677
- }).strict();
1678
- var setupPreviewReadSchema = fieldBridgeIdentitySchema.extend({
1679
- scope: z17.literal("setup_preview"),
1680
- siteId: z17.string().uuid(),
1681
- runId: z17.string().uuid(),
1682
- bridgeSessionId: z17.string().min(1),
1683
- expiresAt: z17.string().datetime(),
1684
- contract: siteFieldContractV1Schema
1685
- }).strict();
1686
- var fieldBridgeBaseSchema = z17.object({
1687
- version: z17.literal(BRIDGE_PROTOCOL_VERSION),
1688
- type: z17.enum(FIELD_BRIDGE_MESSAGE_TYPES),
1689
- siteId: z17.string().uuid(),
1690
- sessionId: z17.string().trim().min(1),
1691
- publicRuntimeKeyId: z17.string().uuid(),
1692
- fieldContractHash: canonicalFieldContractHashSchema,
1693
- deploymentRevision: z17.string().trim().min(1).max(256),
1694
- requestId: z17.string().trim().min(1),
1695
- sentAt: z17.string().datetime()
1696
- }).strict();
1697
- var fieldBridgeFieldSchema = z17.object({
1698
- fieldId: fieldIdSchema,
1699
- fieldType: fieldTypeSchema,
1700
- routeKey: siteFieldRouteKeySchema,
1701
- renderedPath: realRenderedPathSchema,
1702
- sourcePath: z17.string().trim().min(1).optional(),
1703
- editTarget: fieldIdSchema,
1704
- rect: bridgeRectSchema,
1705
- targetResolved: z17.literal(true),
1706
- currentValue: bridgePreviewValueSchema.optional()
1707
- }).strict();
1708
- var fieldBridgeInitMessageSchema = fieldBridgeBaseSchema.extend({
1709
- type: z17.literal("siteplane:field-bridge:init"),
1710
- payload: z17.object({
1711
- adminOrigin: z17.string().url(),
1712
- customerOrigin: z17.string().url(),
1713
- renderedPath: realRenderedPathSchema,
1714
- setupPreview: setupPreviewAccessSchema.optional()
1715
- }).strict()
1716
- });
1717
- var fieldBridgeReadyMessageSchema = fieldBridgeBaseSchema.extend({
1718
- type: z17.literal("siteplane:field-bridge:ready"),
1719
- payload: z17.object({
1720
- renderedPath: realRenderedPathSchema,
1721
- fieldCount: z17.number().int().nonnegative(),
1722
- capabilities: z17.tuple([
1723
- z17.literal("field_selection"),
1724
- z17.literal("preview_values"),
1725
- z17.literal("field_evidence"),
1726
- z17.literal("visual_field_control")
1727
- ]).rest(z17.enum(["analytics_preview_readiness", "setup_preview"])).refine((capabilities) => capabilities.length <= 6)
1728
- }).strict()
1729
- });
1730
- var fieldBridgeFieldsMessageSchema = fieldBridgeBaseSchema.extend({
1731
- type: z17.literal("siteplane:field-bridge:fields"),
1732
- payload: z17.object({
1733
- renderedPath: realRenderedPathSchema,
1734
- fields: z17.array(fieldBridgeFieldSchema)
1735
- }).strict()
1736
- });
1737
- var fieldBridgeSelectFieldMessageSchema = fieldBridgeBaseSchema.extend({
1738
- type: z17.literal("siteplane:field-bridge:select-field"),
1739
- payload: z17.object({
1740
- fieldId: fieldIdSchema,
1741
- selectionMode: fieldSelectionModeSchema
1742
- }).strict()
1743
- });
1744
- var fieldBridgeSetSelectedFieldMessageSchema = fieldBridgeBaseSchema.extend({
1745
- type: z17.literal("siteplane:field-bridge:set-selected-field"),
1746
- payload: z17.object({
1747
- fieldIds: z17.array(fieldIdSchema).max(200),
1748
- primaryFieldId: fieldIdSchema.nullable(),
1749
- scrollIntoView: z17.boolean().optional()
1750
- }).strict().superRefine((value, context) => {
1751
- if (value.fieldIds.length > 0 && value.primaryFieldId === null) {
1752
- context.addIssue({
1753
- code: "custom",
1754
- message: "A non-empty selection needs a primary field.",
1755
- path: ["primaryFieldId"]
1756
- });
1757
- }
1758
- if (value.primaryFieldId !== null && !value.fieldIds.includes(value.primaryFieldId)) {
1759
- context.addIssue({
1760
- code: "custom",
1761
- message: "The primary field must be part of the selection.",
1762
- path: ["primaryFieldId"]
1763
- });
1764
- }
1765
- })
1766
- });
1767
- var fieldBridgeApplyPreviewValuesMessageSchema = fieldBridgeBaseSchema.extend({
1768
- type: z17.literal("siteplane:field-bridge:apply-preview-values"),
1769
- payload: z17.object({ values: z17.record(fieldIdSchema, bridgePreviewValueSchema) }).strict()
1770
- });
1771
- var fieldBridgeTestPreviewValuesMessageSchema = fieldBridgeBaseSchema.extend({
1772
- type: z17.literal("siteplane:field-bridge:test-preview-values"),
1773
- payload: z17.object({ fieldIds: z17.array(fieldIdSchema).min(1).max(200) }).strict()
1774
- });
1775
- var fieldBridgePreviewAckMessageSchema = fieldBridgeBaseSchema.extend({
1776
- type: z17.literal("siteplane:field-bridge:preview-ack"),
1777
- payload: z17.object({
1778
- ackRequestId: z17.string().trim().min(1),
1779
- kind: z17.enum(["apply", "test"]),
1780
- renderedPath: realRenderedPathSchema,
1781
- fieldIds: z17.array(fieldIdSchema).max(200)
1782
- }).strict()
1783
- });
1784
- var fieldBridgeSetVisualControlStateMessageSchema = fieldBridgeBaseSchema.extend({
1785
- type: z17.literal("siteplane:field-bridge:set-visual-control-state"),
1786
- payload: z17.object({
1787
- enabled: z17.boolean(),
1788
- fieldProximityEnabled: z17.boolean(),
1789
- pendingKeys: z17.array(z17.string().trim().min(1).max(2048)).max(50),
1790
- activeFieldIds: z17.array(fieldIdSchema),
1791
- fieldSections: z17.record(fieldIdSchema, bridgeSectionSchema),
1792
- selectedPending: z17.array(z17.object({
1793
- key: z17.string().trim().min(1).max(2048),
1794
- locatorHint: z17.string().trim().min(1).max(2048)
1795
- }).strict()).max(50),
1796
- scrollPendingIntoView: z17.boolean().optional()
1797
- }).strict()
1798
- });
1799
- var fieldBridgeMissingContentMessageSchema = fieldBridgeBaseSchema.extend({
1800
- type: z17.literal("siteplane:field-bridge:missing-content"),
1801
- payload: z17.object({
1802
- action: fieldBridgeMissingContentActionSchema,
1803
- item: setupCorrectionItemSchema,
1804
- suggestedSection: bridgeSectionSchema.optional()
1805
- }).strict()
1806
- });
1807
- var fieldBridgePreviewScrolledMessageSchema = fieldBridgeBaseSchema.extend({
1808
- type: z17.literal("siteplane:field-bridge:preview-scrolled"),
1809
- payload: z17.object({ renderedPath: realRenderedPathSchema }).strict()
1810
- });
1811
- var analyticsPreviewChallengeSchema = z17.object({
1812
- bridgeSessionId: z17.string().uuid(),
1813
- challenge: z17.string().min(32).max(512),
1814
- testRunId: z17.string().trim().min(1).max(160),
1815
- expiresAt: z17.string().datetime()
1816
- }).strict();
1817
- var fieldBridgeAnalyticsProbeSchema = fieldBridgeBaseSchema.extend({
1818
- type: z17.literal("siteplane:field-bridge:analytics-probe"),
1819
- requestId: z17.string().min(1).max(256),
1820
- payload: analyticsPreviewChallengeSchema
1821
- });
1822
- var fieldBridgeAnalyticsProbeResultSchema = fieldBridgeBaseSchema.extend({
1823
- type: z17.literal("siteplane:field-bridge:analytics-probe-result"),
1824
- payload: z17.object({
1825
- ackRequestId: z17.string().min(1).max(256),
1826
- status: z17.enum(["recorded", "failed"])
1827
- }).strict()
1828
- });
1829
- var fieldBridgeErrorMessageSchema = fieldBridgeBaseSchema.extend({
1830
- type: z17.literal("siteplane:field-bridge:error"),
1831
- payload: z17.object({
1832
- code: z17.string().trim().min(1),
1833
- message: z17.string().trim().min(1),
1834
- recoverable: z17.boolean().default(false)
1835
- }).strict()
1836
- });
1837
- var fieldBridgeMessageSchema = z17.discriminatedUnion("type", [
1838
- fieldBridgeInitMessageSchema,
1839
- fieldBridgeReadyMessageSchema,
1840
- fieldBridgeFieldsMessageSchema,
1841
- fieldBridgeSelectFieldMessageSchema,
1842
- fieldBridgeSetSelectedFieldMessageSchema,
1843
- fieldBridgeApplyPreviewValuesMessageSchema,
1844
- fieldBridgeTestPreviewValuesMessageSchema,
1845
- fieldBridgePreviewAckMessageSchema,
1846
- fieldBridgeSetVisualControlStateMessageSchema,
1847
- fieldBridgeMissingContentMessageSchema,
1848
- fieldBridgePreviewScrolledMessageSchema,
1849
- fieldBridgeErrorMessageSchema,
1850
- fieldBridgeAnalyticsProbeSchema,
1851
- fieldBridgeAnalyticsProbeResultSchema
1852
- ]);
1853
-
1854
- // ../shared/dist/commands.js
1855
- import { z as z19 } from "zod";
1856
-
1857
- // ../shared/dist/errors.js
1858
- import { z as z18 } from "zod";
1859
- var UI_ERROR_CATEGORIES = [
1860
- "site_member",
1861
- "workspace_member",
1862
- "internal"
1863
- ];
1864
- var uiErrorCategorySchema = z18.enum(UI_ERROR_CATEGORIES);
1865
- var commandErrorPayloadSchema = z18.object({
1866
- code: z18.string().min(1),
1867
- message: z18.string().min(1),
1868
- category: uiErrorCategorySchema,
1869
- details: z18.record(z18.string(), z18.unknown()).optional()
1870
- });
1871
-
1872
- // ../shared/dist/commands.js
1873
- var commandSuccessSchema = z19.object({
1874
- ok: z19.literal(true),
1875
- data: z19.unknown()
1876
- });
1877
- var commandErrorSchema = z19.object({
1878
- ok: z19.literal(false),
1879
- error: commandErrorPayloadSchema
1880
- });
1881
- var commandResultSchema = z19.discriminatedUnion("ok", [
1882
- commandSuccessSchema,
1883
- commandErrorSchema
1884
- ]);
1885
-
1886
- // ../shared/dist/editor-settings.js
1887
- import { z as z20 } from "zod";
1888
- var editorColorSchemeSchema = z20.enum([
1889
- "paper",
1890
- "slate",
1891
- "siteplane",
1892
- "bloom"
1893
- ]);
1894
- var editorColorSchemes = editorColorSchemeSchema.options;
1895
- var editorColorModeSchema = z20.enum(["light", "dark"]);
1896
- var editorColorModes = editorColorModeSchema.options;
1897
-
1898
- // ../shared/dist/editor-organization.js
1899
- import { z as z21 } from "zod";
1900
- var labelSchema = z21.string().trim().min(1).max(120);
1901
- var updateFieldSchema = z21.object({
1902
- operation: z21.literal("update_field"),
1903
- siteId: z21.string().uuid(),
1904
- fieldId: fieldIdSchema,
1905
- label: labelSchema.optional(),
1906
- description: z21.string().trim().max(500).nullable().optional(),
1907
- section: labelSchema.nullable().optional(),
1908
- subsection: labelSchema.nullable().optional(),
1909
- sortOrder: z21.number().int().nonnegative().optional(),
1910
- status: z21.enum(["hidden", "active"]).optional()
1911
- });
1912
- var updateEditorOrganizationInputSchema = z21.discriminatedUnion("operation", [
1913
- updateFieldSchema,
1914
- z21.object({
1915
- operation: z21.literal("rename_section"),
1916
- siteId: z21.string().uuid(),
1917
- routeKey: siteFieldRouteKeySchema,
1918
- currentSection: labelSchema,
1919
- nextSection: labelSchema
1920
- }),
1921
- z21.object({
1922
- operation: z21.literal("create_group"),
1923
- siteId: z21.string().uuid(),
1924
- routeKey: siteFieldRouteKeySchema,
1925
- section: labelSchema,
1926
- fieldIds: z21.array(fieldIdSchema).max(200).default([])
1927
- }),
1928
- z21.object({
1929
- operation: z21.literal("delete_section"),
1930
- siteId: z21.string().uuid(),
1931
- routeKey: siteFieldRouteKeySchema,
1932
- section: labelSchema
1933
- }),
1934
- z21.object({
1935
- operation: z21.literal("move_section"),
1936
- siteId: z21.string().uuid(),
1937
- routeKey: siteFieldRouteKeySchema,
1938
- section: labelSchema,
1939
- direction: z21.enum(["up", "down"])
1940
- }),
1941
- z21.object({
1942
- operation: z21.literal("create_subgroup"),
1943
- siteId: z21.string().uuid(),
1944
- routeKey: siteFieldRouteKeySchema,
1945
- section: labelSchema,
1946
- subsection: labelSchema,
1947
- fieldIds: z21.array(fieldIdSchema).min(1).max(200)
1948
- }),
1949
- z21.object({
1950
- operation: z21.literal("update_subgroup"),
1951
- siteId: z21.string().uuid(),
1952
- routeKey: siteFieldRouteKeySchema,
1953
- currentSection: labelSchema,
1954
- currentSubsection: labelSchema,
1955
- section: labelSchema,
1956
- subsection: labelSchema.nullable()
1957
- }),
1958
- z21.object({
1959
- operation: z21.literal("rename_route"),
1960
- siteId: z21.string().uuid(),
1961
- routeKey: siteFieldRouteKeySchema.refine((value) => value !== "$global", "Global content has no page label."),
1962
- label: labelSchema
1963
- })
1964
- ]).and(z21.object({
1965
- review: z21.object({
1966
- runId: z21.string().uuid(),
1967
- expectedReviewVersion: z21.number().int().positive()
1968
- }).strict().optional()
1969
- })).superRefine((input, context) => {
1970
- if (input.operation === "update_field" && input.label === void 0 && input.description === void 0 && input.section === void 0 && input.subsection === void 0 && input.sortOrder === void 0 && input.status === void 0) {
1971
- context.addIssue({
1972
- code: "custom",
1973
- message: "At least one field organization value is required."
1974
- });
1975
- }
1976
- if (input.operation === "update_field" && input.section === null && typeof input.subsection === "string") {
1977
- context.addIssue({
1978
- code: "custom",
1979
- message: "A subgroup requires a group.",
1980
- path: ["subsection"]
1981
- });
1982
- }
1983
- });
1984
-
1985
- // ../shared/dist/site-slug.js
1986
- import { z as z22 } from "zod";
1987
- var SITE_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1988
- var RESERVED_SITE_SLUGS = /* @__PURE__ */ new Set([
1989
- "account",
1990
- "admin",
1991
- "api",
1992
- "app",
1993
- "auth",
1994
- "book",
1995
- "claim",
1996
- "dev",
1997
- "login",
1998
- "new",
1999
- "portal",
2000
- "support",
2001
- "workspace"
2002
- ]);
2003
- var siteSlugSchema = z22.string().regex(SITE_SLUG_PATTERN, "Invalid site slug").refine((value) => !RESERVED_SITE_SLUGS.has(value), "Reserved site slug");
2004
-
2005
- // ../shared/dist/entitlements.js
2006
- import { z as z23 } from "zod";
2007
- var entitlementSnapshotSchema = z23.object({
2008
- planKey: z23.string().trim().min(1),
2009
- sitesLimit: z23.number().int().positive(),
2010
- siteMembersPerSiteLimit: z23.number().int().positive(),
2011
- customAdminDomainsEnabled: z23.boolean(),
2012
- agentMcpEnabled: z23.boolean(),
2013
- emailNotificationsEnabled: z23.boolean(),
2014
- analyticsEnabled: z23.boolean(),
2015
- analyticsSitesLimit: z23.number().int().min(0),
2016
- analyticsPortalPerformanceEnabled: z23.boolean(),
2017
- analyticsMonthlyReportsEnabled: z23.boolean(),
2018
- analyticsAiSummaryEnabled: z23.boolean(),
2019
- analyticsRawEventRetentionDays: z23.number().int().min(1).max(ANALYTICS_RETENTION_DEFAULTS.maxRawEventRetentionDaysWithoutAdr),
2020
- analyticsMonthlyEventLimit: z23.number().int().min(0),
2021
- bookingEnabled: z23.boolean().default(false),
2022
- bookingSitesLimit: z23.number().int().min(0).default(0),
2023
- bookingPortalManagementEnabled: z23.boolean().default(false),
2024
- bookingResourcesPerSiteLimit: z23.number().int().min(0).default(0),
2025
- bookingServicesPerSiteLimit: z23.number().int().min(0).default(0),
2026
- bookingMonthlyBookingsLimit: z23.number().int().min(0).default(0),
2027
- bookingRemindersEnabled: z23.boolean().default(false)
2028
- });
2029
- var EARLY_ACCESS_PLAN = {
2030
- planKey: "early_access_2026",
2031
- sitesLimit: 3,
2032
- siteMembersPerSiteLimit: 5,
2033
- customAdminDomainsEnabled: true,
2034
- agentMcpEnabled: true,
2035
- emailNotificationsEnabled: true,
2036
- analyticsEnabled: true,
2037
- analyticsSitesLimit: 3,
2038
- analyticsPortalPerformanceEnabled: false,
2039
- analyticsMonthlyReportsEnabled: false,
2040
- analyticsAiSummaryEnabled: false,
2041
- analyticsRawEventRetentionDays: ANALYTICS_RETENTION_DEFAULTS.enabledRawEventRetentionDays,
2042
- analyticsMonthlyEventLimit: 0,
2043
- bookingEnabled: true,
2044
- bookingSitesLimit: 3,
2045
- bookingPortalManagementEnabled: true,
2046
- bookingResourcesPerSiteLimit: 10,
2047
- bookingServicesPerSiteLimit: 50,
2048
- bookingMonthlyBookingsLimit: 0,
2049
- bookingRemindersEnabled: true
2050
- };
2051
-
2052
- // ../shared/dist/first-party-image-upload.js
2053
- var maxFirstPartyImageUploadBytes = 4 * 1024 * 1024;
2054
-
2055
- // ../shared/dist/readiness.js
2056
- import { z as z24 } from "zod";
2057
- var READINESS_CHECK_KEYS = [
2058
- "agent_instructions_installed",
2059
- "runtime_package_connected",
2060
- "secure_server_access_configured",
2061
- "preview_bridge_working",
2062
- "admin_access_url_selected",
2063
- "default_publishing_mode_selected"
2064
- ];
2065
- var READINESS_STATUSES = [
2066
- "pending",
2067
- "passing",
2068
- "failing",
2069
- "warning"
2070
- ];
2071
- var readinessCheckKeySchema = z24.enum(READINESS_CHECK_KEYS);
2072
- var readinessStatusSchema = z24.enum(READINESS_STATUSES);
2073
-
2074
- // ../shared/dist/site.js
2075
- import { z as z25 } from "zod";
2076
- var SITE_STATUSES = [
2077
- "setup",
2078
- "active",
2079
- "disabled",
2080
- "archived"
2081
- ];
2082
- var siteStatusSchema = z25.enum(SITE_STATUSES);
2083
- var websiteUrlSchema = z25.string().trim().url().refine((value) => value.startsWith("https://") || value.startsWith("http://"), "Website URL must use http or https");
2084
-
2085
- // ../shared/dist/setup-assets.js
2086
- import { z as z26 } from "zod";
2087
- var configureSetupAssetTargetInputSchema = z26.object({
2088
- siteId: z26.string().uuid(),
2089
- runId: z26.string().uuid(),
2090
- expectedReviewVersion: z26.number().int().positive(),
2091
- expectedSnapshotHash: z26.string().regex(/^sha256:[0-9a-f]{64}$/u),
2092
- mutationId: z26.string().uuid(),
2093
- expectedApprovalId: z26.string().uuid().nullable(),
2094
- targetId: z26.string().uuid().nullable(),
2095
- targetType: z26.enum(["repo_static_assets", "siteplane_managed_fallback"]),
2096
- approveManagedHosting: z26.boolean()
2097
- }).strict().refine((value) => value.targetType === "siteplane_managed_fallback" || !value.approveManagedHosting);
2098
- var setupAssetTargetApprovalSchema = z26.object({
2099
- id: z26.string().uuid(),
2100
- runId: z26.string().uuid(),
2101
- reviewVersion: z26.number().int().positive(),
2102
- snapshotHash: z26.string().regex(/^sha256:[0-9a-f]{64}$/u),
2103
- targetId: z26.string().uuid(),
2104
- targetType: z26.enum(["repo_static_assets", "siteplane_managed_fallback"]),
2105
- targetRevision: z26.number().int().positive(),
2106
- deploymentOrigin: z26.string().url(),
2107
- gitConnectionId: z26.string().uuid().nullable(),
2108
- gitRevision: z26.number().int().positive().nullable(),
2109
- managedHostingApproved: z26.boolean(),
2110
- actorUserId: z26.string().uuid(),
2111
- approvedAt: z26.string().datetime({ offset: true })
2112
- }).strict();
2113
- var setupAssetReadinessSchema = z26.union([
2114
- z26.object({
2115
- status: z26.enum([
2116
- "not_required",
2117
- "needs_choice",
2118
- "stale_setup_review",
2119
- "permission_denied"
2120
- ])
2121
- }).strict(),
2122
- z26.object({
2123
- status: z26.literal("stale_approval"),
2124
- approval: setupAssetTargetApprovalSchema.optional()
2125
- }).strict(),
2126
- z26.object({
2127
- status: z26.literal("not_verified"),
2128
- approval: setupAssetTargetApprovalSchema,
2129
- jobId: z26.string().uuid().optional(),
2130
- checkedAt: z26.string().datetime({ offset: true }).nullable().optional()
2131
- }).strict(),
2132
- z26.object({
2133
- status: z26.enum(["ready", "checking", "retrying"]),
2134
- approval: setupAssetTargetApprovalSchema,
2135
- jobId: z26.string().uuid(),
2136
- checkedAt: z26.string().datetime({ offset: true }).nullable()
2137
- }).strict().refine((value) => value.status !== "ready" || value.checkedAt !== null)
2138
- ]);
2139
- var checkSetupAssetTargetInputSchema = z26.object({
2140
- siteId: z26.string().uuid(),
2141
- runId: z26.string().uuid(),
2142
- approvalId: z26.string().uuid(),
2143
- intent: z26.enum(["start", "poll"])
2144
- }).strict();
2145
-
2146
- // ../shared/dist/setup-installation.js
2147
- import { z as z27 } from "zod";
2148
- var setupInstallationRequestSchema = z27.object({
2149
- modules: siteSetupModulesSchema,
2150
- ownerEditabilityNote: siteSetupOwnerEditabilityNoteSchema,
2151
- provider: z27.object({
2152
- projectId: z27.string().min(1).max(200),
2153
- teamId: z27.string().min(1).max(200)
2154
- }).strict()
2155
- }).strict();
2156
-
2157
- // ../shared/dist/setup-claim.js
2158
- import { z as z28 } from "zod";
2159
- var setupClaimCodeSchema = z28.string().regex(/^[0-9A-HJKMNP-TV-Z]{8}$/u);
2160
- var setupClaimBindingSchema = z28.object({
2161
- siteId: z28.string().uuid(),
2162
- runId: z28.string().uuid()
2163
- });
2164
- var setupClaimReceiptSchema = setupClaimBindingSchema.extend({
2165
- status: z28.literal("claimed"),
2166
- requestId: z28.string().uuid(),
2167
- workspaceId: z28.string().uuid(),
2168
- userId: z28.string().uuid(),
2169
- claimedAt: z28.string().datetime({ offset: true })
2170
- }).strict();
2171
- var setupClaimInspectionSchema = setupClaimBindingSchema.extend({
2172
- status: z28.literal("pending"),
2173
- requestId: z28.string().uuid(),
2174
- siteName: z28.string(),
2175
- userId: z28.string().uuid(),
2176
- accountEmail: z28.string().email(),
2177
- workspaceId: z28.string().uuid(),
2178
- workspaceName: z28.string(),
2179
- expiresAt: z28.string().datetime({ offset: true })
2180
- }).strict();
2181
- var setupClaimDenialSchema = z28.object({
2182
- status: z28.enum([
2183
- "invalid_claim_request",
2184
- "invalid_installation",
2185
- "already_claimed",
2186
- "project_expired",
2187
- "invalid_guest_session",
2188
- "stale_setup_review",
2189
- "verified_account_required",
2190
- "workspace_access_denied",
2191
- "workspace_entitlement_required",
2192
- "site_limit_reached",
2193
- "provisional_relationship_conflict",
2194
- "rate_limited"
2195
- ])
2196
- }).strict();
2197
-
2198
- // ../cli/dist/analytics/static-scan.js
2199
- import ts from "typescript";
2200
-
2201
- // ../cli/dist/booking/manifest.js
2202
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
2203
- import { dirname as dirname2 } from "path";
2204
- async function readBookingManifestFile(manifestPath) {
2205
- return validateBookingManifestInput(JSON.parse(await readFile2(manifestPath, "utf8")));
2206
- }
2207
- async function writeBookingManifestFile(manifestPath, manifest) {
2208
- await mkdir2(dirname2(manifestPath), {
2209
- recursive: true
2210
- });
2211
- await writeFile2(manifestPath, `${JSON.stringify(bookingManifestSchema.parse(manifest), null, 2)}
2212
- `, "utf8");
2213
- }
2214
- function validateBookingManifestInput(input) {
2215
- const redactedKeys = collectRedactedBookingKeys(input);
2216
- const redacted = redactBookingManifest(input);
2217
- return {
2218
- manifest: bookingManifestSchema.parse(redacted),
2219
- redactedKeys: [...redactedKeys].sort()
2220
- };
2221
- }
2222
- var secretManifestKeys2 = /* @__PURE__ */ new Set([
2223
- "siteKey",
2224
- "rawKey",
2225
- "token",
2226
- "accessToken"
2227
- ]);
2228
- function collectRedactedBookingKeys(input, prefix = "") {
2229
- if (Array.isArray(input)) {
2230
- return input.flatMap((item, index) => collectRedactedBookingKeys(item, `${prefix}[${index}]`));
2231
- }
2232
- if (!input || typeof input !== "object") {
2233
- return [];
2234
- }
2235
- return Object.entries(input).flatMap(([key, value]) => {
2236
- const path = prefix ? `${prefix}.${key}` : key;
2237
- if (secretManifestKeys2.has(key)) {
2238
- return [path];
2239
- }
2240
- return collectRedactedBookingKeys(value, path);
2241
- });
2242
- }
2243
-
2244
- // ../cli/dist/booking/static-scan.js
2245
- import ts2 from "typescript";
2246
- function scanBookingSourceFiles(files, input) {
2247
- const findings = [];
2248
- const hardErrors = [];
2249
- const warnings = [];
2250
- for (const file of files) {
2251
- let visit2 = function(node) {
2252
- if (ts2.isCallExpression(node) && ts2.isIdentifier(node.expression) && node.expression.text === "withSiteplane") {
2253
- const options = node.arguments[1];
2254
- const booking = options && property(options, "booking");
2255
- const site = booking && property(booking, "site");
2256
- if (site && ts2.isStringLiteralLike(site)) {
2257
- const issue = {
2258
- code: site.text === input.siteId ? "booking_scan.integration_found" : "booking_scan.site_mismatch",
2259
- 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.",
2260
- filePath: file.filePath
2261
- };
2262
- (site.text === input.siteId ? findings : hardErrors).push(issue);
2263
- }
2264
- }
2265
- ts2.forEachChild(node, visit2);
2266
- };
2267
- var visit = visit2;
2268
- const source = ts2.createSourceFile(file.filePath, file.sourceText, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
2269
- visit2(source);
2270
- }
2271
- if (!findings.length && !hardErrors.length)
2272
- hardErrors.push({
2273
- code: "booking_scan.integration_missing",
2274
- message: "Could not verify withSiteplane(nextConfig, { booking: { site: <site-id> } }). Include next.config.ts in the scan and use a literal Site ID.",
2275
- filePath: "next.config.ts"
2276
- });
2277
- if (input.productionOrigin && !files.some((file) => file.sourceText.includes(input.productionOrigin)))
2278
- warnings.push({
2279
- code: "booking_scan.origin_not_detected",
2280
- message: "Verify the public booking address and its allowed origins in Siteplane settings.",
2281
- filePath: "siteplane.booking.json"
2282
- });
2283
- return {
2284
- manifest: bookingManifestSchema.parse({
2285
- schemaVersion: 1,
2286
- ...input,
2287
- integration: "rewrite"
2288
- }),
2289
- findings,
2290
- hardErrors,
2291
- warnings,
2292
- suggestions: []
2293
- };
2294
- }
2295
- function property(node, name2) {
2296
- if (!ts2.isObjectLiteralExpression(node))
2297
- return;
2298
- for (const item of node.properties) {
2299
- if (ts2.isPropertyAssignment(item) && (ts2.isIdentifier(item.name) || ts2.isStringLiteral(item.name)) && item.name.text === name2)
2300
- return item.initializer;
2301
- }
2302
- }
2303
-
2304
- // ../cli/dist/commands/analytics/check.js
2305
- import { readFile as readFile3 } from "fs/promises";
2306
-
2307
- // ../cli/dist/commands/analytics/init.js
2308
- import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
2309
- import { dirname as dirname3, join } from "path";
2310
- var analyticsRulesTemplate = `# Siteplane Analytics Rules
2311
-
2312
- Analytics contract version: ${ANALYTICS_CONTRACT_VERSION}
2313
- Analytics contract hash: ${ANALYTICS_CONTRACT_HASH}
2314
-
2315
- - Do not change visible layout, copy, styling, animation or business logic while adding analytics.
2316
- - Use stable data-siteplane-target-id values that do not depend on visible copy.
2317
- - Use public site keys only through environment references.
2318
- - Do not write secret analytics keys, setup tokens or project CLI tokens into source files.
2319
- - Mount the SDK once in the existing client lifecycle. Wire installDataAttributeTracking and createNextAppRouterNavigationAdapter to analytics.track/getRouteViewId/setPageContext, feed initial and subsequent Next.js pathname changes, and refresh attribute targets after navigation. Dispose attribute tracking and the SDK on unmount.
2320
- - Inspect existing consent management. Pass consentAdapter with getConsent and subscribe to initSiteplaneAnalytics for an existing CMP; return unknown while unresolved, disabled for denial and a permitted mode only for its actual visitor grant. Subscribe returns cleanup. Do not mirror CMP snapshots with setConsent or replace stored opt-outs.
2321
- - Omit consentAdapter only after confirming no existing CMP. An unrecognized CMP blocks Analytics with a concrete repair diagnostic; do not invent a grant or a no-op adapter to pass a check.
2322
- - Suppress editor-preview traffic from live analytics.
2323
- - Run npx siteplane analytics check, npx siteplane analytics sync and npx siteplane analytics test after setup.
2324
- `;
2325
- var analyticsCursorRulesTemplate = `---
2326
- description: Siteplane Analytics rules
2327
- alwaysApply: true
2328
- ---
2329
-
2330
- ${analyticsRulesTemplate}`;
2331
-
2332
- // ../cli/dist/commands/analytics/import.js
2333
- import { createHash } from "crypto";
2334
-
2335
- // ../cli/dist/commands/analytics/sync.js
2336
- function createAnalyticsCliRequestHeaders(config) {
2337
- const headers = {
2338
- authorization: `Bearer ${config.accessToken}`,
2339
- "content-type": "application/json"
2340
- };
2341
- const bypassSecret = config.vercelAutomationBypassSecret?.trim();
2342
- if (bypassSecret) {
2343
- headers["x-vercel-protection-bypass"] = bypassSecret;
2344
- }
2345
- return headers;
2346
- }
2347
-
2348
- // ../cli/dist/commands/analytics/public-key.js
2349
- import { z as z29 } from "zod";
2350
- var responseSchema = z29.object({
2351
- ok: z29.literal(true),
2352
- data: z29.object({
2353
- rawPublicKey: z29.string().regex(/^pk_siteplane_[A-Za-z0-9_-]{16}_[A-Za-z0-9_-]{43}$/)
2354
- })
2355
- });
2356
- var errorResponseSchema = z29.object({
2357
- error: z29.object({
2358
- code: z29.string().regex(/^[a-z][a-z0-9_.-]+$/u)
2359
- })
2360
- });
2361
- async function analyticsPublicKeyCommand(input) {
2362
- const fetcher = input.fetchImpl ?? fetch;
2363
- const response = await fetcher(`${input.config.apiBaseUrl.replace(/\/$/u, "")}/api/cli/analytics/public-key`, {
2364
- method: "POST",
2365
- redirect: "error",
2366
- signal: AbortSignal.timeout(2e4),
2367
- headers: createAnalyticsCliRequestHeaders(input.config),
2368
- body: JSON.stringify({ siteId: input.config.siteId })
2369
- });
2370
- const payload = await response.json().catch(() => null);
2371
- const parsed = responseSchema.safeParse(payload);
2372
- if (!response.ok || !parsed.success) {
2373
- const error = errorResponseSchema.safeParse(payload);
2374
- throw new Error(`${error.success ? error.data.error.code : "analytics_public_key.invalid_response"}: Unable to read the active Analytics public key.`);
2375
- }
2376
- return parsed.data.data.rawPublicKey;
2377
- }
2378
-
2379
- // ../cli/dist/commands/analytics/prepare.js
2380
- import { z as z30 } from "zod";
2381
- var resultSchema = z30.object({
2382
- ok: z30.literal(true),
2383
- data: z30.object({
2384
- rawPublicKey: z30.string().regex(/^pk_siteplane_[A-Za-z0-9_-]{16}_[A-Za-z0-9_-]{43}$/u),
2385
- generation: z30.number().int().positive(),
2386
- status: z30.enum([
2387
- "setup_started",
2388
- "test_mode",
2389
- "active",
2390
- "paused",
2391
- "error",
2392
- "deleting"
2393
- ])
2394
- }).strict()
2395
- }).strict();
2396
- var errorSchema = z30.object({
2397
- error: z30.object({ code: z30.string().regex(/^[a-z][a-z0-9_.-]+$/u) })
2398
- });
2399
-
2400
- // ../cli/dist/commands/analytics/test.js
2401
- import { randomUUID } from "crypto";
2402
-
2403
- // ../cli/dist/commands/booking/check.js
2404
- import { dirname as dirname4, join as join2 } from "path";
2405
- import { access, readFile as readFile4 } from "fs/promises";
2406
- async function bookingCheckCommand(input) {
2407
- const validatedManifest = await readBookingManifestFile(input.manifestPath);
2408
- const configs = (await Promise.all(["next.config.ts", "next.config.js", "next.config.mjs"].map(async (name2) => {
2409
- const path = join2(dirname4(input.manifestPath), name2);
2410
- return await access(path).then(() => path, () => null);
2411
- }))).filter((path) => path !== null);
2412
- const sourceFiles = await readSourceFiles([
2413
- .../* @__PURE__ */ new Set([...input.sourceFilePaths, ...configs])
2414
- ]);
2415
- const scanInput = {
2416
- siteId: validatedManifest.manifest.siteId,
2417
- bookingPageSlug: validatedManifest.manifest.bookingPageSlug,
2418
- ...validatedManifest.manifest.productionOrigin ? { productionOrigin: validatedManifest.manifest.productionOrigin } : {}
2419
- };
2420
- const scanResult = scanBookingSourceFiles(sourceFiles, {
2421
- ...scanInput
2422
- });
2423
- const hardErrors = [
2424
- ...createBoundaryErrors(validatedManifest),
2425
- ...scanResult.hardErrors
2426
- ];
2427
- return {
2428
- ok: hardErrors.length === 0,
2429
- manifest: validatedManifest.manifest,
2430
- scannedManifest: scanResult.manifest,
2431
- redactedKeys: validatedManifest.redactedKeys,
2432
- hardErrors,
2433
- warnings: scanResult.warnings,
2434
- suggestions: scanResult.suggestions,
2435
- findings: scanResult.findings
2436
- };
2437
- }
2438
- async function readSourceFiles(filePaths) {
2439
- return Promise.all(filePaths.map(async (filePath) => ({
2440
- filePath,
2441
- sourceText: await readFile4(filePath, "utf8")
2442
- })));
2443
- }
2444
- function createBoundaryErrors(validation) {
2445
- return validation.redactedKeys.map((key) => ({
2446
- code: "booking_check.raw_key_in_manifest",
2447
- message: `Booking manifest contains a raw key-like field: ${key}`,
2448
- filePath: "siteplane.booking.json"
2449
- }));
2450
- }
2451
-
2452
- // ../cli/dist/commands/booking/init.js
2453
- import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
2454
- import { dirname as dirname5, join as join3 } from "path";
2455
- async function bookingInitCommand(input) {
2456
- const manifest = {
2457
- schemaVersion: 1,
2458
- siteId: input.siteId,
2459
- bookingPageSlug: input.bookingPageSlug,
2460
- ...input.productionOrigin ? { productionOrigin: input.productionOrigin } : {}
2461
- };
2462
- const manifestPath = join3(input.projectDir, "siteplane.booking.json");
2463
- const artifacts = createBookingArtifacts(input.agentClient);
2464
- await writeBookingManifestFile(manifestPath, manifest);
2465
- for (const artifact of artifacts) {
2466
- await writeProjectFile(input.projectDir, artifact.path, artifact.template);
2467
- }
2468
- return {
2469
- manifestPath,
2470
- manifest,
2471
- artifactPaths: artifacts.map((artifact) => artifact.path)
2472
- };
2473
- }
2474
- function createBookingArtifacts(agentClient) {
2475
- const artifacts = [
2476
- {
2477
- path: ".siteplane/booking.md",
2478
- template: bookingRulesTemplate
2479
- }
2480
- ];
2481
- if (agentClient === "codex") {
2482
- artifacts.push({
2483
- path: ".agents/skills/siteplane-booking/SKILL.md",
2484
- template: bookingSkillTemplate("Codex")
2485
- });
2486
- }
2487
- if (agentClient === "claude") {
2488
- artifacts.push({
2489
- path: ".claude/skills/siteplane-booking/SKILL.md",
2490
- template: bookingSkillTemplate("Claude Code")
2491
- });
2492
- }
2493
- if (agentClient === "cursor") {
2494
- artifacts.push({
2495
- path: ".cursor/rules/siteplane-booking.mdc",
2496
- template: bookingCursorRulesTemplate
2497
- });
2498
- }
2499
- return artifacts;
2500
- }
2501
- async function writeProjectFile(projectDir, relativePath, contents) {
2502
- const path = join3(projectDir, relativePath);
2503
- await mkdir4(dirname5(path), { recursive: true });
2504
- await writeFile4(path, contents, "utf8");
2505
- }
2506
- var bookingRulesTemplate = `# Siteplane Booking Rules
2507
-
2508
- - Do not change layout, copy, styling, animation or business logic while adding Booking.
2509
- - Integrate /booking on the customer domain through withSiteplane(nextConfig, { booking: { site: "<site-id>" } }); use the immutable Site ID supplied by Siteplane.
2510
- - Use a normal <a href="/booking"> link, not next/link, an iframe or an embed script.
2511
- - Preserve existing rewrites. Booking-only must not require Editor setup or siteplane.config.json.
2512
- - 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.
2513
- - Preserve customer CSP and middleware; explain required Siteplane/Stripe permissions and exclude /booking from customer middleware.
2514
- - Do not write setup tokens, project CLI tokens or private keys into source files.
2515
- - Run npx siteplane booking check, npx siteplane booking sync and npx siteplane booking test after setup.
2516
- - booking test stays in test_mode; live booking only starts after explicit dashboard activation.
2517
- `;
2518
- function bookingSkillTemplate(agentName) {
2519
- return `# Siteplane Booking Skill
2520
-
2521
- Use this skill in ${agentName} before integrating Siteplane Booking at /booking.
2522
-
2523
- ${bookingRulesTemplate}`;
2524
- }
2525
- var bookingCursorRulesTemplate = `---
2526
- description: Siteplane Booking rules
2527
- alwaysApply: true
2528
- ---
2529
-
2530
- ${bookingRulesTemplate}`;
2531
-
2532
- // ../cli/dist/commands/booking/sync.js
2533
- async function bookingSyncCommand(input) {
2534
- const redacted = validateBookingManifestInput(input.manifest);
2535
- const fetcher = input.fetchImpl ?? fetch;
2536
- return fetcher(`${input.config.apiBaseUrl}/api/cli/booking/sync`, {
2537
- method: "POST",
2538
- headers: createBookingCliRequestHeaders(input.config),
2539
- body: JSON.stringify({
2540
- siteId: input.config.siteId,
2541
- source: "cli",
2542
- manifest: redacted.manifest
2543
- })
2544
- });
2545
- }
2546
- function createBookingCliRequestHeaders(config) {
2547
- const headers = {
2548
- authorization: `Bearer ${config.accessToken}`,
2549
- "content-type": "application/json"
2550
- };
2551
- const bypassSecret = config.vercelAutomationBypassSecret?.trim();
2552
- if (bypassSecret) {
2553
- headers["x-vercel-protection-bypass"] = bypassSecret;
2554
- }
2555
- return headers;
102
+ return Object.fromEntries(keys.filter((key) => key in value).map((key) => [key, value[key]]));
2556
103
  }
2557
-
2558
- // ../cli/dist/commands/booking/test.js
2559
- async function bookingTestCommand(input) {
2560
- const fetcher = input.fetchImpl ?? fetch;
2561
- const booking = bookingCreateRequestSchema.parse(input.booking);
2562
- return fetcher(`${input.config.apiBaseUrl}/api/cli/booking/test`, {
2563
- method: "POST",
2564
- headers: createBookingCliRequestHeaders(input.config),
2565
- body: JSON.stringify({
2566
- siteId: input.config.siteId,
2567
- mode: "test",
2568
- ...input.manifest ? { manifest: input.manifest } : {},
2569
- booking
2570
- })
2571
- });
104
+ function codePoints(value) {
105
+ return Array.from(value).length;
2572
106
  }
2573
-
2574
- // ../cli/dist/commands/export.js
2575
- async function exportCommand(input) {
2576
- requireContentExportScope(input.tokenScopes);
2577
- const values = await input.readPublishedValues();
2578
- if (input.format === "prompt") {
2579
- return {
2580
- kind: "prompt",
2581
- output: Object.entries(values).map(([fieldId, value]) => `${fieldId}: ${JSON.stringify(value)}`).join("\n")
2582
- };
2583
- }
2584
- return {
2585
- kind: "json",
2586
- values
2587
- };
2588
- }
2589
- function requireContentExportScope(scopes) {
2590
- if (!scopes?.includes("content:export")) {
2591
- throw new Error("A Project Connection with content:export is required.");
2592
- }
107
+ function isRecord(value) {
108
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2593
109
  }
2594
110
 
2595
- // ../cli/dist/config/project-config.js
2596
- import { access as access2, chmod, open, readFile as readFile5, rename, rm } from "fs/promises";
2597
- import { randomUUID as randomUUID2 } from "crypto";
2598
- import { join as join4 } from "path";
2599
- import { z as z31 } from "zod";
2600
- var siteplaneProjectConfigSchema = z31.object({
2601
- version: z31.literal(2),
2602
- apiBaseUrl: z31.string().url(),
2603
- siteId: z31.string().uuid(),
2604
- publicSiteKeyId: z31.string().uuid(),
2605
- publicSiteKey: z31.string().trim().min(1),
2606
- runId: z31.string().uuid(),
2607
- appDirectory: z31.string().min(1),
2608
- taskContractVersion: z31.literal("siteplane.setup-task.v2"),
2609
- adminProtocolVersion: z31.literal(2),
2610
- packages: siteSetupPackagesSchema,
2611
- fieldContractHash: z31.string().regex(/^sha256:[0-9a-f]{64}$/iu).optional()
2612
- }).strict();
2613
- async function readProjectPackageJson(projectDir) {
2614
- return JSON.parse(await readFile5(join4(projectDir, "package.json"), "utf8"));
2615
- }
2616
- async function detectNextProject(projectDir) {
2617
- const packageJson = await readProjectPackageJson(projectDir).catch(() => null);
2618
- if (packageJson?.dependencies?.next || packageJson?.devDependencies?.next) {
2619
- return true;
2620
- }
2621
- for (const fileName of [
2622
- "next.config.js",
2623
- "next.config.mjs",
2624
- "next.config.ts"
2625
- ]) {
111
+ // src/runtime/fields.ts
112
+ function createFieldReaders(loadValues) {
113
+ async function read(type, fieldId, fallback) {
2626
114
  try {
2627
- await access2(join4(projectDir, fileName));
2628
- return true;
115
+ const values = await loadValues();
116
+ if (!Object.prototype.hasOwnProperty.call(values, fieldId)) return fallback;
117
+ return readFieldValue(type, values[fieldId]) ?? fallback;
2629
118
  } catch {
119
+ return fallback;
2630
120
  }
2631
121
  }
2632
- return false;
2633
- }
2634
- async function writeProjectConfig(projectDir, config) {
2635
- const path = join4(projectDir, "siteplane.config.json");
2636
- const parsed = siteplaneProjectConfigSchema.parse(config);
2637
- await writeJsonAtomically(path, parsed, 420);
2638
- return path;
2639
- }
2640
- async function readProjectConfig(projectDir) {
2641
- return siteplaneProjectConfigSchema.parse(JSON.parse(await readFile5(join4(projectDir, "siteplane.config.json"), "utf8")));
2642
- }
2643
- async function writeJsonAtomically(path, value, mode) {
2644
- const temporaryPath = `${path}.${randomUUID2()}.tmp`;
2645
- const file = await open(temporaryPath, "wx", mode);
2646
- try {
2647
- await file.writeFile(`${JSON.stringify(value, null, 2)}
2648
- `, "utf8");
2649
- await file.sync();
2650
- } catch (error) {
2651
- await file.close();
2652
- await rm(temporaryPath, { force: true });
2653
- throw error;
2654
- }
2655
- await file.close();
2656
- try {
2657
- await rename(temporaryPath, path);
2658
- await chmod(path, mode);
2659
- } catch (error) {
2660
- await rm(temporaryPath, { force: true });
2661
- throw error;
2662
- }
2663
- }
2664
-
2665
- // ../cli/dist/config/credentials.js
2666
- import { execFile } from "child_process";
2667
- import { randomUUID as randomUUID3 } from "crypto";
2668
- import { chmod as chmod2, lstat, mkdir as mkdir5, open as open2, readFile as readFile6, rename as rename2, rm as rm2 } from "fs/promises";
2669
- import { dirname as dirname6, join as join5, relative } from "path";
2670
- import { promisify } from "util";
2671
- import { z as z32 } from "zod";
2672
- var localSetupInstallationSchema = z32.object({
2673
- key: z32.string().regex(/^[A-Za-z0-9_-]{43}$/u),
2674
- idempotencyKey: z32.string().uuid(),
2675
- apiBaseUrl: z32.string().url(),
2676
- request: setupInstallationRequestSchema,
2677
- bootstrapAcknowledged: z32.boolean()
2678
- }).strict();
2679
- var siteplaneCredentialsSchema = z32.object({
2680
- accessToken: z32.string().trim().min(1),
2681
- siteRevalidationSecret: z32.string().trim().min(1),
2682
- installation: localSetupInstallationSchema.optional(),
2683
- claimReceipt: setupClaimReceiptSchema.optional(),
2684
- adminSession: z32.object({
2685
- secret: z32.string().regex(/^[A-Za-z0-9_-]{43}$/u),
2686
- generation: z32.string().uuid()
2687
- }).strict().optional()
2688
- }).strict();
2689
- var localSetupCredentialsSchema = z32.union([
2690
- siteplaneCredentialsSchema,
2691
- z32.object({ installation: localSetupInstallationSchema }).strict()
2692
- ]);
2693
- async function assertLocalCredentialsPathSafe(projectDir, options = {}) {
2694
- const path = join5(projectDir, ".siteplane/credentials.json");
2695
- await assertCredentialFilesystemSafe(projectDir);
2696
- const isTrackedFile = options.isTrackedFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "ls-files"));
2697
- const isIgnoredFile = options.isIgnoredFile ?? ((targetPath) => gitPathMatches(projectDir, targetPath, "check-ignore"));
2698
- if (await isTrackedFile(path)) {
2699
- throw new Error("Refusing to write Siteplane credentials into a tracked file.");
2700
- }
2701
- if (!await isIgnoredFile(path)) {
2702
- throw new Error("Add .siteplane/credentials.json to .gitignore before running Siteplane init.");
2703
- }
2704
- return path;
2705
- }
2706
- async function assertCredentialFilesystemSafe(projectDir) {
2707
- for (const [path, directory, mode] of [
2708
- [projectDir, true, null],
2709
- [join5(projectDir, ".siteplane"), true, 448],
2710
- [join5(projectDir, ".siteplane/credentials.json"), false, 384]
2711
- ]) {
2712
- const stat = await lstat(path).catch((error) => {
2713
- if (error.code === "ENOENT")
2714
- return null;
2715
- throw error;
2716
- });
2717
- if (!stat)
2718
- continue;
2719
- if (stat.isSymbolicLink() || (directory ? !stat.isDirectory() : !stat.isFile())) {
2720
- throw new Error("Siteplane credential paths must not contain symlinks or unexpected file types.");
2721
- }
2722
- if (mode !== null && (stat.mode & 511) !== mode) {
2723
- throw new Error(`Siteplane credential ${directory ? "directory" : "file"} permissions must be ${mode.toString(8)} before setup.`);
2724
- }
2725
- }
2726
- }
2727
- async function writeLocalCredentials(projectDir, credentials, options = {}) {
2728
- return writeLocalSetupCredentials(projectDir, siteplaneCredentialsSchema.parse(credentials), options);
2729
- }
2730
- async function writeLocalSetupCredentials(projectDir, credentials, options = {}) {
2731
- const path = await assertLocalCredentialsPathSafe(projectDir, options);
2732
- const parsed = localSetupCredentialsSchema.parse(credentials);
2733
- await mkdir5(dirname6(path), { recursive: true, mode: 448 });
2734
- await writeCredentialsAtomically(path, parsed);
2735
- return path;
2736
- }
2737
- async function readLocalCredentials(projectDir) {
2738
- const credentials = await readLocalSetupCredentials(projectDir);
2739
- if (!("accessToken" in credentials)) {
2740
- throw new Error("setup_exchange_pending: Run siteplane setup start to finish the stored installation exchange.");
2741
- }
2742
- return credentials;
2743
- }
2744
- async function readLocalSetupCredentials(projectDir) {
2745
- await assertCredentialFilesystemSafe(projectDir);
2746
- return localSetupCredentialsSchema.parse(JSON.parse(await readFile6(join5(projectDir, ".siteplane/credentials.json"), "utf8")));
2747
- }
2748
- async function writeCredentialsAtomically(path, credentials) {
2749
- const temporaryPath = `${path}.${randomUUID3()}.tmp`;
2750
- const file = await open2(temporaryPath, "wx", 384);
2751
- try {
2752
- await file.writeFile(`${JSON.stringify(credentials, null, 2)}
2753
- `, "utf8");
2754
- await file.sync();
2755
- } catch (error) {
2756
- await file.close();
2757
- await rm2(temporaryPath, { force: true });
2758
- throw error;
2759
- }
2760
- await file.close();
2761
- try {
2762
- await rename2(temporaryPath, path);
2763
- await chmod2(path, 384);
2764
- const directory = await open2(dirname6(path), "r");
2765
- try {
2766
- await directory.sync();
2767
- } finally {
2768
- await directory.close();
2769
- }
2770
- } catch (error) {
2771
- await rm2(temporaryPath, { force: true });
2772
- throw error;
2773
- }
2774
- }
2775
- var execFileAsync = promisify(execFile);
2776
- async function gitPathMatches(projectDir, path, command) {
2777
- const args = command === "check-ignore" ? ["check-ignore", "--quiet", relative(projectDir, path)] : ["ls-files", "--error-unmatch", relative(projectDir, path)];
2778
- try {
2779
- await execFileAsync("git", args, { cwd: projectDir });
2780
- return true;
2781
- } catch {
2782
- return false;
2783
- }
2784
- }
2785
-
2786
- // ../cli/dist/commands/init.js
2787
- import { access as access4 } from "fs/promises";
2788
- import { join as join8, relative as relative3 } from "path";
2789
- import { z as z35 } from "zod";
2790
-
2791
- // ../cli/dist/commands/setup-preflight.js
2792
- import { createHash as createHash2 } from "crypto";
2793
- import semver from "semver";
2794
- import { minimatch } from "minimatch";
2795
- import { parse as parseYaml } from "yaml";
2796
-
2797
- // ../cli/dist/config/installed-package.js
2798
- import { createRequire } from "module";
2799
- import { readFile as readFile7 } from "fs/promises";
2800
- import { join as join6 } from "path";
2801
- import { z as z33 } from "zod";
2802
- var packageSchema = z33.object({
2803
- name: z33.string().optional(),
2804
- version: z33.string(),
2805
- peerDependencies: z33.record(z33.string(), z33.string()).optional()
2806
- });
2807
- async function readInstalledPackage(projectDir, name2) {
2808
- const require2 = createRequire(join6(projectDir, "package.json"));
2809
- for (const directory of require2.resolve.paths(name2) ?? []) {
2810
- try {
2811
- return packageSchema.parse(JSON.parse(await readFile7(join6(directory, name2, "package.json"), "utf8")));
2812
- } catch (error) {
2813
- if (error.code !== "ENOENT")
2814
- throw error;
2815
- }
2816
- }
2817
- throw new Error(`Install ${name2} with the canonical package manager before setup.`);
2818
- }
2819
-
2820
- // ../cli/dist/commands/setup-preflight.js
2821
- import { access as access3, readFile as readFile8, realpath, readdir, readlink } from "fs/promises";
2822
- import { dirname as dirname7, join as join7, relative as relative2, resolve, sep } from "path";
2823
- import { z as z34 } from "zod";
2824
-
2825
- // ../cli/dist/commands/setup-process.js
2826
- import { spawn } from "child_process";
2827
- var SetupFailure = class extends Error {
2828
- code;
2829
- constructor(code, message) {
2830
- super(message);
2831
- this.code = code;
2832
- }
2833
- };
2834
- async function setupProcess(binary, args, options) {
2835
- return new Promise((resolve4, reject) => {
2836
- const child = spawn(binary, args, {
2837
- cwd: options.cwd,
2838
- env: process.env,
2839
- stdio: ["pipe", "pipe", "pipe"]
2840
- });
2841
- const chunks = [];
2842
- const errors = [];
2843
- let errorBytes = 0;
2844
- let bytes = 0;
2845
- let exceeded = false;
2846
- const timer = setTimeout(() => {
2847
- exceeded = true;
2848
- child.kill("SIGKILL");
2849
- }, options.timeoutMs ?? 12e4);
2850
- const capture = (chunk) => {
2851
- bytes += chunk.length;
2852
- if (bytes > 4 * 1024 * 1024) {
2853
- exceeded = true;
2854
- child.kill("SIGKILL");
2855
- } else
2856
- chunks.push(chunk);
2857
- };
2858
- child.stdout.on("data", capture);
2859
- child.stderr.on("data", (chunk) => {
2860
- errorBytes += chunk.length;
2861
- if (errorBytes <= 4 * 1024 * 1024)
2862
- errors.push(chunk);
2863
- else {
2864
- exceeded = true;
2865
- child.kill("SIGKILL");
2866
- }
2867
- });
2868
- child.on("error", () => {
2869
- clearTimeout(timer);
2870
- reject(new SetupFailure("local_tool_unavailable", `${binary} could not be started. Check the local installation and access.`));
2871
- });
2872
- child.on("close", (code) => {
2873
- clearTimeout(timer);
2874
- if (exceeded)
2875
- reject(new SetupFailure("provider_timeout", "The operation exceeded its time or response limit; inspect the existing operation before retrying."));
2876
- else if (code !== 0) {
2877
- const diagnostic = Buffer.concat([...chunks, ...errors]).toString("utf8");
2878
- if (/\b(?:401|403|unauthorized|forbidden|not authenticated|not authorized|login required|E401|E403)\b/iu.test(diagnostic))
2879
- reject(new SetupFailure("provider_access_denied", `${binary} denied access. Restore the existing local login and project/package permissions before retrying.`));
2880
- else if (/\b(?:ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|ECONNREFUSED|429|502|503|504)\b/iu.test(diagnostic))
2881
- reject(new SetupFailure("provider_transport_failed", `${binary} could not reach its provider. Inspect the existing operation before retrying.`));
2882
- else
2883
- reject(new SetupFailure("local_command_failed", `${binary} failed. Check its local login, permissions and project configuration.`));
2884
- } else
2885
- resolve4(Buffer.concat(options.includeStderr ? [...chunks, ...errors] : chunks).toString("utf8"));
2886
- });
2887
- child.stdin.on("error", () => {
2888
- });
2889
- child.stdin.end(options.input);
2890
- });
2891
- }
2892
- async function setupVercelApi(cwd, endpoint, body, method, options) {
2893
- const args = ["api", endpoint, "--raw"];
2894
- if (body !== void 0)
2895
- args.push("--method", method ?? "POST", "--input", "-");
2896
- else if (method)
2897
- args.push("--method", method);
2898
- let output = "";
2899
- for (let attempt = 0; attempt < 3; attempt++) {
2900
- const remaining = (options?.deadline ?? Date.now() + 3e4) - Date.now();
2901
- if (remaining <= 0)
2902
- throw new SetupFailure("provider_deadline_exceeded", "The provider deadline expired; inspect the recorded operation before continuing.");
2903
- try {
2904
- output = await setupProcess("vercel", args, {
2905
- cwd,
2906
- timeoutMs: Math.min(3e4, remaining),
2907
- ...body === void 0 ? {} : { input: JSON.stringify(body) }
2908
- });
2909
- break;
2910
- } catch (error) {
2911
- if (!(error instanceof SetupFailure) || error.code !== "provider_transport_failed" || attempt === 2)
2912
- throw error;
2913
- await new Promise((resolve4) => setTimeout(resolve4, Math.min(1e3 * 2 ** attempt, Math.max(0, (options?.deadline ?? Date.now() + 2e3) - Date.now()))));
2914
- }
2915
- }
2916
- try {
2917
- return JSON.parse(output);
2918
- } catch {
2919
- throw new SetupFailure("invalid_provider_response", "Vercel did not return valid JSON for the bound project.");
2920
- }
2921
- }
2922
-
2923
- // ../cli/dist/commands/setup-preflight.js
2924
- var manifestSchema = z34.object({
2925
- packageManager: z34.string().optional(),
2926
- engines: z34.object({ node: z34.string().optional() }).optional(),
2927
- dependencies: z34.record(z34.string(), z34.string()).optional(),
2928
- devDependencies: z34.record(z34.string(), z34.string()).optional(),
2929
- scripts: z34.record(z34.string(), z34.string()).optional(),
2930
- workspaces: z34.unknown().optional()
2931
- });
2932
- var vercelProjectSchema = z34.object({
2933
- id: z34.string(),
2934
- accountId: z34.string(),
2935
- name: z34.string(),
2936
- nodeVersion: z34.string().nullable().optional(),
2937
- rootDirectory: z34.string().nullable().optional(),
2938
- framework: z34.string().nullable().optional(),
2939
- installCommand: z34.string().nullable().optional(),
2940
- buildCommand: z34.string().nullable().optional(),
2941
- link: z34.object({
2942
- type: z34.string(),
2943
- repo: z34.string().optional(),
2944
- repoId: z34.union([z34.string(), z34.number()]).optional(),
2945
- org: z34.string().optional(),
2946
- productionBranch: z34.string().optional()
2947
- }).nullable().optional()
2948
- });
2949
- var exists = async (path) => access3(path).then(() => true, () => false);
2950
- var fail = (code, message) => {
2951
- throw new SetupFailure(code, message);
2952
- };
2953
- var stable = (version2, major) => new RegExp(`^${major}\\.\\d+\\.\\d+$`, "u").test(version2);
2954
- async function inspectSetupLocalProject(projectDir) {
2955
- const projectDirectory = await realpath(resolve(projectDir));
2956
- const manifest = manifestSchema.parse(JSON.parse(await readFile8(join7(projectDirectory, "package.json"), "utf8")));
2957
- const apps = (await Promise.all(["app", "src/app"].map(async (path) => await exists(join7(projectDirectory, path)) ? path : null))).filter((path) => path !== null);
2958
- if (apps.length !== 1)
2959
- fail("ambiguous_app_directory", "Select one Next.js App Router application with exactly one app/ or src/app/ directory.");
2960
- const repositoryRoot = (await setupProcess("git", ["rev-parse", "--show-toplevel"], {
2961
- cwd: projectDirectory
2962
- })).trim();
2963
- const tracked = await setupProcess("git", ["ls-files", "--stage", "-z"], {
2964
- cwd: repositoryRoot
2965
- });
2966
- for (const entry of tracked.split("\0").filter(Boolean)) {
2967
- if (entry.startsWith("160000 "))
2968
- fail("git_submodule_conflict", "The repository contains Git submodules. Resolve the explicit deployment source boundary before setup; the CLI will not copy external repositories.");
2969
- if (!entry.startsWith("120000 "))
2970
- continue;
2971
- const path = join7(repositoryRoot, entry.slice(entry.indexOf(" ") + 1));
2972
- const target = resolve(dirname7(path), await readlink(path));
2973
- const bound = relative2(repositoryRoot, target);
2974
- if (bound.startsWith("..") || bound.startsWith(sep))
2975
- 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.");
2976
- }
2977
- let lockfileRoot = projectDirectory;
2978
- const lockNames = [
2979
- "package-lock.json",
2980
- "npm-shrinkwrap.json",
2981
- "pnpm-lock.yaml",
2982
- "yarn.lock",
2983
- "bun.lock",
2984
- "bun.lockb"
2985
- ];
2986
- let locks = [];
2987
- for (; ; ) {
2988
- locks = (await Promise.all(lockNames.map(async (name3) => await exists(join7(lockfileRoot, name3)) ? name3 : null))).filter((name3) => name3 !== null);
2989
- if (locks.length || lockfileRoot === repositoryRoot || dirname7(lockfileRoot) === lockfileRoot)
2990
- break;
2991
- lockfileRoot = dirname7(lockfileRoot);
2992
- }
2993
- if (locks.length > 1)
2994
- fail("conflicting_lockfiles", "Resolve conflicting package-manager lockfiles before setup; Siteplane does not replace them.");
2995
- if (!locks.length)
2996
- fail("lockfile_missing", "Install the existing application with its chosen package manager to create one canonical lockfile.");
2997
- const lockName = locks[0];
2998
- if (!["package-lock.json", "pnpm-lock.yaml"].includes(lockName))
2999
- fail("unsupported_package_manager", "This setup supports npm 10 or pnpm 9/10 with their canonical lockfile.");
3000
- const rootManifest = manifestSchema.parse(JSON.parse(await readFile8(join7(lockfileRoot, "package.json"), "utf8")));
3001
- if (lockfileRoot !== projectDirectory) {
3002
- const workspaceFile = join7(lockfileRoot, "pnpm-workspace.yaml");
3003
- 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([
3004
- z34.array(z34.string()),
3005
- z34.object({ packages: z34.array(z34.string()) }).transform((value) => value.packages)
3006
- ]).parse(rootManifest.workspaces);
3007
- const selected = relative2(lockfileRoot, projectDirectory).split(sep).join("/");
3008
- if (!workspace.some((pattern) => !pattern.startsWith("!") && minimatch(selected, pattern)) || workspace.some((pattern) => pattern.startsWith("!") && minimatch(selected, pattern.slice(1))))
3009
- fail("unbound_workspace_app", "The selected application is excluded from the canonical lockfile's workspace packages. Select its actual application root.");
3010
- }
3011
- for (let ancestor = dirname7(lockfileRoot); ancestor.startsWith(repositoryRoot + sep) || ancestor === repositoryRoot; ancestor = dirname7(ancestor)) {
3012
- const ancestorLocks = await Promise.all(lockNames.map((name3) => exists(join7(ancestor, name3))));
3013
- if (ancestorLocks.some(Boolean))
3014
- fail("ambiguous_lockfile_root", "Both the selected package and its repository ancestors contain lockfiles. Select one canonical workspace resolution before setup.");
3015
- if (ancestor === repositoryRoot)
3016
- break;
3017
- }
3018
- const lockText = await readFile8(join7(lockfileRoot, lockName), "utf8");
3019
- const npmLock = lockName === "package-lock.json" ? z34.object({
3020
- lockfileVersion: z34.number(),
3021
- packages: z34.record(z34.string(), z34.object({
3022
- version: z34.string().optional(),
3023
- peerDependencies: z34.record(z34.string(), z34.string()).optional()
3024
- })).optional()
3025
- }).parse(JSON.parse(lockText)) : null;
3026
- async function version2(name3) {
3027
- try {
3028
- return (await readInstalledPackage(projectDirectory, name3)).version;
3029
- } catch {
3030
- const resolved = npmLock?.packages?.[`node_modules/${name3}`]?.version;
3031
- if (resolved)
3032
- return resolved;
3033
- return fail("dependencies_not_installed", `Install the existing ${name3} dependency using the canonical lockfile before setup.`);
3034
- }
3035
- }
3036
- const [nextVersion, reactVersion, reactDomVersion] = await Promise.all([
3037
- version2("next"),
3038
- version2("react"),
3039
- version2("react-dom")
3040
- ]);
3041
- if (!stable(nextVersion, 16))
3042
- fail("unsupported_next_version", "Setup supports stable Next.js 16 App Router projects. Framework migration requires a separate owner decision.");
3043
- if (!stable(reactVersion, 19) || reactDomVersion !== reactVersion)
3044
- fail("react_version_conflict", "Use the same stable React 19/react-dom version compatible with the installed Next.js peers.");
3045
- if (!stable(process.versions.node, 22))
3046
- fail("unsupported_node_version", "Run setup under Node.js 22; this does not change your framework or package-manager versions.");
3047
- const nextMetadata = await readInstalledPackage(projectDirectory, "next").catch(() => npmLock?.packages?.["node_modules/next"] ?? null);
3048
- const peers = nextMetadata?.peerDependencies;
3049
- if (!peers?.react || !peers["react-dom"])
3050
- fail("next_peer_metadata_missing", "Install the locked Next.js dependency before setup so its actual React peer requirements can be checked.");
3051
- if (!semver.satisfies(reactVersion, peers.react) || !semver.satisfies(reactDomVersion, peers["react-dom"]))
3052
- fail("react_peer_conflict", "The installed React pair does not satisfy the installed Next.js peer requirements. Choose a compatible pair explicitly.");
3053
- if (manifest.engines?.node && !semver.satisfies(process.versions.node, manifest.engines.node))
3054
- fail("node_engine_conflict", "The selected application's Node engine declaration excludes the active supported Node.js 22 runtime.");
3055
- const name2 = lockName === "package-lock.json" ? "npm" : "pnpm";
3056
- const declared = rootManifest.packageManager ?? manifest.packageManager ?? null;
3057
- if (rootManifest.packageManager && manifest.packageManager && rootManifest.packageManager !== manifest.packageManager)
3058
- fail("package_manager_conflict", "Application and workspace packageManager declarations disagree.");
3059
- if (declared && !new RegExp(`^${name2}@\\d+\\.\\d+\\.\\d+$`, "u").test(declared))
3060
- fail("package_manager_conflict", "Declare an exact supported npm/pnpm packageManager version matching the canonical lockfile.");
3061
- const localVersion = (await setupProcess(declared ? "npx" : name2, declared ? ["--yes", "--package", declared, name2, "--version"] : ["--version"], { cwd: lockfileRoot })).trim();
3062
- if (!(name2 === "npm" ? stable(localVersion, 10) : stable(localVersion, 9) || stable(localVersion, 10)))
3063
- fail("unsupported_package_manager_version", "Use npm 10 or pnpm 9/10; other versions are outside the initial setup support range.");
3064
- if (declared && declared !== `${name2}@${localVersion}`)
3065
- fail("package_manager_conflict", "The actual local package-manager version differs from the project's exact packageManager declaration. Select the declared tool without rewriting the lockfile.");
3066
- const format = npmLock ? String(npmLock.lockfileVersion) : /^lockfileVersion:\s*['"]?([\d.]+)/mu.exec(lockText)?.[1];
3067
- if (name2 === "npm" && format !== "3" || name2 === "pnpm" && format !== "9.0" && format !== "9")
3068
- fail("lockfile_format_conflict", "The canonical lockfile format does not match npm 10 or pnpm 9/10.");
3069
- const sourceConflicts = [];
3070
- for (const file of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
3071
- if (!await exists(join7(projectDirectory, file)))
3072
- continue;
3073
- const source = await readFile8(join7(projectDirectory, file), "utf8");
3074
- if (/output\s*:\s*['"]export['"]/u.test(source))
3075
- sourceConflicts.push("static_export");
3076
- if (/\bbasePath\s*:/u.test(source))
3077
- sourceConflicts.push("base_path");
3078
- if (/\bloaderFile\s*:|\bloader\s*:\s*['"](?:custom|imgix|cloudinary|akamai)['"]/u.test(source))
3079
- sourceConflicts.push(`inspect_image_loader:${file}`);
3080
- }
3081
- if (sourceConflicts.some((conflict) => conflict === "static_export" || conflict === "base_path"))
3082
- fail("unsupported_server_configuration", "Resolve static export/basePath configuration explicitly; Siteplane requires its server-side admin and revalidation handlers.");
3083
- for (const name3 of [
3084
- "middleware.ts",
3085
- "middleware.js",
3086
- "proxy.ts",
3087
- "proxy.js",
3088
- "src/middleware.ts",
3089
- "src/middleware.js",
3090
- "src/proxy.ts",
3091
- "src/proxy.js"
3092
- ]) {
3093
- if (await exists(join7(projectDirectory, name3))) {
3094
- sourceConflicts.push(`inspect_routing:${name3}`);
3095
- if (await readlink(join7(projectDirectory, name3)).catch(() => null))
3096
- continue;
3097
- const policySource = await readFile8(join7(projectDirectory, name3), "utf8");
3098
- if (/Content-Security-Policy|img-src|default-src/iu.test(policySource))
3099
- sourceConflicts.push(`inspect_image_csp:${name3}`);
3100
- }
3101
- }
3102
- async function inspectSource(directory) {
3103
- for (const entry of await readdir(directory, { withFileTypes: true })) {
3104
- if (entry.isSymbolicLink() || ["node_modules", ".git", ".next", ".siteplane", ".vercel"].includes(entry.name))
3105
- continue;
3106
- const path = join7(directory, entry.name);
3107
- if (entry.isDirectory()) {
3108
- await inspectSource(path);
3109
- continue;
3110
- }
3111
- if (!/\.[cm]?[jt]sx?$/u.test(entry.name))
3112
- continue;
3113
- const source = await readFile8(path, "utf8");
3114
- if (/Content-Security-Policy|img-src|default-src/iu.test(source))
3115
- sourceConflicts.push(`inspect_image_csp:${relative2(projectDirectory, path)}`);
3116
- if (/from\s*["']next\/image["']/u.test(source))
3117
- sourceConflicts.push(`inspect_image_policy:${relative2(projectDirectory, path)}`);
3118
- if (/\b(?:Cookiebot|OneTrust|cookieyes|consentManager|cookieConsent)\b/iu.test(source))
3119
- sourceConflicts.push(`inspect_existing_consent:${relative2(projectDirectory, path)}`);
3120
- if (/from\s*["']next\/image["']/u.test(source) && semver.lt(nextVersion, "16.3.3"))
3121
- fail("next_security_advisory", `Next.js ${nextVersion} uses image optimization affected by the August 2026 AVIF advisory. Review https://nextjs.org/blog/august-2026-security-release and explicitly update the affected dependency before setup; no framework upgrade was performed.`);
3122
- if (/["']use server["']/u.test(source) && semver.lt(nextVersion, "16.2.11"))
3123
- 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.`);
3124
- }
3125
- }
3126
- await inspectSource(join7(projectDirectory, apps[0]));
3127
- const gitRead = async (args) => setupProcess("git", args, { cwd: projectDirectory }).then((value) => value.trim(), () => null);
3128
- return {
3129
- projectDirectory,
3130
- repositoryRoot,
3131
- lockfileRoot,
3132
- appDirectory: apps[0],
3133
- nextVersion,
3134
- reactVersion,
3135
- nodeVersion: process.versions.node,
3136
- packageManager: { name: name2, version: localVersion, declared },
3137
- lockfile: {
3138
- path: relative2(repositoryRoot, join7(lockfileRoot, lockName)),
3139
- format,
3140
- sha256: createHash2("sha256").update(lockText).digest("hex")
3141
- },
3142
- git: {
3143
- branch: await gitRead(["branch", "--show-current"]),
3144
- revision: await gitRead(["rev-parse", "HEAD"]),
3145
- remote: safeGitRemote(await gitRead(["remote", "get-url", "origin"])),
3146
- changes: (await gitRead(["status", "--porcelain=v1", "--untracked-files=all"]))?.split("\n").filter(Boolean) ?? []
3147
- },
3148
- sourceConflicts
3149
- };
3150
- }
3151
- async function setupPreflightCommand(input) {
3152
- let local;
3153
- try {
3154
- local = await inspectSetupLocalProject(input.projectDir);
3155
- await assertLocalCredentialsPathSafe(input.projectDir);
3156
- let linkDirectory = local.projectDirectory;
3157
- while (!await exists(join7(linkDirectory, ".vercel/project.json")) && linkDirectory !== local.repositoryRoot && dirname7(linkDirectory) !== linkDirectory)
3158
- linkDirectory = dirname7(linkDirectory);
3159
- if (!await exists(join7(linkDirectory, ".vercel/project.json")))
3160
- fail("vercel_project_not_linked", "Link this application to its intended Vercel project before setup; Siteplane will not guess a target.");
3161
- const linked = z34.object({
3162
- projectId: z34.string().regex(/^prj_[A-Za-z0-9]+$/u),
3163
- orgId: z34.string().regex(/^(?:team|user)_[A-Za-z0-9]+$/u)
3164
- }).parse(JSON.parse(await readFile8(join7(linkDirectory, ".vercel/project.json"), "utf8")));
3165
- const project = vercelProjectSchema.parse(await setupVercelApi(linkDirectory, `/v9/projects/${linked.projectId}?teamId=${linked.orgId}`));
3166
- if (project.id !== linked.projectId || project.accountId !== linked.orgId)
3167
- fail("vercel_identity_conflict", "The provider project does not match the locally linked project and team.");
3168
- const expectedRoot = relative2(local.repositoryRoot, local.projectDirectory).split(sep).join("/");
3169
- if ((project.rootDirectory ?? "") !== expectedRoot)
3170
- fail("vercel_root_conflict", "Vercel Root Directory and the selected local app must identify the same application.");
3171
- if (project.nodeVersion !== "22.x" || project.framework !== "nextjs")
3172
- fail("vercel_framework_conflict", "The bound Vercel project must use Next.js with Node.js 22 before setup.");
3173
- if (project.link && project.link.productionBranch !== local.git.branch)
3174
- fail("vercel_production_branch_conflict", "The local branch differs from the bound Vercel Production branch.");
3175
- if (project.link?.repo && project.link.org && !local.git.remote?.replace(/\.git$/u, "").endsWith(`${project.link.org}/${project.link.repo}`))
3176
- fail("vercel_git_conflict", "The local origin repository differs from the Vercel Git connection.");
3177
- const env = z34.object({
3178
- envs: z34.array(z34.object({
3179
- key: z34.string(),
3180
- value: z34.string().optional(),
3181
- target: z34.array(z34.string()).optional()
3182
- }))
3183
- }).parse(await setupVercelApi(linkDirectory, `/v10/projects/${linked.projectId}/env?teamId=${linked.orgId}`));
3184
- const corepack = env.envs.some((item) => item.key === "ENABLE_EXPERIMENTAL_COREPACK" && item.value === "1" && item.target?.includes("production"));
3185
- const install = project.installCommand ?? null;
3186
- const selected = corepack ? "corepack" : install ? "install_override" : "automatic";
3187
- if (local.packageManager.declared && selected === "automatic")
3188
- fail("vercel_package_manager_pin_unconfirmed", "This project declares an exact packageManager but Vercel automatic selection does not bind that version. Enable its supported Corepack selection or set an exact install AND build override in the existing project, then rerun preflight. No package, lockfile or provider setting was changed.");
3189
- if (install && /\b(?:yarn|bun)\b/u.test(install))
3190
- fail("vercel_package_manager_conflict", "The Vercel install override selects an unsupported package manager.");
3191
- const overridePin = install ? /\b(npm|pnpm)@(\d+\.\d+\.\d+)\b/u.exec(install) : null;
3192
- if (overridePin && overridePin[1] !== local.packageManager.name)
3193
- fail("vercel_package_manager_conflict", "The provider override selects a different package manager than the canonical lockfile.");
3194
- const overrideFamily = install ? /(?:^|[;&|]\s*)(npm|pnpm)\s+(?:ci|install)\b/u.exec(install)?.[1] : null;
3195
- if (overrideFamily && overrideFamily !== local.packageManager.name)
3196
- fail("vercel_package_manager_conflict", "The provider install command conflicts with the canonical lockfile.");
3197
- if (overridePin && local.packageManager.declared && `${overridePin[1]}@${overridePin[2]}` !== local.packageManager.declared)
3198
- fail("vercel_package_manager_conflict", "The Vercel install override conflicts with the exact packageManager declaration.");
3199
- const buildRunners = (project.buildCommand ?? "").matchAll(/(?:^|[;&|\n])\s*(?:(?:corepack|npx(?:\s+(?:--yes|-y))?)\s+)?(npm|pnpm|yarn|bun)(?:@(\d+\.\d+\.\d+))?\s+(?:run\s+)?build\b/gu);
3200
- for (const [, family, version2] of buildRunners) {
3201
- if (family !== local.packageManager.name || version2 && local.packageManager.declared && `${family}@${version2}` !== local.packageManager.declared)
3202
- fail("vercel_package_manager_conflict", "The explicit Vercel build command conflicts with the selected package manager or its declared version. Align the existing build override and rerun preflight; no setup writes were performed.");
3203
- }
3204
- return {
3205
- status: "ready",
3206
- local,
3207
- provider: {
3208
- projectId: project.id,
3209
- teamId: project.accountId,
3210
- name: project.name,
3211
- rootDirectory: expectedRoot,
3212
- nodeVersion: project.nodeVersion,
3213
- git: project.link,
3214
- installCommand: install,
3215
- buildCommand: project.buildCommand ?? null,
3216
- packageManagerSelection: selected,
3217
- declaredPackageManager: local.packageManager.declared,
3218
- observedPackageManager: null
3219
- }
3220
- };
3221
- } catch (error) {
3222
- return {
3223
- status: "action_required",
3224
- code: error instanceof SetupFailure ? error.code : "invalid_local_project",
3225
- message: error instanceof SetupFailure ? error.message : "The selected project or provider response could not be validated. Check the application manifest and local project access.",
3226
- ...local ? { local } : {}
3227
- };
3228
- }
3229
- }
3230
- function safeGitRemote(value) {
3231
- if (!value)
3232
- return null;
3233
- if (!value.includes("://"))
3234
- return value;
3235
- try {
3236
- const url = new URL(value);
3237
- url.username = "";
3238
- url.password = "";
3239
- url.search = "";
3240
- url.hash = "";
3241
- return url.toString().replace(/\/$/u, "");
3242
- } catch {
3243
- return null;
3244
- }
3245
- }
3246
-
3247
- // ../cli/dist/commands/init.js
3248
- async function initCommand(input) {
3249
- if (!input.setupToken.trim()) {
3250
- throw new Error("A Siteplane setup token is required.");
3251
- }
3252
- if (!await detectNextProject(input.projectDir)) {
3253
- throw new Error("Siteplane init currently supports Next.js projects.");
3254
- }
3255
- await assertLocalCredentialsPathSafe(input.projectDir, {
3256
- ...input.isIgnoredFile ? { isIgnoredFile: input.isIgnoredFile } : {},
3257
- ...input.isTrackedFile ? { isTrackedFile: input.isTrackedFile } : {}
3258
- });
3259
- const preflight = await (input.preflight ?? setupPreflightCommand)({
3260
- projectDir: input.projectDir
3261
- });
3262
- if (preflight.status !== "ready")
3263
- throw new Error(`${preflight.code}: ${preflight.message}`);
3264
- const bootstrap = await bootstrapProjectConnection(input);
3265
- const paths = bootstrap.credentialPurpose === "site_setup" ? await persistSiteSetupBootstrap(input, bootstrap, relative3(preflight.local.lockfileRoot, preflight.local.projectDirectory) || ".") : await persistFeatureBootstrap(input, bootstrap);
3266
- await acknowledgeBootstrapResponse(input);
3267
122
  return {
3268
- ...paths,
3269
- nextSteps: [
3270
- "Run npx siteplane setup context and read the returned task.",
3271
- "Before source changes, briefly tell the user what Siteplane requested and what you will do.",
3272
- "Follow the returned steps through setup prepare and setup deploy --wait, which performs setup verify; stop only at ready_for_review or action_required."
3273
- ]
123
+ text: (fieldId, fallback) => read("text", fieldId, fallback),
124
+ longText: (fieldId, fallback) => read("longText", fieldId, fallback),
125
+ link: (fieldId, fallback) => read("link", fieldId, fallback),
126
+ image: (fieldId, fallback) => read("image", fieldId, fallback),
127
+ attrs
3274
128
  };
3275
129
  }
3276
- var siteSetupBootstrapDataSchema = z35.object({
3277
- credentialPurpose: z35.literal("site_setup"),
3278
- apiBaseUrl: z35.string().url(),
3279
- siteId: z35.string().uuid(),
3280
- publicSiteKeyId: z35.string().uuid(),
3281
- publicSiteKey: z35.string().trim().min(1),
3282
- accessToken: z35.string().trim().min(1),
3283
- siteRevalidationSecret: z35.string().regex(/^[A-Za-z0-9_-]{43}$/u),
3284
- runId: z35.string().uuid(),
3285
- packages: siteSetupPackagesSchema
3286
- }).strict();
3287
- var featureBootstrapDataSchema = z35.object({
3288
- credentialPurpose: z35.enum(["analytics", "booking"]),
3289
- apiBaseUrl: z35.string().url(),
3290
- siteId: z35.string().uuid(),
3291
- accessToken: z35.string().trim().min(1)
3292
- }).strict();
3293
- var bootstrapResponseSchema = z35.object({
3294
- ok: z35.literal(true),
3295
- data: z35.discriminatedUnion("credentialPurpose", [
3296
- siteSetupBootstrapDataSchema,
3297
- featureBootstrapDataSchema
3298
- ])
3299
- }).strict();
3300
- async function bootstrapProjectConnection(input) {
3301
- const fetcher = input.fetcher ?? fetch;
3302
- const existing = await access4(join8(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3303
- const response = await fetcher(`${input.apiBaseUrl.replace(/\/$/, "")}/api/cli/setup/bootstrap`, {
3304
- method: "POST",
3305
- signal: AbortSignal.timeout(2e4),
3306
- headers: createBootstrapHeaders(input),
3307
- body: JSON.stringify({
3308
- action: "bootstrap",
3309
- ...existing ? { expectedSiteId: existing.siteId, expectedRunId: existing.runId } : {},
3310
- agentClient: input.agentClient ?? "codex"
3311
- })
3312
- });
3313
- const payload = await response.json();
3314
- const parsed = bootstrapResponseSchema.safeParse(payload);
3315
- if (!response.ok || !parsed.success) {
3316
- throw new Error(readErrorMessage(payload) ?? "Siteplane init failed.");
3317
- }
3318
- return parsed.data.data;
3319
- }
3320
- async function acknowledgeBootstrapResponse(input) {
3321
- const fetcher = input.fetcher ?? fetch;
3322
- const response = await fetcher(`${input.apiBaseUrl.replace(/\/$/, "")}/api/cli/setup/bootstrap`, {
3323
- method: "POST",
3324
- signal: AbortSignal.timeout(2e4),
3325
- headers: createBootstrapHeaders(input),
3326
- body: JSON.stringify({ action: "acknowledge" })
3327
- });
3328
- if (!response.ok) {
3329
- throw new Error("Siteplane setup acknowledgement failed.");
3330
- }
3331
- }
3332
- async function persistSiteSetupBootstrap(input, bootstrap, appDirectory, installation) {
3333
- const previous = await access4(join8(input.projectDir, "siteplane.config.json")).then(() => readProjectConfig(input.projectDir), () => null);
3334
- if (previous && (previous.siteId !== bootstrap.siteId || previous.runId !== bootstrap.runId || previous.publicSiteKeyId !== bootstrap.publicSiteKeyId || previous.publicSiteKey !== bootstrap.publicSiteKey))
3335
- throw new Error("The grant does not match this local Siteplane run. Preserve this directory and choose the correct owner connection.");
3336
- const previousCredentials = previous ? await access4(join8(input.projectDir, ".siteplane/credentials.json")).then(() => readLocalSetupCredentials(input.projectDir), () => null) : null;
3337
- const credentialsPath = await writeLocalCredentials(input.projectDir, {
3338
- ...previousCredentials && "adminSession" in previousCredentials && previousCredentials.adminSession ? { adminSession: previousCredentials.adminSession } : {},
3339
- ...previousCredentials && "claimReceipt" in previousCredentials && previousCredentials.claimReceipt ? { claimReceipt: previousCredentials.claimReceipt } : {},
3340
- accessToken: bootstrap.accessToken,
3341
- siteRevalidationSecret: bootstrap.siteRevalidationSecret,
3342
- ...installation ?? previousCredentials?.installation ? { installation: installation ?? previousCredentials?.installation } : {}
3343
- }, {
3344
- ...input.isIgnoredFile ? { isIgnoredFile: input.isIgnoredFile } : {},
3345
- ...input.isTrackedFile ? { isTrackedFile: input.isTrackedFile } : {}
3346
- });
3347
- const configPath = await writeProjectConfig(input.projectDir, {
3348
- ...previous ?? {},
3349
- version: 2,
3350
- appDirectory,
3351
- runId: bootstrap.runId,
3352
- packages: bootstrap.packages,
3353
- taskContractVersion: "siteplane.setup-task.v2",
3354
- adminProtocolVersion: 2,
3355
- apiBaseUrl: bootstrap.apiBaseUrl,
3356
- siteId: bootstrap.siteId,
3357
- publicSiteKeyId: bootstrap.publicSiteKeyId,
3358
- publicSiteKey: bootstrap.publicSiteKey
3359
- });
3360
- const [credentials, config] = await Promise.all([
3361
- readLocalCredentials(input.projectDir),
3362
- readProjectConfig(input.projectDir)
3363
- ]);
3364
- if (credentials.accessToken !== bootstrap.accessToken || credentials.siteRevalidationSecret !== bootstrap.siteRevalidationSecret || config.runId !== bootstrap.runId || config.packages.siteplane !== bootstrap.packages.siteplane || config.packages.runtimeNext !== bootstrap.packages.runtimeNext || config.packages.analytics !== bootstrap.packages.analytics || config.apiBaseUrl !== bootstrap.apiBaseUrl || config.siteId !== bootstrap.siteId || config.publicSiteKeyId !== bootstrap.publicSiteKeyId || config.publicSiteKey !== bootstrap.publicSiteKey) {
3365
- throw new Error("Siteplane setup files could not be verified.");
3366
- }
3367
- return { configPath, credentialsPath };
3368
- }
3369
- async function persistFeatureBootstrap(input, bootstrap) {
3370
- const [config, existingCredentials] = await Promise.all([
3371
- readProjectConfig(input.projectDir),
3372
- readLocalCredentials(input.projectDir)
3373
- ]);
3374
- if (config.siteId !== bootstrap.siteId) {
3375
- throw new Error("The setup token belongs to a different Siteplane site.");
3376
- }
3377
- const credentialsPath = await writeLocalCredentials(input.projectDir, {
3378
- ...existingCredentials,
3379
- accessToken: bootstrap.accessToken
3380
- }, {
3381
- ...input.isIgnoredFile ? { isIgnoredFile: input.isIgnoredFile } : {},
3382
- ...input.isTrackedFile ? { isTrackedFile: input.isTrackedFile } : {}
3383
- });
3384
- const persistedCredentials = await readLocalCredentials(input.projectDir);
3385
- if (persistedCredentials.accessToken !== bootstrap.accessToken || persistedCredentials.siteRevalidationSecret !== existingCredentials.siteRevalidationSecret) {
3386
- throw new Error("Siteplane credentials could not be verified.");
3387
- }
3388
- return {
3389
- configPath: join8(input.projectDir, "siteplane.config.json"),
3390
- credentialsPath
3391
- };
130
+ function attrs(fieldId) {
131
+ return typeof fieldId === "string" ? { "data-siteplane-field": fieldId } : {};
3392
132
  }
3393
- function createBootstrapHeaders(input) {
3394
- return new Headers({
3395
- authorization: `Bearer ${input.setupToken}`,
3396
- "content-type": "application/json",
3397
- ...input.vercelAutomationBypassSecret?.trim() ? {
3398
- "x-vercel-protection-bypass": input.vercelAutomationBypassSecret.trim()
3399
- } : {}
3400
- });
3401
- }
3402
- function readErrorMessage(payload) {
3403
- if (payload && typeof payload === "object" && "error" in payload && payload.error && typeof payload.error === "object" && "message" in payload.error && typeof payload.error.message === "string") {
3404
- const code = "code" in payload.error && typeof payload.error.code === "string" ? payload.error.code : null;
3405
- return code ? `${code}: ${payload.error.message}` : payload.error.message;
3406
- }
3407
- return null;
3408
- }
3409
-
3410
- // ../cli/dist/commands/scan.js
3411
- import { readdir as readdir2 } from "fs/promises";
3412
- import { extname, join as join9 } from "path";
3413
- var defaultScanRoots = ["app", "src", "pages", "components", "lib"];
3414
- var excludedDirectories = /* @__PURE__ */ new Set([
3415
- ".git",
3416
- ".next",
3417
- ".turbo",
3418
- ".vercel",
3419
- "build",
3420
- "coverage",
3421
- "dist",
3422
- "node_modules"
3423
- ]);
3424
- var sourceExtensions = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx"]);
3425
- async function resolveScanFilePaths(filePaths, options = {}) {
3426
- if (filePaths.length > 0) {
3427
- return filePaths;
3428
- }
3429
- const projectDir = options.projectDir ?? process.cwd();
3430
- const discovered = await Promise.all(defaultScanRoots.map((root) => collectSourceFiles(join9(projectDir, root))));
3431
- return [...new Set(discovered.flat())].sort();
3432
- }
3433
- async function collectSourceFiles(directory) {
3434
- const entries = await readdir2(directory, { withFileTypes: true }).catch(() => []);
3435
- const files = [];
3436
- for (const entry of entries) {
3437
- const entryPath = join9(directory, entry.name);
3438
- if (entry.isDirectory()) {
3439
- if (!excludedDirectories.has(entry.name)) {
3440
- files.push(...await collectSourceFiles(entryPath));
3441
- }
3442
- continue;
3443
- }
3444
- if (entry.isFile() && sourceExtensions.has(extname(entry.name))) {
3445
- files.push(entryPath);
3446
- }
3447
- }
3448
- return files;
3449
- }
3450
-
3451
- // ../cli/dist/commands/site-setup.js
3452
- import { execFile as execFile2 } from "child_process";
3453
- import { readFile as readFile9 } from "fs/promises";
3454
- import { promisify as promisify2 } from "util";
3455
- import { z as z36 } from "zod";
3456
-
3457
- // ../cli/dist/scan/next-source-scan.js
3458
- import ts3 from "typescript";
3459
- import { isAbsolute, relative as relative4 } from "path";
3460
- var legacyEditableComponentPrefix = "Editable";
3461
- var editableComponentNames = new Set(["Image", "Text", "LongText", "Link"].map((name2) => `${legacyEditableComponentPrefix}${name2}`));
3462
-
3463
- // ../cli/dist/commands/site-setup.js
3464
- var execFileAsync2 = promisify2(execFile2);
3465
- var safeErrorSchema = z36.object({
3466
- code: z36.string().trim().min(1),
3467
- message: z36.string().trim().min(1)
3468
- }).passthrough();
3469
- var errorResponseSchema2 = z36.object({ ok: z36.literal(false), error: safeErrorSchema }).passthrough();
3470
- var contextDataSchema = z36.object({
3471
- task: siteSetupTaskSchema.refine((task) => task.run !== null)
3472
- }).strict();
3473
- var contextResponseSchema = z36.object({ ok: z36.literal(true), data: contextDataSchema }).strict();
3474
- var applyDataSchema = z36.object({
3475
- status: z36.enum(["applied", "ready_for_review"]),
3476
- runId: z36.string().uuid().optional(),
3477
- contractVersionId: z36.string().uuid().optional(),
3478
- fieldContractHash: z36.string().regex(/^sha256:[0-9a-f]{64}$/u),
3479
- editorDefinitionHash: z36.string().regex(/^sha256:[0-9a-f]{64}$/u).optional(),
3480
- fieldCount: z36.number().int().nonnegative().optional(),
3481
- routeCount: z36.number().int().nonnegative().optional()
3482
- }).strict();
3483
- var applyResponseSchema = z36.object({ ok: z36.literal(true), data: applyDataSchema }).strict();
3484
- var verifyDataSchema = z36.object({
3485
- status: z36.literal("ready_for_review"),
3486
- runId: z36.string().uuid().optional(),
3487
- deploymentOrigin: z36.string().url().optional(),
3488
- deploymentRevision: z36.string().optional()
3489
- }).strict();
3490
- var verifyResponseSchema = z36.object({ ok: z36.literal(true), data: verifyDataSchema }).strict();
3491
- async function siteSetupContextCommand(input) {
3492
- const response = await postSiteSetup(input, "context", {});
3493
- const parsed = contextResponseSchema.safeParse(response.payload);
3494
- if (response.ok && parsed.success) {
3495
- return { status: "ok", ...parsed.data.data };
3496
- }
3497
- return actionRequired(response.payload, "Siteplane setup context is unavailable.");
3498
- }
3499
- async function siteSetupVerifyCommand(input) {
3500
- const resolveSourceFiles = input.resolveSourceFiles ?? resolveScanFilePaths;
3501
- const readSourceFile = input.readSourceFile ?? ((path) => readFile9(path, "utf8"));
3502
- const paths = await resolveSourceFiles([], { projectDir: input.projectDir });
3503
- const sources = await Promise.all(paths.map(readSourceFile));
3504
- if (!sources.some(hasMountedFieldRuntimeBridge)) {
3505
- return {
3506
- status: "action_required",
3507
- code: "missing_field_runtime_bridge",
3508
- message: "Mount FieldRuntimeBridge from @siteplane/runtime-next/client before deployment verification."
3509
- };
3510
- }
3511
- const deploymentRevision = await (input.readRevision ?? readGitRevision)(input.projectDir);
3512
- const response = await postSiteSetup(input, "verify", {
3513
- deploymentUrl: input.deploymentUrl,
3514
- deploymentRevision,
3515
- ...input.wait ? { wait: true } : {}
3516
- });
3517
- const parsed = verifyResponseSchema.safeParse(response.payload);
3518
- if (response.ok && parsed.success) {
3519
- return parsed.data.data;
3520
- }
3521
- return actionRequired(response.payload, "Siteplane deployment verification failed.");
3522
- }
3523
- function hasMountedFieldRuntimeBridge(source) {
3524
- return /from\s+["']@siteplane\/runtime-next(?:\/client)?["']/u.test(source) && /<FieldRuntimeBridge(?:\s|\/|>)/u.test(source);
3525
- }
3526
- async function postSiteSetup(input, operation, body) {
3527
- const [config, credentials] = await Promise.all([
3528
- readProjectConfig(input.projectDir),
3529
- readLocalCredentials(input.projectDir)
3530
- ]);
3531
- try {
3532
- const response = await (input.fetcher ?? fetch)(`${config.apiBaseUrl.replace(/\/$/u, "")}/api/cli/setup/${operation}`, {
3533
- method: "POST",
3534
- signal: AbortSignal.timeout(Math.max(1, Math.min(2e4, (input.deadline ?? Date.now() + 2e4) - Date.now()))),
3535
- headers: {
3536
- authorization: `Bearer ${credentials.accessToken}`,
3537
- "content-type": "application/json",
3538
- ...input.vercelAutomationBypassSecret?.trim() ? {
3539
- "x-vercel-protection-bypass": input.vercelAutomationBypassSecret.trim()
3540
- } : {}
3541
- },
3542
- body: JSON.stringify(body)
3543
- });
3544
- const payload = await response.json().catch(() => null);
3545
- return { ok: response.ok, payload };
3546
- } catch {
3547
- return {
3548
- ok: false,
3549
- payload: {
3550
- ok: false,
3551
- error: {
3552
- code: "site_setup.transport_failed",
3553
- message: "The setup request was not acknowledged. Reload the existing task before retrying; no credential values are included."
3554
- }
3555
- }
3556
- };
3557
- }
3558
- }
3559
- function actionRequired(payload, fallbackMessage) {
3560
- const parsed = errorResponseSchema2.safeParse(payload);
3561
- return parsed.success ? {
3562
- status: "action_required",
3563
- code: parsed.data.error.code,
3564
- message: parsed.data.error.message
3565
- } : {
3566
- status: "action_required",
3567
- code: "invalid_server_response",
3568
- message: fallbackMessage
3569
- };
3570
- }
3571
- async function readGitRevision(projectDir) {
3572
- const { stdout } = await execFileAsync2("git", ["rev-parse", "HEAD"], {
3573
- cwd: projectDir,
3574
- encoding: "utf8"
3575
- });
3576
- const revision = stdout.trim();
3577
- if (!revision) {
3578
- throw new Error("A committed Git revision is required before setup verify.");
3579
- }
3580
- return revision;
3581
- }
3582
-
3583
- // ../cli/dist/commands/setup-start.js
3584
- import { randomBytes, randomUUID as randomUUID4 } from "crypto";
3585
- import { access as access5 } from "fs/promises";
3586
- import { join as join10, relative as relative5 } from "path";
3587
- import { z as z37 } from "zod";
3588
- var bootstrapResponseSchema2 = z37.object({
3589
- ok: z37.literal(true),
3590
- data: siteSetupBootstrapDataSchema
3591
- }).strict();
3592
-
3593
- // ../cli/dist/commands/setup-review.js
3594
- import { z as z38 } from "zod";
3595
- var responseSchema2 = z38.object({
3596
- ok: z38.literal(true),
3597
- data: z38.object({
3598
- reviewUrl: z38.string().url(),
3599
- expiresAt: z38.string().datetime({ offset: true })
3600
- }).strict()
3601
- }).strict();
3602
-
3603
- // ../cli/dist/commands/setup-prepare.js
3604
- 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";
3605
- import { randomUUID as randomUUID5 } from "crypto";
3606
- import { dirname as dirname8, join as join11, relative as relative6, sep as sep2 } from "path";
3607
- import ts4 from "typescript";
3608
-
3609
- // ../cli/dist/commands/setup-lock.js
3610
- import { randomUUID as randomUUID6 } from "crypto";
3611
- import { lstat as lstat3, mkdir as mkdir7, open as open4, readFile as readFile11, rm as rm4, rmdir } from "fs/promises";
3612
- import { resolve as resolve2 } from "path";
3613
- import { z as z39 } from "zod";
3614
- var ownerSchema = z39.object({ pid: z39.number().int().positive(), nonce: z39.string().uuid() }).strict();
3615
-
3616
- // ../cli/dist/config/build-provenance.js
3617
- import { createHash as createHash3 } from "crypto";
3618
- import { execFile as execFile3 } from "child_process";
3619
- import { lstat as lstat4, readFile as readFile12, writeFile as writeFile5, mkdir as mkdir8 } from "fs/promises";
3620
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join12, relative as relative7, resolve as resolve3, sep as sep3 } from "path";
3621
- import { isDeepStrictEqual, promisify as promisify3 } from "util";
3622
- import { z as z40 } from "zod";
3623
- var execute = promisify3(execFile3);
3624
- var name = ".siteplane/build-source.json";
3625
- var oid = z40.string().regex(/^[0-9a-f]{40}$/u);
3626
- var entrySchema = z40.object({
3627
- path: z40.string().min(1).max(4096),
3628
- mode: z40.enum(["100644", "100755", "120000"]),
3629
- oid
3630
- }).strict();
3631
- var schema = z40.object({
3632
- version: z40.literal(2),
3633
- revision: oid,
3634
- commit: z40.string().min(1).max(1048576),
3635
- entries: z40.array(entrySchema).min(1).max(1e5),
3636
- providerConfigurations: z40.array(z40.object({
3637
- path: z40.string().max(4096).regex(/(?:^|\/)vercel\.json$/u),
3638
- source: z40.string().max(1048576)
3639
- }).strict()).max(1e3)
3640
- }).strict();
3641
- async function writeBuildProvenance(checkout, revision) {
3642
- const commit = (await execute("git", ["cat-file", "commit", revision], {
3643
- cwd: checkout,
3644
- maxBuffer: 1048576
3645
- })).stdout;
3646
- const tree = (await execute("git", ["ls-tree", "-rz", "--full-tree", revision], {
3647
- cwd: checkout,
3648
- maxBuffer: 16777216
3649
- })).stdout;
3650
- const entries = tree.split("\0").filter(Boolean).map((line) => {
3651
- const match = /^(100644|100755|120000) blob ([0-9a-f]{40})\t([\s\S]+)$/u.exec(line);
3652
- if (!match)
3653
- throw new Error("Git submodules or unsupported tracked objects need an explicit deployment configuration.");
3654
- return { path: match[3], mode: match[1], oid: match[2] };
3655
- });
3656
- for (const entry of entries) {
3657
- if (entry.mode !== "120000")
3658
- continue;
3659
- const { readlink: readlink2 } = await import("fs/promises");
3660
- const path = join12(checkout, entry.path);
3661
- const target2 = resolve3(dirname9(path), await readlink2(path));
3662
- const bound = relative7(checkout, target2);
3663
- if (bound.startsWith("..") || isAbsolute2(bound))
3664
- throw new Error("A tracked symbolic link escapes the committed upload; resolve that source boundary before deployment.");
3665
- }
3666
- const providerConfigurations = await Promise.all(entries.filter((entry) => /(?:^|\/)vercel\.json$/u.test(entry.path)).map(async (entry) => ({
3667
- path: entry.path,
3668
- source: await readFile12(join12(checkout, entry.path), "utf8")
3669
- })));
3670
- const record = schema.parse({
3671
- version: 2,
3672
- revision,
3673
- commit,
3674
- entries,
3675
- providerConfigurations
3676
- });
3677
- const target = join12(checkout, name);
3678
- await mkdir8(dirname9(target), { recursive: true, mode: 448 });
3679
- await writeFile5(target, JSON.stringify(record), { flag: "wx", mode: 384 });
3680
- }
3681
-
3682
- // ../cli/dist/commands/setup-deploy.js
3683
- import { createHash as createHash4, randomBytes as randomBytes2, randomUUID as randomUUID7 } from "crypto";
3684
- import { access as access7, mkdir as mkdir9, mkdtemp, rm as rm5, writeFile as writeFile6 } from "fs/promises";
3685
- import { tmpdir } from "os";
3686
- import { join as join13 } from "path";
3687
- import { z as z41 } from "zod";
3688
- var envSchema = z41.object({
3689
- id: z41.string(),
3690
- key: z41.string(),
3691
- target: z41.array(z41.string()),
3692
- type: z41.string(),
3693
- comment: z41.string().optional(),
3694
- updatedAt: z41.number().optional()
3695
- });
3696
- var deploymentSchema = z41.object({
3697
- id: z41.string(),
3698
- projectId: z41.string(),
3699
- ownerId: z41.string().optional(),
3700
- target: z41.string().nullable(),
3701
- readyState: z41.string(),
3702
- createdAt: z41.number(),
3703
- url: z41.string(),
3704
- meta: z41.record(z41.string(), z41.unknown()).optional(),
3705
- gitSource: z41.object({ sha: z41.string().optional() }).nullable().optional()
3706
- });
3707
- var buildProofSchema = z41.object({
3708
- node: z41.string(),
3709
- packageManager: z41.enum(["npm", "pnpm"]),
3710
- packageManagerVersion: z41.string(),
3711
- lockfileHash: z41.string(),
3712
- revision: z41.string(),
3713
- fieldContractHash: z41.string(),
3714
- siteplane: z41.string(),
3715
- runtimeNext: z41.string(),
3716
- analytics: z41.string().optional(),
3717
- next: z41.string(),
3718
- react: z41.string()
3719
- }).strict();
3720
- var defaults = {
3721
- preflight: setupPreflightCommand,
3722
- context: siteSetupContextCommand,
3723
- api: setupVercelApi,
3724
- process: setupProcess,
3725
- verify: siteSetupVerifyCommand,
3726
- post: postSiteSetup,
3727
- writeBuildProvenance,
3728
- analyticsPublicKey: analyticsPublicKeyCommand,
3729
- now: Date.now,
3730
- pause: (milliseconds) => new Promise((resolve4) => setTimeout(resolve4, milliseconds))
3731
- };
3732
133
 
3733
- // ../cli/dist/commands/setup-claim.js
3734
- import { z as z42 } from "zod";
134
+ // src/index.ts
135
+ var siteplane = createFieldReaders(cache(loadSiteValues));
3735
136
  export {
3736
- bookingCheckCommand,
3737
- bookingInitCommand,
3738
- bookingSyncCommand,
3739
- bookingTestCommand,
3740
- exportCommand,
3741
- initCommand
137
+ siteplane
3742
138
  };