@strata-ds/core 2.1.18 → 2.1.19

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
@@ -98,7 +98,7 @@ Your React Application
98
98
 
99
99
  ## Quick Start (< 5 Minutes)
100
100
 
101
- > 🚀 **New to Strata?** Get your first component rendering in 4 steps.
101
+ Get your first component rendering in 4 steps.
102
102
 
103
103
  ### Step 1: Install
104
104
 
@@ -117,7 +117,7 @@ Go to [strata.charisol.io](https://strata.charisol.io) → **Your Project** →
117
117
 
118
118
  ### Step 3: Wrap Your App
119
119
 
120
- **✅ Recommended: CDN Snapshot Sync** (1 request per poll, edge-cached)
120
+ **Recommended: CDN Snapshot Sync** (1 request per poll, edge-cached)
121
121
 
122
122
  ```tsx
123
123
  "use client"; // Next.js App Router only
@@ -142,12 +142,12 @@ export default function RootLayout({
142
142
  }
143
143
  ```
144
144
 
145
- > 💡 Replace `YOUR_PROJECT_ID` and `pt_live_your_token_here` with values from **Step 2**.
145
+ > Replace `YOUR_PROJECT_ID` and `pt_live_your_token_here` with values from **Step 2**.
146
146
 
147
147
  ---
148
148
 
149
149
  <details>
150
- <summary><strong>⚠️ Legacy Sync</strong> (3 requests per poll — for migration only)</summary>
150
+ <summary><strong>Legacy Sync</strong> (3 requests per poll — for migration only)</summary>
151
151
 
152
152
  ```tsx
153
153
  "use client";
@@ -173,9 +173,9 @@ export default function RootLayout({
173
173
 
174
174
  **Why CDN is better:**
175
175
 
176
- - ✅ 1 request instead of 3 (faster, cheaper)
177
- - ✅ Edge-cached for global performance
178
- - ✅ Atomic updates (no partial states)
176
+ - 1 request instead of 3 (faster, cheaper)
177
+ - Edge-cached for global performance
178
+ - Atomic updates (no partial states)
179
179
 
180
180
  </details>
181
181
 
@@ -224,10 +224,10 @@ Use this checklist to verify your setup after following [Quick Start](#quick-sta
224
224
 
225
225
  **Verification:**
226
226
 
227
- - [ ] Opened DevTools → Console and saw `🔄 Starting design system sync...`
228
- - [ ] Console shows `📊 Components available: ...`
227
+ - [ ] Opened DevTools → Console and saw `Starting design system sync...`
228
+ - [ ] Console shows `Components available: ...`
229
229
  - [ ] Component renders on screen with correct styles
230
- - [ ] Added `<StrataDebug />` and verified connection status is **✅ Connected**
230
+ - [ ] Added `<StrataDebug />` and verified connection status is **Connected**
231
231
 
232
232
  **Stuck?** → Jump to [Debugging and Troubleshooting](#debugging-and-troubleshooting).
233
233
 
@@ -287,7 +287,7 @@ export default function RootLayout({
287
287
  }
288
288
  ```
289
289
 
290
- > 💡 Replace `YOUR_PROJECT_ID` with the ID from your Strata project dashboard. For private projects, add `syncToken="pt_live_your_token_here"` (get it from the **Publish & Sync** tab).
290
+ > Replace `YOUR_PROJECT_ID` with the ID from your Strata project dashboard. For private projects, add `syncToken="pt_live_your_token_here"` (get it from the **Publish & Sync** tab).
291
291
 
292
292
  ### Sync token authentication
293
293
 
@@ -359,10 +359,10 @@ function StatusBar() {
359
359
 
360
360
  Add `<StrataDebug />` anywhere inside `<StrataProvider>` to inspect:
361
361
 
362
- - ✅ Active sync mode (CDN vs Legacy)
363
- - ✅ Connection status
364
- - ✅ Loaded components
365
- - ✅ Sync token presence (never shows the actual token)
362
+ - Active sync mode (CDN vs Legacy)
363
+ - Connection status
364
+ - Loaded components
365
+ - Sync token presence (never shows the actual token)
366
366
 
367
367
  ```tsx
368
368
  "use client";
@@ -380,11 +380,11 @@ function App() {
380
380
 
381
381
  The panel automatically displays the relevant fields for the active sync mode:
382
382
 
383
- - **CDN mode** (`snapshotCdnBase` + `projectId` set): shows `✅ CDN Snapshot`, Project ID, resolved Snapshot URL, token presence, and sync interval.
384
- - **Legacy mode** (`syncUrl` set): shows `⚠️ Legacy (3 requests/poll)`, Sync URL, token presence, and sync interval.
385
- - **Disabled**: shows `❌ Disabled`.
383
+ - **CDN mode** (`snapshotCdnBase` + `projectId` set): shows `CDN Snapshot`, Project ID, resolved Snapshot URL, token presence, and sync interval.
384
+ - **Legacy mode** (`syncUrl` set): shows `Legacy (3 requests/poll)`, Sync URL, token presence, and sync interval.
385
+ - **Disabled**: shows `Disabled`.
386
386
 
387
- > 🔒 The `syncToken` value is **never** rendered — the panel only shows `✅ Present` or `❌ None`.
387
+ > The `syncToken` value is **never** rendered — the panel only shows `Present` or `None`.
388
388
 
389
389
  ---
390
390
 
@@ -424,11 +424,11 @@ Open **DevTools → Network tab** and filter by:
424
424
 
425
425
  Check for these messages:
426
426
 
427
- - ✅ `🔄 Starting design system sync...` → Sync is working
428
- - ✅ `📊 Components available: Button, Navbar, Card` → Components loaded
429
- - ✅ `🎨 Variables available: colors, spacing, typography` → Tokens loaded
430
- - ❌ `❌ Sync failed: 401` → Token issue (see table above)
431
- - ❌ `❌ Sync failed: 403` → CORS issue (see table above)
427
+ - `Starting design system sync...` → Sync is working
428
+ - `Components available: Button, Navbar, Card` → Components loaded
429
+ - `Variables available: colors, spacing, typography` → Tokens loaded
430
+ - `Sync failed: 401` → Token issue (see table above)
431
+ - `Sync failed: 403` → CORS issue (see table above)
432
432
 
433
433
  ---
434
434
 
@@ -543,26 +543,26 @@ const MyComponent = StrataComponentFactory.createComponent(
543
543
 
544
544
  Any project using the Strata Design System can enable full offline resilience in three quick steps:
545
545
 
546
- #### Step 1: Configure Auto-Generation in `package.json`
547
- Simply add a `"strata"` configuration block to your application's `package.json`. The SDK's built-in postinstall hook will automatically fetch the latest snapshot and generate the fallback assets every time you run `npm install`:
548
-
546
+ #### Step 1: Initialize Configuration with strata.json
547
+ Run the initialization CLI tool to prompt for configuration fields and generate a `strata.json` file in your application's root directory:
548
+ ```bash
549
+ npx strata init
550
+ ```
551
+ This will create a `strata.json` file at your project's root:
549
552
  ```json
550
553
  {
551
- "name": "your-app",
552
- "strata": {
553
- "projectId": "YOUR_PROJECT_ID",
554
- "snapshotCdnBase": "https://your-cdn-base-url.cloudfront.net",
555
- "output": "./src/data/strata-snapshot.json",
556
- "outputCss": "./src/styles/strata-fallbacks.css",
557
- "variablesOnly": true
558
- }
554
+ "projectId": "YOUR_PROJECT_ID",
555
+ "snapshotCdnBase": "https://your-cdn-base-url.cloudfront.net",
556
+ "output": "./src/data/strata-snapshot.json",
557
+ "outputCss": "./src/styles/strata-fallbacks.css",
558
+ "variablesOnly": true
559
559
  }
560
560
  ```
561
561
 
562
562
  *(Commit the generated JSON and CSS files to your Git repository as your baseline fallback).*
563
563
 
564
- > 💡 **Manual Generation**: You can also run the CLI snapshot tool manually if needed:
565
- > `npx strata-ds snapshot --project-id "YOUR_PROJECT_ID" --cdn-base "https://your-cdn-base-url.cloudfront.net" --output "./src/data/strata-snapshot.json" --output-css "./src/styles/strata-fallbacks.css" --variables-only`
564
+ > **Manual Generation**: You can run the CLI snapshot tool manually if you need to fetch updates:
565
+ > `npx strata run`
566
566
 
567
567
  #### Step 2: Import Fallback Styles
568
568
  Reference the CSS file in your main style entry point (e.g., `src/index.css` or `src/App.css`):
@@ -594,13 +594,13 @@ export default function App() {
594
594
 
595
595
  ## Key Features
596
596
 
597
- - 🔁 Live sync with Strata backend
598
- - 🧠 Token-driven styling
599
- - 🧩 Dynamic component registry
600
- - 🛠 Inline style overrides supported
601
- - 📦 Installable via npm
602
- - 📴 Offline-first fallback
603
- - 🧪 Debug tools included (`StrataDebug`)
597
+ - Live sync with Strata backend
598
+ - Token-driven styling
599
+ - Dynamic component registry
600
+ - Inline style overrides supported
601
+ - Installable via npm
602
+ - Offline-first fallback
603
+ - Debug tools included (`StrataDebug`)
604
604
 
605
605
  ## License
606
606
 
@@ -22,6 +22,44 @@ async function retrieveSnapshot(options) {
22
22
  if (!data || typeof data !== 'object' || typeof data.variables !== 'object') {
23
23
  throw new Error('Invalid snapshot response shape: missing variables');
24
24
  }
25
+ // Sanitize variables to prevent malformed values from breaking outputs
26
+ const variables = data.variables || {};
27
+ for (const [key, val] of Object.entries(variables)) {
28
+ if (val && typeof val === 'object') {
29
+ let value = val.value;
30
+ let resolvedValue = val.resolvedValue;
31
+ // Sanitize value
32
+ if (typeof value === 'string') {
33
+ if (value.endsWith('\\')) {
34
+ value += '\\';
35
+ }
36
+ if (value.startsWith('url(') && !value.endsWith(')')) {
37
+ if (value === 'url(\\' || value === 'url(\\\\' || value === 'url(\\;') {
38
+ value = 'none';
39
+ }
40
+ else {
41
+ value += ')';
42
+ }
43
+ }
44
+ val.value = value;
45
+ }
46
+ // Sanitize resolvedValue
47
+ if (typeof resolvedValue === 'string') {
48
+ if (resolvedValue.endsWith('\\')) {
49
+ resolvedValue += '\\';
50
+ }
51
+ if (resolvedValue.startsWith('url(') && !resolvedValue.endsWith(')')) {
52
+ if (resolvedValue === 'url(\\' || resolvedValue === 'url(\\\\' || resolvedValue === 'url(\\;') {
53
+ resolvedValue = 'none';
54
+ }
55
+ else {
56
+ resolvedValue += ')';
57
+ }
58
+ }
59
+ val.resolvedValue = resolvedValue;
60
+ }
61
+ }
62
+ }
25
63
  let snapshotJson = data;
26
64
  if (variablesOnly) {
27
65
  snapshotJson = {
@@ -86,17 +124,15 @@ async function retrieveSnapshot(options) {
86
124
  }
87
125
  }
88
126
 
89
- function findHostPackage() {
127
+ function findHostStrataJson() {
90
128
  let currentDir = process.cwd();
91
- // Traverse up to find the host application's package.json
129
+ // Traverse up to find the host application's strata.json
92
130
  while (true) {
93
- const packagePath = path.join(currentDir, 'package.json');
94
- if (fs.existsSync(packagePath)) {
131
+ const jsonPath = path.join(currentDir, 'strata.json');
132
+ if (fs.existsSync(jsonPath)) {
95
133
  try {
96
- const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
97
- if (pkg.name !== '@strata-ds/core' && pkg.strata) {
98
- return { packagePath, rootDir: currentDir, config: pkg.strata };
99
- }
134
+ const config = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
135
+ return { jsonPath, rootDir: currentDir, config };
100
136
  }
101
137
  catch (e) { }
102
138
  }
@@ -108,15 +144,15 @@ function findHostPackage() {
108
144
  return null;
109
145
  }
110
146
  async function run() {
111
- const hostInfo = findHostPackage();
147
+ const hostInfo = findHostStrataJson();
112
148
  if (!hostInfo) {
113
- console.log('[Strata] No "strata" configuration block found in host package.json. Skipping auto-snapshot retrieval.');
149
+ console.log('[Strata] No strata.json configuration file found. Run "npx strata init" to initialize design token fallback configuration.');
114
150
  return;
115
151
  }
116
152
  const { rootDir, config } = hostInfo;
117
153
  const { projectId, snapshotCdnBase, output, outputCss, syncToken, variablesOnly } = config;
118
154
  if (!projectId || !snapshotCdnBase) {
119
- console.warn('[Strata] Warning: "projectId" and "snapshotCdnBase" are required in package.json "strata" config.');
155
+ console.warn('[Strata] Warning: "projectId" and "snapshotCdnBase" are required in strata.json config.');
120
156
  return;
121
157
  }
122
158
  const outputPath = output ? path.resolve(rootDir, output) : undefined;
@@ -129,13 +165,13 @@ async function run() {
129
165
  outputPath,
130
166
  outputCssPath,
131
167
  syncToken,
132
- variablesOnly: variablesOnly !== false, // default to true for post-install variable trimming
168
+ variablesOnly: variablesOnly !== false,
133
169
  });
134
- console.log('✅ [Strata] Postinstall snapshot retrieval complete.');
170
+ console.log('[Strata] Postinstall snapshot retrieval complete.');
135
171
  }
136
172
  catch (error) {
137
173
  // Graceful degradation: log warning but do not throw error so install succeeds
138
- console.warn(`⚠️ [Strata] Postinstall snapshot failed: ${error.message || error}`);
174
+ console.warn(`[Strata] Postinstall snapshot failed: ${error.message || error}`);
139
175
  }
140
176
  }
141
177
  run();
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as fs from 'fs';
4
4
  import * as path from 'path';
5
+ import * as readline from 'readline';
5
6
 
6
7
  async function retrieveSnapshot(options) {
7
8
  const { projectId, cdnBase, outputPath, outputCssPath, syncToken, variablesOnly } = options;
@@ -24,6 +25,44 @@ async function retrieveSnapshot(options) {
24
25
  if (!data || typeof data !== 'object' || typeof data.variables !== 'object') {
25
26
  throw new Error('Invalid snapshot response shape: missing variables');
26
27
  }
28
+ // Sanitize variables to prevent malformed values from breaking outputs
29
+ const variables = data.variables || {};
30
+ for (const [key, val] of Object.entries(variables)) {
31
+ if (val && typeof val === 'object') {
32
+ let value = val.value;
33
+ let resolvedValue = val.resolvedValue;
34
+ // Sanitize value
35
+ if (typeof value === 'string') {
36
+ if (value.endsWith('\\')) {
37
+ value += '\\';
38
+ }
39
+ if (value.startsWith('url(') && !value.endsWith(')')) {
40
+ if (value === 'url(\\' || value === 'url(\\\\' || value === 'url(\\;') {
41
+ value = 'none';
42
+ }
43
+ else {
44
+ value += ')';
45
+ }
46
+ }
47
+ val.value = value;
48
+ }
49
+ // Sanitize resolvedValue
50
+ if (typeof resolvedValue === 'string') {
51
+ if (resolvedValue.endsWith('\\')) {
52
+ resolvedValue += '\\';
53
+ }
54
+ if (resolvedValue.startsWith('url(') && !resolvedValue.endsWith(')')) {
55
+ if (resolvedValue === 'url(\\' || resolvedValue === 'url(\\\\' || resolvedValue === 'url(\\;') {
56
+ resolvedValue = 'none';
57
+ }
58
+ else {
59
+ resolvedValue += ')';
60
+ }
61
+ }
62
+ val.resolvedValue = resolvedValue;
63
+ }
64
+ }
65
+ }
27
66
  let snapshotJson = data;
28
67
  if (variablesOnly) {
29
68
  snapshotJson = {
@@ -93,24 +132,61 @@ function printHelp() {
93
132
  Strata Design System Snapshot CLI
94
133
 
95
134
  Usage:
96
- npx strata-ds snapshot [options]
135
+ npx strata [command] [options]
136
+
137
+ Commands:
138
+ init Interactively initialize strata.json configuration file
139
+ run Fetch snapshot and generate fallbacks using strata.json
140
+ snapshot Legacy command to fetch snapshot using options
97
141
 
98
142
  Options:
99
- --project-id Strata Project ID (required)
100
- --cdn-base CDN base URL (e.g. https://dx2nhw7wqn4nn.cloudfront.net) (required)
101
- --output Path to write the snapshot JSON file (optional)
102
- --output-css Path to write the CSS fallback file (optional)
103
- --sync-token Authorization Sync Token (optional)
104
- --variables-only Only output variables in the snapshot JSON (optional)
143
+ --project-id Strata Project ID (overrides strata.json)
144
+ --cdn-base CDN base URL (overrides strata.json)
145
+ --output Path to write the snapshot JSON file (overrides strata.json)
146
+ --output-css Path to write the CSS fallback file (overrides strata.json)
147
+ --sync-token Authorization Sync Token (overrides strata.json)
148
+ --variables-only Only output variables in the snapshot JSON (overrides strata.json)
105
149
  --help, -h Show help
106
150
  `);
107
151
  }
