@strata-ds/core 2.1.5 → 2.1.16

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/README.md CHANGED
@@ -524,6 +524,61 @@ const MyComponent = StrataComponentFactory.createComponent(
524
524
  componentData,
525
525
  designSystem,
526
526
  );
527
+ ## Offline Resilience & Build-Time Fallbacks
528
+
529
+ `@strata-ds/core` is built to be completely resilient to network outages, CDN downtime, or slow connections using a multi-layered fallback strategy.
530
+
531
+ ### How It Works (The 4 Layers of Defense)
532
+
533
+ 1. **Static CSS Fallbacks (No-JS / Instant Load)**: Design tokens are pre-rendered into a plain CSS file (`strata-fallbacks.css`) containing direct `:root` custom property assignments. This stylesheet loads statically before React boots, ensuring the page never flickers or appears unstyled.
534
+ 2. **Instant React Hydration (`initialData`)**: When the React application mounts, `StrataProvider` initializes with the local snapshot JSON file, allowing it to render immediately with real values without waiting for a CDN fetch.
535
+ 3. **Automatic `localStorage` Cache (Fallback)**: If the app is online, the SDK automatically caches successful live sync updates to `localStorage`. If a user reloads the page while offline, the SDK retrieves the last-known-good cache.
536
+ 4. **ETag Delta Sync (Bandwidth Optimization)**: Live sync requests include an `If-None-Match` conditional header. If nothing changed, the CDN returns a `304 Not Modified` with no body payload—minimizing data usage to ~0 bytes per poll.
537
+
538
+ ---
539
+
540
+ ### Step-by-Step Setup Guide
541
+
542
+ Any project using the Strata Design System can enable full offline resilience in three quick steps:
543
+
544
+ #### Step 1: Generate the Local Snapshot and Fallback CSS
545
+ Run the CLI snapshot tool locally or add it to your project's build process:
546
+ ```bash
547
+ npx strata-ds snapshot \
548
+ --project-id "YOUR_PROJECT_ID" \
549
+ --cdn-base "https://your-cdn-base-url.cloudfront.net" \
550
+ --output "./src/data/strata-snapshot.json" \
551
+ --output-css "./src/styles/strata-fallbacks.css" \
552
+ --variables-only
553
+ ```
554
+ *(Commit the generated JSON and CSS files to your Git repository as your baseline fallback).*
555
+
556
+ #### Step 2: Import Fallback Styles
557
+ Reference the CSS file in your main style entry point (e.g., `src/index.css` or `src/App.css`):
558
+ ```css
559
+ @import './styles/strata-fallbacks.css';
560
+ ```
561
+
562
+ #### Step 3: Configure StrataProvider
563
+ Import the snapshot and configure your `StrataProvider`:
564
+ ```tsx
565
+ import React from 'react';
566
+ import { StrataProvider } from '@strata-ds/core';
567
+ import strataSnapshot from './data/strata-snapshot.json';
568
+
569
+ export default function App() {
570
+ return (
571
+ <StrataProvider
572
+ initialData={strataSnapshot}
573
+ syncEnabled={true}
574
+ projectId="YOUR_PROJECT_ID"
575
+ snapshotCdnBase="https://your-cdn-base-url.cloudfront.net"
576
+ syncInterval={5000}
577
+ >
578
+ <MainLayout />
579
+ </StrataProvider>
580
+ );
581
+ }
527
582
  ```
528
583
 
529
584
  ## Key Features
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ function printHelp() {
7
+ console.log(`
8
+ Strata Design System Snapshot CLI
9
+
10
+ Usage:
11
+ npx strata-ds [options]
12
+
13
+ Options:
14
+ --project-id Strata Project ID (required)
15
+ --cdn-base CDN base URL (e.g. https://dx2nhw7wqn4nn.cloudfront.net) (required)
16
+ --output Path to write the snapshot JSON file (optional)
17
+ --output-css Path to write the CSS fallback file (optional)
18
+ --sync-token Authorization Sync Token (optional)
19
+ --variables-only Only output variables in the snapshot JSON (optional)
20
+ --help, -h Show help
21
+ `);
22
+ }
23
+ async function run() {
24
+ const args = process.argv.slice(2);
25
+ if (args.includes('--help') || args.includes('-h') || args.length === 0) {
26
+ printHelp();
27
+ process.exit(0);
28
+ }
29
+ const getArgValue = (flag) => {
30
+ const idx = args.indexOf(flag);
31
+ if (idx !== -1 && idx + 1 < args.length) {
32
+ return args[idx + 1];
33
+ }
34
+ return undefined;
35
+ };
36
+ const hasFlag = (flag) => {
37
+ return args.includes(flag);
38
+ };
39
+ const projectId = getArgValue('--project-id');
40
+ const cdnBase = getArgValue('--cdn-base');
41
+ const outputPath = getArgValue('--output');
42
+ const outputCssPath = getArgValue('--output-css');
43
+ const syncToken = getArgValue('--sync-token');
44
+ const variablesOnly = hasFlag('--variables-only');
45
+ if (!projectId || !cdnBase) {
46
+ console.error('❌ Error: --project-id and --cdn-base are required.');
47
+ printHelp();
48
+ process.exit(1);
49
+ }
50
+ const base = cdnBase.replace(/\/+$/, '');
51
+ const snapshotUrl = base.endsWith('/snapshots')
52
+ ? `${base}/${projectId}/strata.json`
53
+ : `${base}/snapshots/${projectId}/strata.json`;
54
+ console.log(`📡 Fetching snapshot from: ${snapshotUrl}`);
55
+ try {
56
+ const headers = {};
57
+ if (syncToken) {
58
+ headers['Authorization'] = `Bearer ${syncToken}`;
59
+ }
60
+ const res = await fetch(snapshotUrl, { headers });
61
+ if (!res.ok) {
62
+ throw new Error(`Server returned ${res.status} ${res.statusText}`);
63
+ }
64
+ const data = await res.json();
65
+ // Validate shape
66
+ if (!data || typeof data !== 'object' || typeof data.variables !== 'object') {
67
+ throw new Error('Invalid snapshot response shape: missing variables');
68
+ }
69
+ let snapshotJson = data;
70
+ if (variablesOnly) {
71
+ snapshotJson = {
72
+ variables: data.variables,
73
+ };
74
+ }
75
+ // Write JSON output if requested
76
+ if (outputPath) {
77
+ const resolvedOutput = path.resolve(outputPath);
78
+ fs.mkdirSync(path.dirname(resolvedOutput), { recursive: true });
79
+ fs.writeFileSync(resolvedOutput, JSON.stringify(snapshotJson, null, 2), 'utf-8');
80
+ console.log(`✅ Snapshot JSON written to: ${resolvedOutput}`);
81
+ }
82
+ // Write CSS output if requested
83
+ if (outputCssPath) {
84
+ const resolvedCssOutput = path.resolve(outputCssPath);
85
+ fs.mkdirSync(path.dirname(resolvedCssOutput), { recursive: true });
86
+ let cssContent = `/* @strata-ds/core — Auto-generated CSS fallback variables\n`;
87
+ cssContent += ` * Project: ${projectId}\n`;
88
+ cssContent += ` * Generated: ${new Date().toISOString()}\n`;
89
+ cssContent += ` * DO NOT EDIT MANUALLY — regenerate with CLI snapshot tool\n`;
90
+ cssContent += ` */\n\n`;
91
+ cssContent += `:root {\n`;
92
+ const variables = data.variables || {};
93
+ for (const [key, val] of Object.entries(variables)) {
94
+ const resolvedVal = val.resolvedValue ?? val.value;
95
+ cssContent += ` ${key}: ${resolvedVal};\n`;
96
+ }
97
+ cssContent += `}\n`;
98
+ fs.writeFileSync(resolvedCssOutput, cssContent, 'utf-8');
99
+ console.log(`✅ CSS fallback written to: ${resolvedCssOutput}`);
100
+ }
101
+ }
102
+ catch (error) {
103
+ console.warn(`⚠️ Warning: Fetch failed: ${error.message || error}`);
104
+ // If fetch failed, check if output files already exist to degrade gracefully (exit 0)
105
+ let jsonExists = false;
106
+ let cssExists = false;
107
+ if (outputPath && fs.existsSync(path.resolve(outputPath))) {
108
+ jsonExists = true;
109
+ }
110
+ if (outputCssPath && fs.existsSync(path.resolve(outputCssPath))) {
111
+ cssExists = true;
112
+ }
113
+ const requestedOutputs = [];
114
+ if (outputPath)
115
+ requestedOutputs.push('JSON');
116
+ if (outputCssPath)
117
+ requestedOutputs.push('CSS');
118
+ const existingOutputs = [];
119
+ if (jsonExists)
120
+ existingOutputs.push('JSON');
121
+ if (cssExists)
122
+ existingOutputs.push('CSS');
123
+ if (requestedOutputs.length > 0 && requestedOutputs.length === existingOutputs.length) {
124
+ console.warn(`ℹ️ Existing output file(s) found. Graceful degradation: exiting 0.`);
125
+ process.exit(0);
126
+ }
127
+ else {
128
+ console.error('❌ Error: Fetch failed and no existing local outputs found to fall back on.');
129
+ process.exit(1);
130
+ }
131
+ }
132
+ }
133
+ run();
@@ -7,6 +7,7 @@ export type DesignToken = {
7
7
  comment: string;
8
8
  category?: string;
9
9
  deprecated?: boolean;
10
+ resolvedValue?: string;
10
11
  };
