@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.
- package/CHANGELOG.md +3 -1
- package/README.md +44 -0
- package/dist/cjs/api/claims.cjs +4 -0
- package/dist/cjs/api/claims.cjs.map +1 -1
- package/dist/cjs/api/claims.d.cts +6 -1
- package/dist/cjs/lib/pipes-credential-attribution.cjs +33 -0
- package/dist/cjs/lib/pipes-credential-attribution.cjs.map +1 -0
- package/dist/cjs/lib/pipes-credential-attribution.d.cts +8 -0
- package/dist/cjs/lib/pipes.cjs +26 -10
- package/dist/cjs/lib/pipes.cjs.map +1 -1
- package/dist/cjs/pipes-admin.client.cjs +8 -4
- package/dist/cjs/pipes-admin.client.cjs.map +1 -1
- package/dist/cjs/pipes-admin.client.d.cts +8 -0
- package/dist/esm/api/claims.d.ts +6 -1
- package/dist/esm/api/claims.js +4 -1
- package/dist/esm/api/claims.js.map +1 -1
- package/dist/esm/lib/pipes-credential-attribution.d.ts +8 -0
- package/dist/esm/lib/pipes-credential-attribution.js +31 -0
- package/dist/esm/lib/pipes-credential-attribution.js.map +1 -0
- package/dist/esm/lib/pipes.js +26 -10
- package/dist/esm/lib/pipes.js.map +1 -1
- package/dist/esm/pipes-admin.client.d.ts +8 -0
- package/dist/esm/pipes-admin.client.js +8 -4
- package/dist/esm/pipes-admin.client.js.map +1 -1
- package/package.json +1 -1
|
@@ -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)(
|
|
23
|
-
|
|
24
|
-
|
|
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
|
|
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
|
package/dist/esm/api/claims.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
//#region src/api/claims.d.ts
|
|
2
2
|
interface Claims {
|
|
3
|
-
sid
|
|
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
|
package/dist/esm/api/claims.js
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/esm/lib/pipes.js
CHANGED
|
@@ -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")
|
|
779
|
-
|
|
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")
|
|
985
|
-
|
|
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, {
|