@sylergydigital/issue-pin-sdk 0.6.2 → 0.6.3

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/dist/index.d.cts CHANGED
@@ -279,4 +279,16 @@ declare const Z: {
279
279
  readonly flash: 99998;
280
280
  };
281
281
 
282
- export { type AnchorResolution, type AnnotationSurface, IssuePin as ElementWhisperer, FeedbackButton, type FeedbackMode, FeedbackOverlay, FeedbackProvider, IssuePin, type LauncherRenderProps, type ModalCaptureRenderProps, type PendingPin, type PendingScreenshotPin, ReviewSurfaceOverlay, ScreenshotFeedback, type ScrollContainerBinding, SdkCommentPopover, type ThreadData, ThreadPins, Z, useFeedback, useFeedbackSafe, useIssuePinAnchor };
282
+ /** Convert any string user ID to a valid UUID. Already-valid UUIDs pass through unchanged. */
283
+ declare function normalizeUserId(userId: string): string;
284
+
285
+ /** CSP directives required by the IssuePin SDK.
286
+ * Keyed by CSP directive name, values are source expressions to allow.
287
+ * Use wildcards (*.supabase.co) for zero-config — narrow to your project URL in production if preferred. */
288
+ declare const CSP_REQUIREMENTS: {
289
+ readonly "connect-src": readonly ["https://*.supabase.co", "wss://*.supabase.co"];
290
+ readonly "img-src": readonly ["data:", "blob:"];
291
+ readonly "style-src": readonly ["'unsafe-inline'"];
292
+ };
293
+
294
+ export { type AnchorResolution, type AnnotationSurface, CSP_REQUIREMENTS, IssuePin as ElementWhisperer, FeedbackButton, type FeedbackMode, FeedbackOverlay, FeedbackProvider, IssuePin, type LauncherRenderProps, type ModalCaptureRenderProps, type PendingPin, type PendingScreenshotPin, ReviewSurfaceOverlay, ScreenshotFeedback, type ScrollContainerBinding, SdkCommentPopover, type ThreadData, ThreadPins, Z, normalizeUserId, useFeedback, useFeedbackSafe, useIssuePinAnchor };
package/dist/index.d.ts CHANGED
@@ -279,4 +279,16 @@ declare const Z: {
279
279
  readonly flash: 99998;
280
280
  };
281
281
 
282
- export { type AnchorResolution, type AnnotationSurface, IssuePin as ElementWhisperer, FeedbackButton, type FeedbackMode, FeedbackOverlay, FeedbackProvider, IssuePin, type LauncherRenderProps, type ModalCaptureRenderProps, type PendingPin, type PendingScreenshotPin, ReviewSurfaceOverlay, ScreenshotFeedback, type ScrollContainerBinding, SdkCommentPopover, type ThreadData, ThreadPins, Z, useFeedback, useFeedbackSafe, useIssuePinAnchor };
282
+ /** Convert any string user ID to a valid UUID. Already-valid UUIDs pass through unchanged. */
283
+ declare function normalizeUserId(userId: string): string;
284
+
285
+ /** CSP directives required by the IssuePin SDK.
286
+ * Keyed by CSP directive name, values are source expressions to allow.
287
+ * Use wildcards (*.supabase.co) for zero-config — narrow to your project URL in production if preferred. */
288
+ declare const CSP_REQUIREMENTS: {
289
+ readonly "connect-src": readonly ["https://*.supabase.co", "wss://*.supabase.co"];
290
+ readonly "img-src": readonly ["data:", "blob:"];
291
+ readonly "style-src": readonly ["'unsafe-inline'"];
292
+ };
293
+
294
+ export { type AnchorResolution, type AnnotationSurface, CSP_REQUIREMENTS, IssuePin as ElementWhisperer, FeedbackButton, type FeedbackMode, FeedbackOverlay, FeedbackProvider, IssuePin, type LauncherRenderProps, type ModalCaptureRenderProps, type PendingPin, type PendingScreenshotPin, ReviewSurfaceOverlay, ScreenshotFeedback, type ScrollContainerBinding, SdkCommentPopover, type ThreadData, ThreadPins, Z, normalizeUserId, useFeedback, useFeedbackSafe, useIssuePinAnchor };
package/dist/index.js CHANGED
@@ -77,6 +77,51 @@ var T = {
77
77
  ring: "#6366f1"
78
78
  };
79
79
 