11
12
  export type ComponentProperty = {
12
13
  value: string;
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ type DesignToken = {
11
11
  comment: string;
12
12
  category?: string;
13
13
  deprecated?: boolean;
14
+ resolvedValue?: string;
14
15
  };
15
16
  type ComponentProperty = {
16
17
  value: string;
@@ -87,6 +88,8 @@ interface StrataContextType {
87
88
  syncToken: string | undefined;
88
89
  snapshotCdnBase: string | undefined;
89
90
  projectId: string | undefined;
91
+ dataSource: "live" | "cache" | "initial" | "empty";
92
+ cacheAge: number | null;
90
93
  }
91
94
  declare const useStrata: () => StrataContextType;
92
95
  interface StrataProviderProps {
@@ -133,6 +136,16 @@ interface StrataProviderProps {
133
136
  * Use this to show a loading indicator or log sync lifecycle events.
134
137
  */
135
138
  onSyncStart?: () => void;
139
+ /**
140
+ * Whether to persist and restore cached snapshot to/from localStorage.
141
+ * Defaults to true.
142
+ */
143
+ persistCache?: boolean;
144
+ /**
145
+ * Whether to automatically inject design system variables into document.documentElement.
146
+ * Defaults to true.
147
+ */
148
+ injectCssVars?: boolean;
136
149
  }
137
150
  declare const StrataProvider: React__default.FC<StrataProviderProps>;
138
151
 
package/dist/index.esm.js CHANGED
@@ -1113,35 +1113,103 @@ var StrataProvider = function StrataProvider(_ref) {
1113
1113
  projectId = _ref.projectId,
1114
1114
  onSyncError = _ref.onSyncError,
1115
1115
  onSyncSuccess = _ref.onSyncSuccess,
1116
- onSyncStart = _ref.onSyncStart;
1117
- var _useState = useState(userDesignSystem || initialData || {
1118
- variables: {},
1119
- components: {},
1120
- custom: {
1121
- variables: {},
1122
- components: {}
1116
+ onSyncStart = _ref.onSyncStart,
1117
+ _ref$persistCache = _ref.persistCache,
1118
+ persistCache = _ref$persistCache === void 0 ? true : _ref$persistCache,
1119
+ _ref$injectCssVars = _ref.injectCssVars,
1120
+ injectCssVars = _ref$injectCssVars === void 0 ? true : _ref$injectCssVars;
1121
+ var _useState = useState(function () {
1122
+ if (userDesignSystem) return "initial";
1123
+ if (initialData) return "initial";
1124
+ if (persistCache && projectId) {
1125
+ if (typeof window !== "undefined") {
1126
+ try {
1127
+ var cached = localStorage.getItem("strata-cache-".concat(projectId));
1128
+ if (cached) return "cache";
1129
+ } catch (e) {}
1130
+ }
1123
1131
  }
1132
+ return "empty";
1124
1133
  }),
1125
1134
  _useState2 = _slicedToArray(_useState, 2),
1126
- designSystem = _useState2[0],
1127
- setDesignSystem = _useState2[1];
1128
- var _useState3 = useState("idle"),
1135
+ dataSource = _useState2[0],
1136
+ setDataSource = _useState2[1];
1137
+ var _useState3 = useState(function () {
1138
+ if (userDesignSystem || initialData) return Date.now();
1139
+ if (persistCache && projectId) {
1140
+ if (typeof window !== "undefined") {
1141
+ try {
1142
+ var ts = localStorage.getItem("strata-cache-ts-".concat(projectId));
1143
+ if (ts) {
1144
+ var parsed = Number.parseInt(ts, 10);
1145
+ if (Number.isFinite(parsed)) return parsed;
1146
+ }
1147
+ } catch (e) {}
1148
+ }
1149
+ }
1150
+ return null;
1151
+ }),
1129
1152
  _useState4 = _slicedToArray(_useState3, 2),
1130
- syncStatus = _useState4[0],
1131
- setSyncStatus = _useState4[1];
1132
- var _useState5 = useState(null),
1153
+ dataTimestamp = _useState4[0],
1154
+ setDataTimestamp = _useState4[1];
1155
+ var _useState5 = useState(function () {
1156
+ if (userDesignSystem) return userDesignSystem;
1157
+ if (initialData) return initialData;
1158
+ if (persistCache && projectId) {
1159
+ if (typeof window !== "undefined") {
1160
+ try {
1161
+ var cached = localStorage.getItem("strata-cache-".concat(projectId));
1162
+ if (cached) {
1163
+ var parsed = JSON.parse(cached);
1164
+ if (parsed && parsed.variables && parsed.components) {
1165
+ return parsed;
1166
+ }
1167
+ }
1168
+ } catch (e) {}
1169
+ }
1170
+ }
1171
+ return {
1172
+ variables: {},
1173
+ components: {},
1174
+ custom: {
1175
+ variables: {},
1176
+ components: {}
1177
+ }
1178
+ };
1179
+ }),
1133
1180
  _useState6 = _slicedToArray(_useState5, 2),
1134
- lastSynced = _useState6[0],
1135
- setLastSynced = _useState6[1];
1136
- var _useState7 = useState(0),
1181
+ designSystem = _useState6[0],
1182
+ setDesignSystem = _useState6[1];
1183
+ var _useState7 = useState("idle"),
1137
1184
  _useState8 = _slicedToArray(_useState7, 2),
1138
- syncVersion = _useState8[0],
1139
- setSyncVersion = _useState8[1];
1185
+ syncStatus = _useState8[0],
1186
+ setSyncStatus = _useState8[1];
1187
+ var _useState9 = useState(function () {
1188
+ if (typeof window !== "undefined" && persistCache && projectId) {
1189
+ try {
1190
+ var ts = localStorage.getItem("strata-cache-ts-".concat(projectId));
1191
+ if (ts) {
1192
+ var parsed = Number.parseInt(ts, 10);
1193
+ if (Number.isFinite(parsed)) return new Date(parsed);
1194
+ }
1195
+ } catch (e) {}
1196
+ }
1197
+ return null;
1198
+ }),
1199
+ _useState0 = _slicedToArray(_useState9, 2),
1200
+ lastSynced = _useState0[0],
1201
+ setLastSynced = _useState0[1];
1202
+ var _useState1 = useState(0),
1203
+ _useState10 = _slicedToArray(_useState1, 2),
1204
+ syncVersion = _useState10[0],
1205
+ setSyncVersion = _useState10[1];
1140
1206
  // Ref that tracks the JSON string of the last successfully synced payload so
1141
1207
  // that syncDesignSystem does not need to close over the designSystem state
1142
1208
  // value. This keeps the callback stable and prevents the polling interval
1143
1209
  // from being continuously reset after each successful sync.
1144
1210
  var lastSyncedStringRef = useRef(null);
1211
+ // Ref to track the ETag of the last fetched snapshot
1212
+ var lastETagRef = useRef(null);
1145
1213
  // Refs for lifecycle callbacks so that syncDesignSystem does not need to
1146
1214
  // close over them. Inline functions passed by the consumer (e.g. anonymous
1147
1215
  // arrow functions) would otherwise change identity on every render, forcing
@@ -1178,7 +1246,7 @@ var StrataProvider = function StrataProvider(_ref) {
1178
1246
  }, []);
1179
1247
  var syncDesignSystem = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
1180
1248
  var _onSyncStartRef$curre;
1181
- var headers, remoteData, res, _onSyncErrorRef$curre, data, _onSyncErrorRef$curre2, _yield$Promise$all, _yield$Promise$all2, variablesRes, componentsRes, customRes, _yield$Promise$all3, _yield$Promise$all4, variables, components, custom, newDataString, _onSyncSuccessRef$cur, _onSyncErrorRef$curre3, _t;
1249
+ var headers, remoteData, res, _onSyncErrorRef$curre, etag, data, _onSyncErrorRef$curre2, _yield$Promise$all, _yield$Promise$all2, variablesRes, componentsRes, customRes, _yield$Promise$all3, _yield$Promise$all4, variables, components, custom, newDataString, _onSyncSuccessRef$cur, _onSyncErrorRef$curre3, _t;
1182
1250
  return _regenerator().w(function (_context) {
1183
1251
  while (1) switch (_context.p = _context.n) {
1184
1252
  case 0:
@@ -1195,19 +1263,30 @@ var StrataProvider = function StrataProvider(_ref) {
1195
1263
  Authorization: "Bearer ".concat(syncToken)
1196
1264
  } : {};
1197
1265
  if (!snapshotUrl) {
1198
- _context.n = 8;
1266
+ _context.n = 9;
1199
1267
  break;
1200
1268
  }
1269
+ if (lastETagRef.current) {
1270
+ headers["If-None-Match"] = lastETagRef.current;
1271
+ }
1272
+ // Single CDN snapshot fetch — edge-cached, 1 request per poll
1201
1273
  _context.n = 3;
1202
1274
  return fetch(snapshotUrl, {
1203
1275
  headers: headers
1204
1276
  });
1205
1277
  case 3:
1206
1278
  res = _context.v;
1207
- if (!(!res.ok && res.status >= 400 && res.status < 500)) {
1279
+ if (!(res.status === 304)) {
1208
1280
  _context.n = 4;
1209
1281
  break;
1210
1282
  }
1283
+ setSyncStatus("idle");
1284
+ return _context.a(2);
1285
+ case 4:
1286
+ if (!(!res.ok && res.status >= 400 && res.status < 500)) {
1287
+ _context.n = 5;
1288
+ break;
1289
+ }
1211
1290
  setSyncStatus("error");
1212
1291
  (_onSyncErrorRef$curre = onSyncErrorRef.current) === null || _onSyncErrorRef$curre === void 0 || _onSyncErrorRef$curre.call(onSyncErrorRef, {
1213
1292
  code: res.status,
@@ -1215,19 +1294,23 @@ var StrataProvider = function StrataProvider(_ref) {
1215
1294
  source: "cdn"
1216
1295
  });
1217
1296
  return _context.a(2);
1218
- case 4:
1297
+ case 5:
1219
1298
  if (res.ok) {
1220
- _context.n = 5;
1299
+ _context.n = 6;
1221
1300
  break;
1222
1301
  }
1223
1302
  throw new Error("Snapshot fetch failed: ".concat(res.status));
1224
- case 5:
1225
- _context.n = 6;
1226
- return res.json();
1227
1303
  case 6:
1304
+ etag = res.headers.get("ETag");
1305
+ if (etag) {
1306
+ lastETagRef.current = etag;
1307
+ }
1308
+ _context.n = 7;
1309
+ return res.json();
1310
+ case 7:
1228
1311
  data = _context.v;
1229
1312
  if (!(!data || _typeof(data) !== "object" || Array.isArray(data) || _typeof(data.variables) !== "object" || data.variables === null || Array.isArray(data.variables) || _typeof(data.components) !== "object" || data.components === null || Array.isArray(data.components))) {
1230
- _context.n = 7;
1313
+ _context.n = 8;
1231
1314
  break;
1232
1315
  }
1233
1316
  console.warn("[strata] Invalid snapshot shape received from CDN — skipping update.");
@@ -1238,7 +1321,7 @@ var StrataProvider = function StrataProvider(_ref) {
1238
1321
  source: "cdn"
1239
1322
  });
1240
1323
  return _context.a(2);
1241
- case 7:
1324
+ case 8:
1242
1325
  remoteData = {
1243
1326
  variables: data.variables,
1244
1327
  components: data.components,
@@ -1251,10 +1334,10 @@ var StrataProvider = function StrataProvider(_ref) {
1251
1334
  // ComponentNode shape so that useDynamicComponents and the registry
1252
1335
  // always receive consistently-shaped data.
1253
1336
  remoteData = normalizeComponents(remoteData);
1254
- _context.n = 14;
1337
+ _context.n = 15;
1255
1338
  break;
1256
- case 8:
1257
- _context.n = 9;
1339
+ case 9:
1340
+ _context.n = 10;
1258
1341
  return Promise.all([fetch("".concat(syncUrl, "/variables"), {
1259
1342
  headers: headers
1260
1343
  }), fetch("".concat(syncUrl, "/components"), {
@@ -1262,33 +1345,33 @@ var StrataProvider = function StrataProvider(_ref) {
1262
1345
  }), fetch("".concat(syncUrl, "/custom"), {
1263
1346
  headers: headers
1264
1347
  })]);
1265
- case 9:
1348
+ case 10:
1266
1349
  _yield$Promise$all = _context.v;
1267
1350
  _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 3);
1268
1351
  variablesRes = _yield$Promise$all2[0];
1269
1352
  componentsRes = _yield$Promise$all2[1];
1270
1353
  customRes = _yield$Promise$all2[2];
1271
1354
  if (variablesRes.ok) {
1272
- _context.n = 10;
1355
+ _context.n = 11;
1273
1356
  break;
1274
1357
  }
1275
1358
  throw new Error("Variables fetch failed: ".concat(variablesRes.status));
1276
- case 10:
1359
+ case 11:
1277
1360
  if (componentsRes.ok) {
1278
- _context.n = 11;
1361
+ _context.n = 12;
1279
1362
  break;
1280
1363
  }
1281
1364
  throw new Error("Components fetch failed: ".concat(componentsRes.status));
1282
- case 11:
1365
+ case 12:
1283
1366
  if (customRes.ok) {
1284
- _context.n = 12;
1367
+ _context.n = 13;
1285
1368
  break;
1286
1369
  }
1287
1370
  throw new Error("Custom fetch failed: ".concat(customRes.status));
1288
- case 12:
1289
- _context.n = 13;
1290
- return Promise.all([variablesRes.json(), componentsRes.json(), customRes.json()]);
1291
1371
  case 13:
1372
+ _context.n = 14;
1373
+ return Promise.all([variablesRes.json(), componentsRes.json(), customRes.json()]);
1374
+ case 14:
1292
1375
  _yield$Promise$all3 = _context.v;
1293
1376
  _yield$Promise$all4 = _slicedToArray(_yield$Promise$all3, 3);
1294
1377
  variables = _yield$Promise$all4[0];
@@ -1306,7 +1389,7 @@ var StrataProvider = function StrataProvider(_ref) {
1306
1389
  // ComponentNode shape so that useDynamicComponents and the registry
1307
1390
  // always receive consistently-shaped data.
1308
1391
  remoteData = normalizeComponents(remoteData);
1309
- case 14:
1392
+ case 15:
1310
1393
  // Only update if data actually changed (compared against the last synced
1311
1394
  // snapshot via ref, so this callback stays stable across renders).
1312
1395
  newDataString = JSON.stringify(remoteData);
@@ -1319,14 +1402,22 @@ var StrataProvider = function StrataProvider(_ref) {
1319
1402
  });
1320
1403
  setSyncStatus("success");
1321
1404
  setLastSynced(new Date());
1405
+ setDataSource("live");
1406
+ setDataTimestamp(Date.now());
1407
+ if (persistCache && projectId) {
1408
+ try {
1409
+ localStorage.setItem("strata-cache-".concat(projectId), newDataString);
1410
+ localStorage.setItem("strata-cache-ts-".concat(projectId), Date.now().toString());
1411
+ } catch (e) {}
1412
+ }
1322
1413
  (_onSyncSuccessRef$cur = onSyncSuccessRef.current) === null || _onSyncSuccessRef$cur === void 0 || _onSyncSuccessRef$cur.call(onSyncSuccessRef, remoteData);
1323
1414
  } else {
1324
1415
  setSyncStatus("idle");
1325
1416
  }
1326
- _context.n = 16;
1417
+ _context.n = 17;
1327
1418
  break;
1328
- case 15:
1329
- _context.p = 15;
1419
+ case 16:
1420
+ _context.p = 16;
1330
1421
  _t = _context.v;
1331
1422
  console.error("❌ Sync failed:", _t);
1332
1423
  setSyncStatus("error");
@@ -1335,11 +1426,11 @@ var StrataProvider = function StrataProvider(_ref) {
1335
1426
  message: _t instanceof Error ? _t.message : String(_t),
1336
1427
  source: snapshotUrl ? "cdn" : "sync"
1337
1428
  });
1338
- case 16:
1429
+ case 17:
1339
1430
  return _context.a(2);
1340
1431
  }
1341
- }, _callee, null, [[2, 15]]);
1342
- })), [syncEnabled, syncUrl, syncToken, snapshotUrl, normalizeComponents]);
1432
+ }, _callee, null, [[2, 16]]);
1433
+ })), [syncEnabled, syncUrl, syncToken, snapshotUrl, normalizeComponents, persistCache, projectId]);
1343
1434
  // Force sync function for manual triggering
