@stigmer/react 3.1.8 → 3.1.9

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 (72) hide show
  1. package/environment/EnvironmentPicker.d.ts +17 -1
  2. package/environment/EnvironmentPicker.d.ts.map +1 -1
  3. package/environment/EnvironmentPicker.js +3 -2
  4. package/environment/EnvironmentPicker.js.map +1 -1
  5. package/index.d.ts +2 -2
  6. package/index.d.ts.map +1 -1
  7. package/index.js +2 -2
  8. package/index.js.map +1 -1
  9. package/package.json +4 -4
  10. package/sharing/ShareAgentDialog.d.ts +10 -8
  11. package/sharing/ShareAgentDialog.d.ts.map +1 -1
  12. package/sharing/ShareAgentDialog.js +139 -54
  13. package/sharing/ShareAgentDialog.js.map +1 -1
  14. package/sharing/SharedAgentChat.d.ts +1 -1
  15. package/sharing/SharedAgentChat.d.ts.map +1 -1
  16. package/sharing/index.d.ts +4 -2
  17. package/sharing/index.d.ts.map +1 -1
  18. package/sharing/index.js +2 -1
  19. package/sharing/index.js.map +1 -1
  20. package/sharing/useAgentShare.d.ts +43 -0
  21. package/sharing/useAgentShare.d.ts.map +1 -0
  22. package/sharing/useAgentShare.js +54 -0
  23. package/sharing/useAgentShare.js.map +1 -0
  24. package/sharing/useRotateShareLink.d.ts +22 -19
  25. package/sharing/useRotateShareLink.d.ts.map +1 -1
  26. package/sharing/useRotateShareLink.js +22 -19
  27. package/sharing/useRotateShareLink.js.map +1 -1
  28. package/sharing/useSaveAgentShare.d.ts +105 -0
  29. package/sharing/useSaveAgentShare.d.ts.map +1 -0
  30. package/sharing/useSaveAgentShare.js +97 -0
  31. package/sharing/useSaveAgentShare.js.map +1 -0
  32. package/sharing/useShareAgent.d.ts +5 -4
  33. package/sharing/useShareAgent.d.ts.map +1 -1
  34. package/sharing/useShareAgent.js +5 -4
  35. package/sharing/useShareAgent.js.map +1 -1
  36. package/sharing/useShareToolReadiness.d.ts +29 -25
  37. package/sharing/useShareToolReadiness.d.ts.map +1 -1
  38. package/sharing/useShareToolReadiness.js +47 -51
  39. package/sharing/useShareToolReadiness.js.map +1 -1
  40. package/sharing/useSharedAgentProfile.d.ts +5 -4
  41. package/sharing/useSharedAgentProfile.d.ts.map +1 -1
  42. package/sharing/useSharedAgentProfile.js +6 -5
  43. package/sharing/useSharedAgentProfile.js.map +1 -1
  44. package/src/environment/EnvironmentPicker.tsx +23 -2
  45. package/src/index.ts +8 -4
  46. package/src/sharing/ShareAgentDialog.tsx +353 -119
  47. package/src/sharing/SharedAgentChat.tsx +1 -1
  48. package/src/sharing/__tests__/ShareAgentDialog.test.tsx +550 -369
  49. package/src/sharing/__tests__/useAgentShare.test.tsx +149 -0
  50. package/src/sharing/__tests__/useRotateShareLink.test.tsx +8 -8
  51. package/src/sharing/__tests__/useSaveAgentShare.test.tsx +241 -0
  52. package/src/sharing/__tests__/useShareAgent.test.tsx +6 -2
  53. package/src/sharing/__tests__/useShareToolReadiness.test.tsx +84 -47
  54. package/src/sharing/__tests__/useSharedAgentProfile.test.tsx +1 -1
  55. package/src/sharing/index.ts +9 -7
  56. package/src/sharing/useAgentShare.ts +91 -0
  57. package/src/sharing/useRotateShareLink.ts +30 -25
  58. package/src/sharing/useSaveAgentShare.ts +186 -0
  59. package/src/sharing/useShareAgent.tsx +5 -4
  60. package/src/sharing/useShareToolReadiness.ts +62 -60
  61. package/src/sharing/useSharedAgentProfile.ts +7 -6
  62. package/src/switch/Switch.tsx +6 -1
  63. package/src/switch/__tests__/Switch.test.tsx +19 -0
  64. package/switch/Switch.d.ts.map +1 -1
  65. package/switch/Switch.js +6 -1
  66. package/switch/Switch.js.map +1 -1
  67. package/sharing/useUpdateAgentSharing.d.ts +0 -86
  68. package/sharing/useUpdateAgentSharing.d.ts.map +0 -1
  69. package/sharing/useUpdateAgentSharing.js +0 -81
  70. package/sharing/useUpdateAgentSharing.js.map +0 -1
  71. package/src/sharing/__tests__/useUpdateAgentSharing.test.tsx +0 -200
  72. package/src/sharing/useUpdateAgentSharing.ts +0 -151
