@iqauth/sdk 2.6.4 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +173 -1
  2. package/dist/browser-session.d.mts +4 -4
  3. package/dist/browser-session.d.ts +4 -4
  4. package/dist/browser-session.js +181 -41
  5. package/dist/browser-session.mjs +3 -3
  6. package/dist/browser.d.mts +5 -5
  7. package/dist/browser.d.ts +5 -5
  8. package/dist/browser.js +271 -32
  9. package/dist/browser.mjs +5 -5
  10. package/dist/{chunk-6I6RM4MN.mjs → chunk-6PJRLRB4.mjs} +33 -3
  11. package/dist/{chunk-LIZYFXH7.mjs → chunk-DFWHSDYQ.mjs} +1 -1
  12. package/dist/chunk-GLXSIGVS.mjs +66 -0
  13. package/dist/{chunk-DJIBN2N7.mjs → chunk-GN37E64I.mjs} +29 -7
  14. package/dist/{chunk-WQWBJSSS.mjs → chunk-HVHNYPDC.mjs} +6 -6
  15. package/dist/{chunk-W3F4JYGP.mjs → chunk-JXQI62A7.mjs} +108 -18
  16. package/dist/{chunk-UNYDG2L4.mjs → chunk-NUO2I65G.mjs} +56 -23
  17. package/dist/chunk-PMAFENVI.mjs +229 -0
  18. package/dist/chunk-RR2MGPTK.mjs +2724 -0
  19. package/dist/{chunk-XAWYUPMO.mjs → chunk-RTJAIBXY.mjs} +220 -20
  20. package/dist/{chunk-6TDJJER7.mjs → chunk-RUJXRTEW.mjs} +164 -5
  21. package/dist/{chunk-3JULWS6F.mjs → chunk-WCELYTJ3.mjs} +3 -3
  22. package/dist/{chunk-MKKZULZR.mjs → chunk-WIFG74IK.mjs} +1 -1
  23. package/dist/{chunk-BVV54LPI.mjs → chunk-YVALAG3B.mjs} +10 -4
  24. package/dist/cli/index.js +2 -2
  25. package/dist/cli/index.mjs +2 -2
  26. package/dist/{client-kYlJFgPv.d.mts → client-BGFnBpfc.d.mts} +47 -4
  27. package/dist/{client-BNQe3AgF.d.ts → client-CDQ21LvW.d.ts} +47 -4
  28. package/dist/{doctor-YYNHNMLD.mjs → doctor-JAFXWU3X.mjs} +2 -2
  29. package/dist/errors-Jl1Jtm-6.d.mts +107 -0
  30. package/dist/errors-Jl1Jtm-6.d.ts +107 -0
  31. package/dist/{express-B6_1vBYZ.d.mts → express-CVNQEkOr.d.mts} +2 -2
  32. package/dist/{express-CHpfa7D_.d.ts → express-Piv2WhWM.d.ts} +2 -2
  33. package/dist/express.d.mts +7 -6
  34. package/dist/express.d.ts +7 -6
  35. package/dist/express.js +349 -52
  36. package/dist/express.mjs +39 -12
  37. package/dist/fastify.d.mts +2 -0
  38. package/dist/fastify.d.ts +2 -0
  39. package/dist/fastify.js +332 -52
  40. package/dist/fastify.mjs +23 -8
  41. package/dist/hono.d.mts +2 -0
  42. package/dist/hono.d.ts +2 -0
  43. package/dist/hono.js +329 -52
  44. package/dist/hono.mjs +20 -8
  45. package/dist/index-5KSZEnDe.d.ts +1626 -0
  46. package/dist/index-CKoZHAoc.d.mts +1626 -0
  47. package/dist/index.d.mts +56 -8
  48. package/dist/index.d.ts +56 -8
  49. package/dist/index.js +565 -69
  50. package/dist/index.mjs +29 -9
  51. package/dist/{keys-NLWFAOEM.mjs → keys-6Y776TG2.mjs} +2 -2
  52. package/dist/locales.d.mts +1 -1
  53. package/dist/locales.d.ts +1 -1
  54. package/dist/mobile.d.mts +77 -7
  55. package/dist/mobile.d.ts +77 -7
  56. package/dist/mobile.js +276 -41
  57. package/dist/mobile.mjs +98 -3
  58. package/dist/next.d.mts +2 -1
  59. package/dist/next.d.ts +2 -1
  60. package/dist/next.js +391 -201
  61. package/dist/next.mjs +22 -7
  62. package/dist/{provisioningBridge-DnTfzdZK.d.ts → provisioningBridge-CGpMRie4.d.ts} +1 -1
  63. package/dist/{provisioningBridge-88xjOS2n.d.mts → provisioningBridge-M5G47LWO.d.mts} +1 -1
  64. package/dist/{publishableKey-BaR0HoAH.d.ts → publishableKey-f2kq-rKw.d.mts} +1 -1
  65. package/dist/{publishableKey-BaR0HoAH.d.mts → publishableKey-f2kq-rKw.d.ts} +1 -1
  66. package/dist/react-permissions.d.mts +52 -0
  67. package/dist/react-permissions.d.ts +52 -0
  68. package/dist/react-permissions.js +239 -0
  69. package/dist/react-permissions.mjs +97 -0
  70. package/dist/react.d.mts +9 -1624
  71. package/dist/react.d.ts +9 -1624
  72. package/dist/react.js +313 -33
  73. package/dist/react.mjs +58 -2632
  74. package/dist/{reverify-4UEJXUS6.mjs → reverify-C64QXKJO.mjs} +2 -2
  75. package/dist/server/handlers.d.mts +148 -3
  76. package/dist/server/handlers.d.ts +148 -3
  77. package/dist/server/handlers.js +410 -11
  78. package/dist/server/handlers.mjs +12 -3
  79. package/dist/server.d.mts +151 -8
  80. package/dist/server.d.ts +151 -8
  81. package/dist/server.js +406 -50
  82. package/dist/server.mjs +93 -11
  83. package/dist/service.d.mts +4 -4
  84. package/dist/service.d.ts +4 -4
  85. package/dist/service.js +181 -41
  86. package/dist/service.mjs +3 -3
  87. package/dist/{signIn-OCr88Zf8.d.ts → signIn-BLFnz8SV.d.ts} +78 -3
  88. package/dist/{signIn-4OKLDEIH.mjs → signIn-SHBW6Z4T.mjs} +1 -1
  89. package/dist/{signIn-CiIBTJIh.d.mts → signIn-T-CZ6t6r.d.mts} +78 -3
  90. package/dist/test.mjs +3 -3
  91. package/dist/{tokens-DCyzzn8L.d.mts → tokens-Bqhmqq_R.d.ts} +9 -2
  92. package/dist/{tokens-aHiGFr_E.d.ts → tokens-CITeoG6P.d.mts} +9 -2
  93. package/dist/{types-6bNdxesb.d.ts → types-BdQ2lqfT.d.mts} +1 -1
  94. package/dist/{types-6bNdxesb.d.mts → types-BdQ2lqfT.d.ts} +1 -1
  95. package/dist/{types-DZAflmmq.d.mts → types-XOV9XPVi.d.mts} +99 -10
  96. package/dist/{types-DZAflmmq.d.ts → types-XOV9XPVi.d.ts} +99 -10
  97. package/dist/webhooks.d.mts +100 -17
  98. package/dist/webhooks.d.ts +100 -17
  99. package/dist/webhooks.js +164 -15
  100. package/dist/webhooks.mjs +7 -1
  101. package/dist/ws.d.mts +2 -2
  102. package/dist/ws.d.ts +2 -2
  103. package/dist/ws.js +80 -30
  104. package/dist/ws.mjs +4 -4
  105. package/docs/error-handling.md +101 -0
  106. package/docs/guides/effective-permissions.md +171 -0
  107. package/package.json +13 -3
  108. package/dist/chunk-UKZLOHZG.mjs +0 -83
  109. package/dist/errors-CDdl24MP.d.mts +0 -52
  110. package/dist/errors-CDdl24MP.d.ts +0 -52
