@sylergydigital/issue-pin-sdk 0.6.2 → 0.6.4

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 ADDED
@@ -0,0 +1,228 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@sylergydigital/issue-pin-sdk` are documented here.
4
+
5
+ ## [0.6.3] - 2026-04-14
6
+
7
+ ### Added
8
+ - **UUID normalization for non-UUID auth providers** — SDK auto-converts Firebase, Auth0, Cognito, and other non-UUID user IDs to deterministic UUID v5 format at the SDK boundary. Existing UUID-format IDs pass through unchanged.
9
+ - `normalizeUserId()` / `toSupabaseUuid()` — public utility export for converting user IDs outside the SDK component lifecycle.
10
+ - `CSP_REQUIREMENTS` — typed constant exporting all Content Security Policy directives required by the SDK (`connect-src`, `img-src`, `style-src`), usable in server middleware or build-time CSP generation.
11
+ - Runtime CSP violation detection — `subscribeCspDetection()` automatically activates on SDK mount and logs actionable `[IssuePin]` console warnings when CSP blocks SDK functionality. Per-directive deduplication prevents warning spam.
12
+ - CSP documentation section in SDK README with copy-paste directive block, per-directive explanation table, and programmatic access example.
13
+ - Debug logging for ID conversions — when `debug={true}`, logs `[EW SDK] User ID normalized: "{raw}" -> "{effective}"` for converted IDs.
14
+
15
+ ### Fixed
16
+ - Stale closure in identity warning gated on `authReady` state.
17
+ - Missing SSR guard in `subscribeCspDetection` (safe for server-side rendering).
18
+
19
+ ### Dependencies
20
+ - Added `uuid@^11.0.3` as bundled dependency (CommonJS-compatible).
21
+
22
+ ## [0.6.2] - 2026-04-02
23
+
24
+ ### Fixed
25
+ - Replaced `html2canvas` with `html2canvas-pro` to support modern CSS features like `oklab` color space.
26
+
27
+ ## [0.6.1] - 2026-03-24
28
+
29
+ ### Changed
30
+ - Set up public SDK mirror and npm release pipeline.
31
+
32
+ ## [0.6.0] - 2026-03-24
33
+
34
+ ### Changed
35
+ - Set up public SDK mirror and npm release pipeline.
36
+
37
+ ## [0.5.9] - 2026-03-24
38
+
39
+ ### Changed
40
+ - Public SDK mirror and npm registry setup.
41
+
42
+ ## [0.5.8] - 2026-03-23
43
+
44
+ ### Added
45
+ - `showHints` toggle for instructional UI hints in the SDK.
46
+
47
+ ## [0.5.7] - 2026-03-23
48
+
49
+ ### Added
50
+ - Verified LMS federation rollout (patch).
51
+
52
+ ## [0.5.6] - 2026-03-23
53
+
54
+ ### Added
55
+ - LMS federation rollout with verification.
56
+
57
+ ## [0.5.5] - 2026-03-22
58
+
59
+ ### Fixed
60
+ - SDK build and packaging fixes.
61
+
62
+ ## [0.5.4] - 2026-03-22
63
+
64
+ ### Fixed
65
+ - SDK build and packaging fixes.
66
+
67
+ ## [0.5.3] - 2026-03-22
68
+
69
+ ### Changed
70
+ - Aligned SDK docs and package metadata with router-free integration.
71
+
72
+ ## [0.5.2] - 2026-03-22
73
+
74
+ ### Added
75
+ - Iframe review mode for SDK pins (canvas review surface).
76
+
77
+ ## [0.5.1] - 2026-03-22
78
+
79
+ ### Added
80
+ - Anonymous screenshot reads for SDK workspaces via Supabase RLS.
81
+ - ThreadPins test coverage.
82
+ - npm registry publishing.
83
+
84
+ ## [0.5.0] - 2026-03-22
85
+
86
+ ### Changed
87
+ - npm versioning aligned with git tags.
88
+
89
+ ## [0.4.9] - 2026-03-22
90
+
91
+ ### Changed
92
+ - Vite host allowlist and gitignore for local tooling.
93
+
94
+ ## [0.4.8] - 2026-03-17
95
+
96
+ ### Added
97
+ - SDK customization APIs for launcher visibility and pin visibility control.
98
+
99
+ ## [0.4.7] - 2026-03-17
100
+
101
+ ### Fixed
102
+ - SDK publish build for controlled pin mode.
103
+
104
+ ## [0.4.6] - 2026-03-17
105
+
106
+ ### Changed
107
+ - Thread pins open in a new tab.
108
+
109
+ ## [0.4.5] - 2026-03-17
110
+
111
+ ### Changed
112
+ - Rewrote SDK pin positioning lifecycle for stability.
113
+
114
+ ## [0.4.4] - 2026-03-17
115
+
116
+ ### Fixed
117
+ - Stabilized SDK pin rehydration observer.
118
+
119
+ ## [0.4.3] - 2026-03-17
120
+
121
+ ### Changed
122
+ - Allow anonymous `sdk-resolve` calls.
123
+
124
+ ## [0.4.2] - 2026-03-17
125
+
126
+ ### Changed
127
+ - Allow commenter workspace memberships.
128
+
129
+ ## [0.4.1] - 2026-03-17
130
+
131
+ ### Added
132
+ - Documentation for federated first-write gating.
133
+
134
+ ## [0.4.0] - 2026-03-17
135
+
136
+ ### Fixed
137
+ - Federated SDK author attribution.
138
+
139
+ ## [0.3.4] - 2026-03-16
140
+
141
+ ### Added
142
+ - Anonymous update RLS policy.
143
+
144
+ ## [0.3.3] - 2026-03-16
145
+
146
+ ### Changed
147
+ - Enabled React Router v7 future flag.
148
+
149
+ ## [0.3.2] - 2026-03-16
150
+
151
+ ### Changed
152
+ - Relaxed thread comments foreign key constraint.
153
+
154
+ ## [0.3.1] - 2026-03-16
155
+
156
+ ### Added
157
+ - RLS policies for anonymous inserts.
158
+
159
+ ## [0.3.0] - 2026-03-16
160
+
161
+ ### Fixed
162
+ - SDK feedback launcher click behavior.
163
+
164
+ ## [0.2.9] - 2026-03-16
165
+
166
+ ### Added
167
+ - Hardcoded SDK theme for consistent styling.
168
+
169
+ ## [0.2.8] - 2026-03-16
170
+
171
+ ### Fixed
172
+ - FeedbackButton `.d.ts` build ordering.
173
+
174
+ ## [0.2.7] - 2026-03-16
175
+
176
+ ### Added
177
+ - Debug logging for SDK menu state.
178
+
179
+ ### Fixed
180
+ - SDK menu state management hardened.
181
+
182
+ ## [0.2.6] - 2026-03-16
183
+
184
+ ### Fixed
185
+ - SDK feedback launcher click handling.
186
+
187
+ ## [0.2.5] - 2026-03-16
188
+
189
+ ### Fixed
190
+ - FeedbackButton interaction reliability.
191
+
192
+ ## [0.2.4] - 2026-03-16
193
+
194
+ ### Fixed
195
+ - Stabilized `getSignedUrlRef` for screenshot storage.
196
+
197
+ ## [0.2.3] - 2026-03-16
198
+
199
+ ### Added
200
+ - Error boundary wrapping for ThreadPins.
201
+
202
+ ## [0.2.0] - 2026-03-16
203
+
204
+ ### Changed
205
+ - Renamed SDK package to `@sylergydigital/issue-pin-sdk`.
206
+
207
+ ## [0.1.8] - 2026-03-16
208
+
209
+ ### Fixed
210
+ - TS2722 error in ScreenshotFeedback component.
211
+
212
+ ## [0.1.6] - 2026-03-16
213
+
214
+ ### Fixed
215
+ - Viewport auto-screenshot capture.
216
+
217
+ ## [0.1.5] - 2026-03-16
218
+
219
+ ### Fixed
220
+ - Auto-screenshot fetch reliability.
221
+
222
+ ## [0.1.0] - 2026-03-16
223
+
224
+ ### Added
225
+ - Initial SDK release as `@sylergydigital/issue-pin-sdk`.
226
+ - `<IssuePin />` drop-in component with pin annotations, screenshot capture, and threaded discussions.
227
+ - Supabase-backed real-time data layer.
228
+ - Federated user identity for SDK consumers.
package/README.md CHANGED
@@ -356,6 +356,54 @@ For bulk provisioning or non-Supabase apps, use the `federate-user` edge functio
356
356
 
357
357
  The API key is a **publishable key** — safe to include in client-side code. It only grants scoped access to create threads and comments for the associated workspace, enforced server-side via Row Level Security.
358
358
 
359
+ ## Content Security Policy (CSP)
360
+
361
+ If your app sets a Content Security Policy header, add these directives so the IssuePin SDK can connect to Supabase, render screenshot previews, and apply inline styles:
362
+
363
+ ```
364
+ connect-src https://*.supabase.co wss://*.supabase.co;
365
+ img-src data: blob:;
366
+ style-src 'unsafe-inline';
367
+ ```
368
+
369
+ Merge these with your existing CSP directives — for example, if you already have `connect-src 'self'`, change it to `connect-src 'self' https://*.supabase.co wss://*.supabase.co;`.
370
+
371
+ > **Narrower alternative:** Replace `*.supabase.co` with your project's specific URL (e.g. `https://abcdef.supabase.co`) for a tighter policy.
372
+
373
+ ### Why each directive is needed
374
+
375
+ | Directive | Sources | Reason |
376
+ |-----------|---------|--------|
377
+ | `connect-src` | `https://*.supabase.co` | REST API calls to read/write threads and comments |
378
+ | `connect-src` | `wss://*.supabase.co` | WebSocket connections for real-time thread updates |
379
+ | `img-src` | `data:` `blob:` | Screenshot preview thumbnails rendered as data URIs and blob URLs |
380
+ | `style-src` | `'unsafe-inline'` | html2canvas-pro injects inline styles during screenshot capture |
381
+
382
+ ### Programmatic access
383
+
384
+ The SDK exports a typed constant for use in server-side middleware or build-time CSP generation:
385
+
386
+ ```typescript
387
+ import { CSP_REQUIREMENTS } from "@sylergydigital/issue-pin-sdk";
388
+
389
+ // CSP_REQUIREMENTS = {
390
+ // "connect-src": ["https://*.supabase.co", "wss://*.supabase.co"],
391
+ // "img-src": ["data:", "blob:"],
392
+ // "style-src": ["'unsafe-inline'"],
393
+ // }
394
+ ```
395
+
396
+ ### Runtime detection
397
+
398
+ When a CSP policy blocks an SDK operation, the browser console shows a warning like:
399
+
400
+ ```
401
+ [IssuePin] CSP violation: connect-src blocked "https://abc.supabase.co/rest/v1/threads".
402
+ Add to your Content-Security-Policy: connect-src https://*.supabase.co wss://*.supabase.co
403
+ ```
404
+
405
+ These warnings appear automatically — no `debug` flag needed.
406
+
359
407
  ## AI Agent Prompt
