@sonordev/site-kit 2.8.2 → 3.0.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.
Files changed (117) hide show
  1. package/dist/EngageWidget-LRE4VD7O.js +14 -0
  2. package/dist/{EngageWidget-JIXUBG47.js.map → EngageWidget-LRE4VD7O.js.map} +1 -1
  3. package/dist/EngageWidget-OAOLB6ED.mjs +5 -0
  4. package/dist/{EngageWidget-4W5EM4UO.mjs.map → EngageWidget-OAOLB6ED.mjs.map} +1 -1
  5. package/dist/blog/index.js +2 -1
  6. package/dist/blog/index.js.map +1 -1
  7. package/dist/blog/index.mjs +2 -1
  8. package/dist/blog/index.mjs.map +1 -1
  9. package/dist/chunk-2FEQ6TYD.mjs +37 -0
  10. package/dist/chunk-2FEQ6TYD.mjs.map +1 -0
  11. package/dist/{chunk-5SQ4NRPH.mjs → chunk-3AEOGV6V.mjs} +6 -4
  12. package/dist/chunk-3AEOGV6V.mjs.map +1 -0
  13. package/dist/chunk-662YHKWW.mjs +10 -0
  14. package/dist/chunk-662YHKWW.mjs.map +1 -0
  15. package/dist/{chunk-MNOVPHL6.mjs → chunk-72MRAYAS.mjs} +19 -14
  16. package/dist/chunk-72MRAYAS.mjs.map +1 -0
  17. package/dist/{chunk-5QLM6LZ2.mjs → chunk-APRAGA5G.mjs} +3 -3
  18. package/dist/{chunk-5QLM6LZ2.mjs.map → chunk-APRAGA5G.mjs.map} +1 -1
  19. package/dist/{chunk-MWE2HRPU.js → chunk-D5XTX5EB.js} +19 -14
  20. package/dist/chunk-D5XTX5EB.js.map +1 -0
  21. package/dist/{chunk-HANRPNKG.js → chunk-FMI65E5Y.js} +3 -3
  22. package/dist/{chunk-HANRPNKG.js.map → chunk-FMI65E5Y.js.map} +1 -1
  23. package/dist/{chunk-SLJJJWMV.js → chunk-FPU2QPO4.js} +338 -33
  24. package/dist/chunk-FPU2QPO4.js.map +1 -0
  25. package/dist/{chunk-PKUTYMN7.js → chunk-J25JPU77.js} +2 -2
  26. package/dist/chunk-J25JPU77.js.map +1 -0
  27. package/dist/chunk-J7QI3GDX.js +12 -0
  28. package/dist/chunk-J7QI3GDX.js.map +1 -0
  29. package/dist/chunk-MLJXELPA.js +693 -0
  30. package/dist/chunk-MLJXELPA.js.map +1 -0
  31. package/dist/{chunk-L7XPPFSS.mjs → chunk-QDKQZ5XH.mjs} +2 -2
  32. package/dist/chunk-QDKQZ5XH.mjs.map +1 -0
  33. package/dist/{chunk-IAV32YHL.mjs → chunk-RV45YMBJ.mjs} +338 -33
  34. package/dist/chunk-RV45YMBJ.mjs.map +1 -0
  35. package/dist/chunk-TCVHI3JP.mjs +686 -0
  36. package/dist/chunk-TCVHI3JP.mjs.map +1 -0
  37. package/dist/{chunk-PAF5IGGF.js → chunk-XNUPJC6R.js} +6 -4
  38. package/dist/chunk-XNUPJC6R.js.map +1 -0
  39. package/dist/chunk-YBKALLBH.js +46 -0
  40. package/dist/chunk-YBKALLBH.js.map +1 -0
  41. package/dist/engage/index.d.mts +2 -2
  42. package/dist/engage/index.d.ts +2 -2
  43. package/dist/engage/index.js +5 -4
  44. package/dist/engage/index.js.map +1 -1
  45. package/dist/engage/index.mjs +2 -1
  46. package/dist/engage/index.mjs.map +1 -1
  47. package/dist/forms/index.js +19 -683
  48. package/dist/forms/index.js.map +1 -1
  49. package/dist/forms/index.mjs +4 -676
  50. package/dist/forms/index.mjs.map +1 -1
  51. package/dist/index.d.mts +2 -2
  52. package/dist/index.d.ts +2 -2
  53. package/dist/layout/client.js +2 -2
  54. package/dist/layout/client.mjs +1 -1
  55. package/dist/layout/index.js +5 -5
  56. package/dist/layout/index.mjs +2 -2
  57. package/dist/llms/index.d.mts +18 -4
  58. package/dist/llms/index.d.ts +18 -4
  59. package/dist/llms/index.js +26 -51
  60. package/dist/llms/index.js.map +1 -1
  61. package/dist/llms/index.mjs +16 -41
  62. package/dist/llms/index.mjs.map +1 -1
  63. package/dist/middleware/index.d.mts +62 -1
  64. package/dist/middleware/index.d.ts +62 -1
  65. package/dist/middleware/index.js +105 -0
  66. package/dist/middleware/index.js.map +1 -1
  67. package/dist/middleware/index.mjs +103 -1
  68. package/dist/middleware/index.mjs.map +1 -1
  69. package/dist/seo/index.d.mts +10 -205
  70. package/dist/seo/index.d.ts +10 -205
  71. package/dist/seo/index.js +16 -15
  72. package/dist/seo/index.js.map +1 -1
  73. package/dist/seo/index.mjs +7 -6
  74. package/dist/seo/index.mjs.map +1 -1
  75. package/dist/seo/server.d.mts +2 -106
  76. package/dist/seo/server.d.ts +2 -106
  77. package/dist/seo/server.js +56 -197
  78. package/dist/seo/server.js.map +1 -1
  79. package/dist/seo/server.mjs +2 -183
  80. package/dist/seo/server.mjs.map +1 -1
  81. package/dist/server-l6LMNvF1.d.ts +360 -0
  82. package/dist/server-mX5At_6x.d.mts +360 -0
  83. package/dist/sitemap/index.d.mts +1 -1
  84. package/dist/sitemap/index.d.ts +1 -1
  85. package/dist/sitemap/index.js +2 -2
  86. package/dist/sitemap/index.mjs +1 -1
  87. package/dist/slots/contract.d.mts +83 -0
  88. package/dist/slots/contract.d.ts +83 -0
  89. package/dist/slots/contract.js +41 -0
  90. package/dist/slots/contract.js.map +1 -0
  91. package/dist/slots/contract.mjs +4 -0
  92. package/dist/slots/contract.mjs.map +1 -0
  93. package/dist/slots/index.d.mts +104 -0
  94. package/dist/slots/index.d.ts +104 -0
  95. package/dist/slots/index.js +186 -0
  96. package/dist/slots/index.js.map +1 -0
  97. package/dist/slots/index.mjs +146 -0
  98. package/dist/slots/index.mjs.map +1 -0
  99. package/dist/{types-DYyIAgQg.d.ts → types-DPsbBKiu.d.mts} +1 -1
  100. package/dist/{types-DYyIAgQg.d.mts → types-DPsbBKiu.d.ts} +1 -1
  101. package/dist/{types-BnCwwUX3.d.mts → types-D_1iUxOQ.d.mts} +18 -1
  102. package/dist/{types-BnCwwUX3.d.ts → types-D_1iUxOQ.d.ts} +18 -1
  103. package/dist/{types-J7Z_FqmV.d.mts → types-DhCAWUmd.d.mts} +8 -0
  104. package/dist/{types-0NuBL1Gg.d.ts → types-xcP_owwn.d.ts} +8 -0
  105. package/package.json +11 -1
  106. package/dist/EngageWidget-4W5EM4UO.mjs +0 -4
  107. package/dist/EngageWidget-JIXUBG47.js +0 -13
  108. package/dist/chunk-5SQ4NRPH.mjs.map +0 -1
  109. package/dist/chunk-IAV32YHL.mjs.map +0 -1
  110. package/dist/chunk-L7XPPFSS.mjs.map +0 -1
  111. package/dist/chunk-MNOVPHL6.mjs.map +0 -1
  112. package/dist/chunk-MWE2HRPU.js.map +0 -1
  113. package/dist/chunk-PAF5IGGF.js.map +0 -1
  114. package/dist/chunk-PKUTYMN7.js.map +0 -1
  115. package/dist/chunk-SLJJJWMV.js.map +0 -1
  116. package/dist/routing-C7gmHWm9.d.ts +0 -163
  117. package/dist/routing-trNzR1Pz.d.mts +0 -163