1344
1435
  var forceSync = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
1345
1436
  return _regenerator().w(function (_context2) {
@@ -1364,9 +1455,20 @@ var StrataProvider = function StrataProvider(_ref) {
1364
1455
  }, [syncEnabled, syncUrl, snapshotUrl, syncInterval, syncDesignSystem]);
1365
1456
  // Convert design tokens to Chakra UI theme with enhanced resolution
1366
1457
  var theme = extendTheme({
1367
- styles: {
1368
- global: function global() {
1369
- return {};
1458
+ semanticTokens: {
1459
+ colors: {
1460
+ "chakra-body-bg": {
1461
+ "default": "transparent",
1462
+ _dark: "transparent"
1463
+ },
1464
+ "chakra-body-text": {
1465
+ "default": "inherit",
1466
+ _dark: "inherit"
1467
+ },
1468
+ "chakra-border-color": {
1469
+ "default": "inherit",
1470
+ _dark: "inherit"
1471
+ }
1370
1472
  }
1371
1473
  },
1372
1474
  colors: Object.entries(designSystem.variables).reduce(function (acc, _ref6) {
@@ -1417,13 +1519,37 @@ var StrataProvider = function StrataProvider(_ref) {
1417
1519
  xl: ((_designSystem$variabl24 = designSystem.variables["--shadow-xl"]) === null || _designSystem$variabl24 === void 0 ? void 0 : _designSystem$variabl24.value) || "0 20px 25px -5px rgba(0, 0, 0, 0.1)"
1418
1520
  }
1419
1521
  });
1522
+ // CSS Variable Auto-Injection
1523
+ useEffect(function () {
1524
+ if (injectCssVars === false) return;
1525
+ if (typeof document === 'undefined') return;
1526
+ var vars = designSystem.variables;
1527
+ if (!vars || Object.keys(vars).length === 0) return;
1528
+ var root = document.documentElement;
1529
+ for (var _i = 0, _Object$entries = Object.entries(vars); _i < _Object$entries.length; _i++) {
1530
+ var _token$resolvedValue;
1531
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
1532
+ key = _Object$entries$_i[0],
1533
+ token = _Object$entries$_i[1];
1534
+ root.style.setProperty(key, (_token$resolvedValue = token.resolvedValue) !== null && _token$resolvedValue !== void 0 ? _token$resolvedValue : token.value);
1535
+ }
1536
+ }, [designSystem.variables, injectCssVars]);
1420
1537
  var updateDesignSystem = function updateDesignSystem(newData) {
1421
1538
  setDesignSystem(newData);
1422
1539
  setSyncVersion(function (prev) {
1423
1540
  return prev + 1;
1424
1541
  });
1425
- if (!syncEnabled) {
1426
- localStorage.setItem("designSystemData", JSON.stringify(newData));
1542
+ setDataSource("initial");
1543
+ setDataTimestamp(Date.now());
1544
+ if (persistCache && projectId) {
1545
+ try {
1546
+ localStorage.setItem("strata-cache-".concat(projectId), JSON.stringify(newData));
1547
+ localStorage.setItem("strata-cache-ts-".concat(projectId), Date.now().toString());
1548
+ } catch (e) {}
1549
+ } else if (!syncEnabled && typeof window !== "undefined") {
1550
+ try {
1551
+ localStorage.setItem("designSystemData", JSON.stringify(newData));
1552
+ } catch (e) {}
1427
1553
  }
1428
1554
  };
1429
1555
  var contextValue = {
@@ -1438,7 +1564,9 @@ var StrataProvider = function StrataProvider(_ref) {
1438
1564
  syncInterval: syncInterval,
1439
1565
  syncToken: syncToken,
1440
1566
  snapshotCdnBase: snapshotCdnBase,
1441
- projectId: projectId
1567
+ projectId: projectId,
1568
+ dataSource: dataSource,
1569
+ cacheAge: dataTimestamp ? Date.now() - dataTimestamp : null
1442
1570
  };
1443
1571
  return jsx(StrataContext.Provider, {
1444
1572
  value: contextValue,
@@ -1446,6 +1574,7 @@ var StrataProvider = function StrataProvider(_ref) {
1446
1574
  theme: theme,
1447
1575
  cssVarsRoot: ":root",
1448
1576
  resetCSS: false,
1577
+ disableGlobalStyle: true,
1449
1578
  children: children
1450
1579
  })
1451
1580
  });
package/dist/index.js CHANGED
@@ -1115,35 +1115,103 @@ var StrataProvider = function StrataProvider(_ref) {
1115
1115
  projectId = _ref.projectId,
1116
1116
  onSyncError = _ref.onSyncError,
1117
1117
  onSyncSuccess = _ref.onSyncSuccess,
1118
- onSyncStart = _ref.onSyncStart;
1119
- var _useState = React.useState(userDesignSystem || initialData || {
1120
- variables: {},
1121
- components: {},
1122
- custom: {
1123
- variables: {},
1124
- components: {}
1118
+ onSyncStart = _ref.onSyncStart,
1119
+ _ref$persistCache = _ref.persistCache,
1120
+ persistCache = _ref$persistCache === void 0 ? true : _ref$persistCache,
1121
+ _ref$injectCssVars = _ref.injectCssVars,
1122
+ injectCssVars = _ref$injectCssVars === void 0 ? true : _ref$injectCssVars;
1123
+ var _useState = React.useState(function () {
1124
+ if (userDesignSystem) return "initial";
1125
+ if (initialData) return "initial";
1126
+ if (persistCache && projectId) {
1127
+ if (typeof window !== "undefined") {
1128
+ try {
1129
+ var cached = localStorage.getItem("strata-cache-".concat(projectId));
1130
+ if (cached) return "cache";
1131
+ } catch (e) {}
1132
+ }
1125
1133
  }
1134
+ return "empty";
1126
1135
  }),
1127
1136
  _useState2 = _slicedToArray(_useState, 2),
1128
- designSystem = _useState2[0],
1129
- setDesignSystem = _useState2[1];
1130
- var _useState3 = React.useState("idle"),
1137
+ dataSource = _useState2[0],
1138
+ setDataSource = _useState2[1];
1139
+ var _useState3 = React.useState(function () {
1140
+ if (userDesignSystem || initialData) return Date.now();
1141
+ if (persistCache && projectId) {
1142
+ if (typeof window !== "undefined") {
1143
+ try {
1144
+ var ts = localStorage.getItem("strata-cache-ts-".concat(projectId));
1145
+ if (ts) {
1146
+ var parsed = Number.parseInt(ts, 10);
1147
+ if (Number.isFinite(parsed)) return parsed;
1148
+ }
1149
+ } catch (e) {}
1150
+ }
1151
+ }
1152
+ return null;
1153
+ }),
1131
1154
  _useState4 = _slicedToArray(_useState3, 2),
1132
- syncStatus = _useState4[0],
1133
- setSyncStatus = _useState4[1];
1134
- var _useState5 = React.useState(null),
1155
+ dataTimestamp = _useState4[0],
1156
+ setDataTimestamp = _useState4[1];
1157
+ var _useState5 = React.useState(function () {
1158
+ if (userDesignSystem) return userDesignSystem;
1159
+ if (initialData) return initialData;
1160
+ if (persistCache && projectId) {
1161
+ if (typeof window !== "undefined") {
1162
+ try {
1163
+ var cached = localStorage.getItem("strata-cache-".concat(projectId));
1164
+ if (cached) {
1165
+ var parsed = JSON.parse(cached);
1166
+ if (parsed && parsed.variables && parsed.components) {
1167
+ return parsed;
1168
+ }
1169
+ }
1170
+ } catch (e) {}
1171
+ }
1172
+ }
1173
+ return {
1174
+ variables: {},
1175
+ components: {},
1176
+ custom: {
1177
+ variables: {},
1178
+ components: {}
1179
+ }
1180
+ };
1181
+ }),
1135
1182
  _useState6 = _slicedToArray(_useState5, 2),
1136
- lastSynced = _useState6[0],
1137
- setLastSynced = _useState6[1];
1138
- var _useState7 = React.useState(0),
1183
+ designSystem = _useState6[0],
1184
+ setDesignSystem = _useState6[1];
1185
+ var _useState7 = React.useState("idle"),
1139
1186
  _useState8 = _slicedToArray(_useState7, 2),
1140
- syncVersion = _useState8[0],
1141
- setSyncVersion = _useState8[1];
1187
+ syncStatus = _useState8[0],
1188
+ setSyncStatus = _useState8[1];
1189
+ var _useState9 = React.useState(function () {
1190
+ if (typeof window !== "undefined" && persistCache && projectId) {
1191
+ try {
1192
+ var ts = localStorage.getItem("strata-cache-ts-".concat(projectId));
1193
+ if (ts) {
1194
+ var parsed = Number.parseInt(ts, 10);
1195
+ if (Number.isFinite(parsed)) return new Date(parsed);
1196
+ }
1197
+ } catch (e) {}
1198
+ }
1199
+ return null;
1200
+ }),
1201
+ _useState0 = _slicedToArray(_useState9, 2),
1202
+ lastSynced = _useState0[0],
1203
+ setLastSynced = _useState0[1];
1204
+ var _useState1 = React.useState(0),
1205
+ _useState10 = _slicedToArray(_useState1, 2),
1206
+ syncVersion = _useState10[0],
1207
+ setSyncVersion = _useState10[1];
1142
1208
  // Ref that tracks the JSON string of the last successfully synced payload so
1143
1209
  // that syncDesignSystem does not need to close over the designSystem state
1144
1210
  // value. This keeps the callback stable and prevents the polling interval
1145
1211
  // from being continuously reset after each successful sync.
1146
1212
  var lastSyncedStringRef = React.useRef(null);
1213
+ // Ref to track the ETag of the last fetched snapshot
1214
+ var lastETagRef = React.useRef(null);
1147
1215
  // Refs for lifecycle callbacks so that syncDesignSystem does not need to
1148
1216
  // close over them. Inline functions passed by the consumer (e.g. anonymous
1149
1217
  // arrow functions) would otherwise change identity on every render, forcing
@@ -1180,7 +1248,7 @@ var StrataProvider = function StrataProvider(_ref) {
1180
1248
  }, []);
1181
1249
  var syncDesignSystem = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
1182
1250
  var _onSyncStartRef$curre;
1183
- var headers, remoteData, res, _onSyncErrorRef$curre, data, _onSyncErrorRef$curre2, _yield$Promise$all, _yield$Promise$all2, variablesRes, componentsRes, customRes, _yield$Promise$all3, _yield$Promise$all4, variables, components, custom, newDataString, _onSyncSuccessRef$cur, _onSyncErrorRef$curre3, _t;
1251
+ var headers, remoteData, res, _onSyncErrorRef$curre, etag, data, _onSyncErrorRef$curre2, _yield$Promise$all, _yield$Promise$all2, variablesRes, componentsRes, customRes, _yield$Promise$all3, _yield$Promise$all4, variables, components, custom, newDataString, _onSyncSuccessRef$cur, _onSyncErrorRef$curre3, _t;
1184
1252
  return _regenerator().w(function (_context) {
1185
1253
  while (1) switch (_context.p = _context.n) {
1186
1254
  case 0:
@@ -1197,19 +1265,30 @@ var StrataProvider = function StrataProvider(_ref) {
1197
1265
  Authorization: "Bearer ".concat(syncToken)
1198
1266
  } : {};
1199
1267
  if (!snapshotUrl) {
1200
- _context.n = 8;
1268
+ _context.n = 9;
1201
1269
  break;
1202
1270
  }
1271
+ if (lastETagRef.current) {
1272
+ headers["If-None-Match"] = lastETagRef.current;
1273
+ }
1274
+ // Single CDN snapshot fetch — edge-cached, 1 request per poll
1203
1275
  _context.n = 3;
1204
1276
  return fetch(snapshotUrl, {
1205
1277
  headers: headers
1206
1278
  });
1207
1279
  case 3:
1208
1280
  res = _context.v;
1209
- if (!(!res.ok && res.status >= 400 && res.status < 500)) {
1281
+ if (!(res.status === 304)) {
1210
1282
  _context.n = 4;
1211
1283
  break;
1212
1284
  }
1285
+ setSyncStatus("idle");
1286
+ return _context.a(2);
1287
+ case 4:
1288
+ if (!(!res.ok && res.status >= 400 && res.status < 500)) {
1289
+ _context.n = 5;
1290
+ break;
1291
+ }
1213
1292
  setSyncStatus("error");
1214
1293
  (_onSyncErrorRef$curre = onSyncErrorRef.current) === null || _onSyncErrorRef$curre === void 0 || _onSyncErrorRef$curre.call(onSyncErrorRef, {
1215
1294
  code: res.status,
@@ -1217,19 +1296,23 @@ var StrataProvider = function StrataProvider(_ref) {
1217
1296
  source: "cdn"
1218
1297
  });
1219
1298
  return _context.a(2);
1220
- case 4:
1299
+ case 5:
1221
1300
  if (res.ok) {
1222
- _context.n = 5;
1301
+ _context.n = 6;
1223
1302
  break;
1224
1303
  }
1225
1304
  throw new Error("Snapshot fetch failed: ".concat(res.status));
1226
- case 5:
1227
- _context.n = 6;
1228
- return res.json();
1229
1305
  case 6:
1306
+ etag = res.headers.get("ETag");
1307
+ if (etag) {
1308
+ lastETagRef.current = etag;
1309
+ }
1310
+ _context.n = 7;
1311
+ return res.json();
1312
+ case 7:
1230
1313
  data = _context.v;
1231
1314
  if (!(!data || _typeof(data) !== "object" || Array.isArray(data) || _typeof(data.variables) !== "object" || data.variables === null || Array.isArray(data.variables) || _typeof(data.components) !== "object" || data.components === null || Array.isArray(data.components))) {
1232
- _context.n = 7;
1315
+ _context.n = 8;
1233
1316
  break;
1234
1317
  }
1235
1318
  console.warn("[strata] Invalid snapshot shape received from CDN — skipping update.");
@@ -1240,7 +1323,7 @@ var StrataProvider = function StrataProvider(_ref) {
1240
1323
  source: "cdn"
1241
1324
  });
1242
1325
  return _context.a(2);
1243
- case 7:
1326
+ case 8:
1244
1327
  remoteData = {
1245
1328
  variables: data.variables,
1246
1329
  components: data.components,
@@ -1253,10 +1336,10 @@ var StrataProvider = function StrataProvider(_ref) {
1253
1336
  // ComponentNode shape so that useDynamicComponents and the registry
1254
1337
  // always receive consistently-shaped data.
1255
1338
  remoteData = normalizeComponents(remoteData);
1256
- _context.n = 14;
1339
+ _context.n = 15;
1257
1340
  break;
1258
- case 8:
1259
- _context.n = 9;
1341
+ case 9:
1342
+ _context.n = 10;
1260
1343
  return Promise.all([fetch("".concat(syncUrl, "/variables"), {
1261
1344
  headers: headers
1262
1345
  }), fetch("".concat(syncUrl, "/components"), {
@@ -1264,33 +1347,33 @@ var StrataProvider = function StrataProvider(_ref) {
1264
1347
  }), fetch("".concat(syncUrl, "/custom"), {
1265
1348
  headers: headers
1266
1349
  })]);
1267
- case 9:
1350
+ case 10:
1268
1351
  _yield$Promise$all = _context.v;
1269
1352
  _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 3);
1270
1353
  variablesRes = _yield$Promise$all2[0];
1271
1354
  componentsRes = _yield$Promise$all2[1];
1272
1355
  customRes = _yield$Promise$all2[2];
1273
1356
  if (variablesRes.ok) {
1274
- _context.n = 10;
1357
+ _context.n = 11;
1275
1358
  break;
1276
1359
  }
1277
1360
  throw new Error("Variables fetch failed: ".concat(variablesRes.status));
1278
- case 10:
1361
+ case 11:
1279
1362
  if (componentsRes.ok) {
1280
- _context.n = 11;
1363
+ _context.n = 12;
1281
1364
  break;
1282
1365
  }
1283
1366
  throw new Error("Components fetch failed: ".concat(componentsRes.status));
1284
- case 11:
1367
+ case 12:
1285
1368
  if (customRes.ok) {
1286
- _context.n = 12;
1369
+ _context.n = 13;
1287
1370
  break;
1288
1371
  }
1289
1372
  throw new Error("Custom fetch failed: ".concat(customRes.status));
1290
- case 12:
1291
- _context.n = 13;
1292
- return Promise.all([variablesRes.json(), componentsRes.json(), customRes.json()]);
1293
1373
  case 13:
1374
+ _context.n = 14;
1375
+ return Promise.all([variablesRes.json(), componentsRes.json(), customRes.json()]);
1376
+ case 14:
1294
1377
  _yield$Promise$all3 = _context.v;
1295
1378
  _yield$Promise$all4 = _slicedToArray(_yield$Promise$all3, 3);
1296
1379
  variables = _yield$Promise$all4[0];
@@ -1308,7 +1391,7 @@ var StrataProvider = function StrataProvider(_ref) {
1308
1391
  // ComponentNode shape so that useDynamicComponents and the registry
1309
1392
  // always receive consistently-shaped data.
1310
1393
  remoteData = normalizeComponents(remoteData);
1311
- case 14:
1394
+ case 15:
1312
1395
  // Only update if data actually changed (compared against the last synced
1313
1396
  // snapshot via ref, so this callback stays stable across renders).
1314
1397
  newDataString = JSON.stringify(remoteData);
@@ -1321,14 +1404,22 @@ var StrataProvider = function StrataProvider(_ref) {
1321
1404
  });
1322
1405
  setSyncStatus("success");
1323
1406
  setLastSynced(new Date());
1407
+ setDataSource("live");
1408
+ setDataTimestamp(Date.now());
1409
+ if (persistCache && projectId) {
1410
+ try {
1411
+ localStorage.setItem("strata-cache-".concat(projectId), newDataString);
1412
+ localStorage.setItem("strata-cache-ts-".concat(projectId), Date.now().toString());
1413
+ } catch (e) {}
1414
+ }
1324
1415
  (_onSyncSuccessRef$cur = onSyncSuccessRef.current) === null || _onSyncSuccessRef$cur === void 0 || _onSyncSuccessRef$cur.call(onSyncSuccessRef, remoteData);
1325
1416
  } else {
1326
1417
  setSyncStatus("idle");
1327
1418
  }
1328
- _context.n = 16;
1419
+ _context.n = 17;
1329
1420
  break;
1330
- case 15:
1331
- _context.p = 15;
1421
+ case 16:
1422
+ _context.p = 16;
1332
1423
  _t = _context.v;
1333
1424
  console.error("❌ Sync failed:", _t);
1334
1425
  setSyncStatus("error");
@@ -1337,11 +1428,11 @@ var StrataProvider = function StrataProvider(_ref) {
1337
1428
  message: _t instanceof Error ? _t.message : String(_t),
1338
1429
  source: snapshotUrl ? "cdn" : "sync"
1339
1430
  });
1340
- case 16:
1431
+ case 17:
1341
1432
  return _context.a(2);
1342
1433
  }
1343
- }, _callee, null, [[2, 15]]);
1344
- })), [syncEnabled, syncUrl, syncToken, snapshotUrl, normalizeComponents]);
1434
+ }, _callee, null, [[2, 16]]);
1435
+ })), [syncEnabled, syncUrl, syncToken, snapshotUrl, normalizeComponents, persistCache, projectId]);
1345
1436
  // Force sync function for manual triggering
