@czap/astro 0.1.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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/Satellite.d.ts +42 -0
  4. package/dist/Satellite.d.ts.map +1 -0
  5. package/dist/Satellite.js +55 -0
  6. package/dist/Satellite.js.map +1 -0
  7. package/dist/client-directives/gpu.d.ts +3 -0
  8. package/dist/client-directives/gpu.d.ts.map +1 -0
  9. package/dist/client-directives/gpu.js +5 -0
  10. package/dist/client-directives/gpu.js.map +1 -0
  11. package/dist/client-directives/llm.d.ts +3 -0
  12. package/dist/client-directives/llm.d.ts.map +1 -0
  13. package/dist/client-directives/llm.js +5 -0
  14. package/dist/client-directives/llm.js.map +1 -0
  15. package/dist/client-directives/satellite.d.ts +3 -0
  16. package/dist/client-directives/satellite.d.ts.map +1 -0
  17. package/dist/client-directives/satellite.js +5 -0
  18. package/dist/client-directives/satellite.js.map +1 -0
  19. package/dist/client-directives/stream.d.ts +3 -0
  20. package/dist/client-directives/stream.d.ts.map +1 -0
  21. package/dist/client-directives/stream.js +5 -0
  22. package/dist/client-directives/stream.js.map +1 -0
  23. package/dist/client-directives/wasm.d.ts +3 -0
  24. package/dist/client-directives/wasm.d.ts.map +1 -0
  25. package/dist/client-directives/wasm.js +6 -0
  26. package/dist/client-directives/wasm.js.map +1 -0
  27. package/dist/client-directives/worker.d.ts +3 -0
  28. package/dist/client-directives/worker.d.ts.map +1 -0
  29. package/dist/client-directives/worker.js +5 -0
  30. package/dist/client-directives/worker.js.map +1 -0
  31. package/dist/detect-upgrade.d.ts +16 -0
  32. package/dist/detect-upgrade.d.ts.map +1 -0
  33. package/dist/detect-upgrade.js +105 -0
  34. package/dist/detect-upgrade.js.map +1 -0
  35. package/dist/headers.d.ts +45 -0
  36. package/dist/headers.d.ts.map +1 -0
  37. package/dist/headers.js +64 -0
  38. package/dist/headers.js.map +1 -0
  39. package/dist/index.d.ts +30 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +26 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/integration.d.ts +76 -0
  44. package/dist/integration.d.ts.map +1 -0
  45. package/dist/integration.js +240 -0
  46. package/dist/integration.js.map +1 -0
  47. package/dist/middleware.d.ts +69 -0
  48. package/dist/middleware.d.ts.map +1 -0
  49. package/dist/middleware.js +75 -0
  50. package/dist/middleware.js.map +1 -0
  51. package/dist/quantize.d.ts +50 -0
  52. package/dist/quantize.d.ts.map +1 -0
  53. package/dist/quantize.js +122 -0
  54. package/dist/quantize.js.map +1 -0
  55. package/dist/runtime/boundary.d.ts +123 -0
  56. package/dist/runtime/boundary.d.ts.map +1 -0
  57. package/dist/runtime/boundary.js +164 -0
  58. package/dist/runtime/boundary.js.map +1 -0
  59. package/dist/runtime/globals.d.ts +32 -0
  60. package/dist/runtime/globals.d.ts.map +1 -0
  61. package/dist/runtime/globals.js +45 -0
  62. package/dist/runtime/globals.js.map +1 -0
  63. package/dist/runtime/gpu.d.ts +15 -0
  64. package/dist/runtime/gpu.d.ts.map +1 -0
  65. package/dist/runtime/gpu.js +266 -0
  66. package/dist/runtime/gpu.js.map +1 -0
  67. package/dist/runtime/index.d.ts +7 -0
  68. package/dist/runtime/index.d.ts.map +1 -0
  69. package/dist/runtime/index.js +5 -0
  70. package/dist/runtime/index.js.map +1 -0
  71. package/dist/runtime/llm-receipt-tracker.d.ts +21 -0
  72. package/dist/runtime/llm-receipt-tracker.d.ts.map +1 -0
  73. package/dist/runtime/llm-receipt-tracker.js +60 -0
  74. package/dist/runtime/llm-receipt-tracker.js.map +1 -0
  75. package/dist/runtime/llm-render-pipeline.d.ts +89 -0
  76. package/dist/runtime/llm-render-pipeline.d.ts.map +1 -0
  77. package/dist/runtime/llm-render-pipeline.js +241 -0
  78. package/dist/runtime/llm-render-pipeline.js.map +1 -0
  79. package/dist/runtime/llm-session.d.ts +126 -0
  80. package/dist/runtime/llm-session.d.ts.map +1 -0
  81. package/dist/runtime/llm-session.js +385 -0
  82. package/dist/runtime/llm-session.js.map +1 -0
  83. package/dist/runtime/llm.d.ts +16 -0
  84. package/dist/runtime/llm.d.ts.map +1 -0
  85. package/dist/runtime/llm.js +273 -0
  86. package/dist/runtime/llm.js.map +1 -0
  87. package/dist/runtime/policy.d.ts +100 -0
  88. package/dist/runtime/policy.d.ts.map +1 -0
  89. package/dist/runtime/policy.js +147 -0
  90. package/dist/runtime/policy.js.map +1 -0
  91. package/dist/runtime/receipt-chain.d.ts +22 -0
  92. package/dist/runtime/receipt-chain.d.ts.map +1 -0
  93. package/dist/runtime/receipt-chain.js +80 -0
  94. package/dist/runtime/receipt-chain.js.map +1 -0
  95. package/dist/runtime/runtime-session.d.ts +34 -0
  96. package/dist/runtime/runtime-session.d.ts.map +1 -0
  97. package/dist/runtime/runtime-session.js +102 -0
  98. package/dist/runtime/runtime-session.js.map +1 -0
  99. package/dist/runtime/satellite.d.ts +13 -0
  100. package/dist/runtime/satellite.d.ts.map +1 -0
  101. package/dist/runtime/satellite.js +59 -0
  102. package/dist/runtime/satellite.js.map +1 -0
  103. package/dist/runtime/slots.d.ts +34 -0
  104. package/dist/runtime/slots.d.ts.map +1 -0
  105. package/dist/runtime/slots.js +108 -0
  106. package/dist/runtime/slots.js.map +1 -0
  107. package/dist/runtime/stream-session.d.ts +47 -0
  108. package/dist/runtime/stream-session.d.ts.map +1 -0
  109. package/dist/runtime/stream-session.js +82 -0
  110. package/dist/runtime/stream-session.js.map +1 -0
  111. package/dist/runtime/stream.d.ts +9 -0
  112. package/dist/runtime/stream.d.ts.map +1 -0
  113. package/dist/runtime/stream.js +308 -0
  114. package/dist/runtime/stream.js.map +1 -0
  115. package/dist/runtime/url-policy.d.ts +28 -0
  116. package/dist/runtime/url-policy.d.ts.map +1 -0
  117. package/dist/runtime/url-policy.js +87 -0
  118. package/dist/runtime/url-policy.js.map +1 -0
  119. package/dist/runtime/wasm.d.ts +20 -0
  120. package/dist/runtime/wasm.d.ts.map +1 -0
  121. package/dist/runtime/wasm.js +70 -0
  122. package/dist/runtime/wasm.js.map +1 -0
  123. package/dist/runtime/worker.d.ts +11 -0
  124. package/dist/runtime/worker.d.ts.map +1 -0
  125. package/dist/runtime/worker.js +249 -0
  126. package/dist/runtime/worker.js.map +1 -0
  127. package/package.json +106 -0
  128. package/src/Satellite.astro +39 -0
  129. package/src/Satellite.ts +84 -0
  130. package/src/client-directives/gpu.ts +5 -0
  131. package/src/client-directives/llm.ts +5 -0
  132. package/src/client-directives/satellite.ts +5 -0
  133. package/src/client-directives/stream.ts +5 -0
  134. package/src/client-directives/wasm.ts +6 -0
  135. package/src/client-directives/worker.ts +5 -0
  136. package/src/detect-upgrade.ts +105 -0
  137. package/src/headers.ts +84 -0
  138. package/src/index.ts +30 -0
  139. package/src/integration.ts +309 -0
  140. package/src/middleware.ts +133 -0
  141. package/src/quantize.ts +173 -0
  142. package/src/runtime/boundary.ts +263 -0
  143. package/src/runtime/globals.ts +57 -0
  144. package/src/runtime/gpu.ts +291 -0
  145. package/src/runtime/index.ts +12 -0
  146. package/src/runtime/llm-receipt-tracker.ts +88 -0
  147. package/src/runtime/llm-render-pipeline.ts +366 -0
  148. package/src/runtime/llm-session.ts +548 -0
  149. package/src/runtime/llm.ts +344 -0
  150. package/src/runtime/policy.ts +229 -0
  151. package/src/runtime/receipt-chain.ts +106 -0
  152. package/src/runtime/runtime-session.ts +139 -0
  153. package/src/runtime/satellite.ts +80 -0
  154. package/src/runtime/slots.ts +136 -0
  155. package/src/runtime/stream-session.ts +125 -0
  156. package/src/runtime/stream.ts +407 -0
  157. package/src/runtime/url-policy.ts +107 -0
  158. package/src/runtime/wasm.ts +85 -0
  159. package/src/runtime/worker.ts +307 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Astro 6 `AstroIntegration` for czap.
