@hiver/connector-agent 4.21.2 → 4.22.0-slackM2-beta.0

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.
Files changed (66) hide show
  1. package/app/hig-slack/HigSlackSection.d.ts +3 -0
  2. package/app/hig-slack/HigSlackSection.d.ts.map +1 -1
  3. package/constants/tracking-events.d.ts +4 -0
  4. package/constants/tracking-events.d.ts.map +1 -1
  5. package/features/slack/api/__tests__/errors.test.d.ts +2 -0
  6. package/features/slack/api/__tests__/errors.test.d.ts.map +1 -0
  7. package/features/slack/api/__tests__/links.test.d.ts +2 -0
  8. package/features/slack/api/__tests__/links.test.d.ts.map +1 -0
  9. package/features/slack/api/conversations.d.ts +6 -2
  10. package/features/slack/api/conversations.d.ts.map +1 -1
  11. package/features/slack/api/errors.d.ts +37 -0
  12. package/features/slack/api/errors.d.ts.map +1 -0
  13. package/features/slack/api/index.d.ts +2 -0
  14. package/features/slack/api/index.d.ts.map +1 -1
  15. package/features/slack/api/linked-conv.d.ts +11 -2
  16. package/features/slack/api/linked-conv.d.ts.map +1 -1
  17. package/features/slack/api/links.d.ts +90 -0
  18. package/features/slack/api/links.d.ts.map +1 -0
  19. package/features/slack/api/members.d.ts +2 -2
  20. package/features/slack/api/members.d.ts.map +1 -1
  21. package/features/slack/api/messages.d.ts +1 -1
  22. package/features/slack/api/messages.d.ts.map +1 -1
  23. package/features/slack/components/LinkExistingModal/index.d.ts +29 -0
  24. package/features/slack/components/LinkExistingModal/index.d.ts.map +1 -0
  25. package/features/slack/components/LinkedConversationPanel/Composer.d.ts.map +1 -1
  26. package/features/slack/components/LinkedConversationPanel/LinkedChannelHeader.d.ts +10 -3
  27. package/features/slack/components/LinkedConversationPanel/LinkedChannelHeader.d.ts.map +1 -1
  28. package/features/slack/components/LinkedConversationPanel/MessageItem.d.ts.map +1 -1
  29. package/features/slack/components/LinkedConversationPanel/ThreadDetailView.d.ts.map +1 -1
  30. package/features/slack/components/LinkedConversationPanel/index.d.ts +18 -1
  31. package/features/slack/components/LinkedConversationPanel/index.d.ts.map +1 -1
  32. package/features/slack/components/SlackConversationTab.d.ts.map +1 -1
  33. package/features/slack/components/SlackLinkList.d.ts +23 -0
  34. package/features/slack/components/SlackLinkList.d.ts.map +1 -0
  35. package/features/slack/components/StartModal/index.d.ts +8 -2
  36. package/features/slack/components/StartModal/index.d.ts.map +1 -1
  37. package/features/slack/constants/api.d.ts +6 -0
  38. package/features/slack/constants/api.d.ts.map +1 -1
  39. package/features/slack/context.d.ts +18 -0
  40. package/features/slack/context.d.ts.map +1 -1
  41. package/features/slack/hooks/__tests__/useMarkLinkRead.test.d.ts +2 -0
  42. package/features/slack/hooks/__tests__/useMarkLinkRead.test.d.ts.map +1 -0
  43. package/features/slack/hooks/useMarkLinkRead.d.ts +33 -0
  44. package/features/slack/hooks/useMarkLinkRead.d.ts.map +1 -0
  45. package/features/slack/hooks/useSlackLinks.d.ts +32 -0
  46. package/features/slack/hooks/useSlackLinks.d.ts.map +1 -0
  47. package/features/slack/link-scope.d.ts +7 -0
  48. package/features/slack/link-scope.d.ts.map +1 -0
  49. package/features/slack/types/wire.d.ts +75 -0
  50. package/features/slack/types/wire.d.ts.map +1 -1
  51. package/features/slack/utils/__tests__/join-notices.test.d.ts +2 -0
  52. package/features/slack/utils/__tests__/join-notices.test.d.ts.map +1 -0
  53. package/features/slack/utils/__tests__/slack-thread-url.test.d.ts +2 -0
  54. package/features/slack/utils/__tests__/slack-thread-url.test.d.ts.map +1 -0
  55. package/features/slack/utils/join-notices.d.ts +3 -0
  56. package/features/slack/utils/join-notices.d.ts.map +1 -0
  57. package/features/slack/utils/slack-thread-url.d.ts +23 -0
  58. package/features/slack/utils/slack-thread-url.d.ts.map +1 -0
  59. package/index.d.ts +3 -0
  60. package/index.d.ts.map +1 -1
  61. package/index.es.js +13471 -12560
  62. package/index.umd.js +647 -647
  63. package/main-dev.d.ts.map +1 -1
  64. package/package.json +1 -1
  65. package/testing/mocks/handlers/slack.d.ts +22 -12
  66. package/testing/mocks/handlers/slack.d.ts.map +1 -1
@@ -5,6 +5,9 @@ export type HigSlackSectionProps = SlackContextData & {
5
5
  /** Host hook (M-HIG-2) for the linked-state "View all" link — wired to
6
6
  * activating the Slack tab. The section itself stays panel-free. */
7
7
  onViewAll?: () => void;
8
+ /** Multi-link (M2): clicking a link row should open the Slack tab ON
9
+ * that item. Falls back to `onViewAll` when the host doesn't wire it. */
10
+ onOpenLink?: (linkId: string) => void;
8
11
  theme?: ConnectorThemeConfig;
9
12
  };
10
13
  /** Body-only surface: same props, no self-owned accordion shell. */
