@hyprcart/app-manifest 1.0.0 → 1.0.1

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
@@ -3,16 +3,171 @@ var supportedSurfaces = [
3
3
  "storefront_block",
4
4
  "admin_surface",
5
5
  "checkout_ui",
6
+ "deterministic_function",
6
7
  "checkout_function",
7
8
  "pixel",
9
+ "event_subscription",
10
+ "background_job",
8
11
  "event",
9
12
  "flow",
10
13
  "mcp"
11
14
  ];
15
+ var storefrontBlockRenderTiers = ["static", "edge_render", "edge_stream"];
16
+ var legacyStorefrontBlockRenderTiers = ["edge-function", "edge-stream"];
17
+ var hydrationTriggers = ["load", "visible", "interaction", "idle", "manual"];
12
18
  var defaultRequiredLocales = ["en", "de"];
13
19
  function isSupportedSurface(value) {
14
20
  return supportedSurfaces.includes(value);
15
21
  }
22
+ function normalizeStorefrontBlockRenderTier(value) {
23
+ if (value === "edge-function") return "edge_render";
24
+ if (value === "edge-stream") return "edge_stream";
25
+ if (storefrontBlockRenderTiers.includes(value)) return value;
26
+ return "static";
27
+ }
28
+
29
+ // src/surface-contracts.ts
30
+ function validateExtensionSurfaceDeclarations(manifest) {
31
+ return (manifest.surfaces ?? []).map((surface, index) => validateExtensionSurface(surface, `surfaces.${index}`));
32
+ }
33
+ function validateExtensionSurface(surface, basePath = "surface") {
34
+ const diagnostics = [];
35
+ if (!surface.label || Object.keys(surface.label).length === 0) {
36
+ diagnostics.push(diagnostic("surface.label.missing", "blocking", `${basePath}.label`, "Surface must declare localized labels."));
37
+ }
38
+ if (!surface.entry?.trim()) {
39
+ diagnostics.push(diagnostic("surface.entry.missing", "blocking", `${basePath}.entry`, "Surface must declare an entry file."));
40
+ }
41
+ if (surface.type === "admin_surface") validateAdminSurface(surface, basePath, diagnostics);
42
+ if (surface.type === "checkout_ui") validateCheckoutSurface(surface, basePath, diagnostics);
43
+ if (surface.type === "deterministic_function" || surface.type === "checkout_function") validateDeterministicFunction(surface, basePath, diagnostics);
44
+ if (surface.type === "pixel") validatePixel(surface, basePath, diagnostics);
45
+ if (surface.type === "event_subscription") validateEventSubscription(surface, basePath, diagnostics);
46
+ if (surface.type === "background_job") validateBackgroundJob(surface, basePath, diagnostics);
47
+ if (surface.type === "flow" || surface.type === "event") {
48
+ diagnostics.push(
49
+ diagnostic(
50
+ "surface.flow.deferred_to_075a",
51
+ "warning",
52
+ `${basePath}.type`,
53
+ "Flow trigger/action declarations are owned by 075a and are not activated by 049c.",
54
+ "https://hyprcart.com/docs/app-platform/storefront-app-blocks-internal"
55
+ )
56
+ );
57
+ }
58
+ const blocking = diagnostics.some((entry) => entry.severity === "blocking");
59
+ return {
60
+ surfaceId: surface.id,
61
+ surfaceType: surface.type,
62
+ status: blocking ? "rejected" : surface.type === "storefront_block" ? "active" : surface.type === "flow" || surface.type === "event" ? "deferred" : "preview",
63
+ runtimeOwner: ownerForSurface(surface.type),
64
+ diagnostics
65
+ };
66
+ }
67
+ function validateAdminSurface(surface, basePath, diagnostics) {
68
+ if (!surface.adminSurfaceType) {
69
+ diagnostics.push(diagnostic("surface.admin.type_missing", "blocking", `${basePath}.adminSurfaceType`, "Admin surfaces must declare a specific admin surface type."));
70
+ }
71
+ if (!surface.placement && !surface.compatibleSlots?.length) {
72
+ diagnostics.push(diagnostic("surface.admin.placement_missing", "blocking", `${basePath}.placement`, "Admin surfaces must declare placement targets."));
73
+ }
74
+ if (!surface.scopes?.length) {
75
+ diagnostics.push(diagnostic("surface.admin.scopes_missing", "blocking", `${basePath}.scopes`, "Admin surfaces must declare required scopes."));
76
+ }
77
+ if (!surface.componentKit?.minVersion || !surface.componentKit.components.length) {
78
+ diagnostics.push(diagnostic("surface.admin.component_kit_missing", "blocking", `${basePath}.componentKit`, "Admin surfaces must declare Hyprcart admin component kit version and components."));
79
+ }
80
+ if (surface.adminSurfaceType === "admin_ui_block") {
81
+ const removal = new Set(surface.removalBehavior ?? []);
82
+ if (!removal.has("remove_on_disable") || !removal.has("remove_on_uninstall")) {
83
+ diagnostics.push(diagnostic("surface.admin_block.removal_missing", "blocking", `${basePath}.removalBehavior`, "Admin UI blocks must remove placements on disable and uninstall without tombstones."));
84
+ }
85
+ if (!surface.dimensions) {
86
+ diagnostics.push(diagnostic("surface.admin_block.dimensions_missing", "blocking", `${basePath}.dimensions`, "Admin UI blocks must reserve stable dimensions."));
87
+ }
88
+ }
89
+ if (!surface.inputSchema && !surface.outputSchema) {
90
+ diagnostics.push(diagnostic("surface.admin.schema_missing", "warning", `${basePath}.inputSchema`, "Admin surfaces should declare typed input or output schemas."));
91
+ }
92
+ if (!surface.sandboxPolicy) {
93
+ diagnostics.push(diagnostic("surface.admin.sandbox_missing", "warning", `${basePath}.sandboxPolicy`, "Admin surfaces should declare a sandbox policy."));
94
+ }
95
+ }
96
+ function validateCheckoutSurface(surface, basePath, diagnostics) {
97
+ const sandbox = surface.sandboxPolicy ?? {};
98
+ if (sandbox.allowArbitraryDom === true || sandbox.allowScripts === true || sandbox.allowPaymentBypass === true) {
99
+ diagnostics.push(diagnostic("surface.checkout.unsupported_behavior", "blocking", `${basePath}.sandboxPolicy`, "Checkout UI extensions cannot declare arbitrary DOM, scripts, or payment bypass behavior."));
100
+ }
101
+ if (!surface.placement && !surface.compatibleSlots?.length) {
102
+ diagnostics.push(diagnostic("surface.checkout.placement_missing", "blocking", `${basePath}.placement`, "Checkout UI extensions must declare placement targets."));
103
+ }
104
+ }
105
+ function validateDeterministicFunction(surface, basePath, diagnostics) {
106
+ if (surface.determinism?.networkAccess) {
107
+ diagnostics.push(diagnostic("surface.function.network_forbidden", "blocking", `${basePath}.determinism.networkAccess`, "Deterministic functions cannot use arbitrary network access."));
108
+ }
109
+ if (surface.determinism?.mutationSideEffects) {
110
+ diagnostics.push(diagnostic("surface.function.side_effects_forbidden", "blocking", `${basePath}.determinism.mutationSideEffects`, "Deterministic functions cannot perform direct mutation side effects."));
111
+ }
112
+ if (!surface.inputSchema || !surface.outputSchema) {
113
+ diagnostics.push(diagnostic("surface.function.schema_missing", "blocking", `${basePath}.inputSchema`, "Deterministic functions require typed input and output schemas."));
114
+ }
115
+ }
116
+ function validatePixel(surface, basePath, diagnostics) {
117
+ const sandbox = surface.sandboxPolicy ?? {};
118
+ if (sandbox.domRead === true || sandbox.domWrite === true || sandbox.allowDomScrape === true || sandbox.allowDomWrite === true) {
119
+ diagnostics.push(diagnostic("surface.pixel.dom_access_forbidden", "blocking", `${basePath}.sandboxPolicy`, "Pixels cannot scrape or write storefront DOM."));
120
+ }
121
+ if (surface.consent?.bypass === true || sandbox.consentBypass === true) {
122
+ diagnostics.push(diagnostic("surface.pixel.consent_bypass_forbidden", "blocking", `${basePath}.consent`, "Pixels cannot bypass consent checks."));
123
+ }
124
+ if (!surface.consent?.category) {
125
+ diagnostics.push(diagnostic("surface.pixel.consent_missing", "blocking", `${basePath}.consent.category`, "Pixels must declare a consent category."));
126
+ }
127
+ if (!surface.consent?.events?.length) {
128
+ diagnostics.push(diagnostic("surface.pixel.events_missing", "blocking", `${basePath}.consent.events`, "Pixels must declare events."));
129
+ }
130
+ if (!surface.consent?.destinations?.length) {
131
+ diagnostics.push(diagnostic("surface.pixel.destinations_missing", "blocking", `${basePath}.consent.destinations`, "Pixels must declare destinations."));
132
+ }
133
+ if (!surface.consent?.regions?.length) {
134
+ diagnostics.push(diagnostic("surface.pixel.regions_missing", "warning", `${basePath}.consent.regions`, "Pixels should declare regional availability."));
135
+ }
136
+ const fields = surface.consent?.fields ?? [];
137
+ if (!fields.length || fields.some((field) => /email|phone|name|address|token|secret|session|payment|card/i.test(field))) {
138
+ diagnostics.push(diagnostic("surface.pixel.field_selection_invalid", "blocking", `${basePath}.consent.fields`, "Pixels must declare minimized buyer-safe fields only."));
139
+ }
140
+ }
141
+ function validateEventSubscription(surface, basePath, diagnostics) {
142
+ if (!surface.consent?.events?.length && !surface.requiredContexts?.length) {
143
+ diagnostics.push(diagnostic("surface.event.events_missing", "blocking", `${basePath}.requiredContexts`, "Event subscriptions must declare subscribed event names."));
144
+ }
145
+ if (!surface.scopes?.length) {
146
+ diagnostics.push(diagnostic("surface.event.scopes_missing", "blocking", `${basePath}.scopes`, "Event subscriptions must declare required scopes."));
147
+ }
148
+ }
149
+ function validateBackgroundJob(surface, basePath, diagnostics) {
150
+ if (!surface.retryPolicy) {
151
+ diagnostics.push(diagnostic("surface.background_job.retry_missing", "blocking", `${basePath}.retryPolicy`, "Background jobs must declare bounded retry policy."));
152
+ }
153
+ if ((surface.adminSurfaceType === "bulk_action" || surface.type === "background_job") && surface.overlapPolicy === void 0) {
154
+ diagnostics.push(diagnostic("surface.background_job.overlap_missing", "blocking", `${basePath}.overlapPolicy`, "Background jobs must declare overlap policy."));
155
+ }
156
+ if (!surface.quotaClass) {
157
+ diagnostics.push(diagnostic("surface.background_job.quota_missing", "warning", `${basePath}.quotaClass`, "Background jobs should declare a quota class."));
158
+ }
159
+ }
160
+ function ownerForSurface(surface) {
161
+ if (surface === "storefront_block") return "049c";
162
+ if (surface === "flow" || surface === "event") return "075a";
163
+ if (surface === "admin_surface" || surface === "checkout_ui" || surface === "checkout_function" || surface === "deterministic_function" || surface === "pixel" || surface === "event_subscription" || surface === "background_job") {
164
+ return "049e";
165
+ }
166
+ return "deferred";
167
+ }
168
+ function diagnostic(code, severity, path, message, docsUrl) {
169
+ return { code, severity, path, message, docsUrl };
170
+ }
16
171
 
