@fairmint/canton-node-sdk 0.0.251 → 0.0.253

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 (50) hide show
  1. package/README.md +34 -7
  2. package/build/src/clients/ledger-json-api/operations/v2/commands/async/submit.d.ts +6 -0
  3. package/build/src/clients/ledger-json-api/operations/v2/commands/async/submit.d.ts.map +1 -1
  4. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait-for-reassignment.d.ts +14 -3
  5. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait-for-reassignment.d.ts.map +1 -1
  6. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait-for-transaction-tree.d.ts +34 -28
  7. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait-for-transaction-tree.d.ts.map +1 -1
  8. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait-for-transaction.d.ts +6 -0
  9. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait-for-transaction.d.ts.map +1 -1
  10. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait.d.ts +58 -52
  11. package/build/src/clients/ledger-json-api/operations/v2/commands/submit-and-wait.d.ts.map +1 -1
  12. package/build/src/clients/ledger-json-api/operations/v2/updates/subscribe-to-updates.d.ts +268 -473
  13. package/build/src/clients/ledger-json-api/operations/v2/updates/subscribe-to-updates.d.ts.map +1 -1
  14. package/build/src/clients/ledger-json-api/operations/v2/updates/subscribe-to-updates.js +26 -6
  15. package/build/src/clients/ledger-json-api/operations/v2/updates/subscribe-to-updates.js.map +1 -1
  16. package/build/src/clients/ledger-json-api/schemas/api/completions.d.ts +75 -21
  17. package/build/src/clients/ledger-json-api/schemas/api/completions.d.ts.map +1 -1
  18. package/build/src/clients/ledger-json-api/schemas/api/completions.js +9 -4
  19. package/build/src/clients/ledger-json-api/schemas/api/completions.js.map +1 -1
  20. package/build/src/clients/ledger-json-api/schemas/api/event-details.d.ts +83 -8
  21. package/build/src/clients/ledger-json-api/schemas/api/event-details.d.ts.map +1 -1
  22. package/build/src/clients/ledger-json-api/schemas/api/event-details.js +65 -12
  23. package/build/src/clients/ledger-json-api/schemas/api/event-details.js.map +1 -1
  24. package/build/src/clients/ledger-json-api/schemas/api/reassignment.d.ts +86 -34
  25. package/build/src/clients/ledger-json-api/schemas/api/reassignment.d.ts.map +1 -1
  26. package/build/src/clients/ledger-json-api/schemas/api/reassignment.js +14 -3
  27. package/build/src/clients/ledger-json-api/schemas/api/reassignment.js.map +1 -1
  28. package/build/src/clients/ledger-json-api/schemas/api/state.d.ts +65 -41
  29. package/build/src/clients/ledger-json-api/schemas/api/state.d.ts.map +1 -1
  30. package/build/src/clients/ledger-json-api/schemas/api/updates.d.ts +2341 -1414
  31. package/build/src/clients/ledger-json-api/schemas/api/updates.d.ts.map +1 -1
  32. package/build/src/clients/ledger-json-api/schemas/api/updates.js +86 -42
  33. package/build/src/clients/ledger-json-api/schemas/api/updates.js.map +1 -1
  34. package/build/src/clients/ledger-json-api/schemas/common.d.ts +13 -6
  35. package/build/src/clients/ledger-json-api/schemas/common.d.ts.map +1 -1
  36. package/build/src/clients/ledger-json-api/schemas/common.js +16 -6
  37. package/build/src/clients/ledger-json-api/schemas/common.js.map +1 -1
  38. package/build/src/clients/ledger-json-api/schemas/operations/commands.d.ts +28 -20
  39. package/build/src/clients/ledger-json-api/schemas/operations/commands.d.ts.map +1 -1
  40. package/build/src/clients/ledger-json-api/schemas/wire.d.ts +23 -2
  41. package/build/src/clients/ledger-json-api/schemas/wire.d.ts.map +1 -1
  42. package/build/src/clients/ledger-json-api/schemas/wire.js +23 -3
  43. package/build/src/clients/ledger-json-api/schemas/wire.js.map +1 -1
  44. package/build/src/utils/traffic/paid-traffic-cost.d.ts +2 -2
  45. package/build/src/utils/traffic/paid-traffic-cost.d.ts.map +1 -1
  46. package/build/src/utils/traffic/paid-traffic-cost.js +2 -5
  47. package/build/src/utils/traffic/paid-traffic-cost.js.map +1 -1
  48. package/package.json +14 -15
  49. package/bin/canton-localnet +0 -213
  50. package/scripts/localnet-cloud.sh +0 -1178
@@ -1,1178 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
6
- PROJECT_ROOT="${CANTON_LOCALNET_PROJECT_ROOT:-$(pwd)}"
7
- QUICKSTART_DIR="${CANTON_LOCALNET_QUICKSTART_DIR:-${REPO_ROOT}/libs/cn-quickstart/quickstart}"
8
- DOCKERD_PID_FILE="/tmp/localnet-dockerd.pid"
9
- DOCKERD_LOG_FILE="/tmp/localnet-dockerd.log"
10
- HOSTS_ENTRY="127.0.0.1 scan.localhost sv.localhost wallet.localhost"
11
- CURL_CONNECT_TIMEOUT=2
12
- CURL_MAX_TIME=5
13
- LOCALNET_SPLICE_VERSION="${CANTON_LOCALNET_SPLICE_VERSION:-}"
14
- LOCALNET_SCRIBE_VERSION="${CANTON_LOCALNET_SCRIBE_VERSION:-}"
15
- LOCALNET_PROTOCOL_VERSION="${CANTON_LOCALNET_PROTOCOL_VERSION:-}"
16
- VALIDATOR_READY_ATTEMPTS="${CANTON_LOCALNET_VALIDATOR_READY_ATTEMPTS:-90}"
17
- SCAN_READY_ATTEMPTS="${CANTON_LOCALNET_SCAN_READY_ATTEMPTS:-90}"
18
- SPLICE_CONFIG_PENDING_KEY="CANTON_NODE_SDK_SPLICE_CONFIG_PENDING"
19
- SPLICE_CONFIG_CHANGED="false"
20
-
21
- log() {
22
- printf '[localnet] %s\n' "$*"
23
- }
24
-
25
- is_truthy() {
26
- case "${1,,}" in
27
- 1 | true | yes | on)
28
- return 0
29
- ;;
30
- *)
31
- return 1
32
- ;;
33
- esac
34
- }
35
-
36
- require_command() {
37
- local cmd="$1"
38
- if ! command -v "${cmd}" >/dev/null 2>&1; then
39
- log "Missing required command: ${cmd}"
40
- exit 1
41
- fi
42
- }
43
-
44
- require_positive_integer() {
45
- local name="$1"
46
- local value="$2"
47
-
48
- if [[ ! "${value}" =~ ^[1-9][0-9]*$ ]]; then
49
- log "${name} must be a positive integer; received '${value}'."
50
- exit 1
51
- fi
52
- }
53
-
54
- validate_configuration() {
55
- require_positive_integer "CANTON_LOCALNET_VALIDATOR_READY_ATTEMPTS" "${VALIDATOR_READY_ATTEMPTS}"
56
- require_positive_integer "CANTON_LOCALNET_SCAN_READY_ATTEMPTS" "${SCAN_READY_ATTEMPTS}"
57
- }
58
-
59
- ensure_sudo() {
60
- if ! sudo_noninteractive_available; then
61
- log "Passwordless sudo is required in this cloud environment."
62
- exit 1
63
- fi
64
- }
65
-
66
- sudo_noninteractive_available() {
67
- command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1
68
- }
69
-
70
- ensure_docker_packages() {
71
- if command -v docker >/dev/null 2>&1 \
72
- && docker compose version >/dev/null 2>&1; then
73
- return
74
- fi
75
-
76
- if ! sudo_noninteractive_available || ! command -v apt-get >/dev/null 2>&1; then
77
- log "Docker with Compose is required. Install Docker and start it, then retry."
78
- exit 1
79
- fi
80
-
81
- log "Installing Docker packages..."
82
- sudo apt-get update
83
- sudo apt-get install -y docker.io docker-compose docker-compose-v2
84
- }
85
-
86
- ensure_legacy_iptables() {
87
- if ! command -v update-alternatives >/dev/null 2>&1 \
88
- || [[ ! -x /usr/sbin/iptables-legacy || ! -x /usr/sbin/ip6tables-legacy ]]; then
89
- log "iptables legacy binaries unavailable; skipping backend switch."
90
- return
91
- fi
92
-
93
- if ! iptables --version 2>/dev/null | grep -q 'legacy'; then
94
- log "Switching iptables to legacy backend..."
95
- sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
96
- fi
97
-
98
- if ! ip6tables --version 2>/dev/null | grep -q 'legacy'; then
99
- log "Switching ip6tables to legacy backend..."
100
- sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
101
- fi
102
- }
103
-
104
- docker_ready() {
105
- docker info >/dev/null 2>&1 || (sudo_noninteractive_available && sudo docker info >/dev/null 2>&1)
106
- }
107
-
108
- configure_docker_socket_permissions() {
109
- if [[ ! -S /var/run/docker.sock ]]; then
110
- return
111
- fi
112
-
113
- if ! sudo_noninteractive_available; then
114
- return
115
- fi
116
-
117
- sudo groupadd -f docker >/dev/null 2>&1 || true
118
- sudo chown root:docker /var/run/docker.sock >/dev/null 2>&1 || true
119
- sudo chmod 660 /var/run/docker.sock || true
120
- }
121
-
122
- run_docker() {
123
- if docker info >/dev/null 2>&1; then
124
- docker "$@"
125
- return
126
- fi
127
- if ! sudo_noninteractive_available || ! sudo docker info >/dev/null 2>&1; then
128
- log "Docker daemon is not available."
129
- exit 1
130
- fi
131
- sudo docker "$@"
132
- }
133
-
134
- resolve_quickstart_image_tag() {
135
- local env_file=""
136
- local splice_version=""
137
- local parsed_value=""
138
-
139
- for env_file in "${QUICKSTART_DIR}/.env" "${QUICKSTART_DIR}/.env.local"; do
140
- if [[ ! -f "${env_file}" ]]; then
141
- continue
142
- fi
143
-
144
- parsed_value="$(awk -F= -v key="SPLICE_VERSION" '
145
- $0 ~ /^[[:space:]]*#/ { next }
146
- $1 == key {
147
- value = substr($0, index($0, "=") + 1)
148
- gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
149
- gsub(/^"|"$/, "", value)
150
- gsub(/^'\''|'\''$/, "", value)
151
- parsed = value
152
- }
153
- END {
154
- if (parsed != "") {
155
- print parsed
156
- }
157
- }
158
- ' "${env_file}")"
159
-
160
- if [[ -n "${parsed_value}" ]]; then
161
- splice_version="${parsed_value}"
162
- fi
163
- done
164
-
165
- printf '%s' "${splice_version}"
166
- }
167
-
168
- run_quickstart_command() {
169
- local command="$1"
170
- local docker_shim_dir=""
171
- local quickstart_image_tag=""
172
- local quickstart_path="${HOME}/.dpm/bin:${HOME}/.daml/bin:${PATH}"
173
- local status=0
174
-
175
- quickstart_image_tag="$(resolve_quickstart_image_tag)"
176
-
177
- if ! docker info >/dev/null 2>&1 && sudo docker info >/dev/null 2>&1; then
178
- docker_shim_dir="$(mktemp -d "/tmp/canton-localnet-docker-shim.XXXXXX")"
179
- cat >"${docker_shim_dir}/docker" <<'EOF'
180
- #!/usr/bin/env bash
181
- exec sudo -E docker "$@"
182
- EOF
183
- chmod +x "${docker_shim_dir}/docker"
184
- log "Using sudo docker shim for quickstart command."
185
- fi
186
-
187
- if [[ -n "${docker_shim_dir}" ]]; then
188
- quickstart_path="${docker_shim_dir}:${quickstart_path}"
189
- fi
190
-
191
- set +e
192
- (
193
- cd "${QUICKSTART_DIR}"
194
- MODULES_DIR="${QUICKSTART_DIR}/docker/modules" \
195
- LOCALNET_DIR="${QUICKSTART_DIR}/docker/modules/localnet" \
196
- IMAGE_TAG="${quickstart_image_tag}" \
197
- PATH="${quickstart_path}" \
198
- bash -lc "${command}"
199
- )
200
- status=$?
201
- set -e
202
-
203
- if [[ -n "${docker_shim_dir}" ]]; then
204
- rm -rf "${docker_shim_dir}"
205
- fi
206
-
207
- return "${status}"
208
- }
209
-
210
- run_quickstart_make() {
211
- local target="$1"
212
- run_quickstart_command "make ${target}"
213
- }
214
-
215
- run_infra_compose() {
216
- local compose_args="$1"
217
- local keycloak_compose_file=""
218
- local keycloak_env_file=""
219
- local keycloak_profile=""
220
-
221
- if [[ "$(current_auth_mode)" == "oauth2" ]]; then
222
- keycloak_compose_file='-f "${MODULES_DIR}/keycloak/compose.yaml"'
223
- keycloak_env_file='--env-file "${MODULES_DIR}/keycloak/compose.env"'
224
- keycloak_profile='--profile keycloak'
225
- fi
226
-
227
- run_quickstart_command "docker compose \
228
- -f \"\${LOCALNET_DIR}/compose.yaml\" \
229
- ${keycloak_compose_file} \
230
- --env-file .env \
231
- --env-file .env.local \
232
- --env-file \"\${LOCALNET_DIR}/compose.env\" \
233
- --env-file \"\${LOCALNET_DIR}/env/common.env\" \
234
- ${keycloak_env_file} \
235
- --profile app-provider \
236
- --profile app-user \
237
- --profile sv \
238
- ${keycloak_profile} \
239
- ${compose_args}"
240
- }
241
-
242
- start_docker_daemon() {
243
- local dockerd_pid=""
244
-
245
- if docker_ready; then
246
- configure_docker_socket_permissions
247
- return
248
- fi
249
-
250
- if ! sudo_noninteractive_available; then
251
- log "Docker daemon is not running. Start Docker and retry."
252
- exit 1
253
- fi
254
-
255
- ensure_legacy_iptables
256
-
257
- log "Starting Docker daemon with vfs storage driver..."
258
- sudo nohup dockerd --host=unix:///var/run/docker.sock --pidfile="${DOCKERD_PID_FILE}" --storage-driver=vfs >"${DOCKERD_LOG_FILE}" 2>&1 &
259
-
260
- for _ in $(seq 1 60); do
261
- if sudo docker info >/dev/null 2>&1; then
262
- configure_docker_socket_permissions
263
- return
264
- fi
265
- if [[ -f "${DOCKERD_PID_FILE}" ]]; then
266
- dockerd_pid="$(cat "${DOCKERD_PID_FILE}" 2>/dev/null || true)"
267
- if [[ -n "${dockerd_pid}" ]] && ! ps -p "${dockerd_pid}" >/dev/null 2>&1; then
268
- log "Docker daemon exited before becoming ready."
269
- log "Inspect ${DOCKERD_LOG_FILE}."
270
- exit 1
271
- fi
272
- fi
273
- sleep 1
274
- done
275
-
276
- log "Docker failed to start. Inspect ${DOCKERD_LOG_FILE}."
277
- exit 1
278
- }
279
-
280
- ensure_submodules() {
281
- if [[ -n "${CANTON_LOCALNET_QUICKSTART_DIR:-}" ]]; then
282
- if [[ -d "${QUICKSTART_DIR}" ]]; then
283
- return
284
- fi
285
- log "Configured CANTON_LOCALNET_QUICKSTART_DIR does not exist: ${QUICKSTART_DIR}"
286
- exit 1
287
- fi
288
-
289
- if [[ -d "${REPO_ROOT}/libs/splice" && -d "${QUICKSTART_DIR}" ]]; then
290
- return
291
- fi
292
-
293
- require_command git
294
-
295
- if ! git -C "${REPO_ROOT}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
296
- log "Missing localnet assets and not in a git checkout. Install from npm with bundled assets or clone SDK with submodules."
297
- exit 1
298
- fi
299
-
300
- if [[ ! -d "${REPO_ROOT}/libs/splice" ]]; then
301
- log "Initializing libs/splice submodule..."
302
- git -C "${REPO_ROOT}" submodule update --init --depth 1 libs/splice
303
- fi
304
-
305
- if [[ ! -d "${REPO_ROOT}/libs/cn-quickstart" ]]; then
306
- log "Initializing libs/cn-quickstart submodule..."
307
- git -C "${REPO_ROOT}" submodule update --init --recursive libs/cn-quickstart
308
- fi
309
-
310
- if [[ ! -d "${QUICKSTART_DIR}" ]]; then
311
- log "cn-quickstart directory not found after submodule init."
312
- exit 1
313
- fi
314
- }
315
-
316
- ensure_hosts_entries() {
317
- if ! grep -Eq '(^|[[:space:]])scan\.localhost([[:space:]]|$)' /etc/hosts \
318
- || ! grep -Eq '(^|[[:space:]])sv\.localhost([[:space:]]|$)' /etc/hosts \
319
- || ! grep -Eq '(^|[[:space:]])wallet\.localhost([[:space:]]|$)' /etc/hosts; then
320
- log "Adding localnet host aliases to /etc/hosts..."
321
- if sudo_noninteractive_available; then
322
- echo "${HOSTS_ENTRY}" | sudo tee -a /etc/hosts >/dev/null
323
- return
324
- fi
325
- if [[ -t 0 ]] && command -v sudo >/dev/null 2>&1; then
326
- echo "${HOSTS_ENTRY}" | sudo tee -a /etc/hosts >/dev/null
327
- return
328
- fi
329
- log "Missing localnet host aliases. Add this line to /etc/hosts, then retry:"
330
- log "${HOSTS_ENTRY}"
331
- exit 1
332
- fi
333
- }
334
-
335
- set_quickstart_env_value() {
336
- local file="$1"
337
- local key="$2"
338
- local value="$3"
339
-
340
- if [[ ! -f "${file}" ]]; then
341
- return
342
- fi
343
-
344
- if grep -Eq "^${key}=" "${file}"; then
345
- KEY="${key}" VALUE="${value}" perl -0pi -e '
346
- my $key = $ENV{"KEY"};
347
- my $value = $ENV{"VALUE"};
348
- s/^\Q$key\E=.*/$key=$value/m;
349
- ' "${file}"
350
- else
351
- printf '\n%s=%s\n' "${key}" "${value}" >>"${file}"
352
- fi
353
- }
354
-
355
- patch_quickstart_canton_healthcheck() {
356
- local healthcheck="${QUICKSTART_DIR}/docker/modules/localnet/docker/canton/health-check.sh"
357
-
358
- if [[ ! -f "${healthcheck}" ]]; then
359
- log "Canton quickstart healthcheck not found: ${healthcheck}"
360
- exit 1
361
- fi
362
-
363
- cat >"${healthcheck}" <<'EOF'
364
- #!/bin/bash
365
- set -eou pipefail
366
-
367
- http_check() {
368
- local port="$1"
369
- local path="$2"
370
- local status=""
371
-
372
- echo "Checking http://localhost:${port}${path}"
373
- exec 3<>"/dev/tcp/127.0.0.1/${port}"
374
- printf 'GET %s HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' "${path}" >&3
375
- IFS=$'\r' read -r status <&3 || true
376
- exec 3<&-
377
- exec 3>&-
378
-
379
- case "${status}" in
380
- HTTP/*\ 2*) ;;
381
- *)
382
- echo "Unexpected status from ${port}${path}: ${status}"
383
- return 1
384
- ;;
385
- esac
386
- }
387
-
388
- if [ "${APP_USER_PROFILE:-off}" = "on" ]; then
389
- http_check "2${CANTON_HTTP_HEALTHCHECK_PORT_SUFFIX}" "/health"
390
- fi
391
- if [ "${APP_PROVIDER_PROFILE:-off}" = "on" ]; then
392
- http_check "3${CANTON_HTTP_HEALTHCHECK_PORT_SUFFIX}" "/health"
393
- fi
394
- if [ "${SV_PROFILE:-off}" = "on" ]; then
395
- http_check "4${CANTON_HTTP_HEALTHCHECK_PORT_SUFFIX}" "/health"
396
- fi
397
- EOF
398
- chmod +x "${healthcheck}"
399
- }
400
-
401
- patch_quickstart_splice_healthcheck() {
402
- local healthcheck="${QUICKSTART_DIR}/docker/modules/localnet/docker/splice/health-check.sh"
403
-
404
- if [[ ! -f "${healthcheck}" ]]; then
405
- log "Splice quickstart healthcheck not found: ${healthcheck}"
406
- exit 1
407
- fi
408
-
409
- cat >"${healthcheck}" <<'EOF'
410
- #!/bin/bash
411
- set -eou pipefail
412
-
413
- http_check() {
414
- local port="$1"
415
- local path="$2"
416
- local status=""
417
-
418
- echo "Checking http://localhost:${port}${path}"
419
- exec 3<>"/dev/tcp/127.0.0.1/${port}"
420
- printf 'GET %s HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' "${path}" >&3
421
- IFS=$'\r' read -r status <&3 || true
422
- exec 3<&-
423
- exec 3>&-
424
-
425
- case "${status}" in
426
- HTTP/*\ 2*) ;;
427
- *)
428
- echo "Unexpected status from ${port}${path}: ${status}"
429
- return 1
430
- ;;
431
- esac
432
- }
433
-
434
- if [ "${APP_USER_PROFILE:-off}" = "on" ]; then
435
- http_check "2${VALIDATOR_ADMIN_API_PORT_SUFFIX}" "/api/validator/readyz"
436
- fi
437
- if [ "${APP_PROVIDER_PROFILE:-off}" = "on" ]; then
438
- http_check "3${VALIDATOR_ADMIN_API_PORT_SUFFIX}" "/api/validator/readyz"
439
- fi
440
- if [ "${SV_PROFILE:-off}" = "on" ]; then
441
- http_check "4${VALIDATOR_ADMIN_API_PORT_SUFFIX}" "/api/validator/readyz"
442
- http_check "5012" "/api/scan/readyz"
443
- http_check "5014" "/api/sv/readyz"
444
- fi
445
- EOF
446
- chmod +x "${healthcheck}"
447
- }
448
-
449
- configure_quickstart_localnet() {
450
- local env_file=""
451
- local canton_conf="${QUICKSTART_DIR}/docker/modules/localnet/conf/canton/app.conf"
452
- local splice_sv_conf="${QUICKSTART_DIR}/docker/modules/localnet/conf/splice/sv/app.conf"
453
-
454
- SPLICE_CONFIG_CHANGED="false"
455
- if [[ "$(quickstart_env_value "${SPLICE_CONFIG_PENDING_KEY}")" == "true" ]]; then
456
- SPLICE_CONFIG_CHANGED="true"
457
- fi
458
-
459
- for env_file in "${QUICKSTART_DIR}/.env" "${QUICKSTART_DIR}/.env.local"; do
460
- if [[ -n "${LOCALNET_SPLICE_VERSION}" ]]; then
461
- set_quickstart_env_value "${env_file}" "SPLICE_VERSION" "${LOCALNET_SPLICE_VERSION}"
462
- fi
463
- if [[ -n "${LOCALNET_SCRIBE_VERSION}" ]]; then
464
- set_quickstart_env_value "${env_file}" "SCRIBE_VERSION" "${LOCALNET_SCRIBE_VERSION}"
465
- fi
466
- if [[ -n "${CANTON_LOCALNET_DAML_RUNTIME_VERSION:-}" ]]; then
467
- set_quickstart_env_value "${env_file}" "DAML_RUNTIME_VERSION" "${CANTON_LOCALNET_DAML_RUNTIME_VERSION}"
468
- fi
469
- done
470
-
471
- if [[ ! -f "${canton_conf}" ]]; then
472
- log "Canton quickstart config not found: ${canton_conf}"
473
- exit 1
474
- fi
475
-
476
- if [[ ! -f "${splice_sv_conf}" ]]; then
477
- log "Splice SV quickstart config not found: ${splice_sv_conf}"
478
- exit 1
479
- fi
480
-
481
- if ! grep -Eq '^[[:space:]]*canton\.scan-apps\.scan-app\.enable-forced-acs-snapshots[[:space:]]*=[[:space:]]*(true|yes|on)[[:space:]]*$' "${splice_sv_conf}"; then
482
- cat >>"${splice_sv_conf}" <<'EOF'
483
-
484
- # LocalNet integration tests use this endpoint to create deterministic snapshot-backed fixtures.
485
- canton.scan-apps.scan-app.enable-forced-acs-snapshots = true
486
- EOF
487
- set_quickstart_env_value "${QUICKSTART_DIR}/.env.local" "${SPLICE_CONFIG_PENDING_KEY}" "true"
488
- SPLICE_CONFIG_CHANGED="true"
489
- fi
490
-
491
- if [[ -n "${LOCALNET_PROTOCOL_VERSION}" ]]; then
492
- PROTOCOL_VERSION="${LOCALNET_PROTOCOL_VERSION}" perl -0pi -e '
493
- my $protocol_version = $ENV{"PROTOCOL_VERSION"};
494
- s/initial-protocol-version = \d+/initial-protocol-version = $protocol_version/g;
495
- s/(non-standard-config = yes\n)(?![[:space:]]*alpha-version-support = yes)/$1 alpha-version-support = yes\n/;
496
- s/(initial-protocol-version = \d+\n)(?![[:space:]]*alpha-version-support = yes)/$1 alpha-version-support = yes\n/;
497
- ' "${canton_conf}"
498
- fi
499
-
500
- patch_quickstart_canton_healthcheck
501
- patch_quickstart_splice_healthcheck
502
- }
503
-
504
- requested_auth_mode() {
505
- printf '%s' "${CANTON_LOCALNET_AUTH_MODE:-oauth2}"
506
- }
507
-
508
- quickstart_env_value() {
509
- local key="$1"
510
- local parsed_value=""
511
-
512
- if [[ -f "${QUICKSTART_DIR}/.env.local" ]]; then
513
- parsed_value="$(awk -F= -v key="${key}" '
514
- $0 ~ /^[[:space:]]*#/ { next }
515
- $1 == key {
516
- value = substr($0, index($0, "=") + 1)
517
- gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
518
- gsub(/^"|"$/, "", value)
519
- gsub(/^'\''|'\''$/, "", value)
520
- parsed = value
521
- }
522
- END {
523
- if (parsed != "") {
524
- print parsed
525
- }
526
- }
527
- ' "${QUICKSTART_DIR}/.env.local")"
528
- fi
529
-
530
- printf '%s' "${parsed_value}"
531
- }
532
-
533
- configured_auth_mode() {
534
- quickstart_env_value "AUTH_MODE"
535
- }
536
-
537
- quickstart_profile_config_complete() {
538
- local key=""
539
-
540
- for key in OBSERVABILITY_ENABLED AUTH_MODE PARTY_HINT TEST_MODE; do
541
- if [[ -z "$(quickstart_env_value "${key}")" ]]; then
542
- return 1
543
- fi
544
- done
545
-
546
- return 0
547
- }
548
-
549
- verify_configured_auth_mode() {
550
- local expected_auth_mode="$1"
551
- local actual_auth_mode=""
552
-
553
- actual_auth_mode="$(configured_auth_mode)"
554
- if [[ "${actual_auth_mode}" != "${expected_auth_mode}" ]]; then
555
- log "cn-quickstart setup did not configure AUTH_MODE=${expected_auth_mode}; found '${actual_auth_mode:-unset}'."
556
- exit 1
557
- fi
558
- }
559
-
560
- current_auth_mode() {
561
- local configured=""
562
-
563
- configured="$(configured_auth_mode)"
564
- if [[ -n "${configured}" ]]; then
565
- printf '%s' "${configured}"
566
- return
567
- fi
568
-
569
- requested_auth_mode
570
- }
571
-
572
- run_quickstart_setup() {
573
- local auth_mode=""
574
-
575
- auth_mode="$(requested_auth_mode)"
576
- case "${auth_mode}" in
577
- shared-secret)
578
- log "Running cn-quickstart setup (shared-secret mode)..."
579
- (
580
- cd "${QUICKSTART_DIR}"
581
- printf 'Y\nn\n\n' | make setup || true
582
- )
583
- verify_configured_auth_mode "shared-secret"
584
- ;;
585
- oauth2)
586
- log "Running cn-quickstart setup (OAuth2 enabled)..."
587
- (
588
- cd "${QUICKSTART_DIR}"
589
- # Match CI behavior first, then fall back to prompt-based answers for newer setup flows.
590
- echo "2" | make setup || true
591
- if [[ "$(configured_auth_mode)" != "oauth2" ]]; then
592
- printf 'y\ny\n\nn\n' | make setup
593
- fi
594
- )
595
- verify_configured_auth_mode "oauth2"
596
- ;;
597
- *)
598
- log "Unsupported CANTON_LOCALNET_AUTH_MODE: ${auth_mode}"
599
- exit 1
600
- ;;
601
- esac
602
- }
603
-
604
- quickstart_setup() {
605
- if [[ ! -f "${QUICKSTART_DIR}/.env.local" ]]; then
606
- run_quickstart_setup
607
- elif ! quickstart_profile_config_complete; then
608
- log "Regenerating incomplete cn-quickstart config."
609
- rm -f "${QUICKSTART_DIR}/.env.local"
610
- run_quickstart_setup
611
- elif [[ -n "${CANTON_LOCALNET_AUTH_MODE:-}" && "$(configured_auth_mode)" != "${CANTON_LOCALNET_AUTH_MODE}" ]]; then
612
- log "Regenerating cn-quickstart config for CANTON_LOCALNET_AUTH_MODE=${CANTON_LOCALNET_AUTH_MODE}."
613
- rm -f "${QUICKSTART_DIR}/.env.local"
614
- run_quickstart_setup
615
- else
616
- log "Reusing existing ${QUICKSTART_DIR}/.env.local."
617
- fi
618
-
619
- if [[ ! -f "${QUICKSTART_DIR}/.env.local" ]]; then
620
- log "cn-quickstart setup failed: ${QUICKSTART_DIR}/.env.local was not created."
621
- exit 1
622
- fi
623
-
624
- configure_quickstart_localnet
625
-
626
- if quickstart_infra_only_enabled; then
627
- log "Skipping Daml SDK install for infrastructure-only localnet."
628
- return
629
- fi
630
-
631
- if [[ ! -x "${HOME}/.daml/bin/daml" ]]; then
632
- log "Installing Daml SDK..."
633
- (
634
- cd "${QUICKSTART_DIR}"
635
- make install-daml-sdk
636
- )
637
- else
638
- log "Reusing existing Daml SDK at ${HOME}/.daml/bin/daml."
639
- fi
640
- }
641
-
642
- quickstart_fast_start_enabled() {
643
- is_truthy "${CANTON_LOCALNET_FAST_START:-true}"
644
- }
645
-
646
- quickstart_force_full_start() {
647
- is_truthy "${CANTON_LOCALNET_FORCE_FULL_START:-false}"
648
- }
649
-
650
- quickstart_infra_only_enabled() {
651
- is_truthy "${CANTON_LOCALNET_INFRA_ONLY:-false}"
652
- }
653
-
654
- quickstart_build_artifacts_ready() {
655
- local missing_paths=()
656
-
657
- if [[ ! -f "${QUICKSTART_DIR}/backend/build/distributions/backend.tar" ]]; then
658
- missing_paths+=("backend/build/distributions/backend.tar")
659
- fi
660
-
661
- if [[ ! -d "${QUICKSTART_DIR}/frontend/dist" ]]; then
662
- missing_paths+=("frontend/dist")
663
- fi
664
-
665
- if ! compgen -G "${QUICKSTART_DIR}/daml/licensing/.daml/dist/*.dar" >/dev/null; then
666
- missing_paths+=("daml/licensing/.daml/dist/*.dar")
667
- fi
668
-
669
- if ! compgen -G "${QUICKSTART_DIR}/backend/build/otel-agent/opentelemetry-javaagent-*.jar" >/dev/null; then
670
- missing_paths+=("backend/build/otel-agent/opentelemetry-javaagent-*.jar")
671
- fi
672
-
673
- if [[ ${#missing_paths[@]} -gt 0 ]]; then
674
- log "Fast start unavailable; missing quickstart build artifacts: ${missing_paths[*]}"
675
- return 1
676
- fi
677
-
678
- return 0
679
- }
680
-
681
- extract_quickstart_compose_up_command() {
682
- (
683
- cd "${QUICKSTART_DIR}"
684
- make -n start 2>/dev/null | awk '/docker compose .* up -d --no-recreate/{line=$0} END{print line}'
685
- )
686
- }
687
-
688
- try_fast_start_localnet() {
689
- local compose_up_command=""
690
-
691
- compose_up_command="$(extract_quickstart_compose_up_command)"
692
- if [[ -z "${compose_up_command}" ]]; then
693
- log "Unable to determine quickstart compose startup command."
694
- return 1
695
- fi
696
-
697
- log "Starting cn-quickstart with fast path (skip quickstart rebuild)..."
698
- run_quickstart_command "${compose_up_command}"
699
- }
700
-
701
- start_infra_only_localnet() {
702
- log "Starting cn-quickstart LocalNet infrastructure only (skip quickstart app, PQS, and onboarding)."
703
- run_infra_compose 'up -d --no-recreate'
704
- }
705
-
706
- splice_container_running() {
707
- local running=""
708
-
709
- running="$(run_docker inspect --format '{{.State.Running}}' splice 2>/dev/null || true)"
710
- [[ "${running}" == "true" ]]
711
- }
712
-
713
- recreate_splice_after_config_change() {
714
- local should_recreate="$1"
715
-
716
- if [[ "${should_recreate}" != "true" ]]; then
717
- return
718
- fi
719
-
720
- log "Recreating the running Splice service to apply updated LocalNet configuration."
721
- run_infra_compose 'up -d --no-deps --force-recreate splice'
722
- }
723
-
724
- mark_splice_config_applied() {
725
- if [[ "${SPLICE_CONFIG_CHANGED}" != "true" ]]; then
726
- return
727
- fi
728
-
729
- set_quickstart_env_value "${QUICKSTART_DIR}/.env.local" "${SPLICE_CONFIG_PENDING_KEY}" "false"
730
- SPLICE_CONFIG_CHANGED="false"
731
- }
732
-
733
- stop_infra_only_localnet() {
734
- if [[ ! -f "${QUICKSTART_DIR}/.env.local" ]]; then
735
- return
736
- fi
737
-
738
- log "Stopping cn-quickstart LocalNet infrastructure-only stack..."
739
- run_infra_compose down || true
740
- }
741
-
742
- wait_for_services() {
743
- local auth_mode=""
744
- local code=""
745
- local ledger_code=""
746
-
747
- auth_mode="$(current_auth_mode)"
748
-
749
- if [[ "${auth_mode}" == "oauth2" ]]; then
750
- log "Waiting for Keycloak..."
751
- for _ in $(seq 1 30); do
752
- if curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://localhost:8082/realms/AppProvider >/dev/null 2>&1; then
753
- break
754
- fi
755
- sleep 2
756
- done
757
- if ! curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://localhost:8082/realms/AppProvider >/dev/null 2>&1; then
758
- log "Keycloak did not become ready."
759
- exit 1
760
- fi
761
- else
762
- log "Checking for Keycloak (optional in ${auth_mode} mode)..."
763
- for _ in $(seq 1 5); do
764
- if curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://localhost:8082/realms/AppProvider >/dev/null 2>&1; then
765
- log "Keycloak is ready."
766
- break
767
- fi
768
- sleep 2
769
- done
770
- fi
771
-
772
- log "Waiting for Validator API..."
773
- for _ in $(seq 1 "${VALIDATOR_READY_ATTEMPTS}"); do
774
- code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3903/api/validator/v0/wallet/user-status || true)"
775
- if [[ "${code}" == "200" || "${code}" == "401" ]]; then
776
- break
777
- fi
778
- sleep 2
779
- done
780
- code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3903/api/validator/v0/wallet/user-status || true)"
781
- if [[ "${code}" != "200" && "${code}" != "401" ]]; then
782
- log "Validator API did not become ready."
783
- exit 1
784
- fi
785
-
786
- log "Waiting for Scan API..."
787
- for _ in $(seq 1 "${SCAN_READY_ATTEMPTS}"); do
788
- if curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://scan.localhost:4000/api/scan/v0/dso-party-id >/dev/null 2>&1; then
789
- break
790
- fi
791
- sleep 2
792
- done
793
- if ! curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://scan.localhost:4000/api/scan/v0/dso-party-id >/dev/null 2>&1; then
794
- log "Scan API did not become ready."
795
- exit 1
796
- fi
797
-
798
- log "Waiting for Ledger JSON API..."
799
- for _ in $(seq 1 60); do
800
- ledger_code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3975/v2/version || true)"
801
- if [[ "${ledger_code}" == "200" || "${ledger_code}" == "401" ]]; then
802
- break
803
- fi
804
- sleep 2
805
- done
806
- ledger_code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3975/v2/version || true)"
807
- if [[ "${ledger_code}" != "200" && "${ledger_code}" != "401" ]]; then
808
- log "Ledger JSON API did not become ready (HTTP ${ledger_code})."
809
- exit 1
810
- fi
811
-
812
- log "All localnet services are ready."
813
- }
814
-
815
- start_localnet() {
816
- local should_recreate_splice="false"
817
-
818
- if [[ "${SPLICE_CONFIG_CHANGED}" == "true" ]] && splice_container_running; then
819
- should_recreate_splice="true"
820
- fi
821
-
822
- if quickstart_force_full_start; then
823
- log "Forcing full cn-quickstart start (CANTON_LOCALNET_FORCE_FULL_START=true)."
824
- run_quickstart_make start
825
- recreate_splice_after_config_change "${should_recreate_splice}"
826
- wait_for_services
827
- mark_splice_config_applied
828
- return
829
- fi
830
-
831
- if quickstart_infra_only_enabled; then
832
- start_infra_only_localnet
833
- recreate_splice_after_config_change "${should_recreate_splice}"
834
- wait_for_services
835
- mark_splice_config_applied
836
- return
837
- fi
838
-
839
- if quickstart_fast_start_enabled && quickstart_build_artifacts_ready; then
840
- if try_fast_start_localnet; then
841
- recreate_splice_after_config_change "${should_recreate_splice}"
842
- wait_for_services
843
- mark_splice_config_applied
844
- return
845
- fi
846
- log "Fast start failed; falling back to full cn-quickstart start."
847
- fi
848
-
849
- log "Starting cn-quickstart with full build..."
850
- run_quickstart_make start
851
- recreate_splice_after_config_change "${should_recreate_splice}"
852
- wait_for_services
853
- mark_splice_config_applied
854
- }
855
-
856
- stop_localnet() {
857
- if [[ ! -d "${QUICKSTART_DIR}" ]]; then
858
- log "cn-quickstart directory not found; nothing to stop."
859
- stop_managed_dockerd
860
- return
861
- fi
862
-
863
- log "Stopping cn-quickstart..."
864
- stop_infra_only_localnet
865
- if [[ -f "${QUICKSTART_DIR}/Makefile" ]]; then
866
- run_quickstart_make stop || true
867
- else
868
- log "Quickstart Makefile not found; skipping quickstart stop target."
869
- fi
870
- stop_managed_dockerd
871
- }
872
-
873
- stop_managed_dockerd() {
874
- local pid=""
875
- local cmd=""
876
-
877
- if [[ ! -f "${DOCKERD_PID_FILE}" ]]; then
878
- return
879
- fi
880
-
881
- pid="$(cat "${DOCKERD_PID_FILE}" 2>/dev/null || true)"
882
- if [[ -z "${pid}" ]]; then
883
- rm -f "${DOCKERD_PID_FILE}" "${DOCKERD_LOG_FILE}"
884
- return
885
- fi
886
-
887
- if ! ps -p "${pid}" >/dev/null 2>&1; then
888
- rm -f "${DOCKERD_PID_FILE}" "${DOCKERD_LOG_FILE}"
889
- return
890
- fi
891
-
892
- cmd="$(ps -p "${pid}" -o comm= 2>/dev/null | tr -d '[:space:]')"
893
- if [[ "${cmd}" != "dockerd" ]]; then
894
- log "PID ${pid} is not dockerd; skipping daemon cleanup."
895
- rm -f "${DOCKERD_PID_FILE}"
896
- return
897
- fi
898
-
899
- if ! sudo -n true >/dev/null 2>&1; then
900
- log "Cannot stop managed dockerd without passwordless sudo."
901
- return
902
- fi
903
-
904
- log "Stopping managed dockerd (pid ${pid})..."
905
- sudo kill -TERM "${pid}" >/dev/null 2>&1 || true
906
- for _ in $(seq 1 10); do
907
- if ! ps -p "${pid}" >/dev/null 2>&1; then
908
- break
909
- fi
910
- sleep 1
911
- done
912
- if ps -p "${pid}" >/dev/null 2>&1; then
913
- sudo kill -KILL "${pid}" >/dev/null 2>&1 || true
914
- fi
915
- rm -f "${DOCKERD_PID_FILE}" "${DOCKERD_LOG_FILE}"
916
- }
917
-
918
- status_localnet() {
919
- if docker_ready; then
920
- log "Docker daemon is running."
921
- else
922
- log "Docker daemon is not running."
923
- exit 1
924
- fi
925
-
926
- run_docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
927
- echo
928
-
929
- keycloak_ok="no"
930
- validator_ok="no"
931
- scan_ok="no"
932
- ledger_ok="no"
933
- if curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://localhost:8082/realms/AppProvider >/dev/null 2>&1; then
934
- keycloak_ok="yes"
935
- fi
936
- validator_code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3903/api/validator/v0/wallet/user-status || true)"
937
- if [[ "${validator_code}" == "200" || "${validator_code}" == "401" ]]; then
938
- validator_ok="yes"
939
- fi
940
- if curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://scan.localhost:4000/api/scan/v0/dso-party-id >/dev/null 2>&1; then
941
- scan_ok="yes"
942
- fi
943
- ledger_code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3975/v2/version || true)"
944
- if [[ "${ledger_code}" == "200" || "${ledger_code}" == "401" ]]; then
945
- ledger_ok="yes"
946
- fi
947
-
948
- printf 'Keycloak ready: %s\n' "${keycloak_ok}"
949
- printf 'Validator ready: %s (HTTP %s)\n' "${validator_ok}" "${validator_code:-n/a}"
950
- printf 'Scan ready: %s\n' "${scan_ok}"
951
- printf 'Ledger JSON API ready: %s (HTTP %s)\n' "${ledger_ok}" "${ledger_code:-n/a}"
952
- }
953
-
954
- show_localnet_logs() {
955
- log "==================== Docker Containers ===================="
956
- if docker_ready; then
957
- run_docker ps -a || true
958
- else
959
- log "Docker daemon is not running."
960
- fi
961
-
962
- echo
963
- log "==================== Docker Compose Logs ===================="
964
- if [[ -f "${QUICKSTART_DIR}/.env.local" ]]; then
965
- run_infra_compose 'logs --tail=100' || true
966
- elif [[ -d "${QUICKSTART_DIR}" ]]; then
967
- log "Quickstart local env not found; skipping compose logs: ${QUICKSTART_DIR}/.env.local"
968
- else
969
- log "cn-quickstart directory not found: ${QUICKSTART_DIR}"
970
- fi
971
-
972
- echo
973
- log "==================== Canton Logs ===================="
974
- if [[ -f "${QUICKSTART_DIR}/logs/canton.log" ]]; then
975
- tail -100 "${QUICKSTART_DIR}/logs/canton.log" || true
976
- else
977
- log "Canton log not found: ${QUICKSTART_DIR}/logs/canton.log"
978
- fi
979
-
980
- if [[ -f "${DOCKERD_LOG_FILE}" ]]; then
981
- echo
982
- log "==================== Managed Docker Daemon Logs ===================="
983
- tail -100 "${DOCKERD_LOG_FILE}" || true
984
- fi
985
- }
986
-
987
- run_smoke() {
988
- local auth_mode=""
989
- local validator_code=""
990
- local ledger_code=""
991
-
992
- log "Running localnet smoke checks..."
993
- auth_mode="$(current_auth_mode)"
994
-
995
- if curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://localhost:8082/realms/AppProvider >/dev/null 2>&1; then
996
- log "Keycloak is reachable."
997
- elif [[ "${auth_mode}" == "oauth2" ]]; then
998
- log "Keycloak is not reachable."
999
- exit 1
1000
- else
1001
- log "Keycloak not detected (expected in ${auth_mode} mode)."
1002
- fi
1003
-
1004
- validator_code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3903/api/validator/v0/wallet/user-status || true)"
1005
- if [[ "${validator_code}" != "200" && "${validator_code}" != "401" ]]; then
1006
- log "Validator API is not reachable (HTTP ${validator_code})."
1007
- exit 1
1008
- fi
1009
-
1010
- if ! curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -fsS http://scan.localhost:4000/api/scan/v0/dso-party-id >/dev/null 2>&1; then
1011
- log "Scan API is not reachable."
1012
- exit 1
1013
- fi
1014
-
1015
- ledger_code="$(curl --connect-timeout "${CURL_CONNECT_TIMEOUT}" --max-time "${CURL_MAX_TIME}" -sS -o /dev/null -w '%{http_code}' http://localhost:3975/v2/version || true)"
1016
- if [[ "${ledger_code}" != "200" && "${ledger_code}" != "401" ]]; then
1017
- log "Ledger JSON API is not reachable (HTTP ${ledger_code})."
1018
- exit 1
1019
- fi
1020
-
1021
- log "Smoke checks passed."
1022
- }
1023
-
1024
- read_npm_script() {
1025
- local target_dir="$1"
1026
- local script_name="$2"
1027
-
1028
- if [[ ! -f "${target_dir}/package.json" ]]; then
1029
- return
1030
- fi
1031
-
1032
- node -e 'const fs=require("fs"); const pkgPath=process.argv[1]; const scriptName=process.argv[2]; try { const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8")); const script = pkg?.scripts?.[scriptName]; if (typeof script === "string") process.stdout.write(script); } catch {}' "${target_dir}/package.json" "${script_name}"
1033
- }
1034
-
1035
- script_is_recursive_localnet_test() {
1036
- local script_value="$1"
1037
- echo "${script_value}" | grep -Eq '(^|[[:space:]])(canton-localnet[[:space:]]+test|[^[:space:]]*localnet-cloud\.sh[[:space:]]+test)([[:space:]]|$)'
1038
- }
1039
-
1040
- run_integration_tests() {
1041
- local script_value=""
1042
-
1043
- if [[ -n "${CANTON_LOCALNET_TEST_CMD:-}" ]]; then
1044
- log "Running custom integration command from CANTON_LOCALNET_TEST_CMD..."
1045
- (
1046
- cd "${PROJECT_ROOT}"
1047
- bash -lc "${CANTON_LOCALNET_TEST_CMD}"
1048
- )
1049
- return
1050
- fi
1051
-
1052
- script_value="$(read_npm_script "${PROJECT_ROOT}" "test:integration")"
1053
- if [[ -n "${script_value}" ]]; then
1054
- if script_is_recursive_localnet_test "${script_value}"; then
1055
- log "Skipping recursive test:integration script."
1056
- else
1057
- log "Running project integration tests: npm run test:integration"
1058
- (
1059
- cd "${PROJECT_ROOT}"
1060
- npm run test:integration
1061
- )
1062
- return
1063
- fi
1064
- fi
1065
-
1066
- script_value="$(read_npm_script "${PROJECT_ROOT}" "test:localnet")"
1067
- if [[ -n "${script_value}" ]]; then
1068
- if script_is_recursive_localnet_test "${script_value}"; then
1069
- log "Skipping recursive test:localnet script."
1070
- else
1071
- log "Running project integration tests: npm run test:localnet"
1072
- (
1073
- cd "${PROJECT_ROOT}"
1074
- npm run test:localnet
1075
- )
1076
- return
1077
- fi
1078
- fi
1079
-
1080
- if [[ "${PROJECT_ROOT}" == "${REPO_ROOT}" && -d "${REPO_ROOT}/test/integration/localnet" && -d "${REPO_ROOT}/node_modules" ]]; then
1081
- log "Running bundled SDK localnet integration tests..."
1082
- (
1083
- cd "${REPO_ROOT}"
1084
- npm test -- test/integration/localnet
1085
- )
1086
- return
1087
- fi
1088
-
1089
- log "No integration test command configured; skipping test step."
1090
- }
1091
-
1092
- usage() {
1093
- cat <<'USAGE'
1094
- Usage: scripts/localnet/localnet-cloud.sh <command>
1095
-
1096
- Commands:
1097
- setup Install prerequisites, init submodules, configure quickstart
1098
- start Start localnet and wait for ready endpoints
1099
- stop Stop localnet services
1100
- logs Show localnet diagnostic logs
1101
- status Show docker + endpoint status
1102
- smoke Run endpoint smoke checks
1103
- test Run project integration tests (if configured)
1104
- verify Run setup + start + smoke + test
1105
-
1106
- Environment:
1107
- CANTON_LOCALNET_FAST_START=true|false Enable fast startup path (default: true)
1108
- CANTON_LOCALNET_FORCE_FULL_START=true|false Force full startup with rebuild
1109
- CANTON_LOCALNET_INFRA_ONLY=true|false Start only LocalNet + Keycloak infrastructure
1110
- CANTON_LOCALNET_AUTH_MODE=oauth2|shared-secret
1111
- CANTON_LOCALNET_QUICKSTART_DIR=<path> Use an existing cn-quickstart/quickstart directory
1112
- USAGE
1113
- }
1114
-
1115
- main() {
1116
- if [[ "${1:-}" == "" ]]; then
1117
- usage
1118
- exit 1
1119
- fi
1120
-
1121
- case "$1" in
1122
- setup)
1123
- validate_configuration
1124
- ensure_docker_packages
1125
- start_docker_daemon
1126
- ensure_submodules
1127
- ensure_hosts_entries
1128
- quickstart_setup
1129
- ;;
1130
- start)
1131
- validate_configuration
1132
- require_command curl
1133
- ensure_docker_packages
1134
- start_docker_daemon
1135
- ensure_submodules
1136
- ensure_hosts_entries
1137
- quickstart_setup
1138
- start_localnet
1139
- ;;
1140
- stop)
1141
- stop_localnet
1142
- ;;
1143
- logs)
1144
- show_localnet_logs
1145
- ;;
1146
- status)
1147
- require_command curl
1148
- status_localnet
1149
- ;;
1150
- smoke)
1151
- require_command curl
1152
- run_smoke
1153
- ;;
1154
- test)
1155
- run_integration_tests
1156
- ;;
1157
- verify)
1158
- validate_configuration
1159
- require_command curl
1160
- ensure_docker_packages
1161
- start_docker_daemon
1162
- ensure_submodules
1163
- ensure_hosts_entries
1164
- quickstart_setup
1165
- start_localnet
1166
- run_smoke
1167
- run_integration_tests
1168
- ;;
1169
- *)
1170
- usage
1171
- exit 1
1172
- ;;
1173
- esac
1174
- }
1175
-
1176
- if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
1177
- main "$@"
1178
- fi