UNPKG

optic-react-native

Version:

React Native library for Optic

1 lines 119 kB
{"version":3,"sources":["../node_modules/use-latest-callback/lib/src/useIsomorphicLayoutEffect.js","../node_modules/use-latest-callback/lib/src/index.js","../node_modules/strict-uri-encode/index.js","../node_modules/decode-uri-component/index.js","../node_modules/split-on-first/index.js","../node_modules/filter-obj/index.js","../node_modules/query-string/index.js","../node_modules/escape-string-regexp/index.js","../node_modules/use-sync-external-store/cjs/use-sync-external-store-with-selector.production.js","../node_modules/use-sync-external-store/cjs/use-sync-external-store-with-selector.development.js","../node_modules/use-sync-external-store/with-selector.js","../node_modules/fast-deep-equal/index.js","../src/metrics/globalRenderTracking.ts","../src/store/metricsStore.ts","../src/metrics/network.ts","../src/metrics/startup.ts","../src/core/initOptic.ts","../src/providers/OpticProvider.tsx","../src/overlay/Overlay.tsx","../node_modules/@react-navigation/routers/CommonActions.tsx","../node_modules/@react-navigation/routers/TabRouter.tsx","../node_modules/@react-navigation/routers/DrawerRouter.tsx","../node_modules/@react-navigation/core/BaseNavigationContainer.tsx","../node_modules/use-latest-callback/esm.mjs","../node_modules/@react-navigation/core/createNavigationContainerRef.tsx","../node_modules/@react-navigation/core/DeprecatedNavigationInChildContext.tsx","../node_modules/@react-navigation/core/EnsureSingleNavigator.tsx","../node_modules/@react-navigation/core/NavigationBuilderContext.tsx","../node_modules/@react-navigation/core/NavigationContainerRefContext.tsx","../node_modules/@react-navigation/core/NavigationIndependentTreeContext.tsx","../node_modules/@react-navigation/core/NavigationStateContext.tsx","../node_modules/@react-navigation/core/theming/ThemeProvider.tsx","../node_modules/@react-navigation/core/theming/ThemeContext.tsx","../node_modules/@react-navigation/core/UnhandledActionContext.tsx","../node_modules/@react-navigation/core/useChildListeners.tsx","../node_modules/@react-navigation/core/useEventEmitter.tsx","../node_modules/@react-navigation/core/useKeyedChildListeners.tsx","../node_modules/@react-navigation/core/useNavigationIndependentTree.tsx","../node_modules/@react-navigation/core/useOptionsGetters.tsx","../node_modules/@react-navigation/core/useSyncState.tsx","../node_modules/@react-navigation/core/CurrentRenderContext.tsx","../node_modules/@react-navigation/core/useRouteCache.tsx","../node_modules/@react-navigation/core/getPathFromState.tsx","../node_modules/@react-navigation/core/getStateFromPath.tsx","../node_modules/@react-navigation/core/NavigationContext.tsx","../node_modules/@react-navigation/core/NavigationHelpersContext.tsx","../node_modules/@react-navigation/core/NavigationIndependentTree.tsx","../node_modules/@react-navigation/core/NavigationRouteContext.tsx","../node_modules/@react-navigation/core/PreventRemoveContext.tsx","../node_modules/@react-navigation/core/PreventRemoveProvider.tsx","../node_modules/@react-navigation/core/StaticNavigation.tsx","../node_modules/@react-navigation/core/useRoute.tsx","../node_modules/@react-navigation/core/theming/useTheme.tsx","../node_modules/@react-navigation/core/useFocusEffect.tsx","../node_modules/@react-navigation/core/useNavigation.tsx","../node_modules/@react-navigation/core/useIsFocused.tsx","../node_modules/@react-navigation/core/useNavigationBuilder.tsx","../node_modules/@react-navigation/core/useComponent.tsx","../node_modules/@react-navigation/core/useCurrentRender.tsx","../node_modules/@react-navigation/core/useDescriptors.tsx","../node_modules/@react-navigation/core/SceneView.tsx","../node_modules/@react-navigation/core/NavigationFocusedRouteStateContext.tsx","../node_modules/@react-navigation/core/StaticContainer.tsx","../node_modules/@react-navigation/core/useNavigationCache.tsx","../node_modules/@react-navigation/core/useFocusedListenersChildrenAdapter.tsx","../node_modules/@react-navigation/core/useFocusEvents.tsx","../node_modules/@react-navigation/core/useIsomorphicLayoutEffect.tsx","../node_modules/@react-navigation/core/useLazyValue.tsx","../node_modules/@react-navigation/core/useNavigationHelpers.tsx","../node_modules/@react-navigation/core/useOnAction.tsx","../node_modules/@react-navigation/core/useOnPreventRemove.tsx","../node_modules/@react-navigation/core/useOnGetState.tsx","../node_modules/@react-navigation/core/useOnRouteFocus.tsx","../node_modules/@react-navigation/core/useRegisterNavigator.tsx","../node_modules/@react-navigation/core/useScheduleUpdate.tsx","../node_modules/@react-navigation/core/useNavigationContainerRef.tsx","../node_modules/@react-navigation/core/useNavigationState.tsx","../node_modules/@react-navigation/core/usePreventRemove.tsx","../node_modules/@react-navigation/core/usePreventRemoveContext.tsx","../node_modules/@react-navigation/core/useStateForPath.tsx","../node_modules/@react-navigation/native/createStaticNavigation.tsx","../node_modules/@react-navigation/native/NavigationContainer.tsx","../node_modules/@react-navigation/native/LinkingContext.tsx","../node_modules/@react-navigation/native/LocaleDirContext.tsx","../node_modules/@react-navigation/native/theming/fonts.tsx","../node_modules/@react-navigation/native/UnhandledLinkingContext.tsx","../node_modules/@react-navigation/native/useDocumentTitle.tsx","../node_modules/@react-navigation/native/useLinking.tsx","../node_modules/@react-navigation/native/ServerContext.tsx","../node_modules/@react-navigation/native/useThenable.tsx","../node_modules/@react-navigation/native/Link.tsx","../node_modules/@react-navigation/native/useLinkProps.tsx","../node_modules/@react-navigation/native/ServerContainer.tsx","../node_modules/@react-navigation/native/useLinkBuilder.tsx","../node_modules/@react-navigation/native/useLinkTo.tsx","../node_modules/@react-navigation/native/useLocale.tsx","../node_modules/@react-navigation/native/useScrollToTop.tsx","../src/metrics/fps.ts","../src/metrics/reRenders.ts","../src/metrics/trace.ts"],"sourcesContent":["\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar react_1 = require(\"react\");\n/**\n * Use `useEffect` during SSR and `useLayoutEffect` in the browser to avoid warnings.\n */\nvar useIsomorphicLayoutEffect = typeof document !== 'undefined' ? react_1.useLayoutEffect : react_1.useEffect;\nexports.default = useIsomorphicLayoutEffect;\n","\"use strict\";\nvar React = require(\"react\");\nvar useIsomorphicLayoutEffect_1 = require(\"./useIsomorphicLayoutEffect\");\n/**\n * React hook which returns the latest callback without changing the reference.\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nfunction useLatestCallback(callback) {\n var ref = React.useRef(callback);\n var latestCallback = React.useRef(function latestCallback() {\n var args = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n args[_i] = arguments[_i];\n }\n return ref.current.apply(this, args);\n }).current;\n (0, useIsomorphicLayoutEffect_1.default)(function () {\n ref.current = callback;\n });\n return latestCallback;\n}\nmodule.exports = useLatestCallback;\n","'use strict';\nmodule.exports = str => encodeURIComponent(str).replace(/[!'()*]/g, x => `%${x.charCodeAt(0).toString(16).toUpperCase()}`);\n","'use strict';\nvar token = '%[a-f0-9]{2}';\nvar singleMatcher = new RegExp('(' + token + ')|([^%]+?)', 'gi');\nvar multiMatcher = new RegExp('(' + token + ')+', 'gi');\n\nfunction decodeComponents(components, split) {\n\ttry {\n\t\t// Try to decode the entire string first\n\t\treturn [decodeURIComponent(components.join(''))];\n\t} catch (err) {\n\t\t// Do nothing\n\t}\n\n\tif (components.length === 1) {\n\t\treturn components;\n\t}\n\n\tsplit = split || 1;\n\n\t// Split the array in 2 parts\n\tvar left = components.slice(0, split);\n\tvar right = components.slice(split);\n\n\treturn Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right));\n}\n\nfunction decode(input) {\n\ttry {\n\t\treturn decodeURIComponent(input);\n\t} catch (err) {\n\t\tvar tokens = input.match(singleMatcher) || [];\n\n\t\tfor (var i = 1; i < tokens.length; i++) {\n\t\t\tinput = decodeComponents(tokens, i).join('');\n\n\t\t\ttokens = input.match(singleMatcher) || [];\n\t\t}\n\n\t\treturn input;\n\t}\n}\n\nfunction customDecodeURIComponent(input) {\n\t// Keep track of all the replacements and prefill the map with the `BOM`\n\tvar replaceMap = {\n\t\t'%FE%FF': '\\uFFFD\\uFFFD',\n\t\t'%FF%FE': '\\uFFFD\\uFFFD'\n\t};\n\n\tvar match = multiMatcher.exec(input);\n\twhile (match) {\n\t\ttry {\n\t\t\t// Decode as big chunks as possible\n\t\t\treplaceMap[match[0]] = decodeURIComponent(match[0]);\n\t\t} catch (err) {\n\t\t\tvar result = decode(match[0]);\n\n\t\t\tif (result !== match[0]) {\n\t\t\t\treplaceMap[match[0]] = result;\n\t\t\t}\n\t\t}\n\n\t\tmatch = multiMatcher.exec(input);\n\t}\n\n\t// Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else\n\treplaceMap['%C2'] = '\\uFFFD';\n\n\tvar entries = Object.keys(replaceMap);\n\n\tfor (var i = 0; i < entries.length; i++) {\n\t\t// Replace all decoded components\n\t\tvar key = entries[i];\n\t\tinput = input.replace(new RegExp(key, 'g'), replaceMap[key]);\n\t}\n\n\treturn input;\n}\n\nmodule.exports = function (encodedURI) {\n\tif (typeof encodedURI !== 'string') {\n\t\tthrow new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`');\n\t}\n\n\ttry {\n\t\tencodedURI = encodedURI.replace(/\\+/g, ' ');\n\n\t\t// Try the built in decoder first\n\t\treturn decodeURIComponent(encodedURI);\n\t} catch (err) {\n\t\t// Fallback to a more advanced decoder\n\t\treturn customDecodeURIComponent(encodedURI);\n\t}\n};\n","'use strict';\n\nmodule.exports = (string, separator) => {\n\tif (!(typeof string === 'string' && typeof separator === 'string')) {\n\t\tthrow new TypeError('Expected the arguments to be of type `string`');\n\t}\n\n\tif (separator === '') {\n\t\treturn [string];\n\t}\n\n\tconst separatorIndex = string.indexOf(separator);\n\n\tif (separatorIndex === -1) {\n\t\treturn [string];\n\t}\n\n\treturn [\n\t\tstring.slice(0, separatorIndex),\n\t\tstring.slice(separatorIndex + separator.length)\n\t];\n};\n","'use strict';\nmodule.exports = function (obj, predicate) {\n\tvar ret = {};\n\tvar keys = Object.keys(obj);\n\tvar isArr = Array.isArray(predicate);\n\n\tfor (var i = 0; i < keys.length; i++) {\n\t\tvar key = keys[i];\n\t\tvar val = obj[key];\n\n\t\tif (isArr ? predicate.indexOf(key) !== -1 : predicate(key, val, obj)) {\n\t\t\tret[key] = val;\n\t\t}\n\t}\n\n\treturn ret;\n};\n","'use strict';\nconst strictUriEncode = require('strict-uri-encode');\nconst decodeComponent = require('decode-uri-component');\nconst splitOnFirst = require('split-on-first');\nconst filterObject = require('filter-obj');\n\nconst isNullOrUndefined = value => value === null || value === undefined;\n\nconst encodeFragmentIdentifier = Symbol('encodeFragmentIdentifier');\n\nfunction encoderForArrayFormat(options) {\n\tswitch (options.arrayFormat) {\n\t\tcase 'index':\n\t\t\treturn key => (result, value) => {\n\t\t\t\tconst index = result.length;\n\n\t\t\t\tif (\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\t(options.skipNull && value === null) ||\n\t\t\t\t\t(options.skipEmptyString && value === '')\n\t\t\t\t) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tif (value === null) {\n\t\t\t\t\treturn [...result, [encode(key, options), '[', index, ']'].join('')];\n\t\t\t\t}\n\n\t\t\t\treturn [\n\t\t\t\t\t...result,\n\t\t\t\t\t[encode(key, options), '[', encode(index, options), ']=', encode(value, options)].join('')\n\t\t\t\t];\n\t\t\t};\n\n\t\tcase 'bracket':\n\t\t\treturn key => (result, value) => {\n\t\t\t\tif (\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\t(options.skipNull && value === null) ||\n\t\t\t\t\t(options.skipEmptyString && value === '')\n\t\t\t\t) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tif (value === null) {\n\t\t\t\t\treturn [...result, [encode(key, options), '[]'].join('')];\n\t\t\t\t}\n\n\t\t\t\treturn [...result, [encode(key, options), '[]=', encode(value, options)].join('')];\n\t\t\t};\n\n\t\tcase 'colon-list-separator':\n\t\t\treturn key => (result, value) => {\n\t\t\t\tif (\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\t(options.skipNull && value === null) ||\n\t\t\t\t\t(options.skipEmptyString && value === '')\n\t\t\t\t) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tif (value === null) {\n\t\t\t\t\treturn [...result, [encode(key, options), ':list='].join('')];\n\t\t\t\t}\n\n\t\t\t\treturn [...result, [encode(key, options), ':list=', encode(value, options)].join('')];\n\t\t\t};\n\n\t\tcase 'comma':\n\t\tcase 'separator':\n\t\tcase 'bracket-separator': {\n\t\t\tconst keyValueSep = options.arrayFormat === 'bracket-separator' ?\n\t\t\t\t'[]=' :\n\t\t\t\t'=';\n\n\t\t\treturn key => (result, value) => {\n\t\t\t\tif (\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\t(options.skipNull && value === null) ||\n\t\t\t\t\t(options.skipEmptyString && value === '')\n\t\t\t\t) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\t// Translate null to an empty string so that it doesn't serialize as 'null'\n\t\t\t\tvalue = value === null ? '' : value;\n\n\t\t\t\tif (result.length === 0) {\n\t\t\t\t\treturn [[encode(key, options), keyValueSep, encode(value, options)].join('')];\n\t\t\t\t}\n\n\t\t\t\treturn [[result, encode(value, options)].join(options.arrayFormatSeparator)];\n\t\t\t};\n\t\t}\n\n\t\tdefault:\n\t\t\treturn key => (result, value) => {\n\t\t\t\tif (\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\t(options.skipNull && value === null) ||\n\t\t\t\t\t(options.skipEmptyString && value === '')\n\t\t\t\t) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tif (value === null) {\n\t\t\t\t\treturn [...result, encode(key, options)];\n\t\t\t\t}\n\n\t\t\t\treturn [...result, [encode(key, options), '=', encode(value, options)].join('')];\n\t\t\t};\n\t}\n}\n\nfunction parserForArrayFormat(options) {\n\tlet result;\n\n\tswitch (options.arrayFormat) {\n\t\tcase 'index':\n\t\t\treturn (key, value, accumulator) => {\n\t\t\t\tresult = /\\[(\\d*)\\]$/.exec(key);\n\n\t\t\t\tkey = key.replace(/\\[\\d*\\]$/, '');\n\n\t\t\t\tif (!result) {\n\t\t\t\t\taccumulator[key] = value;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (accumulator[key] === undefined) {\n\t\t\t\t\taccumulator[key] = {};\n\t\t\t\t}\n\n\t\t\t\taccumulator[key][result[1]] = value;\n\t\t\t};\n\n\t\tcase 'bracket':\n\t\t\treturn (key, value, accumulator) => {\n\t\t\t\tresult = /(\\[\\])$/.exec(key);\n\t\t\t\tkey = key.replace(/\\[\\]$/, '');\n\n\t\t\t\tif (!result) {\n\t\t\t\t\taccumulator[key] = value;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (accumulator[key] === undefined) {\n\t\t\t\t\taccumulator[key] = [value];\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\taccumulator[key] = [].concat(accumulator[key], value);\n\t\t\t};\n\n\t\tcase 'colon-list-separator':\n\t\t\treturn (key, value, accumulator) => {\n\t\t\t\tresult = /(:list)$/.exec(key);\n\t\t\t\tkey = key.replace(/:list$/, '');\n\n\t\t\t\tif (!result) {\n\t\t\t\t\taccumulator[key] = value;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (accumulator[key] === undefined) {\n\t\t\t\t\taccumulator[key] = [value];\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\taccumulator[key] = [].concat(accumulator[key], value);\n\t\t\t};\n\n\t\tcase 'comma':\n\t\tcase 'separator':\n\t\t\treturn (key, value, accumulator) => {\n\t\t\t\tconst isArray = typeof value === 'string' && value.includes(options.arrayFormatSeparator);\n\t\t\t\tconst isEncodedArray = (typeof value === 'string' && !isArray && decode(value, options).includes(options.arrayFormatSeparator));\n\t\t\t\tvalue = isEncodedArray ? decode(value, options) : value;\n\t\t\t\tconst newValue = isArray || isEncodedArray ? value.split(options.arrayFormatSeparator).map(item => decode(item, options)) : value === null ? value : decode(value, options);\n\t\t\t\taccumulator[key] = newValue;\n\t\t\t};\n\n\t\tcase 'bracket-separator':\n\t\t\treturn (key, value, accumulator) => {\n\t\t\t\tconst isArray = /(\\[\\])$/.test(key);\n\t\t\t\tkey = key.replace(/\\[\\]$/, '');\n\n\t\t\t\tif (!isArray) {\n\t\t\t\t\taccumulator[key] = value ? decode(value, options) : value;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst arrayValue = value === null ?\n\t\t\t\t\t[] :\n\t\t\t\t\tvalue.split(options.arrayFormatSeparator).map(item => decode(item, options));\n\n\t\t\t\tif (accumulator[key] === undefined) {\n\t\t\t\t\taccumulator[key] = arrayValue;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\taccumulator[key] = [].concat(accumulator[key], arrayValue);\n\t\t\t};\n\n\t\tdefault:\n\t\t\treturn (key, value, accumulator) => {\n\t\t\t\tif (accumulator[key] === undefined) {\n\t\t\t\t\taccumulator[key] = value;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\taccumulator[key] = [].concat(accumulator[key], value);\n\t\t\t};\n\t}\n}\n\nfunction validateArrayFormatSeparator(value) {\n\tif (typeof value !== 'string' || value.length !== 1) {\n\t\tthrow new TypeError('arrayFormatSeparator must be single character string');\n\t}\n}\n\nfunction encode(value, options) {\n\tif (options.encode) {\n\t\treturn options.strict ? strictUriEncode(value) : encodeURIComponent(value);\n\t}\n\n\treturn value;\n}\n\nfunction decode(value, options) {\n\tif (options.decode) {\n\t\treturn decodeComponent(value);\n\t}\n\n\treturn value;\n}\n\nfunction keysSorter(input) {\n\tif (Array.isArray(input)) {\n\t\treturn input.sort();\n\t}\n\n\tif (typeof input === 'object') {\n\t\treturn keysSorter(Object.keys(input))\n\t\t\t.sort((a, b) => Number(a) - Number(b))\n\t\t\t.map(key => input[key]);\n\t}\n\n\treturn input;\n}\n\nfunction removeHash(input) {\n\tconst hashStart = input.indexOf('#');\n\tif (hashStart !== -1) {\n\t\tinput = input.slice(0, hashStart);\n\t}\n\n\treturn input;\n}\n\nfunction getHash(url) {\n\tlet hash = '';\n\tconst hashStart = url.indexOf('#');\n\tif (hashStart !== -1) {\n\t\thash = url.slice(hashStart);\n\t}\n\n\treturn hash;\n}\n\nfunction extract(input) {\n\tinput = removeHash(input);\n\tconst queryStart = input.indexOf('?');\n\tif (queryStart === -1) {\n\t\treturn '';\n\t}\n\n\treturn input.slice(queryStart + 1);\n}\n\nfunction parseValue(value, options) {\n\tif (options.parseNumbers && !Number.isNaN(Number(value)) && (typeof value === 'string' && value.trim() !== '')) {\n\t\tvalue = Number(value);\n\t} else if (options.parseBooleans && value !== null && (value.toLowerCase() === 'true' || value.toLowerCase() === 'false')) {\n\t\tvalue = value.toLowerCase() === 'true';\n\t}\n\n\treturn value;\n}\n\nfunction parse(query, options) {\n\toptions = Object.assign({\n\t\tdecode: true,\n\t\tsort: true,\n\t\tarrayFormat: 'none',\n\t\tarrayFormatSeparator: ',',\n\t\tparseNumbers: false,\n\t\tparseBooleans: false\n\t}, options);\n\n\tvalidateArrayFormatSeparator(options.arrayFormatSeparator);\n\n\tconst formatter = parserForArrayFormat(options);\n\n\t// Create an object with no prototype\n\tconst ret = Object.create(null);\n\n\tif (typeof query !== 'string') {\n\t\treturn ret;\n\t}\n\n\tquery = query.trim().replace(/^[?#&]/, '');\n\n\tif (!query) {\n\t\treturn ret;\n\t}\n\n\tfor (const param of query.split('&')) {\n\t\tif (param === '') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet [key, value] = splitOnFirst(options.decode ? param.replace(/\\+/g, ' ') : param, '=');\n\n\t\t// Missing `=` should be `null`:\n\t\t// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters\n\t\tvalue = value === undefined ? null : ['comma', 'separator', 'bracket-separator'].includes(options.arrayFormat) ? value : decode(value, options);\n\t\tformatter(decode(key, options), value, ret);\n\t}\n\n\tfor (const key of Object.keys(ret)) {\n\t\tconst value = ret[key];\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\tfor (const k of Object.keys(value)) {\n\t\t\t\tvalue[k] = parseValue(value[k], options);\n\t\t\t}\n\t\t} else {\n\t\t\tret[key] = parseValue(value, options);\n\t\t}\n\t}\n\n\tif (options.sort === false) {\n\t\treturn ret;\n\t}\n\n\treturn (options.sort === true ? Object.keys(ret).sort() : Object.keys(ret).sort(options.sort)).reduce((result, key) => {\n\t\tconst value = ret[key];\n\t\tif (Boolean(value) && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// Sort object keys, not values\n\t\t\tresult[key] = keysSorter(value);\n\t\t} else {\n\t\t\tresult[key] = value;\n\t\t}\n\n\t\treturn result;\n\t}, Object.create(null));\n}\n\nexports.extract = extract;\nexports.parse = parse;\n\nexports.stringify = (object, options) => {\n\tif (!object) {\n\t\treturn '';\n\t}\n\n\toptions = Object.assign({\n\t\tencode: true,\n\t\tstrict: true,\n\t\tarrayFormat: 'none',\n\t\tarrayFormatSeparator: ','\n\t}, options);\n\n\tvalidateArrayFormatSeparator(options.arrayFormatSeparator);\n\n\tconst shouldFilter = key => (\n\t\t(options.skipNull && isNullOrUndefined(object[key])) ||\n\t\t(options.skipEmptyString && object[key] === '')\n\t);\n\n\tconst formatter = encoderForArrayFormat(options);\n\n\tconst objectCopy = {};\n\n\tfor (const key of Object.keys(object)) {\n\t\tif (!shouldFilter(key)) {\n\t\t\tobjectCopy[key] = object[key];\n\t\t}\n\t}\n\n\tconst keys = Object.keys(objectCopy);\n\n\tif (options.sort !== false) {\n\t\tkeys.sort(options.sort);\n\t}\n\n\treturn keys.map(key => {\n\t\tconst value = object[key];\n\n\t\tif (value === undefined) {\n\t\t\treturn '';\n\t\t}\n\n\t\tif (value === null) {\n\t\t\treturn encode(key, options);\n\t\t}\n\n\t\tif (Array.isArray(value)) {\n\t\t\tif (value.length === 0 && options.arrayFormat === 'bracket-separator') {\n\t\t\t\treturn encode(key, options) + '[]';\n\t\t\t}\n\n\t\t\treturn value\n\t\t\t\t.reduce(formatter(key), [])\n\t\t\t\t.join('&');\n\t\t}\n\n\t\treturn encode(key, options) + '=' + encode(value, options);\n\t}).filter(x => x.length > 0).join('&');\n};\n\nexports.parseUrl = (url, options) => {\n\toptions = Object.assign({\n\t\tdecode: true\n\t}, options);\n\n\tconst [url_, hash] = splitOnFirst(url, '#');\n\n\treturn Object.assign(\n\t\t{\n\t\t\turl: url_.split('?')[0] || '',\n\t\t\tquery: parse(extract(url), options)\n\t\t},\n\t\toptions && options.parseFragmentIdentifier && hash ? {fragmentIdentifier: decode(hash, options)} : {}\n\t);\n};\n\nexports.stringifyUrl = (object, options) => {\n\toptions = Object.assign({\n\t\tencode: true,\n\t\tstrict: true,\n\t\t[encodeFragmentIdentifier]: true\n\t}, options);\n\n\tconst url = removeHash(object.url).split('?')[0] || '';\n\tconst queryFromUrl = exports.extract(object.url);\n\tconst parsedQueryFromUrl = exports.parse(queryFromUrl, {sort: false});\n\n\tconst query = Object.assign(parsedQueryFromUrl, object.query);\n\tlet queryString = exports.stringify(query, options);\n\tif (queryString) {\n\t\tqueryString = `?${queryString}`;\n\t}\n\n\tlet hash = getHash(object.url);\n\tif (object.fragmentIdentifier) {\n\t\thash = `#${options[encodeFragmentIdentifier] ? encode(object.fragmentIdentifier, options) : object.fragmentIdentifier}`;\n\t}\n\n\treturn `${url}${queryString}${hash}`;\n};\n\nexports.pick = (input, filter, options) => {\n\toptions = Object.assign({\n\t\tparseFragmentIdentifier: true,\n\t\t[encodeFragmentIdentifier]: false\n\t}, options);\n\n\tconst {url, query, fragmentIdentifier} = exports.parseUrl(input, options);\n\treturn exports.stringifyUrl({\n\t\turl,\n\t\tquery: filterObject(query, filter),\n\t\tfragmentIdentifier\n\t}, options);\n};\n\nexports.exclude = (input, filter, options) => {\n\tconst exclusionFilter = Array.isArray(filter) ? key => !filter.includes(key) : (key, value) => !filter(key, value);\n\n\treturn exports.pick(input, exclusionFilter, options);\n};\n","'use strict';\n\nmodule.exports = string => {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError('Expected a string');\n\t}\n\n\t// Escape characters with special meaning either inside or outside character sets.\n\t// Use a simple backslash escape when it’s always valid, and a \\unnnn escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.\n\treturn string\n\t\t.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&')\n\t\t.replace(/-/g, '\\\\x2d');\n};\n","/**\n * @license React\n * use-sync-external-store-with-selector.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar React = require(\"react\");\nfunction is(x, y) {\n return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);\n}\nvar objectIs = \"function\" === typeof Object.is ? Object.is : is,\n useSyncExternalStore = React.useSyncExternalStore,\n useRef = React.useRef,\n useEffect = React.useEffect,\n useMemo = React.useMemo,\n useDebugValue = React.useDebugValue;\nexports.useSyncExternalStoreWithSelector = function (\n subscribe,\n getSnapshot,\n getServerSnapshot,\n selector,\n isEqual\n) {\n var instRef = useRef(null);\n if (null === instRef.current) {\n var inst = { hasValue: !1, value: null };\n instRef.current = inst;\n } else inst = instRef.current;\n instRef = useMemo(\n function () {\n function memoizedSelector(nextSnapshot) {\n if (!hasMemo) {\n hasMemo = !0;\n memoizedSnapshot = nextSnapshot;\n nextSnapshot = selector(nextSnapshot);\n if (void 0 !== isEqual && inst.hasValue) {\n var currentSelection = inst.value;\n if (isEqual(currentSelection, nextSnapshot))\n return (memoizedSelection = currentSelection);\n }\n return (memoizedSelection = nextSnapshot);\n }\n currentSelection = memoizedSelection;\n if (objectIs(memoizedSnapshot, nextSnapshot)) return currentSelection;\n var nextSelection = selector(nextSnapshot);\n if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))\n return (memoizedSnapshot = nextSnapshot), currentSelection;\n memoizedSnapshot = nextSnapshot;\n return (memoizedSelection = nextSelection);\n }\n var hasMemo = !1,\n memoizedSnapshot,\n memoizedSelection,\n maybeGetServerSnapshot =\n void 0 === getServerSnapshot ? null : getServerSnapshot;\n return [\n function () {\n return memoizedSelector(getSnapshot());\n },\n null === maybeGetServerSnapshot\n ? void 0\n : function () {\n return memoizedSelector(maybeGetServerSnapshot());\n }\n ];\n },\n [getSnapshot, getServerSnapshot, selector, isEqual]\n );\n var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);\n useEffect(\n function () {\n inst.hasValue = !0;\n inst.value = value;\n },\n [value]\n );\n useDebugValue(value);\n return value;\n};\n","/**\n * @license React\n * use-sync-external-store-with-selector.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function is(x, y) {\n return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);\n }\n \"undefined\" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&\n \"function\" ===\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&\n __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());\n var React = require(\"react\"),\n objectIs = \"function\" === typeof Object.is ? Object.is : is,\n useSyncExternalStore = React.useSyncExternalStore,\n useRef = React.useRef,\n useEffect = React.useEffect,\n useMemo = React.useMemo,\n useDebugValue = React.useDebugValue;\n exports.useSyncExternalStoreWithSelector = function (\n subscribe,\n getSnapshot,\n getServerSnapshot,\n selector,\n isEqual\n ) {\n var instRef = useRef(null);\n if (null === instRef.current) {\n var inst = { hasValue: !1, value: null };\n instRef.current = inst;\n } else inst = instRef.current;\n instRef = useMemo(\n function () {\n function memoizedSelector(nextSnapshot) {\n if (!hasMemo) {\n hasMemo = !0;\n memoizedSnapshot = nextSnapshot;\n nextSnapshot = selector(nextSnapshot);\n if (void 0 !== isEqual && inst.hasValue) {\n var currentSelection = inst.value;\n if (isEqual(currentSelection, nextSnapshot))\n return (memoizedSelection = currentSelection);\n }\n return (memoizedSelection = nextSnapshot);\n }\n currentSelection = memoizedSelection;\n if (objectIs(memoizedSnapshot, nextSnapshot))\n return currentSelection;\n var nextSelection = selector(nextSnapshot);\n if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))\n return (memoizedSnapshot = nextSnapshot), currentSelection;\n memoizedSnapshot = nextSnapshot;\n return (memoizedSelection = nextSelection);\n }\n var hasMemo = !1,\n memoizedSnapshot,\n memoizedSelection,\n maybeGetServerSnapshot =\n void 0 === getServerSnapshot ? null : getServerSnapshot;\n return [\n function () {\n return memoizedSelector(getSnapshot());\n },\n null === maybeGetServerSnapshot\n ? void 0\n : function () {\n return memoizedSelector(maybeGetServerSnapshot());\n }\n ];\n },\n [getSnapshot, getServerSnapshot, selector, isEqual]\n );\n var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);\n useEffect(\n function () {\n inst.hasValue = !0;\n inst.value = value;\n },\n [value]\n );\n useDebugValue(value);\n return value;\n };\n \"undefined\" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&\n \"function\" ===\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&\n __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/use-sync-external-store-with-selector.production.js');\n} else {\n module.exports = require('./cjs/use-sync-external-store-with-selector.development.js');\n}\n","'use strict';\n\n// do not edit .js files directly - edit src/index.jst\n\n\n\nmodule.exports = function equal(a, b) {\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0;)\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n for (i = length; i-- !== 0;) {\n var key = keys[i];\n\n if (!equal(a[key], b[key])) return false;\n }\n\n return true;\n }\n\n // true if both NaN, false otherwise\n return a!==a && b!==b;\n};\n","import * as React from 'react';\nimport { useMetricsStore } from '../store/metricsStore';\n\ndeclare global {\n var __OPTIC_ROOT_COMPONENT__: React.ComponentType<any> | undefined;\n var __OPTIC_RENDER_TRACKING_ENABLED__: boolean;\n}\n\n// Store to keep track of component renders\nconst renderCounts: Record<string, number> = {};\n\n// Create a wrapper component that tracks renders\nconst withRenderTracking = (WrappedComponent: React.ComponentType<any>) => {\n const RenderTrackingWrapper: React.FC<any> = (props) => {\n const componentName = WrappedComponent.displayName || WrappedComponent.name || 'Unknown';\n const incrementReRender = useMetricsStore((state) => state.incrementReRender);\n \n React.useEffect(() => {\n if (global.__OPTIC_RENDER_TRACKING_ENABLED__) {\n const reRenderInfo = {\n componentName,\n timestamp: Date.now(),\n changedProps: props,\n renderCount: (renderCounts[componentName] || 0) + 1\n };\n incrementReRender(componentName, reRenderInfo);\n renderCounts[componentName] = (renderCounts[componentName] || 0) + 1;\n }\n });\n\n return React.createElement(WrappedComponent, props);\n };\n\n return RenderTrackingWrapper;\n};\n\n// Function to wrap any component with render tracking\nexport function wrapWithRenderTracking<T extends React.ComponentType<any>>(\n component: T\n): T {\n if (!component) return component;\n \n // Skip if already wrapped\n if ((component as any).__OPTIC_WRAPPED__) return component;\n \n const wrapped = withRenderTracking(component);\n (wrapped as any).__OPTIC_WRAPPED__ = true;\n return wrapped as T;\n}\n\n// Function to enable/disable render tracking\nexport function setRenderTrackingEnabled(enabled: boolean) {\n global.__OPTIC_RENDER_TRACKING_ENABLED__ = enabled;\n}\n\n// Function to wrap the root component\nexport function setupGlobalRenderTracking() {\n // Get the root component\n const rootComponent = global.__OPTIC_ROOT_COMPONENT__;\n if (!rootComponent) {\n return;\n }\n\n // Wrap the root component with render tracking\n const wrappedRoot = wrapWithRenderTracking(rootComponent);\n global.__OPTIC_ROOT_COMPONENT__ = wrappedRoot;\n}\n\n// Function to set the root component\nexport function setRootComponent(component: React.ComponentType<any>) {\n if (!component) return;\n \n global.__OPTIC_ROOT_COMPONENT__ = component;\n \n // If render tracking is enabled, wrap the component\n if (global.__OPTIC_RENDER_TRACKING_ENABLED__) {\n setupGlobalRenderTracking();\n }\n}\n\n// Initialize render tracking\nexport function initRenderTracking() {\n // Set initial state\n global.__OPTIC_RENDER_TRACKING_ENABLED__ = true;\n \n // Wrap the root component if it exists\n if (global.__OPTIC_ROOT_COMPONENT__) {\n setupGlobalRenderTracking();\n }\n} ","import { create } from 'zustand';\nimport { InitOpticOptions } from '../core/initOptic';\n\nexport interface NetworkRequest {\n url: string;\n method: string;\n duration: number;\n status: number;\n [key: string]: any; // for any extra fields\n}\n\nexport interface Trace {\n interactionName: string;\n componentName: string;\n duration: number;\n timestamp: number;\n}\n\nexport interface MetricsState {\n currentScreen: string | null;\n screens: Record<string, { \n reRenderCounts: Record<string, number>;\n fps: number | null;\n }>;\n networkRequests: NetworkRequest[];\n traces: Trace[];\n startupTime: number | null;\n setCurrentScreen: (screenName: string | null) => void;\n incrementReRender: (componentName: string) => void;\n setStartupTime: (time: number) => void;\n setFPS: (fps: number, screenName: string) => void;\n addNetworkRequest: (request: NetworkRequest) => void;\n setTrace: (trace: Trace) => void;\n}\n\nexport const useMetricsStore = create<MetricsState>((set, get) => ({\n currentScreen: null,\n screens: {},\n networkRequests: [],\n traces: [],\n startupTime: null,\n\n setCurrentScreen: (screenName) => {\n set((state) => {\n // Initialize screen metrics if they don't exist\n if (screenName && !state.screens[screenName]) {\n return {\n currentScreen: screenName,\n screens: {\n ...state.screens,\n [screenName]: {\n reRenderCounts: {},\n fps: null,\n },\n },\n };\n }\n return { currentScreen: screenName };\n });\n },\n\n incrementReRender: (componentName) => {\n const state = get();\n if (!state.currentScreen) return;\n \n const currentScreen = state.screens[state.currentScreen];\n const currentCount = currentScreen.reRenderCounts[componentName] || 0;\n \n set((state) => ({\n screens: {\n ...state.screens,\n [state.currentScreen!]: {\n ...currentScreen,\n reRenderCounts: {\n ...currentScreen.reRenderCounts,\n [componentName]: currentCount + 1,\n },\n },\n },\n }));\n },\n\n setStartupTime: (time) => {\n set({ startupTime: time });\n },\n\n setFPS: (fps, screenName) => {\n set((state) => ({\n screens: {\n ...state.screens,\n [screenName]: {\n ...state.screens[screenName],\n fps,\n },\n },\n }));\n },\n\n addNetworkRequest: (request) => {\n set((state) => ({\n networkRequests: [...state.networkRequests, request].slice(-50), // Keep last 50 requests\n }));\n },\n\n setTrace: (trace) => {\n set((state) => ({\n traces: [...state.traces, trace].slice(-10), // Keep last 10 traces\n }));\n },\n}));\n\nexport let opticEnabled = true;\n\nexport function setOpticEnabled(value: boolean) {\n opticEnabled = value;\n}\n\nexport function initOptic(options: InitOpticOptions = {}) {\n const { enabled = true, onMetricsLogged } = options;\n opticEnabled = enabled;\n if (!enabled) {\n return;\n }\n // ...rest of your logic...\n}","import { useMetricsStore } from '../store/metricsStore';\n\n// Network performance thresholds (in milliseconds)\nconst NETWORK_THRESHOLDS = {\n GOOD: 200,\n WARNING: 500,\n CRITICAL: 1000,\n};\n\nlet originalFetch: typeof fetch | null = null;\nlet pendingRequests = new Map<string, { startTime: number; url: string; method: string }>();\n\nconst formatDuration = (duration: number): string => {\n if (duration >= 1000) {\n return `${(duration / 1000).toFixed(1)}s`;\n }\n return `${duration}ms`;\n};\n\nexport const initNetworkTracking = () => {\n if (originalFetch !== null) return; // Already initialized\n\n try {\n originalFetch = global.fetch;\n global.fetch = async function (input: RequestInfo | URL, init?: RequestInit) {\n const startTime = Date.now();\n const url = input instanceof Request ? input.url : input.toString();\n const method = input instanceof Request ? input.method : (init?.method || 'GET');\n\n // Store the request start time\n pendingRequests.set(url, { startTime, url, method });\n\n try {\n const response = await originalFetch!(input, init);\n const responseTime = Date.now();\n const responseDuration = responseTime - startTime;\n \n // Clone the response to ensure we can read the body\n const clonedResponse = response.clone();\n \n // Create a new response that will track when the body is read\n const newResponse = new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n\n // Override the json and text methods to track completion\n const originalJson = newResponse.json;\n const originalText = newResponse.text;\n\n newResponse.json = async function() {\n try {\n // First try to read the cloned response to ensure it's valid JSON\n await clonedResponse.json();\n \n // If we get here, the JSON is valid, so read the actual response\n const data = await originalJson.call(this);\n const endTime = Date.now();\n const totalDuration = endTime - startTime;\n\n const metricsStore = useMetricsStore.getState();\n const currentScreen = metricsStore.currentScreen;\n\n const networkRequest = {\n url,\n method,\n duration: totalDuration,\n responseDuration,\n status: response.status,\n screen: currentScreen,\n timestamp: endTime,\n startTime,\n endTime,\n };\n\n metricsStore.addNetworkRequest(networkRequest);\n pendingRequests.delete(url);\n\n return data;\n } catch (error) {\n const endTime = Date.now();\n const totalDuration = endTime - startTime;\n\n const metricsStore = useMetricsStore.getState();\n const currentScreen = metricsStore.currentScreen;\n\n const networkRequest = {\n url,\n method,\n duration: totalDuration,\n responseDuration,\n status: response.status,\n screen: currentScreen,\n timestamp: endTime,\n startTime,\n endTime,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n\n metricsStore.addNetworkRequest(networkRequest);\n pendingRequests.delete(url);\n\n throw error;\n }\n };\n\n newResponse.text = async function() {\n try {\n const data = await originalText.call(this);\n const endTime = Date.now();\n const totalDuration = endTime - startTime;\n\n const metricsStore = useMetricsStore.getState();\n const currentScreen = metricsStore.currentScreen;\n\n const networkRequest = {\n url,\n method,\n duration: totalDuration,\n responseDuration,\n status: response.status,\n screen: currentScreen,\n timestamp: endTime,\n startTime,\n endTime,\n };\n\n metricsStore.addNetworkRequest(networkRequest);\n pendingRequests.delete(url);\n\n return data;\n } catch (error) {\n const endTime = Date.now();\n const totalDuration = endTime - startTime;\n\n const metricsStore = useMetricsStore.getState();\n const currentScreen = metricsStore.currentScreen;\n\n const networkRequest = {\n url,\n method,\n duration: totalDuration,\n responseDuration,\n status: response.status,\n screen: currentScreen,\n timestamp: endTime,\n startTime,\n endTime,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n\n metricsStore.addNetworkRequest(networkRequest);\n pendingRequests.delete(url);\n\n throw error;\n }\n };\n\n return newResponse;\n } catch (error) {\n const endTime = Date.now();\n const totalDuration = endTime - startTime;\n\n const metricsStore = useMetricsStore.getState();\n const currentScreen = metricsStore.currentScreen;\n\n const networkRequest = {\n url,\n method,\n duration: totalDuration,\n status: 0,\n screen: currentScreen,\n timestamp: endTime,\n startTime,\n endTime,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n\n metricsStore.addNetworkRequest(networkRequest);\n pendingRequests.delete(url);\n\n throw error;\n }\n };\n } catch (error) {\n if (originalFetch) {\n global.fetch = originalFetch;\n originalFetch = null;\n }\n }\n};\n\nexport const stopNetworkTracking = () => {\n if (originalFetch === null) return;\n\n global.fetch = originalFetch;\n originalFetch = null;\n pendingRequests.clear();\n};\n\nexport const getNetworkColor = (duration: number | null | undefined): string => {\n if (duration === null || duration === undefined) return '#666666';\n if (duration <= NETWORK_THRESHOLDS.GOOD) return '#4CAF50';\n if (duration <= NETWORK_THRESHOLDS.WARNING) return '#FFC107';\n return '#F44336';\n};\n\nexport const getLatestNetworkRequest = () => {\n const metricsStore = useMetricsStore.getState();\n const currentScreen = metricsStore.currentScreen;\n const networkRequests = metricsStore.networkRequests;\n const screenNetworkRequests = networkRequests.filter(req => req.screen === currentScreen);\n return screenNetworkRequests[screenNetworkRequests.length - 1];\n}; ","export {};\n\nimport { useMetricsStore } from '../store/metricsStore';\n\n// Global app start time (should be set as early as possible in the app entrypoint)\ndeclare global {\n var __OPTIC_APP_START_TIME__: number | undefined;\n var __OPTIC_STARTUP_CAPTURED__: boolean;\n}\n\nif (global.__OPTIC_APP_START_TIME__ === undefined) {\n global.__OPTIC_APP_START_TIME__ = Date.now();\n}\n\nif (global.__OPTIC_STARTUP_CAPTURED__ === undefined) {\n global.__OPTIC_STARTUP_CAPTURED__ = false;\n}\n\n/**\n * Measures time since global app start and logs it to the console.\n * Only measures once and stores the result.\n */\nexport function trackStartupTime() {\n // Only measure startup time once\n if (global.__OPTIC_STARTUP_CAPTURED__) {\n return;\n }\n\n const start = global.__OPTIC_APP_START_TIME__ || Date.now();\n \n // Use requestAnimationFrame to ensure we measure after initial render\n requestAnimationFrame(() => {\n if (!global.__OPTIC_STARTUP_CAPTURED__) {\n const duration = Date.now() - start;\n \n // Mark as captured before setting the time to prevent race conditions\n global.__OPTIC_STARTUP_CAPTURED__ = true;\n \n useMetricsStore.getState().setStartupTime(duration);\n }\n });\n}\n","import { initRenderTracking } from '../metrics/globalRenderTracking';\nimport { initNetworkTracking } from '../metrics/network';\nimport { useMetricsStore } from '../store/metricsStore';\nimport { trackStartupTime } from '../metrics/startup';\nimport { setOpticEnabled } from '../store/metricsStore';\nimport React from 'react';\n\nexport interface InitOpticOptions {\n enabled?: boolean;\n onMetricsLogged?: (metrics: any) => void;\n network?: boolean;\n startup?: boolean;\n reRenders?: boolean;\n traces?: boolean;\n}\n\nexport interface OpticConfig {\n enabled: boolean;\n onMetricsLogged?: (metrics: any) => void;\n network: boolean;\n startup: boolean;\n reRenders: boolean;\n traces: boolean;\n}\n\n// Create a wrapper component that automatically tracks screen names\nfunction withScreenTracking<P extends object>(WrappedComponent: React.ComponentType<P>) {\n const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Unknown';\n const screenName = displayName.replace(/Screen$/, '');\n\n function WithScreenTracking(props: P) {\n const setCurrentScreen = useMetricsStore((state) => state.setCurrentScreen);\n \n React.useEffect(() => {\n setCurrentScreen(screenName);\n return () => setCurrentScreen(null);\n }, [setCurrentScreen]);\n\n return React.createElement(WrappedComponent, props);\n }\n\n WithScreenTracking.displayName = `WithScreenTracking(${displayName})`;\n return WithScreenTracking;\n}\n\n// Function to check if a component is likely a screen\nfunction isScreenComponent(component: any): boolean {\n const name = component.displayName || component.name || '';\n return name.endsWith('Screen') || name.endsWith('Page') || name.endsWith('View');\n}\n\n// Store to keep track of wrapped components\nconst wrappedComponents = new WeakMap();\n\n// Function to wrap a component if it's a screen\nfunction wrapIfScreen<P extends object>(Component: React.ComponentType<P>): React.ComponentType<P> {\n if (!isScreenComponent(Component)) {\n return Component;\n }\n\n // Check if already wrapped\n if (wrappedComponents.has(Component)) {\n return wrappedComponents.get(Component);\n }\n\n // Wrap the component\n const wrapped = withScreenTracking(Component);\n wrappedComponents.set(Component, wrapped);\n return wrapped;\n}\n\nexport function initOptic(options: InitOpticOptions = {}) {\n const {\n enabled = true,\n onMetricsLogged,\n network = true,\n startup = true,\n reRenders = true,\n traces = true,\n } = options;\n\n const config: OpticConfig = {\n enabled,\n onMetricsLogged,\n network,\n startup,\n reRenders,\n traces,\n };\n\n setOpticEnabled(enabled);\n if (!enabled) {\n // Do not initialize anything if disabled\n return;\n }\n\n // Initialize render tracking if enabled\n if (reRenders) {\n initRenderTracking();\n }\n\n // Initialize network tracking if enabled\n if (network) {\n initNetworkTracking();\n }\n\n // Track startup time if enabled\n if (startup) {\n trackStartupTime();\n }\n\n // Initialize metrics store\n useMetricsStore.getState();\n\n // Subscribe to metrics changes and call the callback\n if (onMetricsLogged) {\n const unsubscribe = useMetricsStore.subscribe((metrics) => {\n onMetricsLogged(metrics);\n });\n // Optionally return unsubscribe so the user can clean up\n return {\n config,\n unsubscribe,\n };\n }\n\n return config;\n}\n","import React, { useEffect, useRef } from 'react';\nimport { useMetricsStore } from '../store/metricsStore';\nimport { Overlay } from '../overlay/Overlay';\nimport { useNavigation, useRoute, useNavigationContainerRef } from '@react-navigation/native';\nimport { usePathname, useSegments } from 'expo-router';\nimport { initRenderTracking }