17
172
  // src/validation.ts
18
173
  var riskyDependencyPatterns = [/child_process/i, /node:fs/i, /eval\(/i];
@@ -66,7 +221,24 @@ function validateManifest(manifest, options = {}) {
66
221
  )
67
222
  );
68
223
  }
224
+ if (surface.type === "storefront_block") {
225
+ validateStorefrontBlockSurface(surface, basePath, issues);
226
+ }
69
227
  });
228
+ for (const surfaceResult of validateExtensionSurfaceDeclarations(manifest)) {
229
+ for (const diagnostic2 of surfaceResult.diagnostics) {
230
+ issues.push(
231
+ issue(
232
+ diagnostic2.code,
233
+ diagnostic2.severity === "blocking" ? "blocker" : diagnostic2.severity === "error" ? "error" : diagnostic2.severity === "warning" ? "warning" : "info",
234
+ diagnostic2.path,
235
+ diagnostic2.message,
236
+ void 0,
237
+ diagnostic2.docsUrl
238
+ )
239
+ );
240
+ }
241
+ }
70
242
  const translationStatus = getTranslationStatus(manifest, requiredLocales);
71
243
  for (const gap of translationStatus.missing) {
72
244
  issues.push(
@@ -115,6 +287,38 @@ function validateManifest(manifest, options = {}) {
115
287
  translationStatus
116
288
  };
117
289
  }
290
+ function validateStorefrontBlockSurface(surface, basePath, issues) {
291
+ const renderTier = normalizeStorefrontBlockRenderTier(surface.renderTier ?? surface.tier);
292
+ if (renderTier === "edge_stream" && (!surface.placeholder?.width || !surface.placeholder?.height || !surface.placeholder?.skeleton)) {
293
+ issues.push(
294
+ issue(
295
+ "storefront_block.placeholder.missing",
296
+ "blocker",
297
+ `${basePath}.placeholder`,
298
+ "Streaming app blocks must declare placeholder width, height, and skeleton before install.",
299
+ "Add exact placeholder dimensions and skeleton type.",
300
+ "https://developer.hyprcart.com/docs/app-platform/surfaces"
301
+ )
302
+ );
303
+ }
304
+ for (const island of surface.clientIslands ?? []) {
305
+ if (island.compressedSizeBytes > 32 * 1024 && !island.exceptionId) {
306
+ issues.push(
307
+ issue(
308
+ "client_island.bundle_budget.exceeded",
309
+ "blocker",
310
+ `${basePath}.clientIslands`,
311
+ "Client island bundle exceeds the 32 KB compressed budget.",
312
+ "Reduce bundle size or request a platform exception.",
313
+ "https://developer.hyprcart.com/docs/app-platform/surfaces"
314
+ )
315
+ );
316
+ }
317
+ if (!island.domBoundarySelector?.startsWith("[data-hc-app-block")) {
318
+ issues.push(issue("client_island.dom_boundary.invalid", "blocker", `${basePath}.clientIslands`, "Client island DOM boundary must stay inside the app block wrapper."));
319
+ }
320
+ }
321
+ }
118
322
  function getTranslationStatus(manifest, requiredLocales) {
119
323
  const missing = [];
120
324
  const completeLocales = [];
@@ -147,27 +351,40 @@ function isCompatibleSdk(version, supportedMajor) {
147
351
  return Number.isFinite(major) && major === supportedMajor;
148
352
  }
149
353
  function hashObject(value) {
150
- const json = JSON.stringify(value, Object.keys(value).sort());
354
+ const json = stableStringify(value);
151
355
  let hash = 0;
152
356
  for (let index = 0; index < json.length; index += 1) {
153
357
  hash = hash * 31 + json.charCodeAt(index) >>> 0;
154
358
  }
155
359
  return `mf_${hash.toString(16).padStart(8, "0")}`;
156
360
  }
361
+ function stableStringify(value) {
362
+ return JSON.stringify(sortValue(value));
363
+ }
364
+ function sortValue(value) {
365
+ if (Array.isArray(value)) return value.map(sortValue);
366
+ if (!value || typeof value !== "object") return value;
367
+ return Object.fromEntries(
368
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, sortValue(entry)])
369
+ );
370
+ }
157
371
 
