@milaboratories/pl-client 3.9.1 → 3.9.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-client",
3
- "version": "3.9.1",
3
+ "version": "3.9.2",
4
4
  "description": "New TS/JS client for Platform API",
5
5
  "files": [
6
6
  "./dist/**/*",
@@ -31,8 +31,8 @@
31
31
  "utility-types": "^3.11.0",
32
32
  "yaml": "^2.8.0",
33
33
  "@milaboratories/pl-http": "1.2.4",
34
- "@milaboratories/pl-model-common": "1.42.0",
35
- "@milaboratories/ts-helpers": "1.8.2"
34
+ "@milaboratories/ts-helpers": "1.8.2",
35
+ "@milaboratories/pl-model-common": "1.42.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@protobuf-ts/plugin": "2.11.1",
@@ -41,9 +41,9 @@
41
41
  "openapi-typescript": "^7.10.0",
42
42
  "typescript": "~5.9.3",
43
43
  "vitest": "^4.1.3",
44
+ "@milaboratories/build-configs": "2.0.0",
44
45
  "@milaboratories/ts-configs": "1.2.3",
45
- "@milaboratories/ts-builder": "1.5.0",
46
- "@milaboratories/build-configs": "2.0.0"
46
+ "@milaboratories/ts-builder": "1.5.0"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=22.19.0"
@@ -341,7 +341,7 @@ export class PlClient {
341
341
 
342
342
  // Auto-set default color proof from the client root's signature.
343
343
  // Skip when backend doesn't implement the `set_default_color` TX request.
344
- if (this.ll.supportsSetDefaultColor && !isNullSignedResourceId(clientRoot) && writable) {
344
+ if (this.ll.supportsResourceSignatures && !isNullSignedResourceId(clientRoot) && writable) {
345
345
  const parsed = parseSignedResourceId(clientRoot);
346
346
  if (parsed.signature) {
347
347
  tx.setDefaultColor(parsed.signature as ColorProof);
@@ -17,6 +17,7 @@ import { plAddressToConfig, type wireProtocol, SUPPORTED_WIRE_PROTOCOLS } from "
17
17
  import type { GrpcOptions } from "@protobuf-ts/grpc-transport";
18
18
  import { GrpcTransport } from "@protobuf-ts/grpc-transport";
19
19
  import { LLPlTransaction } from "./ll_transaction";
20
+ import { setResourceSignaturesRequired } from "./types";
20
21
  import { parsePlJwt } from "../util/pl";
21
22
  import { type Dispatcher, interceptors } from "undici";
22
23
  import type { Middleware } from "openapi-fetch";
@@ -159,6 +160,9 @@ export class LLPlClient implements WireClientProviderFactory {
159
160
  // side-effect in ping(); this fallback covers the path where autodetect is disabled.
160
161
  if (!pl._serverInfo) await pl.ping();
161
162
 
163
+ // Install the process-global signature-strictness flag based on backend version.
164
+ setResourceSignaturesRequired(pl.supportsResourceSignatures);
165
+
162
166
  // Guarantee authMethods happened so client can make weighted decision on which auth method to use.
163
167
  if (!pl._authMethodsSync) await pl.authMethods();
164
168
 
@@ -679,8 +683,10 @@ export class LLPlClient implements WireClientProviderFactory {
679
683
  return hasCapability(this.serverInfo.capabilities, capability);
680
684
  }
681
685
 
682
- /** True if the backend implements the setDefaultColor TX request. */
683
- public get supportsSetDefaultColor(): boolean {
686
+ /** True if the backend produces signed resource ids (and accepts the
687
+ * setDefaultColor TX request). Tagged at 3.3.0 — backends older than this
688
+ * return resources without signatures and reject color-proof requests. */
689
+ public get supportsResourceSignatures(): boolean {
684
690
  return isVersionAtLeast(this.serverInfo.coreVersion, [3, 3, 0]);
685
691
  }
686
692
 
@@ -115,7 +115,7 @@ test("check timeout error type (active)", async () => {
115
115
 
116
116
  // Set default color so resource creation succeeds in strict mode.
117
117
  // Skip on older backends that don't implement the setDefaultColor TX request.
118
- if (client.supportsSetDefaultColor) {
118
+ if (client.supportsResourceSignatures) {
119
119
  await tx.send(
120
120
  { oneofKind: "setDefaultColor", setDefaultColor: { colorProof: rootSig } },
121
121
  false,
@@ -189,7 +189,7 @@ test("check is abort error (active)", async () => {
189
189
 
190
190
  // Set default color so resource creation succeeds in strict mode
191
191
  // Skip on older backends that don't implement the setDefaultColor TX request.
192
- if (client.supportsSetDefaultColor) {
192
+ if (client.supportsResourceSignatures) {
193
193
  await tx.send(
194
194
  { oneofKind: "setDefaultColor", setDefaultColor: { colorProof: rootSig } },
195
195
  false,
package/src/core/types.ts CHANGED
@@ -298,13 +298,26 @@ export function isSignedResourceId(resourceId: bigint | string): resourceId is S
298
298
  return typeof resourceId === "string" && resourceId.includes("|");
299
299
  }
300
300
 
301
+ // Process-global switch. Set to false by LLPlClient.build() when the connected
302
+ // backend predates resource signatures (~< 3.3.0). When false, asSignedResourceId
303
+ // accepts ids minted with an empty signature. Single-backend-per-process only:
304
+ // a Node process talking to mixed signed/unsigned backends will share last-wins
305
+ // state. Desktop App is single-backend-per-process, so this is acceptable.
306
+ let resourceSignaturesRequired = true;
307
+
308
+ export function setResourceSignaturesRequired(required: boolean): void {
309
+ resourceSignaturesRequired = required;
310
+ }
311
+
301
312
  /** Validate a string as a SignedResourceId and return it with the branded type.
302
- * Requires the format "<globalId>|<signatureHex>" with a non-empty signature. */
313
+ * Requires the format "<globalId>|<signatureHex>". A non-empty signature is
314
+ * required only when {@link areResourceSignaturesRequired} is true. */
303
315
  export function asSignedResourceId(str: string): SignedResourceId {
304
316
  const pipeIdx = str.indexOf("|");
305
317
  if (pipeIdx < 0) throw new Error(`Not a signed resource id (no '|' separator): ${str}`);
306
318
  if (pipeIdx === 0) throw new Error(`Signed resource id has empty globalId: ${str}`);
307
- if (pipeIdx === str.length - 1) throw new Error(`Signed resource id has empty signature: ${str}`);
319
+ if (resourceSignaturesRequired && pipeIdx === str.length - 1)
320
+ throw new Error(`Signed resource id has empty signature: ${str}`);
308
321
  return str as SignedResourceId;
309
322
  }
310
323