@workos-inc/widgets 1.20.0-next.1791237372282 → 1.20.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.
@@ -5,10 +5,11 @@ const require_lib_use_is_hydrated = require("./lib/use-is-hydrated.cjs");
5
5
  const require_api_api_provider = require("./api/api-provider.cjs");
6
6
  const require_api_client_graphql_hooks = require("./api/client-graphql/hooks.cjs");
7
7
  const require_lib_error_boundary = require("./lib/error-boundary.cjs");
8
+ const require_lib_pipes_credential_attribution = require("./lib/pipes-credential-attribution.cjs");
8
9
  const require_lib_pipes_admin = require("./lib/pipes-admin.cjs");
9
10
  let react_jsx_runtime = require("react/jsx-runtime");
10
11
  //#region src/pipes-admin.client.tsx
11
- const PipesAdmin = ({ authToken, enableSharedConnections, ...domProps }) => {
12
+ const PipesAdmin = ({ authToken, userId, enableSharedConnections, ...domProps }) => {
12
13
  const baseUrl = require_lib_widgets_context.useWorkOsApiUrl();
13
14
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_error_boundary.ErrorBoundary, {
14
15
  fallbackRender: ({ error }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_pipes_admin.PipesAdminError, {
@@ -19,9 +20,12 @@ const PipesAdmin = ({ authToken, enableSharedConnections, ...domProps }) => {
19
20
  widgetType: "pipes-admin",
20
21
  authToken,
21
22
  baseUrl,
22
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PipesAdminImpl, {
23
- enableSharedConnections,
24
- ...domProps
23
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_pipes_credential_attribution.PipesCredentialUserIdContext.Provider, {
24
+ value: userId,
25
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PipesAdminImpl, {
26
+ enableSharedConnections,
27
+ ...domProps
28
+ })
25
29
  })
26
30
  })
27
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"pipes-admin.client.cjs","names":["useWorkOsApiUrl","ErrorBoundary","PipesAdminError","ApiProvider","useIsHydrated","useManageableIntegrations","PipesAdminLoading","PipesAdminPresentational","useOrganizationOwnedIntegrations","useClientGraphqlQuery","clientGraphqlQueryKey","PipesAdminSectionsPresentational"],"sources":["../../src/pipes-admin.client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken } from \"./api/api-provider.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport {\n PipesAdmin as PipesAdminPresentational,\n PipesAdminSections as PipesAdminSectionsPresentational,\n PipesAdminError,\n PipesAdminLoading,\n useManageableIntegrations,\n useOrganizationOwnedIntegrations,\n} from \"./lib/pipes-admin.js\";\nimport type {\n PipesAdminErrorProps,\n PipesAdminLoadingProps,\n} from \"./lib/pipes-admin.js\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlQuery,\n} from \"./api/client-graphql/hooks.js\";\nimport { useIsHydrated } from \"./lib/use-is-hydrated.js\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport { WidgetRootDomProps } from \"./lib/widget-types.js\";\n\ninterface PipesAdminProps extends WidgetRootDomProps {\n authToken: AuthToken;\n /**\n * Opt in to the sectioned administrator experience: the connections the\n * organization owns and shares with everyone (which the administrator can\n * configure, connect, reauthorize and disconnect), followed by the provider\n * settings that govern what members may connect to on their own.\n *\n * The two sections are fetched separately, so provider settings render as\n * soon as they resolve regardless of the shared section.\n *\n * Defaults to `false`, which renders the single unsectioned provider\n * settings list and never requests organization-owned connections.\n */\n enableSharedConnections?: boolean;\n}\n\nconst PipesAdmin: React.FC<PipesAdminProps> = ({\n authToken,\n enableSharedConnections,\n ...domProps\n}) => {\n const baseUrl = useWorkOsApiUrl();\n\n return (\n <ErrorBoundary\n fallbackRender={({ error }) => (\n <PipesAdminError {...domProps} error={error} />\n )}\n >\n <ApiProvider\n widgetType=\"pipes-admin\"\n authToken={authToken}\n baseUrl={baseUrl}\n >\n <PipesAdminImpl\n enableSharedConnections={enableSharedConnections}\n {...domProps}\n />\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\n// The two experiences are separate components so the opt-out path mounts no\n// organization-owned hook at all, and therefore issues exactly the requests it\n// always has.\nconst PipesAdminImpl = ({\n enableSharedConnections,\n ...props\n}: Omit<PipesAdminProps, \"authToken\">) => {\n return enableSharedConnections ? (\n <PipesAdminSectionsImpl {...props} />\n ) : (\n <PipesAdminProviderSettingsImpl {...props} />\n );\n};\n\ntype PipesAdminImplProps = Omit<\n PipesAdminProps,\n \"authToken\" | \"enableSharedConnections\"\n>;\n\nconst PipesAdminProviderSettingsImpl = (props: PipesAdminImplProps) => {\n const isHydrated = useIsHydrated();\n const integrations = useManageableIntegrations();\n\n if (!isHydrated || integrations.isLoading) {\n return <PipesAdminLoading count={6} {...props} />;\n }\n\n if (integrations.isError) {\n return <PipesAdminError error={integrations.error} {...props} />;\n }\n\n return (\n <PipesAdminPresentational integrations={integrations.data} {...props} />\n );\n};\n\nconst PipesAdminSectionsImpl = (props: PipesAdminImplProps) => {\n const isHydrated = useIsHydrated();\n const integrations = useManageableIntegrations();\n // Both sections have their own cache entry and resolve independently:\n // provider settings render as soon as they arrive, and a slow or failing\n // organization request only affects the shared section.\n const shared = useOrganizationOwnedIntegrations();\n const organizations = useClientGraphqlQuery({\n queryKey: clientGraphqlQueryKey(\"ListUserOrganizations\"),\n queryFn: (sdk) => sdk.ListUserOrganizations(),\n });\n const organizationName = organizations.data?.organizations.find(\n (organization) => organization.isCurrent,\n )?.name;\n\n if (!isHydrated || integrations.isLoading) {\n return <PipesAdminLoading count={6} {...props} />;\n }\n\n if (integrations.isError) {\n return <PipesAdminError error={integrations.error} {...props} />;\n }\n\n return (\n <PipesAdminSectionsPresentational\n integrations={integrations.data}\n sharedIntegrations={shared.data}\n isSharedLoading={shared.isLoading}\n organizationName={organizationName}\n {...props}\n />\n );\n};\n\nexport type { PipesAdminProps, PipesAdminLoadingProps, PipesAdminErrorProps };\nexport { PipesAdmin, PipesAdminLoading, PipesAdminError };\n"],"mappings":";;;;;;;;;;AAwCA,MAAM,cAAyC,EAC7C,WACA,yBACA,GAAG,eACC;CACJ,MAAM,UAAUA,4BAAAA,gBAAgB;CAEhC,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,2BAAAA,eAAD;EACE,iBAAiB,EAAE,YACjB,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,iBAAD;GAAiB,GAAI;GAAiB;EAAQ,CAAA;EAGhD,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,yBAAAA,aAAD;GACE,YAAW;GACA;GACF;GAET,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;IAC2B;IACzB,GAAI;GACL,CAAA;EACU,CAAA;CACA,CAAA;AAEnB;AAKA,MAAM,kBAAkB,EACtB,yBACA,GAAG,YACqC;CACxC,OAAO,0BACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,wBAAD,EAAwB,GAAI,MAAQ,CAAA,IAEpC,iBAAA,GAAA,kBAAA,IAAA,CAAC,gCAAD,EAAgC,GAAI,MAAQ,CAAA;AAEhD;AAOA,MAAM,kCAAkC,UAA+B;CACrE,MAAM,aAAaC,4BAAAA,cAAc;CACjC,MAAM,eAAeC,wBAAAA,0BAA0B;CAE/C,IAAI,CAAC,cAAc,aAAa,WAC9B,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,mBAAD;EAAmB,OAAO;EAAG,GAAI;CAAQ,CAAA;CAGlD,IAAI,aAAa,SACf,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACJ,wBAAAA,iBAAD;EAAiB,OAAO,aAAa;EAAO,GAAI;CAAQ,CAAA;CAGjE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACK,wBAAAA,YAAD;EAA0B,cAAc,aAAa;EAAM,GAAI;CAAQ,CAAA;AAE3E;AAEA,MAAM,0BAA0B,UAA+B;CAC7D,MAAM,aAAaH,4BAAAA,cAAc;CACjC,MAAM,eAAeC,wBAAAA,0BAA0B;CAI/C,MAAM,SAASG,wBAAAA,iCAAiC;CAKhD,MAAM,mBAJgBC,iCAAAA,sBAAsB;EAC1C,UAAUC,iCAAAA,sBAAsB,uBAAuB;EACvD,UAAU,QAAQ,IAAI,sBAAsB;CAC9C,CACyB,CAAA,CAAc,MAAM,cAAc,MACxD,iBAAiB,aAAa,SACjC,CAAC,EAAE;CAEH,IAAI,CAAC,cAAc,aAAa,WAC9B,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACJ,wBAAAA,mBAAD;EAAmB,OAAO;EAAG,GAAI;CAAQ,CAAA;CAGlD,IAAI,aAAa,SACf,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACJ,wBAAAA,iBAAD;EAAiB,OAAO,aAAa;EAAO,GAAI;CAAQ,CAAA;CAGjE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACS,wBAAAA,oBAAD;EACE,cAAc,aAAa;EAC3B,oBAAoB,OAAO;EAC3B,iBAAiB,OAAO;EACN;EAClB,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"pipes-admin.client.cjs","names":["useWorkOsApiUrl","ErrorBoundary","PipesAdminError","ApiProvider","PipesCredentialUserIdContext","useIsHydrated","useManageableIntegrations","PipesAdminLoading","PipesAdminPresentational","useOrganizationOwnedIntegrations","useClientGraphqlQuery","clientGraphqlQueryKey","PipesAdminSectionsPresentational"],"sources":["../../src/pipes-admin.client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken } from \"./api/api-provider.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport {\n PipesAdmin as PipesAdminPresentational,\n PipesAdminSections as PipesAdminSectionsPresentational,\n PipesAdminError,\n PipesAdminLoading,\n useManageableIntegrations,\n useOrganizationOwnedIntegrations,\n} from \"./lib/pipes-admin.js\";\nimport type {\n PipesAdminErrorProps,\n PipesAdminLoadingProps,\n} from \"./lib/pipes-admin.js\";\nimport {\n clientGraphqlQueryKey,\n useClientGraphqlQuery,\n} from \"./api/client-graphql/hooks.js\";\nimport { useIsHydrated } from \"./lib/use-is-hydrated.js\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport { WidgetRootDomProps } from \"./lib/widget-types.js\";\nimport { PipesCredentialUserIdContext } from \"./lib/pipes-credential-attribution.js\";\n\ninterface PipesAdminProps extends WidgetRootDomProps {\n authToken: AuthToken;\n /**\n * The acting person's WorkOS user ID for shared API-key and client-credentials\n * writes with an application credential token. Required for those writes only.\n * User-backed sessions use the authenticated user; a different ID is rejected.\n * This prop is not rendered and does not grant authorization. The API validates\n * identity and organization membership.\n */\n userId?: string;\n /**\n * Opt in to the sectioned administrator experience: the connections the\n * organization owns and shares with everyone (which the administrator can\n * configure, connect, reauthorize and disconnect), followed by the provider\n * settings that govern what members may connect to on their own.\n *\n * The two sections are fetched separately, so provider settings render as\n * soon as they resolve regardless of the shared section.\n *\n * Defaults to `false`, which renders the single unsectioned provider\n * settings list and never requests organization-owned connections.\n */\n enableSharedConnections?: boolean;\n}\n\nconst PipesAdmin: React.FC<PipesAdminProps> = ({\n authToken,\n userId,\n enableSharedConnections,\n ...domProps\n}) => {\n const baseUrl = useWorkOsApiUrl();\n\n return (\n <ErrorBoundary\n fallbackRender={({ error }) => (\n <PipesAdminError {...domProps} error={error} />\n )}\n >\n <ApiProvider\n widgetType=\"pipes-admin\"\n authToken={authToken}\n baseUrl={baseUrl}\n >\n <PipesCredentialUserIdContext.Provider value={userId}>\n <PipesAdminImpl\n enableSharedConnections={enableSharedConnections}\n {...domProps}\n />\n </PipesCredentialUserIdContext.Provider>\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\n// The two experiences are separate components so the opt-out path mounts no\n// organization-owned hook at all, and therefore issues exactly the requests it\n// always has.\nconst PipesAdminImpl = ({\n enableSharedConnections,\n ...props\n}: Omit<PipesAdminProps, \"authToken\" | \"userId\">) => {\n return enableSharedConnections ? (\n <PipesAdminSectionsImpl {...props} />\n ) : (\n <PipesAdminProviderSettingsImpl {...props} />\n );\n};\n\ntype PipesAdminImplProps = Omit<\n PipesAdminProps,\n \"authToken\" | \"enableSharedConnections\" | \"userId\"\n>;\n\nconst PipesAdminProviderSettingsImpl = (props: PipesAdminImplProps) => {\n const isHydrated = useIsHydrated();\n const integrations = useManageableIntegrations();\n\n if (!isHydrated || integrations.isLoading) {\n return <PipesAdminLoading count={6} {...props} />;\n }\n\n if (integrations.isError) {\n return <PipesAdminError error={integrations.error} {...props} />;\n }\n\n return (\n <PipesAdminPresentational integrations={integrations.data} {...props} />\n );\n};\n\nconst PipesAdminSectionsImpl = (props: PipesAdminImplProps) => {\n const isHydrated = useIsHydrated();\n const integrations = useManageableIntegrations();\n // Both sections have their own cache entry and resolve independently:\n // provider settings render as soon as they arrive, and a slow or failing\n // organization request only affects the shared section.\n const shared = useOrganizationOwnedIntegrations();\n const organizations = useClientGraphqlQuery({\n queryKey: clientGraphqlQueryKey(\"ListUserOrganizations\"),\n queryFn: (sdk) => sdk.ListUserOrganizations(),\n });\n const organizationName = organizations.data?.organizations.find(\n (organization) => organization.isCurrent,\n )?.name;\n\n if (!isHydrated || integrations.isLoading) {\n return <PipesAdminLoading count={6} {...props} />;\n }\n\n if (integrations.isError) {\n return <PipesAdminError error={integrations.error} {...props} />;\n }\n\n return (\n <PipesAdminSectionsPresentational\n integrations={integrations.data}\n sharedIntegrations={shared.data}\n isSharedLoading={shared.isLoading}\n organizationName={organizationName}\n {...props}\n />\n );\n};\n\nexport type { PipesAdminProps, PipesAdminLoadingProps, PipesAdminErrorProps };\nexport { PipesAdmin, PipesAdminLoading, PipesAdminError };\n"],"mappings":";;;;;;;;;;;AAiDA,MAAM,cAAyC,EAC7C,WACA,QACA,yBACA,GAAG,eACC;CACJ,MAAM,UAAUA,4BAAAA,gBAAgB;CAEhC,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,2BAAAA,eAAD;EACE,iBAAiB,EAAE,YACjB,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,iBAAD;GAAiB,GAAI;GAAiB;EAAQ,CAAA;EAGhD,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,yBAAAA,aAAD;GACE,YAAW;GACA;GACF;GAET,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,yCAAAA,6BAA6B,UAA9B;IAAuC,OAAO;IAC5C,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAD;KAC2B;KACzB,GAAI;IACL,CAAA;GACoC,CAAA;EAC5B,CAAA;CACA,CAAA;AAEnB;AAKA,MAAM,kBAAkB,EACtB,yBACA,GAAG,YACgD;CACnD,OAAO,0BACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,wBAAD,EAAwB,GAAI,MAAQ,CAAA,IAEpC,iBAAA,GAAA,kBAAA,IAAA,CAAC,gCAAD,EAAgC,GAAI,MAAQ,CAAA;AAEhD;AAOA,MAAM,kCAAkC,UAA+B;CACrE,MAAM,aAAaC,4BAAAA,cAAc;CACjC,MAAM,eAAeC,wBAAAA,0BAA0B;CAE/C,IAAI,CAAC,cAAc,aAAa,WAC9B,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,mBAAD;EAAmB,OAAO;EAAG,GAAI;CAAQ,CAAA;CAGlD,IAAI,aAAa,SACf,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACL,wBAAAA,iBAAD;EAAiB,OAAO,aAAa;EAAO,GAAI;CAAQ,CAAA;CAGjE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACM,wBAAAA,YAAD;EAA0B,cAAc,aAAa;EAAM,GAAI;CAAQ,CAAA;AAE3E;AAEA,MAAM,0BAA0B,UAA+B;CAC7D,MAAM,aAAaH,4BAAAA,cAAc;CACjC,MAAM,eAAeC,wBAAAA,0BAA0B;CAI/C,MAAM,SAASG,wBAAAA,iCAAiC;CAKhD,MAAM,mBAJgBC,iCAAAA,sBAAsB;EAC1C,UAAUC,iCAAAA,sBAAsB,uBAAuB;EACvD,UAAU,QAAQ,IAAI,sBAAsB;CAC9C,CACyB,CAAA,CAAc,MAAM,cAAc,MACxD,iBAAiB,aAAa,SACjC,CAAC,EAAE;CAEH,IAAI,CAAC,cAAc,aAAa,WAC9B,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACJ,wBAAAA,mBAAD;EAAmB,OAAO;EAAG,GAAI;CAAQ,CAAA;CAGlD,IAAI,aAAa,SACf,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAACL,wBAAAA,iBAAD;EAAiB,OAAO,aAAa;EAAO,GAAI;CAAQ,CAAA;CAGjE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACU,wBAAAA,oBAAD;EACE,cAAc,aAAa;EAC3B,oBAAoB,OAAO;EAC3B,iBAAiB,OAAO;EACN;EAClB,GAAI;CACL,CAAA;AAEL"}
@@ -4,6 +4,14 @@ import { PipesAdminError, PipesAdminErrorProps, PipesAdminLoading, PipesAdminLoa
4
4
  //#region src/pipes-admin.client.d.ts
5
5
  interface PipesAdminProps extends WidgetRootDomProps {
6
6
  authToken: AuthToken;
7
+ /**
8
+ * The acting person's WorkOS user ID for shared API-key and client-credentials
9
+ * writes with an application credential token. Required for those writes only.
10
+ * User-backed sessions use the authenticated user; a different ID is rejected.
11
+ * This prop is not rendered and does not grant authorization. The API validates
12
+ * identity and organization membership.
13
+ */
14
+ userId?: string;
7
15
  /**
8
16
  * Opt in to the sectioned administrator experience: the connections the
9
17
  * organization owns and shares with everyone (which the administrator can
@@ -1,9 +1,14 @@
1
1
  //#region src/api/claims.d.ts
2
2
  interface Claims {
3
- sid: string;
3
+ sid?: string;
4
+ sub?: string;
5
+ sub_type?: string;
6
+ sub_profile?: string;
7
+ auth_time?: number;
4
8
  permissions?: string[];
5
9
  exp?: number;
6
10
  }
11
+ export declare function getAuthenticatedUserId(claims: Claims): string | undefined;
7
12
  export declare function getClaims(accessToken: string): Claims;
8
13
  //#endregion
9
14
  //# sourceMappingURL=claims.d.ts.map
@@ -1,8 +1,11 @@
1
1
  //#region src/api/claims.ts
2
+ function getAuthenticatedUserId(claims) {
3
+ return (claims.sub_profile === void 0 || claims.sub_profile === "user") && (claims.sub_type === "authkit" || claims.sub_type === void 0 && !!claims.sid && typeof claims.auth_time === "number") && claims.sub?.startsWith("user_") ? claims.sub : void 0;
4
+ }
2
5
  function getClaims(accessToken) {
3
6
  return JSON.parse(atob(accessToken.split(".")[1]));
4
7
  }
5
8
  //#endregion
6
- export { getClaims };
9
+ export { getAuthenticatedUserId, getClaims };
7
10
 
8
11
  //# sourceMappingURL=claims.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claims.js","names":[],"sources":["../../../src/api/claims.ts"],"sourcesContent":["interface Claims {\n sid: string;\n permissions?: string[];\n exp?: number;\n}\n\nexport function getClaims(accessToken: string): Claims {\n return JSON.parse(atob(accessToken.split(\".\")[1]));\n}\n"],"mappings":";AAMA,SAAgB,UAAU,aAA6B;CACrD,OAAO,KAAK,MAAM,KAAK,YAAY,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AACnD"}
1
+ {"version":3,"file":"claims.js","names":[],"sources":["../../../src/api/claims.ts"],"sourcesContent":["interface Claims {\n sid?: string;\n sub?: string;\n sub_type?: string;\n sub_profile?: string;\n auth_time?: number;\n permissions?: string[];\n exp?: number;\n}\n\nexport function getAuthenticatedUserId(claims: Claims): string | undefined {\n const isUserSession =\n (claims.sub_profile === undefined || claims.sub_profile === \"user\") &&\n (claims.sub_type === \"authkit\" ||\n (claims.sub_type === undefined &&\n !!claims.sid &&\n typeof claims.auth_time === \"number\"));\n\n return isUserSession && claims.sub?.startsWith(\"user_\")\n ? claims.sub\n : undefined;\n}\n\nexport function getClaims(accessToken: string): Claims {\n return JSON.parse(atob(accessToken.split(\".\")[1]));\n}\n"],"mappings":";AAUA,SAAgB,uBAAuB,QAAoC;CAQzE,QANG,OAAO,gBAAgB,UAAa,OAAO,gBAAgB,YAC3D,OAAO,aAAa,aAClB,OAAO,aAAa,UACnB,CAAC,CAAC,OAAO,OACT,OAAO,OAAO,cAAc,aAEV,OAAO,KAAK,WAAW,OAAO,IAClD,OAAO,MACP;AACN;AAEA,SAAgB,UAAU,aAA6B;CACrD,OAAO,KAAK,MAAM,KAAK,YAAY,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AACnD"}
@@ -0,0 +1,8 @@
1
+ //#region src/lib/pipes-credential-attribution.d.ts
2
+ export declare const PipesCredentialUserIdContext: import("react").Context<string | undefined>;
3
+ export declare function usePipesCredentialAttribution(): {
4
+ userId: string | undefined;
5
+ error: string | undefined;
6
+ };
7
+ //#endregion
8
+ //# sourceMappingURL=pipes-credential-attribution.d.ts.map
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { useTranslation } from "./i18n/use-translation.js";
3
+ import { getAuthenticatedUserId, getClaims } from "../api/claims.js";
4
+ import { useApi } from "../api/api-provider.js";
5
+ import { createContext, useContext } from "react";
6
+ //#region src/lib/pipes-credential-attribution.tsx
7
+ const PipesCredentialUserIdContext = createContext(void 0);
8
+ function usePipesCredentialAttribution() {
9
+ const hostUserId = useContext(PipesCredentialUserIdContext)?.trim();
10
+ const { authToken } = useApi();
11
+ const translate = useTranslation();
12
+ const claims = authToken ? getClaims(authToken) : void 0;
13
+ const sessionUserId = claims && getAuthenticatedUserId(claims);
14
+ const userId = sessionUserId ?? (claims?.sub_type === "client_api_credential" && hostUserId?.startsWith("user_") ? hostUserId : void 0);
15
+ return {
16
+ userId,
17
+ error: sessionUserId && hostUserId && hostUserId !== sessionUserId ? translate({
18
+ defaultMessage: "Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.",
19
+ description: "Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user",
20
+ id: "pipesCredentialUserMismatch"
21
+ }) : !userId ? translate({
22
+ defaultMessage: "Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.",
23
+ description: "Configuration guidance for shared credential writes without an acting user; no user ID entry is requested",
24
+ id: "pipesCredentialUserRequired"
25
+ }) : void 0
26
+ };
27
+ }
28
+ //#endregion
29
+ export { PipesCredentialUserIdContext, usePipesCredentialAttribution };
30
+
31
+ //# sourceMappingURL=pipes-credential-attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipes-credential-attribution.js","names":[],"sources":["../../../src/lib/pipes-credential-attribution.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { useApi } from \"../api/api-provider.js\";\nimport { getAuthenticatedUserId, getClaims } from \"../api/claims.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\n\nexport const PipesCredentialUserIdContext = createContext<string | undefined>(\n undefined,\n);\n\nexport function usePipesCredentialAttribution() {\n const hostUserId = useContext(PipesCredentialUserIdContext)?.trim();\n const { authToken } = useApi();\n const translate = useTranslation();\n const claims = authToken ? getClaims(authToken) : undefined;\n const sessionUserId = claims && getAuthenticatedUserId(claims);\n const userId =\n sessionUserId ??\n (claims?.sub_type === \"client_api_credential\" &&\n hostUserId?.startsWith(\"user_\")\n ? hostUserId\n : undefined);\n\n const error =\n sessionUserId && hostUserId && hostUserId !== sessionUserId\n ? translate({\n defaultMessage:\n \"Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.\",\n description:\n \"Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user\",\n id: \"pipesCredentialUserMismatch\",\n })\n : !userId\n ? translate({\n defaultMessage:\n \"Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.\",\n description:\n \"Configuration guidance for shared credential writes without an acting user; no user ID entry is requested\",\n id: \"pipesCredentialUserRequired\",\n })\n : undefined;\n\n return { userId, error };\n}\n"],"mappings":";;;;;;AAOA,MAAa,+BAA+B,cAC1C,MACF;AAEA,SAAgB,gCAAgC;CAC9C,MAAM,aAAa,WAAW,4BAA4B,CAAC,EAAE,KAAK;CAClE,MAAM,EAAE,cAAc,OAAO;CAC7B,MAAM,YAAY,eAAe;CACjC,MAAM,SAAS,YAAY,UAAU,SAAS,IAAI;CAClD,MAAM,gBAAgB,UAAU,uBAAuB,MAAM;CAC7D,MAAM,SACJ,kBACC,QAAQ,aAAa,2BACtB,YAAY,WAAW,OAAO,IAC1B,aACA;CAqBN,OAAO;EAAE;EAAQ,OAlBf,iBAAiB,cAAc,eAAe,gBAC1C,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD,CAAC,SACC,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD;CAEe;AACzB"}
@@ -18,6 +18,7 @@ import { DataIntegrationIcon } from "./data-integration-icon.js";
18
18
  import { myDataIntegrationsQueryKeys, useInvalidateConnections } from "./api/pipes.js";
19
19
  import { ADD_CONNECTION, AddConnectionButtonLabel, ConnectAnotherAccountMenuLabel, ConnectionCountStatus, ConnectionNameField, RenameConnectionDialog, RenameMenuLabel, canRenameConnections, createAddConnectionTarget, getConnectionLabel, getConnectionTarget, toAccountDisplayNameInput, toConnectionTargetInput, toCreationTargetInput } from "./pipes-connections.js";
20
20
  import { buildRedactedSecret, isRedactedSecret } from "./redacted-secret.js";
21
+ import { usePipesCredentialAttribution } from "./pipes-credential-attribution.js";
21
22
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
22
23
  import { Callout, Card, Flex, Text } from "@radix-ui/themes";
23
24
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -744,6 +745,8 @@ const API_KEY_REDACTED_PREFIX = "••••";
744
745
  */
745
746
  function ApiKeyDialog({ integration, installation = integration.installation, owner = "user", target = getConnectionTarget(installation), open, onOpenChange, onSuccess, collectName = false }) {
746
747
  const invalidateConnections = useInvalidateConnections(owner);
748
+ const attribution = usePipesCredentialAttribution();
749
+ const attributionError = owner === "organization" ? attribution.error : void 0;
747
750
  const [name, setName] = useState("");
748
751
  const isRotation = installation?.auth_method === "api_key" && installation.state === "connected";
749
752
  const last4 = installation?.api_key_last_4;
@@ -775,8 +778,13 @@ function ApiKeyDialog({ integration, installation = integration.installation, ow
775
778
  ...toCreationTargetInput(target),
776
779
  ...collectName ? toAccountDisplayNameInput(name) : {}
777
780
  };
778
- if (owner === "organization") organizationUpsert.mutate(input);
779
- else userUpsert.mutate(input);
781
+ if (owner === "organization") {
782
+ if (attributionError || !attribution.userId) return;
783
+ organizationUpsert.mutate({
784
+ ...input,
785
+ userId: attribution.userId
786
+ });
787
+ } else userUpsert.mutate(input);
780
788
  };
781
789
  useEffect(() => {
782
790
  reset();
@@ -812,11 +820,11 @@ function ApiKeyDialog({ integration, installation = integration.installation, ow
812
820
  mt: "1",
813
821
  children: integration.description
814
822
  }),
815
- error && /* @__PURE__ */ jsx(Callout.Root, {
823
+ (attributionError || error) && /* @__PURE__ */ jsx(Callout.Root, {
816
824
  my: "3",
817
825
  color: "red",
818
826
  role: "alert",
819
- children: /* @__PURE__ */ jsx(Callout.Text, { children: errorMessage ?? /* @__PURE__ */ jsx(Translation, {
827
+ children: /* @__PURE__ */ jsx(Callout.Text, { children: attributionError ?? errorMessage ?? /* @__PURE__ */ jsx(Translation, {
820
828
  defaultMessage: "An error occurred. Please check the value and try again.",
821
829
  id: "bYLbLL",
822
830
  description: "Generic error message for API key submission failure"
@@ -878,7 +886,7 @@ function ApiKeyDialog({ integration, installation = integration.installation, ow
878
886
  })
879
887
  }) }), /* @__PURE__ */ jsx(Button$1, {
880
888
  type: "button",
881
- disabled: isPending || !secret.trim(),
889
+ disabled: !!attributionError || isPending || !secret.trim(),
882
890
  loading: isPending,
883
891
  onClick: () => upsertApiKey(secret.trim()),
884
892
  children: isRotation ? /* @__PURE__ */ jsx(Translation, {
@@ -929,6 +937,8 @@ function ApiKeyConnectButton({ integration }) {
929
937
  */
930
938
  function ClientCredentialsDialog({ integration, installation = integration.installation, owner = "user", target = getConnectionTarget(installation), fields, open, onOpenChange, onSuccess, collectName = false }) {
931
939
  const invalidateConnections = useInvalidateConnections(owner);
940
+ const attribution = usePipesCredentialAttribution();
941
+ const attributionError = owner === "organization" ? attribution.error : void 0;
932
942
  const [name, setName] = useState("");
933
943
  const isUpdate = installation?.auth_method === "client_credentials";
934
944
  const storedConfig = useMemo(() => isUpdate ? installation?.config ?? {} : {}, [isUpdate, installation?.config]);
@@ -971,6 +981,7 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
971
981
  const { error, isPending } = owner === "organization" ? organizationUpsert : userUpsert;
972
982
  const errorMessage = error instanceof ApiError && error.message ? error.message : null;
973
983
  const handleSubmit = () => {
984
+ if (attributionError) return;
974
985
  if (!configForm.validate()) return;
975
986
  const config = configForm.isDirty ? configForm.buildConfigPayload(storedConfig) : void 0;
976
987
  const input = {
@@ -981,8 +992,13 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
981
992
  ...toCreationTargetInput(target),
982
993
  ...collectName ? toAccountDisplayNameInput(name) : {}
983
994
  };
984
- if (owner === "organization") organizationUpsert.mutate(input);
985
- else userUpsert.mutate(input);
995
+ if (owner === "organization") {
996
+ if (!attribution.userId) return;
997
+ organizationUpsert.mutate({
998
+ ...input,
999
+ userId: attribution.userId
1000
+ });
1001
+ } else userUpsert.mutate(input);
986
1002
  };
987
1003
  return /* @__PURE__ */ jsx(Root$1, {
988
1004
  open,
@@ -1005,11 +1021,11 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
1005
1021
  values: { integrationName: integration.name }
1006
1022
  })
1007
1023
  }),
1008
- error && /* @__PURE__ */ jsx(Callout.Root, {
1024
+ (attributionError || error) && /* @__PURE__ */ jsx(Callout.Root, {
1009
1025
  my: "3",
1010
1026
  color: "red",
1011
1027
  role: "alert",
1012
- children: /* @__PURE__ */ jsx(Callout.Text, { children: errorMessage ?? /* @__PURE__ */ jsx(Translation, {
1028
+ children: /* @__PURE__ */ jsx(Callout.Text, { children: attributionError ?? errorMessage ?? /* @__PURE__ */ jsx(Translation, {
1013
1029
  defaultMessage: "An error occurred. Please check the value and try again.",
1014
1030
  id: "bYLbLL",
1015
1031
  description: "Generic error message for API key submission failure"
@@ -1105,7 +1121,7 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
1105
1121
  })
1106
1122
  }) }), /* @__PURE__ */ jsx(Button$1, {
1107
1123
  type: "button",
1108
- disabled: isPending || !clientId.trim() || secretMissing || configForm.hasMissingRequired,
1124
+ disabled: !!attributionError || isPending || !clientId.trim() || secretMissing || configForm.hasMissingRequired,
1109
1125
  loading: isPending,
1110
1126
  onClick: handleSubmit,
1111
1127
  children: isUpdate ? /* @__PURE__ */ jsx(Translation, {