1346
1437
  var forceSync = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
1347
1438
  return _regenerator().w(function (_context2) {
@@ -1366,9 +1457,20 @@ var StrataProvider = function StrataProvider(_ref) {
1366
1457
  }, [syncEnabled, syncUrl, snapshotUrl, syncInterval, syncDesignSystem]);
1367
1458
  // Convert design tokens to Chakra UI theme with enhanced resolution
1368
1459
  var theme = react.extendTheme({
1369
- styles: {
1370
- global: function global() {
1371
- return {};
1460
+ semanticTokens: {
1461
+ colors: {
1462
+ "chakra-body-bg": {
1463
+ "default": "transparent",
1464
+ _dark: "transparent"
1465
+ },
1466
+ "chakra-body-text": {
1467
+ "default": "inherit",
1468
+ _dark: "inherit"
1469
+ },
1470
+ "chakra-border-color": {
1471
+ "default": "inherit",
1472
+ _dark: "inherit"
1473
+ }
1372
1474
  }
1373
1475
  },
1374
1476
  colors: Object.entries(designSystem.variables).reduce(function (acc, _ref6) {
@@ -1419,13 +1521,37 @@ var StrataProvider = function StrataProvider(_ref) {
1419
1521
  xl: ((_designSystem$variabl24 = designSystem.variables["--shadow-xl"]) === null || _designSystem$variabl24 === void 0 ? void 0 : _designSystem$variabl24.value) || "0 20px 25px -5px rgba(0, 0, 0, 0.1)"
1420
1522
  }
1421
1523
  });
1524
+ // CSS Variable Auto-Injection
1525
+ React.useEffect(function () {
1526
+ if (injectCssVars === false) return;
1527
+ if (typeof document === 'undefined') return;
1528
+ var vars = designSystem.variables;
1529
+ if (!vars || Object.keys(vars).length === 0) return;
1530
+ var root = document.documentElement;
1531
+ for (var _i = 0, _Object$entries = Object.entries(vars); _i < _Object$entries.length; _i++) {
1532
+ var _token$resolvedValue;
1533
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
1534
+ key = _Object$entries$_i[0],
1535
+ token = _Object$entries$_i[1];
1536
+ root.style.setProperty(key, (_token$resolvedValue = token.resolvedValue) !== null && _token$resolvedValue !== void 0 ? _token$resolvedValue : token.value);
1537
+ }
1538
+ }, [designSystem.variables, injectCssVars]);
1422
1539
  var updateDesignSystem = function updateDesignSystem(newData) {
1423
1540
  setDesignSystem(newData);
1424
1541
  setSyncVersion(function (prev) {
1425
1542
  return prev + 1;
1426
1543
  });
1427
- if (!syncEnabled) {
1428
- localStorage.setItem("designSystemData", JSON.stringify(newData));
1544
+ setDataSource("initial");
1545
+ setDataTimestamp(Date.now());
1546
+ if (persistCache && projectId) {
1547
+ try {
1548
+ localStorage.setItem("strata-cache-".concat(projectId), JSON.stringify(newData));
1549
+ localStorage.setItem("strata-cache-ts-".concat(projectId), Date.now().toString());
1550
+ } catch (e) {}
1551
+ } else if (!syncEnabled && typeof window !== "undefined") {
1552
+ try {
1553
+ localStorage.setItem("designSystemData", JSON.stringify(newData));
1554
+ } catch (e) {}
1429
1555
  }
1430
1556
  };
1431
1557
  var contextValue = {
@@ -1440,7 +1566,9 @@ var StrataProvider = function StrataProvider(_ref) {
1440
1566
  syncInterval: syncInterval,
1441
1567
  syncToken: syncToken,
1442
1568
  snapshotCdnBase: snapshotCdnBase,
1443
- projectId: projectId
1569
+ projectId: projectId,
1570
+ dataSource: dataSource,
1571
+ cacheAge: dataTimestamp ? Date.now() - dataTimestamp : null
1444
1572
  };
1445
1573
  return jsxRuntime.jsx(StrataContext.Provider, {
1446
1574
  value: contextValue,
@@ -1448,6 +1576,7 @@ var StrataProvider = function StrataProvider(_ref) {
1448
1576
  theme: theme,
1449
1577
  cssVarsRoot: ":root",
1450
1578
  resetCSS: false,
1579
+ disableGlobalStyle: true,
1451
1580
  children: children
1452
1581
  })
1453
1582
  });
@@ -13,6 +13,8 @@ interface StrataContextType {
13
13
  syncToken: string | undefined;
14
14
  snapshotCdnBase: string | undefined;
15
15
  projectId: string | undefined;
16
+ dataSource: "live" | "cache" | "initial" | "empty";
17
+ cacheAge: number | null;
16
18
  }
17
19
  export declare const useStrata: () => StrataContextType;
18
20
  interface StrataProviderProps {
@@ -59,6 +61,16 @@ interface StrataProviderProps {
59
61
  * Use this to show a loading indicator or log sync lifecycle events.
60
62
  */
61
63
  onSyncStart?: () => void;
64
+ /**
65
+ * Whether to persist and restore cached snapshot to/from localStorage.
66
+ * Defaults to true.
67
+ */
68
+ persistCache?: boolean;
69
+ /**
70
+ * Whether to automatically inject design system variables into document.documentElement.
71
+ * Defaults to true.
72
+ */
73
+ injectCssVars?: boolean;
62
74
  }
63
75
  export declare const StrataProvider: React.FC<StrataProviderProps>;
64
76
  export {};
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@strata-ds/core",
3
- "version": "2.1.5",
3
+ "version": "2.1.16",
4
4
  "type": "module",
5
5
  "description": "The runtime component library for Strata — design once, sync everywhere.",
6
6
  "homepage": "https://strata.charisol.io",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.esm.js",
9
9
  "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "strata-ds": "./dist/cli/snapshot.js"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
15
  "import": "./dist/index.esm.js",