@layerzerolabs/common-canton 1.2.35 → 1.2.37

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 (53) hide show
  1. package/dist/{AH32N3GF.js → 262S47C4.js} +6 -5
  2. package/dist/262S47C4.js.map +1 -0
  3. package/dist/{WAKNWPCR.js → 5AD6IR4R.js} +10 -7
  4. package/dist/5AD6IR4R.js.map +1 -0
  5. package/dist/{IA2UQ4WQ.js → BFQYTMKD.js} +5 -5
  6. package/dist/BFQYTMKD.js.map +1 -0
  7. package/dist/{SEPKIDEX.js → D52OIJDY.js} +2 -2
  8. package/dist/{SEPKIDEX.js.map → D52OIJDY.js.map} +1 -1
  9. package/dist/{ZZCNITRN.js → FFZGONTK.js} +3 -3
  10. package/dist/{ZZCNITRN.js.map → FFZGONTK.js.map} +1 -1
  11. package/dist/{QAKOQQ7E.js → PL4H5XEA.js} +19 -8
  12. package/dist/PL4H5XEA.js.map +1 -0
  13. package/dist/client/canton-client.d.ts +4 -0
  14. package/dist/client/canton-client.d.ts.map +1 -1
  15. package/dist/client/canton-client.js +1 -1
  16. package/dist/client/grpc.d.ts +1 -1
  17. package/dist/client/grpc.d.ts.map +1 -1
  18. package/dist/client/grpc.js +2 -2
  19. package/dist/client/index.d.ts +1 -1
  20. package/dist/client/index.d.ts.map +1 -1
  21. package/dist/client/index.js +3 -3
  22. package/dist/client/interface.d.ts +2 -0
  23. package/dist/client/interface.d.ts.map +1 -1
  24. package/dist/client/topology/types.d.ts +2 -11
  25. package/dist/client/topology/types.d.ts.map +1 -1
  26. package/dist/client/topology/utils.d.ts +4 -4
  27. package/dist/client/topology/utils.d.ts.map +1 -1
  28. package/dist/client/topology/utils.js +2 -1
  29. package/dist/index.js +8 -8
  30. package/dist/provider.d.ts +3 -2
  31. package/dist/provider.d.ts.map +1 -1
  32. package/dist/provider.js +4 -4
  33. package/dist/refresh/index.js +2 -2
  34. package/dist/refresh/resolve.js +2 -2
  35. package/dist/sdk/canton-sdk.d.ts +1 -0
  36. package/dist/sdk/canton-sdk.d.ts.map +1 -1
  37. package/dist/sdk/canton-sdk.js +1 -1
  38. package/dist/sdk/index.js +1 -1
  39. package/package.json +12 -11
  40. package/src/client/canton-client.ts +16 -6
  41. package/src/client/grpc.ts +4 -2
  42. package/src/client/index.ts +0 -1
  43. package/src/client/interface.ts +2 -2
  44. package/src/client/topology/types.ts +2 -12
  45. package/src/client/topology/utils.ts +31 -10
  46. package/src/provider.ts +4 -2
  47. package/src/sdk/canton-sdk.ts +1 -1
  48. package/test/client/topology/utils.test.ts +47 -0
  49. package/test/provider.test.ts +37 -2
  50. package/dist/AH32N3GF.js.map +0 -1
  51. package/dist/IA2UQ4WQ.js.map +0 -1
  52. package/dist/QAKOQQ7E.js.map +0 -1
  53. package/dist/WAKNWPCR.js.map +0 -1
@@ -1003,14 +1003,16 @@ export class CantonClient implements ICantonClient {
1003
1003
  * @param offset - Ledger offset for the snapshot
1004
1004
  * @param opts.templateIds - Optional template IDs to filter by
1005
1005
  * @param opts.limit - Maximum number of contracts to return
1006
+ * @param opts.includeCreatedEventBlob - Include CIP disclosure blobs (default false)
1006
1007
  */
1007
1008
  async queryActiveContracts(
1008
1009
  party: string,
1009
1010
  offset: number,
1010
- opts?: { templateIds?: string[]; limit?: number },
1011
+ opts?: { templateIds?: string[]; limit?: number; includeCreatedEventBlob?: boolean },
1011
1012
  ): Promise<JsActiveContract[]> {
1012
1013
  return this.queryActiveContractsByParties([party], offset, opts?.templateIds ?? [], {
1013
1014
  limit: opts?.limit,
1015
+ includeCreatedEventBlob: opts?.includeCreatedEventBlob,
1014
1016
  });
1015
1017
  }
1016
1018
 
@@ -1023,17 +1025,18 @@ export class CantonClient implements ICantonClient {
1023
1025
  * @param offset - Ledger offset for the snapshot
1024
1026
  * @param templateIds - Template IDs to filter by
1025
1027
  * @param opts.limit - Maximum number of contracts to return
1028
+ * @param opts.includeCreatedEventBlob - Include CIP disclosure blobs (default false)
1026
1029
  */
1027
1030
  async queryActiveContractsByParties(
1028
1031
  parties: string[],
1029
1032
  offset: number,
1030
1033
  templateIds: string[],
1031
- opts?: { limit?: number },
1034
+ opts?: { limit?: number; includeCreatedEventBlob?: boolean },
1032
1035
  ): Promise<JsActiveContract[]> {
1033
1036
  return this.#fetchActiveContracts(
1034
1037
  parties,
1035
1038
  offset,
1036
- this.#buildCumulativeFilters(templateIds),
1039
+ this.#buildCumulativeFilters(templateIds, opts?.includeCreatedEventBlob),
1037
1040
  opts,
1038
1041
  );
1039
1042
  }
@@ -1147,16 +1150,23 @@ export class CantonClient implements ICantonClient {
1147
1150
  * Build cumulative filters for party-based queries.
1148
1151
  * If templateIds provided, filters by those templates; otherwise uses wildcard.
1149
1152
  */
1150
- #buildCumulativeFilters(templateIds?: string[]): CumulativeFilter[] {
1153
+ #buildCumulativeFilters(
1154
+ templateIds?: string[],
1155
+ includeCreatedEventBlob = false,
1156
+ ): CumulativeFilter[] {
1151
1157
  if (templateIds?.length) {
1152
1158
  return templateIds.map((templateId) => ({
1153
1159
  identifierFilter: {
1154
- templateFilter: { value: { templateId, includeCreatedEventBlob: false } },
1160
+ templateFilter: { value: { templateId, includeCreatedEventBlob } },
1155
1161
  },
1156
1162
  }));
1157
1163
  }
1158
1164
  return [
1159
- { identifierFilter: { wildcardFilter: { value: { includeCreatedEventBlob: false } } } },
1165
+ {
1166
+ identifierFilter: {
1167
+ wildcardFilter: { value: { includeCreatedEventBlob } },
1168
+ },
1169
+ },
1160
1170
  ];
1161
1171
  }
1162
1172
 
@@ -68,14 +68,14 @@ export class CantonGrpcClient {
68
68
  #synchronizerId?: string;
69
69
 
70
70
  /**
71
- * @param opts - Admin API host, auth, optional synchronizer id, and optional TLS.
71
+ * @param opts - Admin API host, auth, optional synchronizer id, and transport security.
72
72
  */
73
73
  constructor(opts: CantonGrpcClientOptions) {
74
74
  this.#tokenProvider = opts.tokenProvider;
75
75
  this.#synchronizerId = opts.synchronizerId;
76
76
  this.#transport = new GrpcTransport({
77
77
  host: opts.host,
78
- channelCredentials: buildChannelCredentials(opts.host, opts.tls),
78
+ channelCredentials: buildChannelCredentials(opts.host, opts.insecureTransport),
79
79
  clientOptions: opts.grpcClientOptions ?? DEFAULT_GRPC_CLIENT_OPTIONS,
80
80
  });
81
81
  this.#topologyRead = new TopologyManagerReadServiceClient(this.#transport);
@@ -149,9 +149,11 @@ export class CantonGrpcClient {
149
149
  );
150
150
 
151
151
  const generated = response.generatedTransactions[0];
152
+
152
153
  if (!generated) {
153
154
  throw new CantonProtocolError('GenerateTransactions returned no topology transaction');
154
155
  }
156
+
155
157
  return generated;
156
158
  }