@@ -69,9 +69,14 @@ export function Switch({
69
69
  onClick={() => onCheckedChange(!checked)}
70
70
  className={cn(
71
71
  // Track. `relative` anchors both the thumb and the expanded hit area.
72
+ // Off state uses the form-control token (`--stgm-input`), NOT
73
+ // `bg-muted`: muted matches the popover surface in dark presets, which
74
+ // made the track invisible inside dialogs. Both track fills are
75
+ // registered as surface pairs in the theme contrast contract
76
+ // (@stigmer/theme contract/pairs.ts), so every preset is audited.
72
77
  "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors",
73
78
  "motion-reduce:transition-none",
74
- checked ? "bg-primary" : "bg-muted",
79
+ checked ? "bg-primary" : "bg-input",
75
80
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
76
81
  "disabled:pointer-events-none disabled:opacity-50",
77
82
  // Expanded invisible hit area (~44px tall) for touch targets.
@@ -69,6 +69,25 @@ describe("Switch", () => {
69
69
  expect(onCheckedChange).not.toHaveBeenCalled();
70
70
  });
71
71
 
72
+ it("fills the track with the contract-audited surface tokens", () => {
73
+ // bg-input (off) / bg-primary (on) are registered as surface pairs in
74
+ // the @stigmer/theme contrast contract — bg-muted is NOT valid here (it
75
+ // matches the popover surface in dark presets, making the track
76
+ // invisible inside dialogs).
77
+ const { rerender } = render(
78
+ <Switch checked={false} onCheckedChange={() => {}} aria-label="Enable sharing" />,
79
+ );
80
+
81
+ const el = screen.getByRole("switch");
82
+ expect(el.className).toContain("bg-input");
83
+ expect(el.className).not.toContain("bg-muted");
84
+
85
+ rerender(
86
+ <Switch checked onCheckedChange={() => {}} aria-label="Enable sharing" />,
87
+ );
88
+ expect(el.className).toContain("bg-primary");
89
+ });
90
+
72
91
  it("supports aria-labelledby for external labels", () => {
73
92
  render(
74
93
  <>
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/switch/Switch.tsx"],"names":[],"mappings":"AAIA,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,eAAe,EACf,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,EAAE,EACF,SAAS,GACV,EAAE,WAAW,2CAiCb"}
1
+ {"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../src/switch/Switch.tsx"],"names":[],"mappings":"AAIA,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,eAAe,EACf,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,EAAE,EACF,SAAS,GACV,EAAE,WAAW,2CAsCb"}
package/switch/Switch.js CHANGED
@@ -29,7 +29,12 @@ import { cn } from "@stigmer/theme";
29
29
  export function Switch({ checked, onCheckedChange, disabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, id, className, }) {
30
30
  return (_jsx("button", { type: "button", role: "switch", id: id, "aria-checked": checked, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, disabled: disabled, onClick: () => onCheckedChange(!checked), className: cn(
31
31
  // Track. `relative` anchors both the thumb and the expanded hit area.
32
- "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors", "motion-reduce:transition-none", checked ? "bg-primary" : "bg-muted", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50",
32
+ // Off state uses the form-control token (`--stgm-input`), NOT
33
+ // `bg-muted`: muted matches the popover surface in dark presets, which
34
+ // made the track invisible inside dialogs. Both track fills are
35
+ // registered as surface pairs in the theme contrast contract
36
+ // (@stigmer/theme contract/pairs.ts), so every preset is audited.
37
+ "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors", "motion-reduce:transition-none", checked ? "bg-primary" : "bg-input", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50",
33
38
  // Expanded invisible hit area (~44px tall) for touch targets.
34
39
  "after:absolute after:-inset-3 after:content-['']", className), children: _jsx("span", { "aria-hidden": "true", className: cn("pointer-events-none block size-4 rounded-full bg-background shadow-sm transition-transform", "motion-reduce:transition-none", checked ? "translate-x-[18px]" : "translate-x-0.5") }) }));
35
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../src/switch/Switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAuBpC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,EACP,eAAe,EACf,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,EAAE,EACF,SAAS,GACG;IACZ,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,QAAQ,EACb,EAAE,EAAE,EAAE,kBACQ,OAAO,gBACT,SAAS,qBACJ,cAAc,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EACxC,SAAS,EAAE,EAAE;QACX,sEAAsE;QACtE,mFAAmF,EACnF,+BAA+B,EAC/B,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,EACnC,qGAAqG,EACrG,kDAAkD;QAClD,8DAA8D;QAC9D,kDAAkD,EAClD,SAAS,CACV,YAED,8BACc,MAAM,EAClB,SAAS,EAAE,EAAE,CACX,4FAA4F,EAC5F,+BAA+B,EAC/B,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,iBAAiB,CACnD,GACD,GACK,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../src/switch/Switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAuBpC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,EACP,eAAe,EACf,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,EAAE,EACF,SAAS,GACG;IACZ,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,QAAQ,EACb,EAAE,EAAE,EAAE,kBACQ,OAAO,gBACT,SAAS,qBACJ,cAAc,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EACxC,SAAS,EAAE,EAAE;QACX,sEAAsE;QACtE,8DAA8D;QAC9D,uEAAuE;QACvE,gEAAgE;QAChE,6DAA6D;QAC7D,kEAAkE;QAClE,mFAAmF,EACnF,+BAA+B,EAC/B,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,EACnC,qGAAqG,EACrG,kDAAkD;QAClD,8DAA8D;QAC9D,kDAAkD,EAClD,SAAS,CACV,YAED,8BACc,MAAM,EAClB,SAAS,EAAE,EAAE,CACX,4FAA4F,EAC5F,+BAA+B,EAC/B,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,iBAAiB,CACnD,GACD,GACK,CACV,CAAC;AACJ,CAAC"}
@@ -1,86 +0,0 @@
1
- import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
2
- import { AgentSharingAudience } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
3
- /**
4
- * Who can chat with a shared agent over its hosted link.
5
- *
6
- * - `"public"` — anyone with the link; visitors are anonymous guests.
7
- * - `"org"` — signed-in members of the owning organization only.
8
- * Membership is checked on every conversation turn, so access ends the
9
- * moment a member leaves the org.
10
- */
11
- export type SharingAudience = "public" | "org";
12
- /**
13
- * A complete sharing configuration to persist.
14
- *
15
- * Every field is required by design: the `updateSharing` RPC **replaces**
16
- * the agent's whole `spec.sharing` block, so a caller must always supply
17
- * the full configuration. A partial type here would let a toggle change
18
- * silently wipe `allowedOrigins`, `messages`, or the `audience` — the
19
- * required shape makes that mistake unrepresentable.
20
- */
21
- export interface AgentSharingDraft {
22
- /** Whether hosted-chat access for the configured audience is enabled. */
23
- readonly enabled: boolean;
24
- /** Who can chat: anyone with the link, or org members only. */
25
- readonly audience: SharingAudience;
26
- /**
27
- * Exact web origins allowed to embed the shared agent
28
- * (e.g. `https://example.com`). Stored now; enforced by the embed
29
- * widget's Origin check. Embedding is public-audience only.
30
- */
31
- readonly allowedOrigins: readonly string[];
32
- /** Owner-customized visitor refusal copy. Empty strings mean platform defaults. */
33
- readonly messages: {
34
- /** Shown when a visitor exceeds the message rate limit. */
35
- readonly rateLimited: string;
36
- /** Shown when the org's credits are exhausted (sharing fails closed). */
37
- readonly unavailable: string;
38
- /** Shown when a conversation hits its turn limit or inactivity timeout. */
39
- readonly conversationEnded: string;
40
- };
41
- }
42
- /**
43
- * Maps a proto {@link AgentSharingAudience} to the SDK's string union.
44
- * Unspecified means public by contract (pre-audience shares keep their
45
- * anyone-with-link behavior).
46
- */
47
- export declare function sharingAudienceFromProto(audience: AgentSharingAudience | undefined): SharingAudience;
48
- /** Return value of {@link useUpdateAgentSharing}. */
49
- export interface UseUpdateAgentSharingReturn {
50
- /**
51
- * Persist the complete sharing configuration via the `updateSharing`
52
- * RPC. Resolves with the updated agent.
53
- */
54
- readonly updateSharing: (draft: AgentSharingDraft) => Promise<Agent | undefined>;
55
- /** `true` while the RPC is in flight. */
56
- readonly isPending: boolean;
57
- /** The last error from the RPC, or `null`. */
58
- readonly error: Error | null;
59
- }
60
- /**
61
- * Behavior hook that updates an agent's sharing configuration.
62
- *
63
- * Wraps the targeted `stigmer.agent.updateSharing()` RPC (authorized by
64
- * `can_edit`) with loading and error state management. The hook is
65
- * stateless with respect to the agent — the caller refreshes the resource
66
- * after a successful update (e.g. via `refetch` from `useAgent`), matching
67
- * the {@link useUpdateVisibility} convention.
68
- *
69
- * Pass `null` for `agentId` to produce a stable no-op (useful while the
70
- * agent is still loading).
71
- *
72
- * @example
73
- * ```tsx
74
- * const { updateSharing, isPending } = useUpdateAgentSharing(agent.metadata.id);
75
- *
76
- * await updateSharing({
77
- * enabled: true,
78
- * audience: "public",
79
- * allowedOrigins: ["https://example.com"],
80
- * messages: { rateLimited: "", unavailable: "", conversationEnded: "" },
81
- * });
82
- * refetch();
83
- * ```
84
- */
85
- export declare function useUpdateAgentSharing(agentId: string | null): UseUpdateAgentSharingReturn;
86
- //# sourceMappingURL=useUpdateAgentSharing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useUpdateAgentSharing.d.ts","sourceRoot":"","sources":["../../src/sharing/useUpdateAgentSharing.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oDAAoD,CAAC;AAEhF,OAAO,EACL,oBAAoB,EAGrB,MAAM,qDAAqD,CAAC;AAI7D;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE;QACjB,2DAA2D;QAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,yEAAyE;QACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,2EAA2E;QAC3E,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;KACpC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GACzC,eAAe,CAEjB;AAQD,qDAAqD;AACrD,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IACjF,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,2BAA2B,CAsC7B"}
@@ -1,81 +0,0 @@
1
- "use client";
2
- import { useCallback, useState } from "react";
3
- import { create } from "@bufbuild/protobuf";
4
- import { UpdateAgentSharingInputSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/io_pb";
5
- import { AgentSharingAudience, AgentSharingSchema, AgentSharingMessagesSchema, } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
6
- import { useStigmer } from "../hooks.js";
7
- import { toError } from "../internal/toError.js";
8
- /**
9
- * Maps a proto {@link AgentSharingAudience} to the SDK's string union.
10
- * Unspecified means public by contract (pre-audience shares keep their
11
- * anyone-with-link behavior).
12
- */
13
- export function sharingAudienceFromProto(audience) {
14
- return audience === AgentSharingAudience.org ? "org" : "public";
15
- }
16
- function sharingAudienceToProto(audience) {
17
- return audience === "org"
18
- ? AgentSharingAudience.org
19
- : AgentSharingAudience.public;
20
- }
21
- /**
22
- * Behavior hook that updates an agent's sharing configuration.
23
- *
24
- * Wraps the targeted `stigmer.agent.updateSharing()` RPC (authorized by
25
- * `can_edit`) with loading and error state management. The hook is
26
- * stateless with respect to the agent — the caller refreshes the resource
27
- * after a successful update (e.g. via `refetch` from `useAgent`), matching
28
- * the {@link useUpdateVisibility} convention.
29
- *
30
- * Pass `null` for `agentId` to produce a stable no-op (useful while the
31
- * agent is still loading).
32
- *
33
- * @example
34
- * ```tsx
35
- * const { updateSharing, isPending } = useUpdateAgentSharing(agent.metadata.id);
36
- *
37
- * await updateSharing({
38
- * enabled: true,
39
- * audience: "public",
40
- * allowedOrigins: ["https://example.com"],
41
- * messages: { rateLimited: "", unavailable: "", conversationEnded: "" },
42
- * });
43
- * refetch();
44
- * ```
45
- */
46
- export function useUpdateAgentSharing(agentId) {
47
- const stigmer = useStigmer();
48
- const [isPending, setIsPending] = useState(false);
49
- const [error, setError] = useState(null);
50
- const updateSharing = useCallback(async (draft) => {
51
- if (!agentId)
52
- return undefined;
53
- setIsPending(true);
54
- setError(null);
55
- try {
56
- const input = create(UpdateAgentSharingInputSchema, {
57
- resourceId: agentId,
58
- sharing: create(AgentSharingSchema, {
59
- enabled: draft.enabled,
60
- audience: sharingAudienceToProto(draft.audience),
61
- allowedOrigins: [...draft.allowedOrigins],
62
- messages: create(AgentSharingMessagesSchema, {
63
- rateLimited: draft.messages.rateLimited,
64
- unavailable: draft.messages.unavailable,
65
- conversationEnded: draft.messages.conversationEnded,
66
- }),
67
- }),
68
- });
69
- return await stigmer.agent.updateSharing(input);
70
- }
71
- catch (err) {
72
- setError(toError(err));
73
- throw err;
74
- }
75
- finally {
76
- setIsPending(false);
77
- }
78
- }, [agentId, stigmer]);
79
- return { updateSharing, isPending, error };
80
- }
81
- //# sourceMappingURL=useUpdateAgentSharing.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useUpdateAgentSharing.js","sourceRoot":"","sources":["../../src/sharing/useUpdateAgentSharing.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AA2CjD;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA0C;IAE1C,OAAO,QAAQ,KAAK,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClE,CAAC;AAED,SAAS,sBAAsB,CAAC,QAAyB;IACvD,OAAO,QAAQ,KAAK,KAAK;QACvB,CAAC,CAAC,oBAAoB,CAAC,GAAG;QAC1B,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC;AAClC,CAAC;AAeD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAsB;IAEtB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,MAAM,aAAa,GAAG,WAAW,CAC/B,KAAK,EAAE,KAAwB,EAA8B,EAAE;QAC7D,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAE/B,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEf,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,CAAC,6BAA6B,EAAE;gBAClD,UAAU,EAAE,OAAO;gBACnB,OAAO,EAAE,MAAM,CAAC,kBAAkB,EAAE;oBAClC,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,QAAQ,EAAE,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC;oBAChD,cAAc,EAAE,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC;oBACzC,QAAQ,EAAE,MAAM,CAAC,0BAA0B,EAAE;wBAC3C,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;wBACvC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;wBACvC,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,iBAAiB;qBACpD,CAAC;iBACH,CAAC;aACH,CAAC,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YACvB,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,EACD,CAAC,OAAO,EAAE,OAAO,CAAC,CACnB,CAAC;IAEF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC7C,CAAC"}
@@ -1,200 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { renderHook, act, waitFor } from "@testing-library/react";
3
- import type { ReactNode } from "react";
4
- import type { UpdateAgentSharingInput } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/io_pb";
5
- import { AgentSharingAudience } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
6
- import { StigmerContext } from "../../context";
7
- import {
8
- sharingAudienceFromProto,
9
- useUpdateAgentSharing,
10
- type AgentSharingDraft,
11
- } from "../useUpdateAgentSharing";
12
-
13
- function createMockStigmer(overrides: {
14
- updateSharing?: (input: UpdateAgentSharingInput) => Promise<unknown>;
15
- } = {}) {
16
- return {
17
- agent: {
18
- updateSharing:
19
- overrides.updateSharing ?? vi.fn().mockResolvedValue({}),
20
- },
21
- } as never;
22
- }
23
-
24
- function wrapper(client: unknown) {
25
- return function Wrapper({ children }: { children: ReactNode }) {
26
- return (
27
- <StigmerContext.Provider value={client as never}>
28
- {children}
29
- </StigmerContext.Provider>
30
- );
31
- };
32
- }
33
-
34
- const FULL_DRAFT: AgentSharingDraft = {
35
- enabled: true,
36
- audience: "public",
37
- allowedOrigins: ["https://example.com", "https://docs.example.com"],
38
- messages: {
39
- rateLimited: "Slow down, please.",
40
- unavailable: "We're out of credits.",
41
- conversationEnded: "This conversation has ended.",
42
- },
43
- };
44
-
45
- describe("useUpdateAgentSharing", () => {
46
- beforeEach(() => {
47
- vi.restoreAllMocks();
48
- });
49
-
50
- it("sends the complete sharing block — enabled, origins, and messages", async () => {
51
- const updateSharing = vi.fn().mockResolvedValue({});
52
- const client = createMockStigmer({ updateSharing });
53
-
54
- const { result } = renderHook(() => useUpdateAgentSharing("agt_1"), {
55
- wrapper: wrapper(client),
56
- });
57
-
58
- await act(() => result.current.updateSharing(FULL_DRAFT));
59
-
60
- expect(updateSharing).toHaveBeenCalledTimes(1);
61
- const input = updateSharing.mock.calls[0][0] as UpdateAgentSharingInput;
62
- expect(input.resourceId).toBe("agt_1");
63
- expect(input.sharing?.enabled).toBe(true);
64
- expect(input.sharing?.allowedOrigins).toEqual([
65
- "https://example.com",
66
- "https://docs.example.com",
67
- ]);
68
- expect(input.sharing?.messages?.rateLimited).toBe("Slow down, please.");
69
- expect(input.sharing?.messages?.unavailable).toBe("We're out of credits.");
70
- expect(input.sharing?.messages?.conversationEnded).toBe(
71
- "This conversation has ended.",
72
- );
73
- });
74
-
75
- it("disabling still carries origins, messages, and audience (toggle never clobbers config)", async () => {
76
- const updateSharing = vi.fn().mockResolvedValue({});
77
- const client = createMockStigmer({ updateSharing });
78
-
79
- const { result } = renderHook(() => useUpdateAgentSharing("agt_1"), {
80
- wrapper: wrapper(client),
81
- });
82
-
83
- await act(() =>
84
- result.current.updateSharing({
85
- ...FULL_DRAFT,
86
- enabled: false,
87
- audience: "org",
88
- }),
89
- );
90
-
91
- const input = updateSharing.mock.calls[0][0] as UpdateAgentSharingInput;
92
- expect(input.sharing?.enabled).toBe(false);
93
- // The RPC replaces spec.sharing wholesale — a disable that dropped
94
- // these fields would silently erase the owner's configuration (an
95
- // audience drop would silently revert an org-only agent to public).
96
- expect(input.sharing?.allowedOrigins).toEqual(FULL_DRAFT.allowedOrigins);
97
- expect(input.sharing?.messages?.rateLimited).toBe(
98
- FULL_DRAFT.messages.rateLimited,
99
- );
100
- expect(input.sharing?.audience).toBe(AgentSharingAudience.org);
101
- });
102
-
103
- it("maps the audience union to the proto enum, writing public explicitly", async () => {
104
- const updateSharing = vi.fn().mockResolvedValue({});
105
- const client = createMockStigmer({ updateSharing });
106
-
107
- const { result } = renderHook(() => useUpdateAgentSharing("agt_1"), {
108
- wrapper: wrapper(client),
109
- });
110
-
111
- await act(() => result.current.updateSharing(FULL_DRAFT));
112
- await act(() =>
113
- result.current.updateSharing({ ...FULL_DRAFT, audience: "org" }),
114
- );
115
-
116
- const first = updateSharing.mock.calls[0][0] as UpdateAgentSharingInput;
117
- const second = updateSharing.mock.calls[1][0] as UpdateAgentSharingInput;
118
- // "public" persists as the explicit enum value, never unspecified —
119
- // a console-managed share can't be downgraded by a later manifest
120
- // that relies on the unspecified-means-public default.
121
- expect(first.sharing?.audience).toBe(AgentSharingAudience.public);
122
- expect(second.sharing?.audience).toBe(AgentSharingAudience.org);
123
- });
124
-
125
- it("is a stable no-op when agentId is null", async () => {
126
- const updateSharing = vi.fn();
127
- const client = createMockStigmer({ updateSharing });
128
-
129
- const { result } = renderHook(() => useUpdateAgentSharing(null), {
130
- wrapper: wrapper(client),
131
- });
132
-
133
- const returned = await act(() => result.current.updateSharing(FULL_DRAFT));
134
- expect(returned).toBeUndefined();
135
- expect(updateSharing).not.toHaveBeenCalled();
136
- });
137
-
138
- it("exposes isPending during the request", async () => {
139
- let resolveRpc: (v: unknown) => void = () => {};
140
- const updateSharing = vi.fn().mockReturnValue(
141
- new Promise((resolve) => {
142
- resolveRpc = resolve;
143
- }),
144
- );
145
- const client = createMockStigmer({ updateSharing });
146
-
147
- const { result } = renderHook(() => useUpdateAgentSharing("agt_1"), {
148
- wrapper: wrapper(client),
149
- });
150
-
151
- let pending: Promise<unknown>;
152
- act(() => {
153
- pending = result.current.updateSharing(FULL_DRAFT);
154
- });
155
- expect(result.current.isPending).toBe(true);
156
-
157
- await act(async () => {
158
- resolveRpc({});
159
- await pending;
160
- });
161
- expect(result.current.isPending).toBe(false);
162
- });
163
-
164
- it("captures and rethrows RPC errors", async () => {
165
- const failure = new Error("permission denied");
166
- const updateSharing = vi.fn().mockRejectedValue(failure);
167
- const client = createMockStigmer({ updateSharing });
168
-
169
- const { result } = renderHook(() => useUpdateAgentSharing("agt_1"), {
170
- wrapper: wrapper(client),
171
- });
172
-
173
- let caught: unknown;
174
- await act(async () => {
175
- try {
176
- await result.current.updateSharing(FULL_DRAFT);
177
- } catch (err) {
178
- caught = err;
179
- }
180
- });
181
-
182
- expect(caught).toBe(failure);
183
- await waitFor(() => expect(result.current.error).toBe(failure));
184
- expect(result.current.isPending).toBe(false);
185
- });
186
- });
187
-
188
- describe("sharingAudienceFromProto", () => {
189
- it("maps unspecified to public (pre-audience shares keep their behavior)", () => {
190
- expect(sharingAudienceFromProto(undefined)).toBe("public");
191
- expect(sharingAudienceFromProto(AgentSharingAudience.unspecified)).toBe(
192
- "public",
193
- );
194
- });
195
-
196
- it("maps the explicit values", () => {
197
- expect(sharingAudienceFromProto(AgentSharingAudience.public)).toBe("public");
198
- expect(sharingAudienceFromProto(AgentSharingAudience.org)).toBe("org");
199
- });
200
- });
@@ -1,151 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useState } from "react";
4
- import { create } from "@bufbuild/protobuf";
5
- import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
6
- import { UpdateAgentSharingInputSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/io_pb";
7
- import {
8
- AgentSharingAudience,
9
- AgentSharingSchema,
10
- AgentSharingMessagesSchema,
11
- } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
12
- import { useStigmer } from "../hooks.js";
13
- import { toError } from "../internal/toError.js";
14
-
15
- /**
16
- * Who can chat with a shared agent over its hosted link.
17
- *
18
- * - `"public"` — anyone with the link; visitors are anonymous guests.
19
- * - `"org"` — signed-in members of the owning organization only.
20
- * Membership is checked on every conversation turn, so access ends the
21
- * moment a member leaves the org.
22
- */
23
- export type SharingAudience = "public" | "org";
24
-
25
- /**
26
- * A complete sharing configuration to persist.
27
- *
28
- * Every field is required by design: the `updateSharing` RPC **replaces**
29
- * the agent's whole `spec.sharing` block, so a caller must always supply
30
- * the full configuration. A partial type here would let a toggle change
31
- * silently wipe `allowedOrigins`, `messages`, or the `audience` — the
32
- * required shape makes that mistake unrepresentable.
33
- */
34
- export interface AgentSharingDraft {
35
- /** Whether hosted-chat access for the configured audience is enabled. */
36
- readonly enabled: boolean;
37
- /** Who can chat: anyone with the link, or org members only. */
38
- readonly audience: SharingAudience;
39
- /**
40
- * Exact web origins allowed to embed the shared agent
41
- * (e.g. `https://example.com`). Stored now; enforced by the embed
42
- * widget's Origin check. Embedding is public-audience only.
43
- */
44
- readonly allowedOrigins: readonly string[];
45
- /** Owner-customized visitor refusal copy. Empty strings mean platform defaults. */
46
- readonly messages: {
47
- /** Shown when a visitor exceeds the message rate limit. */
48
- readonly rateLimited: string;
49
- /** Shown when the org's credits are exhausted (sharing fails closed). */
50
- readonly unavailable: string;
51
- /** Shown when a conversation hits its turn limit or inactivity timeout. */
52
- readonly conversationEnded: string;
53
- };
54
- }
55
-
56
- /**
57
- * Maps a proto {@link AgentSharingAudience} to the SDK's string union.
58
- * Unspecified means public by contract (pre-audience shares keep their
59
- * anyone-with-link behavior).
60
- */
61
- export function sharingAudienceFromProto(
62
- audience: AgentSharingAudience | undefined,
63
- ): SharingAudience {
64
- return audience === AgentSharingAudience.org ? "org" : "public";
65
- }
66
-
67
- function sharingAudienceToProto(audience: SharingAudience): AgentSharingAudience {
68
- return audience === "org"
69
- ? AgentSharingAudience.org
70
- : AgentSharingAudience.public;
71
- }
72
-
73
- /** Return value of {@link useUpdateAgentSharing}. */
74
- export interface UseUpdateAgentSharingReturn {
75
- /**
76
- * Persist the complete sharing configuration via the `updateSharing`
77
- * RPC. Resolves with the updated agent.
78
- */
79
- readonly updateSharing: (draft: AgentSharingDraft) => Promise<Agent | undefined>;
80
- /** `true` while the RPC is in flight. */
81
- readonly isPending: boolean;
82
- /** The last error from the RPC, or `null`. */
83
- readonly error: Error | null;
84
- }
85
-
86
- /**
87
- * Behavior hook that updates an agent's sharing configuration.
88
- *
89
- * Wraps the targeted `stigmer.agent.updateSharing()` RPC (authorized by
90
- * `can_edit`) with loading and error state management. The hook is
91
- * stateless with respect to the agent — the caller refreshes the resource
92
- * after a successful update (e.g. via `refetch` from `useAgent`), matching
93
- * the {@link useUpdateVisibility} convention.
94
- *
95
- * Pass `null` for `agentId` to produce a stable no-op (useful while the
96
- * agent is still loading).
97
- *
98
- * @example
99
- * ```tsx
100
- * const { updateSharing, isPending } = useUpdateAgentSharing(agent.metadata.id);
101
- *
102
- * await updateSharing({
103
- * enabled: true,
104
- * audience: "public",
105
- * allowedOrigins: ["https://example.com"],
106
- * messages: { rateLimited: "", unavailable: "", conversationEnded: "" },
107
- * });
108
- * refetch();
109
- * ```
110
- */
111
- export function useUpdateAgentSharing(
112
- agentId: string | null,
113
- ): UseUpdateAgentSharingReturn {
114
- const stigmer = useStigmer();
115
- const [isPending, setIsPending] = useState(false);
116
- const [error, setError] = useState<Error | null>(null);
117
-
118
- const updateSharing = useCallback(
119
- async (draft: AgentSharingDraft): Promise<Agent | undefined> => {
120
- if (!agentId) return undefined;
121
-
122
- setIsPending(true);
123
- setError(null);
124
-
125
- try {
126
- const input = create(UpdateAgentSharingInputSchema, {
127
- resourceId: agentId,
128
- sharing: create(AgentSharingSchema, {
129
- enabled: draft.enabled,
130
- audience: sharingAudienceToProto(draft.audience),
131
- allowedOrigins: [...draft.allowedOrigins],
132
- messages: create(AgentSharingMessagesSchema, {
133
- rateLimited: draft.messages.rateLimited,
134
- unavailable: draft.messages.unavailable,
135
- conversationEnded: draft.messages.conversationEnded,
136
- }),
137
- }),
138
- });
139
- return await stigmer.agent.updateSharing(input);
140
- } catch (err) {
141
- setError(toError(err));
142
- throw err;
143
- } finally {
144
- setIsPending(false);
145
- }
146
- },
147
- [agentId, stigmer],
148
- );
149
-
150
- return { updateSharing, isPending, error };
151
- }