360
408
 
361
409
  Paste this into **Claude Code**, **Cursor**, or **Codex** to integrate the SDK automatically:
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ CSP_REQUIREMENTS: () => CSP_REQUIREMENTS,
33
34
  ElementWhisperer: () => IssuePin,
34
35
  FeedbackButton: () => FeedbackButton,
35
36
  FeedbackOverlay: () => FeedbackOverlay,
@@ -40,6 +41,7 @@ __export(index_exports, {
40
41
  SdkCommentPopover: () => SdkCommentPopover,
41
42
  ThreadPins: () => ThreadPins,
42
43
  Z: () => Z,
44
+ normalizeUserId: () => normalizeUserId,
43
45
  useFeedback: () => useFeedback,
44
46
  useFeedbackSafe: () => useFeedbackSafe,
45
47
  useIssuePinAnchor: () => useIssuePinAnchor
@@ -125,6 +127,51 @@ var T = {
125
127
  ring: "#6366f1"
126
128
  };
127
129
 
130
+ // src/uuid.ts
131
+ var import_uuid = require("uuid");
132
+ var NAMESPACE = "8920e263-ef53-4df0-8108-968cd5d8939e";
133
+ var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
134
+ function normalizeUserId(userId) {
135
+ if (UUID_SHAPE.test(userId)) return userId;
136
+ return (0, import_uuid.v5)(userId, NAMESPACE);
137
+ }
138
+
139
+ // src/csp.ts
140
+ var CSP_REQUIREMENTS = {
141
+ "connect-src": ["https://*.supabase.co", "wss://*.supabase.co"],
142
+ "img-src": ["data:", "blob:"],
143
+ "style-src": ["'unsafe-inline'"]
144
+ };
145
+ var warnedDirectives = /* @__PURE__ */ new Set();
146
+ function isIssuePinViolation(event) {
147
+ const blocked = event.blockedURI;
148
+ const directive = event.violatedDirective;
149
+ if (directive.startsWith("connect-src") && blocked.includes("supabase.co")) return true;
150
+ if (directive.startsWith("img-src") && (blocked === "data" || blocked === "blob")) return true;
151
+ if (directive.startsWith("style-src") && (blocked === "inline" || blocked === "'unsafe-inline'")) return true;
152
+ return false;
153
+ }
154
+ function handleViolation(event) {
155
+ if (!isIssuePinViolation(event)) return;
156
+ const directive = event.violatedDirective.split(" ")[0];
157
+ if (warnedDirectives.has(directive)) return;
158
+ warnedDirectives.add(directive);
159
+ const sources = CSP_REQUIREMENTS[directive];
160
+ const fix = sources ? sources.join(" ") : event.blockedURI;
161
+ console.warn(
162
+ `[IssuePin] CSP violation: ${directive} blocked "${event.blockedURI}". Add to your Content-Security-Policy: ${directive} ${fix}`
163
+ );
164
+ }
165
+ function subscribeCspDetection() {
166
+ if (typeof document === "undefined") return () => {
167
+ };
168
+ const handler = (e) => handleViolation(e);
169
+ document.addEventListener("securitypolicyviolation", handler);
170
+ return () => {
171
+ document.removeEventListener("securitypolicyviolation", handler);
172
+ };
173
+ }
174
+
128
175
  // src/FeedbackProvider.tsx
129
176
  var import_jsx_runtime = require("react/jsx-runtime");
130
177
  var FeedbackContext = (0, import_react2.createContext)(null);
@@ -176,11 +223,11 @@ function setThreadsSchemaMode(workspaceId, mode) {
176
223
  threadsSchemaModeByWorkspace.set(workspaceId, mode);
177
224
  }
178
225
  function resolveIssuePinActorUserId(opts) {
179
- if (opts.explicitUserId) return opts.explicitUserId;
226
+ if (opts.explicitUserId) return normalizeUserId(opts.explicitUserId);
180
227
  if (opts.hasApiKey && !opts.skipFederation && opts.autoIdentityUserId) {
181
228
  return opts.federatedLocalUserId;
182
229
  }
183
- return opts.autoIdentityUserId;
230
+ return opts.autoIdentityUserId ? normalizeUserId(opts.autoIdentityUserId) : opts.autoIdentityUserId;
184
231
  }
185
232
  function resolveIssuePinActorReady(opts) {
186
233
  if (!opts.authReady) return false;
@@ -417,6 +464,10 @@ function FeedbackProvider({
417
464
  hasApiKey: !!config.apiKey,
418
465
  skipFederation: config.skipFederation
419
466
  });
467
+ const rawUserId = config.userId ?? autoIdentity.userId;
468
+ if (config.debug && rawUserId && effectiveUserId && rawUserId !== effectiveUserId) {
469
+ console.log(`[EW SDK] User ID normalized: "${rawUserId}" -> "${effectiveUserId}"`);
470
+ }
420
471
  const actorReady = resolveIssuePinActorReady({
421
472
  authReady,
422
473
  explicitUserId: config.userId,
@@ -501,12 +552,13 @@ function FeedbackProviderInner({
501
552
  console.log(`[EW SDK] ${message}`, extra);
502
553
  }, [debug]);
503
554
  (0, import_react2.useEffect)(() => {
555
+ if (!authReady) return;
504
556
  if (!userDisplayName && !userEmail) {
505
557
  console.warn(
506
558
  '[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'
507
559
  );
508
560
  }
509
- }, []);
561
+ }, [authReady, userDisplayName, userEmail]);
510
562
  const client = (0, import_react2.useMemo)(() => {
511
563
  try {
512
564
  return (0, import_supabase_js.createClient)(supabaseUrl, supabaseAnonKey, {
@@ -613,6 +665,10 @@ function FeedbackProviderInner({
613
665
  debugLog("FeedbackProvider unmounted", { workspaceId, path: pathname });
614
666
  };
615
667
  }, [debugLog, workspaceId, pathname]);
668
+ (0, import_react2.useEffect)(() => {
669
+ const unsubscribe = subscribeCspDetection();
670
+ return unsubscribe;
671
+ }, []);
616
672
  (0, import_react2.useEffect)(() => {
617
673
  debugLog("mode / feedbackActive", { mode, feedbackActive });
618
674
  }, [debugLog, mode, feedbackActive]);
@@ -2483,6 +2539,7 @@ function PinsSlot() {
2483
2539
  }
2484
2540
  // Annotate the CommonJS export names for ESM import in node:
2485
2541
  0 && (module.exports = {
2542
+ CSP_REQUIREMENTS,
2486
2543
  ElementWhisperer,
2487
2544
  FeedbackButton,
2488
2545
  FeedbackOverlay,
@@ -2493,6 +2550,7 @@ function PinsSlot() {
2493
2550
  SdkCommentPopover,
2494
2551
  ThreadPins,
2495
2552
  Z,
2553
+ normalizeUserId,
2496
2554
  useFeedback,
2497
2555
  useFeedbackSafe,
2498
2556
  useIssuePinAnchor