157
159
 
@@ -18,7 +18,6 @@ export type {
18
18
  NamespaceDelegationState,
19
19
  PartyToKeyMappingState,
20
20
  PartyToParticipantMappingState,
21
- TlsOptions,
22
21
  UpdateDecentralizedNamespaceDefinitionTxParams,
23
22
  } from './topology/types';
24
23
  export { computeDecentralizedNamespace, computeMultiTransactionHash } from './topology/utils';
@@ -306,7 +306,7 @@ export interface ICantonClient {
306
306
  queryActiveContracts(
307
307
  party: string,
308
308
  offset: number,
309
- opts?: { templateIds?: string[]; limit?: number },
309
+ opts?: { templateIds?: string[]; limit?: number; includeCreatedEventBlob?: boolean },
310
310
  ): Promise<JsActiveContract[]>;
311
311
 
312
312
  /**
@@ -322,7 +322,7 @@ export interface ICantonClient {
322
322
  parties: string[],
323
323
  offset: number,
324
324
  templateIds: string[],
325
- opts?: { limit?: number },
325
+ opts?: { limit?: number; includeCreatedEventBlob?: boolean },
326
326
  ): Promise<JsActiveContract[]>;
327
327
 
328
328
  /**
@@ -104,16 +104,6 @@ export type PartyToParticipantMappingState = {
104
104
  serial: number;
105
105
  };
106
106
 
107
- /** TLS credentials for Canton admin gRPC connections. */
108
- export type TlsOptions = {
109
- /** CA root certificate for server verification. */
110
- rootCert?: Buffer;
111
- /** Client private key for mutual TLS. */
112
- clientKey?: Buffer;
113
- /** Client certificate for mutual TLS. */
114
- clientCert?: Buffer;
115
- };
116
-
117
107
  /** Options for constructing a {@link CantonGrpcClient}. */
118
108
  export type CantonGrpcClientOptions = {
119
109
  /** Participant admin API host (e.g. `participant.example.com:443`). */
@@ -126,8 +116,8 @@ export type CantonGrpcClientOptions = {
126
116
  * is resolved on the first RPC.
127
117
  */
128
118
  synchronizerId?: string;
129
- /** TLS options; omitted for insecure (non-:443) or default SSL on :443. */
130
- tls?: TlsOptions;
119
+ /** Drops transport encryption; loopback hosts only. Defaults to TLS. */
120
+ insecureTransport?: boolean;
131
121
  /** Overrides the default gRPC channel options. */
132
122
  grpcClientOptions?: ClientOptions;
133
123
  };
@@ -3,8 +3,8 @@ import { ChannelCredentials } from '@grpc/grpc-js';
3
3
 
4
4
  import { bytesToHex } from '@layerzerolabs/common-encoding-utils';
5
5
 
6
+ import { CantonError } from '../../errors';
6
7
  import { cantonMultihash } from '../utils';
7
- import type { TlsOptions } from './types';
8
8
 
9
9
  /** Canton hash purpose for decentralized namespace derivation. */
10
10
  const HASH_PURPOSE_DECENTRALIZED_NAMESPACE = 37;
@@ -77,17 +77,38 @@ export function headStateBaseQuery(synchronizerId: string, proposals = false): B
77
77
  });
78
78
  }
79
79
 
80
+ const LOOPBACK_HOSTNAMES = new Set(['localhost', '::1']);
81
+ const LOOPBACK_IPV4 = /^127(\.\d{1,3}){3}$/;
82
+
83
+ /**
84
+ * Whether a `host:port` target addresses the local machine.
85
+ */
86
+ const isLoopbackHost = (host: string): boolean => {
87
+ const hostname = host
88
+ .replace(/:\d+$/, '')
89
+ .replace(/^\[(.*)\]$/, '$1')
90
+ .toLowerCase();
91
+ return LOOPBACK_HOSTNAMES.has(hostname) || LOOPBACK_IPV4.test(hostname);
92
+ };
93
+
80
94
  /**
81
95
  * Builds gRPC channel credentials for the Canton admin API.
82
96
  *
83
- * Uses explicit TLS when `tls` is set, default SSL for hosts ending in `:443`,
84
- * and insecure credentials otherwise.
97
+ * Encrypted whatever the port, because every admin call carries a reusable bearer token.
98
+ *
99
+ * @throws {CantonError} If an unencrypted channel is asked for on a remote host.
85
100
  */