package/dist/next.mjs CHANGED
@@ -2,15 +2,16 @@ import {
2
2
  handleCallback,
3
3
  handleRefresh,
4
4
  handleSignout,
5
+ handleUserinfo,
5
6
  serializeCookie
6
- } from "./chunk-6TDJJER7.mjs";
7
+ } from "./chunk-RUJXRTEW.mjs";
7
8
  import {
8
9
  assertPublishableKey
9
- } from "./chunk-WQWBJSSS.mjs";
10
+ } from "./chunk-HVHNYPDC.mjs";
10
11
  import {
11
12
  TokensModule
12
- } from "./chunk-UNYDG2L4.mjs";
13
- import "./chunk-6I6RM4MN.mjs";
13
+ } from "./chunk-NUO2I65G.mjs";
14
+ import "./chunk-6PJRLRB4.mjs";
14
15
  import "./chunk-Y6FXYEAI.mjs";
15
16
 
16
17
  // src/next.ts
@@ -43,8 +44,19 @@ function handler(options) {
43
44
  return async (req) => {
44
45
  const url = new URL(req.url);
45
46
  const action = url.pathname.split("/").pop();
46
- const body = await req.json().catch(() => ({}));
47
47
  const cookieHeader = req.headers.get("cookie");
48
+ if (action === "me" && req.method === "GET") {
49
+ if (!options.mountUserinfo) {
50
+ return new Response(JSON.stringify({ success: false, error: { code: "NOT_FOUND", message: "userinfo route not enabled" } }), {
51
+ status: 404,
52
+ headers: { "Content-Type": "application/json" }
53
+ });
54
+ }
55
+ const auth = req.headers.get("authorization");
56
+ const accessToken = auth && auth.replace(/^Bearer /i, "") || readCookieFromHeader(cookieHeader, accessCookie);
57
+ return toResponse(await handleUserinfo(helperConfig, { accessToken, req }));
58
+ }
59
+ const body = await req.json().catch(() => ({}));
48
60
  if (action === "callback") {
49
61
  return toResponse(await handleCallback(helperConfig, {
50
62
  code: body.code,
@@ -54,12 +66,15 @@ function handler(options) {
54
66
  }
55
67
  if (action === "refresh") {
56
68
  const refreshToken = body.refreshToken || readCookieFromHeader(cookieHeader, refreshCookie);
57
- return toResponse(await handleRefresh(helperConfig, { refreshToken }));
69
+ const idempotencyToken = req.headers.get("x-iqauth-idempotency") || body.idempotencyToken;
70
+ return toResponse(await handleRefresh(helperConfig, { refreshToken, idempotencyToken: idempotencyToken ?? void 0 }));
58
71
  }
59
72
  if (action === "signout") {
60
73
  const auth = req.headers.get("authorization");
61
74
  const accessToken = auth && auth.replace(/^Bearer /i, "") || readCookieFromHeader(cookieHeader, accessCookie);
62
- return toResponse(await handleSignout(helperConfig, { accessToken, ssoCookieHeader: cookieHeader ?? void 0 }));
75
+ const refreshToken = readCookieFromHeader(cookieHeader, refreshCookie);
76
+ const idempotencyToken = req.headers.get("x-iqauth-idempotency") ?? void 0;
77
+ return toResponse(await handleSignout(helperConfig, { accessToken, refreshToken, idempotencyToken, ssoCookieHeader: cookieHeader ?? void 0 }));
63
78
  }
64
79
  return new Response(JSON.stringify({ success: false, error: { code: "NOT_FOUND", message: `Unknown action: ${action}` } }), {
65
80
  status: 404,
@@ -1,4 +1,4 @@
1
- import { J as JwtClaims } from './types-DZAflmmq.js';
1
+ import { J as JwtClaims } from './types-XOV9XPVi.js';
2
2
 
3
3
  /**
4
4
  * createProvisioningBridge — server-side helper that lifts the
@@ -1,4 +1,4 @@
1
- import { J as JwtClaims } from './types-DZAflmmq.mjs';
1
+ import { J as JwtClaims } from './types-XOV9XPVi.mjs';
2
2
 
3
3
  /**
4
4
  * createProvisioningBridge — server-side helper that lifts the
@@ -20,7 +20,7 @@ declare function encodePublishableKey(mode: KeyMode, payload: PublishableKeyPayl
20
20
  declare function parsePublishableKey(raw: string): ParsedPublishableKey | null;
21
21
  /**
22
22
  * Strict counterpart to `parsePublishableKey` — throws a typed `IQAuthError`
23
- * (`code: "CONFIG_INVALID"`) with an actionable message when the key is
23
+ * (`code: "config_invalid"`) with an actionable message when the key is
24
24
  * missing, malformed, or encodes a non-URL `iss`. Use this at SDK init so a
25
25
  * bad key fails loudly at boot instead of cryptically at first verify.
26
26
  */
@@ -20,7 +20,7 @@ declare function encodePublishableKey(mode: KeyMode, payload: PublishableKeyPayl
20
20
  declare function parsePublishableKey(raw: string): ParsedPublishableKey | null;
21
21
  /**
22
22
  * Strict counterpart to `parsePublishableKey` — throws a typed `IQAuthError`
23
- * (`code: "CONFIG_INVALID"`) with an actionable message when the key is
23
+ * (`code: "config_invalid"`) with an actionable message when the key is
24
24
  * missing, malformed, or encodes a non-URL `iss`. Use this at SDK init so a
25
25
  * bad key fails loudly at boot instead of cryptically at first verify.
26
26
  */
@@ -0,0 +1,52 @@
1
+ import { S as SessionError } from './index-CKoZHAoc.mjs';
2
+ import 'csstype';
3
+ import 'react/jsx-runtime';
4
+ import 'react';
5
+ import './signIn-T-CZ6t6r.mjs';
6
+ import './publishableKey-f2kq-rKw.mjs';
7
+ import './types-XOV9XPVi.mjs';
8
+ import './types-BdQ2lqfT.mjs';
9
+
10
+ interface UseEffectivePermissionsOptions {
11
+ /**
12
+ * App key (OIDC client_id / manifest key) the permissions should be
13
+ * resolved against. Required — permissions in IQAuth are app-scoped.
14
+ */
15
+ appKey: string;
16
+ /** Disable the network fetch (claims fallback still applies). */
17
+ enabled?: boolean;
18
+ /** Stale window in ms. Default 5min. */
19
+ staleTime?: number;
20
+ /**
21
+ * Override the issuer URL the hook calls. Defaults to the issuer the
22
+ * provider was booted with.
23
+ */
24
+ issuer?: string;
25
+ }
26
+ interface UseEffectivePermissionsResult {
27
+ /** Normalized, wildcard-collapsed set of granted permission ids. */
28
+ permissions: string[];
29
+ /** Wildcard-aware membership check. Identical semantics on server. */
30
+ hasPermission: (id: string) => boolean;
31
+ /** True only while a fetch is actively in flight (and no cached data yet). */
32
+ isLoading: boolean;
33
+ /** Last fetch error, if any. Cleared on next successful refetch. */
34
+ error: SessionError | null;
35
+ /** Force a refetch, bypassing the staleTime window. */
36
+ refetch: () => Promise<void>;
37
+ }
38
+ /**
39
+ * Canonical hook for resolving the *full* effective permission set of the
40
+ * signed-in user against a single app. Use this whenever the JWT
41
+ * `entitlements` claim is too small (apps with hundreds of nodes can't fit
42
+ * them in the token).
43
+ *
44
+ * Requires a `<QueryClientProvider>` (`@tanstack/react-query`) somewhere
45
+ * above this hook in the tree.
46
+ *
47
+ * Returns `{ permissions, hasPermission, isLoading, error, refetch }`.
48
+ * `hasPermission` honours wildcard semantics (`*`, `metrics.*`).
49
+ */
50
+ declare function useEffectivePermissions(opts: UseEffectivePermissionsOptions): UseEffectivePermissionsResult;
51
+
52
+ export { type UseEffectivePermissionsOptions, type UseEffectivePermissionsResult, useEffectivePermissions };
@@ -0,0 +1,52 @@
1
+ import { S as SessionError } from './index-5KSZEnDe.js';
2
+ import 'csstype';
3
+ import 'react/jsx-runtime';
4
+ import 'react';
5
+ import './signIn-BLFnz8SV.js';
6
+ import './publishableKey-f2kq-rKw.js';
7
+ import './types-XOV9XPVi.js';
8
+ import './types-BdQ2lqfT.js';
9
+
10
+ interface UseEffectivePermissionsOptions {
11
+ /**
12
+ * App key (OIDC client_id / manifest key) the permissions should be
13
+ * resolved against. Required — permissions in IQAuth are app-scoped.
14
+ */
15
+ appKey: string;
16
+ /** Disable the network fetch (claims fallback still applies). */
17
+ enabled?: boolean;
18
+ /** Stale window in ms. Default 5min. */
19
+ staleTime?: number;
20
+ /**
21
+ * Override the issuer URL the hook calls. Defaults to the issuer the
22
+ * provider was booted with.
23
+ */
24
+ issuer?: string;
25
+ }
26
+ interface UseEffectivePermissionsResult {
27
+ /** Normalized, wildcard-collapsed set of granted permission ids. */
28
+ permissions: string[];
29
+ /** Wildcard-aware membership check. Identical semantics on server. */
30
+ hasPermission: (id: string) => boolean;
31
+ /** True only while a fetch is actively in flight (and no cached data yet). */
32
+ isLoading: boolean;
33
+ /** Last fetch error, if any. Cleared on next successful refetch. */
34
+ error: SessionError | null;
35
+ /** Force a refetch, bypassing the staleTime window. */
36
+ refetch: () => Promise<void>;
37
+ }
38
+ /**
39
+ * Canonical hook for resolving the *full* effective permission set of the
40
+ * signed-in user against a single app. Use this whenever the JWT
41
+ * `entitlements` claim is too small (apps with hundreds of nodes can't fit
42
+ * them in the token).
43
+ *
44
+ * Requires a `<QueryClientProvider>` (`@tanstack/react-query`) somewhere
45
+ * above this hook in the tree.
46
+ *
47
+ * Returns `{ permissions, hasPermission, isLoading, error, refetch }`.
48
+ * `hasPermission` honours wildcard semantics (`*`, `metrics.*`).
49
+ */
50
+ declare function useEffectivePermissions(opts: UseEffectivePermissionsOptions): UseEffectivePermissionsResult;
51
+
52
+ export { type UseEffectivePermissionsOptions, type UseEffectivePermissionsResult, useEffectivePermissions };
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // src/errors.ts
24
+ var init_errors = __esm({
25
+ "src/errors.ts"() {
26
+ "use strict";
27
+ }
28
+ });
29
+
30
+ // src/browser/storage.ts
31
+ var init_storage = __esm({
32
+ "src/browser/storage.ts"() {
33
+ "use strict";
34
+ }
35
+ });
36
+
37
+ // src/browser/pkce.ts
38
+ var init_pkce = __esm({
39
+ "src/browser/pkce.ts"() {
40
+ "use strict";
41
+ }
42
+ });
43
+
44
+ // src/browser/signIn.ts
45
+ var init_signIn = __esm({
46
+ "src/browser/signIn.ts"() {
47
+ "use strict";
48
+ init_pkce();
49
+ init_storage();
50
+ }
51
+ });
52
+
53
+ // src/react-permissions.ts
54
+ var react_permissions_exports = {};
55
+ __export(react_permissions_exports, {
56
+ useEffectivePermissions: () => useEffectivePermissions
57
+ });
58
+ module.exports = __toCommonJS(react_permissions_exports);
59
+
60
+ // src/react/permissions.tsx
61
+ var import_react2 = require("react");
62
+ var import_react_query = require("@tanstack/react-query");
63
+
64
+ // src/permissions/wildcard.ts
65
+ var SUFFIX = ".*";
66
+ function wildcardPrefix(pattern) {
67
+ return pattern.slice(0, -SUFFIX.length);
68
+ }
69
+ function hasPermission(set, id) {
70
+ if (!id) return false;
71
+ if (!set) return false;
72
+ if (id === "*") {
73
+ for (const entry of set) if (entry === "*") return true;
74
+ return false;
75
+ }
76
+ const queryIsWildcard = id.endsWith(SUFFIX);
77
+ const queryPrefix = queryIsWildcard ? wildcardPrefix(id) : null;
78
+ for (const entry of set) {
79
+ if (!entry) continue;
80
+ if (entry === "*") return true;
81
+ if (entry === id) return true;
82
+ if (entry.endsWith(SUFFIX)) {
83
+ const prefix = wildcardPrefix(entry);
84
+ if (!queryIsWildcard) {
85
+ if (id === prefix) return true;
86
+ if (id.startsWith(prefix + ".")) return true;
87
+ } else {
88
+ if (queryPrefix === prefix) return true;
89
+ if (queryPrefix !== null && queryPrefix.startsWith(prefix + ".")) return true;
90
+ }
91
+ }
92
+ }
93
+ return false;
94
+ }
95
+ function expandPermissions(set) {
96
+ if (!set) return [];
97
+ const seen = /* @__PURE__ */ new Set();
98
+ for (const raw of set) {
99
+ if (typeof raw !== "string" || raw.length === 0) continue;
100
+ seen.add(raw);
101
+ }
102
+ if (seen.has("*")) return ["*"];
103
+ const wildcards = [];
104
+ for (const entry of seen) if (entry.endsWith(SUFFIX)) wildcards.push(entry);
105
+ const out = [];
106
+ for (const entry of seen) {
107
+ let covered = false;
108
+ for (const w of wildcards) {
109
+ if (w === entry) continue;
110
+ const prefix = wildcardPrefix(w);
111
+ if (entry === prefix) {
112
+ covered = true;
113
+ break;
114
+ }
115
+ if (entry.startsWith(prefix + ".")) {
116
+ covered = true;
117
+ break;
118
+ }
119
+ }
120
+ if (!covered) out.push(entry);
121
+ }
122
+ out.sort();
123
+ return out;
124
+ }
125
+
126
+ // src/react/index.tsx
127
+ var import_react = require("react");
128
+
129
+ // src/browser/sessionManager.ts
130
+ init_errors();
131
+
132
+ // src/publishableKey.ts
133
+ init_errors();
134
+
135
+ // src/browser/sessionManager.ts
136
+ init_storage();
137
+
138
+ // src/react/index.tsx
139
+ init_signIn();
140
+
141
+ // src/browser/accountRegistry.ts
142
+ init_storage();
143
+ var COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
144
+
145
+ // src/react/index.tsx
146
+ var import_jsx_runtime = require("react/jsx-runtime");
147
+ var IQAuthContext = (0, import_react.createContext)(null);
148
+ function __useIQAuthInternal() {
149
+ return useCtx();
150
+ }
151
+ function useCtx() {
152
+ const ctx = (0, import_react.useContext)(IQAuthContext);
153
+ if (!ctx) throw new Error("IQAuth hooks must be used inside <IQAuthProvider>");
154
+ return ctx;
155
+ }
156
+ var MultisessionContext = (0, import_react.createContext)(null);
157
+ var SDK_CSS_MAX_LEN = 50 * 1024;
158
+
159
+ // src/react/permissions.tsx
160
+ var DEFAULT_PERMS_STALE_MS = 5 * 60 * 1e3;
161
+ function projectAllowedScopes(rows) {
162
+ if (!Array.isArray(rows)) return [];
163
+ const allowed = [];
164
+ const denied = /* @__PURE__ */ new Set();
165
+ for (const r of rows) {
166
+ if (!r || typeof r.scope !== "string" || !r.scope) continue;
167
+ if (r.effect === "deny") denied.add(r.scope);
168
+ else allowed.push(r.scope);
169
+ }
170
+ return expandPermissions(allowed.filter((s) => !denied.has(s)));
171
+ }
172
+ function useEffectivePermissions(opts) {
173
+ const { manager, snapshot } = __useIQAuthInternal();
174
+ const { appKey, enabled = true, staleTime = DEFAULT_PERMS_STALE_MS, issuer } = opts;
175
+ const claims = snapshot.claims;
176
+ const isPlatformAdmin = Array.isArray(claims?.roles) && claims.roles.includes("platform_admin");
177
+ const userId = snapshot.user?.sub ?? null;
178
+ const tenantId = snapshot.tenantId ?? claims?.tenantId ?? null;
179
+ const issuerUrl = (issuer ?? manager.issuerUrl).replace(/\/$/, "");
180
+ const queryEnabled = enabled && !!userId && !!tenantId && !!appKey && !isPlatformAdmin;
181
+ const query = (0, import_react_query.useQuery)({
182
+ queryKey: ["iqauth", "effective-permissions", issuerUrl, tenantId, userId, appKey],
183
+ queryFn: async () => {
184
+ const url = `${issuerUrl}/api/v1/tenants/${encodeURIComponent(tenantId)}/users/${encodeURIComponent(userId)}/permissions/effective?appKey=${encodeURIComponent(appKey)}`;
185
+ const res = await manager.fetch(url);
186
+ const json = await res.json().catch(() => ({}));
187
+ if (!res.ok) {
188
+ const code = json?.error?.code || `HTTP_${res.status}`;
189
+ const message = json?.error?.message || `HTTP ${res.status}`;
190
+ const e = { code, message };
191
+ throw e;
192
+ }
193
+ const rows = Array.isArray(json) ? json : json?.data ?? [];
194
+ return projectAllowedScopes(rows);
195
+ },
196
+ enabled: queryEnabled,
197
+ staleTime,
198
+ refetchOnWindowFocus: false,
199
+ retry: false
200
+ });
201
+ const refetch = (0, import_react2.useCallback)(async () => {
202
+ if (!queryEnabled) return;
203
+ await query.refetch();
204
+ }, [query, queryEnabled]);
205
+ return (0, import_react2.useMemo)(() => {
206
+ if (isPlatformAdmin) {
207
+ return {
208
+ permissions: ["*"],
209
+ hasPermission: () => true,
210
+ isLoading: false,
211
+ error: null,
212
+ refetch
213
+ };
214
+ }
215
+ const fetched = query.data;
216
+ const perms = fetched ?? expandPermissions(claims?.entitlements ?? []);
217
+ const isLoading = queryEnabled && query.isLoading;
218
+ const error = query.error ? "code" in query.error && typeof query.error.code === "string" ? query.error : { code: "PERMISSIONS_FETCH_FAILED", message: query.error.message || "Failed to fetch permissions" } : null;
219
+ return {
220
+ permissions: perms,
221
+ hasPermission: (id) => hasPermission(perms, id),
222
+ isLoading,
223
+ error,
224
+ refetch
225
+ };
226
+ }, [
227
+ isPlatformAdmin,
228
+ queryEnabled,
229
+ query.data,
230
+ query.isLoading,
231
+ query.error,
232
+ claims?.entitlements,
233
+ refetch
234
+ ]);
235
+ }
236
+ // Annotate the CommonJS export names for ESM import in node:
237
+ 0 && (module.exports = {
238
+ useEffectivePermissions
239
+ });
@@ -0,0 +1,97 @@
1
+ import {
2
+ __useIQAuthInternal
3
+ } from "./chunk-RR2MGPTK.mjs";
4
+ import "./chunk-RTJAIBXY.mjs";
5
+ import "./chunk-GN37E64I.mjs";
6
+ import "./chunk-C2ZTBOAC.mjs";
7
+ import {
8
+ expandPermissions,
9
+ hasPermission
10
+ } from "./chunk-GLXSIGVS.mjs";
11
+ import "./chunk-HVHNYPDC.mjs";
12
+ import "./chunk-5T7GHBX6.mjs";
13
+ import "./chunk-6PJRLRB4.mjs";
14
+ import "./chunk-Y6FXYEAI.mjs";
15
+
16
+ // src/react/permissions.tsx
17
+ import { useCallback, useMemo } from "react";
18
+ import { useQuery } from "@tanstack/react-query";
19
+ var DEFAULT_PERMS_STALE_MS = 5 * 60 * 1e3;
20
+ function projectAllowedScopes(rows) {
21
+ if (!Array.isArray(rows)) return [];
22
+ const allowed = [];
23
+ const denied = /* @__PURE__ */ new Set();
24
+ for (const r of rows) {
25
+ if (!r || typeof r.scope !== "string" || !r.scope) continue;
26
+ if (r.effect === "deny") denied.add(r.scope);
27
+ else allowed.push(r.scope);
28
+ }
29
+ return expandPermissions(allowed.filter((s) => !denied.has(s)));
30
+ }
31
+ function useEffectivePermissions(opts) {
32
+ const { manager, snapshot } = __useIQAuthInternal();
33
+ const { appKey, enabled = true, staleTime = DEFAULT_PERMS_STALE_MS, issuer } = opts;
34
+ const claims = snapshot.claims;
35
+ const isPlatformAdmin = Array.isArray(claims?.roles) && claims.roles.includes("platform_admin");
36
+ const userId = snapshot.user?.sub ?? null;
37
+ const tenantId = snapshot.tenantId ?? claims?.tenantId ?? null;
38
+ const issuerUrl = (issuer ?? manager.issuerUrl).replace(/\/$/, "");
39
+ const queryEnabled = enabled && !!userId && !!tenantId && !!appKey && !isPlatformAdmin;
40
+ const query = useQuery({
41
+ queryKey: ["iqauth", "effective-permissions", issuerUrl, tenantId, userId, appKey],
42
+ queryFn: async () => {
43
+ const url = `${issuerUrl}/api/v1/tenants/${encodeURIComponent(tenantId)}/users/${encodeURIComponent(userId)}/permissions/effective?appKey=${encodeURIComponent(appKey)}`;
44
+ const res = await manager.fetch(url);
45
+ const json = await res.json().catch(() => ({}));
46
+ if (!res.ok) {
47
+ const code = json?.error?.code || `HTTP_${res.status}`;
48
+ const message = json?.error?.message || `HTTP ${res.status}`;
49
+ const e = { code, message };
50
+ throw e;
51
+ }
52
+ const rows = Array.isArray(json) ? json : json?.data ?? [];
53
+ return projectAllowedScopes(rows);
54
+ },
55
+ enabled: queryEnabled,
56
+ staleTime,
57
+ refetchOnWindowFocus: false,
58
+ retry: false
59
+ });
60
+ const refetch = useCallback(async () => {
61
+ if (!queryEnabled) return;
62
+ await query.refetch();
63
+ }, [query, queryEnabled]);
64
+ return useMemo(() => {
65
+ if (isPlatformAdmin) {
66
+ return {
67
+ permissions: ["*"],
68
+ hasPermission: () => true,
69
+ isLoading: false,
70
+ error: null,
71
+ refetch
72
+ };
73
+ }
74
+ const fetched = query.data;
75
+ const perms = fetched ?? expandPermissions(claims?.entitlements ?? []);
76
+ const isLoading = queryEnabled && query.isLoading;
77
+ const error = query.error ? "code" in query.error && typeof query.error.code === "string" ? query.error : { code: "PERMISSIONS_FETCH_FAILED", message: query.error.message || "Failed to fetch permissions" } : null;
78
+ return {
79
+ permissions: perms,
80
+ hasPermission: (id) => hasPermission(perms, id),
81
+ isLoading,
82
+ error,
83
+ refetch
84
+ };
85
+ }, [
86
+ isPlatformAdmin,
87
+ queryEnabled,
88
+ query.data,
89
+ query.isLoading,
90
+ query.error,
91
+ claims?.entitlements,
92
+ refetch
93
+ ]);
94
+ }
95
+ export {
96
+ useEffectivePermissions
97
+ };