@alreadyso/annotate 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -13,9 +13,7 @@ export function App() {
13
13
  <YourApp />
14
14
  <AlreadyAnnotate
15
15
  teamId="YOUR_TEAM_ID"
16
- teamSlug="your-team-slug"
17
- webAppUrl="http://localhost:3000"
18
- authToken="SUPABASE_ACCESS_TOKEN"
16
+ useCookies
19
17
  openOnSave
20
18
  />
21
19
  </>
@@ -25,7 +23,7 @@ export function App() {
25
23
 
26
24
  ## Overlay Helper
27
25
 
28
- If you want the component to fetch an auth token on mount, use `AlreadyAnnotateOverlay`:
26
+ If you want the component to fetch an auth token on mount, use `AlreadyAnnotateOverlay`. For same-origin apps you can also rely on cookies by passing `useCookies`.
29
27
 
30
28
  ```tsx
31
29
  import { AlreadyAnnotateOverlay } from "@alreadyso/annotate";
@@ -41,7 +39,6 @@ export function App() {
41
39
  <YourApp />
42
40
  <AlreadyAnnotateOverlay
43
41
  teamId="YOUR_TEAM_ID"
44
- teamSlug="your-team-slug"
45
42
  getAuthToken={getAuthToken}
46
43
  />
47
44
  </>
@@ -52,13 +49,12 @@ export function App() {
52
49
  ## Props
53
50
 
54
51
  - `teamId` (required): Team UUID for the session.
55
- - `teamSlug` (optional): Used to open the session in the web app after save.
56
- - `webAppUrl` (optional): Defaults to `http://localhost:3000`.
57
- - `authToken` (optional): Supabase access token for user auth.
52
+ - `webAppUrl` (optional): Base URL for the Already web app. Defaults to the current origin in the browser. Use this when embedding the annotator on a different domain.
53
+ - `authToken` (optional): Bearer token for user auth.
58
54
  - `apiKey` (optional): Agent API key (alternative to `authToken`).
59
55
  - `useCookies` (optional): Send cookies with requests (for same-origin use).
60
56
  - `defaultStatus` (optional): Session status to set after saving. Defaults to `todo`.
61
- - `openOnSave` (optional): Open the session after save if `teamSlug` is set. Defaults to `true`.
57
+ - `openOnSave` (optional): Open the session after save (redirects via `/t/by-id`). Defaults to `true`.
62
58
  - `blockInteractions` (optional): Prevent underlying clicks while annotating. Defaults to `true`.
63
59
  - `accentColor` (optional): Accent color for the overlay UI.
64
60
  - `sessionTitle` (optional): Override the session title.
@@ -18,7 +18,6 @@ export type Annotation = {
18
18
  };
19
19
  export type AlreadyAnnotateProps = {
20
20
  teamId: string;
21
- teamSlug?: string;
22
21
  webAppUrl?: string;
23
22
  authToken?: string;
24
23
  apiKey?: string;
@@ -30,4 +29,4 @@ export type AlreadyAnnotateProps = {
30
29
  sessionTitle?: string;
31
30
  onSaveComplete?: (sessionId: string) => void;
32
31
  };
33
- export declare function AlreadyAnnotate({ teamId, teamSlug, webAppUrl, authToken, apiKey, useCookies, defaultStatus, openOnSave, blockInteractions, accentColor, sessionTitle, onSaveComplete, }: AlreadyAnnotateProps): React.ReactPortal | null;
32
+ export declare function AlreadyAnnotate({ teamId, webAppUrl, authToken, apiKey, useCookies, defaultStatus, openOnSave, blockInteractions, accentColor, sessionTitle, onSaveComplete, }: AlreadyAnnotateProps): React.ReactPortal | null;
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
3
  import { createPortal } from "react-dom";
4
- const DEFAULT_WEB_URL = "http://localhost:3000";
5
4
  const DEFAULT_ACCENT = "#2563eb";
6
5
  function nowIso() {
7
6
  return new Date().toISOString();
@@ -136,7 +135,7 @@ function isIgnoredTarget(target) {
136
135
  return true;
137
136
  return false;
138
137
  }
139
- export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL, authToken, apiKey, useCookies = false, defaultStatus = "todo", openOnSave = true, blockInteractions = true, accentColor = DEFAULT_ACCENT, sessionTitle, onSaveComplete, }) {
138
+ export function AlreadyAnnotate({ teamId, webAppUrl, authToken, apiKey, useCookies = false, defaultStatus = "todo", openOnSave = true, blockInteractions = true, accentColor = DEFAULT_ACCENT, sessionTitle, onSaveComplete, }) {
140
139
  const [portalRoot, setPortalRoot] = useState(null);
141
140
  const [isActive, setIsActive] = useState(false);
142
141
  const [hoverRect, setHoverRect] = useState(null);
@@ -284,6 +283,18 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
284
283
  const handleDeleteAnnotation = useCallback((id) => {
285
284
  setAnnotations((prev) => prev.filter((item) => item.id !== id));
286
285
  }, []);
286
+ const resolvedWebAppUrl = useMemo(() => {
287
+ if (webAppUrl)
288
+ return webAppUrl.replace(/\/$/, "");
289
+ if (typeof window !== "undefined")
290
+ return window.location.origin;
291
+ return "";
292
+ }, [webAppUrl]);
293
+ const buildUrl = useCallback((path) => {
294
+ if (!resolvedWebAppUrl)
295
+ return path;
296
+ return `${resolvedWebAppUrl}${path.startsWith("/") ? "" : "/"}${path}`;
297
+ }, [resolvedWebAppUrl]);
287
298
  const buildHeaders = useCallback(() => {
288
299
  const headers = {
289
300
  "Content-Type": "application/json",
@@ -298,7 +309,7 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
298
309
  return headers;
299
310
  }, [apiKey, authToken, teamId]);
300
311
  const createSession = useCallback(async () => {
301
- const response = await fetch(`${webAppUrl}/api/sessions/start`, {
312
+ const response = await fetch(buildUrl("/api/sessions/start"), {
302
313
  method: "POST",
303
314
  headers: buildHeaders(),
304
315
  body: JSON.stringify({ title: pageTitle, source: "web" }),
@@ -312,11 +323,11 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
312
323
  throw new Error("Session creation succeeded but no session_id returned");
313
324
  }
314
325
  return payload.session_id;
315
- }, [buildHeaders, pageTitle, useCookies, webAppUrl]);
326
+ }, [buildHeaders, buildUrl, pageTitle, useCookies]);
316
327
  const updateSessionData = useCallback(async (sessionId) => {
317
328
  const notes = buildNotesDocument(annotations, pageTitle, pageUrl);
318
329
  const timeline = buildTimeline(annotations);
319
- const response = await fetch(`${webAppUrl}/api/sessions/${sessionId}/data`, {
330
+ const response = await fetch(buildUrl(`/api/sessions/${sessionId}/data`), {
320
331
  method: "PATCH",
321
332
  headers: buildHeaders(),
322
333
  body: JSON.stringify({
@@ -331,12 +342,12 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
331
342
  if (!response.ok) {
332
343
  throw new Error(payload.error || payload.message || `Failed to save session data (${response.status})`);
333
344
  }
334
- }, [annotations, buildHeaders, pageTitle, pageUrl, useCookies, webAppUrl]);
345
+ }, [annotations, buildHeaders, buildUrl, pageTitle, pageUrl, useCookies]);
335
346
  const updateSessionStatus = useCallback(async (sessionId) => {
336
347
  if (!defaultStatus || defaultStatus === "in_session" || defaultStatus === "uploading") {
337
348
  return;
338
349
  }
339
- const response = await fetch(`${webAppUrl}/api/sessions/${sessionId}`, {
350
+ const response = await fetch(buildUrl(`/api/sessions/${sessionId}`), {
340
351
  method: "PATCH",
341
352
  headers: buildHeaders(),
342
353
  body: JSON.stringify({ status: defaultStatus }),
@@ -346,7 +357,7 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
346
357
  if (!response.ok) {
347
358
  throw new Error(payload.error || payload.message || `Failed to update session status (${response.status})`);
348
359
  }
349
- }, [buildHeaders, defaultStatus, useCookies, webAppUrl]);
360
+ }, [buildHeaders, buildUrl, defaultStatus, useCookies]);
350
361
  const handleSaveToAlready = useCallback(async () => {
351
362
  if (annotations.length === 0) {
352
363
  setError("Add at least one annotation before saving.");
@@ -360,8 +371,9 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
360
371
  await updateSessionStatus(sessionId);
361
372
  setLastSessionId(sessionId);
362
373
  onSaveComplete?.(sessionId);
363
- if (openOnSave && teamSlug) {
364
- const url = `${webAppUrl}/t/${teamSlug}/sessions/${sessionId}`;
374
+ if (openOnSave) {
375
+ const target = `/t/by-id?teamId=${encodeURIComponent(teamId)}&sessionId=${encodeURIComponent(sessionId)}`;
376
+ const url = buildUrl(target);
365
377
  window.open(url, "_blank", "noopener,noreferrer");
366
378
  }
367
379
  }
@@ -372,7 +384,7 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
372
384
  finally {
373
385
  setSaving(false);
374
386
  }
375
- }, [annotations.length, createSession, onSaveComplete, openOnSave, teamSlug, updateSessionData, updateSessionStatus, webAppUrl]);
387
+ }, [annotations.length, buildUrl, createSession, onSaveComplete, openOnSave, updateSessionData, updateSessionStatus]);
376
388
  const panel = (_jsxs("div", { "data-already-annotate-ui": true, style: {
377
389
  position: "fixed",
378
390
  right: 16,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alreadyso/annotate",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Annotation overlay for creating Already sessions from React apps.",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {