@ic-reactor/react 3.12.5 → 4.0.0-beta.1

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 (139) hide show
  1. package/README.md +236 -423
  2. package/dist/index.d.ts +259 -12
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +470 -17
  5. package/dist/index.js.map +1 -1
  6. package/llms.txt +82 -54
  7. package/package.json +12 -28
  8. package/src/index.tsx +611 -0
  9. package/dist/auth/authentication-manager.d.ts +0 -123
  10. package/dist/auth/authentication-manager.d.ts.map +0 -1
  11. package/dist/auth/authentication-manager.js +0 -767
  12. package/dist/auth/authentication-manager.js.map +0 -1
  13. package/dist/auth/constants.d.ts +0 -24
  14. package/dist/auth/constants.d.ts.map +0 -1
  15. package/dist/auth/constants.js +0 -24
  16. package/dist/auth/constants.js.map +0 -1
  17. package/dist/auth/createIdentityAttributeHooks.d.ts +0 -14
  18. package/dist/auth/createIdentityAttributeHooks.d.ts.map +0 -1
  19. package/dist/auth/createIdentityAttributeHooks.js +0 -106
  20. package/dist/auth/createIdentityAttributeHooks.js.map +0 -1
  21. package/dist/auth/identity-attributes-manager.d.ts +0 -26
  22. package/dist/auth/identity-attributes-manager.d.ts.map +0 -1
  23. package/dist/auth/identity-attributes-manager.js +0 -107
  24. package/dist/auth/identity-attributes-manager.js.map +0 -1
  25. package/dist/auth/identity-attributes.d.ts +0 -19
  26. package/dist/auth/identity-attributes.d.ts.map +0 -1
  27. package/dist/auth/identity-attributes.js +0 -170
  28. package/dist/auth/identity-attributes.js.map +0 -1
  29. package/dist/auth/index.d.ts +0 -8
  30. package/dist/auth/index.d.ts.map +0 -1
  31. package/dist/auth/index.js +0 -8
  32. package/dist/auth/index.js.map +0 -1
  33. package/dist/auth/local-ii-probe.d.ts +0 -46
  34. package/dist/auth/local-ii-probe.d.ts.map +0 -1
  35. package/dist/auth/local-ii-probe.js +0 -102
  36. package/dist/auth/local-ii-probe.js.map +0 -1
  37. package/dist/auth/types.d.ts +0 -179
  38. package/dist/auth/types.d.ts.map +0 -1
  39. package/dist/auth/types.js +0 -2
  40. package/dist/auth/types.js.map +0 -1
  41. package/dist/createActorHooks.d.ts +0 -52
  42. package/dist/createActorHooks.d.ts.map +0 -1
  43. package/dist/createActorHooks.js +0 -17
  44. package/dist/createActorHooks.js.map +0 -1
  45. package/dist/createInfiniteQuery.d.ts +0 -144
  46. package/dist/createInfiniteQuery.d.ts.map +0 -1
  47. package/dist/createInfiniteQuery.js +0 -174
  48. package/dist/createInfiniteQuery.js.map +0 -1
  49. package/dist/createMutation.d.ts +0 -30
  50. package/dist/createMutation.d.ts.map +0 -1
  51. package/dist/createMutation.js +0 -192
  52. package/dist/createMutation.js.map +0 -1
  53. package/dist/createQuery.d.ts +0 -30
  54. package/dist/createQuery.d.ts.map +0 -1
  55. package/dist/createQuery.js +0 -117
  56. package/dist/createQuery.js.map +0 -1
  57. package/dist/createSuspenseInfiniteQuery.d.ts +0 -147
  58. package/dist/createSuspenseInfiniteQuery.d.ts.map +0 -1
  59. package/dist/createSuspenseInfiniteQuery.js +0 -177
  60. package/dist/createSuspenseInfiniteQuery.js.map +0 -1
  61. package/dist/createSuspenseQuery.d.ts +0 -25
  62. package/dist/createSuspenseQuery.d.ts.map +0 -1
  63. package/dist/createSuspenseQuery.js +0 -111
  64. package/dist/createSuspenseQuery.js.map +0 -1
  65. package/dist/defineReactor.d.ts +0 -125
  66. package/dist/defineReactor.d.ts.map +0 -1
  67. package/dist/defineReactor.js +0 -180
  68. package/dist/defineReactor.js.map +0 -1
  69. package/dist/hooks/createAuthHooks.d.ts +0 -43
  70. package/dist/hooks/createAuthHooks.d.ts.map +0 -1
  71. package/dist/hooks/createAuthHooks.js +0 -131
  72. package/dist/hooks/createAuthHooks.js.map +0 -1
  73. package/dist/hooks/index.d.ts +0 -21
  74. package/dist/hooks/index.d.ts.map +0 -1
  75. package/dist/hooks/index.js +0 -24
  76. package/dist/hooks/index.js.map +0 -1
  77. package/dist/hooks/useActorInfiniteQuery.d.ts +0 -39
  78. package/dist/hooks/useActorInfiniteQuery.d.ts.map +0 -1
  79. package/dist/hooks/useActorInfiniteQuery.js +0 -56
  80. package/dist/hooks/useActorInfiniteQuery.js.map +0 -1
  81. package/dist/hooks/useActorMethod.d.ts +0 -115
  82. package/dist/hooks/useActorMethod.d.ts.map +0 -1
  83. package/dist/hooks/useActorMethod.js +0 -250
  84. package/dist/hooks/useActorMethod.js.map +0 -1
  85. package/dist/hooks/useActorMutation.d.ts +0 -48
  86. package/dist/hooks/useActorMutation.d.ts.map +0 -1
  87. package/dist/hooks/useActorMutation.js +0 -69
  88. package/dist/hooks/useActorMutation.js.map +0 -1
  89. package/dist/hooks/useActorQuery.d.ts +0 -32
  90. package/dist/hooks/useActorQuery.d.ts.map +0 -1
  91. package/dist/hooks/useActorQuery.js +0 -46
  92. package/dist/hooks/useActorQuery.js.map +0 -1
  93. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +0 -39
  94. package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +0 -1
  95. package/dist/hooks/useActorSuspenseInfiniteQuery.js +0 -56
  96. package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +0 -1
  97. package/dist/hooks/useActorSuspenseQuery.d.ts +0 -32
  98. package/dist/hooks/useActorSuspenseQuery.d.ts.map +0 -1
  99. package/dist/hooks/useActorSuspenseQuery.js +0 -47
  100. package/dist/hooks/useActorSuspenseQuery.js.map +0 -1
  101. package/dist/types.d.ts +0 -270
  102. package/dist/types.d.ts.map +0 -1
  103. package/dist/types.js +0 -5
  104. package/dist/types.js.map +0 -1
  105. package/dist/utils.d.ts +0 -51
  106. package/dist/utils.d.ts.map +0 -1
  107. package/dist/utils.js +0 -105
  108. package/dist/utils.js.map +0 -1
  109. package/dist/validation.d.ts +0 -131
  110. package/dist/validation.d.ts.map +0 -1
  111. package/dist/validation.js +0 -125
  112. package/dist/validation.js.map +0 -1
  113. package/src/auth/authentication-manager.ts +0 -860
  114. package/src/auth/constants.ts +0 -32
  115. package/src/auth/createIdentityAttributeHooks.ts +0 -143
  116. package/src/auth/identity-attributes-manager.ts +0 -131
  117. package/src/auth/identity-attributes.ts +0 -270
  118. package/src/auth/index.ts +0 -7
  119. package/src/auth/local-ii-probe.ts +0 -147
  120. package/src/auth/types.ts +0 -200
  121. package/src/createActorHooks.ts +0 -220
  122. package/src/createInfiniteQuery.ts +0 -578
  123. package/src/createMutation.ts +0 -341
  124. package/src/createQuery.ts +0 -237
  125. package/src/createSuspenseInfiniteQuery.ts +0 -601
  126. package/src/createSuspenseQuery.ts +0 -234
  127. package/src/defineReactor.ts +0 -324
  128. package/src/hooks/createAuthHooks.ts +0 -189
  129. package/src/hooks/index.ts +0 -103
  130. package/src/hooks/useActorInfiniteQuery.ts +0 -205
  131. package/src/hooks/useActorMethod.ts +0 -507
  132. package/src/hooks/useActorMutation.ts +0 -205
  133. package/src/hooks/useActorQuery.ts +0 -124
  134. package/src/hooks/useActorSuspenseInfiniteQuery.ts +0 -205
  135. package/src/hooks/useActorSuspenseQuery.ts +0 -132
  136. package/src/index.ts +0 -23
  137. package/src/types.ts +0 -499
  138. package/src/utils.ts +0 -121
  139. package/src/validation.ts +0 -202
