@ic-reactor/core 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.
Files changed (75) hide show
  1. package/README.md +4 -4
  2. package/dist/client.d.ts +17 -79
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +49 -527
  5. package/dist/client.js.map +1 -1
  6. package/dist/display/visitor.d.ts.map +1 -1
  7. package/dist/display/visitor.js +6 -1
  8. package/dist/display/visitor.js.map +1 -1
  9. package/dist/display-reactor.d.ts +3 -0
  10. package/dist/display-reactor.d.ts.map +1 -1
  11. package/dist/display-reactor.js +3 -0
  12. package/dist/display-reactor.js.map +1 -1
  13. package/dist/index.d.ts +0 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +0 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/reactor.d.ts +4 -4
  18. package/dist/reactor.d.ts.map +1 -1
  19. package/dist/reactor.js +27 -10
  20. package/dist/reactor.js.map +1 -1
  21. package/dist/types/client.d.ts +1 -120
  22. package/dist/types/client.d.ts.map +1 -1
  23. package/dist/types/display-reactor.d.ts.map +1 -1
  24. package/dist/types/reactor.d.ts +8 -0
  25. package/dist/types/reactor.d.ts.map +1 -1
  26. package/dist/types/variant.d.ts.map +1 -1
  27. package/dist/utils/agent.d.ts +3 -2
  28. package/dist/utils/agent.d.ts.map +1 -1
  29. package/dist/utils/agent.js +9 -3
  30. package/dist/utils/agent.js.map +1 -1
  31. package/dist/utils/constants.d.ts +0 -2
  32. package/dist/utils/constants.d.ts.map +1 -1
  33. package/dist/utils/constants.js +0 -2
  34. package/dist/utils/constants.js.map +1 -1
  35. package/dist/utils/helper.d.ts +14 -1
  36. package/dist/utils/helper.d.ts.map +1 -1
  37. package/dist/utils/helper.js +48 -9
  38. package/dist/utils/helper.js.map +1 -1
  39. package/dist/utils/index.d.ts +1 -0
  40. package/dist/utils/index.d.ts.map +1 -1
  41. package/dist/utils/index.js +1 -0
  42. package/dist/utils/index.js.map +1 -1
  43. package/dist/utils/polling.d.ts.map +1 -1
  44. package/dist/utils/polling.js +2 -2
  45. package/dist/utils/polling.js.map +1 -1
  46. package/dist/utils/query-data.d.ts +4 -0
  47. package/dist/utils/query-data.d.ts.map +1 -0
  48. package/dist/utils/query-data.js +3 -0
  49. package/dist/utils/query-data.js.map +1 -0
  50. package/dist/version.d.ts.map +1 -1
  51. package/dist/version.js +2 -2
  52. package/dist/version.js.map +1 -1
  53. package/llms.txt +43 -0
  54. package/package.json +15 -17
  55. package/src/client.ts +53 -626
  56. package/src/display/visitor.ts +10 -1
  57. package/src/display-reactor.ts +3 -0
  58. package/src/index.ts +0 -1
  59. package/src/reactor.ts +48 -18
  60. package/src/types/client.ts +1 -138
  61. package/src/types/display-reactor.ts +1 -2
  62. package/src/types/reactor.ts +15 -0
  63. package/src/types/variant.ts +8 -6
  64. package/src/utils/agent.ts +12 -3
  65. package/src/utils/constants.ts +0 -5
  66. package/src/utils/helper.ts +52 -7
  67. package/src/utils/index.ts +1 -0
  68. package/src/utils/polling.ts +3 -3
  69. package/src/utils/query-data.ts +5 -0
  70. package/src/version.ts +2 -2
  71. package/dist/identity-attributes.d.ts +0 -19
  72. package/dist/identity-attributes.d.ts.map +0 -1
  73. package/dist/identity-attributes.js +0 -167
  74. package/dist/identity-attributes.js.map +0 -1
  75. package/src/identity-attributes.ts +0 -263