86
- export function buildChannelCredentials(host: string, tls?: TlsOptions): ChannelCredentials {
87
- if (tls) {
88
- return ChannelCredentials.createSsl(tls.rootCert, tls.clientKey, tls.clientCert);
101
+ export const buildChannelCredentials = (
102
+ host: string,
103
+ insecureTransport = false,
104
+ ): ChannelCredentials => {
105
+ if (!insecureTransport) {
106
+ return ChannelCredentials.createSsl();
107
+ } else if (!isLoopbackHost(host)) {
108
+ throw new CantonError(
109
+ `Canton admin API requires an encrypted channel for a remote host: ${host}`,
110
+ );
89
111
  }
90
- return host.endsWith(':443')
91
- ? ChannelCredentials.createSsl()
92
- : ChannelCredentials.createInsecure();
93
- }
112
+
113
+ return ChannelCredentials.createInsecure();
114
+ };
package/src/provider.ts CHANGED
@@ -137,9 +137,10 @@ export type CreateCantonChainProviderOptions = {
137
137
  /**
138
138
  * Create a {@link CantonChainProvider} from a provider URI.
139
139
  *
140
- * - **isLocal=true**: Uses {@link LocalTokenProvider} with admin-level access (self-signed JWTs).
140
+ * - **isLocal=true**: Uses {@link LocalTokenProvider} with admin-level access (self-signed JWTs)
141
+ * over an unencrypted admin channel, allowed for a loopback admin host only.
141
142
  * - **isLocal=false**: Uses {@link ClientCredentialsTokenProvider} with OAuth2 client
142
- * credentials extracted from the URI query parameters.
143
+ * credentials extracted from the URI query parameters, over a TLS admin channel.
143
144
  */
144
145
  export function createCantonChainProvider({
145
146
  uri,
@@ -163,6 +164,7 @@ export function createCantonChainProvider({
163
164
  const grpcClient = new CantonGrpcClient({
164
165
  host: params.adminApiHost,
165
166
  tokenProvider,
167
+ insecureTransport: isLocal,
166
168
  });
167
169
 
168
170
  return {
@@ -421,7 +421,7 @@ export class CantonSdk {
421
421
  queryActiveContracts(
422
422
  party: string,
423
423
  offset: number,
424
- opts?: { templateIds?: string[]; limit?: number },
424
+ opts?: { templateIds?: string[]; limit?: number; includeCreatedEventBlob?: boolean },
425
425
  ): Promise<JsActiveContract[]> {
426
426
  return this.#client.queryActiveContracts(party, offset, opts);
427
427
  }
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { buildChannelCredentials } from '../../../src/client/topology/utils';
4
+
5
+ describe('admin API channel credentials', () => {
6
+ it('encrypts a conventional admin port', () => {
7
+ expect(buildChannelCredentials('participant.example.com:5002')._isSecure()).toBe(true);
8
+ });
9
+
10
+ it('encrypts the HTTPS port', () => {
11
+ expect(buildChannelCredentials('participant.example.com:443')._isSecure()).toBe(true);
12
+ });
13
+
14
+ it('encrypts a loopback host by default', () => {
15
+ expect(buildChannelCredentials('localhost:2902')._isSecure()).toBe(true);
16
+ });
17
+
18
+ it('drops encryption for a loopback name', () => {
19
+ expect(buildChannelCredentials('localhost:2902', true)._isSecure()).toBe(false);
20
+ });
21
+
22
+ it('drops encryption for a loopback address', () => {
23
+ expect(buildChannelCredentials('127.0.0.1:2902', true)._isSecure()).toBe(false);
24
+ });
25
+
26
+ it('drops encryption for a bracketed IPv6 loopback address', () => {
27
+ expect(buildChannelCredentials('[::1]:2902', true)._isSecure()).toBe(false);
28
+ });
29
+
30
+ it('rejects an unencrypted channel to a remote host', () => {
31
+ expect(() => buildChannelCredentials('participant.example.com:5002', true)).toThrow(
32
+ /requires an encrypted channel/,
33
+ );
34
+ });
35
+
36
+ it('rejects an unencrypted channel to a host merely named after loopback', () => {
37
+ expect(() => buildChannelCredentials('localhost.example.com:5002', true)).toThrow(
38
+ /requires an encrypted channel/,
39
+ );
40
+ });
41
+
42
+ it('rejects an unencrypted channel to a public address in the loopback range shape', () => {
43
+ expect(() => buildChannelCredentials('128.0.0.1:2902', true)).toThrow(
44
+ /requires an encrypted channel/,
45
+ );
46
+ });
47
+ });
@@ -1,4 +1,10 @@
1
- import { describe, expect, it, vi } from 'vitest';
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ import type { CantonGrpcClientOptions } from '../src/client/topology/types';
4
+
5
+ const { grpcClientOptions } = vi.hoisted(() => ({
6
+ grpcClientOptions: [] as CantonGrpcClientOptions[],
7
+ }));
2
8
 
3
9
  vi.mock('../src/auth/client-credentials-token-provider', () => ({
4
10
  ClientCredentialsTokenProvider: class {},
@@ -10,7 +16,11 @@ vi.mock('../src/client/canton-client', () => ({
10
16
  CantonClient: class {},
11
17
  }));
12
18
  vi.mock('../src/client/grpc', () => ({
13
- CantonGrpcClient: class {},
19
+ CantonGrpcClient: class {
20
+ constructor(options: CantonGrpcClientOptions) {
21
+ grpcClientOptions.push(options);
22
+ }
23
+ },
14
24
  }));
15
25
  vi.mock('../src/open-api/runtime', () => ({ Configuration: class {} }));
16
26
 
@@ -98,3 +108,28 @@ describe('parseCantonChainUri', () => {
98
108
  }
99
109
  });
100
110
  });
111
+
112
+ describe('createCantonChainProvider', () => {
113
+ beforeEach(() => {
114
+ grpcClientOptions.length = 0;
115
+ });
116
+
117
+ it('leaves the admin channel encrypted for a non-local deployment', async () => {
118
+ const { createCantonChainProvider } = await loadProvider();
119
+
120
+ createCantonChainProvider({
121
+ uri: `${BASE}&token-url=http://token&client-id=cid&client-secret=secret`,
122
+ isLocal: false,
123
+ });
124
+
125
+ expect(grpcClientOptions[0]?.insecureTransport).toBe(false);
126
+ });
127
+
128
+ it('drops admin channel encryption for a local deployment', async () => {
129
+ const { createCantonChainProvider } = await loadProvider();
130
+
131
+ createCantonChainProvider({ uri: BASE, isLocal: true });
132
+
133
+ expect(grpcClientOptions[0]?.insecureTransport).toBe(true);
134
+ });
135
+ });
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/provider.ts"],"names":["parseCantonChainUri","uri","url","URL","adminApiHost","searchParams","get","Error","userId","actAsParam","actAs","split","map","party","trim","filter","length","walletUrl","tokenUrl","undefined","clientId","clientSecret","process","env","CANTON_CLIENT_SECRET","scope","audience","key","delete","jsonApiUrl","toString","replace","oauth2","createCantonChainProvider","isLocal","params","tokenProvider","createTokenProvider","configuration","Configuration","basePath","accessToken","getToken","client","CantonClient","grpcClient","CantonGrpcClient","host","LocalTokenProvider","admin","ClientCredentialsTokenProvider"],"mappings":"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","file":"AH32N3GF.js","sourcesContent":["import {\n ClientCredentialsTokenProvider,\n type ClientCredentialsTokenProviderConfig,\n} from './auth/client-credentials-token-provider';\nimport { LocalTokenProvider } from './auth/local-token-provider';\nimport type { TokenProvider } from './auth/token-provider';\nimport { CantonClient } from './client/canton-client';\nimport { CantonGrpcClient } from './client/grpc';\nimport type { ICantonClient } from './client/interface';\nimport { Configuration } from './open-api/runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Provider Type\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * - {@link client} — JSON Ledger API (commands, queries, updates)\n * - {@link grpcClient} — gRPC Admin API (topology transactions, namespace queries)\n * - {@link tokenProvider} — Shared Bearer-token source used by both transports\n * - {@link walletUrl} — Canton Network validator wallet (scan-proxy CIP-56 endpoints)\n */\nexport type CantonChainProvider = {\n client: ICantonClient;\n grpcClient: CantonGrpcClient;\n tokenProvider: TokenProvider;\n /** Validator wallet URL for scan-proxy CIP-56 endpoints. Required. */\n walletUrl: string;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// URI Parsing\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type CantonChainUriParams = {\n /** Base URL of the JSON Ledger API (e.g. \"http://localhost:5975\") */\n jsonApiUrl: string;\n /** Host:port of the gRPC Admin API (e.g. \"localhost:5076\") */\n adminApiHost: string;\n /** Ledger API user ID (default: \"participant_admin\") */\n userId: string;\n /** Parties granted `actAs` on localnet tokens (comma-separated in the URI). */\n actAs: string[];\n /** Validator wallet URL for scan-proxy CIP-56 endpoints (e.g. \"http://localhost:7201\"). Required. */\n walletUrl: string;\n /** OAuth2 client credentials config — present only for non-local environments */\n oauth2?: ClientCredentialsTokenProviderConfig;\n};\n\n/**\n * Parse a Canton chain provider URI into its constituent parts.\n *\n * URI format:\n * `<json-api-base>?admin-api=<host:port>&user-id=<id>&wallet-url=<url>[&token-url=...&client-id=...&client-secret=...&scope=...&audience=...]`\n *\n * The base URL (everything before the query string) is the JSON Ledger API endpoint.\n * Canton-specific params are extracted and removed; any remaining query params are\n * preserved on the JSON API URL.\n *\n * When `client-secret` is omitted from the URI, `CANTON_CLIENT_SECRET` is read from the\n * environment.\n */\nexport function parseCantonChainUri(uri: string): CantonChainUriParams {\n const url = new URL(uri);\n\n const adminApiHost = url.searchParams.get('admin-api');\n if (!adminApiHost) {\n throw new Error('Canton provider URI missing required \"admin-api\" query parameter');\n }\n\n const userId = url.searchParams.get('user-id') ?? 'participant_admin';\n const actAsParam = url.searchParams.get('act-as');\n const actAs =\n actAsParam\n ?.split(',')\n .map((party) => party.trim())\n .filter((party) => party.length > 0) ?? [];\n const walletUrl = url.searchParams.get('wallet-url');\n if (!walletUrl) {\n throw new Error('Canton provider URI missing required \"wallet-url\" query parameter');\n }\n const tokenUrl = url.searchParams.get('token-url') ?? undefined;\n const clientId = url.searchParams.get('client-id') ?? undefined;\n // Prefer URI param; fall back to env so secrets are not committed in provider configs.\n const clientSecret =\n url.searchParams.get('client-secret') ??\n // eslint-disable-next-line turbo/no-undeclared-env-vars -- runtime OAuth secret, not a turbo task input\n process.env.CANTON_CLIENT_SECRET ??\n undefined;\n const scope = url.searchParams.get('scope') ?? undefined;\n const audience = url.searchParams.get('audience') ?? undefined;\n\n for (const key of [\n 'admin-api',\n 'user-id',\n 'act-as',\n 'wallet-url',\n 'sequencer-url',\n 'sequencer-validators',\n 'sequencer-quorum',\n 'token-url',\n 'client-id',\n 'client-secret',\n 'scope',\n 'audience',\n ]) {\n url.searchParams.delete(key);\n }\n\n const jsonApiUrl = url.toString().replace(/\\/$/, '');\n\n const oauth2 =\n tokenUrl && clientId && clientSecret\n ? { tokenUrl, clientId, clientSecret, scope, audience }\n : undefined;\n\n return {\n jsonApiUrl,\n adminApiHost,\n userId,\n actAs,\n walletUrl,\n oauth2,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Provider Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type CreateCantonChainProviderOptions = {\n /** Raw provider URI (from provider config) */\n uri: string;\n /** When true, uses LocalTokenProvider (self-signed JWTs) instead of OAuth2 */\n isLocal: boolean;\n};\n\n/**\n * Create a {@link CantonChainProvider} from a provider URI.\n *\n * - **isLocal=true**: Uses {@link LocalTokenProvider} with admin-level access (self-signed JWTs).\n * - **isLocal=false**: Uses {@link ClientCredentialsTokenProvider} with OAuth2 client\n * credentials extracted from the URI query parameters.\n */\nexport function createCantonChainProvider({\n uri,\n isLocal,\n}: CreateCantonChainProviderOptions): CantonChainProvider {\n const params = parseCantonChainUri(uri);\n\n const tokenProvider = createTokenProvider(params, isLocal);\n\n // ── JSON Ledger API Client ──────────────────────────────────────────\n const configuration = new Configuration({\n basePath: params.jsonApiUrl,\n accessToken: () => tokenProvider.getToken(),\n });\n const client = new CantonClient(configuration, params.userId, {\n walletUrl: params.walletUrl,\n tokenProvider,\n });\n\n // ── gRPC Admin API Client ───────────────────────────────────────────\n const grpcClient = new CantonGrpcClient({\n host: params.adminApiHost,\n tokenProvider,\n });\n\n return {\n client,\n grpcClient,\n tokenProvider,\n walletUrl: params.walletUrl,\n };\n}\n\nfunction createTokenProvider(params: CantonChainUriParams, isLocal: boolean): TokenProvider {\n if (isLocal) {\n return new LocalTokenProvider({\n userId: params.userId,\n actAs: params.actAs,\n admin: true,\n });\n }\n\n // TODO(canton): add other prod auth methods (direct JWT passthrough, etc.).\n if (!params.oauth2) {\n throw new Error(\n 'Canton provider requires OAuth2 credentials (token-url, client-id, client-secret in URI or CANTON_CLIENT_SECRET)',\n );\n }\n\n return new ClientCredentialsTokenProvider(params.oauth2);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client/grpc.ts"],"names":["DEFAULT_GRPC_CLIENT_OPTIONS","CantonGrpcClient","opts","tokenProvider","synchronizerId","GrpcTransport","host","channelCredentials","buildChannelCredentials","tls","clientOptions","grpcClientOptions","TopologyManagerReadServiceClient","TopologyManagerWriteServiceClient","SynchronizerConnectivityServiceClient","token","getToken","Authorization","response","listConnectedSynchronizers","meta","synchronizer","connectedSynchronizers","CantonProtocolError","mapping","serial","generateTransactions","GenerateTransactionsRequest","create","proposals","GenerateTransactionsRequest_Proposal","operation","Enums_TopologyChangeOp","ADD_REPLACE","store","synchronizerStore","generated","generatedTransactions","getNamespaceDelegation","namespaceFingerprint","listNamespaceDelegation","ListNamespaceDelegationRequest","baseQuery","headStateBaseQuery","filterNamespace","filterTargetKeyFingerprint","results","flatMap","result","item","publicKey","targetKey","namespace","targetKeyFingerprint","computePublicKeyFingerprint","isRootDelegation","context","getDecentralizedNamespaceDefinition","listDecentralizedNamespaceDefinition","ListDecentralizedNamespaceDefinitionRequest","decentralizedNamespace","threshold","owners","getPartyToKeyMapping","partyId","listPartyToKeyMapping","ListPartyToKeyMappingRequest","filterParty","party","signingKeyFingerprints","signingKeys","map","key","getPartyToParticipantMapping","listPartyToParticipant","ListPartyToParticipantRequest","filterParticipant","participants","participant","participantUid","permission","createNamespaceDelegationTx","params","buildNamespaceDelegationMapping","publicKeyDer","createDecentralizedNamespaceDefinitionTx","computeDecentralizedNamespace","buildDecentralizedNamespaceDefinitionMapping","updateDecentralizedNamespaceDefinitionTx","createPartyToKeyTx","buildPartyToKeyMapping","signingPublicKeyDers","createPartyToParticipantTx","buildPartyToParticipantMapping","participantIds","submitTopologyTransactions","transactions","length","CantonError","addTransactions","AddTransactionsRequest","close"],"mappings":"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","file":"IA2UQ4WQ.js","sourcesContent":["import {\n AddTransactionsRequest,\n Enums_TopologyChangeOp,\n GenerateTransactionsRequest,\n GenerateTransactionsRequest_Proposal,\n ListDecentralizedNamespaceDefinitionRequest,\n ListNamespaceDelegationRequest,\n ListPartyToKeyMappingRequest,\n ListPartyToParticipantRequest,\n type SignedTopologyTransaction,\n TopologyManagerReadServiceClient,\n TopologyManagerWriteServiceClient,\n type TopologyMapping,\n} from '@canton-network/core-ledger-proto';\nimport { GrpcTransport } from '@protobuf-ts/grpc-transport';\n\nimport type { TokenProvider } from '../auth/token-provider';\nimport { CantonError, CantonProtocolError } from '../errors';\nimport {\n buildDecentralizedNamespaceDefinitionMapping,\n buildNamespaceDelegationMapping,\n buildPartyToKeyMapping,\n buildPartyToParticipantMapping,\n} from './topology/mappings';\nimport { SynchronizerConnectivityServiceClient } from './topology/synchronizer-connectivity';\nimport type {\n CantonGrpcClientOptions,\n CreateDecentralizedNamespaceDefinitionTxParams,\n CreateNamespaceDelegationTxParams,\n CreatePartyToKeyMappingTxParams,\n CreatePartyToParticipantMappingTxParams,\n DecentralizedNamespaceDefinitionState,\n GeneratedTopologyTransaction,\n NamespaceDelegationState,\n PartyToKeyMappingState,\n PartyToParticipantMappingState,\n UpdateDecentralizedNamespaceDefinitionTxParams,\n} from './topology/types';\nimport {\n buildChannelCredentials,\n computeDecentralizedNamespace,\n headStateBaseQuery,\n synchronizerStore,\n} from './topology/utils';\nimport { computePublicKeyFingerprint } from './utils';\n\n/** Default gRPC client options: 128 MiB message-size limits for large admin responses. */\nconst DEFAULT_GRPC_CLIENT_OPTIONS = {\n 'grpc.max_receive_message_length': 128 * 1024 * 1024,\n 'grpc.max_send_message_length': 128 * 1024 * 1024,\n} as const;\n\n/**\n * gRPC client for the Canton participant admin Topology Manager API.\n *\n * Exposes read queries for topology mappings and write helpers that call\n * `GenerateTransactions` to produce unsigned topology transactions and\n * `AddTransactions` to submit signed ones.\n *\n * A fresh Bearer token is attached to each RPC via {@link TokenProvider}.\n */\nexport class CantonGrpcClient {\n readonly #transport: GrpcTransport;\n readonly #topologyRead: TopologyManagerReadServiceClient;\n readonly #topologyWrite: TopologyManagerWriteServiceClient;\n readonly #connectivity: SynchronizerConnectivityServiceClient;\n readonly #tokenProvider: TokenProvider;\n #synchronizerId?: string;\n\n /**\n * @param opts - Admin API host, auth, optional synchronizer id, and optional TLS.\n */\n constructor(opts: CantonGrpcClientOptions) {\n this.#tokenProvider = opts.tokenProvider;\n this.#synchronizerId = opts.synchronizerId;\n this.#transport = new GrpcTransport({\n host: opts.host,\n channelCredentials: buildChannelCredentials(opts.host, opts.tls),\n clientOptions: opts.grpcClientOptions ?? DEFAULT_GRPC_CLIENT_OPTIONS,\n });\n this.#topologyRead = new TopologyManagerReadServiceClient(this.#transport);\n this.#topologyWrite = new TopologyManagerWriteServiceClient(this.#transport);\n this.#connectivity = new SynchronizerConnectivityServiceClient(this.#transport);\n }\n\n /** Returns per-RPC gRPC metadata with a fresh Bearer token. */\n async #getMeta(): Promise<Record<string, string>> {\n const token = await this.#tokenProvider.getToken();\n return { Authorization: `Bearer ${token}` };\n }\n\n /**\n * Returns the client synchronizer id, discovering it on first use when omitted at construction.\n *\n * @throws {CantonProtocolError} If the participant exposes no synchronizer store.\n */\n async #getSynchronizerId(): Promise<string> {\n if (this.#synchronizerId) {\n return this.#synchronizerId;\n }\n this.#synchronizerId = await this.#discoverSynchronizerId();\n return this.#synchronizerId;\n }\n\n /**\n * Resolves the logical id of the first synchronizer the participant is connected to.\n *\n * @throws {CantonProtocolError} If the participant is not connected to any synchronizer.\n */\n async #discoverSynchronizerId(): Promise<string> {\n const { response } = await this.#connectivity.listConnectedSynchronizers(\n {},\n { meta: await this.#getMeta() },\n );\n for (const synchronizer of response.connectedSynchronizers) {\n if (synchronizer.synchronizerId) {\n return synchronizer.synchronizerId;\n }\n }\n throw new CantonProtocolError('Participant is not connected to any synchronizer');\n }\n\n /**\n * Calls `GenerateTransactions` for a single ADD_REPLACE mapping.\n *\n * @param synchronizerId - Synchronizer store to target.\n * @param mapping - Topology mapping to encode into the transaction.\n * @param serial - Topology serial (`0` lets Canton auto-determine).\n * @returns Unsigned topology transaction (`serializedTransaction`, `transactionHash`).\n * @throws {CantonProtocolError} If the RPC returns no generated transaction.\n */\n async #generateTopologyTransaction(\n synchronizerId: string,\n mapping: TopologyMapping,\n serial: number,\n ): Promise<GeneratedTopologyTransaction> {\n const { response } = await this.#topologyWrite.generateTransactions(\n GenerateTransactionsRequest.create({\n proposals: [\n GenerateTransactionsRequest_Proposal.create({\n operation: Enums_TopologyChangeOp.ADD_REPLACE,\n serial,\n mapping,\n store: synchronizerStore(synchronizerId),\n }),\n ],\n }),\n { meta: await this.#getMeta() },\n );\n\n const generated = response.generatedTransactions[0];\n if (!generated) {\n throw new CantonProtocolError('GenerateTransactions returned no topology transaction');\n }\n return generated;\n }\n\n /**\n * Lists Namespace Delegation (NSD) mappings for a namespace.\n *\n * Queries topology head state on the synchronizer. Returns every result from\n * the list RPC.\n *\n * @param namespaceFingerprint - Namespace to filter on (for root NSD, the owner key fingerprint).\n * @returns All matching NSD mappings, or an empty array if none exist.\n */\n async getNamespaceDelegation(\n namespaceFingerprint: string,\n ): Promise<NamespaceDelegationState[]> {\n const synchronizerId = await this.#getSynchronizerId();\n const { response } = await this.#topologyRead.listNamespaceDelegation(\n ListNamespaceDelegationRequest.create({\n baseQuery: headStateBaseQuery(synchronizerId),\n filterNamespace: namespaceFingerprint,\n // Empty string = no target-key filter; return all delegations for this namespace.\n filterTargetKeyFingerprint: '',\n }),\n { meta: await this.#getMeta() },\n );\n\n return response.results.flatMap((result) => {\n const item = result.item;\n const publicKey = item?.targetKey?.publicKey;\n if (!item || !publicKey) {\n return [];\n }\n return [\n {\n namespace: item.namespace,\n targetKeyFingerprint: computePublicKeyFingerprint(publicKey),\n isRootDelegation: item.isRootDelegation,\n serial: result.context?.serial ?? 0,\n },\n ];\n });\n }\n\n /**\n * Lists Decentralized Namespace Definition (DND) mappings for a namespace.\n *\n * Queries topology head state on the synchronizer. For a party id `hint::1220…`,\n * pass the `1220…` suffix as `namespaceFingerprint`.\n *\n * @param namespaceFingerprint - Decentralized namespace fingerprint to filter on.\n * @returns All matching DND mappings, or an empty array if none exist.\n */\n async getDecentralizedNamespaceDefinition(\n namespaceFingerprint: string,\n ): Promise<DecentralizedNamespaceDefinitionState[]> {\n const synchronizerId = await this.#getSynchronizerId();\n const { response } = await this.#topologyRead.listDecentralizedNamespaceDefinition(\n ListDecentralizedNamespaceDefinitionRequest.create({\n baseQuery: headStateBaseQuery(synchronizerId),\n filterNamespace: namespaceFingerprint,\n }),\n { meta: await this.#getMeta() },\n );\n\n return response.results.flatMap((result) => {\n const item = result.item;\n if (!item) {\n return [];\n }\n return [\n {\n namespace: item.decentralizedNamespace,\n threshold: item.threshold,\n owners: [...item.owners],\n serial: result.context?.serial ?? 0,\n },\n ];\n });\n }\n\n /**\n * Lists Party-to-Key (PTK) mappings for a party.\n *\n * Queries topology head state on the synchronizer.\n *\n * @param partyId - Full party identifier (e.g. `hint::1220…`).\n * @returns All matching PTK mappings, or an empty array if none exist.\n */\n async getPartyToKeyMapping(partyId: string): Promise<PartyToKeyMappingState[]> {\n const synchronizerId = await this.#getSynchronizerId();\n const { response } = await this.#topologyRead.listPartyToKeyMapping(\n ListPartyToKeyMappingRequest.create({\n baseQuery: headStateBaseQuery(synchronizerId),\n filterParty: partyId,\n }),\n { meta: await this.#getMeta() },\n );\n\n return response.results.flatMap((result) => {\n const item = result.item;\n if (!item) {\n return [];\n }\n return [\n {\n party: item.party,\n threshold: item.threshold,\n signingKeyFingerprints: item.signingKeys.map((key) =>\n computePublicKeyFingerprint(key.publicKey),\n ),\n serial: result.context?.serial ?? 0,\n },\n ];\n });\n }\n\n /**\n * Lists Party-to-Participant (PTP) mappings for a party.\n *\n * Queries topology head state on the synchronizer.\n *\n * @param partyId - Full party identifier (e.g. `hint::1220…`).\n * @param proposals - If `true`, query pending proposals instead of authorized mappings.\n * @returns All matching PTP mappings, or an empty array if none exist.\n */\n async getPartyToParticipantMapping(\n partyId: string,\n proposals = false,\n ): Promise<PartyToParticipantMappingState[]> {\n const synchronizerId = await this.#getSynchronizerId();\n const { response } = await this.#topologyRead.listPartyToParticipant(\n ListPartyToParticipantRequest.create({\n baseQuery: headStateBaseQuery(synchronizerId, proposals),\n filterParty: partyId,\n // Empty string = no participant filter; return all hosting mappings for this party.\n filterParticipant: '',\n }),\n { meta: await this.#getMeta() },\n );\n\n return response.results.flatMap((result) => {\n const item = result.item;\n if (!item) {\n return [];\n }\n return [\n {\n party: item.party,\n threshold: item.threshold,\n participants: item.participants.map((participant) => ({\n participantUid: participant.participantUid,\n permission: participant.permission,\n })),\n serial: result.context?.serial ?? 0,\n },\n ];\n });\n }\n\n /**\n * Builds an unsigned Namespace Delegation (NSD) topology transaction.\n *\n * Calls `GenerateTransactions` with an ADD_REPLACE mapping. The returned\n * `transactionHash` must be signed by the namespace key.\n *\n * @param params - Owner public key and optional serial.\n * @returns Unsigned topology transaction (`serializedTransaction`, `transactionHash`).\n */\n async createNamespaceDelegationTx(\n params: CreateNamespaceDelegationTxParams,\n ): Promise<GeneratedTopologyTransaction> {\n const synchronizerId = await this.#getSynchronizerId();\n const mapping = buildNamespaceDelegationMapping(params.publicKeyDer);\n return this.#generateTopologyTransaction(synchronizerId, mapping, params.serial ?? 0);\n }\n\n /**\n * Builds an unsigned Decentralized Namespace Definition (DND) topology transaction.\n *\n * The decentralized namespace id is derived from `params.owners`. All owners\n * must sign the transaction hash.\n *\n * @param params - Owner fingerprints, threshold, and optional serial.\n * @returns Unsigned topology transaction (`serializedTransaction`, `transactionHash`).\n */\n async createDecentralizedNamespaceDefinitionTx(\n params: CreateDecentralizedNamespaceDefinitionTxParams,\n ): Promise<GeneratedTopologyTransaction> {\n const synchronizerId = await this.#getSynchronizerId();\n const decentralizedNamespace = computeDecentralizedNamespace(params.owners);\n const mapping = buildDecentralizedNamespaceDefinitionMapping(\n decentralizedNamespace,\n params.threshold,\n params.owners,\n );\n return this.#generateTopologyTransaction(synchronizerId, mapping, params.serial ?? 0);\n }\n\n async updateDecentralizedNamespaceDefinitionTx(\n params: UpdateDecentralizedNamespaceDefinitionTxParams,\n ): Promise<GeneratedTopologyTransaction> {\n const synchronizerId = await this.#getSynchronizerId();\n const mapping = buildDecentralizedNamespaceDefinitionMapping(\n params.namespace,\n params.threshold,\n params.owners,\n );\n return this.#generateTopologyTransaction(synchronizerId, mapping, params.serial ?? 0);\n }\n\n /**\n * Builds an unsigned Party-to-Key (PTK) topology transaction.\n *\n * Decentralized namespace owners must sign the transaction hash.\n *\n * @param params - Party id, signing keys, threshold, and optional serial.\n * @returns Unsigned topology transaction (`serializedTransaction`, `transactionHash`).\n */\n async createPartyToKeyTx(\n params: CreatePartyToKeyMappingTxParams,\n ): Promise<GeneratedTopologyTransaction> {\n const synchronizerId = await this.#getSynchronizerId();\n const mapping = buildPartyToKeyMapping(\n params.partyId,\n params.signingPublicKeyDers,\n params.threshold,\n );\n return this.#generateTopologyTransaction(synchronizerId, mapping, params.serial ?? 0);\n }\n\n /**\n * Builds an unsigned Party-to-Participant (PTP) topology transaction.\n *\n * Party owners sign the transaction hash. On submit, set `proposal: true` on the\n * signed transaction so the hosting participant can authorize via `Authorize`.\n *\n * @param params - Party id, participant ids, threshold, and optional serial.\n * @returns Unsigned topology transaction (`serializedTransaction`, `transactionHash`).\n */\n async createPartyToParticipantTx(\n params: CreatePartyToParticipantMappingTxParams,\n ): Promise<GeneratedTopologyTransaction> {\n const synchronizerId = await this.#getSynchronizerId();\n const mapping = buildPartyToParticipantMapping(\n params.partyId,\n params.participantIds,\n params.threshold,\n );\n return this.#generateTopologyTransaction(synchronizerId, mapping, params.serial ?? 0);\n }\n\n /**\n * Submits signed topology transactions to the synchronizer store.\n *\n * Multiple transactions are submitted atomically in one `AddTransactions` call.\n * When batching, sign `computeMultiTransactionHash` over all transaction hashes\n * and attach the same `MultiTransactionSignatures` to each entry.\n *\n * Set `proposal: true` on a transaction when the hosting participant must\n * authorize that mapping afterward.\n *\n * @param transactions - One or more signed topology transactions.\n * @throws {CantonError} If `transactions` is empty.\n */\n async submitTopologyTransactions(\n transactions: readonly SignedTopologyTransaction[],\n ): Promise<void> {\n if (transactions.length === 0) {\n throw new CantonError('AddTransactions requires at least one transaction');\n }\n const synchronizerId = await this.#getSynchronizerId();\n await this.#topologyWrite.addTransactions(\n AddTransactionsRequest.create({\n transactions: [...transactions],\n store: synchronizerStore(synchronizerId),\n }),\n { meta: await this.#getMeta() },\n );\n }\n\n /** Closes the underlying gRPC transport. */\n close(): void {\n this.#transport.close();\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client/topology/utils.ts"],"names":["HASH_PURPOSE_DECENTRALIZED_NAMESPACE","HASH_PURPOSE_MULTI_TRANSACTION","computeDecentralizedNamespace","owners","sorted","sort","parts","owner","ownerBytes","Buffer","from","lengthPrefix","alloc","writeUInt32BE","length","push","bytesToHex","cantonMultihash","concat","computeMultiTransactionHash","hashes","left","right","compare","countBuffer","hash","lengthBuffer","synchronizerStore","synchronizerId","StoreId","create","store","oneofKind","synchronizer","id","headStateBaseQuery","proposals","BaseQuery","timeQuery","headState","Empty","buildChannelCredentials","host","tls","ChannelCredentials","createSsl","rootCert","clientKey","clientCert","endsWith","createInsecure"],"mappings":"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","file":"QAKOQQ7E.js","sourcesContent":["import { BaseQuery, Empty, StoreId } from '@canton-network/core-ledger-proto';\nimport { ChannelCredentials } from '@grpc/grpc-js';\n\nimport { bytesToHex } from '@layerzerolabs/common-encoding-utils';\n\nimport { cantonMultihash } from '../utils';\nimport type { TlsOptions } from './types';\n\n/** Canton hash purpose for decentralized namespace derivation. */\nconst HASH_PURPOSE_DECENTRALIZED_NAMESPACE = 37;\n\n/** Canton hash purpose for multi-transaction topology signing. */\nconst HASH_PURPOSE_MULTI_TRANSACTION = 55;\n\n/**\n * Computes the decentralized namespace fingerprint from owner key fingerprints.\n *\n * Owners are sorted lexicographically, then hashed as\n * `1220` + SHA256(purpose=37 || for each owner: len(utf8) || utf8).\n */\nexport function computeDecentralizedNamespace(owners: string[]): string {\n const sorted = [...owners].sort();\n const parts: Buffer[] = [];\n for (const owner of sorted) {\n const ownerBytes = Buffer.from(owner, 'utf-8');\n const lengthPrefix = Buffer.alloc(4);\n lengthPrefix.writeUInt32BE(ownerBytes.length);\n parts.push(lengthPrefix, ownerBytes);\n }\n return bytesToHex(cantonMultihash(HASH_PURPOSE_DECENTRALIZED_NAMESPACE, Buffer.concat(parts)));\n}\n\n/**\n * Combines topology transaction hashes into the digest Canton expects signed.\n *\n * Hashes are sorted lexicographically, count-prefixed, each length-prefixed, then\n * hashed with purpose 55. Pass a single hash when signing one transaction —\n * Canton always uses this multi-transaction format for `AddTransactions`.\n */\nexport function computeMultiTransactionHash(hashes: Uint8Array[]): Uint8Array {\n const sorted = [...hashes].sort((left, right) =>\n Buffer.compare(Buffer.from(left), Buffer.from(right)),\n );\n const parts: Buffer[] = [];\n const countBuffer = Buffer.alloc(4);\n countBuffer.writeUInt32BE(sorted.length);\n parts.push(countBuffer);\n for (const hash of sorted) {\n const lengthBuffer = Buffer.alloc(4);\n lengthBuffer.writeUInt32BE(hash.length);\n parts.push(lengthBuffer, Buffer.from(hash));\n }\n return cantonMultihash(HASH_PURPOSE_MULTI_TRANSACTION, Buffer.concat(parts));\n}\n\n/**\n * Builds a topology `StoreId` scoped to a synchronizer.\n *\n * Used as the `store` field on topology read/write RPC requests.\n */\nexport function synchronizerStore(synchronizerId: string): StoreId {\n return StoreId.create({\n store: { oneofKind: 'synchronizer', synchronizer: { id: synchronizerId } },\n });\n}\n\n/**\n * Builds a topology `BaseQuery` at synchronizer head state.\n *\n * Used as the `baseQuery` field on topology list RPC requests.\n */\nexport function headStateBaseQuery(synchronizerId: string, proposals = false): BaseQuery {\n return BaseQuery.create({\n store: synchronizerStore(synchronizerId),\n timeQuery: { oneofKind: 'headState', headState: Empty.create({}) },\n proposals,\n });\n}\n\n/**\n * Builds gRPC channel credentials for the Canton admin API.\n *\n * Uses explicit TLS when `tls` is set, default SSL for hosts ending in `:443`,\n * and insecure credentials otherwise.\n */\nexport function buildChannelCredentials(host: string, tls?: TlsOptions): ChannelCredentials {\n if (tls) {\n return ChannelCredentials.createSsl(tls.rootCert, tls.clientKey, tls.clientCert);\n }\n return host.endsWith(':443')\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure();\n}\n"]}