@idealyst/mcp-server 1.2.117 → 1.2.119

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.
@@ -67,12 +67,16 @@ __export(tools_exports, {
67
67
  getInstallGuideDefinition: () => getInstallGuideDefinition,
68
68
  getIntro: () => getIntro,
69
69
  getIntroDefinition: () => getIntroDefinition,
70
+ getLiveActivityGuide: () => getLiveActivityGuide,
71
+ getLiveActivityGuideDefinition: () => getLiveActivityGuideDefinition,
70
72
  getLottieGuide: () => getLottieGuide,
71
73
  getLottieGuideDefinition: () => getLottieGuideDefinition,
72
74
  getMarkdownGuide: () => getMarkdownGuide,
73
75
  getMarkdownGuideDefinition: () => getMarkdownGuideDefinition,
74
76
  getNavigationTypes: () => getNavigationTypes2,
75
77
  getNavigationTypesDefinition: () => getNavigationTypesDefinition,
78
+ getNetworkGuide: () => getNetworkGuide,
79
+ getNetworkGuideDefinition: () => getNetworkGuideDefinition,
76
80
  getNotificationsGuide: () => getNotificationsGuide,
77
81
  getNotificationsGuideDefinition: () => getNotificationsGuideDefinition,
78
82
  getOauthClientGuide: () => getOauthClientGuide,
@@ -667,6 +671,21 @@ var getLiveActivityGuideDefinition = {
667
671
  required: ["topic"]
668
672
  }
669
673
  };
674
+ var getNetworkGuideDefinition = {
675
+ name: "get_network_guide",
676
+ description: "Get documentation for @idealyst/network cross-platform network connectivity and utilities package. Covers useNetwork hook, fetchWithTimeout, retry, waitForNetwork, and examples.",
677
+ inputSchema: {
678
+ type: "object",
679
+ properties: {
680
+ topic: {
681
+ type: "string",
682
+ description: "Topic to get docs for: 'overview', 'api', 'examples'",
683
+ enum: ["overview", "api", "examples"]
684
+ }
685
+ },
686
+ required: ["topic"]
687
+ }
688
+ };
670
689
  var toolDefinitions = [
671
690
  // Component tools
672
691
  listComponentsDefinition,
@@ -702,6 +721,7 @@ var toolDefinitions = [
702
721
  getPaymentsGuideDefinition,
703
722
  getNotificationsGuideDefinition,
704
723
  getLiveActivityGuideDefinition,
724
+ getNetworkGuideDefinition,
705
725
  // Package tools
706
726
  listPackagesDefinition,
707
727
  getPackageDocsDefinition,
@@ -954,9 +974,10 @@ var componentMetadata = {
954
974
  },
955
975
  Image: {
956
976
  category: "display",
957
- description: "Cross-platform image component with loading and error states",
977
+ description: "Cross-platform image component for displaying photos, pictures, and remote/local images with loading and error states",
958
978
  features: [
959
- "Multiple resize modes",
979
+ "Display photos, pictures, and media from URLs or local sources",
980
+ "Multiple resize modes (cover, contain, stretch, center)",
960
981
  "Loading placeholder",
961
982
  "Error fallback",
962
983
  "Lazy loading",
@@ -1326,7 +1347,11 @@ var componentAliases = {
1326
1347
  fab: "IconButton",
1327
1348
  modal: "Dialog",
1328
1349
  tooltip: "Tooltip",
1329
- snackbar: "Toast"
1350
+ snackbar: "Toast",
1351
+ photo: "Image",
1352
+ picture: "Image",
1353
+ img: "Image",
1354
+ thumbnail: "Image"
1330
1355
  };
1331
1356
  function findComponentName(componentName) {
1332
1357
  if (componentMetadata[componentName]) {
@@ -3081,7 +3106,8 @@ yarn add @idealyst/audio
3081
3106
  2. **Audio Session** \u2014 On iOS/Android, configure the audio session category before recording/playback
3082
3107
  3. **Audio Profiles** \u2014 Pre-configured \`AudioConfig\` presets: \`speech\`, \`highQuality\`, \`studio\`, \`phone\`
3083
3108
  4. **Session Presets** \u2014 Pre-configured \`AudioSessionConfig\` presets: \`playback\`, \`record\`, \`voiceChat\`, \`ambient\`, \`default\`, \`backgroundRecord\`
3084
- 5. **Background Recording** \u2014 \`useBackgroundRecorder\` hook for recording that continues when the app is backgrounded (iOS/Android). Requires app-level native entitlements.
3109
+ 5. **Audio Level** \u2014 \`recorder.level\` returns \`AudioLevel { current: number, peak: number, rms: number, db: number }\`. All values are 0.0-1.0 except \`db\` (-Infinity to 0).
3110
+ 6. **Background Recording** \u2014 \`useBackgroundRecorder\` hook for recording that continues when the app is backgrounded (iOS/Android). Requires app-level native entitlements.
3085
3111
 
3086
3112
  ## Exports
3087
3113
 
@@ -3179,6 +3205,22 @@ interface UsePlayerOptions {
3179
3205
  | toggleMute | () => void | Toggle mute |
3180
3206
 
3181
3207
  > **Critical:** \`feedPCMData()\` accepts \`ArrayBufferLike | Int16Array\` \u2014 **NOT strings or base64**.
3208
+ > If you receive base64-encoded audio from an external API and need to play it back, you MUST decode it to binary first.
3209
+ > **Cross-platform base64 decode** (do NOT use \`atob()\` \u2014 it's browser-only):
3210
+ > \`\`\`typescript
3211
+ > // Cross-platform: works on web AND React Native
3212
+ > function base64ToArrayBuffer(base64: string): ArrayBuffer {
3213
+ > const binaryString = typeof atob !== 'undefined'
3214
+ > ? atob(base64)
3215
+ > : Buffer.from(base64, 'base64').toString('binary');
3216
+ > const bytes = new Uint8Array(binaryString.length);
3217
+ > for (let i = 0; i < binaryString.length; i++) {
3218
+ > bytes[i] = binaryString.charCodeAt(i);
3219
+ > }
3220
+ > return bytes.buffer;
3221
+ > }
3222
+ > // Then: player.feedPCMData(base64ToArrayBuffer(encodedAudio));
3223
+ > \`\`\`
3182
3224
 
3183
3225
  ---
3184
3226
 
@@ -3628,7 +3670,7 @@ function BackgroundTranscriber() {
3628
3670
 
3629
3671
  \`\`\`tsx
3630
3672
  import React from 'react';
3631
- import { View, Text } from '@idealyst/components';
3673
+ import { View, Text, Progress } from '@idealyst/components';
3632
3674
  import { useRecorder, AUDIO_PROFILES } from '@idealyst/audio';
3633
3675
 
3634
3676
  function AudioLevelMeter() {
@@ -3642,22 +3684,10 @@ function AudioLevelMeter() {
3642
3684
  <Text>Level: {Math.round(recorder.level.current * 100)}%</Text>
3643
3685
  <Text>Peak: {Math.round(recorder.level.peak * 100)}%</Text>
3644
3686
  <Text>dB: {recorder.level.db.toFixed(1)}</Text>
3645
- <View
3646
- style={{
3647
- height: 20,
3648
- backgroundColor: '#e0e0e0',
3649
- borderRadius: 10,
3650
- overflow: 'hidden',
3651
- }}
3652
- >
3653
- <View
3654
- style={{
3655
- width: \`\${recorder.level.current * 100}%\`,
3656
- height: '100%',
3657
- backgroundColor: recorder.level.current > 0.8 ? 'red' : 'green',
3658
- }}
3659
- />
3660
- </View>
3687
+ <Progress
3688
+ value={recorder.level.current * 100}
3689
+ intent={recorder.level.current > 0.8 ? 'danger' : 'success'}
3690
+ />
3661
3691
  </View>
3662
3692
  );
3663
3693
  }
@@ -3731,6 +3761,8 @@ function CameraScreen() {
3731
3761
 
3732
3762
  Renders the camera preview. Must receive a camera instance from \`useCamera().cameraRef.current\`.
3733
3763
 
3764
+ > **IMPORTANT:** CameraPreview uses \`resizeMode\` ('cover' | 'contain'). But when displaying captured photos, use the **Image** component with \`objectFit\` \u2014 NOT \`resizeMode\`. Image does NOT have a \`resizeMode\` prop. Example: \`<Image source={photo.uri} objectFit="cover" />\`.
3765
+
3734
3766
  \`\`\`typescript
3735
3767
  interface CameraPreviewProps {
3736
3768
  camera: ICamera | null; // Camera instance from useCamera().cameraRef.current
@@ -4112,7 +4144,9 @@ import {
4112
4144
  \`\`\`
4113
4145
 
4114
4146
  > **Common mistakes:**
4147
+ > - **\`pick()\` returns \`FilePickerResult\`, NOT an array.** Access files via \`result.files\`: \`result.files.length\`, \`result.files[0].uri\`. Do NOT write \`result.length\` or \`result[0]\` \u2014 \`FilePickerResult\` is an object: \`{ cancelled: boolean, files: PickedFile[], rejected: RejectedFile[] }\`.
4115
4148
  > - The method is \`pick()\`, NOT \`pickFiles()\`
4149
+ > - \`pick()\` accepts overrides DIRECTLY: \`picker.pick({ allowedTypes: ['image'] })\` \u2014 NOT \`picker.pick({ config: { allowedTypes: ['image'] } })\`. The \`{ config: ... }\` wrapper is ONLY for \`useFilePicker()\` initialization.
4116
4150
  > - \`FileType\` values are: \`'image' | 'video' | 'audio' | 'document' | 'archive' | 'any'\` \u2014 NOT \`'pdf'\` or \`'doc'\`
4117
4151
  > - \`PickedFile\` has \`uri\`, \`name\`, \`size\`, \`type\`, \`extension\` \u2014 dimensions are in optional \`dimensions?: { width, height }\`, NOT top-level \`width\`/\`height\`
4118
4152
 
@@ -4167,7 +4201,7 @@ interface UseFilePickerOptions {
4167
4201
  | permission | PermissionResult \\| null | Permission result |
4168
4202
  | error | FilePickerError \\| null | Current error |
4169
4203
  | files | PickedFile[] | Last picked files |
4170
- | pick | (config?) => Promise<FilePickerResult> | **Open file picker** |
4204
+ | pick | (overrides?: Partial\\<FilePickerConfig\\>) => Promise<FilePickerResult> | **Open file picker. Overrides go DIRECTLY \u2014 NOT wrapped in \`{ config }\`.** Example: \`picker.pick({ allowedTypes: ['image'] })\` \u2014 NOT \`picker.pick({ config: { allowedTypes: ['image'] } })\` |
4171
4205
  | captureFromCamera | (options?) => Promise<FilePickerResult> | Open camera to capture |
4172
4206
  | clear | () => void | Clear picked files |
4173
4207
  | checkPermission | () => Promise<PermissionResult> | Check permission |
@@ -4304,6 +4338,27 @@ interface PickedFile {
4304
4338
 
4305
4339
  > **Note:** \`dimensions\` is an optional nested object \u2014 NOT top-level \`width\`/\`height\` properties.
4306
4340
 
4341
+ ### FilePickerResult (returned by pick())
4342
+
4343
+ \`\`\`typescript
4344
+ interface FilePickerResult {
4345
+ cancelled: boolean; // Whether user cancelled the picker
4346
+ files: PickedFile[]; // Picked files (empty if cancelled)
4347
+ rejected: RejectedFile[]; // Files rejected by validation
4348
+ error?: FilePickerError; // Error if picker failed
4349
+ }
4350
+ \`\`\`
4351
+
4352
+ > **CRITICAL:** \`pick()\` returns \`FilePickerResult\`, NOT an array. Always access \`result.files\` to get the array of picked files:
4353
+ > \`\`\`typescript
4354
+ > const result = await picker.pick();
4355
+ > if (!result.cancelled && result.files.length > 0) {
4356
+ > const file = result.files[0]; // \u2705 Correct
4357
+ > console.log(file.uri, file.name);
4358
+ > }
4359
+ > // \u274C WRONG: result.length, result[0] \u2014 FilePickerResult is NOT an array
4360
+ > \`\`\`
4361
+
4307
4362
  ### FilePickerConfig
4308
4363
 
4309
4364
  \`\`\`typescript
@@ -4952,9 +5007,9 @@ Animate any style property changes. Returns an animated style object.
4952
5007
 
4953
5008
  \`\`\`typescript
4954
5009
  interface AnimationOptions {
4955
- duration?: Duration; // ms or theme token key
4956
- easing?: EasingKey; // Theme easing key
4957
- delay?: number; // Delay before animation (ms)
5010
+ duration?: Duration; // ms or theme token key (e.g., 300, 500)
5011
+ easing?: EasingKey; // Theme easing key (e.g., 'easeOut', 'spring')
5012
+ delay?: number; // Delay in ms before animation starts (e.g., 100, 200). Useful for staggered entrance animations.
4958
5013
  }
4959
5014
 
4960
5015
  interface UseAnimatedStyleOptions extends AnimationOptions {
@@ -4981,6 +5036,20 @@ const entranceStyle = useAnimatedStyle(
4981
5036
  { opacity: ready ? 1 : 0, transform: { y: ready ? 0 : 20 } },
4982
5037
  { duration: 400, easing: 'easeOut' }
4983
5038
  );
5039
+
5040
+ // Staggered entrance: use delay for each item
5041
+ const style1 = useAnimatedStyle(
5042
+ { opacity: ready ? 1 : 0, transform: { y: ready ? 0 : 20 } },
5043
+ { duration: 300, easing: 'easeOut', delay: 0 }
5044
+ );
5045
+ const style2 = useAnimatedStyle(
5046
+ { opacity: ready ? 1 : 0, transform: { y: ready ? 0 : 20 } },
5047
+ { duration: 300, easing: 'easeOut', delay: 100 }
5048
+ );
5049
+ const style3 = useAnimatedStyle(
5050
+ { opacity: ready ? 1 : 0, transform: { y: ready ? 0 : 20 } },
5051
+ { duration: 300, easing: 'easeOut', delay: 200 }
5052
+ );
4984
5053
  \`\`\`
4985
5054
 
4986
5055
  ---
@@ -5132,16 +5201,18 @@ For expand/collapse, animate \`opacity\` + \`maxHeight\` together. Do NOT includ
5132
5201
 
5133
5202
  ## Transform Syntax
5134
5203
 
5135
- Use simplified object syntax instead of React Native arrays:
5204
+ **ALWAYS use object syntax** for transforms in useAnimatedStyle/usePresence:
5136
5205
 
5137
5206
  \`\`\`typescript
5138
- // Recommended: object syntax
5207
+ // CORRECT: object syntax (required for animations)
5139
5208
  transform: { x: 10, y: 20, scale: 1.2, rotate: 45 }
5140
5209
 
5141
- // Legacy: array syntax (still supported)
5142
- transform: [{ translateX: 10 }, { translateY: 20 }, { scale: 1.2 }]
5210
+ // WRONG in useAnimatedStyle: array syntax does NOT animate correctly
5211
+ // transform: [{ translateX: 10 }, { translateY: 20 }] // \u274C won't animate
5143
5212
  \`\`\`
5144
5213
 
5214
+ > **IMPORTANT:** Array-syntax transforms (React Native style) do NOT work with \`useAnimatedStyle\` or \`usePresence\`. Always use the simplified object syntax: \`transform: { x, y, scale, rotate }\`. Array syntax is only valid in static \`style\` props on non-animated elements.
5215
+
5145
5216
  | Property | Type | Maps to |
5146
5217
  |----------|------|---------|
5147
5218
  | x | number | translateX |
@@ -10079,6 +10150,396 @@ function MyScreen() {
10079
10150
  `
10080
10151
  };
10081
10152
 
10153
+ // src/data/network-guides.ts
10154
+ var networkGuides = {
10155
+ "idealyst://network/overview": `# @idealyst/network Overview
10156
+
10157
+ Cross-platform network connectivity and utilities for React and React Native. Know when the user has network, what kind, and react to changes in real time.
10158
+
10159
+ ## Features
10160
+
10161
+ - **useNetwork Hook** \u2014 Real-time network state with isConnected, connection type, effective speed
10162
+ - **Network State Listener** \u2014 Subscribe to connectivity changes outside React
10163
+ - **Connection Details** \u2014 WiFi, cellular (2G/3G/4G/5G), ethernet, bluetooth, VPN detection
10164
+ - **Effective Connection Type** \u2014 slow-2g, 2g, 3g, 4g speed categories
10165
+ - **Internet Reachability** \u2014 Distinguish "connected to network" from "can reach internet"
10166
+ - **fetchWithTimeout** \u2014 Fetch wrapper with configurable timeout and auto-abort
10167
+ - **retry** \u2014 Exponential backoff retry with optional network-aware gating
10168
+ - **waitForNetwork** \u2014 Promise that resolves when the device comes back online
10169
+ - **Data Saver Detection** \u2014 Detect if user has enabled data-saving mode (web)
10170
+ - **Cross-Platform** \u2014 navigator.onLine + Network Information API (web), @react-native-community/netinfo (native)
10171
+ - **TypeScript** \u2014 Full type safety and IntelliSense
10172
+
10173
+ ## Installation
10174
+
10175
+ \`\`\`bash
10176
+ yarn add @idealyst/network
10177
+
10178
+ # React Native also needs:
10179
+ yarn add @react-native-community/netinfo
10180
+ cd ios && pod install
10181
+ \`\`\`
10182
+
10183
+ ## Quick Start
10184
+
10185
+ \`\`\`tsx
10186
+ import { useNetwork } from '@idealyst/network';
10187
+
10188
+ function App() {
10189
+ const { isConnected, type, effectiveType } = useNetwork();
10190
+
10191
+ if (!isConnected) {
10192
+ return <Text>You are offline</Text>;
10193
+ }
10194
+
10195
+ return (
10196
+ <Text>
10197
+ Connected via {type} ({effectiveType})
10198
+ </Text>
10199
+ );
10200
+ }
10201
+ \`\`\`
10202
+
10203
+ ## Platform Details
10204
+
10205
+ - **Web**: Uses \`navigator.onLine\`, \`online\`/\`offline\` events, and the Network Information API (\`navigator.connection\`) for connection type, downlink speed, RTT, and data saver detection
10206
+ - **React Native**: Uses \`@react-native-community/netinfo\` for connection type, cellular generation, internet reachability, and real-time state changes
10207
+ - **SSR**: Safe for server-side rendering \u2014 returns sensible defaults when \`navigator\` is unavailable
10208
+ `,
10209
+ "idealyst://network/api": `# Network API Reference
10210
+
10211
+ Complete API reference for @idealyst/network.
10212
+
10213
+ ## useNetwork
10214
+
10215
+ React hook for monitoring network connectivity. Returns reactive state that updates automatically.
10216
+
10217
+ \`\`\`tsx
10218
+ const {
10219
+ state, // NetworkState \u2014 full state object
10220
+ isConnected, // boolean \u2014 device has active network
10221
+ isInternetReachable,// boolean | null \u2014 can reach internet (null = unknown)
10222
+ type, // NetworkConnectionType \u2014 'wifi' | 'cellular' | 'ethernet' | ...
10223
+ effectiveType, // EffectiveConnectionType \u2014 'slow-2g' | '2g' | '3g' | '4g' | 'unknown'
10224
+ refresh, // () => Promise<NetworkState> \u2014 manually refresh state
10225
+ } = useNetwork(options?: UseNetworkOptions);
10226
+ \`\`\`
10227
+
10228
+ ### UseNetworkOptions
10229
+
10230
+ | Option | Type | Default | Description |
10231
+ |--------|------|---------|-------------|
10232
+ | fetchOnMount | boolean | true | Fetch initial state on mount |
10233
+ | reachabilityUrl | string | (google 204) | URL for reachability pings (web only) |
10234
+ | reachabilityPollInterval | number | 0 | Polling interval in ms for reachability checks (web only). 0 = disabled |
10235
+
10236
+ ---
10237
+
10238
+ ## getNetworkState
10239
+
10240
+ Get a one-time snapshot of the current network state.
10241
+
10242
+ \`\`\`tsx
10243
+ // Web (synchronous)
10244
+ import { getNetworkState } from '@idealyst/network';
10245
+ const state: NetworkState = getNetworkState();
10246
+
10247
+ // Native (async \u2014 requires NetInfo fetch)
10248
+ import { getNetworkState } from '@idealyst/network';
10249
+ const state: NetworkState = await getNetworkState();
10250
+ \`\`\`
10251
+
10252
+ **Note:** On web, \`getNetworkState()\` is synchronous. On native, it returns a Promise.
10253
+
10254
+ ---
10255
+
10256
+ ## addNetworkStateListener
10257
+
10258
+ Subscribe to network state changes outside of React.
10259
+
10260
+ \`\`\`tsx
10261
+ import { addNetworkStateListener } from '@idealyst/network';
10262
+
10263
+ const unsubscribe = addNetworkStateListener((state) => {
10264
+ console.log('Network changed:', state.isConnected, state.type);
10265
+ });
10266
+
10267
+ // Later:
10268
+ unsubscribe();
10269
+ \`\`\`
10270
+
10271
+ ---
10272
+
10273
+ ## fetchWithTimeout
10274
+
10275
+ Fetch wrapper that automatically aborts if the request exceeds a timeout.
10276
+
10277
+ \`\`\`tsx
10278
+ import { fetchWithTimeout } from '@idealyst/network';
10279
+
10280
+ const response = await fetchWithTimeout('https://api.example.com/data', {
10281
+ timeout: 5000, // 5 seconds (default: 10000)
10282
+ method: 'GET',
10283
+ headers: { 'Authorization': 'Bearer token' },
10284
+ });
10285
+ \`\`\`
10286
+
10287
+ ### FetchWithTimeoutOptions
10288
+
10289
+ Extends standard \`RequestInit\` with:
10290
+
10291
+ | Option | Type | Default | Description |
10292
+ |--------|------|---------|-------------|
10293
+ | timeout | number | 10000 | Timeout in milliseconds |
10294
+
10295
+ ---
10296
+
10297
+ ## retry
10298
+
10299
+ Retry a function with exponential backoff. Optionally waits for network before retrying.
10300
+
10301
+ \`\`\`tsx
10302
+ import { retry } from '@idealyst/network';
10303
+
10304
+ const data = await retry(
10305
+ () => fetch('https://api.example.com/data').then(r => r.json()),
10306
+ {
10307
+ maxRetries: 3,
10308
+ baseDelay: 1000,
10309
+ maxDelay: 30000,
10310
+ retryOnlyWhenConnected: true,
10311
+ },
10312
+ );
10313
+ \`\`\`
10314
+
10315
+ ### RetryOptions
10316
+
10317
+ | Option | Type | Default | Description |
10318
+ |--------|------|---------|-------------|
10319
+ | maxRetries | number | 3 | Maximum retry attempts |
10320
+ | baseDelay | number | 1000 | Base delay in ms (doubles each attempt) |
10321
+ | maxDelay | number | 30000 | Maximum delay cap in ms |
10322
+ | retryOnlyWhenConnected | boolean | true | Wait for network before retrying |
10323
+
10324
+ ---
10325
+
10326
+ ## waitForNetwork
10327
+
10328
+ Returns a promise that resolves when the device comes back online.
10329
+
10330
+ \`\`\`tsx
10331
+ import { waitForNetwork } from '@idealyst/network';
10332
+
10333
+ // Wait up to 30 seconds for connectivity
10334
+ await waitForNetwork({ timeout: 30000 });
10335
+ console.log('Back online!');
10336
+ \`\`\`
10337
+
10338
+ If already online, resolves immediately. Rejects with an error if the timeout is exceeded.
10339
+
10340
+ ### WaitForNetworkOptions
10341
+
10342
+ | Option | Type | Default | Description |
10343
+ |--------|------|---------|-------------|
10344
+ | timeout | number | 30000 | Max wait time in ms before rejecting |
10345
+
10346
+ ---
10347
+
10348
+ ## NetworkState
10349
+
10350
+ Full network state object returned by the hook and listeners.
10351
+
10352
+ \`\`\`tsx
10353
+ interface NetworkState {
10354
+ isConnected: boolean; // Device has active network
10355
+ isInternetReachable: boolean | null; // Internet reachable (null = unknown)
10356
+ type: NetworkConnectionType; // 'wifi' | 'cellular' | 'ethernet' | ...
10357
+ effectiveType: EffectiveConnectionType; // 'slow-2g' | '2g' | '3g' | '4g' | 'unknown'
10358
+ cellularGeneration: CellularGeneration; // '2g' | '3g' | '4g' | '5g' | null (native only)
10359
+ downlink: number | null; // Mbps (web only, from Network Info API)
10360
+ rtt: number | null; // Round-trip time ms (web only)
10361
+ isDataSaving: boolean | null; // Data saver enabled (web only)
10362
+ }
10363
+ \`\`\`
10364
+
10365
+ ## Type Aliases
10366
+
10367
+ \`\`\`tsx
10368
+ type NetworkConnectionType = 'wifi' | 'cellular' | 'ethernet' | 'bluetooth' | 'vpn' | 'other' | 'none' | 'unknown';
10369
+ type EffectiveConnectionType = 'slow-2g' | '2g' | '3g' | '4g' | 'unknown';
10370
+ type CellularGeneration = '2g' | '3g' | '4g' | '5g' | null;
10371
+ \`\`\`
10372
+ `,
10373
+ "idealyst://network/examples": `# Network Examples
10374
+
10375
+ Complete code examples for common @idealyst/network patterns.
10376
+
10377
+ ## Offline Banner
10378
+
10379
+ \`\`\`tsx
10380
+ import { useNetwork } from '@idealyst/network';
10381
+ import { View, Text } from '@idealyst/components';
10382
+
10383
+ function OfflineBanner() {
10384
+ const { isConnected } = useNetwork();
10385
+
10386
+ if (isConnected) return null;
10387
+
10388
+ return (
10389
+ <View style={{ backgroundColor: '#f44336', padding: 8 }}>
10390
+ <Text style={{ color: '#fff', textAlign: 'center' }}>
10391
+ No internet connection
10392
+ </Text>
10393
+ </View>
10394
+ );
10395
+ }
10396
+ \`\`\`
10397
+
10398
+ ## Adaptive Quality Based on Connection
10399
+
10400
+ \`\`\`tsx
10401
+ import { useNetwork } from '@idealyst/network';
10402
+
10403
+ function MediaPlayer({ videoId }: { videoId: string }) {
10404
+ const { effectiveType, isDataSaving } = useNetwork().state;
10405
+
10406
+ const quality = (() => {
10407
+ if (isDataSaving) return 'low';
10408
+ switch (effectiveType) {
10409
+ case 'slow-2g':
10410
+ case '2g':
10411
+ return 'low';
10412
+ case '3g':
10413
+ return 'medium';
10414
+ case '4g':
10415
+ default:
10416
+ return 'high';
10417
+ }
10418
+ })();
10419
+
10420
+ return <VideoPlayer videoId={videoId} quality={quality} />;
10421
+ }
10422
+ \`\`\`
10423
+
10424
+ ## Retry API Calls
10425
+
10426
+ \`\`\`tsx
10427
+ import { retry, fetchWithTimeout } from '@idealyst/network';
10428
+
10429
+ async function fetchUserProfile(userId: string) {
10430
+ const response = await retry(
10431
+ () => fetchWithTimeout(\`https://api.example.com/users/\${userId}\`, {
10432
+ timeout: 5000,
10433
+ }),
10434
+ { maxRetries: 3, baseDelay: 1000 },
10435
+ );
10436
+
10437
+ if (!response.ok) {
10438
+ throw new Error(\`Failed to fetch user: \${response.status}\`);
10439
+ }
10440
+
10441
+ return response.json();
10442
+ }
10443
+ \`\`\`
10444
+
10445
+ ## Wait for Network Before Action
10446
+
10447
+ \`\`\`tsx
10448
+ import { waitForNetwork } from '@idealyst/network';
10449
+
10450
+ async function syncData() {
10451
+ // If offline, wait up to 60 seconds for connectivity
10452
+ await waitForNetwork({ timeout: 60000 });
10453
+
10454
+ // Now we're online \u2014 sync
10455
+ const response = await fetch('https://api.example.com/sync', {
10456
+ method: 'POST',
10457
+ body: JSON.stringify(pendingChanges),
10458
+ });
10459
+
10460
+ return response.json();
10461
+ }
10462
+ \`\`\`
10463
+
10464
+ ## Network State Listener (Outside React)
10465
+
10466
+ \`\`\`tsx
10467
+ import { addNetworkStateListener } from '@idealyst/network';
10468
+
10469
+ // Subscribe to changes (e.g., in a service or module)
10470
+ const unsubscribe = addNetworkStateListener((state) => {
10471
+ if (!state.isConnected) {
10472
+ queueManager.pause();
10473
+ } else {
10474
+ queueManager.resume();
10475
+ }
10476
+ });
10477
+
10478
+ // Cleanup when done
10479
+ unsubscribe();
10480
+ \`\`\`
10481
+
10482
+ ## Connection Type Display
10483
+
10484
+ \`\`\`tsx
10485
+ import { useNetwork } from '@idealyst/network';
10486
+ import { View, Text } from '@idealyst/components';
10487
+
10488
+ function NetworkInfo() {
10489
+ const { state } = useNetwork();
10490
+
10491
+ return (
10492
+ <View>
10493
+ <Text>Status: {state.isConnected ? 'Online' : 'Offline'}</Text>
10494
+ <Text>Type: {state.type}</Text>
10495
+ <Text>Speed: {state.effectiveType}</Text>
10496
+ {state.cellularGeneration && (
10497
+ <Text>Cellular: {state.cellularGeneration}</Text>
10498
+ )}
10499
+ {state.downlink != null && (
10500
+ <Text>Downlink: {state.downlink} Mbps</Text>
10501
+ )}
10502
+ {state.rtt != null && (
10503
+ <Text>RTT: {state.rtt} ms</Text>
10504
+ )}
10505
+ {state.isDataSaving != null && (
10506
+ <Text>Data Saver: {state.isDataSaving ? 'On' : 'Off'}</Text>
10507
+ )}
10508
+ </View>
10509
+ );
10510
+ }
10511
+ \`\`\`
10512
+
10513
+ ## Fetch with Timeout
10514
+
10515
+ \`\`\`tsx
10516
+ import { fetchWithTimeout } from '@idealyst/network';
10517
+
10518
+ async function quickHealthCheck() {
10519
+ try {
10520
+ const response = await fetchWithTimeout('https://api.example.com/health', {
10521
+ timeout: 3000,
10522
+ method: 'HEAD',
10523
+ });
10524
+ return response.ok;
10525
+ } catch {
10526
+ return false;
10527
+ }
10528
+ }
10529
+ \`\`\`
10530
+
10531
+ ## Best Practices
10532
+
10533
+ 1. **Use \`useNetwork\` for UI** \u2014 The hook handles subscriptions and cleanup automatically
10534
+ 2. **Use \`addNetworkStateListener\` for services** \u2014 For non-React code (queue managers, sync services)
10535
+ 3. **Combine retry + fetchWithTimeout** \u2014 For resilient API calls
10536
+ 4. **Check \`isInternetReachable\`** \u2014 Being "connected" to WiFi doesn't mean you have internet
10537
+ 5. **Respect data saver** \u2014 Reduce payload sizes and avoid autoplay when \`isDataSaving\` is true
10538
+ 6. **Don't poll too aggressively** \u2014 If using \`reachabilityPollInterval\`, keep it >= 15000ms
10539
+ 7. **Use \`waitForNetwork\` for offline-first** \u2014 Queue operations and wait for connectivity to sync
10540
+ `
10541
+ };
10542
+
10082
10543
  // src/data/packages.ts
10083
10544
  var packages = {
10084
10545
  components: {
@@ -11261,6 +11722,52 @@ await end(info.id, { dismissalPolicy: 'default' });`,
11261
11722
  "deliveryActivity() / timerActivity() / mediaActivity() / progressActivity() - Template presets"
11262
11723
  ],
11263
11724
  relatedPackages: ["notifications"]
11725
+ },
11726
+ network: {
11727
+ name: "Network",
11728
+ npmName: "@idealyst/network",
11729
+ description: "Cross-platform network connectivity and utilities for React and React Native. Real-time connection monitoring, fetch with timeout, retry with exponential backoff, and wait-for-network primitives.",
11730
+ category: "utility",
11731
+ platforms: ["web", "native"],
11732
+ documentationStatus: "full",
11733
+ installation: "yarn add @idealyst/network",
11734
+ peerDependencies: [
11735
+ "@react-native-community/netinfo (native)"
11736
+ ],
11737
+ features: [
11738
+ "useNetwork hook \u2014 real-time isConnected, connection type, effective speed",
11739
+ "Network state listener for non-React code",
11740
+ "Connection type detection \u2014 WiFi, cellular, ethernet, bluetooth, VPN",
11741
+ "Effective connection speed \u2014 slow-2g, 2g, 3g, 4g",
11742
+ "Cellular generation \u2014 2G, 3G, 4G, 5G (native)",
11743
+ "Internet reachability \u2014 distinguish connected from reachable",
11744
+ "fetchWithTimeout \u2014 fetch with configurable auto-abort",
11745
+ "retry \u2014 exponential backoff with network-aware gating",
11746
+ "waitForNetwork \u2014 promise that resolves when back online",
11747
+ "Data saver detection (web)",
11748
+ "Downlink speed and RTT estimation (web)"
11749
+ ],
11750
+ quickStart: `import { useNetwork } from '@idealyst/network';
11751
+
11752
+ function App() {
11753
+ const { isConnected, type, effectiveType } = useNetwork();
11754
+
11755
+ if (!isConnected) {
11756
+ return <Text>You are offline</Text>;
11757
+ }
11758
+
11759
+ return <Text>Connected via {type} ({effectiveType})</Text>;
11760
+ }`,
11761
+ apiHighlights: [
11762
+ "useNetwork(options?) - React hook for real-time network state",
11763
+ "getNetworkState() - One-time state snapshot (sync on web, async on native)",
11764
+ "addNetworkStateListener(cb) - Subscribe to changes (returns unsubscribe)",
11765
+ "fetchWithTimeout(url, options) - Fetch with auto-abort timeout",
11766
+ "retry(fn, options) - Exponential backoff retry",
11767
+ "waitForNetwork(options) - Promise that resolves when online",
11768
+ "NetworkState { isConnected, isInternetReachable, type, effectiveType, cellularGeneration, downlink, rtt, isDataSaving }"
11769
+ ],
11770
+ relatedPackages: ["storage", "config"]
11264
11771
  }
11265
11772
  };
11266
11773
  function getPackagesByCategory() {
@@ -15669,16 +16176,23 @@ import { View, Text, Button, TextInput, Card, Icon, ... } from '@idealyst/compon
15669
16176
 
15670
16177
  ## How to Use This MCP Server
15671
16178
 
15672
- This server has tools for every aspect of the framework. **Always look up the API before writing code.**
16179
+ This server has tools for every aspect of the framework. **Look up APIs as you need them \u2014 don't research everything upfront.**
15673
16180
 
15674
- ### Workflow (be efficient \u2014 minimize tool calls)
16181
+ ### Workflow
15675
16182
 
15676
- 1. **Start here** \u2014 this intro covers conventions and gotchas
15677
- 2. **Look up components** \u2014 call \`get_component_types\` for EVERY component you plan to use. Call it for each component you need. (Card has NO compound components \u2014 no Card.Content/Card.Header)
15678
- 3. **Look up packages** \u2014 call the dedicated \`get_*_guide\` tool with topic \`api\` for each \`@idealyst/*\` package
15679
- 4. **Check recipes** \u2014 call \`search_recipes\` to find ready-made patterns for common screens
15680
- 5. **Search icons ONCE** \u2014 combine all needed icon terms into ONE \`search_icons\` call (e.g., \`"home settings check timer calendar"\`)
15681
- 6. **Then write code** \u2014 only after reading the types and guides. Do NOT make additional icon searches \u2014 pick from what you found
16183
+ Write code iteratively \u2014 **look up one API, write one file, repeat**:
16184
+
16185
+ 1. Call \`get_intro\` (this response)
16186
+ 2. Look up the API for your FIRST file only (e.g., \`get_component_types("Button,Card,Text")\`)
16187
+ 3. **Write that file immediately** using the Write tool
16188
+ 4. Then look up the next API you need, write the next file, and so on
16189
+
16190
+ - **Before using a component** \u2014 call \`get_component_types\` for its props (supports batching: \`get_component_types("Button,Card,Text")\`)
16191
+ - **Before using a package** \u2014 call its dedicated \`get_*_guide\` tool with topic \`api\`
16192
+ - **Search icons once** \u2014 batch all terms into one call: \`search_icons("home settings check timer")\`
16193
+ - **Check recipes** \u2014 \`search_recipes\` for ready-made patterns you can adapt
16194
+
16195
+ > **WARNING: Do NOT load multiple package guides, component types, AND icon searches all before writing your first file.** Each tool response is large. If you accumulate 4+ tool responses without writing any code, you WILL exhaust your output token budget and produce zero files. The correct pattern is: **research \u2192 write \u2192 research \u2192 write**, NOT **research \u2192 research \u2192 research \u2192 write**.
15682
16196
 
15683
16197
  ### Component Tools
15684
16198
  - \`list_components\` / \`search_components\` \u2014 Discover available components
@@ -15688,7 +16202,7 @@ This server has tools for every aspect of the framework. **Always look up the AP
15688
16202
  - \`search_icons\` \u2014 Find Material Design icon names (7,447 available). **Batch your needs**: search once with multiple terms like \`"home settings user check"\` rather than making separate calls per icon
15689
16203
 
15690
16204
  ### Package Guide Tools
15691
- **For any \`@idealyst/*\` package, call its dedicated guide tool with topic \`api\` BEFORE writing code.** These return complete TypeScript interfaces, return types, and correct usage. The generic \`get_package_docs\` tool only has summaries.
16205
+ Each \`@idealyst/*\` package has a dedicated guide tool that returns complete TypeScript interfaces and correct usage. The generic \`get_package_docs\` tool only has summaries.
15692
16206
 
15693
16207
  | Package | Guide Tool |
15694
16208
  |---------|-----------|
@@ -15753,6 +16267,10 @@ const tabs: { icon: IconName }[] = [{ icon: 'home' }, { icon: 'search' }]; // NO
15753
16267
 
15754
16268
  > **CRITICAL:** Icon names do NOT have an \`mdi:\` prefix. Use bare names like \`'delete'\`, \`'home'\`, \`'check-circle'\` \u2014 NOT \`'mdi:delete'\`, \`'mdi:home'\`, etc.
15755
16269
  > **CRITICAL:** When defining arrays or objects with icon fields, type them as \`IconName\` \u2014 never \`string\`. Using \`string\` will cause TS2322 when passed to component props.
16270
+ > **CRITICAL:** Helper functions that return icon names MUST have return type \`IconName\`, not \`string\`. Example: \`function getIcon(type: string): IconName { return type === 'pdf' ? 'file-pdf-box' : 'file-document-outline'; }\` \u2014 NOT \`function getIcon(type: string): string\`.
16271
+ > **CRITICAL:** ONLY use icon names returned by \`search_icons\`. Do NOT guess or invent icon names \u2014 unverified names render as blank with runtime warnings. If you need an icon, search for it first.
16272
+
16273
+ **Common verified icon names** (use these without searching): \`home\`, \`cog\`, \`account\`, \`magnify\`, \`plus\`, \`close\`, \`check\`, \`chevron-left\`, \`chevron-right\`, \`chevron-down\`, \`chevron-up\`, \`arrow-left\`, \`arrow-right\`, \`menu\`, \`dots-vertical\`, \`pencil\`, \`delete\`, \`heart\`, \`star\`, \`bell\`, \`email\`, \`phone\`, \`camera\`, \`camera-flip\`, \`flash\`, \`flash-off\`, \`image\`, \`send\`, \`share\`, \`download\`, \`upload\`, \`eye\`, \`eye-off\`, \`lock\`, \`logout\`, \`refresh\`, \`calendar\`, \`clock\`, \`map-marker\`, \`chart-line\`, \`view-dashboard\`, \`account-group\`, \`message\`, \`information\`, \`alert\`, \`check-circle\`, \`close-circle\`, \`play\`, \`pause\`, \`stop\`, \`microphone\`, \`microphone-off\`, \`file-document-outline\`. For any icon NOT on this list, use \`search_icons\` to verify.
15756
16274
 
15757
16275
  ---
15758
16276
 
@@ -15762,26 +16280,27 @@ These are mistakes agents make repeatedly. Each one causes TypeScript compilatio
15762
16280
 
15763
16281
  ### Component Props
15764
16282
  1. **Text** does NOT have \`variant\`, \`intent\`, \`size\`, \`fontSize\`, \`numberOfLines\`, \`ellipsizeMode\`, \`selectable\`, \`textColor\`, or \`onPress\`. Use \`typography\` (\`h1\`\u2013\`h6\`, \`subtitle1\`, \`subtitle2\`, \`body1\`, \`body2\`, \`caption\`), \`weight\` (\`light\`, \`normal\`, \`medium\`, \`semibold\`, \`bold\`), and \`color\` (\`primary\`, \`secondary\`, \`tertiary\`, \`inverse\`). **\`textColor\` is an Icon-only prop** \u2014 Text uses \`color\`. For pressable text, wrap in \`Pressable\` or use \`Button type="text"\`.
15765
- 2. **TextInput** does NOT have \`label\`, \`error\`, \`editable\`, \`autoComplete\`, \`keyboardType\`, or \`onChange\`. Compose labels/errors with \`Text\` + \`View\`. Use \`onChangeText\`, \`inputMode\` (\`text\`, \`email\`, \`password\`, \`number\`), and \`textContentType\`. TextArea is different \u2014 it DOES support \`label\`, \`error\`, \`rows\`, \`onChange\`.
16283
+ 2. **TextInput** does NOT have \`label\`, \`error\`, \`editable\`, \`autoComplete\`, \`keyboardType\`, or \`onChange\`. Compose labels/errors with \`Text\` + \`View\`. Use \`onChangeText\`, \`inputMode\` (\`'text' | 'email' | 'password' | 'number'\` \u2014 NOT \`'decimal'\`, \`'numeric'\`, \`'tel'\`, \`'url'\`), and \`textContentType\`. **TextArea has a DIFFERENT API** \u2014 it DOES support \`label\`, \`error\`, \`rows\`, \`onChange\`, but does NOT have \`onBlur\` or \`onChangeText\`. Always look up TextArea types separately.
15766
16284
  3. **Button/IconButton** \`type\` is \`'contained' | 'outlined' | 'text'\` \u2014 NOT \`'ghost'\`, \`'solid'\`, \`'default'\`. Button has \`leftIcon\` and \`rightIcon\` \u2014 NOT \`icon\`.
15767
16285
  4. **View** does NOT have \`direction\`, \`align\`, or \`onPress\` props. For touch handling, wrap content in \`Pressable\` from \`@idealyst/components\` (NOT from \`react-native\`): \`<Pressable onPress={handlePress}><View>...</View></Pressable>\`. For horizontal layout use \`style={{ flexDirection: 'row' }}\`. View spacing shorthand props (all accept Size: \`xs\`|\`sm\`|\`md\`|\`lg\`|\`xl\`): \`padding\`, \`paddingVertical\`, \`paddingHorizontal\`, \`margin\`, \`marginVertical\`, \`marginHorizontal\`, \`gap\`/\`spacing\`. Do NOT use \`paddingTop\`, \`paddingBottom\`, \`paddingLeft\`, \`paddingRight\`, \`marginTop\`, \`marginBottom\`, \`marginLeft\`, \`marginRight\` as shorthand props \u2014 they do NOT exist and will cause TS2353. For single-side spacing, use \`style={{ paddingTop: 16 }}\`. Other View props: \`background\`, \`radius\`, \`border\`, \`scrollable\`. \`border\` is \`'none' | 'thin' | 'thick'\` \u2014 NOT \`'outline'\`, \`'solid'\`.
15768
- 5. **Badge** \`type\` is \`'filled' | 'outlined' | 'dot'\` \u2014 NOT \`'soft'\`, \`'subtle'\`, \`'solid'\`.
16286
+ 5. **Badge** \`type\` is \`'filled' | 'outlined' | 'dot'\` \u2014 NOT \`'soft'\`, \`'subtle'\`, \`'solid'\`. **Intent type narrowing (CRITICAL):** TS widens string literals in objects/arrays to \`string\`, which fails \`intent\` props. Rules: (a) Simple ternaries in JSX work fine: \`<Badge intent={cond ? 'success' : 'danger'}>\`. (b) **Do NOT use \`as const\` on ternary expressions** \u2014 \`(cond ? 'a' : 'b') as const\` causes TS1355. (c) **Arrays/objects with intent values MUST use \`as const\`**: \`const items = [{ intent: 'success' as const, label: 'OK' }]\` or \`const items = [{ intent: 'success', label: 'OK' }] as const\`. Without \`as const\`, \`item.intent\` becomes \`string\` which fails. (d) For computed values, use typed variable: \`const intent: Intent = ...;\` (import Intent from @idealyst/theme). This applies to ALL components with intent/type props.
15769
16287
  6. **Avatar** uses \`src\` for image URL, \`fallback\` for initials \u2014 NOT \`name\`, \`initials\`, \`label\`. Shape: \`'circle' | 'square'\`.
15770
16288
  7. **Link** requires a \`to\` prop (path string) \u2014 it's a navigation link, NOT pressable text.
15771
16289
  8. **List** takes \`children\` \u2014 NOT \`data\`, \`renderItem\`, or \`keyExtractor\`. Map your data: \`<List>{items.map(item => <View key={item.id}>...</View>)}</List>\`
15772
16290
  9. **Skeleton** uses \`shape\` prop (\`'rectangle' | 'circle' | 'rounded'\`) \u2014 NOT \`variant\`. Props: \`width\`, \`height\`, \`shape\`, \`animation\` (\`'pulse' | 'wave' | 'none'\`). Do NOT build custom skeletons with react-native \`Animated\`.
15773
16291
  10. The component is **TextInput**, NOT \`Input\`.
15774
- 11. **Card** is a simple container \u2014 there are NO compound components like \`Card.Content\`, \`Card.Header\`, \`Card.Body\`, \`Card.Footer\`, \`Card.Title\`. Just put children directly inside \`<Card>...</Card>\`.
16292
+ 11. **Card** is a simple container \u2014 there are NO compound components like \`Card.Content\`, \`Card.Header\`, \`Card.Body\`, \`Card.Footer\`, \`Card.Title\`. Just put children directly inside \`<Card>...</Card>\`. **Card does NOT have \`border\`, \`scrollable\`, or \`backgroundColor\` props** (those are View-only). Card styling props: \`type\` (\`'default'|'outlined'|'elevated'|'filled'\`), \`radius\`, \`intent\`, \`background\`, plus spacing (\`padding\`, \`margin\`, \`gap\`). For borders use \`type="outlined"\`.
16293
+ 12. **Switch** uses \`checked\` and \`onChange\` \u2014 NOT \`value\` and \`onValueChange\` (React Native convention). Also has \`label\`, \`labelPosition\`, \`disabled\`.
15775
16294
 
15776
16295
  ### Navigation
15777
- 11. Use \`NavigatorProvider\` \u2014 there is NO \`Router\` export.
16296
+ 11. **NavigatorProvider** takes a \`route\` prop (SINGULAR) \u2014 NOT \`routes\`: \`<NavigatorProvider route={routeConfig} />\`. There is NO \`Router\` export.
15778
16297
  12. Use \`useNavigator()\` \u2014 NOT \`useNavigate()\`.
15779
- 13. \`navigate()\` takes an **object**: \`navigate({ path: '/settings' })\` \u2014 NOT \`navigate('/settings')\` or \`navigate('routeName', params)\`.
16298
+ 13. \`navigate()\` takes an **object**: \`navigate({ path: '/settings' })\` \u2014 NOT \`navigate('/settings')\` or \`navigate('routeName', params)\`. To pass data use \`vars\`: \`navigate({ path: '/detail/:id', vars: { id: '123' } })\` \u2014 NOT \`params\`: \`navigate({ path: '/detail', params: { id: '123' } })\` (no \`params\` property exists).
15780
16299
  14. \`useNavigationState\` returns \`Record<string, unknown>\` by default. Always provide a type parameter: \`useNavigationState<{ title?: string }>()\`.
15781
16300
  15. \`useParams()\` does NOT accept generic type arguments. It returns \`Record<string, string>\`. Do NOT write \`useParams<{ id: string }>()\` \u2014 that causes TS2558.
15782
16301
 
15783
16302
  ### Imports & Styling
15784
- 16. **Never** import from \`react-native\` \u2014 no \`TouchableOpacity\`, \`FlatList\`, \`ScrollView\`, \`Animated\`, \`Dimensions\`, \`Linking\`, \`Platform\`. Idealyst provides cross-platform alternatives for all of these (e.g., \`openExternalLinks\` on Markdown, \`Pressable\` from \`@idealyst/components\`).
16303
+ 16. **Never** import from \`react-native\` \u2014 no \`TouchableOpacity\`, \`FlatList\`, \`ScrollView\`, \`Animated\`, \`Dimensions\`, \`Linking\`, \`Platform\`. Idealyst provides cross-platform alternatives for all of these (e.g., \`openExternalLinks\` on Markdown, \`Pressable\` from \`@idealyst/components\`). **\`ScrollView\` is NOT exported from \`@idealyst/components\`** \u2014 use \`<View scrollable>\` instead. Do NOT \`import { ScrollView } from '@idealyst/components'\` \u2014 it will cause a TS import error.
15785
16304
  17. **Never** import from \`react-native-unistyles\` \u2014 use \`@idealyst/theme\` (\`configureThemes\`, \`ThemeSettings\`, \`useTheme\`).
15786
16305
  18. **useTheme()** returns the Theme object **directly** (NOT wrapped): \`const theme = useTheme();\`. Do NOT destructure: \`const { theme } = useTheme()\` \u2014 causes TS2339.
15787
16306
  19. **Spacing & Layout**: Use component shorthand props for spacing \u2014 NOT \`theme.spacing\` (which does NOT exist). The correct patterns:
@@ -15792,14 +16311,32 @@ These are mistakes agents make repeatedly. Each one causes TypeScript compilatio
15792
16311
  - \`theme.radii.md\` \u2014 border radius values (this DOES exist)
15793
16312
  - **WRONG**: \`<View paddingTop="md">\` \u2014 does NOT exist as a shorthand prop; use \`style={{ paddingTop: 16 }}\`
15794
16313
  - **WRONG**: \`theme.spacing.md\` \u2014 does NOT exist, causes TS2339
16314
+ - **WRONG**: \`theme.colors.background\` \u2014 does NOT exist. \`theme.colors\` has: \`pallet\`, \`surface\`, \`text\`, \`border\`. Use \`theme.colors.surface.primary\` for background colors.
15795
16315
  - **WRONG**: \`theme.colors.intent.danger\` \u2014 does NOT exist; intents are at \`theme.intents.danger\`
16316
+ - **WRONG**: \`theme.intents.primary.bg\` \u2014 IntentValue does NOT have \`bg\` or \`text\`. IntentValue has: \`primary\` (main color string), \`contrast\` (text-on-bg color), \`light\`, \`dark\`
16317
+ - **CORRECT**: \`theme.intents.primary.primary\` for the color, \`theme.intents.primary.contrast\` for text on that color
16318
+ - **Color key reference** (all keys available):
16319
+ - \`theme.colors.surface\`: \`screen\`, \`primary\`, \`secondary\`, \`tertiary\`, \`inverse\`, \`inverse-secondary\`, \`inverse-tertiary\`
16320
+ - \`theme.colors.text\`: \`primary\`, \`secondary\`, \`tertiary\`, \`inverse\`, \`inverse-secondary\`, \`inverse-tertiary\`
16321
+ - \`theme.colors.border\`: \`primary\`, \`secondary\`, \`tertiary\`, \`disabled\`
16322
+ - \`theme.intents\`: \`primary\`, \`secondary\`, \`success\`, \`warning\`, \`danger\`, \`info\`, \`neutral\` (each has \`.primary\`, \`.contrast\`, \`.light\`, \`.dark\`)
15796
16323
 
15797
16324
  ### Cross-Platform (CRITICAL)
15798
16325
  20. **Never use raw HTML/SVG elements** (\`<svg>\`, \`<circle>\`, \`<canvas>\`, \`<div>\`, \`<span>\`, \`<input>\`) \u2014 they are web-only and will crash on React Native, just like react-native primitives crash on web. Also never use CSS \`transition\` or \`animation\` properties in styles \u2014 they don't exist on native. If you need custom drawing or circular progress, use \`@idealyst/animate\` hooks or \`@idealyst/charts\` \u2014 never raw SVG.
15799
- 21. **Avoid web-only CSS** like \`cursor: 'pointer'\` in shared styles \u2014 not valid on native. Use \`Pressable\` or \`Button\` for interactive elements (they handle cursor automatically on web).
16326
+ 21. **Avoid web-only CSS** like \`cursor: 'pointer'\` in shared styles \u2014 not valid on native. Use \`Pressable\` or \`Button\` for interactive elements (they handle cursor automatically on web). Percentage widths (\`width: '50%'\`) do NOT work reliably on React Native \u2014 use \`flex\` instead.
16327
+ 23. **Use theme colors, never hardcoded hex** \u2014 import \`useTheme\` from \`@idealyst/theme\` and use \`theme.colors.surface.secondary\` (not \`'#f5f5f5'\`), \`theme.colors.border.primary\` (not \`'#e0e0e0'\`), \`theme.intents.primary.primary\` (not \`'#1976d2'\`). Hardcoded colors break dark mode and branding customization. **Exception:** Semi-transparent overlays for camera/media UIs may use \`rgba(0,0,0,0.5)\` since the theme has no overlay color. For other overlays, prefer \`theme.colors.surface.inverse\` with opacity.
16328
+ 22. **Platform file barrel exports**: When creating \`Component.web.tsx\` + \`Component.native.tsx\`, you need THREE index files:
16329
+ - \`index.web.ts\` \u2014 \`export { default as Component } from './Component.web';\`
16330
+ - \`index.native.ts\` \u2014 \`export { default as Component } from './Component.native';\`
16331
+ - \`index.ts\` \u2014 \`export { default as Component } from './Component.web';\` (base file for TypeScript resolution)
16332
+ - **WRONG**: \`export { default } from './Component';\` \u2014 no bare \`Component.ts\` exists, only \`.web.tsx\`/\`.native.tsx\`. This causes TS2307.
16333
+ - **Web-only styles in .web.tsx files**: Cast CSS-only properties with \`as any\`, NOT \`as React.CSSProperties\`. Example: \`style={{ position: 'fixed', transition: 'width 0.2s' } as any}\`. \`React.CSSProperties\` is incompatible with \`StyleProp<ViewStyle>\` \u2014 this causes TS2322.
15800
16334
 
15801
16335
  ### React 19 TypeScript
15802
16336
  - **useRef** requires an initial argument: \`useRef<T>(null)\` \u2014 NOT \`useRef<T>()\`. Omitting the argument causes TS2554. For non-null refs use: \`useRef<number>(0)\`, \`useRef<string[]>([])\`.
16337
+ - **onLayout** callback: The event shape is \`e.nativeEvent.layout.{x, y, width, height}\` \u2014 NOT \`e.layout.width\`. Always destructure: \`onLayout={(e) => { const { width, height } = e.nativeEvent.layout; }}\`. Writing \`e.layout\` causes TS2339.
16338
+ - **Badge children** accepts \`ReactNode\` including numbers \u2014 \`<Badge>{count}</Badge>\` is valid. But if you pass a number to a **string** prop, wrap it: \`<Badge>{String(count)}</Badge>\` or use template literal.
16339
+ - **String literals with apostrophes**: Use backticks or double quotes for strings containing apostrophes \u2014 \`\`I'll be back\`\` or \`"I'll be back"\` \u2014 NOT \`'I'll be back'\` (unescaped \`'\` breaks the string and causes cascading TS errors).
15803
16340
 
15804
16341
  ### Scaffolded Project Layout
15805
16342
  When working in a CLI-scaffolded workspace (created with \`idealyst init\` + \`idealyst create\`), files go in specific locations:
@@ -15816,11 +16353,11 @@ When working in a CLI-scaffolded workspace (created with \`idealyst init\` + \`i
15816
16353
  > **TIP:** Before writing backend code, call \`search_recipes({ query: "trpc" })\` to get the \`trpc-feature\` recipe \u2014 it has the complete step-by-step pattern with correct file paths.
15817
16354
 
15818
16355
  ### Package-Specific (call guide tools for full API)
15819
- 18. **Audio** (\`@idealyst/audio\`) is **PCM streaming**, NOT file-based. \`recorder.stop()\` returns \`void\`. Data is \`ArrayBufferLike\`, NOT strings. Call \`get_audio_guide\` topic \`api\`.
16356
+ 18. **Audio** (\`@idealyst/audio\`) is **PCM streaming**, NOT file-based. \`recorder.stop()\` returns \`void\`. Data is \`ArrayBufferLike\`, NOT strings. Do NOT use \`atob()\` for base64 decoding \u2014 it's browser-only. See the guide for cross-platform patterns. Call \`get_audio_guide\` topic \`api\`.
15820
16357
  19. **Camera** (\`@idealyst/camera\`): Component is \`CameraPreview\`, NOT \`Camera\`. Permission is \`requestPermission()\`, NOT \`requestCameraPermission\`. \`CameraStatus\` is an interface (\`.state\`, \`.permission\`), NOT a string. Call \`get_camera_guide\` topic \`api\`.
15821
- 20. **Files** (\`@idealyst/files\`): Method is \`pick()\`, NOT \`pickFiles()\`. \`FileType\` is \`'image' | 'video' | 'audio' | 'document' | 'archive' | 'any'\` \u2014 NOT \`'pdf'\` or \`'doc'\`. Call \`get_files_guide\` topic \`api\`.
16358
+ 20. **Files** (\`@idealyst/files\`): \`pick()\` returns \`FilePickerResult\` (an **object**, NOT an array). Access files via \`result.files\`: \`result.files.length\`, \`result.files[0].uri\`. Do NOT write \`result.length\` or \`result[0]\`. \`useFilePicker()\` takes \`{ config: { allowedTypes: ['image'], multiple: true } }\` \u2014 NOT \`{ type: 'image' }\`. \`FileType\` is \`'image' | 'video' | 'audio' | 'document' | 'archive' | 'any'\` \u2014 NOT \`'pdf'\` or \`'doc'\`. Call \`get_files_guide\` topic \`api\`.
15822
16359
  21. **Storage** (\`@idealyst/storage\`): Methods are \`getItem()\`/\`setItem()\`, NOT \`get()\`/\`set()\`. Values are string-only. Call \`get_storage_guide\` topic \`api\`.
15823
- 22. **Animate** (\`@idealyst/animate\`): There is NO \`useSequence\` or \`useKeyframes\` \u2014 only \`useAnimatedStyle\`, \`useAnimatedValue\`, \`usePresence\`, \`useGradientBorder\`. Easing values are **camelCase**: \`'easeOut'\` NOT \`'ease-out'\`. \`useAnimatedValue\` REQUIRES an initial number: \`useAnimatedValue(0)\` \u2014 NOT \`useAnimatedValue()\`. Call \`get_animate_guide\` topic \`api\`.
16360
+ 22. **Animate** (\`@idealyst/animate\`): There is NO \`useSequence\` or \`useKeyframes\` \u2014 only \`useAnimatedStyle\`, \`useAnimatedValue\`, \`usePresence\`, \`useGradientBorder\`. Easing values are **camelCase**: \`'easeOut'\` NOT \`'ease-out'\`. \`useAnimatedValue\` REQUIRES an initial number: \`useAnimatedValue(0)\` \u2014 NOT \`useAnimatedValue()\`. \`useAnimatedStyle\` supports a \`delay\` option (ms) for staggered entrances. Transform syntax: use **object** format \`{ x, y, scale, rotate }\` \u2014 NOT array format \`[{ translateX }]\` which doesn't animate. Call \`get_animate_guide\` topic \`api\`.
15824
16361
  23. **Charts** (\`@idealyst/charts\`): \`ChartDataSeries\` requires \`id\` and \`name\` (NOT \`label\`). \`AxisConfig\` uses \`show\` (NOT \`visible\`). \`tickFormat\` type is \`(value: number | string | Date) => string\`. Call \`get_charts_guide\` topic \`api\`.
15825
16362
  `;
15826
16363
 
@@ -23286,7 +23823,7 @@ var import_url = require("url");
23286
23823
  // src/generated/types.json
23287
23824
  var types_default = {
23288
23825
  version: "1.0.93",
23289
- extractedAt: "2026-02-24T16:32:56.796Z",
23826
+ extractedAt: "2026-02-24T21:11:17.058Z",
23290
23827
  components: {
23291
23828
  Accordion: {
23292
23829
  name: "Accordion",
@@ -45587,7 +46124,7 @@ var types_default = {
45587
46124
  navigation: {
45588
46125
  TabBarScreenOptions: 'export type TabBarScreenOptions = {\n /**\n * Icon for tab/drawer navigation.\n *\n * Can be:\n * - A **string** (icon name) \u2014 e.g. `"home"`, `"cog"`. The default layout renders\n * `<Icon name={tabBarIcon} size="sm" />` automatically.\n * - A **render function** \u2014 receives `{ focused, color, size }`. The `size` param is\n * a number (from native tab bars); **ignore it** and use a Size token instead:\n * `tabBarIcon: ({ focused }) => <Icon name={focused ? \'home\' : \'home-outline\'} size="sm" />`\n */\n tabBarIcon?: string | ((props: { focused: boolean; color: string; size: string | number }) => React.ReactElement)\n\n /**\n * Label for tab/drawer navigation\n */\n tabBarLabel?: string;\n \n /**\n * Badge for tab navigation\n */\n tabBarBadge?: string | number;\n \n /**\n * Whether to show the tab bar for this screen\n */\n tabBarVisible?: boolean;\n} & ScreenOptions',
45589
46126
  NavigatorOptions: "export type NavigatorOptions = {\n\n \n /**\n * Custom header title component or string\n */\n headerTitle?: React.ComponentType | React.ReactElement | string;\n \n /**\n * Custom header left component (overrides back button)\n */\n headerLeft?: React.ComponentType | React.ReactElement;\n \n /**\n * Whether to show header back button\n */\n headerBackVisible?: boolean;\n \n /**\n * Custom header right component\n */\n headerRight?: React.ComponentType | React.ReactElement;\n \n /**\n * Whether to hide the native React Navigation header (mobile only)\n */\n headerShown?: boolean;\n}",
45590
- ScreenOptions: "export type ScreenOptions = {\n /**\n * Screen title for navigation headers\n */\n title?: string;\n headerShown?: boolean;\n /**\n * When true, renders the screen outside of parent layout wrappers.\n * Useful for fullscreen modals, onboarding flows, or any screen that\n * should not inherit the parent navigator's layout (header, sidebar, tabs, etc.)\n *\n * Web: Screen renders as a sibling route without the parent LayoutComponent\n * Native: Screen uses fullScreenModal presentation\n */\n fullScreen?: boolean;\n\n} & NavigatorOptions;",
46127
+ ScreenOptions: "export type ScreenOptions = {\n /**\n * Screen title for navigation headers\n */\n title?: string;\n headerShown?: boolean;\n /**\n * Icon name for this screen (used by custom layout components like sidebars, drawers, etc.)\n */\n icon?: string;\n /**\n * When true, renders the screen outside of parent layout wrappers.\n * Useful for fullscreen modals, onboarding flows, or any screen that\n * should not inherit the parent navigator's layout (header, sidebar, tabs, etc.)\n *\n * Web: Screen renders as a sibling route without the parent LayoutComponent\n * Native: Screen uses fullScreenModal presentation\n */\n fullScreen?: boolean;\n\n} & NavigatorOptions;",
45591
46128
  NotFoundComponentProps: "export type NotFoundComponentProps = {\n /** The full path that was attempted */\n path: string\n /** Any route parameters that were parsed from the path */\n params?: Record<string, string>\n}",
45592
46129
  BaseNavigatorParam: "export type BaseNavigatorParam = {\n path: string\n type: 'navigator'\n /**\n * Navigator options. When this navigator is nested inside a tab or drawer,\n * you can include TabBarScreenOptions (tabBarIcon, tabBarLabel, tabBarBadge)\n * so the parent layout can render the tab/drawer entry for this navigator.\n */\n options?: TabBarScreenOptions\n /**\n * Handler called when an invalid route is accessed.\n * - Return NavigateParams to redirect to a different route\n * - Return undefined to show the notFoundComponent (if set)\n * If not defined, bubbles up to parent navigator.\n *\n * @param invalidPath - The path that was attempted but not found\n * @returns NavigateParams to redirect, or undefined to use notFoundComponent\n */\n onInvalidRoute?: (invalidPath: string) => NavigateParams | undefined\n /**\n * Component to render/navigate to when route is invalid and onInvalidRoute returns undefined.\n * - Web: Renders at the current URL via catch-all route\n * - Native: Navigated to as a screen\n * - Optional: If not set and nothing handles the route, a warning is logged\n */\n notFoundComponent?: React.ComponentType<NotFoundComponentProps>\n}",
45593
46130
  TabNavigatorParam: "export type TabNavigatorParam = {\n layout: 'tab'\n routes: RouteParam<TabBarScreenOptions>[]\n layoutComponent?: TabLayoutComponent\n} & BaseNavigatorParam",
@@ -65230,12 +65767,32 @@ function postProcessComponentTypes(componentName, result) {
65230
65767
  }
65231
65768
  if (componentName.toLowerCase() === "card") {
65232
65769
  if (typeof result === "object" && result !== null) {
65233
- result.usageNote = 'Card is a SIMPLE CONTAINER \u2014 there are NO compound components. Do NOT use Card.Content, Card.Header, Card.Body, Card.Footer, Card.Title \u2014 they do NOT exist and will cause TS2339. Just put children directly inside <Card>...</Card>. Example: <Card padding="md"><Text>Title</Text><Text>Body</Text></Card>';
65770
+ result.usageNote = "Card is a SIMPLE CONTAINER \u2014 there are NO compound components. Do NOT use Card.Content, Card.Header, Card.Body, Card.Footer, Card.Title \u2014 they do NOT exist and will cause TS2339. Just put children directly inside <Card>...</Card>. Example: <Card padding=\"md\"><Text>Title</Text><Text>Body</Text></Card>. **Card does NOT have `border`, `scrollable`, or `backgroundColor` props** \u2014 those are View-only props. Using `border` on Card causes TS2322. For borders use `type='outlined'`. For elevated cards use `type='elevated'`. Card styling props: padding, paddingVertical, paddingHorizontal, margin, marginVertical, marginHorizontal, gap/spacing, radius, type ('default'|'outlined'|'elevated'|'filled'), intent, background, style, onPress, disabled. For custom shadows use style={{ ...theme.shadows.md }}.";
65234
65771
  }
65235
65772
  }
65236
65773
  if (componentName.toLowerCase() === "view") {
65237
65774
  if (typeof result === "object" && result !== null) {
65238
- result.usageNote = "View spacing shorthand props: padding, paddingVertical, paddingHorizontal, margin, marginVertical, marginHorizontal, gap/spacing. These accept Size values (xs, sm, md, lg, xl). Do NOT use paddingTop, paddingBottom, paddingLeft, paddingRight, marginTop, marginBottom, marginLeft, marginRight as shorthand props \u2014 they do NOT exist and will cause TS2353. For single-side spacing use style={{ paddingTop: 16 }}.";
65775
+ result.usageNote = "View spacing shorthand props: padding, paddingVertical, paddingHorizontal, margin, marginVertical, marginHorizontal, gap/spacing. These accept Size values (xs, sm, md, lg, xl). Do NOT use paddingTop, paddingBottom, paddingLeft, paddingRight, marginTop, marginBottom, marginLeft, marginRight as shorthand props \u2014 they do NOT exist and will cause TS2353. For single-side spacing use style={{ paddingTop: 16 }}. View does NOT have a `pointerEvents` JSX prop. Use style={{ pointerEvents: 'none' }} instead.";
65776
+ }
65777
+ }
65778
+ if (componentName.toLowerCase() === "textarea") {
65779
+ if (typeof result === "object" && result !== null) {
65780
+ result.usageNote = "TextArea has a DIFFERENT API from TextInput. TextArea uses onChange (not onChangeText) and does NOT have onBlur. TextArea DOES support label, error, and rows props (TextInput does NOT support label/error). Always call get_component_types('TextArea') separately \u2014 do NOT assume it shares TextInput's props.";
65781
+ }
65782
+ }
65783
+ if (componentName.toLowerCase() === "image") {
65784
+ if (typeof result === "object" && result !== null) {
65785
+ result.usageNote = "Image uses `objectFit` (CSS convention) \u2014 NOT `resizeMode` (React Native convention). Valid objectFit values: 'contain', 'cover', 'fill', 'none', 'scale-down'. Image uses `source` prop (accepts URL string or ImageSourcePropType) \u2014 NOT `src`. Example: <Image source=\"https://example.com/photo.jpg\" objectFit=\"cover\" width={200} height={200} />";
65786
+ }
65787
+ }
65788
+ if (componentName.toLowerCase() === "icon") {
65789
+ if (typeof result === "object" && result !== null) {
65790
+ result.usageNote = "Icon color props: Use `intent` for semantic coloring (primary, danger, success, etc.) \u2014 renders the icon in the intent's primary color. Use `textColor` for text-semantic coloring (primary, secondary, tertiary, inverse) \u2014 renders the icon using theme.colors.text[textColor]. Use `color` for arbitrary hex/rgb colors. If the icon represents an action or status, use `intent`. If it should match surrounding text color, use `textColor`.";
65791
+ }
65792
+ }
65793
+ if (componentName.toLowerCase() === "badge") {
65794
+ if (typeof result === "object" && result !== null) {
65795
+ result.usageNote = "Badge `intent` expects Intent: 'primary' | 'success' | 'danger' | 'warning' | 'neutral' | 'info'. Simple ternaries in JSX work fine: `<Badge intent={x > 5 ? 'success' : 'danger'}>` \u2014 TS infers the union. **Do NOT use `as const` on ternary expressions** \u2014 `(cond ? 'a' : 'b') as const` causes TS1355. For arrays of objects, use `as const` on each property value: `{ intent: 'success' as const }`, or use `as const` on the entire array literal. For complex logic, declare a typed variable: `const intent: Intent = cond ? 'success' : 'danger';` (import Intent from @idealyst/theme). This applies to all intent/type props on Badge, Button, Card, Icon, etc.";
65239
65796
  }
65240
65797
  }
65241
65798
  return result;
@@ -65493,8 +66050,8 @@ function getThemeTypes2(args = {}) {
65493
66050
  const result = getThemeTypes(format);
65494
66051
  if (typeof result === "object" && result !== null) {
65495
66052
  const r = result;
65496
- r.useThemeNote = 'IMPORTANT: useTheme() returns Theme directly \u2014 NOT wrapped in an object. Correct: `const theme = useTheme();` WRONG: `const { theme } = useTheme();` (causes TS2339). Theme top-level keys: intents, radii, shadows, colors, sizes, interaction, breakpoints. For spacing, use component props (padding="md", gap="md") \u2014 NOT theme.spacing (does NOT exist). For colors: `style={{ backgroundColor: theme.colors.surface.primary }}`. For radii: `style={{ borderRadius: theme.radii.md }}`. For intents: `theme.intents.primary` (NOT theme.colors.intent).';
65497
- r.themeAccessPatterns = "## Theme Access Patterns\n\n```typescript\nimport { useTheme } from '@idealyst/theme';\nconst theme = useTheme();\n\n// Colors (surface, text, border sub-groups)\ntheme.colors.surface.primary // main background\ntheme.colors.surface.secondary // card/section background\ntheme.colors.text.primary // main text color\ntheme.colors.text.secondary // muted text\ntheme.colors.text.tertiary // subtle text\ntheme.colors.text.inverse // text on dark backgrounds\ntheme.colors.border.primary // standard border\ntheme.colors.border.secondary // subtle border\n\n// Intents (semantic colors with bg, text, border)\ntheme.intents.primary.bg // primary background\ntheme.intents.primary.text // primary text color\ntheme.intents.danger.bg // danger/error background\n// Available: primary, secondary, success, warning, danger, info, neutral\n\n// Radii\ntheme.radii.none // 0\ntheme.radii.sm // small radius\ntheme.radii.md // medium radius\ntheme.radii.lg // large radius\ntheme.radii.xl // extra large\ntheme.radii.full // fully rounded\n\n// Shadows\ntheme.shadows.sm // subtle shadow\ntheme.shadows.md // medium shadow\ntheme.shadows.lg // prominent shadow\n\n// Breakpoints (responsive)\ntheme.breakpoints.xs // 0\ntheme.breakpoints.sm // small screens\ntheme.breakpoints.md // medium screens\ntheme.breakpoints.lg // large screens\n```";
66053
+ r.useThemeNote = "IMPORTANT: useTheme() returns Theme directly \u2014 NOT wrapped in an object. Correct: `const theme = useTheme();` WRONG: `const { theme } = useTheme();` (causes TS2339). Theme top-level keys: intents, radii, shadows, colors, sizes, interaction, breakpoints. For spacing, use component props (padding=\"md\", gap=\"md\") \u2014 NOT theme.spacing (does NOT exist). For colors: `style={{ backgroundColor: theme.colors.surface.primary }}`. For radii: `style={{ borderRadius: theme.radii.md }}`. For intents: `theme.intents.primary.primary` (main color), `.contrast`, `.light`, `.dark`. WRONG: `theme.intents.primary.bg` \u2014 'bg' does NOT exist. WRONG: `theme.intents.primary.text` \u2014 'text' does NOT exist. WRONG: `theme.colors.intent.danger` \u2014 intents are at theme.intents, NOT theme.colors.intent.";
66054
+ r.themeAccessPatterns = "## Theme Access Patterns\n\n```typescript\nimport { useTheme } from '@idealyst/theme';\nconst theme = useTheme();\n\n// Colors (surface, text, border sub-groups)\ntheme.colors.surface.primary // main background\ntheme.colors.surface.secondary // card/section background\ntheme.colors.text.primary // main text color\ntheme.colors.text.secondary // muted text\ntheme.colors.text.tertiary // subtle text\ntheme.colors.text.inverse // text on dark backgrounds\ntheme.colors.border.primary // standard border\ntheme.colors.border.secondary // subtle border\n\n// Intents \u2014 IntentValue has: primary, contrast, light, dark\ntheme.intents.primary.primary // primary intent main color (string)\ntheme.intents.primary.contrast // contrast color for text on primary bg\ntheme.intents.primary.light // lighter variant\ntheme.intents.primary.dark // darker variant\ntheme.intents.danger.primary // danger intent main color\n// Available intents: primary, secondary, success, warning, danger, info, neutral\n// WRONG: theme.intents.primary.bg \u2014 'bg' does NOT exist on IntentValue\n// WRONG: theme.intents.primary.text \u2014 'text' does NOT exist on IntentValue\n\n// Radii\ntheme.radii.none // 0\ntheme.radii.sm // small radius\ntheme.radii.md // medium radius\ntheme.radii.lg // large radius\ntheme.radii.xl // extra large\ntheme.radii.full // fully rounded\n\n// Shadows\ntheme.shadows.sm // subtle shadow\ntheme.shadows.md // medium shadow\ntheme.shadows.lg // prominent shadow\n\n// Breakpoints (responsive)\ntheme.breakpoints.xs // 0\ntheme.breakpoints.sm // small screens\ntheme.breakpoints.md // medium screens\ntheme.breakpoints.lg // large screens\n```";
65498
66055
  r.themeSetup = "## Theme Setup (app initialization)\n\n```typescript\nimport { configureThemes, lightTheme, darkTheme, fromTheme } from '@idealyst/theme';\n\n// Build themes from defaults\nconst light = fromTheme(lightTheme).build();\nconst dark = fromTheme(darkTheme).build();\n\n// Configure at app startup (call once, before any component renders)\nconfigureThemes({ themes: { light, dark } });\n```\n\n## Theme Switching at Runtime\n\n```typescript\nimport { ThemeSettings, getColorScheme } from '@idealyst/theme';\n\n// Switch theme\nThemeSettings.setTheme('dark', 'dark'); // (themeName, contentColor)\nThemeSettings.setTheme('light', 'light', true); // animated transition\n\n// Get current theme name\nconst current = ThemeSettings.getThemeName(); // 'light' or 'dark'\n\n// Follow system light/dark preference\nThemeSettings.setAdaptiveThemes(true);\n\n// Get device color scheme\nconst scheme = getColorScheme(); // 'light' | 'dark' | null\n```\n\nIMPORTANT: Do NOT import from 'react-native-unistyles' directly. Use configureThemes (NOT StyleSheet.configure or UnistylesRegistry). Use ThemeSettings (NOT UnistylesRuntime).";
65499
66056
  }
65500
66057
  return jsonResponse(result);
@@ -65510,6 +66067,8 @@ function getNavigationTypes2(args = {}) {
65510
66067
  const result = getNavigationTypes(format);
65511
66068
  if (typeof result === "object" && result !== null) {
65512
66069
  result.tabBarIconNote = `IMPORTANT: tabBarIcon can be a string (icon name) or a render function. String form (simplest): tabBarIcon: 'home' \u2014 the layout renders <Icon name="home" size="sm" /> automatically. Function form: tabBarIcon: ({ focused }) => <Icon name={focused ? 'home' : 'home-outline'} size="sm" /> WARNING: The function receives { size: number } from native tab bars, but Icon expects a Size token ('xs'|'sm'|'md'|'lg'|'xl'). Do NOT pass the size param to Icon. Use a fixed size token like 'sm' or 'md' instead.`;
66070
+ result.layoutNote = "IMPORTANT: For custom layouts (sidebar, drawer), import Outlet from @idealyst/navigation \u2014 NOT from react-router-dom. Outlet renders the active route's content inside your layout. Example: import { Outlet, useNavigator } from '@idealyst/navigation'; ScreenOptions has: title, headerShown, icon (string), fullScreen. StackLayoutProps has: options, routes (RouteWithFullPath<ScreenOptions>[]), currentPath. Access route metadata: route.options?.icon, route.options?.title, route.fullPath.";
66071
+ result.usageExample = "## NavigatorProvider Usage\n\n```tsx\nimport { NavigatorProvider } from '@idealyst/navigation';\nimport type { NavigatorParam } from '@idealyst/navigation';\n\nconst routeConfig: NavigatorParam = {\n path: '/',\n type: 'navigator',\n layout: 'tab',\n routes: [\n { path: '/home', type: 'screen', component: HomeScreen, options: { title: 'Home', tabBarIcon: 'home' } },\n { path: '/settings', type: 'screen', component: SettingsScreen, options: { title: 'Settings', tabBarIcon: 'cog' } },\n ],\n};\n\n// CRITICAL: The prop is \"route\" (SINGULAR), NOT \"routes\"\nexport const App = () => <NavigatorProvider route={routeConfig} />;\n```";
65513
66072
  }
65514
66073
  return jsonResponse(result);
65515
66074
  } catch (error) {
@@ -65719,6 +66278,17 @@ function getLiveActivityGuide(args) {
65719
66278
  }
65720
66279
  return textResponse(guide);
65721
66280
  }
66281
+ function getNetworkGuide(args) {
66282
+ const topic = args.topic;
66283
+ const uri = `idealyst://network/${topic}`;
66284
+ const guide = networkGuides[uri];
66285
+ if (!guide) {
66286
+ return textResponse(
66287
+ `Topic "${topic}" not found. Available topics: overview, api, examples`
66288
+ );
66289
+ }
66290
+ return textResponse(guide);
66291
+ }
65722
66292
  function listPackages(args = {}) {
65723
66293
  const category = args.category;
65724
66294
  if (category) {
@@ -65969,6 +66539,7 @@ var toolHandlers = {
65969
66539
  get_payments_guide: getPaymentsGuide,
65970
66540
  get_notifications_guide: getNotificationsGuide,
65971
66541
  get_live_activity_guide: getLiveActivityGuide,
66542
+ get_network_guide: getNetworkGuide,
65972
66543
  list_packages: listPackages,
65973
66544
  get_package_docs: getPackageDocs,
65974
66545
  search_packages: searchPackages2,
@@ -66024,12 +66595,16 @@ function callTool(name, args = {}) {
66024
66595
  getInstallGuideDefinition,
66025
66596
  getIntro,
66026
66597
  getIntroDefinition,
66598
+ getLiveActivityGuide,
66599
+ getLiveActivityGuideDefinition,
66027
66600
  getLottieGuide,
66028
66601
  getLottieGuideDefinition,
66029
66602
  getMarkdownGuide,
66030
66603
  getMarkdownGuideDefinition,
66031
66604
  getNavigationTypes,
66032
66605
  getNavigationTypesDefinition,
66606
+ getNetworkGuide,
66607
+ getNetworkGuideDefinition,
66033
66608
  getNotificationsGuide,
66034
66609
  getNotificationsGuideDefinition,
66035
66610
  getOauthClientGuide,