@@ -1 +1 @@
1
- {"version":3,"file":"HigSlackSection.d.ts","sourceRoot":"","sources":["../../../src/app/hig-slack/HigSlackSection.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAkC,MAAM,OAAO,CAAC;AAQ3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AASjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAyBpE,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IACpD;yEACqE;IACrE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAC9B,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAoQ5D;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CAIpD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAI5D,CAAC"}
1
+ {"version":3,"file":"HigSlackSection.d.ts","sourceRoot":"","sources":["../../../src/app/hig-slack/HigSlackSection.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAkC,MAAM,OAAO,CAAC;AAc3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAUjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAyBpE,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IACpD;yEACqE;IACrE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;8EAC0E;IAC1E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAC9B,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAiX5D;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CAIpD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAI5D,CAAC"}
@@ -58,4 +58,8 @@ export declare const SLACK_EXISTING_CHANNEL_LINKED = "slack_existing_channel_lin
58
58
  export declare const SLACK_NEW_CHANNEL_LINKED = "slack_new_channel_linked";
59
59
  export declare const SLACK_REPLY_SENT = "slack_reply_sent";
60
60
  export declare const SLACK_OLDER_MESSAGES_LOADED = "slack_older_messages_loaded";
61
+ export declare const SLACK_LINK_EXISTING_CLICKED = "slack_link_existing_clicked";
62
+ export declare const SLACK_EXISTING_THREAD_LINKED = "slack_existing_thread_linked";
63
+ export declare const SLACK_CONVERSATION_UNLINKED = "slack_conversation_unlinked";
64
+ export declare const SLACK_LINK_SWITCHED = "slack_link_switched";
61
65
  //# sourceMappingURL=tracking-events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tracking-events.d.ts","sourceRoot":"","sources":["../../src/constants/tracking-events.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AACrE,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAC7E,eAAO,MAAM,gCAAgC,qCAAqC,CAAC;AACnF,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAC/E,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAC/D,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;AACvE,eAAO,MAAM,6BAA6B,4CAA4C,CAAC;AACvF,eAAO,MAAM,4BAA4B,2CAA2C,CAAC;AACrF,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AACxE,eAAO,MAAM,yBAAyB,wCAAwC,CAAC;AAC/E,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAC3E,eAAO,MAAM,0BAA0B,yCAAyC,CAAC;AACjF,eAAO,MAAM,yBAAyB,wCAAwC,CAAC;AAC/E,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAC3E,eAAO,MAAM,oBAAoB,mCAAmC,CAAC;AACrE,eAAO,MAAM,2BAA2B,0CAA0C,CAAC;AACnF,eAAO,MAAM,yBAAyB,wCAAwC,CAAC;AAC/E,eAAO,MAAM,mCAAmC,yBAAyB,CAAC;AAC1E,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAC/D,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAC/D,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AACjE,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AACvE,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AACjE,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAC/E,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AACzE,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAChE,eAAO,MAAM,oBAAoB,4BAA4B,CAAC;AAC9D,eAAO,MAAM,YAAY,wBAAwB,CAAC;AAClD,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AACzE,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AAKrE,eAAO,MAAM,0BAA0B,yCAAyC,CAAC;AAKjF,eAAO,MAAM,8BAA8B,6CAA6C,CAAC;AAGzF,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AACjE,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAC/E,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAC7E,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AACnE,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAInD,eAAO,MAAM,2BAA2B,gCAAgC,CAAC"}
1
+ {"version":3,"file":"tracking-events.d.ts","sourceRoot":"","sources":["../../src/constants/tracking-events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/api/__tests__/errors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=links.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.test.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/api/__tests__/links.test.ts"],"names":[],"mappings":""}
@@ -8,6 +8,10 @@ import { ExternalConversation, SlackOlderPage, SlackThreadGroup, StartExistingCh
8
8
  export interface SlackPageParams {
9
9
  beforeTs?: string;
10
10
  pageSize?: number;
11
+ /** Multi-link selector (M2): scope the read to one link row. Omitted ⇒
12
+ * backend serves the most recently linked item (flag-off compat shim).
13
+ * Query-param casing is snake_case on the wire (`link_id`). */
14
+ linkId?: string;
11
15
  }
12
16
  export declare const startExistingChannel: (payload: StartExistingChannelRequest) => Promise<StartResponse>;
13
17
  export declare const startNewChannel: (payload: StartNewChannelRequest) => Promise<StartResponse>;
@@ -18,7 +22,7 @@ export declare const getExternalConversation: (hiverConvId: string, page?: Slack
18
22
  * backwards into older history. Returns older thread replies (thread mode)
19
23
  * or older thread roots (channel mode); the caller merges + dedupes.
20
24
  */
21
- export declare const getExternalConversationPage: (hiverConvId: string, beforeTs: string, pageSize?: number) => Promise<SlackOlderPage>;
25
+ export declare const getExternalConversationPage: (hiverConvId: string, beforeTs: string, pageSize?: number, linkId?: string) => Promise<SlackOlderPage>;
22
26
  /**
23
27
  * Channel mode (B4): lazily fetch a single thread's full messages
24
28
  * (root + replies) when the user drills into it. The list view only
@@ -31,7 +35,7 @@ export declare const getThread: (hiverConvId: string, threadTs: string, page?: S
31
35
  * page's nextCursor as `beforeTs`. Returns the older replies window (the
32
36
  * thread root is omitted from `messages` — it stays pinned in page 0).
33
37
  */
34
- export declare const getThreadPage: (hiverConvId: string, threadTs: string, beforeTs: string, pageSize?: number) => Promise<SlackOlderPage>;
38
+ export declare const getThreadPage: (hiverConvId: string, threadTs: string, beforeTs: string, pageSize?: number, linkId?: string) => Promise<SlackOlderPage>;
35
39
  export declare const getExternalConversationsByTarget: (params: {
36
40
  channelId: string;
37
41
  externalThreadTs?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/conversations.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,oBAAoB,EAEpB,cAAc,EAGd,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,aAAa,EACd,MAAM,6BAA6B,CAAC;AAErC;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAgED,eAAO,MAAM,oBAAoB,YAAmB,2BAA2B,KAAG,OAAO,CAAC,aAAa,CAQtG,CAAC;AAEF,eAAO,MAAM,eAAe,YAAmB,sBAAsB,KAAG,OAAO,CAAC,aAAa,CAQ5F,CAAC;AAeF,eAAO,MAAM,uBAAuB,gBACrB,MAAM,SACZ,eAAe,KACrB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CA0BrC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,gBACzB,MAAM,YACT,MAAM,aACL,MAAM,KAChB,OAAO,CAAC,cAAc,CASxB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,gBACP,MAAM,YACT,MAAM,SACT,eAAe,KACrB,OAAO,CAAC,gBAAgB,CAQ1B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,gBACX,MAAM,YACT,MAAM,YACN,MAAM,aACL,MAAM,KAChB,OAAO,CAAC,cAAc,CAQxB,CAAC;AAEF,eAAO,MAAM,gCAAgC,WAAkB;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,KAAG,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAUrC,CAAC"}
1
+ {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/conversations.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,oBAAoB,EAEpB,cAAc,EAGd,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,aAAa,EACd,MAAM,6BAA6B,CAAC;AAErC;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;oEAEgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAiED,eAAO,MAAM,oBAAoB,YAAmB,2BAA2B,KAAG,OAAO,CAAC,aAAa,CAQtG,CAAC;AAEF,eAAO,MAAM,eAAe,YAAmB,sBAAsB,KAAG,OAAO,CAAC,aAAa,CAQ5F,CAAC;AAeF,eAAO,MAAM,uBAAuB,gBACrB,MAAM,SACZ,eAAe,KACrB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CA0BrC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,gBACzB,MAAM,YACT,MAAM,aACL,MAAM,WACR,MAAM,KACd,OAAO,CAAC,cAAc,CASxB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,gBACP,MAAM,YACT,MAAM,SACT,eAAe,KACrB,OAAO,CAAC,gBAAgB,CAQ1B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,gBACX,MAAM,YACT,MAAM,YACN,MAAM,aACL,MAAM,WACR,MAAM,KACd,OAAO,CAAC,cAAc,CAQxB,CAAC;AAEF,eAAO,MAAM,gCAAgC,WAAkB;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,KAAG,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAUrC,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Central Slack error taxonomy (M2). Every mapped backend error returns
3
+ * `{ detail: { reason: '<code>', … } }` — switch on `detail.reason`,
4
+ * NEVER on HTTP status alone: two different 409s exist now
5
+ * (already-linked vs cap-reached).
6
+ *
7
+ * One historical wrinkle: the pre-M2 already-linked 409 returned only
8
+ * `{ existingLinkId }` with NO reason key (the backend is adding
9
+ * `reason: 'slack_target_already_linked'` alongside it). We therefore
10
+ * treat "409 with an existingLinkId" as already-linked even when the
11
+ * reason is absent, so the client works against both backend versions.
12
+ *
13
+ * Shapes are read defensively (detail-nested first, then top-level)
14
+ * because the agent controller serialises FastAPI HTTPException as
15
+ * `{ detail: { reason } }` while the generic user-tier resolver returns
16
+ * a top-level `reason` — same duality isSlackAuthError already handles.
17
+ */
18
+ export type SlackErrorReason = 'slack_invalid_auth' | 'hiver_conv_not_linked' | 'slack_target_already_linked' | 'slack_link_cap_reached' | 'slack_api_error' | 'workspace_connector_missing' | 'user_slack_auth_missing';
19
+ export interface ParsedSlackError {
20
+ status?: number;
21
+ reason?: SlackErrorReason | string;
22
+ /** Slack's own error code when reason === 'slack_api_error'
23
+ * (e.g. 'name_taken', 'not_in_channel'). */
24
+ code?: string;
25
+ /** Set on the already-linked 409 — the linkId of the existing row,
26
+ * so the UI can switch straight to that item. */
27
+ existingLinkId?: string;
28
+ message?: string;
29
+ }
30
+ export declare const parseSlackError: (err: unknown) => ParsedSlackError;
31
+ export declare const isSlackErrorReason: (err: unknown, reason: SlackErrorReason) => boolean;
32
+ /** 404 for an unknown / stale linkId — the item was unlinked elsewhere.
33
+ * Correct handling: refetch the links list; the item is gone. */
34
+ export declare const isStaleLinkError: (err: unknown) => boolean;
35
+ export declare const isLinkCapReachedError: (err: unknown) => boolean;
36
+ export declare const isTargetAlreadyLinkedError: (err: unknown) => boolean;
37
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,gBAAgB,GACxB,oBAAoB,GACpB,uBAAuB,GACvB,6BAA6B,GAC7B,wBAAwB,GACxB,iBAAiB,GACjB,6BAA6B,GAC7B,yBAAyB,CAAC;AAE9B,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IACnC;iDAC6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;sDACkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAeD,eAAO,MAAM,eAAe,QAAS,OAAO,KAAG,gBAiB9C,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,OAAO,UAAU,gBAAgB,KAAG,OACpC,CAAC;AAEzC;kEACkE;AAClE,eAAO,MAAM,gBAAgB,QAAS,OAAO,KAAG,OAG/C,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAS,OAAO,KAAG,OAA4D,CAAC;AAElH,eAAO,MAAM,0BAA0B,QAAS,OAAO,KAAG,OACF,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export { getExternalConversation, getExternalConversationPage, getExternalConversationsByTarget, getThreadPage, startExistingChannel, startNewChannel } from './conversations';
2
2
  export { postMessage } from './messages';
3
3
  export { getChannelMembers } from './members';
4
+ export { getLinks, getThreadPreview, linkExistingChannel, linkExistingThread, markLinkRead, unlinkConversation } from './links';
5
+ export { parseSlackError } from './errors';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,aAAa,EACb,oBAAoB,EACpB,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,aAAa,EACb,oBAAoB,EACpB,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC"}
@@ -52,7 +52,16 @@ export declare function backedOffInterval(baseMs: number, failureCount: number):
52
52
  * exponentially up to MAX_POLL_BACKOFF_MS and snaps back to base on
53
53
  * the first success (see `backedOffInterval`).
54
54
  */
55
- export declare function useLinkedConversation(hiverConvId: string, enabled?: boolean, refetchIntervalMs?: number): import('@tanstack/react-query').UseQueryResult<ExternalConversation | null, Error>;
55
+ /**
56
+ * Query-key builders (M2). The linkId lands in the key ONLY when
57
+ * provided, so flag-off single-link surfaces keep today's exact key
58
+ * shape — and the cache-patching call sites (Composer optimistic writes,
59
+ * MessageItem delete invalidation) build keys through these helpers
60
+ * instead of hand-rolled arrays, so reads and writes can't drift apart.
61
+ */
62
+ export declare const linkedConvQueryKey: (hiverConvId: string, linkId?: string) => string[];
63
+ export declare const threadQueryKey: (hiverConvId: string, threadTs: string | null, linkId?: string) => (string | null)[];
64
+ export declare function useLinkedConversation(hiverConvId: string, enabled?: boolean, refetchIntervalMs?: number, linkId?: string): import('@tanstack/react-query').UseQueryResult<ExternalConversation | null, Error>;
56
65
  /**
57
66
  * Channel mode (B4): lazily fetch a single thread's messages (root +
58
67
  * replies) when the user drills into it from the channel list. Enabled
@@ -61,5 +70,5 @@ export declare function useLinkedConversation(hiverConvId: string, enabled?: boo
61
70
  * `useLinkedConversation`, pauses when the surface is inactive (`isActive`
62
71
  * false) and backs off while the endpoint is failing.
63
72
  */
64
- export declare function useThread(hiverConvId: string, threadTs: string | null, isActive?: boolean): import('@tanstack/react-query').UseQueryResult<SlackThreadGroup, Error>;
73
+ export declare function useThread(hiverConvId: string, threadTs: string | null, isActive?: boolean, linkId?: string): import('@tanstack/react-query').UseQueryResult<SlackThreadGroup, Error>;
65
74
  //# sourceMappingURL=linked-conv.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"linked-conv.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/linked-conv.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE1F;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAG9E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,UAAO,EACd,iBAAiB,GAAE,MAAqC,sFA+BzD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,UAAO,2EAWtF"}
1
+ {"version":3,"file":"linked-conv.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/linked-conv.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE1F;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAG9E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,gBAAiB,MAAM,WAAW,MAAM,aACyB,CAAC;AAEjG,eAAO,MAAM,cAAc,gBAAiB,MAAM,YAAY,MAAM,GAAG,IAAI,WAAW,MAAM,sBACc,CAAC;AAE3G,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,UAAO,EACd,iBAAiB,GAAE,MAAqC,EACxD,MAAM,CAAC,EAAE,MAAM,sFA+BhB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,UAAO,EAAE,MAAM,CAAC,EAAE,MAAM,2EAcvG"}
@@ -0,0 +1,90 @@
1
+ import { LinkExistingChannelRequest, LinkExistingThreadRequest, SlackLink, SlackLinksResponse, SlackThreadPreview, StartResponse } from '../types/wire';
2
+ /**
3
+ * Poll cadence for the links list (the switcher payload). The endpoint is
4
+ * declared safe to poll — it never mutates read state — and it's the ONLY
5
+ * background poll for non-selected links: their unread counts and
6
+ * lastActivityTs ride this query, while message polling stays scoped to
7
+ * the one selected link (decision D8). Kept as a named constant so the
8
+ * cadence is tunable without touching call sites.
9
+ */
10
+ export declare const LINKS_POLL_INTERVAL_MS = 5000;
11
+ /**
12
+ * Last-resort cap when the server omits `cap`/`remainingSlots` (should not
13
+ * happen per contract). The SERVER value always wins when present —
14
+ * decision D6: never trust a hardcoded 4.
15
+ */
16
+ export declare const FALLBACK_LINK_CAP = 4;
17
+ /** Query key for the links list — exported so mutations (link, unlink,
18
+ * mark-read) and M2-C's optimistic unread updates target one shape. */
19
+ export declare const linksQueryKey: (hiverConvId: string) => readonly ["slack", "links", string];
20
+ interface RawSlackLink extends Omit<SlackLink, 'channelName' | 'parentExternalId' | 'threadTs' | 'lastActivityTs' | 'unreadCount'> {
21
+ channelName?: string | null;
22
+ parentExternalId?: string | null;
23
+ threadTs?: string | null;
24
+ lastActivityTs?: string | null;
25
+ unreadCount?: number;
26
+ }
27
+ interface RawLinksResponse {
28
+ links?: RawSlackLink[] | null;
29
+ totalUnreadCount?: number;
30
+ cap?: number;
31
+ remainingSlots?: number;
32
+ }
33
+ export declare const normaliseLinksResponse: (body: RawLinksResponse | undefined) => SlackLinksResponse;
34
+ /**
35
+ * Display label for a link. `channelName` can legitimately be null on
36
+ * older links until first read — fall back to a kind-appropriate
37
+ * placeholder instead of an empty string (TC-012).
38
+ */
39
+ export declare const linkDisplayName: (link: Pick<SlackLink, "channelName" | "targetKind">) => string;
40
+ /**
41
+ * Cold-open selection rule (decision D9): the item with the most recent
42
+ * activity wins; items with no cached activity rank last and tie-break by
43
+ * most recently linked. This is deliberately NOT the backend's
44
+ * omitted-linkId fallback (most recently LINKED) — a different rule the
45
+ * contract tells us not to lean on.
46
+ */
47
+ export declare const pickDefaultLink: (links: SlackLink[]) => SlackLink | null;
48
+ export declare const getLinks: (hiverConvId: string) => Promise<SlackLinksResponse>;
49
+ /**
50
+ * The switcher query: every link on the conversation with unread + cap
51
+ * info, polled at LINKS_POLL_INTERVAL_MS with the shared exponential
52
+ * backoff. Pass `refetchIntervalMs: 0` for surfaces that are mounted but
53
+ * hidden (same `isActive` convention as useLinkedConversation).
54
+ */
55
+ export declare function useLinks(hiverConvId: string, enabled?: boolean, refetchIntervalMs?: number): import('@tanstack/react-query').UseQueryResult<SlackLinksResponse, Error>;
56
+ /**
57
+ * Unlink one item. 204; frees a cap slot. Nothing happens on Slack —
58
+ * the channel/thread and all history survive (say so in confirm copy).
59
+ * Anyone with access to the conversation may unlink.
60
+ */
61
+ export declare const unlinkConversation: (hiverConvId: string, linkId: string) => Promise<void>;
62
+ /**
63
+ * Mark one item read — clears its per-viewer unreadCount. Call ONLY when
64
+ * the rep actually views the item (opens it, or it's the cold-open
65
+ * default in view); never from a background poll or prefetch. Omitting
66
+ * `lastReadTs` marks up to the newest message the backend knows about,
67
+ * which is what we want in almost every case.
68
+ */
69
+ export declare const markLinkRead: (hiverConvId: string, linkId: string, lastReadTs?: string) => Promise<void>;
70
+ /**
71
+ * Attach an existing Slack thread. Posts `messageText` into the thread
72
+ * (always — no silent attach), then links it. Response shape is identical
73
+ * to /start/existing-channel so the success path reuses that handling;
74
+ * `externalConversationId` IS the new linkId.
75
+ */
76
+ export declare const linkExistingThread: (payload: LinkExistingThreadRequest) => Promise<StartResponse>;
77
+ /**
78
+ * Attach an existing Slack channel (posts `messageText` top-level, then
79
+ * links the whole channel → renders in channel mode like a started one).
80
+ */
81
+ export declare const linkExistingChannel: (payload: LinkExistingChannelRequest) => Promise<StartResponse>;
82
+ /**
83
+ * DUMMY CONTRACT (decision D1): fetch preview meta for a pasted thread
84
+ * URL before linking. The backend endpoint is not designed yet — this is
85
+ * the shape we agreed to build against (MSW mocks it in dev). Wire
86
+ * casing follows the live convention: snake_case query params.
87
+ */
88
+ export declare const getThreadPreview: (channelId: string, threadTs: string) => Promise<SlackThreadPreview>;
89
+ export {};
90
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/links.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,SAAS,EACT,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,6BAA6B,CAAC;AAErC;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC;wEACwE;AACxE,eAAO,MAAM,aAAa,gBAAiB,MAAM,wCAA6C,CAAC;AAE/F,UAAU,YACR,SAAQ,IAAI,CAAC,SAAS,EAAE,aAAa,GAAG,kBAAkB,GAAG,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAAC;IAC3G,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAWD,eAAO,MAAM,sBAAsB,SAAU,gBAAgB,GAAG,SAAS,KAAG,kBAS3E,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,SAAU,IAAI,CAAC,SAAS,EAAE,aAAa,GAAG,YAAY,CAAC,KAAG,MACC,CAAC;AAExF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,UAAW,SAAS,EAAE,KAAG,SAAS,GAAG,IAShE,CAAC;AAEF,eAAO,MAAM,QAAQ,gBAAuB,MAAM,KAAG,OAAO,CAAC,kBAAkB,CAM9E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,UAAO,EAAE,iBAAiB,GAAE,MAA+B,6EAW/G;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gBAAuB,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAK1F,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,gBAAuB,MAAM,UAAU,MAAM,eAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAMzG,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,YAAmB,yBAAyB,KAAG,OAAO,CAAC,aAAa,CAQlG,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,YAAmB,0BAA0B,KAAG,OAAO,CAAC,aAAa,CAQpG,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,cAAqB,MAAM,YAAY,MAAM,KAAG,OAAO,CAAC,kBAAkB,CAOtG,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { ChannelMember } from '../types/wire';
2
- export declare const getChannelMembers: (hiverConvId?: string, channelId?: string) => Promise<ChannelMember[]>;
2
+ export declare const getChannelMembers: (hiverConvId?: string, channelId?: string, linkId?: string) => Promise<ChannelMember[]>;
3
3
  /**
4
4
  * Cached channel-members query. Used by the linked-conv panel to
5
5
  * resolve `<@USER_ID>` mention tokens to display names, and by the
6
6
  * composer's @-mention picker — same queryKey → one shared fetch.
7
7
  * Names are stable, so a long staleTime avoids refetch churn.
8
8
  */
9
- export declare function useChannelMembers(hiverConvId: string, enabled?: boolean): import('@tanstack/react-query').UseQueryResult<ChannelMember[], Error>;
9
+ export declare function useChannelMembers(hiverConvId: string, enabled?: boolean, linkId?: string): import('@tanstack/react-query').UseQueryResult<ChannelMember[], Error>;
10
10
  //# sourceMappingURL=members.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/members.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,eAAO,MAAM,iBAAiB,iBAAwB,MAAM,cAAc,MAAM,KAAG,OAAO,CAAC,aAAa,EAAE,CAgBzG,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,UAAO,0EAQpE"}
1
+ {"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/members.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,eAAO,MAAM,iBAAiB,iBACd,MAAM,cACR,MAAM,WACT,MAAM,KACd,OAAO,CAAC,aAAa,EAAE,CAmBzB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,UAAO,EAAE,MAAM,CAAC,EAAE,MAAM,0EAWrF"}
@@ -6,5 +6,5 @@ export declare const postMessage: (payload: PostMessageRequest) => Promise<Slack
6
6
  * returns 204. `hiver_conv_id` resolves the linked channel/thread the
7
7
  * message lives in.
8
8
  */
9
- export declare const deleteMessage: (externalMessageId: string, hiverConvId: string) => Promise<void>;
9
+ export declare const deleteMessage: (externalMessageId: string, hiverConvId: string, linkId?: string) => Promise<void>;
10
10
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/messages.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAqBpF,eAAO,MAAM,WAAW,YAAmB,kBAAkB,KAAG,OAAO,CAAC,YAAY,CAOnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,sBAA6B,MAAM,eAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAWhG,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/api/messages.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAqBpF,eAAO,MAAM,WAAW,YAAmB,kBAAkB,KAAG,OAAO,CAAC,YAAY,CAOnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,sBAA6B,MAAM,eAAe,MAAM,WAAW,MAAM,KAAG,OAAO,CAAC,IAAI,CAYjH,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { FC } from 'react';
2
+ interface LinkExistingModalProps {
3
+ open: boolean;
4
+ onClose: () => void;
5
+ /** Fired on success with the NEW link's id (externalConversationId)
6
+ * so the parent can select/open it. */
7
+ onLinked?: (linkId: string) => void;
8
+ /** 409 slack_target_already_linked: the parent switches to the
9
+ * existing item instead of surfacing an error. */
10
+ onAlreadyLinked?: (existingLinkId: string) => void;
11
+ /** Links currently on the conversation — analytics metadata only
12
+ * (PRD: linked count 0–3 at the moment of linking). */
13
+ linkedCount?: number;
14
+ }
15
+ /**
16
+ * M2 "Link Slack Conversation" modal (Figma M2 1705:92605 / 1719:109242).
17
+ * Two tabs:
18
+ * Thread — paste a Slack thread permalink → Fetch → preview card
19
+ * (first message, channel, member count, type) → link.
20
+ * Channel — search the workspace channel directory → pick → link.
21
+ *
22
+ * Both link endpoints ALWAYS post before linking; per product decision
23
+ * D2 the modal has no compose box and sends `messageText: ''`.
24
+ * Preview rides the DUMMY /preview/thread contract (decision D1) until
25
+ * the backend endpoint is finalised.
26
+ */
27
+ export declare const LinkExistingModal: FC<LinkExistingModalProps>;
28
+ export {};
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkExistingModal/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAyC,MAAM,OAAO,CAAC;AAsClE,UAAU,sBAAsB;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;4CACwC;IACxC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;uDACmD;IACnD,eAAe,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;4DACwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CA2WxD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/Composer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,EAAE,EAA+E,MAAM,OAAO,CAAC;AAgFvH,UAAU,aAAa;IACrB;oEACgE;IAChE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAChD;wEACoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;oDACgD;IAChD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;4CAEwC;IACxC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC;;;wEAGoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAijBtC,CAAC"}
1
+ {"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/Composer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,EAAE,EAA+E,MAAM,OAAO,CAAC;AAoFvH,UAAU,aAAa;IACrB;oEACgE;IAChE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAChD;wEACoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;oDACgD;IAChD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;4CAEwC;IACxC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC;;;wEAGoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA+jBtC,CAAC"}
@@ -7,14 +7,21 @@ interface LinkedChannelHeaderProps {
7
7
  * present, the additive `URL:` row renders a blue, truncated link opening in
8
8
  * a new tab. Absent → `Channel:`-only Phase-1 layout. */
9
9
  channelUrl?: string;
10
+ /** Multi-link (M2): render a "← Back" row above the meta rows, returning to
11
+ * the links list. Absent (flag off / single link) → no back affordance. */
12
+ onBack?: () => void;
13
+ /** Multi-link (M2): render the kebab (⋮) menu with the Unlink action.
14
+ * Absent → no kebab (flag off). */
15
+ onUnlink?: () => void;
10
16
  }
11
17
  /**
12
18
  * HIG-only top content band (Figma 679:621193) pinned above the linked panel.
13
19
  * Phase 1 renders a `Channel:` (gray label) + `#<name>` (dark value) row; Phase 2
14
20
  * adds an additive `URL:` row (blue, truncated link opening Slack in a new tab)
15
- * whenever a `channelUrl` is supplied. The bottom hairline lives on
16
- * `ChannelHeaderBand`. Purely presentational — gated by `showChannelHeader` at
17
- * the call site.
21
+ * whenever a `channelUrl` is supplied. M2 (multi-link) adds an optional "← Back"
22
+ * row (returns to the links list, Figma M2 1699:30955) and a kebab menu with
23
+ * Unlink on the Channel row (Figma M2 1767:108199). The bottom hairline lives on
24
+ * `ChannelHeaderBand`. Gated by `showChannelHeader` at the call site.
18
25
  */
19
26
  export declare const LinkedChannelHeader: FC<LinkedChannelHeaderProps>;
20
27
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"LinkedChannelHeader.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/LinkedChannelHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAM3B,UAAU,wBAAwB;IAChC;sFACkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB;;8DAE0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAYD;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CA4C5D,CAAC"}
1
+ {"version":3,"file":"LinkedChannelHeader.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/LinkedChannelHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAwB,MAAM,OAAO,CAAC;AAOjD,UAAU,wBAAwB;IAChC;sFACkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB;;8DAE0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;gFAC4E;IAC5E,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;wCACoC;IACpC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAYD;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAyH5D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/MessageItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,EAAE,EAA8C,MAAM,OAAO,CAAC;AAYtF,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,6BAA6B,CAAC;AAiB/E,UAAU,gBAAgB;IACxB,OAAO,EAAE,YAAY,CAAC;IACtB;wEACoE;IACpE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;;;4DAGwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;kCAE8B;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;2EACuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;gDAE4C;IAC5C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;yEAEqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;yEAGqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;yDACqD;IACrD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAkDD;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAwQ5C,CAAC"}
1
+ {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/MessageItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,EAAE,EAA8C,MAAM,OAAO,CAAC;AAatF,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,6BAA6B,CAAC;AAiB/E,UAAU,gBAAgB;IACxB,OAAO,EAAE,YAAY,CAAC;IACtB;wEACoE;IACpE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;;;4DAGwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;kCAE8B;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;2EACuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;gDAE4C;IAC5C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;yEAEqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;yEAGqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;yDACqD;IACrD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAkDD;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA0Q5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadDetailView.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/ThreadDetailView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAyC,MAAM,OAAO,CAAC;AA0F7E,UAAU,qBAAqB;IAC7B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;0EACsE;IACtE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;qEAEiE;IACjE,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA0KtD,CAAC"}
1
+ {"version":3,"file":"ThreadDetailView.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/ThreadDetailView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAyC,MAAM,OAAO,CAAC;AA4F7E,UAAU,qBAAqB;IAC7B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;0EACsE;IACtE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;qEAEiE;IACjE,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAiLtD,CAAC"}
@@ -23,5 +23,22 @@ import { FC } from 'react';
23
23
  * The 50-entry trim flag (`isTrimmed`) renders a muted footer at
24
24
  * the top of the scroll list when the cache hit the M1 cap.
25
25
  */
26
- export declare const LinkedConversationPanel: FC;
26
+ export interface LinkedConversationPanelProps {
27
+ /** Multi-link (M2): pin the panel to ONE link row. Every read/write in
28
+ * the subtree is scoped to it (via LinkScopeProvider). Undefined =
29
+ * flag-off single-link mode — today's behavior, byte-identical keys. */
30
+ linkId?: string;
31
+ /** Multi-link: "← Back" in the channel band returns to the links list. */
32
+ onBack?: () => void;
33
+ /** Multi-link: fired after a successful unlink so the parent can drop
34
+ * the selection and fall back to the list. */
35
+ onUnlinked?: () => void;
36
+ }
37
+ /**
38
+ * Public surface. Wraps the panel subtree in LinkScopeProvider so deep
39
+ * call sites (Composer cache patches, MessageItem delete, the thread
40
+ * drill-in) read the SAME linkId this panel is pinned to without prop
41
+ * threading. Flag-off callers mount it prop-less — nothing changes.
42
+ */
43
+ export declare const LinkedConversationPanel: FC<LinkedConversationPanelProps>;
27
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAA8D,MAAM,OAAO,CAAC;AA+BvF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB,EAAE,EAmhBrC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/LinkedConversationPanel/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAA8D,MAAM,OAAO,CAAC;AAqCvF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;6EAEyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;mDAC+C;IAC/C,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AA8kBD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,4BAA4B,CAIpE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SlackConversationTab.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/components/SlackConversationTab.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAoC,MAAM,OAAO,CAAC;AAwB7D,UAAU,yBAAyB;IACjC;;oDAEgD;IAChD,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;CACnC;AAuCD,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAmN9D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"SlackConversationTab.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/components/SlackConversationTab.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAA4C,MAAM,OAAO,CAAC;AAkCrE,UAAU,yBAAyB;IACjC;;oDAEgD;IAChD,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;CACnC;AA0CD,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAmZ9D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { FC } from 'react';
2
+ import { SlackLink } from '../types/wire';
3
+ interface SlackLinkListProps {
4
+ links: SlackLink[];
5
+ /** Server-authoritative cap info (never hardcode 4 — decision D6). */
6
+ cap: number;
7
+ remainingSlots: number;
8
+ onOpen: (linkId: string) => void;
9
+ onStartNew: () => void;
10
+ onLinkExisting: () => void;
11
+ }
12
+ /**
13
+ * Multi-link switcher — the HIG Slack tab's landing view (Figma M2
14
+ * 1673:23178): one card per linked Slack conversation with its unread
15
+ * count, then "+ Start new" + "Link existing" CTAs. Both CTAs disable
16
+ * at zero remaining slots with the server-cap limit message.
17
+ *
18
+ * Purely presentational — the parent (SlackConversationTab) owns the
19
+ * links query, selection state, and the two modals.
20
+ */
21
+ export declare const SlackLinkList: FC<SlackLinkListProps>;
22
+ export {};
23
+ //# sourceMappingURL=SlackLinkList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlackLinkList.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/components/SlackLinkList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAM3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,UAAU,kBAAkB;IAC1B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AA+BD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAyFhD,CAAC"}
@@ -3,8 +3,14 @@ interface StartModalProps {
3
3
  open: boolean;
4
4
  onClose: () => void;
5
5
  /** Called after a successful start, with the linked channel id so
6
- * the parent can transition to the linked-conv view. */
7
- onStarted?: (channelId: string) => void;
6
+ * the parent can transition to the linked-conv view. M2 adds the new
7
+ * link row's id (`externalConversationId`) as a second arg so the
8
+ * multi-link tab can select the exact item without waiting a poll. */
9
+ onStarted?: (channelId: string, linkId?: string) => void;
10
+ /** Multi-link (M2): 409 slack_target_already_linked → the parent
11
+ * switches to the existing item (Figma M2 "switch to that tab").
12
+ * Absent (flag off) → the M1 silent-adopt behavior is preserved. */
13
+ onAlreadyLinked?: (existingLinkId: string) => void;
8
14
  }
9
15
  /**
10
16
  * UI-2 — shared shell for the "Start new" flow. Two tabs:
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/StartModal/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAqD,MAAM,OAAO,CAAC;AAkC9E,UAAU,eAAe;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;6DACyD;IACzD,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAID;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAkP1C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/components/StartModal/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAqD,MAAM,OAAO,CAAC;AAmC9E,UAAU,eAAe;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;2EAGuE;IACvE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD;;yEAEqE;IACrE,eAAe,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAID;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA2P1C,CAAC"}
@@ -7,6 +7,12 @@ export declare const SLACK_MESSAGE_BY_ID_API: string;
7
7
  export declare const SLACK_EXTERNAL_CONVERSATION_API: string;
8
8
  export declare const SLACK_THREAD_API: string;
9
9
  export declare const SLACK_EXTERNAL_CONVERSATIONS_BY_TARGET_API: string;
10
+ export declare const SLACK_LINKS_API: string;
11
+ export declare const SLACK_LINK_BY_ID_API: string;
12
+ export declare const SLACK_LINK_READ_API: string;
13
+ export declare const SLACK_LINK_EXISTING_THREAD_API: string;
14
+ export declare const SLACK_LINK_EXISTING_CHANNEL_API: string;
15
+ export declare const SLACK_THREAD_PREVIEW_API: string;
10
16
  export declare const SLACK_CHANNEL_MEMBERS_API: string;
11
17
  export declare const SLACK_CHANNELS_API: string;
12
18
  export declare const SLACK_WORKSPACE_USERS_API: string;
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/constants/api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,gBAAgB,+BAA4B,CAAC;AAE1D,eAAO,MAAM,gCAAgC,EAAE,MAAqD,CAAC;AACrG,eAAO,MAAM,2BAA2B,EAAE,MAAgD,CAAC;AAE3F,eAAO,MAAM,kBAAkB,EAAE,MAAuC,CAAC;AAGzE,eAAO,MAAM,uBAAuB,EAAE,MAA0D,CAAC;AAEjG,eAAO,MAAM,+BAA+B,EAAE,MAAiE,CAAC;AAGhH,eAAO,MAAM,gBAAgB,EAAE,MAAmF,CAAC;AACnH,eAAO,MAAM,0CAA0C,EAAE,MAA+D,CAAC;AAEzH,eAAO,MAAM,yBAAyB,EAAE,MAA8C,CAAC;AAMvF,eAAO,MAAM,kBAAkB,EAAE,MAAuC,CAAC;AASzE,eAAO,MAAM,yBAAyB,EAAE,MAAoC,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/constants/api.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,gBAAgB,+BAA4B,CAAC;AAE1D,eAAO,MAAM,gCAAgC,EAAE,MAAqD,CAAC;AACrG,eAAO,MAAM,2BAA2B,EAAE,MAAgD,CAAC;AAE3F,eAAO,MAAM,kBAAkB,EAAE,MAAuC,CAAC;AAGzE,eAAO,MAAM,uBAAuB,EAAE,MAA0D,CAAC;AAEjG,eAAO,MAAM,+BAA+B,EAAE,MAAiE,CAAC;AAGhH,eAAO,MAAM,gBAAgB,EAAE,MAAmF,CAAC;AACnH,eAAO,MAAM,0CAA0C,EAAE,MAA+D,CAAC;AAKzH,eAAO,MAAM,eAAe,EAAE,MAAwE,CAAC;AAEvG,eAAO,MAAM,oBAAoB,EAAE,MAAgF,CAAC;AAGpH,eAAO,MAAM,mBAAmB,EAAE,MAAqF,CAAC;AAGxH,eAAO,MAAM,8BAA8B,EAAE,MAAmD,CAAC;AACjG,eAAO,MAAM,+BAA+B,EAAE,MAAoD,CAAC;AAKnG,eAAO,MAAM,wBAAwB,EAAE,MAA6C,CAAC;AAErF,eAAO,MAAM,yBAAyB,EAAE,MAA8C,CAAC;AAMvF,eAAO,MAAM,kBAAkB,EAAE,MAAuC,CAAC;AASzE,eAAO,MAAM,yBAAyB,EAAE,MAAoC,CAAC"}
@@ -86,6 +86,24 @@ export interface SlackContextData {
86
86
  * then won't re-trigger the highlight.
87
87
  */
88
88
  onHighlightConsumed?: () => void;
89
+ /**
90
+ * Multi-link (M2): the link row the notification originated from
91
+ * (`notification.metadata.linked_conversations[].linkId`). When present
92
+ * and still linked, the tab auto-opens THAT item before the message
93
+ * highlight runs — critical when two links are two threads in the SAME
94
+ * channel, where the channel name can't disambiguate. Treat as optional:
95
+ * older notifications won't carry it, and the tab then falls back to the
96
+ * cold-open default (decision D4).
97
+ */
98
+ highlightLinkId?: string;
99
+ /**
100
+ * Multi-link (M2, flag `rls-slack-multi-link` evaluated host-side):
101
+ * loads the multi-link UI — links-list switcher, link-existing flows,
102
+ * unlink, per-link unread. Default off (undefined) ⇒ the M1 single-link
103
+ * surfaces render and NOTHING new goes on the wire (no linkId/link_id
104
+ * anywhere), so old and new backends/UIs can coexist during rollout.
105
+ */
106
+ multiLinkEnabled?: boolean;
89
107
  /**
90
108
  * HIG UI layer: render the pinned "Channel:/URL:" band above the linked panel
91
109
  * (linked state only, thread + channel modes). Default off (undefined) — only
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/features/slack/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,EAAE,EAAE,SAAS,EAAc,MAAM,OAAO,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;IAClE;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACrH;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAErF,CAAC;AAKF,eAAO,MAAM,eAAe,QAAO,gBAMlC,CAAC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/features/slack/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,EAAE,EAAE,SAAS,EAAc,MAAM,OAAO,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;IAClE;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACrH;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAErF,CAAC;AAKF,eAAO,MAAM,eAAe,QAAO,gBAMlC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useMarkLinkRead.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMarkLinkRead.test.d.ts","sourceRoot":"","sources":["../../../../../src/features/slack/hooks/__tests__/useMarkLinkRead.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ interface UseMarkLinkReadArgs {
2
+ hiverConvId: string;
3
+ /** The link currently open in the panel; null = nothing viewed (the
4
+ * list view / flag off) — never fires. */
5
+ linkId: string | null;
6
+ /** True only when the surface is genuinely in front of the rep
7
+ * (`isActive` from the host — a display:none tab must not read). */
8
+ isViewed: boolean;
9
+ /** The viewed link's current unread count (from the links query).
10
+ * 0 → nothing to clear → no call (zero can be a legit bounded-cache
11
+ * value; firing anyway would just be a pointless POST). */
12
+ unreadCount: number;
13
+ /** Newest-activity marker for the viewed link. When it advances while
14
+ * the item stays visible (and unread rises), the read re-fires so
15
+ * the badge never sticks on an actively-watched conversation. */
16
+ lastActivityTs: string | null;
17
+ }
18
+ /**
19
+ * M2 mark-as-read (decision + contract hard rule): POST …/read fires ONLY
20
+ * when the rep actually views an item — never from a poll, prefetch, or a
21
+ * hidden surface. Clearing is optimistic: the viewed link's unreadCount
22
+ * zeroes in the links cache immediately (list badge, section rows, and
23
+ * the collated total all read from that one cache entry).
24
+ *
25
+ * Dedupe: one call per (linkId, lastActivityTs) pair — the effect re-runs
26
+ * on every links poll, but an already-marked position never re-posts.
27
+ * Browser-tab visibility is checked at call time; a hidden document
28
+ * defers to the next effect run (links keep polling, so the effect
29
+ * re-evaluates when the rep comes back and data has moved).
30
+ */
31
+ export declare function useMarkLinkRead({ hiverConvId, linkId, isViewed, unreadCount, lastActivityTs }: UseMarkLinkReadArgs): void;
32
+ export {};
33
+ //# sourceMappingURL=useMarkLinkRead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMarkLinkRead.d.ts","sourceRoot":"","sources":["../../../../src/features/slack/hooks/useMarkLinkRead.ts"],"names":[],"mappings":"AAOA,UAAU,mBAAmB;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB;+CAC2C;IAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;yEACqE;IACrE,QAAQ,EAAE,OAAO,CAAC;IAClB;;gEAE4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB;;sEAEkE;IAClE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE,mBAAmB,QA8ClH"}