@ic-reactor/react 3.6.0 → 3.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.
- package/README.md +28 -8
- package/dist/auth/authentication-manager.d.ts +66 -0
- package/dist/auth/authentication-manager.d.ts.map +1 -0
- package/dist/auth/authentication-manager.js +458 -0
- package/dist/auth/authentication-manager.js.map +1 -0
- package/dist/auth/constants.d.ts +18 -0
- package/dist/auth/constants.d.ts.map +1 -0
- package/dist/auth/constants.js +18 -0
- package/dist/auth/constants.js.map +1 -0
- package/dist/auth/createIdentityAttributeHooks.d.ts +14 -0
- package/dist/auth/createIdentityAttributeHooks.d.ts.map +1 -0
- package/dist/auth/createIdentityAttributeHooks.js +54 -0
- package/dist/auth/createIdentityAttributeHooks.js.map +1 -0
- package/dist/auth/identity-attributes-manager.d.ts +19 -0
- package/dist/auth/identity-attributes-manager.d.ts.map +1 -0
- package/dist/auth/identity-attributes-manager.js +94 -0
- package/dist/auth/identity-attributes-manager.js.map +1 -0
- package/dist/auth/identity-attributes.d.ts +19 -0
- package/dist/auth/identity-attributes.d.ts.map +1 -0
- package/dist/auth/identity-attributes.js +170 -0
- package/dist/auth/identity-attributes.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/types.d.ts +75 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/createActorHooks.d.ts +12 -12
- package/dist/createActorHooks.d.ts.map +1 -1
- package/dist/createActorHooks.js.map +1 -1
- package/dist/createInfiniteQuery.d.ts +32 -32
- package/dist/createInfiniteQuery.d.ts.map +1 -1
- package/dist/createInfiniteQuery.js +6 -6
- package/dist/createInfiniteQuery.js.map +1 -1
- package/dist/createMutation.d.ts +12 -1
- package/dist/createMutation.d.ts.map +1 -1
- package/dist/createMutation.js +11 -0
- package/dist/createMutation.js.map +1 -1
- package/dist/createQuery.d.ts +12 -2
- package/dist/createQuery.d.ts.map +1 -1
- package/dist/createQuery.js +15 -5
- package/dist/createQuery.js.map +1 -1
- package/dist/createSuspenseInfiniteQuery.d.ts +31 -31
- package/dist/createSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/createSuspenseInfiniteQuery.js +6 -6
- package/dist/createSuspenseInfiniteQuery.js.map +1 -1
- package/dist/createSuspenseQuery.d.ts +2 -2
- package/dist/createSuspenseQuery.d.ts.map +1 -1
- package/dist/createSuspenseQuery.js.map +1 -1
- package/dist/defineReactor.d.ts +74 -0
- package/dist/defineReactor.d.ts.map +1 -0
- package/dist/defineReactor.js +75 -0
- package/dist/defineReactor.js.map +1 -0
- package/dist/{createAuthHooks.d.ts → hooks/createAuthHooks.d.ts} +6 -13
- package/dist/hooks/createAuthHooks.d.ts.map +1 -0
- package/dist/{createAuthHooks.js → hooks/createAuthHooks.js} +12 -57
- package/dist/hooks/createAuthHooks.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.d.ts +9 -9
- package/dist/hooks/useActorInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorInfiniteQuery.js +3 -1
- package/dist/hooks/useActorInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorMethod.d.ts +17 -17
- package/dist/hooks/useActorMethod.d.ts.map +1 -1
- package/dist/hooks/useActorMethod.js.map +1 -1
- package/dist/hooks/useActorMutation.d.ts +18 -7
- package/dist/hooks/useActorMutation.d.ts.map +1 -1
- package/dist/hooks/useActorMutation.js +11 -0
- package/dist/hooks/useActorMutation.js.map +1 -1
- package/dist/hooks/useActorQuery.d.ts +8 -8
- package/dist/hooks/useActorQuery.d.ts.map +1 -1
- package/dist/hooks/useActorQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts +9 -9
- package/dist/hooks/useActorSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js +3 -1
- package/dist/hooks/useActorSuspenseInfiniteQuery.js.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.d.ts +8 -8
- package/dist/hooks/useActorSuspenseQuery.d.ts.map +1 -1
- package/dist/hooks/useActorSuspenseQuery.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +24 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -2
- package/dist/utils.js.map +1 -1
- package/llms.txt +48 -0
- package/package.json +27 -21
- package/src/auth/authentication-manager.ts +519 -0
- package/src/auth/constants.ts +25 -0
- package/src/auth/createIdentityAttributeHooks.ts +83 -0
- package/src/auth/identity-attributes-manager.ts +127 -0
- package/src/auth/identity-attributes.ts +270 -0
- package/src/auth/index.ts +7 -0
- package/src/auth/types.ts +88 -0
- package/src/createActorHooks.ts +81 -49
- package/src/createInfiniteQuery.ts +153 -97
- package/src/createMutation.ts +34 -18
- package/src/createQuery.ts +92 -48
- package/src/createSuspenseInfiniteQuery.ts +165 -114
- package/src/createSuspenseQuery.ts +67 -41
- package/src/defineReactor.test.ts +70 -0
- package/src/defineReactor.ts +150 -0
- package/src/{createAuthHooks.ts → hooks/createAuthHooks.ts} +17 -98
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useActorInfiniteQuery.ts +44 -30
- package/src/hooks/useActorMethod.ts +62 -53
- package/src/hooks/useActorMutation.ts +47 -30
- package/src/hooks/useActorQuery.ts +36 -32
- package/src/hooks/useActorSuspenseInfiniteQuery.ts +56 -30
- package/src/hooks/useActorSuspenseQuery.ts +42 -32
- package/src/index.ts +3 -1
- package/src/types.ts +76 -71
- package/src/utils.test.ts +14 -0
- package/src/utils.ts +15 -2
- package/dist/createAuthHooks.d.ts.map +0 -1
- package/dist/createAuthHooks.js.map +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthenticationClientOptions,
|
|
3
|
+
IdentityAttributeResult,
|
|
4
|
+
RequestIdentityAttributesParameters,
|
|
5
|
+
RequestOpenIdIdentityAttributesParameters,
|
|
6
|
+
} from "./types"
|
|
7
|
+
|
|
8
|
+
import { AuthenticationManager } from "./authentication-manager"
|
|
9
|
+
import {
|
|
10
|
+
decodeIdentityAttributeValues,
|
|
11
|
+
identityAttributeKeys,
|
|
12
|
+
normalizeSignedIdentityAttributes,
|
|
13
|
+
} from "./identity-attributes"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Requests and decodes signed identity attributes for an authenticated
|
|
17
|
+
* Internet Identity session.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const attributes = new IdentityAttributesManager(authentication)
|
|
22
|
+
* const result = await attributes.request({ keys: ["name"] })
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class IdentityAttributesManager {
|
|
26
|
+
constructor(public readonly authentication: AuthenticationManager) {}
|
|
27
|
+
|
|
28
|
+
public request = async ({
|
|
29
|
+
keys,
|
|
30
|
+
nonce,
|
|
31
|
+
identityProvider,
|
|
32
|
+
openIdProvider,
|
|
33
|
+
windowOpenerFeatures,
|
|
34
|
+
signIn = true,
|
|
35
|
+
maxTimeToLive,
|
|
36
|
+
targets,
|
|
37
|
+
}: RequestIdentityAttributesParameters): Promise<IdentityAttributeResult> => {
|
|
38
|
+
const authClient = await this.authentication.ensureClient(
|
|
39
|
+
getAuthClientOptions({
|
|
40
|
+
identityProvider,
|
|
41
|
+
windowOpenerFeatures,
|
|
42
|
+
openIdProvider,
|
|
43
|
+
})
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if (!authClient) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
"Authentication module is missing or failed to initialize. To request identity attributes, please install @icp-sdk/auth v7 or provide a compatible authClient."
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.authentication.setAuthenticating()
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const identityPromise = signIn
|
|
56
|
+
? this.authentication.signInOrRecoverIdentity({
|
|
57
|
+
maxTimeToLive,
|
|
58
|
+
targets,
|
|
59
|
+
})
|
|
60
|
+
: Promise.resolve(authClient.getIdentity())
|
|
61
|
+
const requestPromise = authClient.requestAttributes({ keys, nonce })
|
|
62
|
+
|
|
63
|
+
const [signedAttributes, identity] = await Promise.all([
|
|
64
|
+
requestPromise,
|
|
65
|
+
identityPromise,
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
const finalIdentity = identity ?? (await authClient.getIdentity())
|
|
69
|
+
const isAuthenticated = await authClient.isAuthenticated()
|
|
70
|
+
await this.authentication.commitIdentity(finalIdentity, isAuthenticated)
|
|
71
|
+
|
|
72
|
+
const normalizedSignedAttributes =
|
|
73
|
+
normalizeSignedIdentityAttributes(signedAttributes)
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
principal: finalIdentity.getPrincipal().toText(),
|
|
77
|
+
requestedKeys: keys,
|
|
78
|
+
signedAttributes: normalizedSignedAttributes,
|
|
79
|
+
decodedAttributes: decodeIdentityAttributeValues(
|
|
80
|
+
normalizedSignedAttributes.data,
|
|
81
|
+
keys
|
|
82
|
+
),
|
|
83
|
+
completedAt: new Date().toISOString(),
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.authentication.setAuthenticationError(error as Error)
|
|
87
|
+
throw error
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public requestOpenId = async ({
|
|
92
|
+
nonce,
|
|
93
|
+
openIdProvider,
|
|
94
|
+
keys,
|
|
95
|
+
identityProvider,
|
|
96
|
+
windowOpenerFeatures,
|
|
97
|
+
signIn,
|
|
98
|
+
maxTimeToLive,
|
|
99
|
+
targets,
|
|
100
|
+
}: RequestOpenIdIdentityAttributesParameters): Promise<IdentityAttributeResult> => {
|
|
101
|
+
return this.request({
|
|
102
|
+
keys: identityAttributeKeys({ openIdProvider, keys }),
|
|
103
|
+
nonce,
|
|
104
|
+
identityProvider,
|
|
105
|
+
openIdProvider,
|
|
106
|
+
windowOpenerFeatures,
|
|
107
|
+
signIn,
|
|
108
|
+
maxTimeToLive,
|
|
109
|
+
targets,
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getAuthClientOptions(
|
|
115
|
+
options: AuthenticationClientOptions
|
|
116
|
+
): AuthenticationClientOptions {
|
|
117
|
+
return {
|
|
118
|
+
identityProvider: options.identityProvider,
|
|
119
|
+
windowOpenerFeatures: options.windowOpenerFeatures,
|
|
120
|
+
openIdProvider:
|
|
121
|
+
options.openIdProvider === "google" ||
|
|
122
|
+
options.openIdProvider === "apple" ||
|
|
123
|
+
options.openIdProvider === "microsoft"
|
|
124
|
+
? options.openIdProvider
|
|
125
|
+
: undefined,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { IDL } from "@icp-sdk/core/candid"
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
IdentityAttributeOpenIdProvider,
|
|
5
|
+
IdentityAttributeValues,
|
|
6
|
+
SignedIdentityAttributes,
|
|
7
|
+
} from "./types"
|
|
8
|
+
import { IC_INTERNET_IDENTITY_PROVIDER } from "./constants"
|
|
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
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./authentication-manager"
|
|
2
|
+
export * from "./identity-attributes-manager"
|
|
3
|
+
export * from "./identity-attributes"
|
|
4
|
+
export * from "./constants"
|
|
5
|
+
export * from "./types"
|
|
6
|
+
export * from "../hooks/createAuthHooks"
|
|
7
|
+
export * from "./createIdentityAttributeHooks"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Identity } from "@icp-sdk/core/agent"
|
|
2
|
+
import type { Principal } from "@icp-sdk/core/principal"
|
|
3
|
+
|
|
4
|
+
export interface SignedIdentityAttributes {
|
|
5
|
+
data: Uint8Array
|
|
6
|
+
signature: Uint8Array
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface IdentityAttributeRequest {
|
|
10
|
+
keys: string[]
|
|
11
|
+
nonce: Uint8Array
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IdentityAttributeValues {
|
|
15
|
+
email?: string
|
|
16
|
+
name?: string
|
|
17
|
+
verified_email?: string
|
|
18
|
+
[key: string]: string | undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface IdentityAttributeResult {
|
|
22
|
+
principal: string
|
|
23
|
+
requestedKeys: string[]
|
|
24
|
+
signedAttributes: SignedIdentityAttributes
|
|
25
|
+
decodedAttributes: IdentityAttributeValues
|
|
26
|
+
completedAt: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type IdentityAttributeOpenIdProviderAlias = "google" | "apple" | "microsoft"
|
|
30
|
+
|
|
31
|
+
export type IdentityAttributeOpenIdProvider =
|
|
32
|
+
IdentityAttributeOpenIdProviderAlias | (string & {})
|
|
33
|
+
|
|
34
|
+
export interface AuthenticationClientOptions {
|
|
35
|
+
identityProvider?: string | URL
|
|
36
|
+
windowOpenerFeatures?: string
|
|
37
|
+
openIdProvider?: IdentityAttributeOpenIdProvider
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface AuthClientSignInOptions {
|
|
41
|
+
maxTimeToLive?: bigint
|
|
42
|
+
targets?: Principal[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AuthenticationSignInOptions
|
|
46
|
+
extends AuthClientSignInOptions, AuthenticationClientOptions {
|
|
47
|
+
onSuccess?: () => void | Promise<void>
|
|
48
|
+
onError?: (error?: string) => void | Promise<void>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface RequestIdentityAttributesParameters {
|
|
52
|
+
keys: string[]
|
|
53
|
+
nonce: Uint8Array
|
|
54
|
+
identityProvider?: string | URL
|
|
55
|
+
openIdProvider?: IdentityAttributeOpenIdProvider
|
|
56
|
+
windowOpenerFeatures?: string
|
|
57
|
+
signIn?: boolean
|
|
58
|
+
maxTimeToLive?: bigint
|
|
59
|
+
targets?: Principal[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface RequestOpenIdIdentityAttributesParameters {
|
|
63
|
+
nonce: Uint8Array
|
|
64
|
+
openIdProvider: IdentityAttributeOpenIdProvider
|
|
65
|
+
keys: string[]
|
|
66
|
+
identityProvider?: string | URL
|
|
67
|
+
windowOpenerFeatures?: string
|
|
68
|
+
signIn?: boolean
|
|
69
|
+
maxTimeToLive?: bigint
|
|
70
|
+
targets?: Principal[]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface AuthClientLike {
|
|
74
|
+
getIdentity(): Promise<Identity> | Identity
|
|
75
|
+
isAuthenticated(): Promise<boolean> | boolean
|
|
76
|
+
signIn(options?: AuthClientSignInOptions): Promise<Identity>
|
|
77
|
+
signOut(options?: { returnTo?: string }): Promise<void>
|
|
78
|
+
requestAttributes(
|
|
79
|
+
params: IdentityAttributeRequest
|
|
80
|
+
): Promise<SignedIdentityAttributes>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface AuthState {
|
|
84
|
+
identity: Identity | null
|
|
85
|
+
isAuthenticating: boolean
|
|
86
|
+
isAuthenticated: boolean
|
|
87
|
+
error: Error | undefined
|
|
88
|
+
}
|
package/src/createActorHooks.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
DisplayReactor,
|
|
22
22
|
ReactorReturnErr,
|
|
23
23
|
ReactorReturnOk,
|
|
24
|
+
ReactorQueryData,
|
|
24
25
|
BaseActor,
|
|
25
26
|
FunctionName,
|
|
26
27
|
TransformKey,
|
|
@@ -46,102 +47,133 @@ import { InfiniteQueryConfig } from "./createInfiniteQuery"
|
|
|
46
47
|
import { SuspenseInfiniteQueryConfig } from "./createSuspenseInfiniteQuery"
|
|
47
48
|
import { QueryConfig, SuspenseQueryConfig, MutationConfig } from "./types"
|
|
48
49
|
|
|
49
|
-
export type ActorHooks<
|
|
50
|
+
export type ActorHooks<Service, Transform extends TransformKey> = {
|
|
50
51
|
useActorQuery: {
|
|
51
|
-
<
|
|
52
|
-
config: QueryConfig<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
<Method extends FunctionName<Service>>(
|
|
53
|
+
config: QueryConfig<
|
|
54
|
+
Service,
|
|
55
|
+
Method,
|
|
56
|
+
Transform,
|
|
57
|
+
ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>
|
|
58
|
+
>
|
|
59
|
+
): UseQueryResult<
|
|
60
|
+
ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
|
|
61
|
+
ReactorReturnErr<Service, Method, Transform>
|
|
62
|
+
>
|
|
63
|
+
<Method extends FunctionName<Service>, TData>(
|
|
64
|
+
config: QueryConfig<Service, Method, Transform, TData>
|
|
65
|
+
): UseQueryResult<TData, ReactorReturnErr<Service, Method, Transform>>
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
useActorSuspenseQuery: {
|
|
60
|
-
<
|
|
61
|
-
config: SuspenseQueryConfig<
|
|
69
|
+
<Method extends FunctionName<Service>>(
|
|
70
|
+
config: SuspenseQueryConfig<
|
|
71
|
+
Service,
|
|
72
|
+
Method,
|
|
73
|
+
Transform,
|
|
74
|
+
ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>
|
|
75
|
+
>
|
|
76
|
+
): UseSuspenseQueryResult<
|
|
77
|
+
ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
|
|
78
|
+
ReactorReturnErr<Service, Method, Transform>
|
|
79
|
+
>
|
|
80
|
+
<Method extends FunctionName<Service>, TData>(
|
|
81
|
+
config: SuspenseQueryConfig<Service, Method, Transform, TData>
|
|
62
82
|
): UseSuspenseQueryResult<
|
|
63
|
-
|
|
64
|
-
ReactorReturnErr<
|
|
83
|
+
TData,
|
|
84
|
+
ReactorReturnErr<Service, Method, Transform>
|
|
65
85
|
>
|
|
66
|
-
<M extends FunctionName<A>, TData>(
|
|
67
|
-
config: SuspenseQueryConfig<A, M, T, TData>
|
|
68
|
-
): UseSuspenseQueryResult<TData, ReactorReturnErr<A, M, T>>
|
|
69
86
|
}
|
|
70
87
|
|
|
71
|
-
useActorInfiniteQuery: <
|
|
72
|
-
|
|
88
|
+
useActorInfiniteQuery: <
|
|
89
|
+
Method extends FunctionName<Service>,
|
|
90
|
+
TPageParam = unknown,
|
|
91
|
+
>(
|
|
92
|
+
config: InfiniteQueryConfig<Service, Method, Transform, TPageParam>
|
|
73
93
|
) => UseInfiniteQueryResult<
|
|
74
|
-
InfiniteData<
|
|
75
|
-
|
|
94
|
+
InfiniteData<
|
|
95
|
+
ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
|
|
96
|
+
TPageParam
|
|
97
|
+
>,
|
|
98
|
+
ReactorReturnErr<Service, Method, Transform>
|
|
76
99
|
>
|
|
77
100
|
|
|
78
101
|
useActorSuspenseInfiniteQuery: <
|
|
79
|
-
|
|
102
|
+
Method extends FunctionName<Service>,
|
|
80
103
|
TPageParam = unknown,
|
|
81
104
|
>(
|
|
82
|
-
config: SuspenseInfiniteQueryConfig<
|
|
105
|
+
config: SuspenseInfiniteQueryConfig<Service, Method, Transform, TPageParam>
|
|
83
106
|
) => UseSuspenseInfiniteQueryResult<
|
|
84
|
-
InfiniteData<
|
|
85
|
-
|
|
107
|
+
InfiniteData<
|
|
108
|
+
ReactorQueryData<ReactorReturnOk<Service, Method, Transform>>,
|
|
109
|
+
TPageParam
|
|
110
|
+
>,
|
|
111
|
+
ReactorReturnErr<Service, Method, Transform>
|
|
86
112
|
>
|
|
87
113
|
|
|
88
|
-
useActorMutation: <
|
|
89
|
-
config: MutationConfig<
|
|
90
|
-
) => UseMutationResult<
|
|
114
|
+
useActorMutation: <Method extends FunctionName<Service>>(
|
|
115
|
+
config: MutationConfig<Service, Method, Transform>
|
|
116
|
+
) => UseMutationResult<
|
|
117
|
+
ReactorReturnOk<Service, Method, Transform>,
|
|
118
|
+
ReactorReturnErr<Service, Method, Transform>
|
|
119
|
+
>
|
|
91
120
|
|
|
92
|
-
useActorMethod: <
|
|
93
|
-
config: Omit<
|
|
94
|
-
|
|
121
|
+
useActorMethod: <Method extends FunctionName<Service>>(
|
|
122
|
+
config: Omit<
|
|
123
|
+
UseActorMethodParameters<Service, Method, Transform>,
|
|
124
|
+
"reactor"
|
|
125
|
+
>
|
|
126
|
+
) => ReturnType<typeof useActorMethod<Service, Method, Transform>>
|
|
95
127
|
}
|
|
96
128
|
|
|
97
|
-
export function createActorHooks<
|
|
98
|
-
reactor: DisplayReactor<
|
|
99
|
-
): ActorHooks<
|
|
129
|
+
export function createActorHooks<Service>(
|
|
130
|
+
reactor: DisplayReactor<Service>
|
|
131
|
+
): ActorHooks<Service, "display">
|
|
100
132
|
|
|
101
133
|
export function createActorHooks<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
>(reactor: Reactor<
|
|
134
|
+
Service = BaseActor,
|
|
135
|
+
Transform extends TransformKey = "candid",
|
|
136
|
+
>(reactor: Reactor<Service, Transform>): ActorHooks<Service, Transform>
|
|
105
137
|
|
|
106
|
-
export function createActorHooks<
|
|
107
|
-
reactor: Reactor<
|
|
108
|
-
): ActorHooks<
|
|
138
|
+
export function createActorHooks<Service, Transform extends TransformKey>(
|
|
139
|
+
reactor: Reactor<Service, Transform>
|
|
140
|
+
): ActorHooks<Service, Transform> {
|
|
109
141
|
return {
|
|
110
142
|
useActorQuery: ((config: any) =>
|
|
111
143
|
useActorQuery({ ...config, reactor })) as ActorHooks<
|
|
112
|
-
|
|
113
|
-
|
|
144
|
+
Service,
|
|
145
|
+
Transform
|
|
114
146
|
>["useActorQuery"],
|
|
115
147
|
|
|
116
148
|
useActorSuspenseQuery: ((config: any) =>
|
|
117
149
|
useActorSuspenseQuery({ ...config, reactor })) as ActorHooks<
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
Service,
|
|
151
|
+
Transform
|
|
120
152
|
>["useActorSuspenseQuery"],
|
|
121
153
|
|
|
122
154
|
useActorInfiniteQuery: ((config: any) =>
|
|
123
155
|
useActorInfiniteQuery({ ...config, reactor })) as ActorHooks<
|
|
124
|
-
|
|
125
|
-
|
|
156
|
+
Service,
|
|
157
|
+
Transform
|
|
126
158
|
>["useActorInfiniteQuery"],
|
|
127
159
|
|
|
128
160
|
useActorSuspenseInfiniteQuery: ((config: any) =>
|
|
129
161
|
useActorSuspenseInfiniteQuery({ ...config, reactor })) as ActorHooks<
|
|
130
|
-
|
|
131
|
-
|
|
162
|
+
Service,
|
|
163
|
+
Transform
|
|
132
164
|
>["useActorSuspenseInfiniteQuery"],
|
|
133
165
|
|
|
134
166
|
useActorMutation: ((config: any) =>
|
|
135
167
|
useActorMutation({ ...config, reactor })) as ActorHooks<
|
|
136
|
-
|
|
137
|
-
|
|
168
|
+
Service,
|
|
169
|
+
Transform
|
|
138
170
|
>["useActorMutation"],
|
|
139
171
|
|
|
140
172
|
useActorMethod: (config) =>
|
|
141
173
|
useActorMethod({ ...config, reactor } as UseActorMethodParameters<
|
|
142
|
-
|
|
174
|
+
Service,
|
|
143
175
|
any,
|
|
144
|
-
|
|
176
|
+
Transform
|
|
145
177
|
>),
|
|
146
178
|
}
|
|
147
179
|
}
|