@@ -1,4 +1,4 @@
1
- import { L as LLMsDataResponse } from '../types-J7Z_FqmV.mjs';
1
+ import { L as LLMsDataResponse } from '../types-DhCAWUmd.mjs';
2
2
  import '../llms/contract.mjs';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { L as LLMsDataResponse } from '../types-0NuBL1Gg.js';
1
+ import { L as LLMsDataResponse } from '../types-xcP_owwn.js';
2
2
  import '../llms/contract.js';
3
3
 
4
4
  /**
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkMWE2HRPU_js = require('../chunk-MWE2HRPU.js');
3
+ var chunkD5XTX5EB_js = require('../chunk-D5XTX5EB.js');
4
4
  var chunkJP5WGL75_js = require('../chunk-JP5WGL75.js');
5
5
  require('../chunk-ATG4FJY6.js');
6
6
  require('../chunk-ZSMWDLMK.js');
@@ -500,7 +500,7 @@ function createSitemap(config) {
500
500
  }
501
501
  if (config.optimizedLLMsTxt !== false) {
502
502
  try {
503
- const writeResult = await chunkMWE2HRPU_js.writeLLMsTxtToPublic({
503
+ const writeResult = await chunkD5XTX5EB_js.writeLLMsTxtToPublic({
504
504
  apiUrl,
505
505
  apiKey,
506
506
  full: config.optimizedLLMsFullTxt ?? false,
@@ -1,4 +1,4 @@
1
- import { writeLLMsTxtToPublic } from '../chunk-MNOVPHL6.mjs';
1
+ import { writeLLMsTxtToPublic } from '../chunk-72MRAYAS.mjs';
2
2
  import { getSiteConfig } from '../chunk-B22WSN4L.mjs';
3
3
  import '../chunk-H23ZT2I2.mjs';
4
4
  import '../chunk-4XPGGLVP.mjs';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @sonordev/site-kit/slots/contract — Managed Slots wire contract (v1)
3
+ *
4
+ * Single source of truth for the slot payload shape and content signing,
5
+ * shared by site-kit (verify side) and sonor-api (sign side) — same pattern
6
+ * as `@sonordev/site-kit/llms/contract`.
7
+ *
8
+ * Security model: every SlotContent is HMAC-signed with the project API key.
9
+ * site-kit verifies before rendering and falls back to the developer's static
10
+ * content on any mismatch, so platform-originated content carries provenance
11
+ * end to end. See docs/SITE-KIT-3.0-SPEC-SLOTS.md.
12
+ */
13
+ /** Bump on breaking payload changes. */
14
+ declare const SLOTS_CONTRACT_VERSION = 1;
15
+ /**
16
+ * v1 supports plain text only — rendered as React text (escaped), never
17
+ * dangerouslySetInnerHTML. 'markdown' / 'rich' are reserved for a future
18
+ * contract version behind a real sanitizer decision.
19
+ */
20
+ type SlotContentType = 'text';
21
+ declare const SLOT_CONTENT_TYPES: readonly SlotContentType[];
22
+ /** Hard cap on managed content length; longer payloads are rejected → fallback. */
23
+ declare const SLOT_CONTENT_MAX_LENGTH = 10000;
24
+ /** Slot ids: lowercase, page-scoped by convention, e.g. "home-hero-headline". */
25
+ declare const SLOT_ID_PATTERN: RegExp;
26
+ interface SlotContent {
27
+ slot_id: string;
28
+ type: SlotContentType;
29
+ /** The managed text. Rendered escaped — never as HTML. */
30
+ content: string;
31
+ /** Forward-compat: experiment/personalization variant that produced this content. */
32
+ variant_id?: string | null;
33
+ experiment_id?: string | null;
34
+ /** ISO timestamp of the last content change. */
35
+ updated_at?: string | null;
36
+ /** Hex HMAC-SHA256 over the canonical payload, keyed with the project API key. */
37
+ signature: string;
38
+ }
39
+ interface SlotResolveRequestEntry {
40
+ id: string;
41
+ /**
42
+ * The developer's current static text for this slot (when statically
43
+ * extractable). Stored as `fallback_text` on registration so the dashboard
44
+ * editor shows the live copy instead of a bare slot id. Never rendered by
45
+ * the API anywhere — display + drafting context only.
46
+ */
47
+ fallback?: string;
48
+ /**
49
+ * The route this slot renders on (e.g. "/" or "/pricing"). A static literal,
50
+ * never derived from the request — it feeds the Copy Evidence Loop's
51
+ * slot↔page mapping so Signal can judge the slot against its page's metrics.
52
+ */
53
+ page?: string;
54
+ }
55
+ interface SlotsResolveRequest {
56
+ contract_version: number;
57
+ slots: SlotResolveRequestEntry[];
58
+ /** Multi-site sub-dimension: normalized lowercase host (see CLAUDE.md "site" convention). */
59
+ site?: string;
60
+ }
61
+ interface SlotsResolveResponse {
62
+ contract_version: number;
63
+ slots: Record<string, SlotContent | null>;
64
+ }
65
+ declare function isValidSlotId(id: string): boolean;
66
+ /**
67
+ * Canonical string both sides sign/verify. Exported separately from the HMAC
68
+ * helpers so an edge-runtime resolver can reproduce it with WebCrypto.
69
+ */
70
+ declare function slotSigningPayload(content: Pick<SlotContent, 'slot_id' | 'type' | 'content'>): string;
71
+ /**
72
+ * Sign slot content with the project API key (sonor-api side).
73
+ * Returns the hex HMAC-SHA256 signature.
74
+ */
75
+ declare function signSlotContent(content: Pick<SlotContent, 'slot_id' | 'type' | 'content'>, apiKey: string): string;
76
+ /**
77
+ * Verify a slot payload's shape + signature (site-kit side).
78
+ * Returns true only when the payload is well-formed, within limits, and the
79
+ * signature matches the project API key. Constant-time comparison.
80
+ */
81
+ declare function verifySlotContent(content: unknown, apiKey: string): content is SlotContent;
82
+
83
+ export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, type SlotContent, type SlotContentType, type SlotResolveRequestEntry, type SlotsResolveRequest, type SlotsResolveResponse, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @sonordev/site-kit/slots/contract — Managed Slots wire contract (v1)
3
+ *
4
+ * Single source of truth for the slot payload shape and content signing,
5
+ * shared by site-kit (verify side) and sonor-api (sign side) — same pattern
6
+ * as `@sonordev/site-kit/llms/contract`.
7
+ *
8
+ * Security model: every SlotContent is HMAC-signed with the project API key.
9
+ * site-kit verifies before rendering and falls back to the developer's static
10
+ * content on any mismatch, so platform-originated content carries provenance
11
+ * end to end. See docs/SITE-KIT-3.0-SPEC-SLOTS.md.
12
+ */
13
+ /** Bump on breaking payload changes. */
14
+ declare const SLOTS_CONTRACT_VERSION = 1;
15
+ /**
16
+ * v1 supports plain text only — rendered as React text (escaped), never
17
+ * dangerouslySetInnerHTML. 'markdown' / 'rich' are reserved for a future
18
+ * contract version behind a real sanitizer decision.
19
+ */
20
+ type SlotContentType = 'text';
21
+ declare const SLOT_CONTENT_TYPES: readonly SlotContentType[];
22
+ /** Hard cap on managed content length; longer payloads are rejected → fallback. */
23
+ declare const SLOT_CONTENT_MAX_LENGTH = 10000;
24
+ /** Slot ids: lowercase, page-scoped by convention, e.g. "home-hero-headline". */
25
+ declare const SLOT_ID_PATTERN: RegExp;
26
+ interface SlotContent {
27
+ slot_id: string;
28
+ type: SlotContentType;
29
+ /** The managed text. Rendered escaped — never as HTML. */
30
+ content: string;
31
+ /** Forward-compat: experiment/personalization variant that produced this content. */
32
+ variant_id?: string | null;
33
+ experiment_id?: string | null;
34
+ /** ISO timestamp of the last content change. */
35
+ updated_at?: string | null;
36
+ /** Hex HMAC-SHA256 over the canonical payload, keyed with the project API key. */
37
+ signature: string;
38
+ }
39
+ interface SlotResolveRequestEntry {
40
+ id: string;
41
+ /**
42
+ * The developer's current static text for this slot (when statically
43
+ * extractable). Stored as `fallback_text` on registration so the dashboard
44
+ * editor shows the live copy instead of a bare slot id. Never rendered by
45
+ * the API anywhere — display + drafting context only.
46
+ */
47
+ fallback?: string;
48
+ /**
49
+ * The route this slot renders on (e.g. "/" or "/pricing"). A static literal,
50
+ * never derived from the request — it feeds the Copy Evidence Loop's
51
+ * slot↔page mapping so Signal can judge the slot against its page's metrics.
52
+ */
53
+ page?: string;
54
+ }
55
+ interface SlotsResolveRequest {
56
+ contract_version: number;
57
+ slots: SlotResolveRequestEntry[];
58
+ /** Multi-site sub-dimension: normalized lowercase host (see CLAUDE.md "site" convention). */
59
+ site?: string;
60
+ }
61
+ interface SlotsResolveResponse {
62
+ contract_version: number;
63
+ slots: Record<string, SlotContent | null>;
64
+ }
65
+ declare function isValidSlotId(id: string): boolean;
66
+ /**
67
+ * Canonical string both sides sign/verify. Exported separately from the HMAC
68
+ * helpers so an edge-runtime resolver can reproduce it with WebCrypto.
69
+ */
70
+ declare function slotSigningPayload(content: Pick<SlotContent, 'slot_id' | 'type' | 'content'>): string;
71
+ /**
72
+ * Sign slot content with the project API key (sonor-api side).
73
+ * Returns the hex HMAC-SHA256 signature.
74
+ */
75
+ declare function signSlotContent(content: Pick<SlotContent, 'slot_id' | 'type' | 'content'>, apiKey: string): string;
76
+ /**
77
+ * Verify a slot payload's shape + signature (site-kit side).
78
+ * Returns true only when the payload is well-formed, within limits, and the
79
+ * signature matches the project API key. Constant-time comparison.
80
+ */
81
+ declare function verifySlotContent(content: unknown, apiKey: string): content is SlotContent;
82
+
83
+ export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, type SlotContent, type SlotContentType, type SlotResolveRequestEntry, type SlotsResolveRequest, type SlotsResolveResponse, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent };
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var chunkYBKALLBH_js = require('../chunk-YBKALLBH.js');
4
+ require('../chunk-ZSMWDLMK.js');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "SLOTS_CONTRACT_VERSION", {
9
+ enumerable: true,
10
+ get: function () { return chunkYBKALLBH_js.SLOTS_CONTRACT_VERSION; }
11
+ });
12
+ Object.defineProperty(exports, "SLOT_CONTENT_MAX_LENGTH", {
13
+ enumerable: true,
14
+ get: function () { return chunkYBKALLBH_js.SLOT_CONTENT_MAX_LENGTH; }
15
+ });
16
+ Object.defineProperty(exports, "SLOT_CONTENT_TYPES", {
17
+ enumerable: true,
18
+ get: function () { return chunkYBKALLBH_js.SLOT_CONTENT_TYPES; }
19
+ });
20
+ Object.defineProperty(exports, "SLOT_ID_PATTERN", {
21
+ enumerable: true,
22
+ get: function () { return chunkYBKALLBH_js.SLOT_ID_PATTERN; }
23
+ });
24
+ Object.defineProperty(exports, "isValidSlotId", {
25
+ enumerable: true,
26
+ get: function () { return chunkYBKALLBH_js.isValidSlotId; }
27
+ });
28
+ Object.defineProperty(exports, "signSlotContent", {
29
+ enumerable: true,
30
+ get: function () { return chunkYBKALLBH_js.signSlotContent; }
31
+ });
32
+ Object.defineProperty(exports, "slotSigningPayload", {
33
+ enumerable: true,
34
+ get: function () { return chunkYBKALLBH_js.slotSigningPayload; }
35
+ });
36
+ Object.defineProperty(exports, "verifySlotContent", {
37
+ enumerable: true,
38
+ get: function () { return chunkYBKALLBH_js.verifySlotContent; }
39
+ });
40
+ //# sourceMappingURL=contract.js.map
41
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"contract.js"}
@@ -0,0 +1,4 @@
1
+ export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-2FEQ6TYD.mjs';
2
+ import '../chunk-4XPGGLVP.mjs';
3
+ //# sourceMappingURL=contract.mjs.map
4
+ //# sourceMappingURL=contract.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"contract.mjs"}
@@ -0,0 +1,104 @@
1
+ import * as React from 'react';
2
+ import { SlotContent } from './contract.mjs';
3
+ export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, SlotContentType, SlotsResolveRequest, SlotsResolveResponse, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from './contract.mjs';
4
+
5
+ /**
6
+ * @sonordev/site-kit/slots — Server-Only Resolution
7
+ *
8
+ * SECURITY: uses the private SONOR_API_KEY. Import only in server code
9
+ * (RSC, route handlers, server actions).
10
+ *
11
+ * Design rules (see docs/SITE-KIT-3.0-SPEC-SLOTS.md):
12
+ * - Static-safe: plain fetch with ISR caching; never touches request state,
13
+ * so pages using slots stay prerenderable.
14
+ * - Fallback-first: EVERY failure mode resolves to null (component renders
15
+ * its children). Slots must never break a build or a page.
16
+ * - Signed: unsigned/tampered payloads are dropped with a warning.
17
+ */
18
+
19
+ interface SlotResolveOptions {
20
+ /** Multi-site sub-dimension: normalized lowercase host. */
21
+ site?: string;
22
+ /** ISR revalidate window in seconds (default 300; instant updates come from the revalidate webhook). */
23
+ revalidate?: number;
24
+ /**
25
+ * The slot's current static text, reported on resolve so the dashboard
26
+ * editor shows the live copy. ManagedSlot supplies this automatically when
27
+ * its children are a plain string.
28
+ */
29
+ fallback?: string;
30
+ /**
31
+ * The route this slot renders on (static literal, e.g. "/pricing") — feeds
32
+ * the Copy Evidence Loop's slot↔page mapping.
33
+ */
34
+ page?: string;
35
+ }
36
+ /** Resolve one slot. Null on any failure → caller renders fallback. */
37
+ declare function getSlot(id: string, options?: SlotResolveOptions): Promise<SlotContent | null>;
38
+ /**
39
+ * Batch resolution for layout-level prefetch. v1 fans out to the per-slot
40
+ * cached resolver (one wire shape, no behavioral difference); the batch
41
+ * endpoint exists in the contract so this can become a single request
42
+ * without a wire change.
43
+ */
44
+ declare function resolveSlots(ids: string[], options?: SlotResolveOptions): Promise<Record<string, SlotContent | null>>;
45
+
46
+ interface ManagedSlotProps extends Omit<SlotResolveOptions, 'fallback'> {
47
+ /** Stable slot id, lowercase, page-scoped by convention (e.g. "home-hero-headline"). */
48
+ id: string;
49
+ /**
50
+ * The developer-owned static content — exactly what the page ships without
51
+ * Sonor. Rendered verbatim whenever no managed content resolves.
52
+ */
53
+ children: React.ReactNode;
54
+ }
55
+ /**
56
+ * ManagedSlot — a Sonor-managed text region inside an element the developer
57
+ * still owns. Renders a fragment: no wrapper tag, no className opinion — put
58
+ * it INSIDE your element and keep your markup.
59
+ *
60
+ * Server component. Resolution is static-safe (ISR-cached fetch, no request
61
+ * access) and fallback-first: any failure renders the children. Managed
62
+ * content is signature-verified and rendered as escaped text, never HTML.
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * <h1 className="hero-title">
67
+ * <ManagedSlot id="home-hero-headline" page="/">
68
+ * New Homes in Cincinnati & Northern Kentucky
69
+ * </ManagedSlot>
70
+ * </h1>
71
+ * ```
72
+ */
73
+ declare function ManagedSlot({ id, children, site, revalidate, page, }: ManagedSlotProps): Promise<React.ReactElement>;
74
+
75
+ /**
76
+ * @sonordev/site-kit/slots — On-demand Revalidation
77
+ *
78
+ * Sonor calls this when slot content changes (owner edit or approved Signal
79
+ * proposal) so the change is live in seconds instead of at the next ISR
80
+ * window. Mirrors the llms revalidation handler pattern.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * // app/api/revalidate-slots/route.ts
85
+ * import { createSlotsRevalidateHandler } from '@sonordev/site-kit/slots'
86
+ *
87
+ * export const POST = createSlotsRevalidateHandler(process.env.REVALIDATION_SECRET!)
88
+ * ```
89
+ */
90
+ type RevalidateTagFn = (tag: string) => void;
91
+ declare const SLOTS_CACHE_TAG = "sonor-slots";
92
+ /**
93
+ * Create a POST handler that busts the slots data cache.
94
+ * Protected by a shared secret. (POST handlers are never statically
95
+ * prerendered, so reading the request here is fine.)
96
+ */
97
+ declare function createSlotsRevalidateHandler(secret: string, options?: {
98
+ /** Additional cache tags to revalidate alongside slots. */
99
+ extraTags?: string[];
100
+ /** Custom revalidateTag (for testing or frameworks other than Next.js). */
101
+ revalidateTag?: RevalidateTagFn;
102
+ }): (request: Request) => Promise<Response>;
103
+
104
+ export { ManagedSlot, type ManagedSlotProps, SLOTS_CACHE_TAG, SlotContent, type SlotResolveOptions, createSlotsRevalidateHandler, ManagedSlot as default, getSlot, resolveSlots };
@@ -0,0 +1,104 @@
1
+ import * as React from 'react';
2
+ import { SlotContent } from './contract.js';
3
+ export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, SlotContentType, SlotsResolveRequest, SlotsResolveResponse, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from './contract.js';
4
+
5
+ /**
6
+ * @sonordev/site-kit/slots — Server-Only Resolution
7
+ *
8
+ * SECURITY: uses the private SONOR_API_KEY. Import only in server code
9
+ * (RSC, route handlers, server actions).
10
+ *
11
+ * Design rules (see docs/SITE-KIT-3.0-SPEC-SLOTS.md):
12
+ * - Static-safe: plain fetch with ISR caching; never touches request state,
13
+ * so pages using slots stay prerenderable.
14
+ * - Fallback-first: EVERY failure mode resolves to null (component renders
15
+ * its children). Slots must never break a build or a page.
16
+ * - Signed: unsigned/tampered payloads are dropped with a warning.
17
+ */
18
+
19
+ interface SlotResolveOptions {
20
+ /** Multi-site sub-dimension: normalized lowercase host. */
21
+ site?: string;
22
+ /** ISR revalidate window in seconds (default 300; instant updates come from the revalidate webhook). */
23
+ revalidate?: number;
24
+ /**
25
+ * The slot's current static text, reported on resolve so the dashboard
26
+ * editor shows the live copy. ManagedSlot supplies this automatically when
27
+ * its children are a plain string.
28
+ */
29
+ fallback?: string;
30
+ /**
31
+ * The route this slot renders on (static literal, e.g. "/pricing") — feeds
32
+ * the Copy Evidence Loop's slot↔page mapping.
33
+ */
34
+ page?: string;
35
+ }
36
+ /** Resolve one slot. Null on any failure → caller renders fallback. */
37
+ declare function getSlot(id: string, options?: SlotResolveOptions): Promise<SlotContent | null>;
38
+ /**
39
+ * Batch resolution for layout-level prefetch. v1 fans out to the per-slot
40
+ * cached resolver (one wire shape, no behavioral difference); the batch
41
+ * endpoint exists in the contract so this can become a single request
42
+ * without a wire change.
43
+ */
44
+ declare function resolveSlots(ids: string[], options?: SlotResolveOptions): Promise<Record<string, SlotContent | null>>;
45
+
46
+ interface ManagedSlotProps extends Omit<SlotResolveOptions, 'fallback'> {
47
+ /** Stable slot id, lowercase, page-scoped by convention (e.g. "home-hero-headline"). */
48
+ id: string;
49
+ /**
50
+ * The developer-owned static content — exactly what the page ships without
51
+ * Sonor. Rendered verbatim whenever no managed content resolves.
52
+ */
53
+ children: React.ReactNode;
54
+ }
55
+ /**
56
+ * ManagedSlot — a Sonor-managed text region inside an element the developer
57
+ * still owns. Renders a fragment: no wrapper tag, no className opinion — put
58
+ * it INSIDE your element and keep your markup.
59
+ *
60
+ * Server component. Resolution is static-safe (ISR-cached fetch, no request
61
+ * access) and fallback-first: any failure renders the children. Managed
62
+ * content is signature-verified and rendered as escaped text, never HTML.
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * <h1 className="hero-title">
67
+ * <ManagedSlot id="home-hero-headline" page="/">
68
+ * New Homes in Cincinnati & Northern Kentucky
69
+ * </ManagedSlot>
70
+ * </h1>
71
+ * ```
72
+ */
73
+ declare function ManagedSlot({ id, children, site, revalidate, page, }: ManagedSlotProps): Promise<React.ReactElement>;
74
+
75
+ /**
76
+ * @sonordev/site-kit/slots — On-demand Revalidation
77
+ *
78
+ * Sonor calls this when slot content changes (owner edit or approved Signal
79
+ * proposal) so the change is live in seconds instead of at the next ISR
80
+ * window. Mirrors the llms revalidation handler pattern.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * // app/api/revalidate-slots/route.ts
85
+ * import { createSlotsRevalidateHandler } from '@sonordev/site-kit/slots'
86
+ *
87
+ * export const POST = createSlotsRevalidateHandler(process.env.REVALIDATION_SECRET!)
88
+ * ```
89
+ */
90
+ type RevalidateTagFn = (tag: string) => void;
91
+ declare const SLOTS_CACHE_TAG = "sonor-slots";
92
+ /**
93
+ * Create a POST handler that busts the slots data cache.
94
+ * Protected by a shared secret. (POST handlers are never statically
95
+ * prerendered, so reading the request here is fine.)
96
+ */
97
+ declare function createSlotsRevalidateHandler(secret: string, options?: {
98
+ /** Additional cache tags to revalidate alongside slots. */
99
+ extraTags?: string[];
100
+ /** Custom revalidateTag (for testing or frameworks other than Next.js). */
101
+ revalidateTag?: RevalidateTagFn;
102
+ }): (request: Request) => Promise<Response>;
103
+
104
+ export { ManagedSlot, type ManagedSlotProps, SLOTS_CACHE_TAG, SlotContent, type SlotResolveOptions, createSlotsRevalidateHandler, ManagedSlot as default, getSlot, resolveSlots };
@@ -0,0 +1,186 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var chunkYBKALLBH_js = require('../chunk-YBKALLBH.js');
6
+ require('../chunk-ZSMWDLMK.js');
7
+ require('server-only');
8
+ var react = require('react');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ function getApiConfig() {
12
+ const apiUrl = process.env.SONOR_API_URL || "https://api.sonor.io";
13
+ const apiKey = process.env.SONOR_API_KEY || "";
14
+ if (!apiKey) return null;
15
+ return { apiUrl, apiKey };
16
+ }
17
+ var warned = /* @__PURE__ */ new Set();
18
+ function warnOnce(key, message) {
19
+ if (warned.has(key)) return;
20
+ warned.add(key);
21
+ console.warn(message);
22
+ }
23
+ async function fetchSlot(id, site, revalidate, fallback, page) {
24
+ if (!chunkYBKALLBH_js.isValidSlotId(id)) {
25
+ warnOnce(`id:${id}`, `[site-kit/slots] Invalid slot id "${id}" (expected ${"`"}[a-z0-9-_.:]${"`"}, lowercase) \u2014 rendering fallback`);
26
+ return null;
27
+ }
28
+ const config = getApiConfig();
29
+ if (!config) {
30
+ warnOnce("no-key", "[site-kit/slots] SONOR_API_KEY is not set \u2014 all slots render their fallbacks");
31
+ return null;
32
+ }
33
+ try {
34
+ const response = await fetch(`${config.apiUrl}/api/public/slots/resolve`, {
35
+ method: "POST",
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ "x-api-key": config.apiKey
39
+ },
40
+ body: JSON.stringify({
41
+ contract_version: chunkYBKALLBH_js.SLOTS_CONTRACT_VERSION,
42
+ slots: [
43
+ {
44
+ id,
45
+ ...fallback ? { fallback: fallback.slice(0, chunkYBKALLBH_js.SLOT_CONTENT_MAX_LENGTH) } : {},
46
+ ...page ? { page } : {}
47
+ }
48
+ ],
49
+ ...site ? { site } : {}
50
+ }),
51
+ next: { revalidate, tags: ["sonor-slots"] }
52
+ });
53
+ if (!response.ok) {
54
+ if (response.status !== 404) {
55
+ warnOnce(
56
+ `http:${response.status}`,
57
+ `[site-kit/slots] Resolve returned ${response.status} \u2014 rendering fallbacks`
58
+ );
59
+ }
60
+ await response.text().catch(() => {
61
+ });
62
+ return null;
63
+ }
64
+ const data = await response.json();
65
+ const payload = data?.slots?.[id];
66
+ if (!payload) return null;
67
+ if (!chunkYBKALLBH_js.verifySlotContent(payload, config.apiKey)) {
68
+ warnOnce(
69
+ `sig:${id}`,
70
+ `[site-kit/slots] Dropped slot "${id}": payload failed shape/signature verification \u2014 rendering fallback`
71
+ );
72
+ return null;
73
+ }
74
+ return payload;
75
+ } catch (err) {
76
+ warnOnce("network", `[site-kit/slots] Resolve failed (${err?.message}) \u2014 rendering fallbacks`);
77
+ return null;
78
+ }
79
+ }
80
+ var getSlotCached = react.cache(
81
+ (id, site, revalidate, fallback, page) => fetchSlot(id, site, revalidate, fallback, page)
82
+ );
83
+ function getSlot(id, options = {}) {
84
+ const fallback = options.fallback?.trim() || void 0;
85
+ const page = options.page?.trim() || void 0;
86
+ return getSlotCached(id, options.site, options.revalidate ?? 300, fallback, page);
87
+ }
88
+ async function resolveSlots(ids, options = {}) {
89
+ const entries = await Promise.all(
90
+ ids.map(async (id) => [id, await getSlot(id, options)])
91
+ );
92
+ return Object.fromEntries(entries);
93
+ }
94
+ async function ManagedSlot({
95
+ id,
96
+ children,
97
+ site,
98
+ revalidate,
99
+ page
100
+ }) {
101
+ const fallback = typeof children === "string" ? children : void 0;
102
+ const managed = await getSlot(id, { site, revalidate, fallback, page });
103
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: managed ? managed.content : children });
104
+ }
105
+ var ManagedSlot_default = ManagedSlot;
106
+
107
+ // src/slots/revalidate.ts
108
+ var SLOTS_CACHE_TAG = "sonor-slots";
109
+ function createSlotsRevalidateHandler(secret, options) {
110
+ return async function POST(request) {
111
+ try {
112
+ const authHeader = request.headers.get("authorization");
113
+ const url = new URL(request.url);
114
+ const tokenFromQuery = url.searchParams.get("secret");
115
+ const token = authHeader?.replace(/^Bearer\s+/i, "") || tokenFromQuery;
116
+ if (!secret || token !== secret) {
117
+ return new Response(JSON.stringify({ error: "Invalid secret" }), {
118
+ status: 401,
119
+ headers: { "Content-Type": "application/json" }
120
+ });
121
+ }
122
+ let revalidateTag;
123
+ if (options?.revalidateTag) {
124
+ revalidateTag = options.revalidateTag;
125
+ } else {
126
+ const nextCache = await import('next/cache');
127
+ revalidateTag = nextCache.revalidateTag;
128
+ }
129
+ const tags = [SLOTS_CACHE_TAG, ...options?.extraTags || []];
130
+ for (const tag of tags) {
131
+ revalidateTag(tag);
132
+ }
133
+ return new Response(JSON.stringify({ revalidated: true, tags }), {
134
+ status: 200,
135
+ headers: { "Content-Type": "application/json" }
136
+ });
137
+ } catch (err) {
138
+ console.error("[site-kit/slots] Revalidation failed:", err);
139
+ return new Response(JSON.stringify({ error: "Revalidation failed" }), {
140
+ status: 500,
141
+ headers: { "Content-Type": "application/json" }
142
+ });
143
+ }
144
+ };
145
+ }
146
+
147
+ Object.defineProperty(exports, "SLOTS_CONTRACT_VERSION", {
148
+ enumerable: true,
149
+ get: function () { return chunkYBKALLBH_js.SLOTS_CONTRACT_VERSION; }
150
+ });
151
+ Object.defineProperty(exports, "SLOT_CONTENT_MAX_LENGTH", {
152
+ enumerable: true,
153
+ get: function () { return chunkYBKALLBH_js.SLOT_CONTENT_MAX_LENGTH; }
154
+ });
155
+ Object.defineProperty(exports, "SLOT_CONTENT_TYPES", {
156
+ enumerable: true,
157
+ get: function () { return chunkYBKALLBH_js.SLOT_CONTENT_TYPES; }
158
+ });
159
+ Object.defineProperty(exports, "SLOT_ID_PATTERN", {
160
+ enumerable: true,
161
+ get: function () { return chunkYBKALLBH_js.SLOT_ID_PATTERN; }
162
+ });
163
+ Object.defineProperty(exports, "isValidSlotId", {
164
+ enumerable: true,
165
+ get: function () { return chunkYBKALLBH_js.isValidSlotId; }
166
+ });
167
+ Object.defineProperty(exports, "signSlotContent", {
168
+ enumerable: true,
169
+ get: function () { return chunkYBKALLBH_js.signSlotContent; }
170
+ });
171
+ Object.defineProperty(exports, "slotSigningPayload", {
172
+ enumerable: true,
173
+ get: function () { return chunkYBKALLBH_js.slotSigningPayload; }
174
+ });
175
+ Object.defineProperty(exports, "verifySlotContent", {
176
+ enumerable: true,
177
+ get: function () { return chunkYBKALLBH_js.verifySlotContent; }
178
+ });
179
+ exports.ManagedSlot = ManagedSlot;
180
+ exports.SLOTS_CACHE_TAG = SLOTS_CACHE_TAG;
181
+ exports.createSlotsRevalidateHandler = createSlotsRevalidateHandler;
182
+ exports.default = ManagedSlot_default;
183
+ exports.getSlot = getSlot;
184
+ exports.resolveSlots = resolveSlots;
185
+ //# sourceMappingURL=index.js.map
186
+ //# sourceMappingURL=index.js.map