3
+ *
4
+ * Registers the `@czap/vite` plugin, injects the detect/boot scripts,
5
+ * registers every client directive (`client:satellite`,
6
+ * `client:stream`, `client:llm`, `client:worker`, `client:gpu`,
7
+ * `client:wasm`) that the host opts into, and turns on Astro's
8
+ * `serverIslands` experimental flag when requested.
9
+ *
10
+ * @module
11
+ */
12
+ import type { AstroIntegration } from 'astro';
13
+ import type { PluginConfig } from '@czap/vite';
14
+ import type { RuntimeEndpointPolicy } from '@czap/web';
15
+ import { type RuntimeHtmlPolicy } from './runtime/policy.js';
16
+ /**
17
+ * Options passed to {@link integration} from `astro.config.mjs`. Every
18
+ * field is optional; omitted features fall back to conservative
19
+ * defaults (detect enabled, stream/llm/gpu enabled, workers/wasm/server
20
+ * islands opt-in).
21
+ */
22
+ export interface IntegrationConfig {
23
+ /** Overrides passed through to `@czap/vite`'s plugin. */
24
+ readonly vite?: PluginConfig;
25
+ /** Enable the inline detect script (default `true`). */
26
+ readonly detect?: boolean;
27
+ /** Turn on Astro's experimental server-islands flag (default `false`). */
28
+ readonly serverIslands?: boolean;
29
+ /** WASM runtime configuration. */
30
+ readonly wasm?: {
31
+ readonly enabled?: boolean;
32
+ readonly path?: string;
33
+ };
34
+ /** GPU runtime configuration. */
35
+ readonly gpu?: {
36
+ readonly enabled?: boolean;
37
+ readonly preferWebGPU?: boolean;
38
+ };
39
+ /** Off-thread worker runtime configuration. */
40
+ readonly workers?: {
41
+ readonly enabled?: boolean;
42
+ };
43
+ /** SSE streaming runtime configuration. */
44
+ readonly stream?: {
45
+ readonly enabled?: boolean;
46
+ };
47
+ /** LLM streaming runtime configuration. */
48
+ readonly llm?: {
49
+ readonly enabled?: boolean;
50
+ };
51
+ /** Security policies applied to runtime fetch/HTML boundaries. */
52
+ readonly security?: {
53
+ readonly endpointPolicy?: RuntimeEndpointPolicy;
54
+ readonly htmlPolicy?: RuntimeHtmlPolicy;
55
+ };
56
+ }
57
+ /**
58
+ * Build the czap `AstroIntegration`.
59
+ *
60
+ * Plug the returned object into `astro.config.mjs`'s `integrations`
61
+ * array. The integration wires Astro's `astro:config:setup`,
62
+ * `astro:config:done`, `astro:server:setup`, and `astro:build:done`
63
+ * hooks.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * // astro.config.mjs
68
+ * import { integration as czap } from '@czap/astro';
69
+ *
70
+ * const config = defineConfig({
71
+ * integrations: [czap({ detect: true, workers: { enabled: true } })],
72
+ * });
73
+ * ```
74
+ */
75
+ export declare function integration(config?: IntegrationConfig): AstroIntegration;
76
+ //# sourceMappingURL=integration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../src/integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,qBAAqB,CAAC;AAM7B;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,kCAAkC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,iCAAiC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/E,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAClD,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACjD,2CAA2C;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9C,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,cAAc,CAAC,EAAE,qBAAqB,CAAC;QAChD,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;KACzC,CAAC;CACH;AAmGD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,gBAAgB,CAuIxE"}
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Astro 6 `AstroIntegration` for czap.
3
+ *
4
+ * Registers the `@czap/vite` plugin, injects the detect/boot scripts,
5
+ * registers every client directive (`client:satellite`,
6
+ * `client:stream`, `client:llm`, `client:worker`, `client:gpu`,
7
+ * `client:wasm`) that the host opts into, and turns on Astro's
8
+ * `serverIslands` experimental flag when requested.
9
+ *
10
+ * @module
11
+ */
12
+ import { plugin } from '@czap/vite';
13
+ import { DETECT_UPGRADE_SCRIPT } from './detect-upgrade.js';
14
+ import { getCzapHeaderEntries } from './headers.js';
15
+ import { normalizeRuntimeSecurityPolicy, } from './runtime/policy.js';
16
+ // ---------------------------------------------------------------------------
17
+ // Detect Script
18
+ // ---------------------------------------------------------------------------
19
+ /**
20
+ * Inline script that runs device detection on page load and stores
21
+ * the result as CSS custom properties on the <html> element and
22
+ * as a global for runtime access.
23
+ */
24
+ const DETECT_INLINE_SCRIPT = `
25
+ (function(){
26
+ function writeDetectState(next) {
27
+ var safe = Object.freeze(Object.assign({}, next));
28
+ try {
29
+ Object.defineProperty(window, '__CZAP_DETECT__', {
30
+ value: safe,
31
+ configurable: true,
32
+ enumerable: false,
33
+ writable: false
34
+ });
35
+ } catch (_) {
36
+ try {
37
+ window.__CZAP_DETECT__ = safe;
38
+ } catch (_) {}
39
+ }
40
+ }
41
+
42
+ try {
43
+ var h = document.documentElement;
44
+ var w = window.innerWidth || 0;
45
+ var cores = navigator.hardwareConcurrency || 2;
46
+ var mem = navigator.deviceMemory || 4;
47
+ var touch = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
48
+ var motion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
49
+ var dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
50
+ var dpr = window.devicePixelRatio || 1;
51
+
52
+ h.style.setProperty('--czap-vw', w + 'px');
53
+ h.style.setProperty('--czap-cores', String(cores));
54
+ h.style.setProperty('--czap-dpr', String(dpr));
55
+ h.setAttribute('data-czap-touch', String(touch));
56
+ h.setAttribute('data-czap-motion', motion ? 'reduce' : 'no-preference');
57
+ h.setAttribute('data-czap-scheme', dark ? 'dark' : 'light');
58
+
59
+ // Provisional tier -- conservative, no GPU probe available inline.
60
+ // Full detect package overrides on hydration via data-czap-tier attribute.
61
+ var tier = 'reactive';
62
+ if (motion) tier = 'static';
63
+ else if (cores <= 2 || mem <= 2) tier = 'styled';
64
+ h.setAttribute('data-czap-tier', tier);
65
+ h.setAttribute('data-czap-tier-provisional', 'true');
66
+
67
+ writeDetectState({
68
+ tier: tier,
69
+ provisional: true
70
+ });
71
+ } catch(e) {}
72
+ })();
73
+ `.trim();
74
+ function serializeInlineRuntimePolicy(policy) {
75
+ return JSON.stringify(policy).replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026');
76
+ }
77
+ function runtimeBootstrapScript(policy) {
78
+ return `
79
+ import { bootstrapSlots, configureRuntimePolicy, installSwapReinit } from '@czap/astro/runtime';
80
+
81
+ configureRuntimePolicy(${serializeInlineRuntimePolicy(policy)});
82
+ bootstrapSlots();
83
+ installSwapReinit();
84
+ `.trim();
85
+ }
86
+ const WASM_RUNTIME_SCRIPT = `
87
+ import { wasmUrl } from 'virtual:czap/wasm-url';
88
+ import { configureWasmRuntime } from '@czap/astro/runtime';
89
+
90
+ configureWasmRuntime(wasmUrl);
91
+ `.trim();
92
+ /**
93
+ * Build an `updateConfig` payload that toggles a single experimental flag
94
+ * not yet present in Astro's declared `experimental` shape.
95
+ *
96
+ * The `experimental` field on `AstroConfig` is strictly keyed, so adding
97
+ * an unknown flag requires a widening bridge. Containing that bridge
98
+ * here keeps the cast off individual call sites.
99
+ */
100
+ function withExperimentalFlag(flag, value) {
101
+ return { experimental: { [flag]: value } };
102
+ }
103
+ // ---------------------------------------------------------------------------
104
+ // Integration
105
+ // ---------------------------------------------------------------------------
106
+ /**
107
+ * Build the czap `AstroIntegration`.
108
+ *
109
+ * Plug the returned object into `astro.config.mjs`'s `integrations`
110
+ * array. The integration wires Astro's `astro:config:setup`,
111
+ * `astro:config:done`, `astro:server:setup`, and `astro:build:done`
112
+ * hooks.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * // astro.config.mjs
117
+ * import { integration as czap } from '@czap/astro';
118
+ *
119
+ * const config = defineConfig({
120
+ * integrations: [czap({ detect: true, workers: { enabled: true } })],
121
+ * });
122
+ * ```
123
+ */
124
+ export function integration(config) {
125
+ const detectEnabled = config?.detect !== false;
126
+ const serverIslandsEnabled = config?.serverIslands === true;
127
+ const workersEnabled = config?.workers?.enabled === true;
128
+ const gpuEnabled = config?.gpu?.enabled !== false;
129
+ const streamEnabled = config?.stream?.enabled !== false;
130
+ const llmEnabled = config?.llm?.enabled !== false;
131
+ const wasmEnabled = config?.wasm?.enabled === true;
132
+ const runtimePolicy = normalizeRuntimeSecurityPolicy({
133
+ endpointPolicy: config?.security?.endpointPolicy,
134
+ htmlPolicy: config?.security?.htmlPolicy,
135
+ });
136
+ return {
137
+ name: '@czap/astro',
138
+ hooks: {
139
+ 'astro:config:setup': ({ updateConfig, addClientDirective, injectScript, logger }) => {
140
+ logger.info('Setting up @czap integration');
141
+ // Astro may carry a different Vite type graph than @czap/vite. The plugin
142
+ // runtime contract is still compatible, so the host integration owns the
143
+ // version bridge here instead of leaking duplicate plugin shapes downstream.
144
+ const astroViteConfig = {
145
+ plugins: [
146
+ plugin({
147
+ ...(config?.vite ?? {}),
148
+ ...(wasmEnabled ? { wasm: { enabled: true, path: config?.wasm?.path } } : {}),
149
+ }),
150
+ ],
151
+ };
152
+ updateConfig({
153
+ vite: astroViteConfig,
154
+ });
155
+ // Register client directives
156
+ addClientDirective({
157
+ name: 'satellite',
158
+ entrypoint: '@czap/astro/client-directives/satellite',
159
+ });
160
+ logger.info('Registered satellite client directive');
161
+ if (streamEnabled) {
162
+ addClientDirective({
163
+ name: 'stream',
164
+ entrypoint: '@czap/astro/client-directives/stream',
165
+ });
166
+ logger.info('Registered stream client directive');
167
+ }
168
+ if (llmEnabled) {
169
+ addClientDirective({
170
+ name: 'llm',
171
+ entrypoint: '@czap/astro/client-directives/llm',
172
+ });
173
+ logger.info('Registered llm client directive');
174
+ }
175
+ if (workersEnabled) {
176
+ addClientDirective({
177
+ name: 'worker',
178
+ entrypoint: '@czap/astro/client-directives/worker',
179
+ });
180
+ logger.info('Registered worker client directive');
181
+ }
182
+ if (gpuEnabled) {
183
+ addClientDirective({
184
+ name: 'gpu',
185
+ entrypoint: '@czap/astro/client-directives/gpu',
186
+ });
187
+ logger.info('Registered gpu client directive');
188
+ }
189
+ if (wasmEnabled) {
190
+ addClientDirective({
191
+ name: 'wasm',
192
+ entrypoint: '@czap/astro/client-directives/wasm',
193
+ });
194
+ logger.info('Registered wasm client directive');
195
+ }
196
+ // Inject detect script for client-side capability detection
197
+ if (detectEnabled) {
198
+ injectScript('head-inline', DETECT_INLINE_SCRIPT);
199
+ logger.info('Injected detect script');
200
+ // Inject GPU probe upgrade (deferred, non-blocking)
201
+ if (gpuEnabled) {
202
+ injectScript('page', DETECT_UPGRADE_SCRIPT);
203
+ logger.info('Injected GPU probe upgrade');
204
+ }
205
+ }
206
+ injectScript('page', runtimeBootstrapScript(runtimePolicy));
207
+ if (wasmEnabled) {
208
+ injectScript('page', WASM_RUNTIME_SCRIPT);
209
+ logger.info('Injected wasm runtime bootstrap');
210
+ }
211
+ // Configure server islands if enabled.
212
+ // `serverIslands` is not in Astro 6's declared experimental keys yet;
213
+ // enablement is delegated via a named bridge so only the one call site
214
+ // opts out of the declared-config shape.
215
+ if (serverIslandsEnabled) {
216
+ updateConfig(withExperimentalFlag('serverIslands', true));
217
+ logger.info('Enabled server islands');
218
+ }
219
+ },
220
+ 'astro:config:done': ({ config: astroConfig, logger }) => {
221
+ logger.info(`@czap configured for ${astroConfig.output} output`);
222
+ },
223
+ 'astro:server:setup': ({ server, logger }) => {
224
+ logger.info('@czap dev server middleware active');
225
+ if (detectEnabled || workersEnabled) {
226
+ server.middlewares.use((_req, res, next) => {
227
+ for (const [header, value] of getCzapHeaderEntries({ detectEnabled, workersEnabled })) {
228
+ res.setHeader(header, value);
229
+ }
230
+ next();
231
+ });
232
+ }
233
+ },
234
+ 'astro:build:done': ({ logger }) => {
235
+ logger.info('@czap build integration complete');
236
+ },
237
+ },
238
+ };
239
+ }
240
+ //# sourceMappingURL=integration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.js","sourceRoot":"","sources":["../src/integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EACL,8BAA8B,GAG/B,MAAM,qBAAqB,CAAC;AAoC7B,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiD5B,CAAC,IAAI,EAAE,CAAC;AAET,SAAS,4BAA4B,CAAC,MAA6B;IACjE,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC3G,CAAC;AAED,SAAS,sBAAsB,CAAC,MAA6B;IAC3D,OAAO;;;yBAGgB,4BAA4B,CAAC,MAAM,CAAC;;;CAG5D,CAAC,IAAI,EAAE,CAAC;AACT,CAAC;AAED,MAAM,mBAAmB,GAAG;;;;;CAK3B,CAAC,IAAI,EAAE,CAAC;AAET;;;;;;;GAOG;AACH,SAAS,oBAAoB,CAAC,IAAY,EAAE,KAAc;IACxD,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;AAC7C,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,WAAW,CAAC,MAA0B;IACpD,MAAM,aAAa,GAAG,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;IAC/C,MAAM,oBAAoB,GAAG,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5D,MAAM,cAAc,GAAG,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,MAAM,UAAU,GAAG,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,KAAK,CAAC;IAClD,MAAM,aAAa,GAAG,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,KAAK,CAAC;IACxD,MAAM,UAAU,GAAG,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,KAAK,CAAC;IAClD,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD,MAAM,aAAa,GAAG,8BAA8B,CAAC;QACnD,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc;QAChD,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;KACzC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,aAAa;QAEnB,KAAK,EAAE;YACL,oBAAoB,EAAE,CAAC,EAAE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE;gBAEnF,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;gBAE5C,0EAA0E;gBAC1E,yEAAyE;gBACzE,6EAA6E;gBAC7E,MAAM,eAAe,GAAG;oBACtB,OAAO,EAAE;wBACP,MAAM,CAAC;4BACL,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;4BACvB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;yBAC9E,CAAC;qBACH;iBACiB,CAAC;gBAErB,YAAY,CAAC;oBACX,IAAI,EAAE,eAAe;iBACtB,CAAC,CAAC;gBAEH,6BAA6B;gBAC7B,kBAAkB,CAAC;oBACjB,IAAI,EAAE,WAAW;oBACjB,UAAU,EAAE,yCAAyC;iBACtD,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;gBAErD,IAAI,aAAa,EAAE,CAAC;oBAClB,kBAAkB,CAAC;wBACjB,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE,sCAAsC;qBACnD,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;gBACpD,CAAC;gBAED,IAAI,UAAU,EAAE,CAAC;oBACf,kBAAkB,CAAC;wBACjB,IAAI,EAAE,KAAK;wBACX,UAAU,EAAE,mCAAmC;qBAChD,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;gBACjD,CAAC;gBAED,IAAI,cAAc,EAAE,CAAC;oBACnB,kBAAkB,CAAC;wBACjB,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE,sCAAsC;qBACnD,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;gBACpD,CAAC;gBAED,IAAI,UAAU,EAAE,CAAC;oBACf,kBAAkB,CAAC;wBACjB,IAAI,EAAE,KAAK;wBACX,UAAU,EAAE,mCAAmC;qBAChD,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;gBACjD,CAAC;gBAED,IAAI,WAAW,EAAE,CAAC;oBAChB,kBAAkB,CAAC;wBACjB,IAAI,EAAE,MAAM;wBACZ,UAAU,EAAE,oCAAoC;qBACjD,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;gBAClD,CAAC;gBAED,4DAA4D;gBAC5D,IAAI,aAAa,EAAE,CAAC;oBAClB,YAAY,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;oBAClD,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;oBAEtC,oDAAoD;oBACpD,IAAI,UAAU,EAAE,CAAC;wBACf,YAAY,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;wBAC5C,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;oBAC5C,CAAC;gBACH,CAAC;gBAED,YAAY,CAAC,MAAM,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC,CAAC;gBAE5D,IAAI,WAAW,EAAE,CAAC;oBAChB,YAAY,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;oBAC1C,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;gBACjD,CAAC;gBAED,uCAAuC;gBACvC,sEAAsE;gBACtE,uEAAuE;gBACvE,yCAAyC;gBACzC,IAAI,oBAAoB,EAAE,CAAC;oBACzB,YAAY,CAAC,oBAAoB,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC1D,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;YAED,mBAAmB,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE;gBACvD,MAAM,CAAC,IAAI,CAAC,wBAAwB,WAAW,CAAC,MAAM,SAAS,CAAC,CAAC;YACnE,CAAC;YAED,oBAAoB,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;gBAC3C,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;gBAElD,IAAI,aAAa,IAAI,cAAc,EAAE,CAAC;oBACpC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,GAA8C,EAAE,IAAgB,EAAE,EAAE;wBACzG,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,oBAAoB,CAAC,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC;4BACtF,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;wBAC/B,CAAC;wBACD,IAAI,EAAE,CAAC;oBACT,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,kBAAkB,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;gBACjC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YAClD,CAAC;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Edge middleware -- Client Hints parsing, tier detection, response headers.
3
+ *
4
+ * Framework-agnostic handler compatible with Astro middleware,
5
+ * Cloudflare Workers, and Express/Vite dev server.
6
+ *
7
+ * @module
8
+ */
9
+ import type { CompiledOutputs, EdgeHostAdapterConfig, ThemeCompileResult } from '@czap/edge';
10
+ import type { ExtendedDeviceCapabilities } from '@czap/detect';
11
+ /**
12
+ * Shape of `context.locals.czap` injected by {@link czapMiddleware}.
13
+ * Astro components (and downstream middleware) read this to drive
14
+ * adaptive rendering decisions.
15
+ */
16
+ export interface CzapLocals {
17
+ /** Resolved tiers (capability, motion, design). */
18
+ readonly tier: {
19
+ readonly cap: string;
20
+ readonly motion: string;
21
+ readonly design: string;
22
+ };
23
+ /** Parsed device capabilities. */
24
+ readonly capabilities: ExtendedDeviceCapabilities;
25
+ /** Edge-host resolution result, present when an edge adapter is configured. */
26
+ readonly edge?: {
27
+ readonly theme?: ThemeCompileResult;
28
+ readonly compiledOutputs?: CompiledOutputs;
29
+ readonly htmlAttributes: string;
30
+ readonly cacheStatus: 'disabled' | 'hit' | 'miss';
31
+ };
32
+ }
33
+ /**
34
+ * Options accepted by {@link czapMiddleware}.
35
+ *
36
+ * Omit `edge` to run in pure Client-Hints mode. Pass `edge` when you
37
+ * have an `@czap/edge` host adapter (KV cache, theme compilation).
38
+ */
39
+ export interface CzapMiddlewareConfig {
40
+ /** Edge host adapter configuration (KV cache, theme compilation). */
41
+ readonly edge?: EdgeHostAdapterConfig;
42
+ /** Whether to include the Client Hints request headers (default `true`). */
43
+ readonly detect?: boolean;
44
+ /** Whether to emit COOP/COEP headers for worker features. */
45
+ readonly workers?: {
46
+ readonly enabled?: boolean;
47
+ };
48
+ }
49
+ interface MiddlewareContext {
50
+ readonly request: Request;
51
+ locals: Record<string, unknown>;
52
+ }
53
+ /**
54
+ * Create the czap edge middleware.
55
+ *
56
+ * Parses Client Hints from request headers, computes tier detection,
57
+ * injects results into `context.locals.czap`, and sets Client Hints
58
+ * response headers (`Accept-CH`, `Critical-CH`).
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // Astro middleware (src/middleware.ts)
63
+ * import { czapMiddleware } from '@czap/astro';
64
+ * export const onRequest = czapMiddleware();
65
+ * ```
66
+ */
67
+ export declare function czapMiddleware(config?: CzapMiddlewareConfig): (context: MiddlewareContext, next: () => Promise<Response>) => Promise<Response>;
68
+ export {};
69
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAO/D;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,kCAAkC;IAClC,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAClD,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC;QACpC,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;QAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG,KAAK,GAAG,MAAM,CAAC;KACnD,CAAC;CACH;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACnD;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,MAAM,CAAC,EAAE,oBAAoB,GAC5B,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAmDlF"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Edge middleware -- Client Hints parsing, tier detection, response headers.
3
+ *
4
+ * Framework-agnostic handler compatible with Astro middleware,
5
+ * Cloudflare Workers, and Express/Vite dev server.
6
+ *
7
+ * @module
8
+ */
9
+ import { ClientHints, createEdgeHostAdapter, EdgeTier } from '@czap/edge';
10
+ import { applyCzapHeaders } from './headers.js';
11
+ // ---------------------------------------------------------------------------
12
+ // Middleware
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Create the czap edge middleware.
16
+ *
17
+ * Parses Client Hints from request headers, computes tier detection,
18
+ * injects results into `context.locals.czap`, and sets Client Hints
19
+ * response headers (`Accept-CH`, `Critical-CH`).
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // Astro middleware (src/middleware.ts)
24
+ * import { czapMiddleware } from '@czap/astro';
25
+ * export const onRequest = czapMiddleware();
26
+ * ```
27
+ */
28
+ export function czapMiddleware(config) {
29
+ const edgeConfig = config?.edge;
30
+ let edgeAdapter = null;
31
+ if (edgeConfig) {
32
+ edgeAdapter = createEdgeHostAdapter(edgeConfig);
33
+ }
34
+ const detectEnabled = config?.detect !== false;
35
+ const workersEnabled = config?.workers?.enabled === true;
36
+ return async (context, next) => {
37
+ const edgeResolution = edgeAdapter ? await edgeAdapter.resolve(context.request.headers) : null;
38
+ const capabilities = edgeResolution?.capabilities ?? ClientHints.parseClientHints(context.request.headers);
39
+ const tier = edgeResolution?.tier ?? EdgeTier.detectTier(context.request.headers);
40
+ // Inject into locals for component access
41
+ context.locals.czap = {
42
+ tier: {
43
+ cap: tier.capLevel,
44
+ motion: tier.motionTier,
45
+ design: tier.designTier,
46
+ },
47
+ capabilities,
48
+ ...(edgeResolution
49
+ ? {
50
+ edge: {
51
+ theme: edgeResolution.theme,
52
+ compiledOutputs: edgeResolution.compiledOutputs,
53
+ htmlAttributes: edgeResolution.htmlAttributes,
54
+ cacheStatus: edgeResolution.cacheStatus,
55
+ },
56
+ }
57
+ : {}),
58
+ };
59
+ // Continue to the route handler
60
+ const response = await next();
61
+ // Add Client Hints request headers to the response
62
+ const headers = applyCzapHeaders(new Headers(response.headers), {
63
+ detectEnabled,
64
+ workersEnabled,
65
+ acceptCH: edgeResolution?.responseHeaders.acceptCH ?? ClientHints.acceptCHHeader(),
66
+ criticalCH: edgeResolution?.responseHeaders.criticalCH ?? ClientHints.criticalCHHeader(),
67
+ });
68
+ return new Response(response.body, {
69
+ status: response.status,
70
+ statusText: response.statusText,
71
+ headers,
72
+ });
73
+ };
74
+ }
75
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAiDhD,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC5B,MAA6B;IAE7B,MAAM,UAAU,GAAG,MAAM,EAAE,IAAI,CAAC;IAChC,IAAI,WAAW,GAAoD,IAAI,CAAC;IACxE,IAAI,UAAU,EAAE,CAAC;QACf,WAAW,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;IAC/C,MAAM,cAAc,GAAG,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzD,OAAO,KAAK,EAAE,OAA0B,EAAE,IAA6B,EAAqB,EAAE;QAC5F,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/F,MAAM,YAAY,GAAG,cAAc,EAAE,YAAY,IAAI,WAAW,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3G,MAAM,IAAI,GAAG,cAAc,EAAE,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAElF,0CAA0C;QAC1C,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG;YACpB,IAAI,EAAE;gBACJ,GAAG,EAAE,IAAI,CAAC,QAAQ;gBAClB,MAAM,EAAE,IAAI,CAAC,UAAU;gBACvB,MAAM,EAAE,IAAI,CAAC,UAAU;aACxB;YACD,YAAY;YACZ,GAAG,CAAC,cAAc;gBAChB,CAAC,CAAC;oBACE,IAAI,EAAE;wBACJ,KAAK,EAAE,cAAc,CAAC,KAAK;wBAC3B,eAAe,EAAE,cAAc,CAAC,eAAe;wBAC/C,cAAc,EAAE,cAAc,CAAC,cAAc;wBAC7C,WAAW,EAAE,cAAc,CAAC,WAAW;qBACxC;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACa,CAAC;QAEvB,gCAAgC;QAChC,MAAM,QAAQ,GAAG,MAAM,IAAI,EAAE,CAAC;QAE9B,mDAAmD;QACnD,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;YAC9D,aAAa;YACb,cAAc;YACd,QAAQ,EAAE,cAAc,EAAE,eAAe,CAAC,QAAQ,IAAI,WAAW,CAAC,cAAc,EAAE;YAClF,UAAU,EAAE,cAAc,EAAE,eAAe,CAAC,UAAU,IAAI,WAAW,CAAC,gBAAgB,EAAE;SACzF,CAAC,CAAC;QAEH,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;YACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,OAAO;SACR,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Quantize component helpers -- server-side initial state resolution.
3
+ *
4
+ * Maps {@link ServerIslandContext} (user agent, client hints, detected
5
+ * tier) to the best initial boundary state for SSR and server islands.
6
+ *
7
+ * @module
8
+ */
9
+ import type { Boundary, CapLevel, Quantizer } from '@czap/core';
10
+ /**
11
+ * Server-only context that {@link resolveInitialState} consumes. Astro
12
+ * builds this from the incoming request (user agent + Client Hints)
13
+ * and the tier detected by the edge middleware.
14
+ */
15
+ export interface ServerIslandContext {
16
+ /** Raw `User-Agent` header. */
17
+ readonly userAgent: string;
18
+ /** Flat Client Hints header map. */
19
+ readonly clientHints: Record<string, string>;
20
+ /** Tier detected by `@czap/edge`. */
21
+ readonly detectedTier: CapLevel;
22
+ }
23
+ /**
24
+ * Props accepted by the `Quantize` Astro component and by
25
+ * {@link resolveInitialState}.
26
+ */
27
+ export interface QuantizeProps<B extends Boundary.Shape = Boundary.Shape> {
28
+ /** Boundary to quantize. */
29
+ readonly boundary: B;
30
+ /** Optional explicit quantizer definition. */
31
+ readonly quantizer?: Quantizer<B>;
32
+ /** Explicit initial state (skips resolution). */
33
+ readonly initialState?: string;
34
+ /** Final fallback if resolution fails. */
35
+ readonly fallback?: string;
36
+ /** Extra CSS class names. */
37
+ readonly class?: string;
38
+ }
39
+ /**
40
+ * Resolve the initial boundary state for server-side rendering.
41
+ *
42
+ * Priority:
43
+ * 1. Use viewport width from client hints if available
44
+ * 2. Estimate viewport from user agent
45
+ * 3. Fall back to tier-based synthetic value
46
+ *
47
+ * Evaluates the boundary thresholds to find the matching state.
48
+ */
49
+ export declare function resolveInitialState<B extends Boundary.Shape>(boundary: B, context: ServerIslandContext): string;
50
+ //# sourceMappingURL=quantize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quantize.d.ts","sourceRoot":"","sources":["../src/quantize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOhE;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,+BAA+B;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,qCAAqC;IACrC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK;IACtE,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAClC,iDAAiD;IACjD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AA6ED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAwC/G"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Quantize component helpers -- server-side initial state resolution.
3
+ *
4
+ * Maps {@link ServerIslandContext} (user agent, client hints, detected
5
+ * tier) to the best initial boundary state for SSR and server islands.
6
+ *
7
+ * @module
8
+ */
9
+ import { VIEWPORT } from '@czap/core';
10
+ // ---------------------------------------------------------------------------
11
+ // Client Hint Parsing
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Parse a viewport width from client hints.
15
+ * Supports Sec-CH-Viewport-Width and Sec-CH-Width headers.
16
+ */
17
+ function parseViewportWidth(clientHints) {
18
+ const raw = clientHints['sec-ch-viewport-width'] ??
19
+ clientHints['Sec-CH-Viewport-Width'] ??
20
+ clientHints['sec-ch-width'] ??
21
+ clientHints['Sec-CH-Width'];
22
+ if (raw === undefined)
23
+ return undefined;
24
+ const parsed = parseInt(raw, 10);
25
+ return Number.isFinite(parsed) ? parsed : undefined;
26
+ }
27
+ /**
28
+ * Parse prefers-reduced-motion from client hints.
29
+ */
30
+ function parsePrefersReducedMotion(clientHints) {
31
+ const raw = clientHints['sec-ch-prefers-reduced-motion'] ?? clientHints['Sec-CH-Prefers-Reduced-Motion'];
32
+ if (raw === undefined)
33
+ return undefined;
34
+ return raw === 'reduce';
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // User Agent Heuristics
38
+ // ---------------------------------------------------------------------------
39
+ /**
40
+ * Estimate a viewport width from user agent string for common device classes.
41
+ */
42
+ function estimateViewportFromUA(ua) {
43
+ const lower = ua.toLowerCase();
44
+ if (lower.includes('mobile') || lower.includes('android') || lower.includes('iphone')) {
45
+ return VIEWPORT.mobile;
46
+ }
47
+ if (lower.includes('tablet') || lower.includes('ipad')) {
48
+ return VIEWPORT.tablet;
49
+ }
50
+ return VIEWPORT.desktop;
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Tier-Based Heuristic
54
+ // ---------------------------------------------------------------------------
55
+ const TIER_ORDINALS = {
56
+ static: 0,
57
+ styled: 1,
58
+ reactive: 2,
59
+ animated: 3,
60
+ gpu: 4,
61
+ };
62
+ /**
63
+ * Map a CapLevel tier to a synthetic viewport-like value for boundary evaluation.
64
+ * This bridges between the capability tier system and viewport-based boundaries.
65
+ */
66
+ function syntheticValueFromTier(tier) {
67
+ const ord = TIER_ORDINALS[tier];
68
+ // Map tier ordinal to viewport-like breakpoints: 320, 640, 960, 1280, 1920
69
+ return 320 + ord * 320;
70
+ }
71
+ // ---------------------------------------------------------------------------
72
+ // Public API
73
+ // ---------------------------------------------------------------------------
74
+ /**
75
+ * Resolve the initial boundary state for server-side rendering.
76
+ *
77
+ * Priority:
78
+ * 1. Use viewport width from client hints if available
79
+ * 2. Estimate viewport from user agent
80
+ * 3. Fall back to tier-based synthetic value
81
+ *
82
+ * Evaluates the boundary thresholds to find the matching state.
83
+ */
84
+ export function resolveInitialState(boundary, context) {
85
+ const stateNames = boundary.states;
86
+ const thresholds = boundary.thresholds;
87
+ if (stateNames.length === 0)
88
+ return '';
89
+ if (stateNames.length === 1)
90
+ return stateNames[0];
91
+ // Determine the signal value to evaluate against the boundary
92
+ let value;
93
+ // Check client hints first (most accurate)
94
+ const hintWidth = parseViewportWidth(context.clientHints);
95
+ const reducedMotion = parsePrefersReducedMotion(context.clientHints);
96
+ if (hintWidth !== undefined) {
97
+ value = hintWidth;
98
+ }
99
+ else if (context.userAgent) {
100
+ value = estimateViewportFromUA(context.userAgent);
101
+ }
102
+ else {
103
+ value = syntheticValueFromTier(context.detectedTier);
104
+ }
105
+ // If reduced motion is detected and the tier suggests limited capability,
106
+ // bias toward the lowest state
107
+ if (reducedMotion === true && TIER_ORDINALS[context.detectedTier] <= 1) {
108
+ return stateNames[0];
109
+ }
110
+ // Evaluate against boundary thresholds to find the matching state.
111
+ // thresholds[i] is the lower bound for state[i].
112
+ // Walk backwards from the highest threshold to find the first match.
113
+ for (let i = stateNames.length - 1; i >= 0; i--) {
114
+ const threshold = thresholds[i];
115
+ if (threshold !== undefined && value >= threshold) {
116
+ return stateNames[i];
117
+ }
118
+ }
119
+ // Fallback to first state
120
+ return stateNames[0];
121
+ }
122
+ //# sourceMappingURL=quantize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quantize.js","sourceRoot":"","sources":["../src/quantize.ts"],"names":[],"mappings":"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"}