@distrohelena/canton-typescript-sdk 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +333 -1
- package/dist/client/canton-client-options.d.ts +3 -0
- package/dist/client/canton-client-options.js +2 -0
- package/dist/client/service-registry.js +3 -2
- package/dist/core/errors/grpc-transport-error.d.ts +14 -0
- package/dist/core/errors/grpc-transport-error.js +76 -0
- package/dist/core/types/canton-hash-purpose.d.ts +2 -1
- package/dist/core/types/canton-hash-purpose.js +1 -0
- package/dist/core/types/daml-numeric.d.ts +6 -0
- package/dist/core/types/daml-numeric.js +14 -0
- package/dist/core/types/daml-party.d.ts +6 -0
- package/dist/core/types/daml-party.js +14 -0
- package/dist/core/types/requests/create-decentralized-party-request.d.ts +41 -0
- package/dist/core/types/requests/create-decentralized-party-request.js +82 -0
- package/dist/core/types/requests/create-external-party-request.d.ts +42 -0
- package/dist/core/types/requests/create-external-party-request.js +47 -0
- package/dist/core/types/requests/finalize-decentralized-party-request.d.ts +39 -0
- package/dist/core/types/requests/finalize-decentralized-party-request.js +42 -0
- package/dist/core/types/requests/get-active-contracts-page-request.d.ts +15 -2
- package/dist/core/types/requests/get-active-contracts-page-request.js +4 -0
- package/dist/core/types/topology/topology-signature-format.d.ts +2 -1
- package/dist/core/types/topology/topology-signature-format.js +1 -0
- package/dist/daml-lf/container/dar-archive-entry.d.ts +8 -0
- package/dist/daml-lf/container/dar-archive-entry.js +8 -0
- package/dist/daml-lf/container/dar-archive-loader.js +14 -0
- package/dist/daml-lf/container/dar-archive.d.ts +6 -0
- package/dist/daml-lf/container/dar-archive.js +4 -0
- package/dist/daml-lf/container/dar-source-bundle-loader.d.ts +5 -0
- package/dist/daml-lf/container/dar-source-bundle-loader.js +33 -0
- package/dist/daml-lf/container/dar-source-bundle.d.ts +45 -0
- package/dist/daml-lf/container/dar-source-bundle.js +11 -0
- package/dist/daml-lf/container/dar-source-file-entry.d.ts +8 -0
- package/dist/daml-lf/container/dar-source-file-entry.js +8 -0
- package/dist/daml-lf/daml-lf-compilation.d.ts +12 -0
- package/dist/daml-lf/daml-lf-compilation.js +35 -0
- package/dist/daml-lf/index.d.ts +11 -0
- package/dist/daml-lf/index.js +10 -0
- package/dist/daml-lf/interpreter/daml-lf-builtin-dispatch.d.ts +43 -0
- package/dist/daml-lf/interpreter/daml-lf-builtin-dispatch.js +933 -0
- package/dist/daml-lf/interpreter/daml-lf-evaluator.d.ts +95 -0
- package/dist/daml-lf/interpreter/daml-lf-evaluator.js +1131 -0
- package/dist/daml-lf/interpreter/daml-lf-interpreter-scaffold.d.ts +3 -0
- package/dist/daml-lf/interpreter/daml-lf-interpreter-scaffold.js +6 -1
- package/dist/daml-lf/interpreter/daml-lf-lexical-scope.d.ts +13 -0
- package/dist/daml-lf/interpreter/daml-lf-lexical-scope.js +46 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-frame.d.ts +16 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-frame.js +15 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-value.d.ts +21 -0
- package/dist/daml-lf/interpreter/daml-lf-runtime-value.js +4 -1
- package/dist/daml-lf/interpreter/daml-lf-step-kind.d.ts +7 -0
- package/dist/daml-lf/interpreter/daml-lf-step-kind.js +8 -0
- package/dist/daml-lf/interpreter/daml-lf-trace-sink.interface.d.ts +30 -0
- package/dist/daml-lf/interpreter/daml-lf-trace-sink.interface.js +1 -0
- package/dist/daml-lf/model/daml-lf-builtin-type.d.ts +3 -0
- package/dist/daml-lf/model/daml-lf-builtin-type.js +3 -0
- package/dist/daml-lf/model/daml-lf-choice.d.ts +5 -0
- package/dist/daml-lf/model/daml-lf-choice.js +4 -0
- package/dist/daml-lf/model/daml-lf-expression-path.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-expression-path.js +81 -0
- package/dist/daml-lf/model/daml-lf-expression.d.ts +146 -0
- package/dist/daml-lf/model/daml-lf-expression.js +71 -0
- package/dist/daml-lf/model/daml-lf-template.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-template.js +2 -0
- package/dist/daml-lf/model/daml-lf-type.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-type.js +4 -0
- package/dist/daml-lf/model/lf-2-model-mapper.d.ts +5 -0
- package/dist/daml-lf/model/lf-2-model-mapper.js +445 -12
- package/dist/debugger/errors/replay-determinism.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-determinism.exception.js +3 -0
- package/dist/debugger/errors/replay-missing-package.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-missing-package.exception.js +3 -0
- package/dist/debugger/errors/replay-missing-source.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-missing-source.exception.js +3 -0
- package/dist/debugger/errors/replay-source-map.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-source-map.exception.js +3 -0
- package/dist/debugger/errors/replay-state-hydration.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-state-hydration.exception.js +3 -0
- package/dist/debugger/errors/replay-unsupported-lf-construct.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-unsupported-lf-construct.exception.js +3 -0
- package/dist/debugger/errors/replay-unsupported-update.exception.d.ts +3 -0
- package/dist/debugger/errors/replay-unsupported-update.exception.js +3 -0
- package/dist/debugger/index.d.ts +31 -0
- package/dist/debugger/index.js +31 -0
- package/dist/debugger/ledger-replay-debugger-client.d.ts +31 -0
- package/dist/debugger/ledger-replay-debugger-client.js +53 -0
- package/dist/debugger/replay/ledger-replay-environment-builder.d.ts +95 -0
- package/dist/debugger/replay/ledger-replay-environment-builder.js +249 -0
- package/dist/debugger/replay/ledger-replay-session-loader.d.ts +78 -0
- package/dist/debugger/replay/ledger-replay-session-loader.js +565 -0
- package/dist/debugger/replay/replay-artifact-resolver.d.ts +30 -0
- package/dist/debugger/replay/replay-artifact-resolver.js +210 -0
- package/dist/debugger/replay/replay-determinism-validator.d.ts +12 -0
- package/dist/debugger/replay/replay-determinism-validator.js +161 -0
- package/dist/debugger/replay/replay-entrypoint-definition-resolver.d.ts +40 -0
- package/dist/debugger/replay/replay-entrypoint-definition-resolver.js +337 -0
- package/dist/debugger/replay/replay-entrypoint.d.ts +22 -0
- package/dist/debugger/replay/replay-entrypoint.js +14 -0
- package/dist/debugger/replay/replay-ledger-value-normalizer.d.ts +7 -0
- package/dist/debugger/replay/replay-ledger-value-normalizer.js +194 -0
- package/dist/debugger/replay/replay-update-loader.d.ts +24 -0
- package/dist/debugger/replay/replay-update-loader.js +94 -0
- package/dist/debugger/replay/replay-update-visibility-validator.d.ts +19 -0
- package/dist/debugger/replay/replay-update-visibility-validator.js +19 -0
- package/dist/debugger/session/in-memory-replay-session-store.d.ts +27 -0
- package/dist/debugger/session/in-memory-replay-session-store.js +109 -0
- package/dist/debugger/session/replay-phase.d.ts +7 -0
- package/dist/debugger/session/replay-phase.js +8 -0
- package/dist/debugger/session/replay-scope.d.ts +10 -0
- package/dist/debugger/session/replay-scope.js +10 -0
- package/dist/debugger/session/replay-session-metadata.d.ts +10 -0
- package/dist/debugger/session/replay-session-metadata.js +10 -0
- package/dist/debugger/session/replay-session-request.d.ts +6 -0
- package/dist/debugger/session/replay-session-request.js +10 -0
- package/dist/debugger/session/replay-session.d.ts +12 -0
- package/dist/debugger/session/replay-session.js +10 -0
- package/dist/debugger/session/replay-source-location.d.ts +17 -0
- package/dist/debugger/session/replay-source-location.js +16 -0
- package/dist/debugger/session/replay-stack-frame.d.ts +8 -0
- package/dist/debugger/session/replay-stack-frame.js +8 -0
- package/dist/debugger/session/replay-state-delta.d.ts +29 -0
- package/dist/debugger/session/replay-state-delta.js +24 -0
- package/dist/debugger/session/replay-step-advance-result.d.ts +24 -0
- package/dist/debugger/session/replay-step-advance-result.js +16 -0
- package/dist/debugger/session/replay-step.d.ts +30 -0
- package/dist/debugger/session/replay-step.js +24 -0
- package/dist/debugger/session/replay-value-preview.d.ts +8 -0
- package/dist/debugger/session/replay-value-preview.js +15 -0
- package/dist/debugger/source/daml-source-mapper.d.ts +12 -0
- package/dist/debugger/source/daml-source-mapper.js +21 -0
- package/dist/debugger/source/dar-source-map-metadata.d.ts +26 -0
- package/dist/debugger/source/dar-source-map-metadata.js +10 -0
- package/dist/debugger/source/source-coverage-validator.d.ts +8 -0
- package/dist/debugger/source/source-coverage-validator.js +16 -0
- package/dist/debugger/source/source-indexed-compilation.d.ts +45 -0
- package/dist/debugger/source/source-indexed-compilation.js +110 -0
- package/dist/debugger/source/source-mapping-precision.d.ts +5 -0
- package/dist/debugger/source/source-mapping-precision.js +4 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +12 -0
- package/dist/query/cache/memory-query-cache.d.ts +9 -0
- package/dist/query/cache/memory-query-cache.js +24 -0
- package/dist/query/cache/query-cache-store.d.ts +5 -0
- package/dist/query/cache/query-cache-store.js +1 -0
- package/dist/query/canton-manager-options.d.ts +17 -0
- package/dist/query/canton-manager-options.js +1 -0
- package/dist/query/canton-manager.d.ts +11 -0
- package/dist/query/canton-manager.js +42 -0
- package/dist/query/errors/pqs-query-error.d.ts +10 -0
- package/dist/query/errors/pqs-query-error.js +11 -0
- package/dist/query/errors/pqs-schema-profile-error.d.ts +3 -0
- package/dist/query/errors/pqs-schema-profile-error.js +3 -0
- package/dist/query/errors/query-capability-error.d.ts +7 -0
- package/dist/query/errors/query-capability-error.js +10 -0
- package/dist/query/grpc/grpc-contract-query-client.d.ts +32 -0
- package/dist/query/grpc/grpc-contract-query-client.js +126 -0
- package/dist/query/model-types.d.ts +258 -0
- package/dist/query/model-types.js +14 -0
- package/dist/query/pqs/pqs-pool.d.ts +13 -0
- package/dist/query/pqs/pqs-pool.js +18 -0
- package/dist/query/pqs/pqs-query-client.d.ts +49 -0
- package/dist/query/pqs/pqs-query-client.js +324 -0
- package/dist/query/pqs/pqs-schema-profile.d.ts +25 -0
- package/dist/query/pqs/pqs-schema-profile.js +120 -0
- package/dist/query/pqs/pqs-sql-compiler.d.ts +7 -0
- package/dist/query/pqs/pqs-sql-compiler.js +132 -0
- package/dist/query/pqs/read-only-sql.d.ts +1 -0
- package/dist/query/pqs/read-only-sql.js +35 -0
- package/dist/query/query-client.d.ts +61 -0
- package/dist/query/query-client.js +1 -0
- package/dist/query/query-source.d.ts +4 -0
- package/dist/query/query-source.js +5 -0
- package/dist/services/party-management/decentralized-party-lifecycle.d.ts +6 -0
- package/dist/services/party-management/decentralized-party-lifecycle.js +82 -0
- package/dist/services/party-management/party-management-service-client.d.ts +16 -1
- package/dist/services/party-management/party-management-service-client.js +142 -1
- package/dist/services/topology-manager-write/topology-signed-transaction-assembler.js +4 -0
- package/dist/testing/campaign/campaign-artifact.d.ts +20 -0
- package/dist/testing/campaign/campaign-artifact.js +147 -0
- package/dist/testing/campaign/campaign-definition.d.ts +9 -0
- package/dist/testing/campaign/campaign-definition.js +78 -0
- package/dist/testing/campaign/campaign-metrics.d.ts +32 -0
- package/dist/testing/campaign/campaign-metrics.js +26 -0
- package/dist/testing/campaign/campaign-model.d.ts +11 -0
- package/dist/testing/campaign/campaign-model.js +21 -0
- package/dist/testing/campaign/campaign-runner.d.ts +99 -0
- package/dist/testing/campaign/campaign-runner.js +194 -0
- package/dist/testing/campaign/campaign-scheduler.d.ts +40 -0
- package/dist/testing/campaign/campaign-scheduler.js +75 -0
- package/dist/testing/campaign/campaign-types.d.ts +52 -0
- package/dist/testing/campaign/campaign-types.js +11 -0
- package/dist/testing/daml/daml-action-arbitrary.d.ts +13 -0
- package/dist/testing/daml/daml-action-arbitrary.js +24 -0
- package/dist/testing/daml/daml-choice-action-arbitrary.d.ts +18 -0
- package/dist/testing/daml/daml-choice-action-arbitrary.js +27 -0
- package/dist/testing/daml/daml-create-action-arbitrary.d.ts +19 -0
- package/dist/testing/daml/daml-create-action-arbitrary.js +34 -0
- package/dist/testing/daml/daml-testing-catalog.d.ts +38 -0
- package/dist/testing/daml/daml-testing-catalog.js +40 -0
- package/dist/testing/daml/daml-value-arbitrary.d.ts +8 -0
- package/dist/testing/daml/daml-value-arbitrary.js +43 -0
- package/dist/testing/daml/declarative-campaign-arbitrary.d.ts +15 -0
- package/dist/testing/daml/declarative-campaign-arbitrary.js +30 -0
- package/dist/testing/errors/invariant-campaign-failure.d.ts +24 -0
- package/dist/testing/errors/invariant-campaign-failure.js +37 -0
- package/dist/testing/errors/testing-configuration-error.d.ts +3 -0
- package/dist/testing/errors/testing-configuration-error.js +6 -0
- package/dist/testing/handlers/handler.d.ts +19 -0
- package/dist/testing/handlers/handler.js +31 -0
- package/dist/testing/index.d.ts +22 -0
- package/dist/testing/index.js +22 -0
- package/dist/testing/runtime/campaign-isolation.d.ts +14 -0
- package/dist/testing/runtime/campaign-isolation.js +23 -0
- package/dist/testing/runtime/canton-test-runtime.d.ts +58 -0
- package/dist/testing/runtime/canton-test-runtime.js +138 -0
- package/dist/testing/runtime/declarative-action-executor.d.ts +16 -0
- package/dist/testing/runtime/declarative-action-executor.js +41 -0
- package/dist/testing/targets/target.d.ts +49 -0
- package/dist/testing/targets/target.js +121 -0
- package/dist/transports/grpc/grpc-channel-factory.js +31 -1
- package/dist/transports/grpc/grpc-transport.js +5 -3
- package/dist/transports/grpc/mappers/commands-mapper.js +18 -0
- package/dist/transports/grpc/mappers/contracts-mapper.d.ts +3 -1
- package/dist/transports/grpc/mappers/contracts-mapper.js +16 -3
- package/dist/transports/grpc/mappers/topology-manager-write-mapper.js +59 -1
- package/dist/transports/json/mappers/commands-mapper.js +20 -6
- package/node/.generated/start-local/additional-config.extra-participants.conf +37 -0
- package/node/.generated/start-local/additional-config.extra-validators.conf +35 -0
- package/node/.generated/start-local/compose-extra-participants.yaml +147 -0
- package/node/.generated/start-local/extra-participants.env +30 -0
- package/node/es256-jwt.mjs +177 -0
- package/node/start-local.sh +886 -0
- package/node/stop-local.sh +200 -0
- package/node/test-start-local.sh +354 -0
- package/node/test-stop-local.sh +112 -0
- package/package.json +21 -2
package/README.md
CHANGED
|
@@ -13,10 +13,120 @@ TypeScript SDK for Canton with:
|
|
|
13
13
|
npm install @distrohelena/canton-typescript-sdk
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
## Experimental invariant testing
|
|
17
|
+
|
|
18
|
+
`@distrohelena/canton-typescript-sdk/testing` is an experimental, opt-in
|
|
19
|
+
Foundry-style fuzzing surface for Canton. It provides semantic parity for
|
|
20
|
+
campaign runs, exact depth, handlers, permissive or strict protocol reverts,
|
|
21
|
+
invariants, shrinking, replay traces, and safe artifacts. It does not attempt
|
|
22
|
+
to reproduce Foundry's EVM, ABI, PRNG, or shrink sequence byte-for-byte.
|
|
23
|
+
|
|
24
|
+
Define the campaign once, keep ledger I/O in explicit runtime hooks, and use
|
|
25
|
+
safe isolation. Shared or production ledgers must use an explicit external or
|
|
26
|
+
snapshot policy; cleanup policies need contract discovery for ambiguous
|
|
27
|
+
submissions.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import * as fc from "fast-check";
|
|
31
|
+
import {
|
|
32
|
+
defineInvariantCampaign,
|
|
33
|
+
runInvariantCampaignCheckAsync,
|
|
34
|
+
} from "@distrohelena/canton-typescript-sdk/testing";
|
|
35
|
+
|
|
36
|
+
const campaign = defineInvariantCampaign<{ total: number }>({
|
|
37
|
+
runtime: {
|
|
38
|
+
actors: {
|
|
39
|
+
issuer: { party: "Issuer", participant: "participant-a" },
|
|
40
|
+
},
|
|
41
|
+
isolation: { kind: "external" },
|
|
42
|
+
},
|
|
43
|
+
config: { runs: 100, depth: 8, failOnRevert: false, seed: 42 },
|
|
44
|
+
targets: [{ key: "Main:Iou:Create", actors: ["issuer"] }],
|
|
45
|
+
invariants: [async ({ model }) => {
|
|
46
|
+
if (model.total < 0) throw new Error("negative total");
|
|
47
|
+
}],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await runInvariantCampaignCheckAsync({
|
|
51
|
+
campaign,
|
|
52
|
+
arbitrary: fc.constant([{ actor: "issuer", targetKey: "Main:Iou:Create" }]),
|
|
53
|
+
key: (actions) => JSON.stringify(actions),
|
|
54
|
+
setupAsync: async () => ({ model: { total: 0 }, ghost: {} }),
|
|
55
|
+
executeAsync: async () => ({ kind: "accepted", updateId: "update-1" }),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Use `createDamlTestingCatalog`, `targetTemplate`, and
|
|
60
|
+
`resolveDeclarativeTargets` to discover targets. `targetTemplate(id).create()`
|
|
61
|
+
and `.choice(name)` select create and exercise actions; pair the resolved
|
|
62
|
+
targets with `createDeclarativeCampaignArbitrary` for an exact-depth action
|
|
63
|
+
sequence. In `executeAsync`, pass each action to `executeDeclarativeActionAsync`
|
|
64
|
+
with the campaign runtime and an explicit `resolveContractIdAsync` callback for
|
|
65
|
+
choices. The callback is intentional: the SDK will not guess an active contract
|
|
66
|
+
from stale local state. `handler`, `bound`, and handler assumptions support
|
|
67
|
+
custom operations alongside declarative actions. A failed check returns the
|
|
68
|
+
shrunk counterexample trace; `InvariantCampaignFailure` and replay artifacts
|
|
69
|
+
expose only allowlisted diagnostics.
|
|
70
|
+
|
|
71
|
+
Automatic Party fields require an explicit `valueParties` list. When writing
|
|
72
|
+
commands by hand, use `DamlParty` and `DamlNumeric` for Party and exact decimal
|
|
73
|
+
Numeric values; a plain string is DAML `Text` and a plain JavaScript number is
|
|
74
|
+
not an exact Numeric value.
|
|
75
|
+
|
|
16
76
|
## Live Integration Tests
|
|
17
77
|
|
|
18
78
|
The repository also supports a live SDK validation suite against an already-running CN quickstart localnet.
|
|
19
79
|
|
|
80
|
+
## Localnet launchers
|
|
81
|
+
|
|
82
|
+
The published package includes launchers for an existing CN Quickstart checkout.
|
|
83
|
+
Docker Compose must be installed and available. Set `CN_QUICKSTART_DIR` to the
|
|
84
|
+
checkout (or its `quickstart/` directory) when it is not in a supported relative
|
|
85
|
+
location.
|
|
86
|
+
|
|
87
|
+
After installing the package, run:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
canton-localnet-start
|
|
91
|
+
canton-localnet-stop
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You can also run them without a global install:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm exec --package @distrohelena/canton-typescript-sdk canton-localnet-start
|
|
98
|
+
npm exec --package @distrohelena/canton-typescript-sdk canton-localnet-stop
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
These commands launch and stop CN Quickstart; they do not provision a
|
|
102
|
+
Quickstart checkout.
|
|
103
|
+
|
|
104
|
+
### Optional ES256 bearer tokens
|
|
105
|
+
|
|
106
|
+
Set `LOCALNET_ES256_JWT=1` when starting the localnet to add ES256 JWT
|
|
107
|
+
verification to the primary participants and any `EXTRA_PARTICIPANTS`. The
|
|
108
|
+
existing `AUTH_MODE` stays active for Quickstart's internal services.
|
|
109
|
+
|
|
110
|
+
By default, the launcher creates reusable P-256 development key material and
|
|
111
|
+
a self-signed certificate in `.generated/localnet-es256` at the package root. Set
|
|
112
|
+
`LOCALNET_ES256_ROTATE=1` to replace generated material, or set both
|
|
113
|
+
`LOCALNET_ES256_PRIVATE_KEY_PATH` and `LOCALNET_ES256_CERTIFICATE_PATH` to
|
|
114
|
+
use your own matching PEM private key and certificate.
|
|
115
|
+
|
|
116
|
+
The launcher writes a short-lived (ten-minute) token for `ledger-api-user` to
|
|
117
|
+
`ledger-api-user.token` in that runtime directory and prints its path. Use it
|
|
118
|
+
with the live SDK suite:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
SDK_TEST_LEDGER_BEARER_TOKEN="$(cat .generated/localnet-es256/ledger-api-user.token)" \
|
|
122
|
+
npm run test:live
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This is development-only key material. A custom `LOCALNET_ES256_SUBJECT` must
|
|
126
|
+
already be a Ledger API user with the appropriate rights on each participant.
|
|
127
|
+
Extra participants use the existing shared-secret onboarding flow; the current
|
|
128
|
+
OAuth2-plus-extras limitation still applies.
|
|
129
|
+
|
|
20
130
|
The live suite runs single-worker with an extended timeout because it mutates and reads a shared localnet.
|
|
21
131
|
|
|
22
132
|
Prerequisites:
|
|
@@ -61,6 +171,69 @@ Run:
|
|
|
61
171
|
npm run test:live
|
|
62
172
|
```
|
|
63
173
|
|
|
174
|
+
The opt-in live stateful fuzz campaign uses the two-participant CN quickstart
|
|
175
|
+
`Main:Iou` fixture. It is disabled by default and must be enabled explicitly:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
SDK_TEST_ENABLE_LIVE_FUZZING=1 \
|
|
179
|
+
FUZZ_NUM_RUNS=20 \
|
|
180
|
+
npm run test:live:fuzz
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The campaign requires both gRPC participants, with node 0 using
|
|
184
|
+
`SDK_TEST_LEDGER_ENDPOINT`, `SDK_TEST_LEDGER_ADMIN_ENDPOINT`, and
|
|
185
|
+
`SDK_TEST_PARTICIPANT_ADMIN_ENDPOINT`, and node 1 using the corresponding
|
|
186
|
+
`SDK_TEST_SECONDARY_*` variables. It allocates an issuer on participant A and
|
|
187
|
+
an owner on participant B unless `FUZZ_LIVE_ISSUER_PARTY` and
|
|
188
|
+
`FUZZ_LIVE_OWNER_PARTY` are both supplied. For exact replay, keep those party
|
|
189
|
+
IDs, `FUZZ_LIVE_RUN_ID`, `FUZZ_SEED`, and `FUZZ_PATH` unchanged.
|
|
190
|
+
|
|
191
|
+
Campaign controls include:
|
|
192
|
+
|
|
193
|
+
- `FUZZ_LIVE_DEPTH=N` for exact-depth Foundry-style runs. If it is absent,
|
|
194
|
+
`FUZZ_LIVE_MAX_COMMANDS=N` retains the legacy variable-length behavior;
|
|
195
|
+
equal values are accepted when both are supplied, while conflicting values
|
|
196
|
+
fail fast.
|
|
197
|
+
- `FUZZ_LIVE_FAIL_ON_REVERT=true|false` controls protocol reverts. It defaults
|
|
198
|
+
to `false`; transport errors, timeouts, malformed responses, and ambiguous
|
|
199
|
+
commit outcomes remain fatal. `FUZZ_LIVE_REQUIRE_ARCHIVE=true|false` also
|
|
200
|
+
accepts legacy `1|0` and requires strict reverts for archive smoke mode.
|
|
201
|
+
- `FUZZ_LIVE_ACTION_WEIGHTS=query=30,fetch=20,events=20,exercise=10,probe=20`
|
|
202
|
+
sets non-negative action weights. Exact-depth campaigns always retain a
|
|
203
|
+
no-contract `probe` fallback and a post-archive read action.
|
|
204
|
+
- `FUZZ_LIVE_ACTORS=issuer,owner` selects eligible actors. `issuer` is
|
|
205
|
+
mandatory; omitting `owner` removes owner-targeted generated reads while
|
|
206
|
+
retaining the cross-participant fixture checks.
|
|
207
|
+
- `FUZZ_LIVE_POLL_TIMEOUT_MS`, `FUZZ_LIVE_POLL_INTERVAL_MS`,
|
|
208
|
+
`FUZZ_LIVE_TEST_TIMEOUT_MS`, and `FUZZ_LIVE_CLEANUP_TIMEOUT_MS` control
|
|
209
|
+
polling and timeouts.
|
|
210
|
+
- `FUZZ_LIVE_FAILURE_DIR` defaults to `tests/live/.artifacts/failures`.
|
|
211
|
+
`FUZZ_LIVE_REPLAY_FAILURES=true|false` enables automatic replay of valid
|
|
212
|
+
artifacts in that directory; stale or corrupt automatic artifacts are
|
|
213
|
+
reported and skipped. `FUZZ_LIVE_REPLAY_FILE=/path/to/failure.json` performs
|
|
214
|
+
explicit replay and validates run ID, party IDs, and fingerprints before
|
|
215
|
+
connecting to participants.
|
|
216
|
+
|
|
217
|
+
Artifacts contain allowlisted campaign data only: endpoints, credentials,
|
|
218
|
+
headers, and arbitrary error objects are never serialized. They are written
|
|
219
|
+
with restrictive permissions and no-clobber atomic persistence. For a strict
|
|
220
|
+
four-step smoke run, use:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
SDK_TEST_ENABLE_LIVE_FUZZING=1 \
|
|
224
|
+
FUZZ_NUM_RUNS=1 \
|
|
225
|
+
FUZZ_LIVE_DEPTH=4 \
|
|
226
|
+
FUZZ_LIVE_FAIL_ON_REVERT=true \
|
|
227
|
+
FUZZ_LIVE_REQUIRE_ARCHIVE=1 \
|
|
228
|
+
FUZZ_LIVE_FAILURE_DIR=tests/live/.artifacts/smoke \
|
|
229
|
+
npm run test:live:fuzz
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
This fixture assumes the CN quickstart already has the `Main:Iou` package on
|
|
233
|
+
both participants. The ledger-only DAML Ops localnet launcher is not a
|
|
234
|
+
substitute: open ports are insufficient without the quickstart Ledger API,
|
|
235
|
+
package, party, and cross-participant visibility checks.
|
|
236
|
+
|
|
64
237
|
Experimental multi-host external-party coverage is opt-in:
|
|
65
238
|
|
|
66
239
|
- set `SDK_TEST_ENABLE_MULTI_HOST_EXTERNAL_PARTY=1` to enable the multi-host live spec
|
|
@@ -135,8 +308,128 @@ For gRPC, channel security resolves per surface:
|
|
|
135
308
|
- ledger admin services use `ledgerAdminGrpcChannelSecurity ?? grpcChannelSecurity ?? GrpcChannelSecurity.tls`
|
|
136
309
|
- participant admin services use `participantAdminGrpcChannelSecurity ?? grpcChannelSecurity ?? GrpcChannelSecurity.tls`
|
|
137
310
|
|
|
311
|
+
### gRPC error handling
|
|
312
|
+
|
|
313
|
+
gRPC failures reject with `GrpcTransportError`, a `TransportError` subclass
|
|
314
|
+
with the gRPC status code, service/method, copied metadata, and decoded
|
|
315
|
+
`google.rpc.Status` trailer when Canton provides one. Use `onGrpcError` for
|
|
316
|
+
centralized logging or telemetry; it observes the error but cannot replace the
|
|
317
|
+
rejection if the callback itself fails.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
import { GrpcTransportError } from "@distrohelena/canton-typescript-sdk";
|
|
321
|
+
|
|
322
|
+
const client = new CantonClient(new CantonClientOptions({
|
|
323
|
+
// existing gRPC connection options,
|
|
324
|
+
onGrpcError: (error) => {
|
|
325
|
+
logger.error({ code: error.grpcCode, status: error.status });
|
|
326
|
+
},
|
|
327
|
+
}));
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
await client.userManagementService.listUsersAsync(/* request */);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
if (error instanceof GrpcTransportError) {
|
|
333
|
+
console.error(error.grpcCode, error.serviceName, error.methodName);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Application-specific `google.protobuf.Any` values in `error.status.details`
|
|
339
|
+
remain opaque (`typeUrl` and bytes) unless the application knows that type.
|
|
340
|
+
|
|
341
|
+
### External party lifecycle
|
|
342
|
+
|
|
343
|
+
For an externally controlled party, provide the public key and a callback that
|
|
344
|
+
delegates signing to your HSM, KMS, wallet, or other key service. The SDK
|
|
345
|
+
generates the Canton topology, requests signatures for each topology
|
|
346
|
+
transaction and its multihash, then allocates the party. It never receives a
|
|
347
|
+
private key.
|
|
348
|
+
|
|
349
|
+
```ts
|
|
350
|
+
import {
|
|
351
|
+
CreateExternalPartyRequest,
|
|
352
|
+
ExternalPartyCryptoKeyFormat,
|
|
353
|
+
ExternalPartySignatureFormat,
|
|
354
|
+
ExternalPartySigningAlgorithmSpec,
|
|
355
|
+
ExternalPartySigningKeySpec,
|
|
356
|
+
ExternalPartySigningPublicKey,
|
|
357
|
+
} from "@distrohelena/canton-typescript-sdk";
|
|
358
|
+
|
|
359
|
+
const party = await client.partyManagementService.createExternalPartyAsync(
|
|
360
|
+
new CreateExternalPartyRequest({
|
|
361
|
+
synchronizer: "sync::sandbox",
|
|
362
|
+
partyHint: "alice",
|
|
363
|
+
publicKey: new ExternalPartySigningPublicKey({
|
|
364
|
+
format: ExternalPartyCryptoKeyFormat.raw,
|
|
365
|
+
keyData: ed25519PublicKeyBytes,
|
|
366
|
+
keySpec: ExternalPartySigningKeySpec.ecCurve25519,
|
|
367
|
+
}),
|
|
368
|
+
sign: async ({ payload }) => ({
|
|
369
|
+
signature: await keyService.sign(payload),
|
|
370
|
+
format: ExternalPartySignatureFormat.raw,
|
|
371
|
+
signingAlgorithmSpec: ExternalPartySigningAlgorithmSpec.ed25519,
|
|
372
|
+
}),
|
|
373
|
+
}),
|
|
374
|
+
);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Use the same flow for secp256k1 by supplying
|
|
378
|
+
`ExternalPartySigningKeySpec.ecSecp256k1` and the signer’s compatible Canton
|
|
379
|
+
signature format and algorithm. This convenience operation is gRPC-only.
|
|
380
|
+
|
|
138
381
|
## Service Map
|
|
139
382
|
|
|
383
|
+
## Canton Manager queries
|
|
384
|
+
|
|
385
|
+
`CantonManager` keeps gRPC as the write path and selects a single query source
|
|
386
|
+
at initialization. PQS exposes the complete PQS relation surface; gRPC exposes
|
|
387
|
+
an all-hosted-party active-contract snapshot.
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
import {
|
|
391
|
+
CantonManager,
|
|
392
|
+
MemoryQueryCache,
|
|
393
|
+
QuerySource,
|
|
394
|
+
TransportKind,
|
|
395
|
+
} from "@distrohelena/canton-typescript-sdk";
|
|
396
|
+
|
|
397
|
+
const manager = new CantonManager({
|
|
398
|
+
grpc: { transportKind: TransportKind.grpc, ledgerEndpoint: "localhost:6865" },
|
|
399
|
+
querySource: QuerySource.pqs,
|
|
400
|
+
pqs: { connectionString: process.env.PQS_URL!, schema: "public" },
|
|
401
|
+
cache: { store: new MemoryQueryCache(), ttlMs: 5_000 },
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const contracts = await manager.query.contracts.findMany({
|
|
405
|
+
where: { templateId: { equals: "packageId:Module:Template" }, active: true },
|
|
406
|
+
take: 50,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
await manager.grpc.commandService.submitAndWaitAsync(/* existing command request */);
|
|
410
|
+
await manager.disposeAsync();
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
With `QuerySource.grpc`, omit `pqs`; contract queries fetch the participant's
|
|
414
|
+
active-contract snapshot using the Ledger API wildcard for all hosted parties.
|
|
415
|
+
PQS-only relation delegates and raw SQL then reject with `QueryCapabilityError`.
|
|
416
|
+
|
|
417
|
+
PQS managers expose `contracts`, `contractTypes`, `events`, `exercises`,
|
|
418
|
+
`exerciseTypes`, `packages`, `transactions`, and `watermark`. Raw SQL is
|
|
419
|
+
available through `manager.query.$queryRaw(...)` when the selected client is
|
|
420
|
+
PQS-specific. It accepts one read-only statement with positional parameters;
|
|
421
|
+
use a read-only PostgreSQL role as defense in depth.
|
|
422
|
+
|
|
423
|
+
The PQS relation delegates use a Prisma-like surface: `findMany({ where,
|
|
424
|
+
select, orderBy, skip, take })`, `findUnique({ where, select })`, `count`, and
|
|
425
|
+
`aggregate({ count, min, max, sum })`. Filters support `equals`, `in`,
|
|
426
|
+
`{ is: null }`, `{ isNot: null }`, and `{ has: party }` on array fields.
|
|
427
|
+
Ordering accepts one field. `exercises` intentionally has no `findUnique`
|
|
428
|
+
because the v1 PQS profile does not declare a stable key. The manager validates
|
|
429
|
+
the selected PQS schema profile before its first query. In gRPC mode, only the
|
|
430
|
+
active-contract `findMany`, `findUnique`, and `count` subset is available;
|
|
431
|
+
unsupported query features reject with `QueryCapabilityError`.
|
|
432
|
+
|
|
140
433
|
- Ledger endpoint:
|
|
141
434
|
- `versionService.getLedgerApiVersionAsync(...)`: `json`, `grpc`
|
|
142
435
|
- `healthService.checkAsync(...)`: `grpc` only
|
|
@@ -160,6 +453,7 @@ For gRPC, channel security resolves per surface:
|
|
|
160
453
|
- `partyManagementService.getPartiesAsync(...)`: `grpc` only
|
|
161
454
|
- `partyManagementService.generateExternalPartyTopologyAsync(...)`: `grpc` only
|
|
162
455
|
- `partyManagementService.allocateExternalPartyAsync(...)`: `grpc` only
|
|
456
|
+
- `partyManagementService.createExternalPartyAsync(...)`: `grpc` only
|
|
163
457
|
- `userManagementService.grantUserRightsAsync(...)`: `json`, `grpc`
|
|
164
458
|
- `packageManagementService.uploadDarFileAsync(...)`: `json`, `grpc`
|
|
165
459
|
|
|
@@ -189,6 +483,7 @@ Subpath exports are available when you want to construct directly over a transpo
|
|
|
189
483
|
- `@distrohelena/canton-typescript-sdk/grpc`
|
|
190
484
|
- `@distrohelena/canton-typescript-sdk/json`
|
|
191
485
|
- `@distrohelena/canton-typescript-sdk/daml-lf`
|
|
486
|
+
- `@distrohelena/canton-typescript-sdk/debugger`
|
|
192
487
|
- `@distrohelena/canton-typescript-sdk/daml-interface`
|
|
193
488
|
|
|
194
489
|
`GrpcLedgerClient` and `JsonLedgerClient` expose the same service properties as `CantonClient`.
|
|
@@ -208,7 +503,8 @@ Current scope:
|
|
|
208
503
|
- immutable package/module/definition model
|
|
209
504
|
- workspace, compilation, and symbol resolution
|
|
210
505
|
- semantic queries over the compiled model
|
|
211
|
-
-
|
|
506
|
+
- evaluator core and trace-sink contracts
|
|
507
|
+
- replay-effect tracing for debugger-owned sessions
|
|
212
508
|
|
|
213
509
|
Example:
|
|
214
510
|
|
|
@@ -230,6 +526,42 @@ const compilation = DamlLfCompilation.createOrThrow(workspace);
|
|
|
230
526
|
const semanticModel = compilation.createSemanticModel();
|
|
231
527
|
```
|
|
232
528
|
|
|
529
|
+
## Replay Debugger
|
|
530
|
+
|
|
531
|
+
The package also exposes an experimental replay debugger at `@distrohelena/canton-typescript-sdk/debugger`.
|
|
532
|
+
|
|
533
|
+
Current scope:
|
|
534
|
+
|
|
535
|
+
- load a replay session from a committed update offset
|
|
536
|
+
- hydrate referenced contracts through the gRPC contract and event-query services
|
|
537
|
+
- precompute a stepwise LF trace and expose stepping/session APIs
|
|
538
|
+
- replay LF update bodies for the supported evaluator subset, including nested exercise-driven effects
|
|
539
|
+
- validate replay determinism against the observed update payload
|
|
540
|
+
|
|
541
|
+
Current limits:
|
|
542
|
+
|
|
543
|
+
- replay depends on gRPC-visible create/exercise payloads
|
|
544
|
+
- source-aware replay expects DAR provenance with debugger source-map metadata
|
|
545
|
+
- unsupported LF constructs still fail fast with `ReplayUnsupportedLfConstructException`
|
|
546
|
+
- source locations currently map to executable definition spans from the DAR source map
|
|
547
|
+
|
|
548
|
+
Example:
|
|
549
|
+
|
|
550
|
+
```ts
|
|
551
|
+
import {
|
|
552
|
+
LedgerReplayDebuggerClient,
|
|
553
|
+
ReplaySessionRequest,
|
|
554
|
+
} from "@distrohelena/canton-typescript-sdk/debugger";
|
|
555
|
+
|
|
556
|
+
const debuggerClient = new LedgerReplayDebuggerClient({
|
|
557
|
+
sessionLoader,
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
const session = await debuggerClient.loadSessionAsync(
|
|
561
|
+
new ReplaySessionRequest({ offset: "42" }),
|
|
562
|
+
);
|
|
563
|
+
```
|
|
564
|
+
|
|
233
565
|
## DAML Interface Generator
|
|
234
566
|
|
|
235
567
|
The `@distrohelena/canton-typescript-sdk/daml-interface` subpath exposes a generator that turns compiled `DAR` or `DALF` artifacts into an in-memory TypeScript binding project.
|
|
@@ -2,6 +2,7 @@ import { TransportKind } from "../core/types/transport-kind.js";
|
|
|
2
2
|
import { GrpcChannelSecurity } from "../core/types/grpc-channel-security.js";
|
|
3
3
|
import { IAuthProvider } from "../core/auth/auth-provider.interface.js";
|
|
4
4
|
import { ICommandSigner } from "../core/signing/command-signer.interface.js";
|
|
5
|
+
import type { GrpcTransportError } from "../core/errors/grpc-transport-error.js";
|
|
5
6
|
export declare class CantonClientOptions {
|
|
6
7
|
readonly transportKind: TransportKind;
|
|
7
8
|
readonly ledgerEndpoint?: string;
|
|
@@ -17,6 +18,7 @@ export declare class CantonClientOptions {
|
|
|
17
18
|
readonly ledgerAdminAuthProvider?: IAuthProvider;
|
|
18
19
|
readonly participantAdminAuthProvider?: IAuthProvider;
|
|
19
20
|
readonly commandSigner?: ICommandSigner;
|
|
21
|
+
readonly onGrpcError?: (error: GrpcTransportError) => void;
|
|
20
22
|
constructor(init: {
|
|
21
23
|
transportKind: TransportKind;
|
|
22
24
|
ledgerEndpoint?: string;
|
|
@@ -32,5 +34,6 @@ export declare class CantonClientOptions {
|
|
|
32
34
|
ledgerAdminAuthProvider?: IAuthProvider;
|
|
33
35
|
participantAdminAuthProvider?: IAuthProvider;
|
|
34
36
|
commandSigner?: ICommandSigner;
|
|
37
|
+
onGrpcError?: (error: GrpcTransportError) => void;
|
|
35
38
|
});
|
|
36
39
|
}
|
|
@@ -14,6 +14,7 @@ export class CantonClientOptions {
|
|
|
14
14
|
ledgerAdminAuthProvider;
|
|
15
15
|
participantAdminAuthProvider;
|
|
16
16
|
commandSigner;
|
|
17
|
+
onGrpcError;
|
|
17
18
|
constructor(init) {
|
|
18
19
|
this.transportKind = init.transportKind;
|
|
19
20
|
this.ledgerEndpoint = init.ledgerEndpoint;
|
|
@@ -33,5 +34,6 @@ export class CantonClientOptions {
|
|
|
33
34
|
this.participantAdminAuthProvider =
|
|
34
35
|
init.participantAdminAuthProvider;
|
|
35
36
|
this.commandSigner = init.commandSigner;
|
|
37
|
+
this.onGrpcError = init.onGrpcError;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
@@ -1119,11 +1119,12 @@ export function createServiceRegistry(options) {
|
|
|
1119
1119
|
ledgerAdminTransport,
|
|
1120
1120
|
participantAdminTransport,
|
|
1121
1121
|
].filter((item) => item !== undefined));
|
|
1122
|
+
const topologyManagerWriteService = new TopologyManagerWriteServiceClient(topologyManagerWriteTransport);
|
|
1122
1123
|
return {
|
|
1123
1124
|
transport,
|
|
1124
1125
|
versionService: new VersionServiceClient(versionTransport),
|
|
1125
1126
|
healthService: new HealthServiceClient(healthTransport),
|
|
1126
|
-
partyManagementService: new PartyManagementServiceClient(partyManagementTransport),
|
|
1127
|
+
partyManagementService: new PartyManagementServiceClient(partyManagementTransport, topologyManagerWriteService),
|
|
1127
1128
|
userManagementService: new UserManagementServiceClient(userManagementTransport),
|
|
1128
1129
|
commandInspectionService: new CommandInspectionServiceClient(commandInspectionTransport),
|
|
1129
1130
|
identityProviderConfigService: new IdentityProviderConfigServiceClient(identityProviderConfigTransport),
|
|
@@ -1139,7 +1140,7 @@ export function createServiceRegistry(options) {
|
|
|
1139
1140
|
identityInitializationService: new IdentityInitializationServiceClient(identityInitializationTransport),
|
|
1140
1141
|
synchronizerConnectivityService: new SynchronizerConnectivityServiceClient(synchronizerConnectivityTransport),
|
|
1141
1142
|
topologyManagerReadService: new TopologyManagerReadServiceClient(topologyManagerReadTransport),
|
|
1142
|
-
topologyManagerWriteService
|
|
1143
|
+
topologyManagerWriteService,
|
|
1143
1144
|
trafficControlService: new TrafficControlServiceClient(trafficControlTransport),
|
|
1144
1145
|
topologyAggregationService: new TopologyAggregationServiceClient(topologyAggregationTransport),
|
|
1145
1146
|
commandService: new CommandServiceClient(commandTransport, options.commandSigner),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Status as GrpcStatusDetails } from "../../transports/grpc/generated/canton/google/rpc/status.js";
|
|
2
|
+
import { TransportError } from "./transport-error.js";
|
|
3
|
+
export type GrpcErrorMetadata = Readonly<Record<string, readonly string[]>>;
|
|
4
|
+
export type { GrpcStatusDetails };
|
|
5
|
+
export declare class GrpcTransportError extends TransportError {
|
|
6
|
+
readonly grpcCode: string;
|
|
7
|
+
readonly serviceName?: string;
|
|
8
|
+
readonly methodName?: string;
|
|
9
|
+
readonly metadata: GrpcErrorMetadata;
|
|
10
|
+
readonly status?: GrpcStatusDetails;
|
|
11
|
+
readonly cause: Error;
|
|
12
|
+
private constructor();
|
|
13
|
+
static fromUnknown(error: unknown): GrpcTransportError | undefined;
|
|
14
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Status } from "../../transports/grpc/generated/canton/google/rpc/status.js";
|
|
2
|
+
import { TransportError } from "./transport-error.js";
|
|
3
|
+
export class GrpcTransportError extends TransportError {
|
|
4
|
+
grpcCode;
|
|
5
|
+
serviceName;
|
|
6
|
+
methodName;
|
|
7
|
+
metadata;
|
|
8
|
+
status;
|
|
9
|
+
cause;
|
|
10
|
+
constructor(message, rawError, metadata, status) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.grpcCode = rawError.code;
|
|
13
|
+
this.serviceName = rawError.serviceName;
|
|
14
|
+
this.methodName = rawError.methodName;
|
|
15
|
+
this.metadata = metadata;
|
|
16
|
+
this.status = status;
|
|
17
|
+
this.cause = rawError;
|
|
18
|
+
}
|
|
19
|
+
static fromUnknown(error) {
|
|
20
|
+
if (!isRpcErrorLike(error)) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const metadata = copyMetadata(error.meta);
|
|
24
|
+
const status = decodeStatusDetails(error.meta);
|
|
25
|
+
return new GrpcTransportError(formatMessage(error), error, metadata, status);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isRpcErrorLike(error) {
|
|
29
|
+
if (!(error instanceof Error) || error.name !== "RpcError") {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const candidate = error;
|
|
33
|
+
return typeof candidate.code === "string";
|
|
34
|
+
}
|
|
35
|
+
function copyMetadata(metadata) {
|
|
36
|
+
const copied = Object.create(null);
|
|
37
|
+
for (const [key, value] of Object.entries(metadata ?? {})) {
|
|
38
|
+
const strings = asArray(value).filter((metadataValue) => typeof metadataValue === "string");
|
|
39
|
+
if (strings.length > 0) {
|
|
40
|
+
copied[key] = Object.freeze([...strings]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return Object.freeze(copied);
|
|
44
|
+
}
|
|
45
|
+
function decodeStatusDetails(metadata) {
|
|
46
|
+
const values = asArray(metadata?.["grpc-status-details-bin"]);
|
|
47
|
+
for (const value of values) {
|
|
48
|
+
const bytes = toBinary(value);
|
|
49
|
+
if (bytes === undefined) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return Status.fromBinary(bytes);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Try another trailer value without masking the original RPC failure.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
function asArray(value) {
|
|
62
|
+
return Array.isArray(value) ? value : value === undefined ? [] : [value];
|
|
63
|
+
}
|
|
64
|
+
function toBinary(value) {
|
|
65
|
+
if (typeof value === "string") {
|
|
66
|
+
return Buffer.from(value, "base64");
|
|
67
|
+
}
|
|
68
|
+
return value instanceof Uint8Array ? value : undefined;
|
|
69
|
+
}
|
|
70
|
+
function formatMessage(error) {
|
|
71
|
+
const operation = [error.serviceName, error.methodName]
|
|
72
|
+
.filter((part) => part !== undefined)
|
|
73
|
+
.join(".");
|
|
74
|
+
const location = operation.length > 0 ? ` from ${operation}` : "";
|
|
75
|
+
return `gRPC ${error.code}${location}: ${error.message}`;
|
|
76
|
+
}
|
|
@@ -2,4 +2,5 @@ export var CantonHashPurpose;
|
|
|
2
2
|
(function (CantonHashPurpose) {
|
|
3
3
|
CantonHashPurpose[CantonHashPurpose["topologyTransactionSignature"] = 11] = "topologyTransactionSignature";
|
|
4
4
|
CantonHashPurpose[CantonHashPurpose["publicKeyFingerprint"] = 12] = "publicKeyFingerprint";
|
|
5
|
+
CantonHashPurpose[CantonHashPurpose["decentralizedNamespace"] = 37] = "decentralizedNamespace";
|
|
5
6
|
})(CantonHashPurpose || (CantonHashPurpose = {}));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ValidationError } from "../errors/validation-error.js";
|
|
2
|
+
/** Exact decimal DAML Numeric value, encoded without floating-point rounding. */
|
|
3
|
+
export class DamlNumeric {
|
|
4
|
+
value;
|
|
5
|
+
constructor(value) {
|
|
6
|
+
if (!/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value)) {
|
|
7
|
+
throw new ValidationError("DAML numeric values must be exact decimal strings");
|
|
8
|
+
}
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
|
+
toJSON() {
|
|
12
|
+
return this.value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ValidationError } from "../errors/validation-error.js";
|
|
2
|
+
/** Explicit DAML Party value for commands whose field type is Party, not Text. */
|
|
3
|
+
export class DamlParty {
|
|
4
|
+
value;
|
|
5
|
+
constructor(value) {
|
|
6
|
+
if (value.length === 0) {
|
|
7
|
+
throw new ValidationError("DAML party values must not be empty");
|
|
8
|
+
}
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
|
+
toJSON() {
|
|
12
|
+
return this.value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ExternalPartySigningPublicKey } from "../external-party/external-party-signing-public-key.js";
|
|
2
|
+
import { ExternalPartySigningRequest, ExternalPartySigningResult } from "./create-external-party-request.js";
|
|
3
|
+
export interface DecentralizedPartyKey {
|
|
4
|
+
readonly publicKey: ExternalPartySigningPublicKey;
|
|
5
|
+
readonly sign?: DecentralizedPartySigner;
|
|
6
|
+
}
|
|
7
|
+
export interface DecentralizedPartySigningRequest extends ExternalPartySigningRequest {
|
|
8
|
+
readonly role: "owner" | "partySigningKey";
|
|
9
|
+
readonly transactionHash: Uint8Array;
|
|
10
|
+
}
|
|
11
|
+
export type DecentralizedPartySigner = (request: DecentralizedPartySigningRequest) => Promise<ExternalPartySigningResult>;
|
|
12
|
+
export declare class CreateDecentralizedPartyRequest {
|
|
13
|
+
readonly synchronizer: string;
|
|
14
|
+
readonly partyHint: string;
|
|
15
|
+
readonly owners: readonly DecentralizedPartyKey[];
|
|
16
|
+
readonly ownerThreshold: number;
|
|
17
|
+
readonly partySigningKeys: readonly DecentralizedPartyKey[];
|
|
18
|
+
readonly partySigningThreshold: number;
|
|
19
|
+
readonly localParticipantObservationOnly: boolean;
|
|
20
|
+
readonly otherConfirmingParticipantUids: readonly string[];
|
|
21
|
+
readonly confirmationThreshold: number;
|
|
22
|
+
readonly observingParticipantUids: readonly string[];
|
|
23
|
+
readonly identityProviderId?: string;
|
|
24
|
+
readonly waitForAllocation?: boolean;
|
|
25
|
+
readonly userId?: string;
|
|
26
|
+
constructor(init: {
|
|
27
|
+
synchronizer?: string;
|
|
28
|
+
partyHint?: string;
|
|
29
|
+
owners?: readonly DecentralizedPartyKey[];
|
|
30
|
+
ownerThreshold?: number;
|
|
31
|
+
partySigningKeys?: readonly DecentralizedPartyKey[];
|
|
32
|
+
partySigningThreshold?: number;
|
|
33
|
+
localParticipantObservationOnly?: boolean;
|
|
34
|
+
otherConfirmingParticipantUids?: readonly string[];
|
|
35
|
+
confirmationThreshold?: number;
|
|
36
|
+
observingParticipantUids?: readonly string[];
|
|
37
|
+
identityProviderId?: string;
|
|
38
|
+
waitForAllocation?: boolean;
|
|
39
|
+
userId?: string;
|
|
40
|
+
});
|
|
41
|
+
}
|