80
+ // src/uuid.ts
81
+ import { v5 as uuidv5 } from "uuid";
82
+ var NAMESPACE = "8920e263-ef53-4df0-8108-968cd5d8939e";
83
+ var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
84
+ function normalizeUserId(userId) {
85
+ if (UUID_SHAPE.test(userId)) return userId;
86
+ return uuidv5(userId, NAMESPACE);
87
+ }
88
+
89
+ // src/csp.ts
90
+ var CSP_REQUIREMENTS = {
91
+ "connect-src": ["https://*.supabase.co", "wss://*.supabase.co"],
92
+ "img-src": ["data:", "blob:"],
93
+ "style-src": ["'unsafe-inline'"]
94
+ };
95
+ var warnedDirectives = /* @__PURE__ */ new Set();
96
+ function isIssuePinViolation(event) {
97
+ const blocked = event.blockedURI;
98
+ const directive = event.violatedDirective;
99
+ if (directive.startsWith("connect-src") && blocked.includes("supabase.co")) return true;
100
+ if (directive.startsWith("img-src") && (blocked === "data" || blocked === "blob")) return true;
101
+ if (directive.startsWith("style-src") && (blocked === "inline" || blocked === "'unsafe-inline'")) return true;
102
+ return false;
103
+ }
104
+ function handleViolation(event) {
105
+ if (!isIssuePinViolation(event)) return;
106
+ const directive = event.violatedDirective.split(" ")[0];
107
+ if (warnedDirectives.has(directive)) return;
108
+ warnedDirectives.add(directive);
109
+ const sources = CSP_REQUIREMENTS[directive];
110
+ const fix = sources ? sources.join(" ") : event.blockedURI;
111
+ console.warn(
112
+ `[IssuePin] CSP violation: ${directive} blocked "${event.blockedURI}". Add to your Content-Security-Policy: ${directive} ${fix}`
113
+ );
114
+ }
115
+ function subscribeCspDetection() {
116
+ if (typeof document === "undefined") return () => {
117
+ };
118
+ const handler = (e) => handleViolation(e);
119
+ document.addEventListener("securitypolicyviolation", handler);
120
+ return () => {
121
+ document.removeEventListener("securitypolicyviolation", handler);
122
+ };
123
+ }
124
+
80
125
  // src/FeedbackProvider.tsx
81
126
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
82
127
  var FeedbackContext = createContext(null);
@@ -128,11 +173,11 @@ function setThreadsSchemaMode(workspaceId, mode) {
128
173
  threadsSchemaModeByWorkspace.set(workspaceId, mode);
129
174
  }
130
175
  function resolveIssuePinActorUserId(opts) {
131
- if (opts.explicitUserId) return opts.explicitUserId;
176
+ if (opts.explicitUserId) return normalizeUserId(opts.explicitUserId);
132
177
  if (opts.hasApiKey && !opts.skipFederation && opts.autoIdentityUserId) {
133
178
  return opts.federatedLocalUserId;
134
179
  }
135
- return opts.autoIdentityUserId;
180
+ return opts.autoIdentityUserId ? normalizeUserId(opts.autoIdentityUserId) : opts.autoIdentityUserId;
136
181
  }
137
182
  function resolveIssuePinActorReady(opts) {
138
183
  if (!opts.authReady) return false;
@@ -369,6 +414,10 @@ function FeedbackProvider({
369
414
  hasApiKey: !!config.apiKey,
370
415
  skipFederation: config.skipFederation
371
416
  });
417
+ const rawUserId = config.userId ?? autoIdentity.userId;
418
+ if (config.debug && rawUserId && effectiveUserId && rawUserId !== effectiveUserId) {
419
+ console.log(`[EW SDK] User ID normalized: "${rawUserId}" -> "${effectiveUserId}"`);
420
+ }
372
421
  const actorReady = resolveIssuePinActorReady({
373
422
  authReady,
374
423
  explicitUserId: config.userId,
@@ -453,12 +502,13 @@ function FeedbackProviderInner({
453
502
  console.log(`[EW SDK] ${message}`, extra);
454
503
  }, [debug]);
455
504
  useEffect(() => {
505
+ if (!authReady) return;
456
506
  if (!userDisplayName && !userEmail) {
457
507
  console.warn(
458
508
  '[IssuePin] No user identity provided \u2014 comments will appear as "Unknown". Pass supabaseClient={supabase} for automatic identity, or user={{ email, displayName }} for manual attribution. See https://github.com/sylergydigital/issue-pin/blob/main/sdk/README.md#user-identity-avoiding-unknown-comments'
459
509
  );
460
510
  }
461
- }, []);
511
+ }, [authReady, userDisplayName, userEmail]);
462
512
  const client = useMemo(() => {
463
513
  try {
464
514
  return createClient(supabaseUrl, supabaseAnonKey, {
@@ -565,6 +615,10 @@ function FeedbackProviderInner({
565
615
  debugLog("FeedbackProvider unmounted", { workspaceId, path: pathname });
566
616
  };
567
617
  }, [debugLog, workspaceId, pathname]);
618
+ useEffect(() => {
619
+ const unsubscribe = subscribeCspDetection();
620
+ return unsubscribe;
621
+ }, []);
568
622
  useEffect(() => {
569
623
  debugLog("mode / feedbackActive", { mode, feedbackActive });
570
624
  }, [debugLog, mode, feedbackActive]);
@@ -2434,6 +2488,7 @@ function PinsSlot() {
2434
2488
  return /* @__PURE__ */ jsx9(ThreadPins, {});
2435
2489
  }
2436
2490
  export {
2491
+ CSP_REQUIREMENTS,
2437
2492
  IssuePin as ElementWhisperer,
2438
2493
  FeedbackButton,
2439
2494
  FeedbackOverlay,
@@ -2444,6 +2499,7 @@ export {
2444
2499
  SdkCommentPopover,
2445
2500
  ThreadPins,
2446
2501
  Z,
2502
+ normalizeUserId,
2447
2503
  useFeedback,
2448
2504
  useFeedbackSafe,
2449
2505
  useIssuePinAnchor