@osdk/react-devtools 0.15.0 → 0.15.1-main-273cce9794f8fd17dc5becdff89fcc57a571f79d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @osdk/react-devtools
2
2
 
3
+ ## 0.15.1-main-273cce9794f8fd17dc5becdff89fcc57a571f79d
4
+
5
+ ### Patch Changes
6
+
7
+ - 273cce9: fix console log source attribution always resolving to ConsoleLogStore instead of the real caller
8
+
3
9
  ## 0.15.0
4
10
 
5
11
  ### Minor Changes
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import { captureCallerLocation, formatCallerLocation } from "../utils/browser-compat/callerLocation.js";
17
18
  import { CircularBuffer } from "../utils/CircularBuffer.js";
18
19
  import { SubscribableStore } from "./SubscribableStore.js";
19
20
  const CONSOLE_LEVELS = ["log", "warn", "error", "info", "debug"];
@@ -25,8 +26,6 @@ const MAX_DEPTH = 3;
25
26
  const MAX_STRING_SIZE = 10240; // 10KB
26
27
  const MAX_TOTAL_SIZE = 10240; // 10KB
27
28
 
28
- const INTERNAL_FRAME_PATTERN = /ConsoleLogStore|serializeArg|serializeValue|getCallerLocation|capEntrySize|osdkConsoleWrapper/u;
29
-
30
29
  // BrowserLogger formats calls with %c CSS styling and a "border: 1px solid"
31
30
  // pattern from its createStyle(). We filter these from the devtools console
32
31
  // because devtools monitors the same operations through its own instrumentation.
@@ -34,9 +33,6 @@ const BROWSER_LOGGER_CSS = "border: 1px solid";
34
33
  function isBrowserLoggerCall(args) {
35
34
  return typeof args[0] === "string" && args[0].startsWith("%c") && typeof args[1] === "string" && args[1].includes(BROWSER_LOGGER_CSS);
36
35
  }
