@claudian-collab/protocol 4.1.1 → 4.1.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/README.md
CHANGED
|
@@ -64,7 +64,7 @@ part of the public surface.
|
|
|
64
64
|
|
|
65
65
|
Package SemVer, canonical wire version, and Cloud binding version are independent concepts.
|
|
66
66
|
|
|
67
|
-
- **Package version** (this `package.json`): `4.1.
|
|
67
|
+
- **Package version** (this `package.json`): `4.1.2`. Behavior-preserving implementation refactors and reviewed compatible defect corrections may use a patch release when public declarations, runtime exports, and accepted wire/binding semantics remain unchanged. Minor releases may add backward-compatible API. Removing or incompatibly changing an existing declaration, export, runtime behavior, codec, error, limit, ref rule, operation, or compatibility rule requires a major release. Package API SemVer is classified independently from the wire and Cloud binding contracts, but a compatible package addition cannot exempt a changed wire contract from a wire-version increase or a changed Cloud binding contract from a binding-version increase. The package version never signals wire compatibility by itself.
|
|
68
68
|
- **Wire version** (`COLLAB_PROTOCOL_VERSION`): currently `8`. The supported range is exactly `[8, 8]`. This is independent from Cloud binding version `4` and the application-owned LAN bindings. Any change to an existing envelope, DTO, operation payload shape, or operation definition requires a new wire-protocol version. This includes additive operations: every wire-contract change increases the canonical wire version.
|
|
69
69
|
- **Cloud binding version** (`COLLAB_CLOUD_BINDING_VERSION`): currently `4`. It versions Cloud routes, bounded transfer streams, and capabilities independently from package and wire versions. Every Cloud binding-contract change increases this version. Bindings before v4 and wire versions before v8 are unsupported rather than translated or dual-interpreted.
|
|
70
70
|
|
|
@@ -1924,13 +1924,16 @@ function validateContinuity(records) {
|
|
|
1924
1924
|
if (!members.has(item.value.memberId)
|
|
1925
1925
|
|| lifecycle?.value.operationKind !== 'authority-transfer'
|
|
1926
1926
|
|| lifecycle.value.direction !== 'cloud-to-lan'
|
|
1927
|
-
|| lifecycle.value.state !== 'completed'
|
|
1927
|
+
|| (lifecycle.value.state !== 'completed' && lifecycle.value.state !== 'cancelled')
|
|
1928
1928
|
|| terminal === undefined
|
|
1929
1929
|
|| recovery === undefined
|
|
1930
1930
|
|| item.value.memberId !== recovery.value.targetHostMemberId
|
|
1931
|
-
|| item.value.requestSha256 !== recovery.value.targetActivationRequestSha256
|
|
1932
1931
|
|| !terminal.value.eligibleMemberIds.includes(item.value.memberId)
|
|
1933
1932
|
|| response === undefined
|
|
1933
|
+
|| response.phase !== lifecycle.value.phase
|
|
1934
|
+
|| response.state !== lifecycle.value.state
|
|
1935
|
+
|| (response.state === 'completed'
|
|
1936
|
+
&& item.value.requestSha256 !== recovery.value.targetActivationRequestSha256)
|
|
1934
1937
|
|| response.batchRevision !== lifecycle.value.batchRevision
|
|
1935
1938
|
|| response.batchSha256 !== lifecycle.value.batchSha256
|
|
1936
1939
|
|| response.checkpointSha256 !== lifecycle.value.checkpointSha256
|
|
@@ -906,8 +906,8 @@ function terminalResponderRecord(source, recordId, revision, deferPrincipals) {
|
|
|
906
906
|
}
|
|
907
907
|
else if (operation === 'getProjectAuthorityTransfer') {
|
|
908
908
|
if (response.decoded.direction !== 'cloud-to-lan'
|
|
909
|
-
|| response.decoded.phase
|
|
910
|
-
|
|
909
|
+
|| !((response.decoded.phase === 'completed' && response.decoded.state === 'completed')
|
|
910
|
+
|| (response.decoded.phase === 'cancelled' && response.decoded.state === 'cancelled'))
|
|
911
911
|
|| response.decoded.expiresAt !== expiresAt)
|
|
912
912
|
throw invalidPayload('responseJson');
|
|
913
913
|
}
|
|
@@ -1218,9 +1218,17 @@ function validateCheckpointRecordSequence(records, profile, acknowledgementBindi
|
|
|
1218
1218
|
.map(item => [item.value.memberId, item.value.principalId]));
|
|
1219
1219
|
const terminalResponders = records.filter((item) => (item.kind === 'terminal-responder'));
|
|
1220
1220
|
const tombstones = records.filter((item) => (item.kind === 'tombstone'));
|
|
1221
|
+
const terminalResponder = terminalResponders[0];
|
|
1222
|
+
const transferTerminalResponse = terminalResponder?.value.operation
|
|
1223
|
+
=== 'getProjectAuthorityTransfer'
|
|
1224
|
+
? canonicalOperationResponseJson({ responseJson: terminalResponder.value.responseJson }, 'responseJson', 'getProjectAuthorityTransfer').decoded
|
|
1225
|
+
: undefined;
|
|
1226
|
+
const terminalRequiresTombstone = terminalResponder !== undefined && (terminalResponder.value.operation === 'retireProject'
|
|
1227
|
+
|| transferTerminalResponse?.state === 'completed');
|
|
1221
1228
|
if (terminalResponders.length > 1
|
|
1222
|
-
|| (
|
|
1223
|
-
||
|
|
1229
|
+
|| (terminalRequiresTombstone && (tombstones.length !== 1
|
|
1230
|
+
|| terminalResponder.value.expiresAt !== tombstones[0].value.terminalExpiresAt))
|
|
1231
|
+
|| (terminalResponder !== undefined && !terminalRequiresTombstone && tombstones.length !== 0))
|
|
1224
1232
|
throw invalidPayload('records');
|
|
1225
1233
|
const tombstone = tombstones[0];
|
|
1226
1234
|
const retirementTerminal = terminalResponders.find(item => (item.value.operation === 'retireProject'));
|
|
@@ -1914,13 +1914,16 @@ function validateContinuity(records) {
|
|
|
1914
1914
|
if (!members.has(item.value.memberId)
|
|
1915
1915
|
|| lifecycle?.value.operationKind !== 'authority-transfer'
|
|
1916
1916
|
|| lifecycle.value.direction !== 'cloud-to-lan'
|
|
1917
|
-
|| lifecycle.value.state !== 'completed'
|
|
1917
|
+
|| (lifecycle.value.state !== 'completed' && lifecycle.value.state !== 'cancelled')
|
|
1918
1918
|
|| terminal === undefined
|
|
1919
1919
|
|| recovery === undefined
|
|
1920
1920
|
|| item.value.memberId !== recovery.value.targetHostMemberId
|
|
1921
|
-
|| item.value.requestSha256 !== recovery.value.targetActivationRequestSha256
|
|
1922
1921
|
|| !terminal.value.eligibleMemberIds.includes(item.value.memberId)
|
|
1923
1922
|
|| response === undefined
|
|
1923
|
+
|| response.phase !== lifecycle.value.phase
|
|
1924
|
+
|| response.state !== lifecycle.value.state
|
|
1925
|
+
|| (response.state === 'completed'
|
|
1926
|
+
&& item.value.requestSha256 !== recovery.value.targetActivationRequestSha256)
|
|
1924
1927
|
|| response.batchRevision !== lifecycle.value.batchRevision
|
|
1925
1928
|
|| response.batchSha256 !== lifecycle.value.batchSha256
|
|
1926
1929
|
|| response.checkpointSha256 !== lifecycle.value.checkpointSha256
|
|
@@ -891,8 +891,8 @@ function terminalResponderRecord(source, recordId, revision, deferPrincipals) {
|
|
|
891
891
|
}
|
|
892
892
|
else if (operation === 'getProjectAuthorityTransfer') {
|
|
893
893
|
if (response.decoded.direction !== 'cloud-to-lan'
|
|
894
|
-
|| response.decoded.phase
|
|
895
|
-
|
|
894
|
+
|| !((response.decoded.phase === 'completed' && response.decoded.state === 'completed')
|
|
895
|
+
|| (response.decoded.phase === 'cancelled' && response.decoded.state === 'cancelled'))
|
|
896
896
|
|| response.decoded.expiresAt !== expiresAt)
|
|
897
897
|
throw invalidPayload('responseJson');
|
|
898
898
|
}
|
|
@@ -1203,9 +1203,17 @@ export function validateCheckpointRecordSequence(records, profile, acknowledgeme
|
|
|
1203
1203
|
.map(item => [item.value.memberId, item.value.principalId]));
|
|
1204
1204
|
const terminalResponders = records.filter((item) => (item.kind === 'terminal-responder'));
|
|
1205
1205
|
const tombstones = records.filter((item) => (item.kind === 'tombstone'));
|
|
1206
|
+
const terminalResponder = terminalResponders[0];
|
|
1207
|
+
const transferTerminalResponse = terminalResponder?.value.operation
|
|
1208
|
+
=== 'getProjectAuthorityTransfer'
|
|
1209
|
+
? canonicalOperationResponseJson({ responseJson: terminalResponder.value.responseJson }, 'responseJson', 'getProjectAuthorityTransfer').decoded
|
|
1210
|
+
: undefined;
|
|
1211
|
+
const terminalRequiresTombstone = terminalResponder !== undefined && (terminalResponder.value.operation === 'retireProject'
|
|
1212
|
+
|| transferTerminalResponse?.state === 'completed');
|
|
1206
1213
|
if (terminalResponders.length > 1
|
|
1207
|
-
|| (
|
|
1208
|
-
||
|
|
1214
|
+
|| (terminalRequiresTombstone && (tombstones.length !== 1
|
|
1215
|
+
|| terminalResponder.value.expiresAt !== tombstones[0].value.terminalExpiresAt))
|
|
1216
|
+
|| (terminalResponder !== undefined && !terminalRequiresTombstone && tombstones.length !== 0))
|
|
1209
1217
|
throw invalidPayload('records');
|
|
1210
1218
|
const tombstone = tombstones[0];
|
|
1211
1219
|
const retirementTerminal = terminalResponders.find(item => (item.value.operation === 'retireProject'));
|