Skip to content
Merged
2 changes: 1 addition & 1 deletion .cursor/skills/localnet-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Read the public [LocalNet guide](https://github.com/Fairmint/canton-node-sdk/wiki/LocalNet-testing)
first.

**ENG-1635:** `@fairmint/canton-dev-tools@0.1.7+` owns LocalNet lifecycle, pins, and shared test
**ENG-1635:** `@fairmint/canton-dev-tools@0.1.11+` owns LocalNet lifecycle, pins, and shared test
helpers. This repository does not ship LocalNet scripts or a `canton-localnet` binary.

- Commands: `npm run localnet:*` (wired to `canton-dev-tools`) or
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
See [CLAUDE.md](CLAUDE.md), [README.md](README.md), and
`.cursor/skills/localnet-testing/SKILL.md`. `package.json` (`localnet:*` scripts) is the source of
truth for LocalNet commands in this repo; lifecycle is owned by
`@fairmint/canton-dev-tools@0.1.7+`.
`@fairmint/canton-dev-tools@0.1.11+`.
Comment thread
HardlyDifficult marked this conversation as resolved.

## LocalNet ownership (ENG-1635)

**`@fairmint/canton-dev-tools` owns LocalNet** (CLI, pins, and shared test helpers). This SDK does
not ship a LocalNet engine or `canton-localnet` binary.

- Install pin: `devDependency` `@fairmint/canton-dev-tools@0.1.7` (exact).
- Install pin: `devDependency` `@fairmint/canton-dev-tools@0.1.11` (exact).
- Repo scripts: `npm run localnet:*` → `canton-dev-tools <command>`.
- Integration helpers: import from `@fairmint/canton-dev-tools/testing`.
- Pins / auth defaults: see Dev Tools
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ npm run build
### LocalNet (owned by `@fairmint/canton-dev-tools`)

LocalNet lifecycle and shared test helpers live in
[`@fairmint/canton-dev-tools@0.1.7`](https://www.npmjs.com/package/@fairmint/canton-dev-tools)
[`@fairmint/canton-dev-tools@0.1.11`](https://www.npmjs.com/package/@fairmint/canton-dev-tools)
(see its [COMPATIBILITY.md](https://github.com/Fairmint/canton-dev-tools/blob/main/COMPATIBILITY.md)).
This SDK does not publish a LocalNet CLI or `scripts/localnet-cloud.sh`.

Expand Down
2 changes: 1 addition & 1 deletion docs/package-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repository / CI-only. Repeatable enforcement lives in `npm run check:package-art

LocalNet CLI and shared integration-test helpers are **not** published here. They live in
[`@fairmint/canton-dev-tools`](https://www.npmjs.com/package/@fairmint/canton-dev-tools)
(`0.1.7+`), including `scripts/localnet-cloud.sh` and `@fairmint/canton-dev-tools/testing`.
(`0.1.11+`), including `scripts/localnet-cloud.sh` and `@fairmint/canton-dev-tools/testing`.

## CI-only / must not publish

Expand Down
9 changes: 9 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@ const eslintConfig = [
'@typescript-eslint/no-redundant-type-constituents': 'off',
},
},
// Test-only override: jest mocks are invoked as bare functions and never rely on
// `this`, so unbound-method reports false positives there. Disabled for test files
// only; non-test code keeps full protection, with no per-assertion suppressions.
{
files: ['test/**/*'],
rules: {
'@typescript-eslint/unbound-method': 'off',
},
},
// Prettier config last to override any conflicting rules
eslintConfigPrettier,
];
Expand Down
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@hardlydifficult/websocket": "1.0.73",
"@stellar/stellar-base": "15.0.0",
"axios": "1.20.0",
"dotenv": "17.4.2",
"dotenv": "18.0.3",
Comment thread
HardlyDifficult marked this conversation as resolved.
"glob": "13.0.6",
"openapi-fetch": "0.17.0",
"openapi-typescript": "7.13.0",
Expand All @@ -75,27 +75,27 @@
"zod": "4.6.5"
},
"devDependencies": {
"@fairmint/canton-dev-tools": "0.1.7",
"@fairmint/canton-dev-tools": "0.1.11",
Comment thread
HardlyDifficult marked this conversation as resolved.
"@types/jest": "30.0.0",
"@types/node": "26.1.2",
"@types/node": "26.6.2",
"@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.62.1",
"@typescript-eslint/parser": "8.62.1",
"@typescript-eslint/eslint-plugin": "8.70.1",
"@typescript-eslint/parser": "8.70.1",
"eslint": "9.39.2",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-typescript": "4.4.5",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-markdown": "5.1.0",
"eslint-plugin-unused-imports": "4.4.1",
"jest": "30.4.2",
"jest": "30.5.2",
"markdownlint-cli": "0.49.1",
"npm-package-json-lint": "10.4.1",
"prettier": "3.9.6",
"npm-package-json-lint": "11.0.0",
"prettier": "3.9.8",
"prettier-plugin-jsdoc": "1.8.1",
"prettier-plugin-organize-imports": "4.3.0",
"prettier-plugin-packagejson": "3.0.2",
"ts-jest": "29.4.12",
"tsx": "4.23.7",
"tsx": "4.23.15",
"typescript": "5.9.3",
"typescript-7": "npm:typescript@7.0.2"
},
Expand Down
1 change: 1 addition & 0 deletions src/utils/external-signing/external-party-onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ async function readExistingExternalPartyAfterAllocationConflict(
const abortError = new ValidationError('Canton external-party conflict reconciliation was aborted', { partyId });
const createAbortError = (): ValidationError => abortError;
try {
// eslint-disable-next-line @typescript-eslint/promise-function-async -- non-async arrow preserves rejection timing expected by race tests
const partyDetailsResponse = await runWithAbortSignal(signal, createAbortError, () =>
signal === undefined
? ledgerClient.getPartyDetails({
Expand Down
34 changes: 17 additions & 17 deletions test/typecheck/ledger-contract-by-id.typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,20 @@ createdEvent.offset;

void ledgerClient.getContractById(request, exactBodyRetry);
void ledgerClient.getContractById(requestWithoutParties, derivedBodyRetry);
void requestWithUnknownField;
void requestWithUndefinedOptional;
void requestWithPlainString;
void requestWithPartyAsContract;
void requestWithContractAsParty;
void createArgument;
void optionalContractKey;
void responseContractId;
void responseWitness;
void responseTemplateId;
void responsePackageId;
void responsePackageName;
void responseInterfaceId;
void responseImplementationPackageId;
void unvalidatedTemplateId;
void nullContractKey;
void invalidCreateArgument;
requestWithUnknownField;
requestWithUndefinedOptional;
requestWithPlainString;
requestWithPartyAsContract;
requestWithContractAsParty;
createArgument;
optionalContractKey;
responseContractId;
responseWitness;
responseTemplateId;
responsePackageId;
responsePackageName;
responseInterfaceId;
responseImplementationPackageId;
unvalidatedTemplateId;
nullContractKey;
invalidCreateArgument;
2 changes: 1 addition & 1 deletion test/typecheck/ledger-dars.typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ void client.validateDar({ darFile: Buffer.from('dar'), synchronizerId: 'sync::on

// @ts-expect-error Successful DAR upload responses cannot expose arbitrary properties.
const invalidResponse: UploadDarResponse = { packageId: 'unexpected' };
void invalidResponse;
invalidResponse;
142 changes: 71 additions & 71 deletions test/typecheck/ledger-interactive-submission.typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,14 @@ const prepareResponse: PrepareResponse = {
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V3',
};

void executeAndWaitForTransactionRequest;
void invalidHelperHashingScheme;
void unspecifiedTransactionShape;
void executeAndWaitResponse;
void prepareRequest;
void unspecifiedPrepareHashingScheme;
void unspecifiedCostHintSigningAlgorithm;
void prepareResponse;
executeAndWaitForTransactionRequest;
invalidHelperHashingScheme;
unspecifiedTransactionShape;
executeAndWaitResponse;
prepareRequest;
unspecifiedPrepareHashingScheme;
unspecifiedCostHintSigningAlgorithm;
prepareResponse;

const invalidOffsetRequest: ExecuteAndWaitRequest = {
...executeAndWaitRequest,
Expand Down Expand Up @@ -256,11 +256,11 @@ const invalidExerciseChoiceArgument: ExercisedTransactionEvent['choiceArgument']
// @ts-expect-error Exercise results are JSON values when present.
const invalidExerciseResult: ExercisedTransactionEvent['exerciseResult'] = Symbol('invalid');

void normalizedTraceContext;
void normalizedTraceState;
void nullTraceState;
void rawExternalHashString;
void unvalidatedExternalHash;
normalizedTraceContext;
normalizedTraceState;
nullTraceState;
rawExternalHashString;
unvalidatedExternalHash;

type PrepareCommand = PrepareRequest['commands'][number];
type CreateArguments = Extract<PrepareCommand, { CreateCommand: unknown }>['CreateCommand']['createArguments'];
Expand Down Expand Up @@ -329,43 +329,43 @@ const invalidMultiBranchEvent: InteractiveSubmissionEvent = {
CreatedEvent: createdEvent,
};

void invalidOffsetRequest;
void invalidHashingSchemeRequest;
void unspecifiedHashingSchemeRequest;
void decodedProtoAny;
void invalidDecodedProtoAny;
void invalidSignatureFormat;
void unspecifiedSignatureFormat;
void invalidSigningAlgorithm;
void unspecifiedSigningAlgorithm;
void emptyTransactionEvents;
void nullContractKey;
void nullInterfaceViewValue;
void createdEventArgument;
void exerciseChoiceArgument;
void exerciseResult;
void invalidCreatedEventArgument;
void invalidExerciseChoiceArgument;
void invalidExerciseResult;
void createArguments;
void exerciseArguments;
void createAndExerciseCreateArguments;
void createAndExerciseChoiceArguments;
void exerciseByKeyContractKey;
void exerciseByKeyChoiceArgument;
void prefetchContractKey;
void invalidCreateArguments;
void invalidExerciseArguments;
void invalidCreateAndExerciseCreateArguments;
void invalidCreateAndExerciseChoiceArguments;
void invalidExerciseByKeyContractKey;
void invalidExerciseByKeyChoiceArgument;
void invalidPrefetchContractKey;
void invalidMultiBranchCommand;
void invalidMultiBranchDeduplication;
void invalidMultiBranchTime;
void invalidMultiBranchIdentifierFilter;
void invalidMultiBranchEvent;
invalidOffsetRequest;
invalidHashingSchemeRequest;
unspecifiedHashingSchemeRequest;
decodedProtoAny;
invalidDecodedProtoAny;
invalidSignatureFormat;
unspecifiedSignatureFormat;
invalidSigningAlgorithm;
unspecifiedSigningAlgorithm;
emptyTransactionEvents;
nullContractKey;
nullInterfaceViewValue;
createdEventArgument;
exerciseChoiceArgument;
exerciseResult;
invalidCreatedEventArgument;
invalidExerciseChoiceArgument;
invalidExerciseResult;
createArguments;
exerciseArguments;
createAndExerciseCreateArguments;
createAndExerciseChoiceArguments;
exerciseByKeyContractKey;
exerciseByKeyChoiceArgument;
prefetchContractKey;
invalidCreateArguments;
invalidExerciseArguments;
invalidCreateAndExerciseCreateArguments;
invalidCreateAndExerciseChoiceArguments;
invalidExerciseByKeyContractKey;
invalidExerciseByKeyChoiceArgument;
invalidPrefetchContractKey;
invalidMultiBranchCommand;
invalidMultiBranchDeduplication;
invalidMultiBranchTime;
invalidMultiBranchIdentifierFilter;
invalidMultiBranchEvent;

const invalidPackagePreference: PrepareRequest = {
...prepareRequest,
Expand All @@ -381,8 +381,8 @@ const incompletePrepareResponse: PrepareResponse = {
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V3',
};

void invalidPackagePreference;
void incompletePrepareResponse;
invalidPackagePreference;
incompletePrepareResponse;

type Assert<Condition extends true> = Condition;
type IsRequired<Container, Key extends keyof Container> = {} extends Pick<Container, Key> ? false : true;
Expand Down Expand Up @@ -510,18 +510,18 @@ const absentPreferredPackage: PreferredPackageVersionResponse = {};
// @ts-expect-error Public responses normalize wire null into an absent optional property.
const wireNullPreferredPackage: PreferredPackageVersionResponse = { packagePreference: null };

void multipleRawPrepareCommands;
void multiplePrepareCommands;
multipleRawPrepareCommands;
multiplePrepareCommands;
void ledgerClient.interactiveSubmissionGetPreferredPackageVersion(
preferredPackageVersionRequest,
preferredPackageVersionOptions
);
void ledgerClient.interactiveSubmissionGetPreferredPackages(preferredPackagesRequest, preferredPackagesOptions);
void preferredPackagesRequest;
void preferredPackageVersionRequest;
void preferredPackagesResponse;
void absentPreferredPackage;
void wireNullPreferredPackage;
preferredPackagesRequest;
preferredPackageVersionRequest;
preferredPackagesResponse;
absentPreferredPackage;
wireNullPreferredPackage;

// @ts-expect-error Every derived traffic-cost estimate includes its server estimation timestamp.
const trafficEstimateWithoutTimestamp: TrafficCostEstimate = {
Expand All @@ -533,15 +533,15 @@ const trafficEstimateWithoutTimestamp: TrafficCostEstimate = {
costInDollars: 0.01,
};

void emptyPartySignatures;
void partyWithoutSignatures;
void emptyRawPartySignatureGroups;
void emptyRawSignatures;
void emptyRawPrepareCommands;
void emptyRawActAs;
void emptyPrepareCommands;
void emptyActAsParties;
void trafficEstimateWithoutTimestamp;
void invalidExecuteExactBodyOptions;
void invalidExecuteAndWaitExactBodyOptions;
void invalidExecuteAndWaitForTransactionExactBodyOptions;
emptyPartySignatures;
partyWithoutSignatures;
emptyRawPartySignatureGroups;
emptyRawSignatures;
emptyRawPrepareCommands;
emptyRawActAs;
emptyPrepareCommands;
emptyActAsParties;
trafficEstimateWithoutTimestamp;
invalidExecuteExactBodyOptions;
invalidExecuteAndWaitExactBodyOptions;
invalidExecuteAndWaitForTransactionExactBodyOptions;
14 changes: 7 additions & 7 deletions test/typecheck/operation-retry.typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const invalidTuplePayload: DeepReadonly<NonEmptyTuplePayload> = {
// @ts-expect-error DeepReadonly must preserve non-empty tuple constraints.
values: [],
};
void validTuplePayload;
void invalidTuplePayload;
validTuplePayload;
invalidTuplePayload;
void parameterizedRequestCallback('value', 5);

void client.allocateExternalParty(signedRequest, {
Expand All @@ -52,7 +52,7 @@ void client.allocateExternalParty(signedRequest, {
const [transaction] = params.onboardingTransactions;
if (transaction && 'signatures' in transaction) {
const signature: string = transaction.signatures[0]?.signature ?? '';
void signature;
signature;
}
return signedRequest;
},
Expand All @@ -78,7 +78,7 @@ void client.allocateExternalParty(requestWithCallerOnlyMetadata, {
maxAttempts: 1,
beforeAttempt: ({ params }) => {
// @ts-expect-error Retry hooks expose validated declared params, not caller-only structural extensions.
void params.callerOnlyMetadata;
params.callerOnlyMetadata;
},
},
});
Expand Down Expand Up @@ -130,7 +130,7 @@ const invalidGetOperationConfig = {
requestSemantics: 'mutation',
// @ts-expect-error Factory-created GET operations cannot use mutation semantics.
} satisfies ApiOperationConfig<void, unknown>;
void invalidGetOperationConfig;
invalidGetOperationConfig;

const invalidDeleteOperationConfig = {
paramsSchema: z.void(),
Expand All @@ -139,7 +139,7 @@ const invalidDeleteOperationConfig = {
requestSemantics: 'read',
// @ts-expect-error Factory-created DELETE operations cannot use read semantics.
} satisfies ApiOperationConfig<void, unknown>;
void invalidDeleteOperationConfig;
invalidDeleteOperationConfig;

const invalidPatchOperationConfig = {
paramsSchema: z.void(),
Expand All @@ -148,7 +148,7 @@ const invalidPatchOperationConfig = {
requestSemantics: 'read',
// @ts-expect-error Factory-created PATCH operations cannot use read semantics.
} satisfies ApiOperationConfig<void, unknown>;
void invalidPatchOperationConfig;
invalidPatchOperationConfig;

// Custom ApiOperation subclasses retain their declared params while forwarding the same typed options.
void client.getParties({}, { signal: new AbortController().signal });
Expand Down
Loading
Loading