@distrohelena/canton-typescript-sdk 0.1.43 → 0.1.45
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/dist/cjs/query/grpc/grpc-contract-cache.js +10 -3
- package/dist/cjs/query/grpc/grpc-query-client.js +135 -33
- package/dist/cjs/query/grpc/grpc-query-snapshot-reader.js +58 -23
- package/dist/cjs/query/grpc/grpc-relation-mapper.js +92 -34
- package/dist/cjs/transports/grpc/mappers/contracts-mapper.js +11 -0
- package/dist/query/grpc/grpc-contract-cache.js +10 -3
- package/dist/query/grpc/grpc-query-client.d.ts +6 -0
- package/dist/query/grpc/grpc-query-client.js +136 -34
- package/dist/query/grpc/grpc-query-snapshot-reader.d.ts +12 -1
- package/dist/query/grpc/grpc-query-snapshot-reader.js +58 -23
- package/dist/query/grpc/grpc-relation-mapper.d.ts +18 -2
- package/dist/query/grpc/grpc-relation-mapper.js +91 -34
- package/dist/transports/grpc/mappers/contracts-mapper.d.ts +7 -0
- package/dist/transports/grpc/mappers/contracts-mapper.js +11 -0
- package/package.json +1 -1
|
@@ -242,40 +242,92 @@ export function referencedGrpcPackageIds(fragment) {
|
|
|
242
242
|
* Derives contractType metadata straight from already-fetched created-contract events instead of the
|
|
243
243
|
* Package Service. Only valid where the caller has confirmed the query's relation closure is a subset of
|
|
244
244
|
* {contracts, contractTypes} — every contract's own creation event already carries packageName directly,
|
|
245
|
-
* so no archive decode is needed. "version" is a placeholder: this path is unreachable from
|
|
246
|
-
* can see the "packages" relation, so it is never observed.
|
|
245
|
+
* so no archive decode is needed. "version" is a per-package placeholder: this path is unreachable from
|
|
246
|
+
* any query that can see the "packages" relation, so it is never observed.
|
|
247
247
|
*/
|
|
248
248
|
export function contractTypeMetadataFromCreations(creationIdentities) {
|
|
249
249
|
const packages = new Map();
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
250
|
+
addDerivedCreationEntries(packages, creationIdentities);
|
|
251
|
+
return finalizeDerivedPackages(packages);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Extends the creations-only derivation to exercises: for a direct exercise the choice owner IS the
|
|
255
|
+
* exercised template, so the event's own packageName names the owner's package and choice/consuming come
|
|
256
|
+
* straight off the event. Returns undefined when the window contains an interface-exercised choice — its
|
|
257
|
+
* owner is the interface, whose package name the event does not carry, so only the decoded archive can
|
|
258
|
+
* produce its canonical choiceFqn. Unobserved choices are simply absent, which is complete for query plans
|
|
259
|
+
* that reach exerciseTypes only through observed exercises (never for exerciseTypes catalog queries).
|
|
260
|
+
*/
|
|
261
|
+
export function packageMetadataFromEvents(fragment) {
|
|
262
|
+
if (fragment.typeIdentities.some((identity) => identity.choice !== undefined && identity.packageName === undefined)) {
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
const packages = new Map();
|
|
266
|
+
addDerivedCreationEntries(packages, fragment.creationIdentities);
|
|
267
|
+
for (const identity of fragment.typeIdentities) {
|
|
268
|
+
if (identity.packageName === undefined) {
|
|
269
|
+
throw new ValidationError("gRPC query contract type identity is missing its package name");
|
|
270
|
+
}
|
|
271
|
+
const template = derivedTemplateFor(derivedPackageFor(packages, identity.packageId, identity.packageName), identity.templateId.moduleName, identity.templateId.entityName);
|
|
272
|
+
if (identity.choice !== undefined) {
|
|
273
|
+
const consuming = template.choices.get(identity.choice);
|
|
274
|
+
if (consuming !== undefined && consuming !== identity.consuming) {
|
|
275
|
+
throw new ValidationError(`gRPC query choice ${identity.choice} reports conflicting consuming flags`);
|
|
276
|
+
}
|
|
277
|
+
template.choices.set(identity.choice, identity.consuming === true);
|
|
272
278
|
}
|
|
273
279
|
}
|
|
280
|
+
return finalizeDerivedPackages(packages);
|
|
281
|
+
}
|
|
282
|
+
function addDerivedCreationEntries(packages, creationIdentities) {
|
|
283
|
+
for (const creation of creationIdentities) {
|
|
284
|
+
derivedTemplateFor(derivedPackageFor(packages, creation.representativePackageId ?? creation.creationPackageId, creation.packageName), creation.templateId.moduleName, creation.templateId.entityName);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function derivedPackageFor(packages, packageId, packageName) {
|
|
288
|
+
const existing = packages.get(packageId);
|
|
289
|
+
if (existing === undefined) {
|
|
290
|
+
const created = { name: packageName, templates: new Map() };
|
|
291
|
+
packages.set(packageId, created);
|
|
292
|
+
return created;
|
|
293
|
+
}
|
|
294
|
+
else if (existing.name !== packageName) {
|
|
295
|
+
throw new ValidationError(`gRPC query package ${packageId} reports conflicting package names`);
|
|
296
|
+
}
|
|
297
|
+
return existing;
|
|
298
|
+
}
|
|
299
|
+
function derivedTemplateFor(pkg, moduleName, entityName) {
|
|
300
|
+
const identity = `${moduleName} ${entityName}`;
|
|
301
|
+
let template = pkg.templates.get(identity);
|
|
302
|
+
if (template === undefined) {
|
|
303
|
+
template = { moduleName, entityName, choices: new Map() };
|
|
304
|
+
pkg.templates.set(identity, template);
|
|
305
|
+
}
|
|
306
|
+
return template;
|
|
307
|
+
}
|
|
308
|
+
function finalizeDerivedPackages(packages) {
|
|
274
309
|
return Object.freeze([...packages.entries()].map(([id, pkg]) => Object.freeze({
|
|
275
310
|
id,
|
|
276
311
|
name: pkg.name,
|
|
277
|
-
|
|
278
|
-
|
|
312
|
+
// Unique per package: two versions of the same package name can both appear in one window, and
|
|
313
|
+
// duplicate name+version pairs are rejected during dataset normalization.
|
|
314
|
+
version: `unresolved-${id}`,
|
|
315
|
+
templates: Object.freeze([...pkg.templates.values()].map((template) => {
|
|
316
|
+
const templateFqn = `${pkg.name}:${template.moduleName}:${template.entityName}`;
|
|
317
|
+
return Object.freeze({
|
|
318
|
+
moduleName: template.moduleName,
|
|
319
|
+
entityName: template.entityName,
|
|
320
|
+
payloadType: "template",
|
|
321
|
+
aliases: Object.freeze([templateFqn, `${template.moduleName}:${template.entityName}`, template.entityName]),
|
|
322
|
+
templateFqn,
|
|
323
|
+
choices: Object.freeze([...template.choices.entries()].map(([choice, consuming]) => Object.freeze({
|
|
324
|
+
choice,
|
|
325
|
+
consuming,
|
|
326
|
+
aliases: Object.freeze([`${templateFqn}:${choice}`, `${template.moduleName}:${template.entityName}:${choice}`, `${template.entityName}:${choice}`, choice]),
|
|
327
|
+
choiceFqn: `${templateFqn}:${choice}`,
|
|
328
|
+
})).sort((left, right) => left.choice.localeCompare(right.choice))),
|
|
329
|
+
});
|
|
330
|
+
})),
|
|
279
331
|
})));
|
|
280
332
|
}
|
|
281
333
|
function compareTemplateMetadata(left, right) {
|
|
@@ -298,7 +350,6 @@ function normalizeGrpcPackageMetadataUnsafe(packages) {
|
|
|
298
350
|
}
|
|
299
351
|
const packageValues = Array.from(packages);
|
|
300
352
|
const packageIds = new Set();
|
|
301
|
-
const packageNameVersions = new Set();
|
|
302
353
|
const normalized = [];
|
|
303
354
|
for (const pkg of packageValues) {
|
|
304
355
|
if (pkg === null || typeof pkg !== "object") {
|
|
@@ -313,11 +364,10 @@ function normalizeGrpcPackageMetadataUnsafe(packages) {
|
|
|
313
364
|
throw new ValidationError(`gRPC query has duplicate package metadata ${packageId}`);
|
|
314
365
|
}
|
|
315
366
|
packageIds.add(packageId);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
packageNameVersions.add(nameVersion);
|
|
367
|
+
// Same name+version under two different ids is NOT rejected: package ids are content-addressed, so a
|
|
368
|
+
// recompiled or re-uploaded DAR legitimately reappears with a new id and an unchanged manifest. The
|
|
369
|
+
// name-derived canonical rows go through deduplicateCanonicalRows, which throws on any genuine
|
|
370
|
+
// metadata conflict for one canonical key — the only conflict that would actually matter.
|
|
321
371
|
const templatesValue = value.templates;
|
|
322
372
|
if (!Array.isArray(templatesValue)) {
|
|
323
373
|
throw new ValidationError(`gRPC query package ${packageId} templates are invalid`);
|
|
@@ -563,12 +613,19 @@ function identitiesFor(event) {
|
|
|
563
613
|
}
|
|
564
614
|
function typeIdentityRows(event, registry) {
|
|
565
615
|
const template = requiredTemplate(event.templateId, "event template");
|
|
566
|
-
const contract = { pk: registry.get(contractIdentity(template)), templateId: copyTemplate(template), packageId: template.packageId };
|
|
616
|
+
const contract = { pk: registry.get(contractIdentity(template)), templateId: copyTemplate(template), packageId: template.packageId, packageName: event.packageName };
|
|
567
617
|
if (!isExercised(event)) {
|
|
568
618
|
return [contract];
|
|
569
619
|
}
|
|
570
620
|
const owner = exerciseOwner(event);
|
|
571
|
-
return [contract, {
|
|
621
|
+
return [contract, {
|
|
622
|
+
pk: registry.get(exerciseIdentity(owner, event.choice, event.consuming)),
|
|
623
|
+
templateId: copyTemplate(owner),
|
|
624
|
+
packageId: owner.packageId,
|
|
625
|
+
...(event.interfaceId === undefined ? { packageName: event.packageName } : {}),
|
|
626
|
+
choice: event.choice,
|
|
627
|
+
consuming: event.consuming,
|
|
628
|
+
}];
|
|
572
629
|
}
|
|
573
630
|
function activeContractEntries(responses) {
|
|
574
631
|
const entries = responses.map((response) => {
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { QueryContractsResponse } from "../../../core/types/responses/query-contracts-response.js";
|
|
2
2
|
import { GetActiveContractsPageRequest } from "../generated/canton/com/daml/ledger/api/v2/state_service.js";
|
|
3
|
+
/** A fully qualified template reference; packageId is a concrete package id or a "#package-name" reference. */
|
|
4
|
+
export interface GrpcQueryTemplateRef {
|
|
5
|
+
readonly packageId: string;
|
|
6
|
+
readonly moduleName: string;
|
|
7
|
+
readonly entityName: string;
|
|
8
|
+
}
|
|
3
9
|
export declare function mapGrpcQueryContractsRequest(request: {
|
|
4
10
|
party?: string;
|
|
5
11
|
parties?: readonly string[];
|
|
6
12
|
allParties?: boolean;
|
|
7
13
|
templateId?: string;
|
|
14
|
+
templateRefs?: readonly GrpcQueryTemplateRef[];
|
|
8
15
|
interfaceId?: string;
|
|
9
16
|
includeInterfaceView?: boolean;
|
|
10
17
|
includeCreatedEventBlob?: boolean;
|
|
@@ -52,6 +52,17 @@ function createFilters(request) {
|
|
|
52
52
|
},
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
+
for (const ref of request.templateRefs ?? []) {
|
|
56
|
+
cumulative.push({
|
|
57
|
+
identifierFilter: {
|
|
58
|
+
oneofKind: "templateFilter",
|
|
59
|
+
templateFilter: {
|
|
60
|
+
templateId: { packageId: ref.packageId, moduleName: ref.moduleName, entityName: ref.entityName },
|
|
61
|
+
includeCreatedEventBlob,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
55
66
|
if (request.interfaceId) {
|
|
56
67
|
cumulative.push({
|
|
57
68
|
identifierFilter: {
|