@@ -1,32 +0,0 @@
1
- export const IC_INTERNET_IDENTITY_PROVIDER = "https://id.ai/authorize"
2
-
3
- /**
4
- * `ic_env` key used to provide a fully resolved Internet Identity URL.
5
- */
6
- export const INTERNET_IDENTITY_PROVIDER_ENV_KEY = "INTERNET_IDENTITY_PROVIDER"
7
-
8
- /**
9
- * Well-known Internet Identity canister ID used when deploying II locally.
10
- */
11
- export const LOCAL_INTERNET_IDENTITY_CANISTER_ID = "rdmx6-jaaaa-aaaaa-aaadq-cai"
12
-
13
- /**
14
- * Builds the local Internet Identity provider URL for the given replica port.
15
- *
16
- * `authorizePath` selects the shape the installed build understands: modern
17
- * builds serve `/authorize` as a real asset, while pre-2026 ones serve the SPA
18
- * at `/` and drive the flow from a `#authorize` fragment. `AuthenticationManager`
19
- * probes the canister and passes the right one; the default keeps the previous
20
- * behaviour for direct callers.
21
- */
22
- export const localInternetIdentityProvider = (
23
- port: number,
24
- canisterId: string = LOCAL_INTERNET_IDENTITY_CANISTER_ID,
25
- authorizePath: "/authorize" | "/#authorize" = "/authorize"
26
- ) => `http://${canisterId}.localhost:${port}${authorizePath}`
27
-
28
- /**
29
- * Legacy default URL for local Internet Identity, using port `4943`.
30
- */
31
- export const LOCAL_INTERNET_IDENTITY_PROVIDER =
32
- localInternetIdentityProvider(4943)
@@ -1,143 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react"
2
- import type { IdentityAttributesManager } from "./identity-attributes-manager.js"
3
- import type {
4
- IdentityAttributeResult,
5
- RequestIdentityAttributesParameters,
6
- RequestOpenIdIdentityAttributesParameters,
7
- } from "./types.js"
8
-
9
- export interface UseIdentityAttributesReturn {
10
- requestAttributes: (
11
- params: RequestIdentityAttributesParameters
12
- ) => Promise<IdentityAttributeResult>
13
- requestOpenIdAttributes: (
14
- params: RequestOpenIdIdentityAttributesParameters
15
- ) => Promise<IdentityAttributeResult>
16
- attributes: IdentityAttributeResult | null
17
- isRequestingAttributes: boolean
18
- attributeError: Error | null
19
- clearAttributes: () => void
20
- }
21
-
22
- export function createIdentityAttributeHooks(
23
- identityAttributes: IdentityAttributesManager
24
- ) {
25
- const useIdentityAttributes = (): UseIdentityAttributesReturn => {
26
- const [attributes, setAttributes] =
27
- useState<IdentityAttributeResult | null>(null)
28
- const [isRequestingAttributes, setIsRequestingAttributes] = useState(false)
29
- const [attributeError, setAttributeError] = useState<Error | null>(null)
30
-
31
- /** The principal the session is currently signed in as, if any. */
32
- const currentPrincipal = useCallback(() => {
33
- const { authState } = identityAttributes.authentication
34
- return authState.isAuthenticated
35
- ? authState.identity?.getPrincipal().toText()
36
- : undefined
37
- }, [])
38
-
39
- /**
40
- * A request started before a sign-out or an account switch resolves after
41
- * it, and publishing that result would put the previous user's decoded PII
42
- * back on screen with no further auth event to clear it again. So a result
43
- * is committed only when it is the signed-in user's own: it carries the
44
- * principal that is current when it resolves, or the session has not
45
- * changed since it was asked for.
46
- *
47
- * The first test is the one the default flow needs. With `signIn: true`
48
- * the request itself signs the user in, so the principal seen before the
49
- * request (none, for a first sign-in; the old account, for a switch made
50
- * inside the provider window) is never the one the result belongs to.
51
- * Comparing against the pre-request principal alone left the hook's
52
- * `attributes` null after every successful first-time sign-in.
53
- */
54
- const isCurrent = useCallback(
55
- (requestedFor: string | undefined) => requestedFor === currentPrincipal(),
56
- [currentPrincipal]
57
- )
58
-
59
- const publishIfCurrent = useCallback(
60
- (requestedFor: string | undefined, result: IdentityAttributeResult) => {
61
- const current = currentPrincipal()
62
- if (result.principal !== current && requestedFor !== current) {
63
- return false
64
- }
65
- setAttributes(result)
66
- return true
67
- },
68
- [currentPrincipal]
69
- )
70
-
71
- const requestAttributes = useCallback(
72
- async (params: RequestIdentityAttributesParameters) => {
73
- setIsRequestingAttributes(true)
74
- setAttributeError(null)
75
- const requestedFor = currentPrincipal()
76
- try {
77
- const result = await identityAttributes.request(params)
78
- publishIfCurrent(requestedFor, result)
79
- return result
80
- } catch (error) {
81
- if (isCurrent(requestedFor)) setAttributeError(error as Error)
82
- throw error
83
- } finally {
84
- setIsRequestingAttributes(false)
85
- }
86
- },
87
- []
88
- )
89
-
90
- const requestOpenIdAttributes = useCallback(
91
- async (params: RequestOpenIdIdentityAttributesParameters) => {
92
- setIsRequestingAttributes(true)
93
- setAttributeError(null)
94
- const requestedFor = currentPrincipal()
95
- try {
96
- const result = await identityAttributes.requestOpenId(params)
97
- publishIfCurrent(requestedFor, result)
98
- return result
99
- } catch (error) {
100
- if (isCurrent(requestedFor)) setAttributeError(error as Error)
101
- throw error
102
- } finally {
103
- setIsRequestingAttributes(false)
104
- }
105
- },
106
- []
107
- )
108
-
109
- const clearAttributes = useCallback(() => {
110
- setAttributes(null)
111
- setAttributeError(null)
112
- }, [])
113
-
114
- // Decoded attributes are the signed-in user's personal data — a name, an
115
- // email. They used to survive a sign-out or a switch to another account,
116
- // so the next person to look at the screen saw the previous user's details.
117
- // Drop them whenever the principal behind them changes.
118
- const attributedPrincipal = useRef<string | undefined>(undefined)
119
- useEffect(() => {
120
- const { authentication } = identityAttributes
121
- attributedPrincipal.current ??= currentPrincipal()
122
-
123
- return authentication.subscribeAuthState(() => {
124
- const principal = currentPrincipal()
125
- if (principal === attributedPrincipal.current) return
126
- attributedPrincipal.current = principal
127
- setAttributes(null)
128
- setAttributeError(null)
129
- })
130
- }, [])
131
-
132
- return {
133
- requestAttributes,
134
- requestOpenIdAttributes,
135
- attributes,
136
- isRequestingAttributes,
137
- attributeError,
138
- clearAttributes,
139
- }
140
- }
141
-
142
- return { useIdentityAttributes }
143
- }
@@ -1,131 +0,0 @@
1
- import type {
2
- IdentityAttributeNonce,
3
- IdentityAttributeResult,
4
- RequestIdentityAttributesParameters,
5
- RequestOpenIdIdentityAttributesParameters,
6
- } from "./types.js"
7
-
8
- import { AuthenticationManager } from "./authentication-manager.js"
9
- import {
10
- decodeIdentityAttributeValues,
11
- identityAttributeKeys,
12
- normalizeSignedIdentityAttributes,
13
- } from "./identity-attributes.js"
14
-
15
- /**
16
- * Requests and decodes signed identity attributes for an authenticated
17
- * Internet Identity session.
18
- *
19
- * Await `authentication.prepareClient()` once during startup (the `useAuth`
20
- * hook already does) so that {@link request} can open the identity provider
21
- * window synchronously from a click handler.
22
- *
23
- * @example
24
- * ```ts
25
- * const attributes = new IdentityAttributesManager(authentication)
26
- * const result = await attributes.request({
27
- * keys: ["name"],
28
- * nonce: () => fetchNonceFromCanister(),
29
- * })
30
- * ```
31
- */
32
- export class IdentityAttributesManager {
33
- constructor(public readonly authentication: AuthenticationManager) {}
34
-
35
- public request = async ({
36
- keys,
37
- nonce,
38
- signIn = true,
39
- maxTimeToLive,
40
- targets,
41
- ...clientOptions
42
- }: RequestIdentityAttributesParameters): Promise<IdentityAttributeResult> => {
43
- // Nothing may be awaited before `requestAttributes` / `signIn` are invoked:
44
- // the ICRC-29 transport only opens the identity provider window while the
45
- // browser still considers us inside the user gesture. `getPreparedClient`
46
- // is synchronous whenever `prepareClient()` has run.
47
- const preparedClient = this.authentication.getPreparedClient(clientOptions)
48
- const authClient =
49
- preparedClient ?? (await this.authentication.ensureClient(clientOptions))
50
-
51
- if (!authClient) {
52
- throw new Error(
53
- "Authentication module is missing or failed to initialize. To request identity attributes, please install @icp-sdk/auth v8, or provide a compatible authClient."
54
- )
55
- }
56
-
57
- this.authentication.setAuthenticating()
58
-
59
- try {
60
- // `signIn` first: it opens the transport channel synchronously, and the
61
- // attribute request then reuses that same channel and window.
62
- const identityPromise = signIn
63
- ? this.authentication.signInOrRecoverIdentity({
64
- maxTimeToLive,
65
- targets,
66
- })
67
- : Promise.resolve(authClient.getIdentity())
68
- const requestPromise = authClient.requestAttributes({
69
- keys,
70
- nonce: toAuthClientNonce(nonce),
71
- })
72
-
73
- const [signedAttributes, identity] = await Promise.all([
74
- requestPromise,
75
- identityPromise,
76
- ])
77
-
78
- const finalIdentity = identity ?? (await authClient.getIdentity())
79
- const isAuthenticated = await authClient.isAuthenticated()
80
- await this.authentication.commitIdentity(finalIdentity, isAuthenticated)
81
-
82
- const normalizedSignedAttributes =
83
- normalizeSignedIdentityAttributes(signedAttributes)
84
-
85
- return {
86
- principal: finalIdentity.getPrincipal().toText(),
87
- requestedKeys: keys,
88
- signedAttributes: normalizedSignedAttributes,
89
- decodedAttributes: decodeIdentityAttributeValues(
90
- normalizedSignedAttributes.data,
91
- keys
92
- ),
93
- completedAt: new Date().toISOString(),
94
- }
95
- } catch (error) {
96
- this.authentication.setAuthenticationError(error as Error)
97
- throw error
98
- }
99
- }
100
-
101
- public requestOpenId = ({
102
- keys,
103
- openIdProvider,
104
- ...rest
105
- }: RequestOpenIdIdentityAttributesParameters): Promise<IdentityAttributeResult> => {
106
- // Called (not awaited) synchronously so the user gesture is preserved.
107
- return this.request({
108
- ...rest,
109
- openIdProvider,
110
- keys: identityAttributeKeys({ openIdProvider, keys }),
111
- })
112
- }
113
- }
114
-
115
- /**
116
- * Adapts our nonce input to the `@icp-sdk/auth` nonce contract.
117
- *
118
- * v8 takes `() => Promise<Uint8Array>` — a thunk, so it can journal the value
119
- * and replay the same bytes through a redirect flow. The thunk form also opens
120
- * the transport channel synchronously, which is what preserves the user
121
- * gesture.
122
- *
123
- * Until 3.12.0 this probed `typeof authClient.memoize === "function"` to detect
124
- * v8 and fell back to a bare promise for v7. The peer range is now `^8.0.0`, so
125
- * the probe would only ever take one branch.
126
- */
127
- function toAuthClientNonce(
128
- nonce: IdentityAttributeNonce
129
- ): () => Promise<Uint8Array> {
130
- return () => Promise.resolve(typeof nonce === "function" ? nonce() : nonce)
131
- }
@@ -1,270 +0,0 @@
1
- import { IDL } from "@icp-sdk/core/candid"
2
-
3
- import type {
4
- IdentityAttributeOpenIdProvider,
5
- IdentityAttributeValues,
6
- SignedIdentityAttributes,
7
- } from "./types.js"
8
- import { IC_INTERNET_IDENTITY_PROVIDER } from "./constants.js"
9
-
10
- export const IDENTITY_ATTRIBUTES_PROVIDER = IC_INTERNET_IDENTITY_PROVIDER
11
-
12
- /**
13
- * @deprecated Use the default ClientManager identity provider or
14
- * `IDENTITY_ATTRIBUTES_PROVIDER` instead.
15
- */
16
- export const IDENTITY_ATTRIBUTES_BETA_PROVIDER = IDENTITY_ATTRIBUTES_PROVIDER
17
-
18
- const OPEN_ID_PROVIDER_URLS = {
19
- apple: "https://appleid.apple.com",
20
- google: "https://accounts.google.com",
21
- microsoft: "https://login.microsoftonline.com/{tid}/v2.0",
22
- } as const
23
-
24
- export function identityAttributeKeys({
25
- openIdProvider,
26
- keys,
27
- }: {
28
- openIdProvider: IdentityAttributeOpenIdProvider
29
- keys: string[]
30
- }): string[] {
31
- const provider = normalizeOpenIdProvider(openIdProvider)
32
- return keys.map((key) => `openid:${provider}:${key}`)
33
- }
34
-
35
- export function normalizeOpenIdProvider(
36
- openIdProvider: IdentityAttributeOpenIdProvider
37
- ): string {
38
- return (
39
- OPEN_ID_PROVIDER_URLS[
40
- openIdProvider as keyof typeof OPEN_ID_PROVIDER_URLS
41
- ] ?? openIdProvider
42
- )
43
- }
44
-
45
- export async function resolveIdentityAttributeKeys({
46
- openIdProvider,
47
- keys,
48
- }: {
49
- openIdProvider: IdentityAttributeOpenIdProvider
50
- keys: string[]
51
- }): Promise<string[]> {
52
- return identityAttributeKeys({ openIdProvider, keys })
53
- }
54
-
55
- export function decodeIdentityAttributeValues(
56
- data: Uint8Array,
57
- requestedKeys: string[]
58
- ): IdentityAttributeValues {
59
- const requestedKeyMap = requestedKeys.reduce<Record<string, string>>(
60
- (acc, key) => {
61
- acc[key] = identityAttributeDisplayKey(key)
62
- acc[identityAttributeDisplayKey(key)] = identityAttributeDisplayKey(key)
63
- return acc
64
- },
65
- {}
66
- )
67
-
68
- const decodedValues = decodeCandidAttributeValues(data, requestedKeyMap)
69
- if (Object.keys(decodedValues).length > 0) {
70
- return decodedValues
71
- }
72
-
73
- return extractPrintableAttributeValues(data, requestedKeys)
74
- }
75
-
76
- function decodeCandidAttributeValues(
77
- data: Uint8Array,
78
- requestedKeyMap: Record<string, string>
79
- ): IdentityAttributeValues {
80
- const textPairs = IDL.Vec(IDL.Tuple(IDL.Text, IDL.Text))
81
- const recordPairs = IDL.Vec(
82
- IDL.Record({
83
- key: IDL.Text,
84
- value: IDL.Text,
85
- })
86
- )
87
-
88
- const candidates = [
89
- [textPairs],
90
- [recordPairs],
91
- [IDL.Record({ attributes: textPairs })],
92
- [IDL.Record({ values: textPairs })],
93
- [IDL.Record({ attributes: recordPairs })],
94
- [IDL.Record({ values: recordPairs })],
95
- ]
96
-
97
- for (const candidate of candidates) {
98
- try {
99
- const decoded = IDL.decode(candidate, data)
100
- const values = collectDecodedAttributeValues(decoded, requestedKeyMap)
101
- if (Object.keys(values).length > 0) {
102
- return values
103
- }
104
- } catch {
105
- // Try the next known beta payload shape, then fall back to text extraction.
106
- }
107
- }
108
-
109
- return {}
110
- }
111
-
112
- function collectDecodedAttributeValues(
113
- value: unknown,
114
- requestedKeyMap: Record<string, string>,
115
- activeKey?: string
116
- ): IdentityAttributeValues {
117
- const values: IdentityAttributeValues = {}
118
-
119
- if (typeof value === "string") {
120
- const displayKey = requestedKeyMap[value]
121
- if (displayKey) {
122
- return values
123
- }
124
- if (activeKey && isPrintableTextValue(value)) {
125
- values[activeKey] = value
126
- }
127
- return values
128
- }
129
-
130
- if (Array.isArray(value)) {
131
- if (value.length === 2 && typeof value[0] === "string") {
132
- const displayKey = requestedKeyMap[value[0]]
133
- if (
134
- displayKey &&
135
- typeof value[1] === "string" &&
136
- isPrintableTextValue(value[1])
137
- ) {
138
- values[displayKey] = value[1]
139
- return values
140
- }
141
- }
142
-
143
- for (const item of value) {
144
- Object.assign(
145
- values,
146
- collectDecodedAttributeValues(item, requestedKeyMap, activeKey)
147
- )
148
- }
149
- return values
150
- }
151
-
152
- if (value && typeof value === "object") {
153
- const record = value as Record<string, unknown>
154
- if (typeof record.key === "string" && typeof record.value === "string") {
155
- const displayKey = requestedKeyMap[record.key]
156
- if (displayKey && isPrintableTextValue(record.value)) {
157
- values[displayKey] = record.value
158
- return values
159
- }
160
- }
161
-
162
- for (const [key, nested] of Object.entries(record)) {
163
- const displayKey = requestedKeyMap[key] ?? activeKey
164
- if (
165
- displayKey &&
166
- typeof nested === "string" &&
167
- isPrintableTextValue(nested)
168
- ) {
169
- values[displayKey] = nested
170
- continue
171
- }
172
- Object.assign(
173
- values,
174
- collectDecodedAttributeValues(nested, requestedKeyMap, displayKey)
175
- )
176
- }
177
- }
178
-
179
- return values
180
- }
181
-
182
- function extractPrintableAttributeValues(
183
- data: Uint8Array,
184
- requestedKeys: string[]
185
- ): IdentityAttributeValues {
186
- const text = new TextDecoder().decode(data)
187
- const values: IdentityAttributeValues = {}
188
-
189
- for (const requestedKey of requestedKeys) {
190
- const start = text.indexOf(requestedKey)
191
- if (start === -1) {
192
- continue
193
- }
194
-
195
- const tail = text.slice(start + requestedKey.length)
196
- const printableRuns = tail.match(/[\x20-\x7E]{2,512}/g) ?? []
197
- const value = printableRuns
198
- .map((candidate) =>
199
- cleanPrintableAttributeValue(candidate, requestedKeys)
200
- )
201
- .find(
202
- (candidate) =>
203
- isPrintableTextValue(candidate) &&
204
- candidate !== requestedKey &&
205
- !candidate.startsWith("openid:")
206
- )
207
-
208
- if (value) {
209
- values[identityAttributeDisplayKey(requestedKey)] = value.trim()
210
- }
211
- }
212
-
213
- return values
214
- }
215
-
216
- function cleanPrintableAttributeValue(
217
- value: string,
218
- requestedKeys: string[]
219
- ): string {
220
- let cleaned = value
221
-
222
- for (const requestedKey of requestedKeys) {
223
- const nextKeyIndex = cleaned.indexOf(requestedKey)
224
- if (nextKeyIndex > 0) {
225
- cleaned = cleaned.slice(
226
- 0,
227
- trimCandidTextLengthPrefix(cleaned, nextKeyIndex)
228
- )
229
- }
230
- }
231
-
232
- const nextOpenIdKeyIndex = cleaned.indexOf("openid:")
233
- if (nextOpenIdKeyIndex > 0) {
234
- cleaned = cleaned.slice(
235
- 0,
236
- trimCandidTextLengthPrefix(cleaned, nextOpenIdKeyIndex)
237
- )
238
- }
239
-
240
- return cleaned.trim()
241
- }
242
-
243
- function trimCandidTextLengthPrefix(value: string, index: number): number {
244
- let trimmedIndex = index
245
- while (trimmedIndex > 0 && isAsciiDigit(value.charCodeAt(trimmedIndex - 1))) {
246
- trimmedIndex -= 1
247
- }
248
- return trimmedIndex
249
- }
250
-
251
- function isAsciiDigit(charCode: number): boolean {
252
- return charCode >= 48 && charCode <= 57
253
- }
254
-
255
- function identityAttributeDisplayKey(key: string): string {
256
- return key.split(":").pop() || key
257
- }
258
-
259
- function isPrintableTextValue(value: string): boolean {
260
- return value.length > 0 && value.length <= 512 && /^[\x20-\x7E]+$/.test(value)
261
- }
262
-
263
- export function normalizeSignedIdentityAttributes(
264
- attributes: SignedIdentityAttributes
265
- ): SignedIdentityAttributes {
266
- return {
267
- data: new Uint8Array(attributes.data),
268
- signature: new Uint8Array(attributes.signature),
269
- }
270
- }
package/src/auth/index.ts DELETED
@@ -1,7 +0,0 @@
1
- export * from "./authentication-manager.js"
2
- export * from "./identity-attributes-manager.js"
3
- export * from "./identity-attributes.js"
4
- export * from "./constants.js"
5
- export * from "./types.js"
6
- export * from "../hooks/createAuthHooks.js"
7
- export * from "./createIdentityAttributeHooks.js"