@buoy-gg/env 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +388 -0
  2. package/lib/commonjs/env/EnvVariables.js +25 -0
  3. package/lib/commonjs/env/components/EnvStatsOverview.js +134 -0
  4. package/lib/commonjs/env/components/EnvVarRow.js +170 -0
  5. package/lib/commonjs/env/components/EnvVarSection.js +84 -0
  6. package/lib/commonjs/env/components/EnvVarsModal.js +315 -0
  7. package/lib/commonjs/env/hooks/useDynamicEnv.js +87 -0
  8. package/lib/commonjs/env/index.js +16 -0
  9. package/lib/commonjs/env/types/index.js +27 -0
  10. package/lib/commonjs/env/types/types.js +1 -0
  11. package/lib/commonjs/env/types/userTypes.js +1 -0
  12. package/lib/commonjs/env/utils/envTypeDetector.js +59 -0
  13. package/lib/commonjs/env/utils/helpers.js +119 -0
  14. package/lib/commonjs/env/utils/index.js +38 -0
  15. package/lib/commonjs/env/utils/utils.js +121 -0
  16. package/lib/commonjs/index.js +54 -0
  17. package/lib/commonjs/package.json +1 -0
  18. package/lib/commonjs/preset.js +90 -0
  19. package/lib/module/env/EnvVariables.js +11 -0
  20. package/lib/module/env/components/EnvStatsOverview.js +130 -0
  21. package/lib/module/env/components/EnvVarRow.js +166 -0
  22. package/lib/module/env/components/EnvVarSection.js +80 -0
  23. package/lib/module/env/components/EnvVarsModal.js +311 -0
  24. package/lib/module/env/hooks/useDynamicEnv.js +83 -0
  25. package/lib/module/env/index.js +3 -0
  26. package/lib/module/env/types/index.js +4 -0
  27. package/lib/module/env/types/types.js +1 -0
  28. package/lib/module/env/types/userTypes.js +1 -0
  29. package/lib/module/env/utils/envTypeDetector.js +55 -0
  30. package/lib/module/env/utils/helpers.js +114 -0
  31. package/lib/module/env/utils/index.js +5 -0
  32. package/lib/module/env/utils/utils.js +116 -0
  33. package/lib/module/index.js +13 -0
  34. package/lib/module/preset.js +85 -0
  35. package/lib/typescript/env/EnvVariables.d.ts +8 -0
  36. package/lib/typescript/env/EnvVariables.d.ts.map +1 -0
  37. package/lib/typescript/env/components/EnvStatsOverview.d.ts +20 -0
  38. package/lib/typescript/env/components/EnvStatsOverview.d.ts.map +1 -0
  39. package/lib/typescript/env/components/EnvVarRow.d.ts +9 -0
  40. package/lib/typescript/env/components/EnvVarRow.d.ts.map +1 -0
  41. package/lib/typescript/env/components/EnvVarSection.d.ts +10 -0
  42. package/lib/typescript/env/components/EnvVarSection.d.ts.map +1 -0
  43. package/lib/typescript/env/components/EnvVarsModal.d.ts +26 -0
  44. package/lib/typescript/env/components/EnvVarsModal.d.ts.map +1 -0
  45. package/lib/typescript/env/hooks/useDynamicEnv.d.ts +39 -0
  46. package/lib/typescript/env/hooks/useDynamicEnv.d.ts.map +1 -0
  47. package/lib/typescript/env/index.d.ts +2 -0
  48. package/lib/typescript/env/index.d.ts.map +1 -0
  49. package/lib/typescript/env/types/index.d.ts +3 -0
  50. package/lib/typescript/env/types/index.d.ts.map +1 -0
  51. package/lib/typescript/env/types/types.d.ts +67 -0
  52. package/lib/typescript/env/types/types.d.ts.map +1 -0
  53. package/lib/typescript/env/types/userTypes.d.ts +3 -0
  54. package/lib/typescript/env/types/userTypes.d.ts.map +1 -0
  55. package/lib/typescript/env/utils/envTypeDetector.d.ts +10 -0
  56. package/lib/typescript/env/utils/envTypeDetector.d.ts.map +1 -0
  57. package/lib/typescript/env/utils/helpers.d.ts +70 -0
  58. package/lib/typescript/env/utils/helpers.d.ts.map +1 -0
  59. package/lib/typescript/env/utils/index.d.ts +4 -0
  60. package/lib/typescript/env/utils/index.d.ts.map +1 -0
  61. package/lib/typescript/env/utils/utils.d.ts +24 -0
  62. package/lib/typescript/env/utils/utils.d.ts.map +1 -0
  63. package/lib/typescript/index.d.ts +5 -0
  64. package/lib/typescript/index.d.ts.map +1 -0
  65. package/lib/typescript/preset.d.ts +86 -0
  66. package/lib/typescript/preset.d.ts.map +1 -0
  67. package/package.json +66 -0
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+
3
+ import { View, Text, StyleSheet } from "react-native";
4
+ import { CompactRow, TypeBadge, buoyColors } from "@buoy-gg/shared-ui";
5
+ import { getEnvVarType } from "../utils/envTypeDetector";
6
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
7
+ const getStatusConfig = (status, expectedType) => {
8
+ switch (status) {
9
+ case "required_present":
10
+ return {
11
+ label: "Valid",
12
+ color: buoyColors.success,
13
+ sublabel: "Required"
14
+ };
15
+ case "required_missing":
16
+ return {
17
+ label: "Missing",
18
+ color: buoyColors.error,
19
+ sublabel: "Required"
20
+ };
21
+ case "required_wrong_value":
22
+ return {
23
+ label: "Wrong",
24
+ color: buoyColors.warning,
25
+ sublabel: "Invalid value"
26
+ };
27
+ case "required_wrong_type":
28
+ return {
29
+ label: "Type Error",
30
+ color: buoyColors.info,
31
+ sublabel: "Wrong type"
32
+ };
33
+ case "optional_present":
34
+ return {
35
+ label: "Set",
36
+ color: buoyColors.textSecondary,
37
+ sublabel: "Optional"
38
+ };
39
+ }
40
+ };
41
+ const formatEnvKey = key => {
42
+ // Format key similar to React Query: "section > subsection"
43
+ return key.split("_").join(" › ");
44
+ };
45
+ const formatValue = value => {
46
+ if (value === undefined || value === null) {
47
+ return "undefined";
48
+ }
49
+ const str = typeof value === "string" ? value : String(value);
50
+ return str;
51
+ };
52
+ export function EnvVarRow({
53
+ envVar,
54
+ isExpanded,
55
+ onPress
56
+ }) {
57
+ const config = getStatusConfig(envVar.status, envVar.expectedType);
58
+ const hasValue = envVar.value !== undefined && envVar.value !== null;
59
+
60
+ // Format primary text like React Query does: "section › subsection"
61
+ // For env vars, we'll show the key formatted nicely
62
+ const keyParts = envVar.key.split("_");
63
+ const primaryText = keyParts.map(part => part.toLowerCase()).join(" › ");
64
+
65
+ // Create expanded content for value and expected value
66
+ const expandedContent = /*#__PURE__*/_jsxs(View, {
67
+ style: styles.expandedContainer,
68
+ children: [/*#__PURE__*/_jsxs(View, {
69
+ style: styles.expandedRow,
70
+ children: [/*#__PURE__*/_jsx(Text, {
71
+ style: styles.expandedLabel,
72
+ children: "Value:"
73
+ }), /*#__PURE__*/_jsx(Text, {
74
+ style: styles.expandedValue,
75
+ numberOfLines: 3,
76
+ children: formatValue(envVar.value) || "undefined"
77
+ })]
78
+ }), envVar.status === "required_wrong_type" && envVar.expectedType && /*#__PURE__*/_jsxs(_Fragment, {
79
+ children: [/*#__PURE__*/_jsxs(View, {
80
+ style: styles.expandedRow,
81
+ children: [/*#__PURE__*/_jsx(Text, {
82
+ style: styles.expandedLabel,
83
+ children: "Type:"
84
+ }), /*#__PURE__*/_jsx(TypeBadge, {
85
+ type: getEnvVarType(envVar.value)
86
+ })]
87
+ }), /*#__PURE__*/_jsxs(View, {
88
+ style: styles.expandedRow,
89
+ children: [/*#__PURE__*/_jsx(Text, {
90
+ style: styles.expandedLabel,
91
+ children: "Expected:"
92
+ }), /*#__PURE__*/_jsx(TypeBadge, {
93
+ type: envVar.expectedType
94
+ })]
95
+ })]
96
+ }), envVar.status === "required_wrong_value" && envVar.expectedValue && /*#__PURE__*/_jsxs(View, {
97
+ style: styles.expandedRow,
98
+ children: [/*#__PURE__*/_jsx(Text, {
99
+ style: styles.expandedLabel,
100
+ children: "Expected:"
101
+ }), /*#__PURE__*/_jsx(Text, {
102
+ style: styles.expandedExpected,
103
+ children: String(envVar.expectedValue)
104
+ })]
105
+ }), envVar.description && /*#__PURE__*/_jsxs(View, {
106
+ style: styles.expandedRow,
107
+ children: [/*#__PURE__*/_jsx(Text, {
108
+ style: styles.expandedLabel,
109
+ children: "Info:"
110
+ }), /*#__PURE__*/_jsx(Text, {
111
+ style: styles.expandedDescription,
112
+ children: envVar.description
113
+ })]
114
+ })]
115
+ });
116
+ return /*#__PURE__*/_jsx(CompactRow, {
117
+ statusDotColor: config.color,
118
+ statusLabel: config.label,
119
+ statusSublabel: config.sublabel,
120
+ primaryText: primaryText,
121
+ secondaryText: undefined // Don't show value inline anymore
122
+ ,
123
+ expandedContent: expandedContent,
124
+ isExpanded: isExpanded,
125
+ expandedGlowColor: config.color,
126
+ customBadge: envVar.expectedType ? /*#__PURE__*/_jsx(TypeBadge, {
127
+ type: envVar.expectedType
128
+ }) : undefined,
129
+ showChevron: true,
130
+ onPress: onPress ? () => onPress(envVar) : undefined
131
+ });
132
+ }
133
+ const styles = StyleSheet.create({
134
+ expandedContainer: {
135
+ gap: 6
136
+ },
137
+ expandedRow: {
138
+ flexDirection: "row",
139
+ alignItems: "center",
140
+ gap: 8
141
+ },
142
+ expandedLabel: {
143
+ fontSize: 10,
144
+ color: buoyColors.textMuted,
145
+ fontWeight: "600",
146
+ minWidth: 60,
147
+ fontFamily: "monospace"
148
+ },
149
+ expandedValue: {
150
+ fontSize: 11,
151
+ color: buoyColors.textSecondary,
152
+ fontFamily: "monospace",
153
+ flex: 1
154
+ },
155
+ expandedExpected: {
156
+ fontSize: 11,
157
+ color: buoyColors.warning,
158
+ fontFamily: "monospace",
159
+ flex: 1
160
+ },
161
+ expandedDescription: {
162
+ fontSize: 11,
163
+ color: buoyColors.textSecondary,
164
+ flex: 1
165
+ }
166
+ });
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useState } from "react";
4
+ import { View, Text, StyleSheet } from "react-native";
5
+ import { EnvVarRow } from "./EnvVarRow";
6
+ import { SectionHeader, buoyColors } from "@buoy-gg/shared-ui";
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ export function EnvVarSection({
9
+ title,
10
+ count,
11
+ vars,
12
+ emptyMessage
13
+ }) {
14
+ const [expandedVar, setExpandedVar] = useState(null);
15
+ const handleVarPress = useCallback(envVar => {
16
+ setExpandedVar(prev => prev === envVar.key ? null : envVar.key);
17
+ }, []);
18
+ if (vars.length === 0 && title === "Required Variables") {
19
+ return /*#__PURE__*/_jsxs(View, {
20
+ style: styles.sectionContainer,
21
+ children: [/*#__PURE__*/_jsxs(SectionHeader, {
22
+ children: [/*#__PURE__*/_jsx(SectionHeader.Title, {
23
+ children: title
24
+ }), /*#__PURE__*/_jsx(SectionHeader.Badge, {
25
+ count: 0,
26
+ color: buoyColors.primary
27
+ })]
28
+ }), /*#__PURE__*/_jsx(View, {
29
+ style: styles.emptySection,
30
+ children: /*#__PURE__*/_jsx(Text, {
31
+ style: styles.emptySectionText,
32
+ children: emptyMessage
33
+ })
34
+ })]
35
+ });
36
+ }
37
+ if (vars.length === 0) return null;
38
+ return /*#__PURE__*/_jsxs(View, {
39
+ style: styles.sectionContainer,
40
+ children: [title !== "" && /*#__PURE__*/_jsxs(SectionHeader, {
41
+ children: [/*#__PURE__*/_jsx(SectionHeader.Title, {
42
+ children: title
43
+ }), /*#__PURE__*/_jsx(SectionHeader.Badge, {
44
+ count: count,
45
+ color: buoyColors.primary
46
+ })]
47
+ }), /*#__PURE__*/_jsx(View, {
48
+ style: styles.sectionContent,
49
+ children: vars.map(envVar => /*#__PURE__*/_jsx(EnvVarRow, {
50
+ envVar: envVar,
51
+ isExpanded: expandedVar === envVar.key,
52
+ onPress: handleVarPress
53
+ }, envVar.key))
54
+ })]
55
+ });
56
+ }
57
+ const styles = StyleSheet.create({
58
+ sectionContainer: {
59
+ gap: 8
60
+ },
61
+ sectionContent: {
62
+ // No gap needed, EnvVarRow has its own margins
63
+ },
64
+ emptySection: {
65
+ padding: 20,
66
+ backgroundColor: buoyColors.primary + "08",
67
+ borderRadius: 8,
68
+ borderWidth: 1,
69
+ borderColor: buoyColors.primary + "20",
70
+ alignItems: "center"
71
+ },
72
+ emptySectionText: {
73
+ color: buoyColors.primary,
74
+ fontSize: 11,
75
+ textAlign: "center",
76
+ fontFamily: "monospace",
77
+ opacity: 0.8,
78
+ letterSpacing: 0.5
79
+ }
80
+ });
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+
3
+ import { JsModal, devToolsStorageKeys, ModalHeader, HeaderSearchButton, Search, X, displayValue, buoyColors } from "@buoy-gg/shared-ui";
4
+ import { useCallback, useState, useRef, useEffect, useMemo } from "react";
5
+ import { View, TextInput, TouchableOpacity, StyleSheet, ScrollView, Text } from "react-native";
6
+ import { EnvStatsOverview } from "./EnvStatsOverview";
7
+ import { useDynamicEnv } from "../hooks/useDynamicEnv";
8
+ import { processEnvVars, calculateStats } from "../utils";
9
+ import { EnvVarSection } from "./EnvVarSection";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ /**
12
+ * Full-screen modal for inspecting required environment variables. Handles automatic
13
+ * discovery, validation, filtering, and rich search so teams can quickly spot missing
14
+ * or misconfigured values during development sessions.
15
+ */
16
+ export function EnvVarsModal({
17
+ visible,
18
+ onClose,
19
+ requiredEnvVars,
20
+ onBack,
21
+ onMinimize,
22
+ enableSharedModalDimensions = false
23
+ }) {
24
+ const [activeFilter, setActiveFilter] = useState("all");
25
+ const [isSearchActive, setIsSearchActive] = useState(false);
26
+ const [searchQuery, setSearchQuery] = useState("");
27
+ const searchInputRef = useRef(null);
28
+ const handleModeChange = useCallback(_mode => {
29
+ // Mode changes handled by JsModal
30
+ }, []);
31
+
32
+ // Focus search input when search becomes active
33
+ useEffect(() => {
34
+ if (isSearchActive && searchInputRef.current) {
35
+ searchInputRef.current.focus();
36
+ }
37
+ }, [isSearchActive]);
38
+
39
+ // Clear search when changing filters
40
+ useEffect(() => {
41
+ setSearchQuery("");
42
+ setIsSearchActive(false);
43
+ }, [activeFilter]);
44
+
45
+ // Auto-collect environment variables
46
+ const envResults = useDynamicEnv();
47
+ const autoCollectedEnvVars = useMemo(() => {
48
+ const envVars = {};
49
+ envResults.forEach(({
50
+ key,
51
+ data
52
+ }) => {
53
+ if (data !== undefined && data !== null) {
54
+ envVars[key] = typeof data === "string" ? data : displayValue(data);
55
+ }
56
+ });
57
+ return envVars;
58
+ }, [envResults]);
59
+
60
+ // Process and categorize environment variables
61
+ const {
62
+ requiredVars,
63
+ optionalVars
64
+ } = useMemo(() => {
65
+ return processEnvVars(autoCollectedEnvVars, requiredEnvVars);
66
+ }, [autoCollectedEnvVars, requiredEnvVars]);
67
+
68
+ // Calculate statistics
69
+ const stats = useMemo(() => {
70
+ if (requiredEnvVars === undefined) {
71
+ return {
72
+ totalCount: 0,
73
+ requiredCount: 0,
74
+ optionalCount: 0,
75
+ presentRequiredCount: 0,
76
+ missingCount: 0,
77
+ wrongValueCount: 0,
78
+ wrongTypeCount: 0
79
+ };
80
+ }
81
+ return calculateStats(requiredVars, optionalVars, autoCollectedEnvVars);
82
+ }, [requiredEnvVars, requiredVars, optionalVars, autoCollectedEnvVars]);
83
+
84
+ // Combine all vars and sort by priority (issues first)
85
+ const allVars = useMemo(() => {
86
+ const combined = [...requiredVars, ...optionalVars];
87
+
88
+ // Sort by status priority: errors first, then warnings, then valid
89
+ return combined.sort((a, b) => {
90
+ const priorityMap = {
91
+ "required_missing": 1,
92
+ "required_wrong_type": 2,
93
+ "required_wrong_value": 3,
94
+ "required_present": 4,
95
+ "optional_present": 5
96
+ };
97
+ return (priorityMap[a.status] || 999) - (priorityMap[b.status] || 999);
98
+ });
99
+ }, [requiredVars, optionalVars]);
100
+
101
+ // Filter variables based on active filter and search
102
+ const filteredVars = useMemo(() => {
103
+ let vars = [];
104
+ switch (activeFilter) {
105
+ case "all":
106
+ vars = allVars;
107
+ break;
108
+ case "missing":
109
+ vars = allVars.filter(v => v.status === "required_missing");
110
+ break;
111
+ case "issues":
112
+ vars = allVars.filter(v => v.status === "required_wrong_type" || v.status === "required_wrong_value");
113
+ break;
114
+ }
115
+
116
+ // Apply search filter
117
+ if (searchQuery) {
118
+ const query = searchQuery.toLowerCase();
119
+ vars = vars.filter(v => v.key.toLowerCase().includes(query) || v.description?.toLowerCase().includes(query) || typeof v.value === 'string' && v.value.toLowerCase().includes(query));
120
+ }
121
+ return vars;
122
+ }, [allVars, optionalVars, activeFilter, searchQuery]);
123
+
124
+ // Calculate health percentage
125
+ const healthPercentage = stats.requiredCount > 0 ? Math.round(stats.presentRequiredCount / stats.requiredCount * 100) : 100;
126
+ const healthStatus = healthPercentage === 100 ? "HEALTHY" : healthPercentage >= 75 ? "WARNING" : healthPercentage >= 50 ? "ERROR" : "CRITICAL";
127
+ const healthColor = healthPercentage === 100 ? buoyColors.success : healthPercentage >= 75 ? buoyColors.warning : healthPercentage >= 50 ? buoyColors.error : buoyColors.error;
128
+ if (!visible) return null;
129
+ const storagePrefix = enableSharedModalDimensions ? devToolsStorageKeys.modal.root() : devToolsStorageKeys.env.modal();
130
+ return /*#__PURE__*/_jsx(JsModal, {
131
+ visible: visible,
132
+ onClose: onClose,
133
+ onMinimize: onMinimize,
134
+ persistenceKey: storagePrefix,
135
+ header: {
136
+ customContent: /*#__PURE__*/_jsxs(ModalHeader, {
137
+ children: [onBack && /*#__PURE__*/_jsx(ModalHeader.Navigation, {
138
+ onBack: onBack
139
+ }), /*#__PURE__*/_jsx(ModalHeader.Content, {
140
+ title: isSearchActive ? "" : "Environment Variables",
141
+ noMargin: isSearchActive,
142
+ children: isSearchActive && /*#__PURE__*/_jsxs(View, {
143
+ style: styles.headerSearchContainer,
144
+ children: [/*#__PURE__*/_jsx(Search, {
145
+ size: 12,
146
+ color: buoyColors.textSecondary
147
+ }), /*#__PURE__*/_jsx(TextInput, {
148
+ ref: searchInputRef,
149
+ style: styles.headerSearchInput,
150
+ placeholder: "Search env keys...",
151
+ placeholderTextColor: buoyColors.textMuted,
152
+ value: searchQuery,
153
+ onChangeText: setSearchQuery,
154
+ autoCorrect: false,
155
+ autoCapitalize: "none"
156
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
157
+ onPress: () => {
158
+ setIsSearchActive(false);
159
+ setSearchQuery("");
160
+ },
161
+ style: styles.clearButton,
162
+ children: /*#__PURE__*/_jsx(X, {
163
+ size: 12,
164
+ color: buoyColors.textSecondary
165
+ })
166
+ })]
167
+ })
168
+ }), /*#__PURE__*/_jsx(ModalHeader.Actions, {
169
+ children: !isSearchActive && /*#__PURE__*/_jsx(HeaderSearchButton, {
170
+ onPress: () => setIsSearchActive(true)
171
+ })
172
+ })]
173
+ }),
174
+ showToggleButton: true
175
+ },
176
+ onModeChange: handleModeChange,
177
+ enablePersistence: true,
178
+ initialMode: "bottomSheet",
179
+ enableGlitchEffects: true,
180
+ styles: {},
181
+ children: /*#__PURE__*/_jsxs(ScrollView, {
182
+ style: styles.scrollContainer,
183
+ contentContainerStyle: styles.contentContainer,
184
+ showsVerticalScrollIndicator: false,
185
+ children: [/*#__PURE__*/_jsx(EnvStatsOverview, {
186
+ stats: stats,
187
+ healthPercentage: healthPercentage,
188
+ healthStatus: healthStatus,
189
+ healthColor: healthColor,
190
+ activeFilter: activeFilter,
191
+ onFilterChange: setActiveFilter
192
+ }), filteredVars.length > 0 ? /*#__PURE__*/_jsxs(View, {
193
+ style: styles.varsSection,
194
+ children: [/*#__PURE__*/_jsxs(View, {
195
+ style: styles.sectionHeader,
196
+ children: [/*#__PURE__*/_jsx(Text, {
197
+ style: styles.sectionTitle,
198
+ children: activeFilter === "all" ? "ALL VARIABLES" : activeFilter === "missing" ? "MISSING VARIABLES" : "ISSUES TO FIX"
199
+ }), /*#__PURE__*/_jsx(View, {
200
+ style: styles.countBadge,
201
+ children: /*#__PURE__*/_jsx(Text, {
202
+ style: styles.countText,
203
+ children: filteredVars.length
204
+ })
205
+ })]
206
+ }), /*#__PURE__*/_jsx(EnvVarSection, {
207
+ title: "",
208
+ count: 0,
209
+ vars: filteredVars,
210
+ emptyMessage: ""
211
+ })]
212
+ }) : /*#__PURE__*/_jsxs(View, {
213
+ style: styles.emptyState,
214
+ children: [/*#__PURE__*/_jsx(Search, {
215
+ size: 32,
216
+ color: buoyColors.textMuted
217
+ }), /*#__PURE__*/_jsx(Text, {
218
+ style: styles.emptyTitle,
219
+ children: searchQuery ? "No results found" : "No variables"
220
+ }), /*#__PURE__*/_jsx(Text, {
221
+ style: styles.emptySubtitle,
222
+ children: searchQuery ? `No variables matching "${searchQuery}"` : `No ${activeFilter === "all" ? "" : activeFilter} variables found`
223
+ })]
224
+ })]
225
+ })
226
+ });
227
+ }
228
+ const styles = StyleSheet.create({
229
+ scrollContainer: {
230
+ flex: 1,
231
+ backgroundColor: buoyColors.base
232
+ },
233
+ contentContainer: {
234
+ padding: 8,
235
+ paddingBottom: 24
236
+ },
237
+ headerSearchContainer: {
238
+ flexDirection: "row",
239
+ alignItems: "center",
240
+ flex: 1,
241
+ backgroundColor: buoyColors.input,
242
+ borderRadius: 6,
243
+ paddingHorizontal: 10,
244
+ paddingVertical: 4,
245
+ marginHorizontal: 12,
246
+ marginVertical: 4,
247
+ height: 32,
248
+ borderWidth: 1,
249
+ borderColor: buoyColors.border
250
+ },
251
+ headerSearchInput: {
252
+ flex: 1,
253
+ marginLeft: 8,
254
+ fontSize: 13,
255
+ color: buoyColors.text,
256
+ padding: 0,
257
+ height: '100%'
258
+ },
259
+ clearButton: {
260
+ padding: 4,
261
+ marginLeft: 4
262
+ },
263
+ varsSection: {
264
+ marginTop: 16
265
+ },
266
+ sectionHeader: {
267
+ flexDirection: "row",
268
+ justifyContent: "space-between",
269
+ alignItems: "center",
270
+ marginBottom: 8,
271
+ paddingHorizontal: 8
272
+ },
273
+ sectionTitle: {
274
+ fontSize: 10,
275
+ fontWeight: "700",
276
+ color: buoyColors.textMuted,
277
+ letterSpacing: 1.2,
278
+ fontFamily: "monospace"
279
+ },
280
+ countBadge: {
281
+ backgroundColor: buoyColors.primary + "15",
282
+ paddingHorizontal: 8,
283
+ paddingVertical: 2,
284
+ borderRadius: 9999,
285
+ borderWidth: 1,
286
+ borderColor: buoyColors.primary + "40"
287
+ },
288
+ countText: {
289
+ fontSize: 10,
290
+ fontWeight: "500",
291
+ color: buoyColors.primary,
292
+ fontFamily: "monospace"
293
+ },
294
+ emptyState: {
295
+ alignItems: "center",
296
+ justifyContent: "center",
297
+ paddingVertical: 48
298
+ },
299
+ emptyTitle: {
300
+ fontSize: 16,
301
+ fontWeight: "600",
302
+ color: buoyColors.text,
303
+ marginTop: 12,
304
+ marginBottom: 8
305
+ },
306
+ emptySubtitle: {
307
+ fontSize: 13,
308
+ color: buoyColors.textSecondary,
309
+ textAlign: "center"
310
+ }
311
+ });
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+
3
+ import { useMemo } from "react";
4
+ /**
5
+ * Hook that returns all available environment variables with parsed values
6
+ * Includes all available environment variables by default (only EXPO_PUBLIC_ prefixed vars are loaded by Expo)
7
+ *
8
+ * @example
9
+ * // Get all available environment variables (only EXPO_PUBLIC_ prefixed)
10
+ * const envVars = useDynamicEnv();
11
+ * // Returns: [
12
+ * // { key: 'EXPO_PUBLIC_API_URL', data: 'https://api.example.com' },
13
+ * // { key: 'EXPO_PUBLIC_APP_NAME', data: 'MyApp' },
14
+ * // ...
15
+ * // ]
16
+ *
17
+ * @example
18
+ * // Filter to specific variables
19
+ * const envVars = useDynamicEnv({
20
+ * envFilter: (key) => key.includes('API') || key.includes('URL')
21
+ * });
22
+ *
23
+ * @example
24
+ * // Filter by value content
25
+ * const envVars = useDynamicEnv({
26
+ * envFilter: (key, value) => value !== undefined && value.length > 0
27
+ * });
28
+ */
29
+ export function useDynamicEnv({
30
+ envFilter = () => true // Default: include all available environment variables (EXPO_PUBLIC_ only)
31
+ } = {}) {
32
+ // Helper function to get a single environment variable value
33
+ const getEnvValue = useMemo(() => {
34
+ return key => {
35
+ // @ts-ignore thhis does exist
36
+ const value = process.env[key];
37
+ if (value === undefined) {
38
+ return null;
39
+ }
40
+
41
+ // Try to parse as JSON for complex values, fall back to string
42
+ try {
43
+ // Only attempt JSON parsing if it looks like JSON (starts with { or [)
44
+ if (value.startsWith("{") || value.startsWith("[")) {
45
+ return JSON.parse(value);
46
+ }
47
+
48
+ // Parse boolean-like strings
49
+ if (value.toLowerCase() === "true") return true;
50
+ if (value.toLowerCase() === "false") return false;
51
+
52
+ // Parse number-like strings
53
+ if (/^\d+$/.test(value)) {
54
+ const num = parseInt(value, 10);
55
+ return !isNaN(num) ? num : value;
56
+ }
57
+ if (/^\d*\.\d+$/.test(value)) {
58
+ const num = parseFloat(value);
59
+ return !isNaN(num) ? num : value;
60
+ }
61
+ return value;
62
+ } catch {
63
+ return value;
64
+ }
65
+ };
66
+ }, []);
67
+
68
+ // Get all environment variables and process them
69
+ const envResults = useMemo(() => {
70
+ // @ts-ignore thhis does exist
71
+ const allEnvKeys = Object.keys(process.env);
72
+ const filteredKeys = allEnvKeys.filter(key => {
73
+ // @ts-ignore thhis does exist
74
+ const value = process.env[key];
75
+ return envFilter(key, value);
76
+ });
77
+ return filteredKeys.map(key => ({
78
+ key,
79
+ data: getEnvValue(key)
80
+ }));
81
+ }, [envFilter, getEnvValue]);
82
+ return envResults;
83
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+
3
+ export * from "./EnvVariables";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export * from "./types";
4
+ export * from "./userTypes";
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ "use strict";