@@ -154,7 +154,16 @@ export class DisplayCodecVisitor extends IDL.Visitor<unknown, z.ZodTypeAny> {
154
154
  decode: (val) => {
155
155
  if (val instanceof Principal) return val.toText()
156
156
  if (typeof val === "string") return val
157
- return String(val)
157
+ if (
158
+ val &&
159
+ typeof val === "object" &&
160
+ typeof (val as { toText?: unknown }).toText === "function"
161
+ ) {
162
+ return (val as { toText: () => string }).toText()
163
+ }
164
+ throw new TypeError(
165
+ `[ic-reactor] Cannot decode value as Principal display text: expected a string or Principal instance, got ${typeof val}`
166
+ )
158
167
  },
159
168
  encode: (val) => {
160
169
  if (typeof val === "string") return Principal.fromText(val)
@@ -44,6 +44,9 @@ import {
44
44
  * Validators receive **display types** (strings), making them perfect for
45
45
  * form validation.
46
46
  *
47
+ * Use `DisplayReactor` for UI/forms where principals and numeric values should
48
+ * be string-friendly. Use `Reactor` when you need raw Candid types directly.
49
+ *
47
50
  * @typeParam A - The actor service type
48
51
  *
49
52
  * @example
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  export * from "./reactor"
2
2
  export * from "./client"
3
3
  export * from "./utils"
4
- export * from "./identity-attributes"
5
4
  export * from "./display"
6
5
  export * from "./display-reactor"
7
6
  export * from "./types"
package/src/reactor.ts CHANGED
@@ -14,6 +14,7 @@ import type {
14
14
  TransformKey,
15
15
  ReactorArgs,
16
16
  ReactorReturnOk,
17
+ ReactorQueryData,
17
18
  ReactorQueryParams,
18
19
  ReactorCallParams,
19
20
  CanisterId,
@@ -23,6 +24,7 @@ import { DEFAULT_POLLING_OPTIONS } from "@icp-sdk/core/agent"
23
24
  import { IDL } from "@icp-sdk/core/candid"
24
25
  import { Principal } from "@icp-sdk/core/principal"
25
26
  import { generateKey, extractOkResult } from "./utils/helper"
27
+ import { toReactorQueryData } from "./utils/query-data"
26
28
  import {
27
29
  processQueryCallResponse,
28
30
  processUpdateCallResponse,
@@ -206,13 +208,23 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
206
208
  : this.canisterId.toString()
207
209
  const queryKeys: any[] = [resolvedCanisterId, params.functionName]
208
210
 
209
- if (callConfig?.effectiveCanisterId) {
210
- const effectiveCanisterId = Principal.from(
211
- callConfig.effectiveCanisterId
212
- ).toString()
213
-
214
- if (effectiveCanisterId !== resolvedCanisterId) {
215
- queryKeys.push({ effectiveCanisterId })
211
+ const effectiveTarget =
212
+ callConfig?.effectiveTarget ??
213
+ (callConfig?.effectiveCanisterId
214
+ ? { canisterId: callConfig.effectiveCanisterId }
215
+ : undefined)
216
+
217
+ if (effectiveTarget) {
218
+ const targetKey =
219
+ "canisterId" in effectiveTarget
220
+ ? { canisterId: effectiveTarget.canisterId.toString() }
221
+ : { subnetId: effectiveTarget.subnetId.toString() }
222
+
223
+ if (
224
+ !("canisterId" in targetKey) ||
225
+ targetKey.canisterId !== resolvedCanisterId
226
+ ) {
227
+ queryKeys.push({ effectiveTarget: targetKey })
216
228
  }
217
229
  }
218
230
 
@@ -232,10 +244,15 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
232
244
 
233
245
  public getQueryOptions<M extends FunctionName<A>>(
234
246
  params: ReactorCallParams<A, M, T>
235
- ): FetchQueryOptions<ReactorReturnOk<A, M, T>> {
247
+ ): FetchQueryOptions<ReactorQueryData<ReactorReturnOk<A, M, T>>> {
236
248
  return {
237
249
  queryKey: this.generateQueryKey(params, params.callConfig),
238
- queryFn: () => this.callMethod(params),
250
+ queryFn: async () => {
251
+ const result = await this.callMethod(params)
252
+ return toReactorQueryData<ReactorReturnOk<A, M, T>>(
253
+ result as ReactorReturnOk<A, M, T>
254
+ )
255
+ },
239
256
  }
240
257
  }
241
258
 
@@ -376,9 +393,11 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
376
393
  */
377
394
  public async fetchQuery<M extends FunctionName<A>>(
378
395
  params: ReactorCallParams<A, M, T>
379
- ): Promise<ReactorReturnOk<A, M, T>> {
396
+ ): Promise<ReactorQueryData<ReactorReturnOk<A, M, T>>> {
380
397
  const options = this.getQueryOptions(params)
381
- return this.queryClient.ensureQueryData<ReactorReturnOk<A, M, T>>(options)
398
+ return this.queryClient.ensureQueryData<
399
+ ReactorQueryData<ReactorReturnOk<A, M, T>>
400
+ >(options)
382
401
  }
383
402
 
384
403
  /**
@@ -387,9 +406,11 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
387
406
  public getQueryData<M extends FunctionName<A>>(
388
407
  params: ReactorQueryParams<A, M, T>,
389
408
  callConfig?: CallConfig
390
- ): ReactorReturnOk<A, M, T> | undefined {
409
+ ): ReactorQueryData<ReactorReturnOk<A, M, T>> | undefined {
391
410
  const queryKey = this.generateQueryKey(params, callConfig)
392
- return this.queryClient.getQueryData<ReactorReturnOk<A, M, T>>(queryKey)
411
+ return this.queryClient.getQueryData<
412
+ ReactorQueryData<ReactorReturnOk<A, M, T>>
413
+ >(queryKey)
393
414
  }
394
415
 
395
416
  /**
@@ -404,12 +425,16 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
404
425
  const canisterId = callConfig?.canisterId
405
426
  ? Principal.from(callConfig.canisterId)
406
427
  : this.canisterId
407
- const effectiveCanisterId = callConfig?.effectiveCanisterId ?? canisterId
428
+ const effectiveTarget =
429
+ callConfig?.effectiveTarget ??
430
+ (callConfig?.effectiveCanisterId
431
+ ? { canisterId: callConfig.effectiveCanisterId }
432
+ : { canisterId })
408
433
 
409
434
  const response = await agent.query(canisterId, {
410
435
  methodName,
411
436
  arg,
412
- effectiveCanisterId,
437
+ effectiveTarget,
413
438
  })
414
439
 
415
440
  return processQueryCallResponse(response, canisterId, methodName)
@@ -427,13 +452,17 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
427
452
  const canisterId = callConfig?.canisterId
428
453
  ? Principal.from(callConfig.canisterId)
429
454
  : this.canisterId
430
- const effectiveCanisterId = callConfig?.effectiveCanisterId ?? canisterId
455
+ const effectiveTarget =
456
+ callConfig?.effectiveTarget ??
457
+ (callConfig?.effectiveCanisterId
458
+ ? { canisterId: callConfig.effectiveCanisterId }
459
+ : { canisterId })
431
460
  const pollingOptions = callConfig?.pollingOptions ?? this.pollingOptions
432
461
 
433
462
  const response = await agent.call(canisterId, {
434
463
  methodName,
435
464
  arg,
436
- effectiveCanisterId,
465
+ effectiveTarget,
437
466
  nonce: callConfig?.nonce,
438
467
  })
439
468
 
@@ -442,7 +471,8 @@ export class Reactor<A = BaseActor, T extends TransformKey = "candid"> {
442
471
  canisterId,
443
472
  methodName,
444
473
  agent,
445
- pollingOptions
474
+ pollingOptions,
475
+ effectiveTarget
446
476
  )
447
477
  }
448
478
 
@@ -1,96 +1,12 @@
1
- import type { HttpAgent, HttpAgentOptions, Identity } from "@icp-sdk/core/agent"
2
- import type { Principal } from "@icp-sdk/core/principal"
1
+ import type { HttpAgent, HttpAgentOptions } from "@icp-sdk/core/agent"
3
2
  import type { QueryClient } from "@tanstack/query-core"
4
3
 
5
4
  /**
6
5
  * Parameters for configuring a ClientManager instance.
7
6
  *
8
7
  * @property {QueryClient} queryClient - The TanStack QueryClient used for caching and state management.
9
- * @property {number} [port] - The port used for the local IC replica (default is 4943).
10
8
  * @property {HttpAgentOptions} [agentOptions] - Optional configuration for the underlying HttpAgent.
11
- * @property {boolean} [withLocalEnv] - If true, configures the agent for a local environment.
12
- * @property {boolean} [withProcessEnv] - If true, auto-configures the agent based on process.env settings.
13
9
  */
14
- export interface SignedIdentityAttributes {
15
- data: Uint8Array
16
- signature: Uint8Array
17
- }
18
-
19
- export interface IdentityAttributeRequest {
20
- keys: string[]
21
- nonce: Uint8Array
22
- }
23
-
24
- export interface IdentityAttributeValues {
25
- email?: string
26
- name?: string
27
- verified_email?: string
28
- [key: string]: string | undefined
29
- }
30
-
31
- export interface IdentityAttributeResult {
32
- principal: string
33
- requestedKeys: string[]
34
- signedAttributes: SignedIdentityAttributes
35
- decodedAttributes: IdentityAttributeValues
36
- completedAt: string
37
- }
38
-
39
- type IdentityAttributeOpenIdProviderAlias = "google" | "apple" | "microsoft"
40
-
41
- export type IdentityAttributeOpenIdProvider =
42
- | IdentityAttributeOpenIdProviderAlias
43
- | (string & {})
44
-
45
- export interface ClientManagerAuthClientOptions {
46
- identityProvider?: string | URL
47
- windowOpenerFeatures?: string
48
- openIdProvider?: IdentityAttributeOpenIdProvider
49
- }
50
-
51
- export interface AuthClientSignInOptions {
52
- maxTimeToLive?: bigint
53
- targets?: Principal[]
54
- }
55
-
56
- export interface ClientManagerSignInOptions
57
- extends AuthClientSignInOptions, ClientManagerAuthClientOptions {
58
- onSuccess?: () => void | Promise<void>
59
- onError?: (error?: string) => void | Promise<void>
60
- }
61
-
62
- export interface RequestIdentityAttributesParameters {
63
- keys: string[]
64
- nonce: Uint8Array
65
- identityProvider?: string | URL
66
- openIdProvider?: IdentityAttributeOpenIdProvider
67
- windowOpenerFeatures?: string
68
- signIn?: boolean
69
- maxTimeToLive?: bigint
70
- targets?: Principal[]
71
- }
72
-
73
- export interface RequestOpenIdIdentityAttributesParameters {
74
- nonce: Uint8Array
75
- openIdProvider: IdentityAttributeOpenIdProvider
76
- keys: string[]
77
- identityProvider?: string | URL
78
- windowOpenerFeatures?: string
79
- signIn?: boolean
80
- maxTimeToLive?: bigint
81
- targets?: Principal[]
82
- }
83
-
84
- export interface AuthClientLike {
85
- getIdentity(): Promise<Identity> | Identity
86
- isAuthenticated(): Promise<boolean> | boolean
87
- signIn(options?: AuthClientSignInOptions): Promise<Identity>
88
- signOut(options?: { returnTo?: string }): Promise<void>
89
- requestAttributes(
90
- params: IdentityAttributeRequest
91
- ): Promise<SignedIdentityAttributes>
92
- }
93
-
94
10
  export interface ClientManagerParameters {
95
11
  /**
96
12
  * The TanStack QueryClient used for caching and state management.
@@ -100,37 +16,6 @@ export interface ClientManagerParameters {
100
16
  * Optional configuration for the underlying HttpAgent.
101
17
  */
102
18
  agentOptions?: HttpAgentOptions
103
- /**
104
- * The port used for the local IC replica (default is 4943).
105
- */
106
- port?: number
107
- /**
108
- * If true, configures the agent for a local environment.
109
- */
110
- withLocalEnv?: boolean
111
- /**
112
- * If true, auto-configures the agent based on process.env settings.
113
- */
114
- withProcessEnv?: boolean
115
- /**
116
- * Optional pre-initialized AuthClient instance.
117
- * If provided, the manager will use this instance instead of dynamically importing
118
- * and creating a new one from `@icp-sdk/auth`.
119
- * This is useful for environments where dynamic imports are not supported or
120
- * when you want to share an AuthClient instance across multiple managers.
121
- */
122
- authClient?: AuthClientLike
123
- /**
124
- * **EXPERIMENTAL** - If true, uses the canister environment from `@icp-sdk/core/agent/canister-env`
125
- * to automatically configure the agent host and root key based on the `ic_env` cookie.
126
- *
127
- * ⚠️ This feature is experimental and may cause issues with update calls on localhost development.
128
- * Use with caution and only when you need automatic environment detection from the IC SDK.
129
- *
130
- * @experimental
131
- * @default false
132
- */
133
- withCanisterEnv?: boolean
134
19
  }
135
20
 
136
21
  /**
@@ -163,28 +48,6 @@ export interface AgentState {
163
48
  isLocalhost: boolean
164
49
  }
165
50
 
166
- /**
167
- * Represents the authentication state of an agent.
168
- */
169
- export interface AuthState {
170
- identity: Identity | null
171
-
172
- /**
173
- * Indicates whether the authentication process is ongoing.
174
- */
175
- isAuthenticating: boolean
176
-
177
- /**
178
- * Indicates whether the agent is authenticated.
179
- */
180
- isAuthenticated: boolean
181
-
182
- /**
183
- * Represents any error that occurred during authentication.
184
- */
185
- error: Error | undefined
186
- }
187
-
188
51
  export interface UpdateAgentParameters extends HttpAgentOptions {
189
52
  agent?: HttpAgent
190
53
  }
@@ -15,8 +15,7 @@ import {
15
15
  * Either success (true) or failure with issues.
16
16
  */
17
17
  export type ValidationResult =
18
- | { success: true }
19
- | { success: false; issues: ValidationIssue[] }
18
+ { success: true } | { success: false; issues: ValidationIssue[] }
20
19
 
21
20
  /**
22
21
  * A validator function that validates method arguments.
@@ -130,6 +130,21 @@ export type ReactorReturnOk<
130
130
  Transform extends TransformKey = "candid",
131
131
  > = TransformReturnRegistry<OkResult<ActorMethodReturnType<A[M]>>, A>[Transform]
132
132
 
133
+ /**
134
+ * Data stored by TanStack Query for a reactor call.
135
+ *
136
+ * TanStack Query reserves `undefined` for a missing cache entry, so successful
137
+ * canister results that contain only `undefined` are represented as `null` at
138
+ * the query boundary. Direct `callMethod` calls keep their original result.
139
+ */
140
+ export type ReactorQueryData<T> = 0 extends 1 & T
141
+ ? T
142
+ : [T] extends [void]
143
+ ? null
144
+ : undefined extends T
145
+ ? Exclude<T, undefined> | null
146
+ : T
147
+
133
148
  export type ReactorReturnErr<
134
149
  A,
135
150
  M extends FunctionName<A>,
@@ -20,12 +20,14 @@ export type CandidVariant<T> =
20
20
  ? {
21
21
  _type: CandidVariantKey<T> & string
22
22
  } & {
23
- [K in CandidVariantKey<T> & string as CandidVariantValue<
24
- T,
25
- K
26
- > extends null
27
- ? never
28
- : K]: CandidVariantValue<T, K>
23
+ [
24
+ K in CandidVariantKey<T> & string as CandidVariantValue<
25
+ T,
26
+ K
27
+ > extends null
28
+ ? never
29
+ : K
30
+ ]: CandidVariantValue<T, K>
29
31
  }
30
32
  : T
31
33
 
@@ -4,6 +4,7 @@ import type {
4
4
  HttpDetailsResponse,
5
5
  PollingOptions,
6
6
  SubmitResponse,
7
+ TargetPrincipal,
7
8
  } from "@icp-sdk/core/agent"
8
9
  import { Principal } from "@icp-sdk/core/principal"
9
10
 
@@ -40,6 +41,8 @@ export function processQueryCallResponse(
40
41
  canisterId: Principal,
41
42
  methodName: string
42
43
  ): Uint8Array {
44
+ const effectiveTarget = { canisterId }
45
+
43
46
  switch (response.status) {
44
47
  case QueryResponseStatus.Rejected: {
45
48
  const uncertifiedRejectErrorCode = new UncertifiedRejectErrorCode(
@@ -51,6 +54,7 @@ export function processQueryCallResponse(
51
54
  )
52
55
  uncertifiedRejectErrorCode.callContext = {
53
56
  canisterId,
57
+ effectiveTarget,
54
58
  methodName,
55
59
  httpDetails: response.httpDetails,
56
60
  }
@@ -79,6 +83,7 @@ export function processQueryCallResponse(
79
83
  * @param methodName - The method name being called
80
84
  * @param agent - The HTTP agent
81
85
  * @param pollingOptions - Options for polling
86
+ * @param effectiveTarget - Canister or subnet used to route and verify the call
82
87
  * @returns The raw reply bytes
83
88
  * @throws RejectError if the call was rejected
84
89
  * @throws UnknownError if the response format is unexpected
@@ -88,7 +93,8 @@ export async function processUpdateCallResponse(
88
93
  canisterId: Principal,
89
94
  methodName: string,
90
95
  agent: Agent,
91
- pollingOptions: PollingOptions
96
+ pollingOptions: PollingOptions,
97
+ effectiveTarget: TargetPrincipal
92
98
  ): Promise<Uint8Array> {
93
99
  let reply: Uint8Array | undefined
94
100
  let certificate: Certificate | undefined
@@ -101,7 +107,7 @@ export async function processUpdateCallResponse(
101
107
  certificate = await Certificate.create({
102
108
  certificate: cert,
103
109
  rootKey: agent.rootKey,
104
- principal: { canisterId },
110
+ principal: effectiveTarget,
105
111
  agent,
106
112
  })
107
113
 
@@ -144,6 +150,7 @@ export async function processUpdateCallResponse(
144
150
  )
145
151
  certifiedRejectErrorCode.callContext = {
146
152
  canisterId,
153
+ effectiveTarget,
147
154
  methodName,
148
155
  httpDetails: result.response,
149
156
  }
@@ -160,6 +167,7 @@ export async function processUpdateCallResponse(
160
167
  )
161
168
  errorCode.callContext = {
162
169
  canisterId,
170
+ effectiveTarget,
163
171
  methodName,
164
172
  httpDetails: result.response,
165
173
  }
@@ -171,7 +179,7 @@ export async function processUpdateCallResponse(
171
179
  // Contains the certificate and the reply from the boundary node
172
180
  const response = await pollForResponse(
173
181
  agent,
174
- canisterId,
182
+ effectiveTarget,
175
183
  result.requestId,
176
184
  pollingOptions
177
185
  )
@@ -193,6 +201,7 @@ export async function processUpdateCallResponse(
193
201
  )
194
202
  errorCode.callContext = {
195
203
  canisterId,
204
+ effectiveTarget,
196
205
  methodName,
197
206
  httpDetails,
198
207
  }
@@ -5,8 +5,3 @@ export const LOCAL_HOSTS = ["localhost", "127.0.0.1"]
5
5
  export const IC_HOST_NETWORK_URI = "https://ic0.app"
6
6
 
7
7
  export const LOCAL_HOST_NETWORK_URI = "http://127.0.0.1:4943"
8
-
9
- export const IC_INTERNET_IDENTITY_PROVIDER = "https://id.ai/authorize"
10
-
11
- export const LOCAL_INTERNET_IDENTITY_PROVIDER =
12
- "http://rdmx6-jaaaa-aaaaa-aaadq-cai.localhost:4943/authorize"
@@ -8,23 +8,37 @@ export const generateKey = (args: any[]) => {
8
8
  )
9
9
  }
10
10
 
11
+ const getEnv = () => {
12
+ try {
13
+ return process.env
14
+ } catch {
15
+ return undefined
16
+ }
17
+ }
18
+
11
19
  /**
12
20
  * Checks if the current environment is local or development.
13
21
  *
22
+ * Honors both legacy `DFX_NETWORK` (dfx) and `ICP_NETWORK` (icp-cli).
23
+ *
14
24
  * @returns `true` if running in a local or development environment, otherwise `false`.
15
25
  */
16
26
  export const isInLocalOrDevelopment = () => {
17
- return typeof process !== "undefined" && process.env.DFX_NETWORK === "local"
27
+ const env = getEnv()
28
+ return env?.DFX_NETWORK === "local" || env?.ICP_NETWORK === "local"
18
29
  }
19
30
 
20
31
  /**
21
32
  * Retrieves the network from the process environment variables.
22
33
  *
34
+ * Honors both legacy `DFX_NETWORK` (dfx) and `ICP_NETWORK` (icp-cli),
35
+ * with `ICP_NETWORK` taking precedence when both are set.
36
+ *
23
37
  * @returns The network name, defaulting to "ic" if not specified.
24
38
  */
25
39
  export const getProcessEnvNetwork = () => {
26
- if (typeof process === "undefined") return "ic"
27
- else return process.env.DFX_NETWORK ?? "ic"
40
+ const env = getEnv()
41
+ return env?.ICP_NETWORK ?? env?.DFX_NETWORK ?? "ic"
28
42
  }
29
43
 
30
44
  /**
@@ -33,19 +47,50 @@ export const getProcessEnvNetwork = () => {
33
47
  * Checks in order:
34
48
  * - `import.meta.env?.DEV` (Vite / ESM environments)
35
49
  * - `process.env.NODE_ENV === 'development'` (Node)
36
- * - `process.env.DFX_NETWORK === 'local'` (local IC replica)
50
+ * - `process.env.DFX_NETWORK === 'local'` (dfx local replica)
51
+ * - `process.env.ICP_NETWORK === 'local'` (icp-cli local network)
37
52
  */
38
53
  export const isDev = (): boolean => {
39
54
  const importMetaDev =
40
55
  typeof import.meta !== "undefined" && (import.meta as any).env?.DEV
56
+ const env = getEnv()
41
57
  const nodeDev =
42
- typeof process !== "undefined" &&
43
- (process.env.NODE_ENV === "development" ||
44
- process.env.DFX_NETWORK === "local")
58
+ env?.NODE_ENV === "development" ||
59
+ env?.DFX_NETWORK === "local" ||
60
+ env?.ICP_NETWORK === "local"
45
61
 
46
62
  return Boolean(importMetaDev || nodeDev)
47
63
  }
48
64
 
65
+ /**
66
+ * Checks if a given host URL is a mainnet Internet Computer boundary node host.
67
+ *
68
+ * @param host - The host URL to evaluate.
69
+ * @returns `true` if the host is a mainnet host, default to true if host is undefined, otherwise `false`.
70
+ */
71
+ export const isMainnetHost = (host?: string): boolean => {
72
+ if (!host) return true
73
+
74
+ try {
75
+ const url = new URL(
76
+ host.startsWith("http")
77
+ ? host
78
+ : `${typeof window !== "undefined" ? window.location.protocol : "https:"}//${host}`
79
+ )
80
+ const hostname = url.hostname
81
+ return (
82
+ hostname === "ic0.app" ||
83
+ hostname.endsWith(".ic0.app") ||
84
+ hostname === "icp0.io" ||
85
+ hostname.endsWith(".icp0.io") ||
86
+ hostname === "icp-api.io" ||
87
+ hostname.endsWith(".icp-api.io")
88
+ )
89
+ } catch {
90
+ return false
91
+ }
92
+ }
93
+
49
94
  /**
50
95
  * Determines the network type based on the provided hostname.
51
96
  *
@@ -4,3 +4,4 @@ export * from "./helper"
4
4
  export * from "./polling"
5
5
  export * from "./zod"
6
6
  export * from "./agent"
7
+ export * from "./query-data"
@@ -29,8 +29,8 @@ import {
29
29
  PollStrategy,
30
30
  RequestId,
31
31
  RequestStatusResponseStatus,
32
+ TargetPrincipal,
32
33
  } from "@icp-sdk/core/agent"
33
- import { Principal } from "@icp-sdk/core/principal"
34
34
 
35
35
  export interface PollingConfig {
36
36
  /**
@@ -283,14 +283,14 @@ export function createPollingStrategy(cfg: PollingConfig = {}): PollStrategy {
283
283
  * Async strategy function invoked by the IC agent on each polling cycle.
284
284
  * Determines whether to continue waiting based on request status.
285
285
  *
286
- * @param {Principal} _canisterId - Target canister principal (unused but required by interface)
286
+ * @param {TargetPrincipal} _effectiveTarget - Target canister or subnet (unused but required by interface)
287
287
  * @param {RequestId} _requestId - Request identifier (unused but required by interface)
288
288
  * @param {RequestStatusResponseStatus} [rawStatus] - Current request status from IC
289
289
  * @returns {Promise<void>} - Resolves after calculated delay, or immediately for terminal states
290
290
  * @throws {Error} - If abortSignal is triggered
291
291
  */
292
292
  return async function strategy(
293
- _canisterId: Principal,
293
+ _effectiveTarget: TargetPrincipal,
294
294
  _requestId: RequestId,
295
295
  rawStatus?: RequestStatusResponseStatus
296
296
  ): Promise<void> {
@@ -0,0 +1,5 @@
1
+ import type { ReactorQueryData } from "../types/reactor"
2
+
3
+ /** Convert a direct reactor result into a value TanStack Query can cache. */
4
+ export const toReactorQueryData = <T>(value: T): ReactorQueryData<T> =>
5
+ (value === undefined ? null : value) as ReactorQueryData<T>
package/src/version.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { version } from "../package.json"
1
+ import pkg from "../package.json"
2
2
  /**
3
3
  * Library version - automatically synced from package.json.
4
4
  */
5
- export const VERSION = version
5
+ export const VERSION = pkg.version
@@ -1,19 +0,0 @@
1
- import type { IdentityAttributeOpenIdProvider, IdentityAttributeValues, SignedIdentityAttributes } from "./types/client";
2
- export declare const IDENTITY_ATTRIBUTES_PROVIDER = "https://id.ai/authorize";
3
- /**
4
- * @deprecated Use the default ClientManager identity provider or
5
- * `IDENTITY_ATTRIBUTES_PROVIDER` instead.
6
- */
7
- export declare const IDENTITY_ATTRIBUTES_BETA_PROVIDER = "https://id.ai/authorize";
8
- export declare function identityAttributeKeys({ openIdProvider, keys, }: {
9
- openIdProvider: IdentityAttributeOpenIdProvider;
10
- keys: string[];
11
- }): string[];
12
- export declare function normalizeOpenIdProvider(openIdProvider: IdentityAttributeOpenIdProvider): string;
13
- export declare function resolveIdentityAttributeKeys({ openIdProvider, keys, }: {
14
- openIdProvider: IdentityAttributeOpenIdProvider;
15
- keys: string[];
16
- }): Promise<string[]>;
17
- export declare function decodeIdentityAttributeValues(data: Uint8Array, requestedKeys: string[]): IdentityAttributeValues;
18
- export declare function normalizeSignedIdentityAttributes(attributes: SignedIdentityAttributes): SignedIdentityAttributes;
19
- //# sourceMappingURL=identity-attributes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity-attributes.d.ts","sourceRoot":"","sources":["../src/identity-attributes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,+BAA+B,EAC/B,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,gBAAgB,CAAA;AAGvB,eAAO,MAAM,4BAA4B,4BAAgC,CAAA;AAEzE;;;GAGG;AACH,eAAO,MAAM,iCAAiC,4BAA+B,CAAA;AAQ7E,wBAAgB,qBAAqB,CAAC,EACpC,cAAc,EACd,IAAI,GACL,EAAE;IACD,cAAc,EAAE,+BAA+B,CAAA;IAC/C,IAAI,EAAE,MAAM,EAAE,CAAA;CACf,GAAG,MAAM,EAAE,CAGX;AAED,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,+BAA+B,GAC9C,MAAM,CAMR;AAED,wBAAsB,4BAA4B,CAAC,EACjD,cAAc,EACd,IAAI,GACL,EAAE;IACD,cAAc,EAAE,+BAA+B,CAAA;IAC/C,IAAI,EAAE,MAAM,EAAE,CAAA;CACf,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAEpB;AAED,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,UAAU,EAChB,aAAa,EAAE,MAAM,EAAE,GACtB,uBAAuB,CAgBzB;AAsLD,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,wBAAwB,GACnC,wBAAwB,CAK1B"}