@peers-app/peers-sdk 0.31.1 → 0.31.3

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.
@@ -36,7 +36,8 @@ export declare class ContractRegistry {
36
36
  *
37
37
  * Validates:
38
38
  * 1. The implementation satisfies its own declared contract shape.
39
- * 2. Immutability — a frozen contract cannot be redefined with a different shape.
39
+ * 2. Immutability — a frozen contract cannot be redefined with a different shape. A mutable
40
+ * copy of one registers as the frozen version ({@link followStableDefinitions}).
40
41
  * 3. `alsoImplements` declarations.
41
42
  *
42
43
  * If no active provider exists for this contract yet, the new provider
@@ -72,12 +73,30 @@ export declare class ContractRegistry {
72
73
  replaceBatch(providerPackageId: string, registrations: readonly IContractProviderRegistration[]): IValidationResult;
73
74
  /**
74
75
  * Validate a complete provider registration batch without changing registry state.
76
+ * Like the batch methods, it validates the registrations as
77
+ * {@link followStableDefinitions} would commit them.
75
78
  *
76
79
  * @param providerPackageId - Trusted provider package identity.
77
80
  * @param registrations - Definitions and compatibility declarations to validate.
78
81
  * @returns Combined validation result.
79
82
  */
80
83
  validateBatch(providerPackageId: string, registrations: readonly IContractProviderRegistration[]): IValidationResult;
84
+ /**
85
+ * The registrations as the registry would take them now. A mutable (`devTag: "dev"`)
86
+ * definition of a contract version the registry already holds as stable becomes the stable
87
+ * version, and so does a mutable definition carried by an `alsoImplements` declaration. Its
88
+ * shape must still match the frozen one, which validation checks.
89
+ *
90
+ * A dev or beta package can implement a contract another package froze, but it can't reopen
91
+ * it. The batch methods apply this when they validate and commit, against the registry as it
92
+ * is then. So a package whose registrations were built before another package froze a contract
93
+ * still registers, even when the two load at the same time.
94
+ *
95
+ * @param registrations - Definitions and compatibility declarations to settle.
96
+ * @returns The registrations with those definitions made stable; the others unchanged.
97
+ */
98
+ followStableDefinitions(registrations: readonly IContractProviderRegistration[]): IContractProviderRegistration[];
99
+ private validateSettled;
81
100
  private commitRegistrations;
82
101
  private commitProvider;
83
102
  /**
@@ -25,7 +25,8 @@ class ContractRegistry {
25
25
  *
26
26
  * Validates:
27
27
  * 1. The implementation satisfies its own declared contract shape.
28
- * 2. Immutability — a frozen contract cannot be redefined with a different shape.
28
+ * 2. Immutability — a frozen contract cannot be redefined with a different shape. A mutable
29
+ * copy of one registers as the frozen version ({@link followStableDefinitions}).
29
30
  * 3. `alsoImplements` declarations.
30
31
  *
31
32
  * If no active provider exists for this contract yet, the new provider
@@ -51,11 +52,12 @@ class ContractRegistry {
51
52
  * @returns The combined validation result.
52
53
  */
53
54
  registerBatch(providerPackageId, registrations) {
54
- const validation = this.validateBatch(providerPackageId, registrations);
55
+ const settled = this.followStableDefinitions(registrations);
56
+ const validation = this.validateSettled(providerPackageId, settled);
55
57
  if (!validation.valid) {
56
58
  return validation;
57
59
  }
58
- this.commitRegistrations(providerPackageId, registrations);
60
+ this.commitRegistrations(providerPackageId, settled);
59
61
  return validation;
60
62
  }
61
63
  /**
@@ -70,13 +72,14 @@ class ContractRegistry {
70
72
  * @returns Validation result; invalid replacements leave the registry unchanged.
71
73
  */
72
74
  replaceBatch(providerPackageId, registrations) {
73
- const validation = this.validateBatch(providerPackageId, registrations);
75
+ const settled = this.followStableDefinitions(registrations);
76
+ const validation = this.validateSettled(providerPackageId, settled);
74
77
  if (!validation.valid) {
75
78
  return validation;
76
79
  }
77
80
  const previouslyActive = new Set((this.packageContracts.get(providerPackageId) ?? []).filter((key) => this.activeProviders.get(key)?.providerPackageId === providerPackageId));
78
81
  this.unregister(providerPackageId);
79
- this.commitRegistrations(providerPackageId, registrations);
82
+ this.commitRegistrations(providerPackageId, settled);
80
83
  for (const key of previouslyActive) {
81
84
  const provider = this.allProviders
82
85
  .get(key)
@@ -89,12 +92,53 @@ class ContractRegistry {
89
92
  }
90
93
  /**
91
94
  * Validate a complete provider registration batch without changing registry state.
95
+ * Like the batch methods, it validates the registrations as
96
+ * {@link followStableDefinitions} would commit them.
92
97
  *
93
98
  * @param providerPackageId - Trusted provider package identity.
94
99
  * @param registrations - Definitions and compatibility declarations to validate.
95
100
  * @returns Combined validation result.
96
101
  */
97
102
  validateBatch(providerPackageId, registrations) {
103
+ return this.validateSettled(providerPackageId, this.followStableDefinitions(registrations));
104
+ }
105
+ /**
106
+ * The registrations as the registry would take them now. A mutable (`devTag: "dev"`)
107
+ * definition of a contract version the registry already holds as stable becomes the stable
108
+ * version, and so does a mutable definition carried by an `alsoImplements` declaration. Its
109
+ * shape must still match the frozen one, which validation checks.
110
+ *
111
+ * A dev or beta package can implement a contract another package froze, but it can't reopen
112
+ * it. The batch methods apply this when they validate and commit, against the registry as it
113
+ * is then. So a package whose registrations were built before another package froze a contract
114
+ * still registers, even when the two load at the same time.
115
+ *
116
+ * @param registrations - Definitions and compatibility declarations to settle.
117
+ * @returns The registrations with those definitions made stable; the others unchanged.
118
+ */
119
+ followStableDefinitions(registrations) {
120
+ const settle = (definition) => {
121
+ if (definition.devTag !== "dev")
122
+ return definition;
123
+ const existing = this.definitions.get((0, types_1.contractKey)(definition.contractId, definition.version));
124
+ if (!existing || existing.devTag)
125
+ return definition;
126
+ const { devTag: _mutable, ...stable } = definition;
127
+ return stable;
128
+ };
129
+ return registrations.map((registration) => ({
130
+ ...registration,
131
+ definition: settle(registration.definition),
132
+ ...(registration.alsoImplements
133
+ ? {
134
+ alsoImplements: registration.alsoImplements.map((declaration) => declaration.definition
135
+ ? { ...declaration, definition: settle(declaration.definition) }
136
+ : declaration),
137
+ }
138
+ : {}),
139
+ }));
140
+ }
141
+ validateSettled(providerPackageId, registrations) {
98
142
  const candidateDefinitions = new Map(this.definitions);
99
143
  const batchKeys = new Set();
100
144
  for (const { definition } of registrations) {
@@ -8,8 +8,9 @@ import type { IPackageDefinitionResult } from "../contracts/types";
8
8
  * Materializes catalog identities and supplemental metadata, publishes contract providers,
9
9
  * saves package assistants and registers table definitions after successful preparation.
10
10
  *
11
- * When a contract version was previously frozen (promoted to stable), the
12
- * installer preserves its stable status rather than re-registering it as dev.
11
+ * When a contract version was previously frozen (promoted to stable), it stays stable: the
12
+ * registry registers a dev copy of it as the frozen version, when it validates and commits
13
+ * ({@link ContractRegistry.followStableDefinitions}).
13
14
  * Without `opts.registry` or the context's PackageLoader registry, catalog rows
14
15
  * are still written but no provider is published.
15
16
  */
@@ -11,8 +11,9 @@ const tool_catalog_1 = require("../contracts/tool-catalog");
11
11
  * Materializes catalog identities and supplemental metadata, publishes contract providers,
12
12
  * saves package assistants and registers table definitions after successful preparation.
13
13
  *
14
- * When a contract version was previously frozen (promoted to stable), the
15
- * installer preserves its stable status rather than re-registering it as dev.
14
+ * When a contract version was previously frozen (promoted to stable), it stays stable: the
15
+ * registry registers a dev copy of it as the frozen version, when it validates and commits
16
+ * ({@link ContractRegistry.followStableDefinitions}).
16
17
  * Without `opts.registry` or the context's PackageLoader registry, catalog rows
17
18
  * are still written but no provider is published.
18
19
  */
@@ -24,12 +25,8 @@ async function installContractPackage(dataContext, packageDefinition, opts) {
24
25
  const registry = sharedRegistry ?? new registry_1.ContractRegistry();
25
26
  const registrations = packageDefinition.contracts.map((contract) => {
26
27
  const key = `${contract.contractId}@${contract.version}`;
27
- const existing = registry.getDefinition(contract.contractId, contract.version);
28
- const definition = existing && !existing.devTag && contract.devTag === "dev"
29
- ? { ...contract, devTag: undefined }
30
- : contract;
31
28
  return {
32
- definition,
29
+ definition: contract,
33
30
  alsoImplements: packageDefinition.alsoImplements.get(key) ?? [],
34
31
  exposes: packageDefinition.exposes?.get(key) ?? [],
35
32
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.31.1",
3
+ "version": "0.31.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"