@backmatter/core 0.0.32 → 0.0.33

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backmatter/core",
3
- "version": "0.0.32",
3
+ "version": "0.0.33",
4
4
  "description": "Experimental Backmatter SDK. APIs will break. Not ready for production.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -59,11 +59,17 @@ export type PreviewPointMessage = Envelope & {
59
59
 
60
60
  export type PreviewGrabMessage = Envelope & {
61
61
  type: "backmatter:grab";
62
- blockId: string;
62
+ /** Null when the click is not inside a page block. */
63
+ blockId: string | null;
63
64
  blockType: string | null;
64
65
  blockIndex: number | null;
65
66
  quote: string;
66
67
  shift: boolean;
68
+ component?: string;
69
+ file?: string;
70
+ line?: number;
71
+ column?: number;
72
+ stack?: string[];
67
73
  };
68
74
 
69
75
  export type PreviewHighlightMessage = Envelope & {
@@ -119,6 +125,37 @@ function readEnvelope(value: Record<string, unknown>): Envelope | null {
119
125
  return { v: PREVIEW_CHANNEL_VERSION, ref };
120
126
  }
121
127
 
128
+ const GRAB_FILE = /^[\w./@+-]+\.(?:tsx|ts|jsx|js|mdx)$/;
129
+
130
+ function readGrabPlace(data: Record<string, unknown>): Pick<
131
+ PreviewGrabMessage,
132
+ "component" | "file" | "line" | "column" | "stack"
133
+ > {
134
+ const component =
135
+ typeof data.component === "string" && data.component.length > 0 && data.component.length <= 80
136
+ ? data.component
137
+ : undefined;
138
+ const file =
139
+ typeof data.file === "string" && data.file.length <= 240 && GRAB_FILE.test(data.file) && !data.file.includes("..")
140
+ ? data.file
141
+ : undefined;
142
+ const line = typeof data.line === "number" && Number.isInteger(data.line) && data.line > 0 ? data.line : undefined;
143
+ const column =
144
+ typeof data.column === "number" && Number.isInteger(data.column) && data.column > 0 ? data.column : undefined;
145
+ const stack = Array.isArray(data.stack)
146
+ ? data.stack
147
+ .filter((item): item is string => typeof item === "string" && item.length > 0 && item.length <= 80)
148
+ .slice(0, 4)
149
+ : [];
150
+ return {
151
+ ...(component ? { component } : {}),
152
+ ...(file ? { file } : {}),
153
+ ...(line ? { line } : {}),
154
+ ...(column ? { column } : {}),
155
+ ...(stack.length > 0 ? { stack } : {}),
156
+ };
157
+ }
158
+
122
159
  /** Parse a channel payload. Legacy hotkey messages (no `v`) still parse. */
123
160
  export function parsePreviewMessage(data: unknown): PreviewChannelMessage | null {
124
161
  const hotkey = parsePreviewHotkey(data);
@@ -167,7 +204,8 @@ export function parsePreviewMessage(data: unknown): PreviewChannelMessage | null
167
204
  return { type: "backmatter:point", ...envelope, on: data.on };
168
205
  }
169
206
  case "backmatter:grab": {
170
- if (typeof data.blockId !== "string" || data.blockId.length === 0) return null;
207
+ const blockId = data.blockId === null ? null : typeof data.blockId === "string" ? data.blockId : undefined;
208
+ if (blockId === undefined || blockId === "") return null;
171
209
  if (data.blockType !== null && typeof data.blockType !== "string") return null;
172
210
  if (
173
211
  data.blockIndex !== null &&
@@ -176,14 +214,17 @@ export function parsePreviewMessage(data: unknown): PreviewChannelMessage | null
176
214
  return null;
177
215
  }
178
216
  if (typeof data.quote !== "string" || typeof data.shift !== "boolean") return null;
217
+ const place = readGrabPlace(data);
218
+ if (blockId === null && !normalizePointerQuote(data.quote) && !place.component && !place.file) return null;
179
219
  return {
180
220
  type: "backmatter:grab",
181
221
  ...envelope,
182
- blockId: data.blockId,
222
+ blockId,
183
223
  blockType: data.blockType,
184
224
  blockIndex: data.blockIndex,
185
225
  quote: normalizePointerQuote(data.quote),
186
226
  shift: data.shift,
227
+ ...place,
187
228
  };
188
229
  }
189
230
  case "backmatter:highlight": {