108
- async function run() {
109
- const args = process.argv.slice(2);
110
- if (args.includes('--help') || args.includes('-h') || args.length === 0) {
111
- printHelp();
112
- process.exit(0);
152
+ function askQuestion(query) {
153
+ const rl = readline.createInterface({
154
+ input: process.stdin,
155
+ output: process.stdout,
156
+ });
157
+ return new Promise((resolve) => rl.question(query, (ans) => {
158
+ rl.close();
159
+ resolve(ans.trim());
160
+ }));
161
+ }
162
+ async function runInit() {
163
+ console.log('Strata Design System Initialization\n');
164
+ let projectId = '';
165
+ while (!projectId) {
166
+ projectId = await askQuestion('Enter your Strata Project ID (required): ');
167
+ if (!projectId) {
168
+ console.log('Error: Project ID is required.');
169
+ }
113
170
  }
171
+ const cdnBase = (await askQuestion('Enter CDN Base URL (default: https://dx2nhw7wqn4nn.cloudfront.net): ')) || 'https://dx2nhw7wqn4nn.cloudfront.net';
172
+ const output = (await askQuestion('Enter path to write snapshot JSON file (default: ./src/data/strata-snapshot.json): ')) || './src/data/strata-snapshot.json';
173
+ const outputCss = (await askQuestion('Enter path to write CSS fallback file (default: ./src/styles/strata-fallbacks.css): ')) || './src/styles/strata-fallbacks.css';
174
+ const varsOnlyInput = await askQuestion('Only output variables in snapshot JSON? (Y/n): ');
175
+ const variablesOnly = varsOnlyInput.toLowerCase() !== 'n';
176
+ const config = {
177
+ projectId,
178
+ snapshotCdnBase: cdnBase,
179
+ output,
180
+ outputCss,
181
+ variablesOnly,
182
+ };
183
+ const strataJsonPath = path.join(process.cwd(), 'strata.json');
184
+ fs.writeFileSync(strataJsonPath, JSON.stringify(config, null, 2), 'utf8');
185
+ console.log(`\nConfig file written successfully to: ${strataJsonPath}`);
186
+ console.log('To fetch your design tokens, run: npx strata run');
187
+ }
188
+ async function runRetrieve(command) {
189
+ const args = process.argv.slice(2);
114
190
  const getArgValue = (flag) => {
115
191
  const idx = args.indexOf(flag);
116
192
  if (idx !== -1 && idx + 1 < args.length) {
@@ -121,14 +197,37 @@ async function run() {
121
197
  const hasFlag = (flag) => {
122
198
  return args.includes(flag);
123
199
  };
124
- const projectId = getArgValue('--project-id');
125
- const cdnBase = getArgValue('--cdn-base');
126
- const outputPath = getArgValue('--output');
127
- const outputCssPath = getArgValue('--output-css');
128
- const syncToken = getArgValue('--sync-token');
129
- const variablesOnly = hasFlag('--variables-only');
200
+ // Load config from strata.json if it exists
201
+ const strataJsonPath = path.join(process.cwd(), 'strata.json');
202
+ let config = {};
203
+ if (fs.existsSync(strataJsonPath)) {
204
+ try {
205
+ config = JSON.parse(fs.readFileSync(strataJsonPath, 'utf8'));
206
+ }
207
+ catch (e) {
208
+ console.error(`Error reading strata.json: ${e.message}`);
209
+ process.exit(1);
210
+ }
211
+ }
212
+ else if (command === 'run') {
213
+ console.error('Error: strata.json not found. Run "npx strata init" to initialize configuration.');
214
+ process.exit(1);
215
+ }
216
+ const projectId = getArgValue('--project-id') || config.projectId;
217
+ const cdnBase = getArgValue('--cdn-base') || config.snapshotCdnBase;
218
+ const outputPath = getArgValue('--output') || config.output;
219
+ const outputCssPath = getArgValue('--output-css') || config.outputCss;
220
+ const syncToken = getArgValue('--sync-token') || config.syncToken;
221
+ // variables-only is true by default if not set to false
222
+ let variablesOnly = true;
223
+ if (hasFlag('--variables-only')) {
224
+ variablesOnly = true;
225
+ }
226
+ else if (config.variablesOnly !== undefined) {
227
+ variablesOnly = config.variablesOnly;
228
+ }
130
229
  if (!projectId || !cdnBase) {
131
- console.error('❌ Error: --project-id and --cdn-base are required.');
230
+ console.error('Error: --project-id and --cdn-base are required (or must be configured in strata.json).');
132
231
  printHelp();
133
232
  process.exit(1);
134
233
  }
@@ -136,15 +235,33 @@ async function run() {
136
235
  await retrieveSnapshot({
137
236
  projectId,
138
237
  cdnBase,
139
- outputPath,
140
- outputCssPath,
238
+ outputPath: outputPath ? path.resolve(outputPath) : undefined,
239
+ outputCssPath: outputCssPath ? path.resolve(outputCssPath) : undefined,
141
240
  syncToken,
142
241
  variablesOnly,
143
242
  });
144
243
  }
145
244
  catch (error) {
146
- console.error(`❌ Error: ${error.message || error}`);
245
+ console.error(`Error: ${error.message || error}`);
147
246
  process.exit(1);
148
247
  }
149
248
  }
150
- run();
249
+ async function main() {
250
+ const args = process.argv.slice(2);
251
+ const command = args[0];
252
+ if (args.includes('--help') || args.includes('-h') || !command) {
253
+ printHelp();
254
+ process.exit(0);
255
+ }
256
+ if (command === 'init') {
257
+ await runInit();
258
+ }
259
+ else if (command === 'run' || command === 'snapshot') {
260
+ await runRetrieve(command);
261
+ }
262
+ else {
263
+ // If it's not a recognized command, default to legacy options-based fetch
264
+ await runRetrieve('legacy');
265
+ }
266
+ }
267
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strata-ds/core",
3
- "version": "2.1.18",
3
+ "version": "2.1.19",
4
4
  "type": "module",
5
5
  "description": "The runtime component library for Strata — design once, sync everywhere.",
6
6
  "homepage": "https://strata.charisol.io",
@@ -8,7 +8,8 @@
8
8
  "module": "dist/index.esm.js",
9
9
  "types": "dist/index.d.ts",
10
10
  "bin": {
11
- "strata-ds": "./dist/cli/snapshot.js"
11
+ "strata-ds": "./dist/cli/snapshot.js",
12
+ "strata": "./dist/cli/snapshot.js"
12
13
  },
13
14
  "exports": {
14
15
  ".": {