37
- const CHROME_FRAME_REGEX_PAREN = /at\s+.*?\((.*?):(\d+):\d+\)/u;
38
- const CHROME_FRAME_REGEX_BARE = /at\s+(.*?):(\d+):\d+/u;
39
- const FIREFOX_FRAME_REGEX = /@(.*?):(\d+):\d+/u;
40
36
  function serializeValue(value, depth, seen) {
41
37
  if (value == null) {
42
38
  return String(value);
@@ -105,33 +101,6 @@ function serializeArg(arg) {
105
101
  }
106
102
  return result;
107
103
  }
108
- function getCallerLocation() {
109
- const err = new Error();
110
- const stack = err.stack;
111
- if (!stack) {
112
- return undefined;
113
- }
114
- const lines = stack.split("\n");
115
- for (const line of lines) {
116
- if (INTERNAL_FRAME_PATTERN.test(line)) {
117
- continue;
118
- }
119
- let match = CHROME_FRAME_REGEX_PAREN.exec(line);
120
- if (!match) {
121
- match = CHROME_FRAME_REGEX_BARE.exec(line);
122
- }
123
- if (!match) {
124
- match = FIREFOX_FRAME_REGEX.exec(line);
125
- }
126
- if (match) {
127
- const filePath = match[1];
128
- const lineNum = match[2];
129
- const fileName = filePath.split("/").pop() ?? filePath;
130
- return `${fileName}:${lineNum}`;
131
- }
132
- }
133
- return undefined;
134
- }
135
104
 
136
105
  /**
137
106
  * React DevTools' installHook re-emits console.error/warn (to append the React
@@ -191,9 +160,9 @@ export class ConsoleLogStore extends SubscribableStore {
191
160
  this.originals.set(level, original);
192
161
  const store = this;
193
162
  const wrapper = function (...args) {
194
- // Capture the source synchronously, before any async boundary, so the
195
- // user's frame is still on the stack. The in-panel `entry.source` is
196
- // canonical and accurate — verified by ConsoleLogStore.test.ts.
163
+ // Capture the source synchronously, while the user's frame is still on
164
+ // the stack. captureCallerLocation() skips this wrapper by identity, so
165
+ // minification can't break it.
197
166
  //
198
167
  // Browser DevTools source-link attribution (the clickable link beside
199
168
  // each console row) is decided by V8 and follows wherever the original
@@ -209,7 +178,7 @@ export class ConsoleLogStore extends SubscribableStore {
209
178
  // reentrancy guarding is incompatible with the microtask deferral that
210
179
  // makes the source attribution improvement possible.
211
180
  const skipCapture = store.suppressed || store.capturing || isBrowserLoggerCall(args);
212
- const source = skipCapture ? undefined : getCallerLocation();
181
+ const source = skipCapture ? undefined : formatCallerLocation(captureCallerLocation(wrapper));
213
182
  const skip = skipCapture || source !== undefined && isReactDevtoolsFrame(source);
214
183
  Function.prototype.apply.call(original, this ?? console, args);
215
184
  if (skip) {
@@ -1 +1 @@
1
- {"version":3,"file":"ConsoleLogStore.js","names":["CircularBuffer","SubscribableStore","CONSOLE_LEVELS","entryCounter","nextId","Date","now","MAX_DEPTH","MAX_STRING_SIZE","MAX_TOTAL_SIZE","INTERNAL_FRAME_PATTERN","BROWSER_LOGGER_CSS","isBrowserLoggerCall","args","startsWith","includes","CHROME_FRAME_REGEX_PAREN","CHROME_FRAME_REGEX_BARE","FIREFOX_FRAME_REGEX","serializeValue","value","depth","seen","String","type","description","name","obj","Node","tagName","Error","stack","message","has","Array","isArray","length","add","items","i","push","join","entries","key","Object","keys","val","delete","serializeArg","arg","WeakSet","result","slice","getCallerLocation","err","undefined","lines","split","line","test","match","exec","filePath","lineNum","fileName","pop","isReactDevtoolsFrame","source","capEntrySize","totalSize","longestIndex","longestLength","replacement","ConsoleLogStore","cachedEntries","originals","Map","wrappers","installed","suppressed","capturing","notifyScheduled","constructor","capacity","install","level","original","console","set","store","wrapper","skipCapture","skip","Function","prototype","apply","call","queueMicrotask","serializedArgs","map","entry","id","timestamp","scheduleNotify","uninstall","get","ourWrapper","clear","suppress","unsuppress","getEntries","toArray","getSize","notifySubscribers","dispose","clearSubscribers"],"sources":["ConsoleLogStore.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CircularBuffer } from \"../utils/CircularBuffer.js\";\nimport { SubscribableStore } from \"./SubscribableStore.js\";\n\nexport type ConsoleLogLevel = \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n\nconst CONSOLE_LEVELS: readonly ConsoleLogLevel[] = [\n \"log\",\n \"warn\",\n \"error\",\n \"info\",\n \"debug\",\n] as const;\n\nexport interface ConsoleLogEntry {\n readonly id: string;\n readonly level: ConsoleLogLevel;\n readonly args: readonly string[];\n readonly timestamp: number;\n readonly source?: string;\n}\n\nlet entryCounter = 0;\n\nfunction nextId(): string {\n return `console-${++entryCounter}-${Date.now()}`;\n}\n\nconst MAX_DEPTH = 3;\nconst MAX_STRING_SIZE = 10240; // 10KB\nconst MAX_TOTAL_SIZE = 10240; // 10KB\n\nconst INTERNAL_FRAME_PATTERN =\n /ConsoleLogStore|serializeArg|serializeValue|getCallerLocation|capEntrySize|osdkConsoleWrapper/u;\n\n// BrowserLogger formats calls with %c CSS styling and a \"border: 1px solid\"\n// pattern from its createStyle(). We filter these from the devtools console\n// because devtools monitors the same operations through its own instrumentation.\nconst BROWSER_LOGGER_CSS = \"border: 1px solid\";\nfunction isBrowserLoggerCall(args: unknown[]): boolean {\n return (\n typeof args[0] === \"string\" &&\n args[0].startsWith(\"%c\") &&\n typeof args[1] === \"string\" &&\n args[1].includes(BROWSER_LOGGER_CSS)\n );\n}\n\nconst CHROME_FRAME_REGEX_PAREN = /at\\s+.*?\\((.*?):(\\d+):\\d+\\)/u;\nconst CHROME_FRAME_REGEX_BARE = /at\\s+(.*?):(\\d+):\\d+/u;\nconst FIREFOX_FRAME_REGEX = /@(.*?):(\\d+):\\d+/u;\n\nfunction serializeValue(\n value: unknown,\n depth: number,\n seen: WeakSet<object>\n): string {\n if (value == null) {\n return String(value);\n }\n\n const type = typeof value;\n\n if (type === \"string\") {\n if (depth === 0) {\n return value as string;\n }\n return `\"${value as string}\"`;\n }\n if (type === \"number\" || type === \"boolean\") {\n return String(value);\n }\n if (type === \"bigint\") {\n return `BigInt(${String(value)})`;\n }\n if (type === \"symbol\") {\n return `Symbol(${(value as symbol).description ?? \"\"})`;\n }\n if (type === \"function\") {\n return `[Function: ${\n (value as (...args: readonly unknown[]) => unknown).name || \"anonymous\"\n }]`;\n }\n\n const obj = value as object;\n\n if (typeof Node !== \"undefined\" && obj instanceof Node) {\n const el = obj as { tagName?: string };\n return `[HTMLElement: ${el.tagName ?? \"unknown\"}]`;\n }\n\n if (obj instanceof Error) {\n return obj.stack ?? obj.message;\n }\n\n if (seen.has(obj)) {\n return \"[Circular]\";\n }\n\n if (depth >= MAX_DEPTH) {\n if (Array.isArray(obj)) {\n return `[Array(${obj.length})]`;\n }\n return \"[Object]\";\n }\n\n seen.add(obj);\n try {\n if (Array.isArray(obj)) {\n const items: string[] = [];\n for (let i = 0; i < obj.length; i++) {\n items.push(serializeValue(obj[i], depth + 1, seen));\n }\n return `[${items.join(\",\")}]`;\n }\n\n const entries: string[] = [];\n for (const key of Object.keys(obj)) {\n const val = serializeValue(\n (obj as Record<string, unknown>)[key],\n depth + 1,\n seen\n );\n entries.push(`\"${key}\":${val}`);\n }\n return `{${entries.join(\",\")}}`;\n } catch {\n return String(obj);\n } finally {\n seen.delete(obj);\n }\n}\n\nfunction serializeArg(arg: unknown): string {\n const seen = new WeakSet<object>();\n const result = serializeValue(arg, 0, seen);\n if (result.length > MAX_STRING_SIZE) {\n return `${result.slice(0, MAX_STRING_SIZE)}...truncated`;\n }\n return result;\n}\n\nfunction getCallerLocation(): string | undefined {\n const err = new Error();\n const stack = err.stack;\n if (!stack) {\n return undefined;\n }\n\n const lines = stack.split(\"\\n\");\n\n for (const line of lines) {\n if (INTERNAL_FRAME_PATTERN.test(line)) {\n continue;\n }\n\n let match = CHROME_FRAME_REGEX_PAREN.exec(line);\n if (!match) {\n match = CHROME_FRAME_REGEX_BARE.exec(line);\n }\n if (!match) {\n match = FIREFOX_FRAME_REGEX.exec(line);\n }\n\n if (match) {\n const filePath = match[1];\n const lineNum = match[2];\n const fileName = filePath.split(\"/\").pop() ?? filePath;\n return `${fileName}:${lineNum}`;\n }\n }\n\n return undefined;\n}\n\n/**\n * React DevTools' installHook re-emits console.error/warn (to append the React\n * component stack) through our wrapper, which surfaces as a duplicate entry\n * whose resolved source is installHook.js. Recognize those frames so the\n * re-emission can be dropped — the app's own call is captured separately with\n * its real source, since our wrapper sits on top of installHook's.\n */\nfunction isReactDevtoolsFrame(source: string): boolean {\n return (\n source.startsWith(\"installHook.js\") ||\n source.includes(\"react_devtools\") ||\n source.includes(\"react-devtools\") ||\n source.includes(\"react-router-dom\")\n );\n}\n\nfunction capEntrySize(args: string[]): string[] {\n let totalSize = 0;\n for (const arg of args) {\n totalSize += arg.length;\n }\n\n if (totalSize <= MAX_TOTAL_SIZE) {\n return args;\n }\n\n const result = [...args];\n while (totalSize > MAX_TOTAL_SIZE) {\n let longestIndex = 0;\n let longestLength = 0;\n for (let i = 0; i < result.length; i++) {\n if (result[i].length > longestLength) {\n longestLength = result[i].length;\n longestIndex = i;\n }\n }\n if (longestLength <= 40) {\n break;\n }\n const replacement = `...truncated (${longestLength} bytes)`;\n totalSize += replacement.length - longestLength;\n result[longestIndex] = replacement;\n }\n return result;\n}\n\nexport class ConsoleLogStore extends SubscribableStore {\n private readonly entries: CircularBuffer<ConsoleLogEntry>;\n private cachedEntries: readonly ConsoleLogEntry[] | null = null;\n private readonly originals = new Map<\n ConsoleLogLevel,\n (...args: unknown[]) => void\n >();\n private readonly wrappers = new Map<\n ConsoleLogLevel,\n (...args: unknown[]) => void\n >();\n private installed = false;\n private suppressed = false;\n private capturing = false;\n private notifyScheduled = false;\n\n constructor(capacity: number = 1000) {\n super();\n this.entries = new CircularBuffer(capacity);\n }\n\n install(): void {\n if (this.installed) {\n return;\n }\n\n for (const level of CONSOLE_LEVELS) {\n const original = console[level]; // eslint-disable-line no-console\n this.originals.set(level, original);\n\n const store = this;\n const wrapper = function osdkConsoleWrapper(\n this: Console,\n ...args: unknown[]\n ) {\n // Capture the source synchronously, before any async boundary, so the\n // user's frame is still on the stack. The in-panel `entry.source` is\n // canonical and accurate — verified by ConsoleLogStore.test.ts.\n //\n // Browser DevTools source-link attribution (the clickable link beside\n // each console row) is decided by V8 and follows wherever the original\n // method was *called*. Routing the call through Function.prototype.apply\n // is best-effort; in practice the link may still resolve to the wrapper\n // file in some Chromium versions. There is no fully-portable JS-level\n // mitigation; if needed, prefer the panel-side source field.\n //\n // Reentrancy note: capture work runs in queueMicrotask, so `capturing`\n // resets between the wrapper microtask and any nested microtask. A\n // getter that calls console.log during serialization may therefore be\n // captured (one extra entry, no infinite loop). Strict synchronous\n // reentrancy guarding is incompatible with the microtask deferral that\n // makes the source attribution improvement possible.\n const skipCapture =\n store.suppressed || store.capturing || isBrowserLoggerCall(args);\n const source = skipCapture ? undefined : getCallerLocation();\n const skip =\n skipCapture || (source !== undefined && isReactDevtoolsFrame(source));\n\n Function.prototype.apply.call(original, this ?? console, args);\n\n if (skip) {\n return;\n }\n\n queueMicrotask(() => {\n if (store.capturing) {\n return;\n }\n store.capturing = true;\n try {\n const serializedArgs = capEntrySize(args.map(serializeArg));\n const entry: ConsoleLogEntry = {\n id: nextId(),\n level,\n args: serializedArgs,\n timestamp: Date.now(),\n ...(source !== undefined ? { source } : {}),\n };\n\n store.entries.push(entry);\n store.cachedEntries = null;\n store.scheduleNotify();\n } catch {\n } finally {\n store.capturing = false;\n }\n });\n };\n\n console[level] = wrapper; // eslint-disable-line no-console\n this.wrappers.set(level, wrapper);\n }\n\n this.installed = true;\n }\n\n uninstall(): void {\n if (!this.installed) {\n return;\n }\n\n for (const level of CONSOLE_LEVELS) {\n const original = this.originals.get(level);\n const ourWrapper = this.wrappers.get(level);\n if (original && ourWrapper && console[level] === ourWrapper) {\n console[level] = original; // eslint-disable-line no-console\n }\n }\n\n this.originals.clear();\n this.wrappers.clear();\n this.installed = false;\n }\n\n suppress(): void {\n this.suppressed = true;\n }\n\n unsuppress(): void {\n this.suppressed = false;\n }\n\n getEntries(): readonly ConsoleLogEntry[] {\n if (this.cachedEntries != null) {\n return this.cachedEntries;\n }\n this.cachedEntries = this.entries.toArray();\n return this.cachedEntries;\n }\n\n getSize(): number {\n return this.entries.getSize();\n }\n\n clear(): void {\n this.entries.clear();\n this.cachedEntries = null;\n this.notifySubscribers();\n }\n\n dispose(): void {\n this.uninstall();\n this.entries.clear();\n this.cachedEntries = null;\n this.clearSubscribers();\n }\n\n private scheduleNotify(): void {\n if (this.notifyScheduled) {\n return;\n }\n this.notifyScheduled = true;\n queueMicrotask(() => {\n this.notifyScheduled = false;\n this.notifySubscribers();\n });\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"ConsoleLogStore.js","names":["captureCallerLocation","formatCallerLocation","CircularBuffer","SubscribableStore","CONSOLE_LEVELS","entryCounter","nextId","Date","now","MAX_DEPTH","MAX_STRING_SIZE","MAX_TOTAL_SIZE","BROWSER_LOGGER_CSS","isBrowserLoggerCall","args","startsWith","includes","serializeValue","value","depth","seen","String","type","description","name","obj","Node","tagName","Error","stack","message","has","Array","isArray","length","add","items","i","push","join","entries","key","Object","keys","val","delete","serializeArg","arg","WeakSet","result","slice","isReactDevtoolsFrame","source","capEntrySize","totalSize","longestIndex","longestLength","replacement","ConsoleLogStore","cachedEntries","originals","Map","wrappers","installed","suppressed","capturing","notifyScheduled","constructor","capacity","install","level","original","console","set","store","wrapper","skipCapture","undefined","skip","Function","prototype","apply","call","queueMicrotask","serializedArgs","map","entry","id","timestamp","scheduleNotify","uninstall","get","ourWrapper","clear","suppress","unsuppress","getEntries","toArray","getSize","notifySubscribers","dispose","clearSubscribers"],"sources":["ConsoleLogStore.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n captureCallerLocation,\n formatCallerLocation,\n} from \"../utils/browser-compat/callerLocation.js\";\nimport { CircularBuffer } from \"../utils/CircularBuffer.js\";\nimport { SubscribableStore } from \"./SubscribableStore.js\";\n\nexport type ConsoleLogLevel = \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n\nconst CONSOLE_LEVELS: readonly ConsoleLogLevel[] = [\n \"log\",\n \"warn\",\n \"error\",\n \"info\",\n \"debug\",\n] as const;\n\nexport interface ConsoleLogEntry {\n readonly id: string;\n readonly level: ConsoleLogLevel;\n readonly args: readonly string[];\n readonly timestamp: number;\n readonly source?: string;\n}\n\nlet entryCounter = 0;\n\nfunction nextId(): string {\n return `console-${++entryCounter}-${Date.now()}`;\n}\n\nconst MAX_DEPTH = 3;\nconst MAX_STRING_SIZE = 10240; // 10KB\nconst MAX_TOTAL_SIZE = 10240; // 10KB\n\n// BrowserLogger formats calls with %c CSS styling and a \"border: 1px solid\"\n// pattern from its createStyle(). We filter these from the devtools console\n// because devtools monitors the same operations through its own instrumentation.\nconst BROWSER_LOGGER_CSS = \"border: 1px solid\";\nfunction isBrowserLoggerCall(args: unknown[]): boolean {\n return (\n typeof args[0] === \"string\" &&\n args[0].startsWith(\"%c\") &&\n typeof args[1] === \"string\" &&\n args[1].includes(BROWSER_LOGGER_CSS)\n );\n}\n\nfunction serializeValue(\n value: unknown,\n depth: number,\n seen: WeakSet<object>\n): string {\n if (value == null) {\n return String(value);\n }\n\n const type = typeof value;\n\n if (type === \"string\") {\n if (depth === 0) {\n return value as string;\n }\n return `\"${value as string}\"`;\n }\n if (type === \"number\" || type === \"boolean\") {\n return String(value);\n }\n if (type === \"bigint\") {\n return `BigInt(${String(value)})`;\n }\n if (type === \"symbol\") {\n return `Symbol(${(value as symbol).description ?? \"\"})`;\n }\n if (type === \"function\") {\n return `[Function: ${\n (value as (...args: readonly unknown[]) => unknown).name || \"anonymous\"\n }]`;\n }\n\n const obj = value as object;\n\n if (typeof Node !== \"undefined\" && obj instanceof Node) {\n const el = obj as { tagName?: string };\n return `[HTMLElement: ${el.tagName ?? \"unknown\"}]`;\n }\n\n if (obj instanceof Error) {\n return obj.stack ?? obj.message;\n }\n\n if (seen.has(obj)) {\n return \"[Circular]\";\n }\n\n if (depth >= MAX_DEPTH) {\n if (Array.isArray(obj)) {\n return `[Array(${obj.length})]`;\n }\n return \"[Object]\";\n }\n\n seen.add(obj);\n try {\n if (Array.isArray(obj)) {\n const items: string[] = [];\n for (let i = 0; i < obj.length; i++) {\n items.push(serializeValue(obj[i], depth + 1, seen));\n }\n return `[${items.join(\",\")}]`;\n }\n\n const entries: string[] = [];\n for (const key of Object.keys(obj)) {\n const val = serializeValue(\n (obj as Record<string, unknown>)[key],\n depth + 1,\n seen\n );\n entries.push(`\"${key}\":${val}`);\n }\n return `{${entries.join(\",\")}}`;\n } catch {\n return String(obj);\n } finally {\n seen.delete(obj);\n }\n}\n\nfunction serializeArg(arg: unknown): string {\n const seen = new WeakSet<object>();\n const result = serializeValue(arg, 0, seen);\n if (result.length > MAX_STRING_SIZE) {\n return `${result.slice(0, MAX_STRING_SIZE)}...truncated`;\n }\n return result;\n}\n\n/**\n * React DevTools' installHook re-emits console.error/warn (to append the React\n * component stack) through our wrapper, which surfaces as a duplicate entry\n * whose resolved source is installHook.js. Recognize those frames so the\n * re-emission can be dropped — the app's own call is captured separately with\n * its real source, since our wrapper sits on top of installHook's.\n */\nfunction isReactDevtoolsFrame(source: string): boolean {\n return (\n source.startsWith(\"installHook.js\") ||\n source.includes(\"react_devtools\") ||\n source.includes(\"react-devtools\") ||\n source.includes(\"react-router-dom\")\n );\n}\n\nfunction capEntrySize(args: string[]): string[] {\n let totalSize = 0;\n for (const arg of args) {\n totalSize += arg.length;\n }\n\n if (totalSize <= MAX_TOTAL_SIZE) {\n return args;\n }\n\n const result = [...args];\n while (totalSize > MAX_TOTAL_SIZE) {\n let longestIndex = 0;\n let longestLength = 0;\n for (let i = 0; i < result.length; i++) {\n if (result[i].length > longestLength) {\n longestLength = result[i].length;\n longestIndex = i;\n }\n }\n if (longestLength <= 40) {\n break;\n }\n const replacement = `...truncated (${longestLength} bytes)`;\n totalSize += replacement.length - longestLength;\n result[longestIndex] = replacement;\n }\n return result;\n}\n\nexport class ConsoleLogStore extends SubscribableStore {\n private readonly entries: CircularBuffer<ConsoleLogEntry>;\n private cachedEntries: readonly ConsoleLogEntry[] | null = null;\n private readonly originals = new Map<\n ConsoleLogLevel,\n (...args: unknown[]) => void\n >();\n private readonly wrappers = new Map<\n ConsoleLogLevel,\n (...args: unknown[]) => void\n >();\n private installed = false;\n private suppressed = false;\n private capturing = false;\n private notifyScheduled = false;\n\n constructor(capacity: number = 1000) {\n super();\n this.entries = new CircularBuffer(capacity);\n }\n\n install(): void {\n if (this.installed) {\n return;\n }\n\n for (const level of CONSOLE_LEVELS) {\n const original = console[level]; // eslint-disable-line no-console\n this.originals.set(level, original);\n\n const store = this;\n const wrapper = function osdkConsoleWrapper(\n this: Console,\n ...args: unknown[]\n ) {\n // Capture the source synchronously, while the user's frame is still on\n // the stack. captureCallerLocation() skips this wrapper by identity, so\n // minification can't break it.\n //\n // Browser DevTools source-link attribution (the clickable link beside\n // each console row) is decided by V8 and follows wherever the original\n // method was *called*. Routing the call through Function.prototype.apply\n // is best-effort; in practice the link may still resolve to the wrapper\n // file in some Chromium versions. There is no fully-portable JS-level\n // mitigation; if needed, prefer the panel-side source field.\n //\n // Reentrancy note: capture work runs in queueMicrotask, so `capturing`\n // resets between the wrapper microtask and any nested microtask. A\n // getter that calls console.log during serialization may therefore be\n // captured (one extra entry, no infinite loop). Strict synchronous\n // reentrancy guarding is incompatible with the microtask deferral that\n // makes the source attribution improvement possible.\n const skipCapture =\n store.suppressed || store.capturing || isBrowserLoggerCall(args);\n const source = skipCapture\n ? undefined\n : formatCallerLocation(captureCallerLocation(wrapper));\n const skip =\n skipCapture || (source !== undefined && isReactDevtoolsFrame(source));\n\n Function.prototype.apply.call(original, this ?? console, args);\n\n if (skip) {\n return;\n }\n\n queueMicrotask(() => {\n if (store.capturing) {\n return;\n }\n store.capturing = true;\n try {\n const serializedArgs = capEntrySize(args.map(serializeArg));\n const entry: ConsoleLogEntry = {\n id: nextId(),\n level,\n args: serializedArgs,\n timestamp: Date.now(),\n ...(source !== undefined ? { source } : {}),\n };\n\n store.entries.push(entry);\n store.cachedEntries = null;\n store.scheduleNotify();\n } catch {\n } finally {\n store.capturing = false;\n }\n });\n };\n\n console[level] = wrapper; // eslint-disable-line no-console\n this.wrappers.set(level, wrapper);\n }\n\n this.installed = true;\n }\n\n uninstall(): void {\n if (!this.installed) {\n return;\n }\n\n for (const level of CONSOLE_LEVELS) {\n const original = this.originals.get(level);\n const ourWrapper = this.wrappers.get(level);\n if (original && ourWrapper && console[level] === ourWrapper) {\n console[level] = original; // eslint-disable-line no-console\n }\n }\n\n this.originals.clear();\n this.wrappers.clear();\n this.installed = false;\n }\n\n suppress(): void {\n this.suppressed = true;\n }\n\n unsuppress(): void {\n this.suppressed = false;\n }\n\n getEntries(): readonly ConsoleLogEntry[] {\n if (this.cachedEntries != null) {\n return this.cachedEntries;\n }\n this.cachedEntries = this.entries.toArray();\n return this.cachedEntries;\n }\n\n getSize(): number {\n return this.entries.getSize();\n }\n\n clear(): void {\n this.entries.clear();\n this.cachedEntries = null;\n this.notifySubscribers();\n }\n\n dispose(): void {\n this.uninstall();\n this.entries.clear();\n this.cachedEntries = null;\n this.clearSubscribers();\n }\n\n private scheduleNotify(): void {\n if (this.notifyScheduled) {\n return;\n }\n this.notifyScheduled = true;\n queueMicrotask(() => {\n this.notifyScheduled = false;\n this.notifySubscribers();\n });\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // V8-only stack APIs (Error.captureStackTrace / prepareStackTrace / CallSite)
18
+ // are typed as always-present by @types/node, but Firefox/Safari lack them at
19
+ // runtime — so the `typeof ... === "function"` check below is a real feature
20
+ // test, not a type-narrowing no-op.
21
+
22
+ // Non-V8 engines (Firefox/Safari) format frames as `name@file:line:column`.
23
+ // Anchored to end-of-line and excluding `@` from the captured group so a line
24
+ // it can't parse fails closed (undefined) instead of matching a partial
25
+ // location.
26
+ const LINE_LOCATION_REGEX = /@([^@]*):(\d+):(\d+)\s*$/u;
27
+ export function parseLineLocation(line) {
28
+ const match = LINE_LOCATION_REGEX.exec(line);
29
+ if (!match) {
30
+ return undefined;
31
+ }
32
+ return {
33
+ fileName: match[1],
34
+ line: Number(match[2]),
35
+ column: Number(match[3])
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Returns the caller's stack line, skipping V8's "Error" header if present.
41
+ * `framesBeforeCaller` = frames from the capture point to the caller.
42
+ */
43
+ export function locateCallerLine(stack, framesBeforeCaller) {
44
+ const lines = stack.split("\n");
45
+ const hasHeader = parseLineLocation(lines[0]) === undefined;
46
+ return lines[(hasHeader ? 1 : 0) + framesBeforeCaller];
47
+ }
48
+ function captureViaCallSites(captureStackTrace, boundaryFn) {
49
+ const originalPrepareStackTrace = Error.prepareStackTrace;
50
+ let callSites;
51
+ Error.prepareStackTrace = (_err, sites) => {
52
+ callSites = sites;
53
+ };
54
+ try {
55
+ const target = {};
56
+ captureStackTrace(target, boundaryFn);
57
+ // Accessing `.stack` forces the lazy formatter (our override above) to
58
+ // run, populating `callSites` before we restore the original.
59
+ void target.stack;
60
+ } finally {
61
+ Error.prepareStackTrace = originalPrepareStackTrace;
62
+ }
63
+ const site = callSites?.[0];
64
+ if (!site) {
65
+ return undefined;
66
+ }
67
+ const fileName = site.getFileName() ?? site.getEvalOrigin();
68
+ const line = site.getLineNumber();
69
+ if (fileName == null || line == null) {
70
+ return undefined;
71
+ }
72
+ // column is captured when present but never rendered (formatCallerLocation
73
+ // emits file:line), so a null column must not throw away a good file:line —
74
+ // some native/eval call sites report one.
75
+ const column = site.getColumnNumber();
76
+ return column == null ? {
77
+ fileName,
78
+ line
79
+ } : {
80
+ fileName,
81
+ line,
82
+ column
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Returns the location of whoever called `boundaryFn`. On V8 it elides
88
+ * `boundaryFn` by function identity (minification-proof); elsewhere it skips a
89
+ * fixed 2 frames, so `boundaryFn` must call this directly.
90
+ */
91
+ export function captureCallerLocation(boundaryFn) {
92
+ // Best-effort: this pokes host/engine internals and mutates a shared global.
93
+ // If it throws, the caller gets `undefined` instead of a thrown error.
94
+ try {
95
+ const captureStackTrace = Error.captureStackTrace;
96
+ if (typeof captureStackTrace === "function") {
97
+ return captureViaCallSites(captureStackTrace, boundaryFn);
98
+ }
99
+ const stack = new Error().stack;
100
+ if (!stack) {
101
+ return undefined;
102
+ }
103
+ const callerLine = locateCallerLine(stack, 2);
104
+ if (!callerLine) {
105
+ return undefined;
106
+ }
107
+ return parseLineLocation(callerLine);
108
+ } catch {
109
+ return undefined;
110
+ }
111
+ }
112
+ export function formatCallerLocation(location) {
113
+ if (!location) {
114
+ return undefined;
115
+ }
116
+ const shortName = location.fileName.split("/").pop() ?? location.fileName;
117
+ return `${shortName}:${location.line}`;
118
+ }
119
+ //# sourceMappingURL=callerLocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callerLocation.js","names":["LINE_LOCATION_REGEX","parseLineLocation","line","match","exec","undefined","fileName","Number","column","locateCallerLine","stack","framesBeforeCaller","lines","split","hasHeader","captureViaCallSites","captureStackTrace","boundaryFn","originalPrepareStackTrace","Error","prepareStackTrace","callSites","_err","sites","target","site","getFileName","getEvalOrigin","getLineNumber","getColumnNumber","captureCallerLocation","callerLine","formatCallerLocation","location","shortName","pop"],"sources":["callerLocation.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// V8-only stack APIs (Error.captureStackTrace / prepareStackTrace / CallSite)\n// are typed as always-present by @types/node, but Firefox/Safari lack them at\n// runtime — so the `typeof ... === \"function\"` check below is a real feature\n// test, not a type-narrowing no-op.\n\nexport interface CallerLocation {\n readonly fileName: string;\n readonly line: number;\n readonly column?: number;\n}\n\n// Non-V8 engines (Firefox/Safari) format frames as `name@file:line:column`.\n// Anchored to end-of-line and excluding `@` from the captured group so a line\n// it can't parse fails closed (undefined) instead of matching a partial\n// location.\nconst LINE_LOCATION_REGEX = /@([^@]*):(\\d+):(\\d+)\\s*$/u;\n\nexport function parseLineLocation(line: string): CallerLocation | undefined {\n const match = LINE_LOCATION_REGEX.exec(line);\n if (!match) {\n return undefined;\n }\n return {\n fileName: match[1],\n line: Number(match[2]),\n column: Number(match[3]),\n };\n}\n\n/**\n * Returns the caller's stack line, skipping V8's \"Error\" header if present.\n * `framesBeforeCaller` = frames from the capture point to the caller.\n */\nexport function locateCallerLine(\n stack: string,\n framesBeforeCaller: number\n): string | undefined {\n const lines = stack.split(\"\\n\");\n const hasHeader = parseLineLocation(lines[0]) === undefined;\n return lines[(hasHeader ? 1 : 0) + framesBeforeCaller];\n}\n\nfunction captureViaCallSites(\n captureStackTrace: typeof Error.captureStackTrace,\n boundaryFn: (...args: unknown[]) => unknown\n): CallerLocation | undefined {\n const originalPrepareStackTrace = Error.prepareStackTrace;\n let callSites: NodeJS.CallSite[] | undefined;\n Error.prepareStackTrace = (_err, sites) => {\n callSites = sites;\n };\n try {\n const target: { stack?: unknown } = {};\n captureStackTrace(target, boundaryFn);\n // Accessing `.stack` forces the lazy formatter (our override above) to\n // run, populating `callSites` before we restore the original.\n void target.stack;\n } finally {\n Error.prepareStackTrace = originalPrepareStackTrace;\n }\n\n const site = callSites?.[0];\n if (!site) {\n return undefined;\n }\n const fileName = site.getFileName() ?? site.getEvalOrigin();\n const line = site.getLineNumber();\n if (fileName == null || line == null) {\n return undefined;\n }\n // column is captured when present but never rendered (formatCallerLocation\n // emits file:line), so a null column must not throw away a good file:line —\n // some native/eval call sites report one.\n const column = site.getColumnNumber();\n return column == null ? { fileName, line } : { fileName, line, column };\n}\n\n/**\n * Returns the location of whoever called `boundaryFn`. On V8 it elides\n * `boundaryFn` by function identity (minification-proof); elsewhere it skips a\n * fixed 2 frames, so `boundaryFn` must call this directly.\n */\nexport function captureCallerLocation(\n boundaryFn: (...args: unknown[]) => unknown\n): CallerLocation | undefined {\n // Best-effort: this pokes host/engine internals and mutates a shared global.\n // If it throws, the caller gets `undefined` instead of a thrown error.\n try {\n const captureStackTrace = Error.captureStackTrace;\n if (typeof captureStackTrace === \"function\") {\n return captureViaCallSites(captureStackTrace, boundaryFn);\n }\n\n const stack = new Error().stack;\n if (!stack) {\n return undefined;\n }\n const callerLine = locateCallerLine(stack, 2);\n if (!callerLine) {\n return undefined;\n }\n return parseLineLocation(callerLine);\n } catch {\n return undefined;\n }\n}\n\nexport function formatCallerLocation(\n location: CallerLocation | undefined\n): string | undefined {\n if (!location) {\n return undefined;\n }\n const shortName = location.fileName.split(\"/\").pop() ?? location.fileName;\n return `${shortName}:${location.line}`;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"mappings":"AAiBA,SAAS,yBAAyB,wBAAyB;AAE3D,YAAY,kBAAkB,QAAQ,SAAS,UAAU,SAAS;AAUlE,iBAAiB,gBAAgB;UACtB;UACA,OAAO;UACP;UACA;UACA;AACV;AAyMD,OAAO,cAAM,wBAAwB,kBAAkB;CACrD,iBAAiB;CACjB,QAAQ;CACR,iBAAiB;CAIjB,iBAAiB;CAIjB,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CAER,YAAYA;CAKZ;CA2EA;CAkBA;CAIA;CAIA,uBAAuB;CAQvB;CAIA;CAMA;CAOA,QAAQ;AAUT","names":["capacity: number"],"sources":["../../../src/store/ConsoleLogStore.ts"],"version":3,"file":"ConsoleLogStore.d.ts"}
1
+ {"mappings":"AAqBA,SAAS,yBAAyB,wBAAyB;AAE3D,YAAY,kBAAkB,QAAQ,SAAS,UAAU,SAAS;AAUlE,iBAAiB,gBAAgB;UACtB;UACA,OAAO;UACP;UACA;UACA;AACV;AAiKD,OAAO,cAAM,wBAAwB,kBAAkB;CACrD,iBAAiB;CACjB,QAAQ;CACR,iBAAiB;CAIjB,iBAAiB;CAIjB,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CAER,YAAYA;CAKZ;CA6EA;CAkBA;CAIA;CAIA,uBAAuB;CAQvB;CAIA;CAMA;CAOA,QAAQ;AAUT","names":["capacity: number"],"sources":["../../../src/store/ConsoleLogStore.ts"],"version":3,"file":"ConsoleLogStore.d.ts"}
@@ -0,0 +1,18 @@
1
+ export interface CallerLocation {
2
+ readonly fileName: string;
3
+ readonly line: number;
4
+ readonly column?: number;
5
+ }
6
+ export declare function parseLineLocation(line: string): CallerLocation | undefined;
7
+ /**
8
+ * Returns the caller's stack line, skipping V8's "Error" header if present.
9
+ * `framesBeforeCaller` = frames from the capture point to the caller.
10
+ */
11
+ export declare function locateCallerLine(stack: string, framesBeforeCaller: number): string | undefined;
12
+ /**
13
+ * Returns the location of whoever called `boundaryFn`. On V8 it elides
14
+ * `boundaryFn` by function identity (minification-proof); elsewhere it skips a
15
+ * fixed 2 frames, so `boundaryFn` must call this directly.
16
+ */
17
+ export declare function captureCallerLocation(boundaryFn: (...args: unknown[]) => unknown): CallerLocation | undefined;
18
+ export declare function formatCallerLocation(location: CallerLocation | undefined): string | undefined;
@@ -0,0 +1 @@
1
+ {"mappings":"AAqBA,iBAAiB,eAAe;UACrB;UACA;UACA;AACV;AAQD,OAAO,iBAAS,kBAAkBA,eAAe;;;;;AAgBjD,OAAO,iBAAS,iBACdC,eACAC;;;;;;AA+CF,OAAO,iBAAS,sBACdC,aAAa,GAAG,8BACf;AAuBH,OAAO,iBAAS,qBACdC,UAAU","names":["line: string","stack: string","framesBeforeCaller: number","boundaryFn: (...args: unknown[]) => unknown","location: CallerLocation | undefined"],"sources":["../../../../src/utils/browser-compat/callerLocation.ts"],"version":3,"file":"callerLocation.d.ts"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osdk/react-devtools",
3
- "version": "0.15.0",
3
+ "version": "0.15.1-main-273cce9794f8fd17dc5becdff89fcc57a571f79d",
4
4
  "description": "Developer tools and debugging utilities for OSDK React Toolkit",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -73,11 +73,11 @@
73
73
  "typescript": "~5.5.4",
74
74
  "vite": "^6.3.5",
75
75
  "vitest": "^2.0.0",
76
- "@osdk/api": "2.45.0",
77
- "@osdk/client": "2.45.0",
78
- "@osdk/monorepo.tsconfig": "~0.7.0",
76
+ "@osdk/api": "2.46.0",
77
+ "@osdk/client": "2.46.0",
79
78
  "@osdk/monorepo.api-extractor": "~0.7.0",
80
- "@osdk/react": "2.45.0"
79
+ "@osdk/monorepo.tsconfig": "~0.7.0",
80
+ "@osdk/react": "2.46.0"
81
81
  },
82
82
  "publishConfig": {
83
83
  "access": "public"