158
372
  // src/contract-generation.ts
159
373
  function generateContracts(manifest, schemaVersion = "2026-06-06") {
160
374
  const surfaces = manifest.surfaces.map(renderSurfaceContract).join("\n\n");
375
+ const surfaceMetadata = validateExtensionSurfaceDeclarations(manifest);
161
376
  const content = [
162
377
  "/* Generated by Hyprcart app tooling. */",
163
378
  `export const schemaVersion = ${JSON.stringify(schemaVersion)};`,
164
379
  `export const sdkVersion = ${JSON.stringify(manifest.sdkVersion)};`,
380
+ `export const surfaceContracts = ${JSON.stringify(surfaceMetadata, null, 2)} as const;`,
165
381
  surfaces
166
382
  ].join("\n");
167
383
  return {
168
384
  manifestHash: stableHash(JSON.stringify(manifest)),
169
385
  schemaVersion,
170
386
  sdkVersion: manifest.sdkVersion,
387
+ surfaces: surfaceMetadata,
171
388
  files: [
172
389
  {
173
390
  path: "generated/hyprcart.contracts.ts",
@@ -266,15 +483,355 @@ var developerToolingOperationMetadata = [
266
483
  stability: "preview"
267
484
  }
268
485
  ];
486
+
487
+ // src/admin-component-kit.ts
488
+ var defaultSupportedComponents = [
489
+ "Page",
490
+ "Section",
491
+ "Stack",
492
+ "InlineStack",
493
+ "Grid",
494
+ "ResourcePanel",
495
+ "AdminBlock",
496
+ "Modal",
497
+ "Sheet",
498
+ "Text",
499
+ "Heading",
500
+ "Badge",
501
+ "Status",
502
+ "DescriptionList",
503
+ "DataTable",
504
+ "Timeline",
505
+ "Metric",
506
+ "EmptyState",
507
+ "Skeleton",
508
+ "Form",
509
+ "TextField",
510
+ "NumberField",
511
+ "Select",
512
+ "Combobox",
513
+ "Checkbox",
514
+ "RadioGroup",
515
+ "DatePicker",
516
+ "FilePicker",
517
+ "ResourcePicker",
518
+ "ValidationMessage",
519
+ "Button",
520
+ "IconButton",
521
+ "Banner",
522
+ "Toast",
523
+ "InlineError",
524
+ "Progress",
525
+ "Spinner",
526
+ "Tooltip",
527
+ "ConfirmDialog",
528
+ "TitleBar",
529
+ "Breadcrumbs",
530
+ "Tabs",
531
+ "ActionList",
532
+ "ContextualSaveBar",
533
+ "CommandAction",
534
+ "SearchResult"
535
+ ];
536
+ var supportedAdminComponentKitComponents = [...defaultSupportedComponents];
537
+ function validateAdminComponentKitManifest(input) {
538
+ const diagnostics = [];
539
+ if (!input.minVersion) {
540
+ diagnostics.push({ code: "admin_component_kit.version_missing", path: "componentKit.minVersion", message: "Admin component kit minimum version is required." });
541
+ }
542
+ const supported = new Set(input.supportedComponents ?? supportedAdminComponentKitComponents);
543
+ for (const component of input.components ?? []) {
544
+ if (!supported.has(component)) {
545
+ diagnostics.push({ code: "admin_component_kit.component_unsupported", path: "componentKit.components", message: `${component} is not an approved admin component.` });
546
+ }
547
+ }
548
+ for (const [key, value] of Object.entries(input.tokens ?? {})) {
549
+ if (/(?:#[0-9a-f]{3,8}\b|rgba?\(|font|radius|shadow)/i.test(`${key}:${String(value)}`)) {
550
+ diagnostics.push({ code: "admin_component_kit.token_forbidden", path: `componentKit.tokens.${key}`, message: "Apps cannot declare custom visual tokens outside the platform kit." });
551
+ }
552
+ }
553
+ if (input.css && /(?:font-family|border-radius|box-shadow|position\s*:\s*fixed)/i.test(input.css)) {
554
+ diagnostics.push({ code: "admin_component_kit.css_forbidden", path: "componentKit.css", message: "Apps cannot inject global CSS or incompatible visual rules into admin surfaces." });
555
+ }
556
+ return { valid: diagnostics.length === 0, diagnostics };
557
+ }
558
+
559
+ // src/capability-declarations.ts
560
+ var appGovernanceCapabilityTypes = [
561
+ "api_operation",
562
+ "storefront_block",
563
+ "admin_surface",
564
+ "checkout_surface",
565
+ "pixel",
566
+ "event_subscription",
567
+ "mcp_tool",
568
+ "mcp_resource",
569
+ "mcp_resource_template",
570
+ "mcp_prompt",
571
+ "background_job"
572
+ ];
573
+ var appGovernanceDataClasses = ["public", "merchant_operational", "restricted_customer", "payment_adjacent", "auth_sensitive", "security", "operator_only"];
574
+ var appGovernanceRiskClasses = ["low", "medium", "high", "critical"];
575
+ var appGovernanceCostClasses = ["free", "low", "medium", "high", "operator"];
576
+ var appGovernanceApprovalPolicies = ["required", "optional", "operator_only", "automation_policy_required", "not_approvable"];
577
+ function validateAppCapabilityDeclarations(input) {
578
+ const issues = [];
579
+ const capabilityKeys = /* @__PURE__ */ new Set();
580
+ for (const [index, capability] of (input.capabilities ?? []).entries()) {
581
+ const path = `capabilities.${index}`;
582
+ if (!capability.key?.trim()) issues.push(issue2("capability.key.missing", `${path}.key`, "Capability key is required."));
583
+ if (capabilityKeys.has(capability.key)) issues.push(issue2("capability.key.duplicate", `${path}.key`, "Capability key must be unique."));
584
+ capabilityKeys.add(capability.key);
585
+ if (!isOneOf(capability.type, appGovernanceCapabilityTypes)) issues.push(issue2("capability.type.invalid", `${path}.type`, "Capability type is not supported."));
586
+ if (!isOneOf(capability.dataClass, appGovernanceDataClasses)) issues.push(issue2("capability.data_class.invalid", `${path}.dataClass`, "Data class is not supported."));
587
+ if (!isOneOf(capability.riskClass, appGovernanceRiskClasses)) issues.push(issue2("capability.risk_class.invalid", `${path}.riskClass`, "Risk class is not supported."));
588
+ if (!isOneOf(capability.costClass, appGovernanceCostClasses)) issues.push(issue2("capability.cost_class.invalid", `${path}.costClass`, "Cost class is not supported."));
589
+ if (!isOneOf(capability.approvalPolicy, appGovernanceApprovalPolicies)) issues.push(issue2("capability.approval_policy.invalid", `${path}.approvalPolicy`, "Approval policy is not supported."));
590
+ if (capability.mutating && capability.riskClass === "low") {
591
+ issues.push(issue2("capability.mutating.low_risk", `${path}.riskClass`, "Mutating capabilities must be medium risk or higher."));
592
+ }
593
+ }
594
+ for (const [index, egress] of (input.egress ?? []).entries()) {
595
+ const path = `egress.${index}`;
596
+ for (const host of egress.hosts ?? []) {
597
+ if (!isNormalizedHostPattern(host)) issues.push(issue2("egress.host.invalid", `${path}.hosts`, "Egress host must be normalized and must not contain credentials, path, query, or fragment."));
598
+ }
599
+ for (const capabilityKey of egress.requiredForCapabilities ?? []) {
600
+ if (!capabilityKeys.has(capabilityKey)) issues.push(issue2("egress.capability.unknown", `${path}.requiredForCapabilities`, `Unknown capability ${capabilityKey}.`));
601
+ }
602
+ }
603
+ for (const [index, retention] of (input.dataRetention ?? []).entries()) {
604
+ const path = `dataRetention.${index}`;
605
+ if (retention.merchantVisible !== true) {
606
+ issues.push(issue2("retention.visibility.required", `${path}.merchantVisible`, "Retention policy must be visible to merchants at install and uninstall."));
607
+ }
608
+ for (const capabilityKey of retention.appliesTo ?? []) {
609
+ if (!capabilityKeys.has(capabilityKey)) issues.push(issue2("retention.capability.unknown", `${path}.appliesTo`, `Unknown capability ${capabilityKey}.`));
610
+ }
611
+ }
612
+ return { valid: issues.length === 0, issues };
613
+ }
614
+ function isNormalizedHostPattern(host) {
615
+ if (!host || host.includes("@") || host.includes("/") || host.includes("?") || host.includes("#")) return false;
616
+ return /^[a-z0-9*.-]+(?::\d+)?$/i.test(host);
617
+ }
618
+ function isOneOf(value, values) {
619
+ return values.includes(value);
620
+ }
621
+ function issue2(code, path, message) {
622
+ return { code, path, message };
623
+ }
624
+
625
+ // src/ai-mcp-metadata.ts
626
+ var aiMcpDescriptorTypes = ["tool", "resource", "resource_template", "prompt"];
627
+ var aiMcpHumanApprovalPolicies = ["not_required", "required", "required_for_mutation", "automation_policy_allowed"];
628
+ var unsafeAuthorityPattern = /(ignore previous|system prompt|act as admin|bypass|override policy|grant .*scope|no approval)/i;
629
+ function validateAiMcpDescriptorMetadata(descriptors) {
630
+ const issues = [];
631
+ const names = /* @__PURE__ */ new Set();
632
+ descriptors.forEach((descriptor, index) => {
633
+ const path = `ai.mcp.${descriptor.descriptorType}.${index}`;
634
+ if (!descriptor.name?.trim()) issues.push(issue3("ai_mcp.name.missing", `${path}.name`, "Descriptor name is required."));
635
+ if (names.has(descriptor.name)) issues.push(issue3("ai_mcp.name.duplicate", `${path}.name`, "Descriptor name must be unique per app installation."));
636
+ names.add(descriptor.name);
637
+ if (!aiMcpDescriptorTypes.includes(descriptor.descriptorType)) issues.push(issue3("ai_mcp.type.invalid", `${path}.descriptorType`, "Descriptor type is not supported."));
638
+ if (!aiMcpHumanApprovalPolicies.includes(descriptor.humanApprovalPolicy)) issues.push(issue3("ai_mcp.approval.invalid", `${path}.humanApprovalPolicy`, "Human approval policy is not supported."));
639
+ if (descriptor.mutating && descriptor.humanApprovalPolicy === "not_required") {
640
+ issues.push(issue3("ai_mcp.mutating.approval_required", `${path}.humanApprovalPolicy`, "Mutating descriptors require human approval or automation policy."));
641
+ }
642
+ if (descriptor.resourceUriTemplate && /token|secret|bearer/i.test(descriptor.resourceUriTemplate)) {
643
+ issues.push(issue3("ai_mcp.resource_template.secret", `${path}.resourceUriTemplate`, "Resource URI templates must not embed tokens or secrets."));
644
+ }
645
+ for (const text of [descriptor.description, descriptor.promptTemplate].filter((value) => Boolean(value))) {
646
+ if (unsafeAuthorityPattern.test(text)) {
647
+ issues.push(issue3("ai_mcp.metadata.untrusted_authority", path, "Descriptor text is untrusted metadata and cannot claim platform authority."));
648
+ }
649
+ }
650
+ });
651
+ return { valid: issues.length === 0, issues };
652
+ }
653
+ function classifyAiMcpMetadataAuthority(text) {
654
+ return unsafeAuthorityPattern.test(text) ? "untrusted_authority_claim" : "safe_descriptor";
655
+ }
656
+ function issue3(code, path, message) {
657
+ return { code, path, message };
658
+ }
659
+
660
+ // src/launch-readiness.ts
661
+ var REQUIRED_LOCALES = ["en", "de"];
662
+ function validateLaunchReadinessManifest(manifest) {
663
+ const issues = [];
664
+ const launch = manifest.launch;
665
+ if (!launch) {
666
+ return issue4("launch.missing", "launch", "Launch readiness declaration is required.");
667
+ }
668
+ validateAdminApi(launch, issues);
669
+ validateAppData(launch, issues);
670
+ validateEnvironments(launch, issues);
671
+ validateSecrets(launch, issues);
672
+ validateSettings(launch, issues);
673
+ validateConsent(launch, issues);
674
+ validateLifecycleCallbacks(launch, issues);
675
+ validateAssets(launch, issues);
676
+ validateSandbox(launch, issues);
677
+ validateEvidence(launch, issues);
678
+ validateCompatibility(launch, issues);
679
+ return { valid: issues.length === 0, issues };
680
+ }
681
+ function assertLaunchReadinessManifest(manifest) {
682
+ const result = validateLaunchReadinessManifest(manifest);
683
+ if (!result.valid) {
684
+ throw new Error(result.issues.map((entry) => `${entry.code}:${entry.path}`).join(", "));
685
+ }
686
+ }
687
+ function validateAdminApi(launch, issues) {
688
+ if (!launch.adminApi?.minApiVersion) addIssue(issues, "launch.admin_api.missing", "launch.adminApi", "Admin API declaration is required.");
689
+ if (!launch.adminApi?.operations?.length) addIssue(issues, "launch.admin_api.operations_missing", "launch.adminApi.operations", "At least one Admin API operation declaration is required.");
690
+ }
691
+ function validateAppData(launch, issues) {
692
+ if (!launch.appData?.length) addIssue(issues, "launch.app_data.missing", "launch.appData", "App data declarations are required.");
693
+ for (const [index, declaration] of (launch.appData ?? []).entries()) {
694
+ if (!declaration.namespace) addIssue(issues, "launch.app_data.namespace_missing", `launch.appData.${index}.namespace`, "App data namespace is required.");
695
+ if (declaration.visibility === "storefront_public" && !declaration.storefrontMaterialization?.cacheTags?.length) {
696
+ addIssue(issues, "launch.app_data.cache_tags_missing", `launch.appData.${index}.storefrontMaterialization.cacheTags`, "Storefront-public app data requires cache tags.");
697
+ }
698
+ }
699
+ }
700
+ function validateEnvironments(launch, issues) {
701
+ const keys = new Set((launch.environments ?? []).map((environment) => environment.key));
702
+ for (const key of ["development", "staging", "production"]) {
703
+ if (!keys.has(key)) addIssue(issues, "launch.environment.missing", `launch.environments.${key}`, `${key} environment is required.`);
704
+ }
705
+ const production = (launch.environments ?? []).find((environment) => environment.key === "production");
706
+ if (production && !production.promotionRequiresCertification) {
707
+ addIssue(issues, "launch.environment.production_certification", "launch.environments.production", "Production environment must require certification.");
708
+ }
709
+ }
710
+ function validateSecrets(launch, issues) {
711
+ if (!launch.secrets?.length) addIssue(issues, "launch.secrets.missing", "launch.secrets", "At least one secret declaration is required.");
712
+ for (const [index, secret] of (launch.secrets ?? []).entries()) {
713
+ if (secret.runtimeExposure === "runtime_only" && secret.key.toLowerCase().startsWith("next_public")) {
714
+ addIssue(issues, "launch.secrets.client_bundle", `launch.secrets.${index}.key`, "Secrets cannot target client bundles.");
715
+ }
716
+ }
717
+ }
718
+ function validateSettings(launch, issues) {
719
+ if (!launch.settings?.length) addIssue(issues, "launch.settings.missing", "launch.settings", "Merchant settings declaration is required.");
720
+ for (const [index, setting] of (launch.settings ?? []).entries()) {
721
+ for (const locale of REQUIRED_LOCALES) {
722
+ if (!setting.label[locale]) addIssue(issues, "launch.settings.locale_missing", `launch.settings.${index}.label.${locale}`, "Setting labels require English and German.");
723
+ }
724
+ }
725
+ }
726
+ function validateConsent(launch, issues) {
727
+ const consent = launch.consent;
728
+ if (!consent) {
729
+ addIssue(issues, "launch.consent.missing", "launch.consent", "Consent metadata is required.");
730
+ return;
731
+ }
732
+ for (const [field, value] of Object.entries({
733
+ appIcon: consent.appIcon,
734
+ developerName: consent.developerName,
735
+ supportUrl: consent.supportUrl,
736
+ privacyPolicyUrl: consent.privacyPolicyUrl,
737
+ termsUrl: consent.termsUrl,
738
+ reviewerInstructions: consent.reviewerInstructions
739
+ })) {
740
+ if (!value) addIssue(issues, "launch.consent.field_missing", `launch.consent.${field}`, "Consent metadata field is required.");
741
+ }
742
+ if (!consent.screenshots.length) addIssue(issues, "launch.consent.screenshots_missing", "launch.consent.screenshots", "At least one screenshot is required.");
743
+ if (!consent.dataCategories.length) addIssue(issues, "launch.consent.data_categories_missing", "launch.consent.dataCategories", "Data categories are required.");
744
+ }
745
+ function validateLifecycleCallbacks(launch, issues) {
746
+ if (!launch.lifecycleCallbacks?.length) addIssue(issues, "launch.callbacks.missing", "launch.lifecycleCallbacks", "Lifecycle callback declarations are required.");
747
+ }
748
+ function validateAssets(launch, issues) {
749
+ const kinds = new Set((launch.assets ?? []).map((asset) => asset.kind));
750
+ for (const kind of ["icon", "screenshot"]) {
751
+ if (!kinds.has(kind)) addIssue(issues, "launch.assets.required_missing", `launch.assets.${kind}`, `${kind} asset is required.`);
752
+ }
753
+ }
754
+ function validateSandbox(launch, issues) {
755
+ if (!launch.sandbox?.fixturePackId) addIssue(issues, "launch.sandbox.missing", "launch.sandbox", "Sandbox fixture declaration is required.");
756
+ if (launch.sandbox && !launch.sandbox.anonymizationRequired) {
757
+ addIssue(issues, "launch.sandbox.anonymization_required", "launch.sandbox.anonymizationRequired", "Sandbox fixtures must require anonymization.");
758
+ }
759
+ }
760
+ function validateEvidence(launch, issues) {
761
+ if (!launch.evidence?.testCommand) addIssue(issues, "launch.evidence.test_missing", "launch.evidence.testCommand", "Evidence test command is required.");
762
+ if (!launch.evidence?.buildCommand) addIssue(issues, "launch.evidence.build_missing", "launch.evidence.buildCommand", "Evidence build command is required.");
763
+ }
764
+ function validateCompatibility(launch, issues) {
765
+ if (!launch.compatibility?.adminApiVersion) addIssue(issues, "launch.compatibility.missing", "launch.compatibility", "Compatibility declaration is required.");
766
+ }
767
+ function addIssue(issues, code, path, message) {
768
+ issues.push({ code, path, message });
769
+ }
770
+ function issue4(code, path, message) {
771
+ return { valid: false, issues: [{ code, path, message }] };
772
+ }
773
+
774
+ // src/preview-validation.ts
775
+ function validateNoDeployPreviewManifest(manifest) {
776
+ const validation = validateManifest(manifest);
777
+ const diagnostics = validation.issues.map((issue5) => ({
778
+ code: `manifest.${issue5.code}`,
779
+ message: issue5.message,
780
+ path: issue5.path
781
+ }));
782
+ if (manifest.surfaces.length === 0) {
783
+ diagnostics.push({
784
+ code: "preview.surface_missing",
785
+ message: "No-deploy preview requires at least one app surface.",
786
+ path: "surfaces"
787
+ });
788
+ }
789
+ for (const surface of manifest.surfaces) {
790
+ if (!surface.entry) {
791
+ diagnostics.push({
792
+ code: "preview.surface_entry_missing",
793
+ message: "Preview surfaces must declare an entry point.",
794
+ path: `surfaces.${surface.id}.entry`
795
+ });
796
+ }
797
+ }
798
+ return {
799
+ status: diagnostics.length === 0 ? "valid" : "invalid",
800
+ createdProductionState: false,
801
+ diagnostics
802
+ };
803
+ }
269
804
  export {
805
+ aiMcpDescriptorTypes,
806
+ aiMcpHumanApprovalPolicies,
807
+ appGovernanceApprovalPolicies,
808
+ appGovernanceCapabilityTypes,
809
+ appGovernanceCostClasses,
810
+ appGovernanceDataClasses,
811
+ appGovernanceRiskClasses,
812
+ assertLaunchReadinessManifest,
270
813
  checkCompatibility,
814
+ classifyAiMcpMetadataAuthority,
271
815
  defaultRequiredLocales,
272
816
  developerToolingOperationMetadata,
273
817
  generateContracts,
274
818
  generateIdeMetadata,
275
819
  getTranslationStatus,
820
+ hydrationTriggers,
821
+ isNormalizedHostPattern,
276
822
  isSupportedSurface,
823
+ legacyStorefrontBlockRenderTiers,
824
+ normalizeStorefrontBlockRenderTier,
825
+ storefrontBlockRenderTiers,
826
+ supportedAdminComponentKitComponents,
277
827
  supportedSurfaces,
278
- validateManifest
828
+ validateAdminComponentKitManifest,
829
+ validateAiMcpDescriptorMetadata,
830
+ validateAppCapabilityDeclarations,
831
+ validateExtensionSurface,
832
+ validateExtensionSurfaceDeclarations,
833
+ validateLaunchReadinessManifest,
834
+ validateManifest,
835
+ validateNoDeployPreviewManifest
279
836
  };
280
837
  //# sourceMappingURL=index.js.map