@blue-repository/types 0.11.0 → 0.13.0
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 +1 -1
- package/dist/meta.d.ts +2 -2
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +2 -0
- package/dist/meta.js.map +1 -1
- package/dist/packages/conversation/blue-ids.d.ts +7 -7
- package/dist/packages/conversation/blue-ids.js +7 -7
- package/dist/packages/conversation/contents/AcceptChangeWorkflow.d.ts +1 -1
- package/dist/packages/conversation/contents/AcceptChangeWorkflow.js +1 -1
- package/dist/packages/conversation/contents/AcceptChangeWorkflow.js.map +1 -1
- package/dist/packages/conversation/contents/ChangeOperation.d.ts +1 -1
- package/dist/packages/conversation/contents/ChangeOperation.js +1 -1
- package/dist/packages/conversation/contents/ChangeRequest.d.ts +8 -8
- package/dist/packages/conversation/contents/ChangeRequest.js +8 -8
- package/dist/packages/conversation/contents/ChangeRequest.js.map +1 -1
- package/dist/packages/conversation/contents/ChangeWorkflow.d.ts +2 -2
- package/dist/packages/conversation/contents/ChangeWorkflow.js +2 -2
- package/dist/packages/conversation/contents/ChangeWorkflow.js.map +1 -1
- package/dist/packages/conversation/contents/ProposeChangeOperation.d.ts +1 -1
- package/dist/packages/conversation/contents/ProposeChangeOperation.js +1 -1
- package/dist/packages/conversation/contents/ProposeChangeWorkflow.d.ts +2 -2
- package/dist/packages/conversation/contents/ProposeChangeWorkflow.js +2 -2
- package/dist/packages/conversation/contents/ProposeChangeWorkflow.js.map +1 -1
- package/dist/packages/conversation/contents/RejectChangeWorkflow.d.ts +1 -1
- package/dist/packages/conversation/contents/RejectChangeWorkflow.js +1 -1
- package/dist/packages/conversation/contents/RejectChangeWorkflow.js.map +1 -1
- package/dist/packages/conversation/contents/index.d.ts +204 -204
- package/dist/packages/conversation/contents/index.d.ts.map +1 -1
- package/dist/packages/conversation/contents/index.js +21 -21
- package/dist/packages/conversation/contents/index.js.map +1 -1
- package/dist/packages/conversation/index.d.ts +255 -255
- package/dist/packages/conversation/meta.d.ts +28 -28
- package/dist/packages/conversation/meta.js +21 -21
- package/dist/packages/conversation/meta.js.map +1 -1
- package/dist/packages/conversation/schemas/ChangeOperation.d.ts +5 -5
- package/dist/packages/conversation/schemas/ChangeRequest.d.ts +3 -3
- package/dist/packages/conversation/schemas/ChangeRequest.js +1 -1
- package/dist/packages/conversation/schemas/ChangeRequest.js.map +1 -1
- package/dist/packages/conversation/schemas/ChangeWorkflow.d.ts +5 -5
- package/dist/packages/conversation/schemas/ProposeChangeOperation.d.ts +5 -5
- package/dist/packages/conversation/schemas/ProposeChangeWorkflow.d.ts +5 -5
- package/dist/packages/conversation/schemas/index.d.ts +30 -30
- package/dist/packages/conversation/schemas/index.js +7 -7
- package/dist/packages/conversation/schemas/index.js.map +1 -1
- package/dist/repository.d.ts +256 -256
- package/package.json +2 -2
package/README.md
CHANGED
package/dist/meta.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export declare const name: "Blue Repository";
|
|
2
|
-
export declare const repositoryVersions: readonly ["CQn9FCus2xkhgCdSZQqKQmKGRLKnqTboSyiJXn3pya68"];
|
|
2
|
+
export declare const repositoryVersions: readonly ["CQn9FCus2xkhgCdSZQqKQmKGRLKnqTboSyiJXn3pya68", "22xxEjtpjUSpttaRiHX5XbmGNcFhpgLipai685YMdMWv", "58apGqo2EExaKTQQJmjASbj8p7tHvrWkoQVjWeWzaox5"];
|
|
3
3
|
declare const _default: {
|
|
4
4
|
readonly name: "Blue Repository";
|
|
5
|
-
readonly repositoryVersions: readonly ["CQn9FCus2xkhgCdSZQqKQmKGRLKnqTboSyiJXn3pya68"];
|
|
5
|
+
readonly repositoryVersions: readonly ["CQn9FCus2xkhgCdSZQqKQmKGRLKnqTboSyiJXn3pya68", "22xxEjtpjUSpttaRiHX5XbmGNcFhpgLipai685YMdMWv", "58apGqo2EExaKTQQJmjASbj8p7tHvrWkoQVjWeWzaox5"];
|
|
6
6
|
};
|
|
7
7
|
export default _default;
|
|
8
8
|
//# sourceMappingURL=meta.d.ts.map
|
package/dist/meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,EAAG,iBAA0B,CAAC;AAC/C,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,EAAG,iBAA0B,CAAC;AAC/C,eAAO,MAAM,kBAAkB,2JAIrB,CAAC;;;;;AACX,wBAAqD"}
|
package/dist/meta.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const name = 'Blue Repository';
|
|
2
2
|
export const repositoryVersions = [
|
|
3
3
|
'CQn9FCus2xkhgCdSZQqKQmKGRLKnqTboSyiJXn3pya68',
|
|
4
|
+
'22xxEjtpjUSpttaRiHX5XbmGNcFhpgLipai685YMdMWv',
|
|
5
|
+
'58apGqo2EExaKTQQJmjASbj8p7tHvrWkoQVjWeWzaox5',
|
|
4
6
|
];
|
|
5
7
|
export default { name, repositoryVersions };
|
|
6
8
|
//# sourceMappingURL=meta.js.map
|
package/dist/meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,iBAA0B,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,8CAA8C;CACtC,CAAC;AACX,eAAe,EAAE,IAAI,EAAE,kBAAkB,EAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,iBAA0B,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,8CAA8C;IAC9C,8CAA8C;IAC9C,8CAA8C;CACtC,CAAC;AACX,eAAe,EAAE,IAAI,EAAE,kBAAkB,EAAW,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export declare const blueIds: {
|
|
2
2
|
readonly 'Conversation/Accept Change Operation': "APk3siB8g9pvWLG3qyqtGjRNNGB7RDpFWQtG4epj5Avv";
|
|
3
|
-
readonly 'Conversation/Accept Change Workflow': "
|
|
3
|
+
readonly 'Conversation/Accept Change Workflow': "29xcoYKf9p47xagTDwGLuQyFrT9WBN3Sd7FaPtqLvydy";
|
|
4
4
|
readonly 'Conversation/Actor': "CN5efWVizJbRsMCw8YWRfT2q9vM9XfeGDN9wFvYcvMnQ";
|
|
5
|
-
readonly 'Conversation/Change Operation': "
|
|
6
|
-
readonly 'Conversation/Change Request': "
|
|
7
|
-
readonly 'Conversation/Change Workflow': "
|
|
5
|
+
readonly 'Conversation/Change Operation': "Hd5uuFjqxyw5mrFPgJf2mcatij8ddtmGAMJu9ij5K1tc";
|
|
6
|
+
readonly 'Conversation/Change Request': "FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG";
|
|
7
|
+
readonly 'Conversation/Change Workflow': "4pFvBSYyitoq8rWqTmY5rLywU2tpZsivDUCAo5vwoAT9";
|
|
8
8
|
readonly 'Conversation/Chat Message': "AkUKoKY1hHY1CytCrAXDPKCd4md1QGmn1WNcQtWBsyAD";
|
|
9
9
|
readonly 'Conversation/Composite Timeline Channel': "HsNatiPt2YvmkWQoqtfrFCbdp75ZUBLBUkWeq84WTfnr";
|
|
10
10
|
readonly 'Conversation/Contracts Change Policy': "6FDVZRQwuhXdXtnXq8kRg3f3DM8SUdbN3TT8rSGJcS2U";
|
|
@@ -25,11 +25,11 @@ export declare const blueIds: {
|
|
|
25
25
|
readonly 'Conversation/Lifecycle Event': "5YZEAtUaHhNfnVnwtSsyBnBakpcSwdL75UcgtrtnqeYn";
|
|
26
26
|
readonly 'Conversation/Operation': "BoAiqVUZv9Fum3wFqaX2JnQMBHJLxJSo2V9U2UBmCfsC";
|
|
27
27
|
readonly 'Conversation/Operation Request': "HM4Ku4LFcjC5MxnhPMRwQ8w3BbHmJKKZfHTTzsd4jbJq";
|
|
28
|
-
readonly 'Conversation/Propose Change Operation': "
|
|
29
|
-
readonly 'Conversation/Propose Change Workflow': "
|
|
28
|
+
readonly 'Conversation/Propose Change Operation': "BeiedmmcKDhStxDnnQqUaXDJLofWSnqX6CazKTvVpfbW";
|
|
29
|
+
readonly 'Conversation/Propose Change Workflow': "7dUt8jiX5vGeZL7wVzWFA8uEw37T6oPgC8KyDZmqxeSj";
|
|
30
30
|
readonly 'Conversation/Proposed Change Invalid': "EbGQYtYR9UNAxcn7auCCujXmnz6DWxMpqVcgYSsKE85M";
|
|
31
31
|
readonly 'Conversation/Reject Change Operation': "4T5AmhKAXSJAAHDEjtVJ2FQgCyz2qyd9qG5uoh627Ux6";
|
|
32
|
-
readonly 'Conversation/Reject Change Workflow': "
|
|
32
|
+
readonly 'Conversation/Reject Change Workflow': "9fnXwi4Za8hjEj6zDSEjhbA5dLrDzs7sxoDMGLmRT2Gz";
|
|
33
33
|
readonly 'Conversation/Request': "8f9UhHMbRe62sFgzQVheToaJPYi7t7HPNVvpQTbqfL5n";
|
|
34
34
|
readonly 'Conversation/Response': "36epvrpVHZLjapbeZsNodz2NDnm7XZeNZcnkWHgkP1pp";
|
|
35
35
|
readonly 'Conversation/Sequential Workflow': "7X3LkN54Yp88JgZbppPhP6hM3Jqiqv8Z2i4kS7phXtQe";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const blueIds = {
|
|
2
2
|
'Conversation/Accept Change Operation': 'APk3siB8g9pvWLG3qyqtGjRNNGB7RDpFWQtG4epj5Avv',
|
|
3
|
-
'Conversation/Accept Change Workflow': '
|
|
3
|
+
'Conversation/Accept Change Workflow': '29xcoYKf9p47xagTDwGLuQyFrT9WBN3Sd7FaPtqLvydy',
|
|
4
4
|
'Conversation/Actor': 'CN5efWVizJbRsMCw8YWRfT2q9vM9XfeGDN9wFvYcvMnQ',
|
|
5
|
-
'Conversation/Change Operation': '
|
|
6
|
-
'Conversation/Change Request': '
|
|
7
|
-
'Conversation/Change Workflow': '
|
|
5
|
+
'Conversation/Change Operation': 'Hd5uuFjqxyw5mrFPgJf2mcatij8ddtmGAMJu9ij5K1tc',
|
|
6
|
+
'Conversation/Change Request': 'FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG',
|
|
7
|
+
'Conversation/Change Workflow': '4pFvBSYyitoq8rWqTmY5rLywU2tpZsivDUCAo5vwoAT9',
|
|
8
8
|
'Conversation/Chat Message': 'AkUKoKY1hHY1CytCrAXDPKCd4md1QGmn1WNcQtWBsyAD',
|
|
9
9
|
'Conversation/Composite Timeline Channel': 'HsNatiPt2YvmkWQoqtfrFCbdp75ZUBLBUkWeq84WTfnr',
|
|
10
10
|
'Conversation/Contracts Change Policy': '6FDVZRQwuhXdXtnXq8kRg3f3DM8SUdbN3TT8rSGJcS2U',
|
|
@@ -25,11 +25,11 @@ export const blueIds = {
|
|
|
25
25
|
'Conversation/Lifecycle Event': '5YZEAtUaHhNfnVnwtSsyBnBakpcSwdL75UcgtrtnqeYn',
|
|
26
26
|
'Conversation/Operation': 'BoAiqVUZv9Fum3wFqaX2JnQMBHJLxJSo2V9U2UBmCfsC',
|
|
27
27
|
'Conversation/Operation Request': 'HM4Ku4LFcjC5MxnhPMRwQ8w3BbHmJKKZfHTTzsd4jbJq',
|
|
28
|
-
'Conversation/Propose Change Operation': '
|
|
29
|
-
'Conversation/Propose Change Workflow': '
|
|
28
|
+
'Conversation/Propose Change Operation': 'BeiedmmcKDhStxDnnQqUaXDJLofWSnqX6CazKTvVpfbW',
|
|
29
|
+
'Conversation/Propose Change Workflow': '7dUt8jiX5vGeZL7wVzWFA8uEw37T6oPgC8KyDZmqxeSj',
|
|
30
30
|
'Conversation/Proposed Change Invalid': 'EbGQYtYR9UNAxcn7auCCujXmnz6DWxMpqVcgYSsKE85M',
|
|
31
31
|
'Conversation/Reject Change Operation': '4T5AmhKAXSJAAHDEjtVJ2FQgCyz2qyd9qG5uoh627Ux6',
|
|
32
|
-
'Conversation/Reject Change Workflow': '
|
|
32
|
+
'Conversation/Reject Change Workflow': '9fnXwi4Za8hjEj6zDSEjhbA5dLrDzs7sxoDMGLmRT2Gz',
|
|
33
33
|
'Conversation/Request': '8f9UhHMbRe62sFgzQVheToaJPYi7t7HPNVvpQTbqfL5n',
|
|
34
34
|
'Conversation/Response': '36epvrpVHZLjapbeZsNodz2NDnm7XZeNZcnkWHgkP1pp',
|
|
35
35
|
'Conversation/Sequential Workflow': '7X3LkN54Yp88JgZbppPhP6hM3Jqiqv8Z2i4kS7phXtQe',
|
|
@@ -13,7 +13,7 @@ export declare const AcceptChangeWorkflow: {
|
|
|
13
13
|
readonly type: {
|
|
14
14
|
readonly blueId: "DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K";
|
|
15
15
|
};
|
|
16
|
-
readonly value: "const
|
|
16
|
+
readonly value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst isArray = Array.isArray;\n\nconst postfixValue = currentContract?.postfix || '';\nconst proposedPath = '/proposedChange' + postfixValue;\n\nconst change = document(proposedPath);\nif (!change) {\n return invalid('no proposed change at ' + proposedPath);\n}\n\nconst requestChangeset = isArray(change?.changeset) ? change.changeset : [];\nconst sectionChanges = change.sectionChanges;\n\nconst entryPath = (entry) => `${entry?.path || ''}`;\nconst isContractsPath = (p) => p === '/contracts' || p.startsWith('/contracts/');\nconst isProposedChangePath = (p) => p.startsWith('/proposedChange');\n\nconst contracts = document('/contracts') || {};\nconst policy = Object.values(contracts).find((c) => c?.requireSectionChanges !== undefined);\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (\n policyEnabled &&\n requestChangeset.some((e) => isContractsPath(entryPath(e)))\n) {\n return invalid('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n}\n\nif (requestChangeset.some((e) => isProposedChangePath(entryPath(e)))) {\n return invalid('changeset cannot modify /proposedChange');\n}\n\nconst escapePointer = (value) =>\n `${value}`.split('~').join('~0').split('/').join('~1');\n\nconst contractPtr = (key) => '/contracts/' + escapePointer(key);\n\nconst isMetaKey = (key) =>\n key === 'type' || key === 'keyType' || key === 'valueType' || key === 'description';\n\nconst contractKeysFromMap = (contractsMap) =>\n Object.keys(contractsMap || {}).filter((k) => !isMetaKey(k));\n\nconst normalizeSection = (section, contractKeys) => ({\n ...(section || {}),\n type: 'Conversation/Document Section',\n relatedContracts: (section?.relatedContracts?.length ? section.relatedContracts : contractKeys)\n});\n\nconst hasMatchingRelatedContracts = (section, contractKeys) => {\n const related = isArray(section?.relatedContracts)\n ? section.relatedContracts.map((value) => `${value}`)\n : [];\n if (!related.length) {\n return true;\n }\n if (related.length !== contractKeys.length) {\n return false;\n }\n const relatedMap = {};\n for (const value of related) {\n const key = `${value}`;\n relatedMap[key] = (relatedMap[key] || 0) + 1;\n }\n if (Object.keys(relatedMap).length !== contractKeys.length) {\n return false;\n }\n for (const key of contractKeys) {\n if (!relatedMap[key]) {\n return false;\n }\n }\n return true;\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = {};\nconst seenContractKeys = {};\nconst existingContractKeys = {};\nfor (const key of Object.keys(contracts || {}).filter((k) => !isMetaKey(k))) {\n existingContractKeys[key] = true;\n}\n\nconst trackSectionKey = (sectionKey) => {\n if (seenSectionKeys[sectionKey]) {\n return invalid(`section key duplicated in sectionChanges: ${sectionKey}`);\n }\n seenSectionKeys[sectionKey] = true;\n return null;\n};\n\nconst trackContractKey = (sectionKey, contractKey) => {\n const existingSection = seenContractKeys[contractKey];\n if (existingSection && existingSection !== sectionKey) {\n return invalid(`contract key used by multiple sections in request: ${contractKey}`);\n }\n seenContractKeys[contractKey] = sectionKey;\n return null;\n};\n\nconst addList = isArray(sectionChanges?.add) ? sectionChanges.add : [];\nfor (const entry of addList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.add is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n if (existingContractKeys[sectionKey]) {\n return invalid(`contract key already exists at ${contractPtr(sectionKey)}`);\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n if (existingContractKeys[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst modifyList = isArray(sectionChanges?.modify) ? sectionChanges.modify : [];\nfor (const entry of modifyList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.modify is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n const existingRelated = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts.map((value) => `${value}`)\n : [];\n const existingRelatedMap = {};\n for (const value of existingRelated) {\n existingRelatedMap[`${value}`] = true;\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n if (existingContractKeys[key] && !existingRelatedMap[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n for (const oldKey of existingRelated) {\n if (contractKeys.indexOf(oldKey) === -1) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(oldKey) });\n }\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst removeList = isArray(sectionChanges?.remove) ? sectionChanges.remove : [];\nfor (const entry of removeList) {\n const sectionKey = `${entry?.sectionKey || entry || ''}`;\n if (!sectionKey) return invalid('sectionChanges.remove is missing sectionKey');\n\n const related = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts\n : [];\n\n for (const key of related) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(key) });\n }\n sectionChangeset.push({ op: 'remove', path: contractPtr(sectionKey) });\n}\n\nconst combined = sectionChangeset.concat(requestChangeset);\n\nif (combined.length === 0) {\n return invalid('no changes provided');\n}\n\nreturn {\n changeset: combined.concat({ op: 'remove', path: proposedPath })\n};\n";
|
|
17
17
|
};
|
|
18
18
|
readonly name: "Prepare";
|
|
19
19
|
readonly type: {
|
|
@@ -14,7 +14,7 @@ export const AcceptChangeWorkflow = {
|
|
|
14
14
|
type: {
|
|
15
15
|
blueId: 'DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K',
|
|
16
16
|
},
|
|
17
|
-
value:
|
|
17
|
+
value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst isArray = Array.isArray;\n\nconst postfixValue = currentContract?.postfix || '';\nconst proposedPath = '/proposedChange' + postfixValue;\n\nconst change = document(proposedPath);\nif (!change) {\n return invalid('no proposed change at ' + proposedPath);\n}\n\nconst requestChangeset = isArray(change?.changeset) ? change.changeset : [];\nconst sectionChanges = change.sectionChanges;\n\nconst entryPath = (entry) => `${entry?.path || ''}`;\nconst isContractsPath = (p) => p === '/contracts' || p.startsWith('/contracts/');\nconst isProposedChangePath = (p) => p.startsWith('/proposedChange');\n\nconst contracts = document('/contracts') || {};\nconst policy = Object.values(contracts).find((c) => c?.requireSectionChanges !== undefined);\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (\n policyEnabled &&\n requestChangeset.some((e) => isContractsPath(entryPath(e)))\n) {\n return invalid('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n}\n\nif (requestChangeset.some((e) => isProposedChangePath(entryPath(e)))) {\n return invalid('changeset cannot modify /proposedChange');\n}\n\nconst escapePointer = (value) =>\n `${value}`.split('~').join('~0').split('/').join('~1');\n\nconst contractPtr = (key) => '/contracts/' + escapePointer(key);\n\nconst isMetaKey = (key) =>\n key === 'type' || key === 'keyType' || key === 'valueType' || key === 'description';\n\nconst contractKeysFromMap = (contractsMap) =>\n Object.keys(contractsMap || {}).filter((k) => !isMetaKey(k));\n\nconst normalizeSection = (section, contractKeys) => ({\n ...(section || {}),\n type: 'Conversation/Document Section',\n relatedContracts: (section?.relatedContracts?.length ? section.relatedContracts : contractKeys)\n});\n\nconst hasMatchingRelatedContracts = (section, contractKeys) => {\n const related = isArray(section?.relatedContracts)\n ? section.relatedContracts.map((value) => `${value}`)\n : [];\n if (!related.length) {\n return true;\n }\n if (related.length !== contractKeys.length) {\n return false;\n }\n const relatedMap = {};\n for (const value of related) {\n const key = `${value}`;\n relatedMap[key] = (relatedMap[key] || 0) + 1;\n }\n if (Object.keys(relatedMap).length !== contractKeys.length) {\n return false;\n }\n for (const key of contractKeys) {\n if (!relatedMap[key]) {\n return false;\n }\n }\n return true;\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = {};\nconst seenContractKeys = {};\nconst existingContractKeys = {};\nfor (const key of Object.keys(contracts || {}).filter((k) => !isMetaKey(k))) {\n existingContractKeys[key] = true;\n}\n\nconst trackSectionKey = (sectionKey) => {\n if (seenSectionKeys[sectionKey]) {\n return invalid(`section key duplicated in sectionChanges: ${sectionKey}`);\n }\n seenSectionKeys[sectionKey] = true;\n return null;\n};\n\nconst trackContractKey = (sectionKey, contractKey) => {\n const existingSection = seenContractKeys[contractKey];\n if (existingSection && existingSection !== sectionKey) {\n return invalid(`contract key used by multiple sections in request: ${contractKey}`);\n }\n seenContractKeys[contractKey] = sectionKey;\n return null;\n};\n\nconst addList = isArray(sectionChanges?.add) ? sectionChanges.add : [];\nfor (const entry of addList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.add is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n if (existingContractKeys[sectionKey]) {\n return invalid(`contract key already exists at ${contractPtr(sectionKey)}`);\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n if (existingContractKeys[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst modifyList = isArray(sectionChanges?.modify) ? sectionChanges.modify : [];\nfor (const entry of modifyList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.modify is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n const existingRelated = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts.map((value) => `${value}`)\n : [];\n const existingRelatedMap = {};\n for (const value of existingRelated) {\n existingRelatedMap[`${value}`] = true;\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n if (existingContractKeys[key] && !existingRelatedMap[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n for (const oldKey of existingRelated) {\n if (contractKeys.indexOf(oldKey) === -1) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(oldKey) });\n }\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst removeList = isArray(sectionChanges?.remove) ? sectionChanges.remove : [];\nfor (const entry of removeList) {\n const sectionKey = `${entry?.sectionKey || entry || ''}`;\n if (!sectionKey) return invalid('sectionChanges.remove is missing sectionKey');\n\n const related = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts\n : [];\n\n for (const key of related) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(key) });\n }\n sectionChangeset.push({ op: 'remove', path: contractPtr(sectionKey) });\n}\n\nconst combined = sectionChangeset.concat(requestChangeset);\n\nif (combined.length === 0) {\n return invalid('no changes provided');\n}\n\nreturn {\n changeset: combined.concat({ op: 'remove', path: proposedPath })\n};\n",
|
|
18
18
|
},
|
|
19
19
|
name: 'Prepare',
|
|
20
20
|
type: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AcceptChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/AcceptChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW,EACT,sEAAsE;IACxE,IAAI,EAAE,wBAAwB;IAC9B,OAAO,EAAE;QACP,WAAW,EACT,iEAAiE;QACnE,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH,
|
|
1
|
+
{"version":3,"file":"AcceptChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/AcceptChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW,EACT,sEAAsE;IACxE,IAAI,EAAE,wBAAwB;IAC9B,OAAO,EAAE;QACP,WAAW,EACT,iEAAiE;QACnE,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH,i8NAAi8N;iBACp8N;gBACD,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;YACD;gBACE,SAAS,EAAE;oBACT,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EAAE,4BAA4B;iBACpC;gBACD,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;SACF;KACF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,8CAA8C;KACvD;CACO,CAAC"}
|
|
@@ -3,7 +3,7 @@ export declare const ChangeOperation: {
|
|
|
3
3
|
readonly name: "Change Operation";
|
|
4
4
|
readonly request: {
|
|
5
5
|
readonly type: {
|
|
6
|
-
readonly blueId: "
|
|
6
|
+
readonly blueId: "FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG";
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
readonly type: {
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
export declare const ChangeRequest: {
|
|
2
|
-
readonly changeDescription: {
|
|
3
|
-
readonly description: "Required human-readable summary used for review and audit.";
|
|
4
|
-
readonly type: {
|
|
5
|
-
readonly blueId: "DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K";
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
2
|
readonly changeset: {
|
|
9
|
-
readonly description: "RFC 6902 patch entries outside /contracts (blocked by policy
|
|
3
|
+
readonly description: "RFC 6902 patch entries outside /contracts (blocked by policy if it touches /contracts).";
|
|
10
4
|
readonly itemType: {
|
|
11
5
|
readonly blueId: "Bz49DbfqKC1yJeCfv5RYPZUKTfb7rtZnmreCaz4RsXn5";
|
|
12
6
|
};
|
|
@@ -14,7 +8,7 @@ export declare const ChangeRequest: {
|
|
|
14
8
|
readonly blueId: "6aehfNAxHLC1PHHoDr3tYtFH3RWNbiWdFancJ1bypXEY";
|
|
15
9
|
};
|
|
16
10
|
};
|
|
17
|
-
readonly description: "Payload for propose
|
|
11
|
+
readonly description: "Payload for propose and direct change operations.";
|
|
18
12
|
readonly name: "Change Request";
|
|
19
13
|
readonly sectionChanges: {
|
|
20
14
|
readonly description: "Section-based /contracts mutations (required when Contracts Change Policy is enabled).";
|
|
@@ -22,5 +16,11 @@ export declare const ChangeRequest: {
|
|
|
22
16
|
readonly blueId: "DEmFwGa1sWm2BKhrN98LREKiB8j8B8kFAo7KBkkaojnN";
|
|
23
17
|
};
|
|
24
18
|
};
|
|
19
|
+
readonly summary: {
|
|
20
|
+
readonly description: "Human-readable summary of the requested change. Required when proposal is created.";
|
|
21
|
+
readonly type: {
|
|
22
|
+
readonly blueId: "DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K";
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
25
|
};
|
|
26
26
|
//# sourceMappingURL=ChangeRequest.d.ts.map
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
export const ChangeRequest = {
|
|
2
|
-
changeDescription: {
|
|
3
|
-
description: 'Required human-readable summary used for review and audit.',
|
|
4
|
-
type: {
|
|
5
|
-
blueId: 'DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K',
|
|
6
|
-
},
|
|
7
|
-
},
|
|
8
2
|
changeset: {
|
|
9
|
-
description: 'RFC 6902 patch entries outside /contracts (blocked by policy
|
|
3
|
+
description: 'RFC 6902 patch entries outside /contracts (blocked by policy if it touches /contracts).',
|
|
10
4
|
itemType: {
|
|
11
5
|
blueId: 'Bz49DbfqKC1yJeCfv5RYPZUKTfb7rtZnmreCaz4RsXn5',
|
|
12
6
|
},
|
|
@@ -14,7 +8,7 @@ export const ChangeRequest = {
|
|
|
14
8
|
blueId: '6aehfNAxHLC1PHHoDr3tYtFH3RWNbiWdFancJ1bypXEY',
|
|
15
9
|
},
|
|
16
10
|
},
|
|
17
|
-
description: 'Payload for propose
|
|
11
|
+
description: 'Payload for propose and direct change operations.',
|
|
18
12
|
name: 'Change Request',
|
|
19
13
|
sectionChanges: {
|
|
20
14
|
description: 'Section-based /contracts mutations (required when Contracts Change Policy is enabled).',
|
|
@@ -22,5 +16,11 @@ export const ChangeRequest = {
|
|
|
22
16
|
blueId: 'DEmFwGa1sWm2BKhrN98LREKiB8j8B8kFAo7KBkkaojnN',
|
|
23
17
|
},
|
|
24
18
|
},
|
|
19
|
+
summary: {
|
|
20
|
+
description: 'Human-readable summary of the requested change. Required when proposal is created.',
|
|
21
|
+
type: {
|
|
22
|
+
blueId: 'DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
25
|
};
|
|
26
26
|
//# sourceMappingURL=ChangeRequest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeRequest.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/ChangeRequest.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,
|
|
1
|
+
{"version":3,"file":"ChangeRequest.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/ChangeRequest.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,SAAS,EAAE;QACT,WAAW,EACT,yFAAyF;QAC3F,QAAQ,EAAE;YACR,MAAM,EAAE,8CAA8C;SACvD;QACD,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,WAAW,EAAE,mDAAmD;IAChE,IAAI,EAAE,gBAAgB;IACtB,cAAc,EAAE;QACd,WAAW,EACT,wFAAwF;QAC1F,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,OAAO,EAAE;QACP,WAAW,EACT,oFAAoF;QACtF,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;CACO,CAAC"}
|
|
@@ -4,7 +4,7 @@ export declare const ChangeWorkflow: {
|
|
|
4
4
|
readonly request: {
|
|
5
5
|
readonly description: "Expected request payload for this workflow.";
|
|
6
6
|
readonly type: {
|
|
7
|
-
readonly blueId: "
|
|
7
|
+
readonly blueId: "FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG";
|
|
8
8
|
};
|
|
9
9
|
};
|
|
10
10
|
readonly steps: {
|
|
@@ -13,7 +13,7 @@ export declare const ChangeWorkflow: {
|
|
|
13
13
|
readonly type: {
|
|
14
14
|
readonly blueId: "DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K";
|
|
15
15
|
};
|
|
16
|
-
readonly value: "const issues = [];\n\nconst request = event.message.request || {};\n\nconst changeDescription = request.changeDescription;\nconst rawChangeset = request.changeset;\nconst rawSectionChanges = request.sectionChanges;\nconst requestSectionChanges = rawSectionChanges || {};\n\nconst toText = (value) => {\n const raw = value && value.value ? value.value : value;\n return raw && raw.trim ? raw.trim() : '';\n};\nconst asList = (value) => Array.isArray(value) ? value : [];\nconst hasType = (value) => value && value.type;\nconst escapePointer = (value) => {\n const text = toText(value);\n return text.split('~').join('~0').split('/').join('~1');\n};\nconst requestChangeset = asList(rawChangeset);\n\nconst uniqueKeys = (values, label) => {\n const seen = new Set();\n const output = [];\n for (const value of values) {\n const key = toText(value);\n if (!key) {\n issues.push(label + ' contains invalid key');\n continue;\n }\n if (seen.has(key)) {\n issues.push(label + ' contains duplicate key: ' + key);\n continue;\n }\n seen.add(key);\n output.push(key);\n }\n return output;\n};\n\nconst sameStringSet = (left, right) => {\n if (left.length !== right.length) return false;\n const set = new Set(left);\n if (set.size !== right.length) return false;\n for (const value of right) {\n if (!set.has(value)) return false;\n }\n return true;\n};\n\nconst contracts = Object(document('/contracts') || {});\n\nconst isDocumentSection = (contract) =>\n !!contract && Array.isArray(contract.relatedContracts);\n\nconst isContractsChangePolicy = (contract) => {\n if (!contract) return false;\n return 'requireSectionChanges' in contract;\n};\n\nconst findPolicy = () => {\n for (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isContractsChangePolicy(contract)) {\n return contract;\n }\n }\n return null;\n};\n\nconst policy = findPolicy();\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (!toText(changeDescription)) {\n issues.push('changeDescription is missing');\n}\n\nconst hasChangeset = !!rawChangeset;\nconst hasSectionChanges = !!rawSectionChanges;\n\nif (!hasChangeset && !hasSectionChanges) {\n issues.push('changeset or sectionChanges is required');\n}\n\nconst isContractsPath = (path) => {\n const value = toText(path);\n return value === '/contracts' || value.startsWith('/contracts/');\n};\nif (policyEnabled && hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isContractsPath(entry.path)) {\n issues.push('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n break;\n }\n }\n}\nconst isProposedChangePath = (path) =>\n toText(path).startsWith('/proposedChange');\nif (hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isProposedChangePath(entry.path)) {\n issues.push('changeset cannot modify /proposedChange');\n break;\n }\n }\n}\n\nconst existingSections = {};\nfor (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isDocumentSection(contract)) {\n existingSections[key] = contract;\n }\n}\n\nconst contractIndex = {};\nfor (const sectionKey of Object.keys(existingSections)) {\n const section = existingSections[sectionKey];\n const related = asList(section.relatedContracts);\n for (const relatedKey of related) {\n const contractKey = toText(relatedKey);\n if (!contractKey) continue;\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n contractIndex[contractKey] = null;\n } else if (!contractIndex[contractKey]) {\n contractIndex[contractKey] = sectionKey;\n }\n }\n}\n\nconst normalizeSectionDefinition = (sectionDef, label) => {\n if (!sectionDef) {\n issues.push(label + ' entry must be an object');\n return null;\n }\n const sectionKey = toText(sectionDef.sectionKey);\n if (!sectionKey) {\n issues.push(label + ' sectionKey is missing');\n return null;\n }\n const section = sectionDef.section;\n if (!section) {\n issues.push(label + ' section is missing');\n return null;\n }\n\n const rawContractsMap = sectionDef.contracts && sectionDef.contracts.value\n ? sectionDef.contracts.value\n : sectionDef.contracts || {};\n const contractDefs = [];\n const contractKeys = [];\n for (const [rawKey, contract] of Object.entries(rawContractsMap)) {\n if (\n rawKey === 'type' ||\n rawKey === 'keyType' ||\n rawKey === 'valueType' ||\n rawKey === 'description'\n ) {\n continue;\n }\n const key = toText(rawKey);\n if (!key) {\n issues.push(label + ' contract key is missing');\n continue;\n }\n if (!contract) {\n issues.push(label + ' contract ' + key + ' is missing or invalid');\n continue;\n }\n if (!hasType(contract)) {\n issues.push(label + ' contract ' + key + ' is missing type');\n }\n contractDefs.push({ key, contract });\n contractKeys.push(key);\n }\n\n if (!hasType(section)) {\n issues.push(label + ' section ' + sectionKey + ' is missing type');\n }\n\n const related = section.relatedContracts\n ? uniqueKeys(asList(section.relatedContracts), label + ' section ' + sectionKey + ' relatedContracts')\n : null;\n if (related && !sameStringSet(related, contractKeys)) {\n issues.push(label + ' section ' + sectionKey + ' relatedContracts must match contracts');\n }\n\n const normalizedRelated = related || contractKeys;\n const normalizedSection = Object.assign({}, section, {\n type: 'Conversation/Document Section',\n relatedContracts: normalizedRelated\n });\n\n return {\n sectionKey,\n section: normalizedSection,\n contractDefs,\n contractKeys\n };\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = new Set();\nconst seenContractKeys = new Set();\n\nconst addList = asList(requestSectionChanges.add);\nconst modifyList = asList(requestSectionChanges.modify);\nconst removeList = asList(requestSectionChanges.remove);\n\nfor (const entry of addList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.add');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n if (contracts[sectionKey]) {\n issues.push('section key already exists at /contracts/' + sectionKey);\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contracts[contractKey]) {\n issues.push('contract key already exists at /contracts/' + contractKey);\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nfor (const entry of modifyList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.modify');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n } else if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n }\n\n const existingRelated =\n existingSection && existingSection.relatedContracts\n ? asList(existingSection.relatedContracts)\n : [];\n if (existingSection && !existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n const op = contracts[contractDef.key] ? 'replace' : 'add';\n sectionChangeset.push({\n op,\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n\n const toRemove = uniqueKeys(existingRelated, 'sectionChanges.modify remove list').filter(\n (key) => !normalized.contractKeys.includes(key)\n );\n for (const contractKey of toRemove) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n\n sectionChangeset.push({\n op: 'replace',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nconst removeKeys = uniqueKeys(removeList, 'sectionChanges.remove');\nfor (const sectionKey of removeKeys) {\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n continue;\n }\n if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n continue;\n }\n\n const related = existingSection.relatedContracts\n ? uniqueKeys(asList(existingSection.relatedContracts), 'sectionChanges.remove relatedContracts')\n : [];\n if (!existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of related) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(sectionKey)\n });\n}\nconst combinedChangeset = sectionChangeset.concat(hasChangeset ? requestChangeset : []);\n\nif (combinedChangeset.length === 0) {\n issues.push('no changes provided');\n}\n\nif (issues.length > 0) {\n return {\n changeset: [],\n events: [\n {\n type: \"Conversation/Proposed Change Invalid\",\n reason: issues.join('; ')\n }\n ]\n }\n}\n\nreturn {\n changeset: combinedChangeset\n};\n";
|
|
16
|
+
readonly value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst isArray = Array.isArray;\n\nconst change = event.message.request;\n\nconst summary = change?.summary;\nif (!summary || typeof summary !== 'string') {\n return invalid('summary is missing');\n}\n\nconst requestChangeset = isArray(change?.changeset) ? change.changeset : [];\nconst sectionChanges = change.sectionChanges;\n\nconst entryPath = (entry) => `${entry?.path || ''}`;\nconst isContractsPath = (p) => p === '/contracts' || p.startsWith('/contracts/');\nconst isProposedChangePath = (p) => p.startsWith('/proposedChange');\n\nconst contracts = document('/contracts') || {};\nconst policy = Object.values(contracts).find((c) => c?.requireSectionChanges !== undefined);\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (\n policyEnabled &&\n requestChangeset.some((e) => isContractsPath(entryPath(e)))\n) {\n return invalid('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n}\n\nif (requestChangeset.some((e) => isProposedChangePath(entryPath(e)))) {\n return invalid('changeset cannot modify /proposedChange');\n}\n\nconst escapePointer = (value) =>\n `${value}`.split('~').join('~0').split('/').join('~1');\n\nconst contractPtr = (key) => '/contracts/' + escapePointer(key);\n\nconst isMetaKey = (key) =>\n key === 'type' || key === 'keyType' || key === 'valueType' || key === 'description';\n\nconst contractKeysFromMap = (contractsMap) =>\n Object.keys(contractsMap || {}).filter((k) => !isMetaKey(k));\n\nconst normalizeSection = (section, contractKeys) => ({\n ...(section || {}),\n type: 'Conversation/Document Section',\n relatedContracts: (section?.relatedContracts?.length ? section.relatedContracts : contractKeys)\n});\n\nconst hasMatchingRelatedContracts = (section, contractKeys) => {\n const related = isArray(section?.relatedContracts)\n ? section.relatedContracts.map((value) => `${value}`)\n : [];\n if (!related.length) {\n return true;\n }\n if (related.length !== contractKeys.length) {\n return false;\n }\n const relatedMap = {};\n for (const value of related) {\n const key = `${value}`;\n relatedMap[key] = (relatedMap[key] || 0) + 1;\n }\n if (Object.keys(relatedMap).length !== contractKeys.length) {\n return false;\n }\n for (const key of contractKeys) {\n if (!relatedMap[key]) {\n return false;\n }\n }\n return true;\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = {};\nconst seenContractKeys = {};\nconst existingContractKeys = {};\nfor (const key of Object.keys(contracts || {}).filter((k) => !isMetaKey(k))) {\n existingContractKeys[key] = true;\n}\n\nconst trackSectionKey = (sectionKey) => {\n if (seenSectionKeys[sectionKey]) {\n return invalid(`section key duplicated in sectionChanges: ${sectionKey}`);\n }\n seenSectionKeys[sectionKey] = true;\n return null;\n};\n\nconst trackContractKey = (sectionKey, contractKey) => {\n const existingSection = seenContractKeys[contractKey];\n if (existingSection && existingSection !== sectionKey) {\n return invalid(`contract key used by multiple sections in request: ${contractKey}`);\n }\n seenContractKeys[contractKey] = sectionKey;\n return null;\n};\n\nconst addList = isArray(sectionChanges?.add) ? sectionChanges.add : [];\nfor (const entry of addList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.add is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n if (existingContractKeys[sectionKey]) {\n return invalid(`contract key already exists at ${contractPtr(sectionKey)}`);\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n if (existingContractKeys[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst modifyList = isArray(sectionChanges?.modify) ? sectionChanges.modify : [];\nfor (const entry of modifyList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.modify is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n const existingRelated = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts.map((value) => `${value}`)\n : [];\n const existingRelatedMap = {};\n for (const value of existingRelated) {\n existingRelatedMap[`${value}`] = true;\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n if (existingContractKeys[key] && !existingRelatedMap[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n for (const oldKey of existingRelated) {\n if (contractKeys.indexOf(oldKey) === -1) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(oldKey) });\n }\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst removeList = isArray(sectionChanges?.remove) ? sectionChanges.remove : [];\nfor (const entry of removeList) {\n const sectionKey = `${entry?.sectionKey || entry || ''}`;\n if (!sectionKey) return invalid('sectionChanges.remove is missing sectionKey');\n\n const related = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts\n : [];\n\n for (const key of related) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(key) });\n }\n sectionChangeset.push({ op: 'remove', path: contractPtr(sectionKey) });\n}\n\nconst combined = sectionChangeset.concat(requestChangeset);\n\nif (combined.length === 0) {\n return invalid('no changes provided');\n}\n\nreturn { changeset: combined };\n";
|
|
17
17
|
};
|
|
18
18
|
readonly name: "Prepare";
|
|
19
19
|
readonly type: {
|
|
@@ -4,7 +4,7 @@ export const ChangeWorkflow = {
|
|
|
4
4
|
request: {
|
|
5
5
|
description: 'Expected request payload for this workflow.',
|
|
6
6
|
type: {
|
|
7
|
-
blueId: '
|
|
7
|
+
blueId: 'FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG',
|
|
8
8
|
},
|
|
9
9
|
},
|
|
10
10
|
steps: {
|
|
@@ -14,7 +14,7 @@ export const ChangeWorkflow = {
|
|
|
14
14
|
type: {
|
|
15
15
|
blueId: 'DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K',
|
|
16
16
|
},
|
|
17
|
-
value: "const issues = [];\n\nconst request = event.message.request || {};\n\nconst changeDescription = request.changeDescription;\nconst rawChangeset = request.changeset;\nconst rawSectionChanges = request.sectionChanges;\nconst requestSectionChanges = rawSectionChanges || {};\n\nconst toText = (value) => {\n const raw = value && value.value ? value.value : value;\n return raw && raw.trim ? raw.trim() : '';\n};\nconst asList = (value) => Array.isArray(value) ? value : [];\nconst hasType = (value) => value && value.type;\nconst escapePointer = (value) => {\n const text = toText(value);\n return text.split('~').join('~0').split('/').join('~1');\n};\nconst requestChangeset = asList(rawChangeset);\n\nconst uniqueKeys = (values, label) => {\n const seen = new Set();\n const output = [];\n for (const value of values) {\n const key = toText(value);\n if (!key) {\n issues.push(label + ' contains invalid key');\n continue;\n }\n if (seen.has(key)) {\n issues.push(label + ' contains duplicate key: ' + key);\n continue;\n }\n seen.add(key);\n output.push(key);\n }\n return output;\n};\n\nconst sameStringSet = (left, right) => {\n if (left.length !== right.length) return false;\n const set = new Set(left);\n if (set.size !== right.length) return false;\n for (const value of right) {\n if (!set.has(value)) return false;\n }\n return true;\n};\n\nconst contracts = Object(document('/contracts') || {});\n\nconst isDocumentSection = (contract) =>\n !!contract && Array.isArray(contract.relatedContracts);\n\nconst isContractsChangePolicy = (contract) => {\n if (!contract) return false;\n return 'requireSectionChanges' in contract;\n};\n\nconst findPolicy = () => {\n for (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isContractsChangePolicy(contract)) {\n return contract;\n }\n }\n return null;\n};\n\nconst policy = findPolicy();\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (!toText(changeDescription)) {\n issues.push('changeDescription is missing');\n}\n\nconst hasChangeset = !!rawChangeset;\nconst hasSectionChanges = !!rawSectionChanges;\n\nif (!hasChangeset && !hasSectionChanges) {\n issues.push('changeset or sectionChanges is required');\n}\n\nconst isContractsPath = (path) => {\n const value = toText(path);\n return value === '/contracts' || value.startsWith('/contracts/');\n};\nif (policyEnabled && hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isContractsPath(entry.path)) {\n issues.push('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n break;\n }\n }\n}\nconst isProposedChangePath = (path) =>\n toText(path).startsWith('/proposedChange');\nif (hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isProposedChangePath(entry.path)) {\n issues.push('changeset cannot modify /proposedChange');\n break;\n }\n }\n}\n\nconst existingSections = {};\nfor (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isDocumentSection(contract)) {\n existingSections[key] = contract;\n }\n}\n\nconst contractIndex = {};\nfor (const sectionKey of Object.keys(existingSections)) {\n const section = existingSections[sectionKey];\n const related = asList(section.relatedContracts);\n for (const relatedKey of related) {\n const contractKey = toText(relatedKey);\n if (!contractKey) continue;\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n contractIndex[contractKey] = null;\n } else if (!contractIndex[contractKey]) {\n contractIndex[contractKey] = sectionKey;\n }\n }\n}\n\nconst normalizeSectionDefinition = (sectionDef, label) => {\n if (!sectionDef) {\n issues.push(label + ' entry must be an object');\n return null;\n }\n const sectionKey = toText(sectionDef.sectionKey);\n if (!sectionKey) {\n issues.push(label + ' sectionKey is missing');\n return null;\n }\n const section = sectionDef.section;\n if (!section) {\n issues.push(label + ' section is missing');\n return null;\n }\n\n const rawContractsMap = sectionDef.contracts && sectionDef.contracts.value\n ? sectionDef.contracts.value\n : sectionDef.contracts || {};\n const contractDefs = [];\n const contractKeys = [];\n for (const [rawKey, contract] of Object.entries(rawContractsMap)) {\n if (\n rawKey === 'type' ||\n rawKey === 'keyType' ||\n rawKey === 'valueType' ||\n rawKey === 'description'\n ) {\n continue;\n }\n const key = toText(rawKey);\n if (!key) {\n issues.push(label + ' contract key is missing');\n continue;\n }\n if (!contract) {\n issues.push(label + ' contract ' + key + ' is missing or invalid');\n continue;\n }\n if (!hasType(contract)) {\n issues.push(label + ' contract ' + key + ' is missing type');\n }\n contractDefs.push({ key, contract });\n contractKeys.push(key);\n }\n\n if (!hasType(section)) {\n issues.push(label + ' section ' + sectionKey + ' is missing type');\n }\n\n const related = section.relatedContracts\n ? uniqueKeys(asList(section.relatedContracts), label + ' section ' + sectionKey + ' relatedContracts')\n : null;\n if (related && !sameStringSet(related, contractKeys)) {\n issues.push(label + ' section ' + sectionKey + ' relatedContracts must match contracts');\n }\n\n const normalizedRelated = related || contractKeys;\n const normalizedSection = Object.assign({}, section, {\n type: 'Conversation/Document Section',\n relatedContracts: normalizedRelated\n });\n\n return {\n sectionKey,\n section: normalizedSection,\n contractDefs,\n contractKeys\n };\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = new Set();\nconst seenContractKeys = new Set();\n\nconst addList = asList(requestSectionChanges.add);\nconst modifyList = asList(requestSectionChanges.modify);\nconst removeList = asList(requestSectionChanges.remove);\n\nfor (const entry of addList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.add');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n if (contracts[sectionKey]) {\n issues.push('section key already exists at /contracts/' + sectionKey);\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contracts[contractKey]) {\n issues.push('contract key already exists at /contracts/' + contractKey);\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nfor (const entry of modifyList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.modify');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n } else if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n }\n\n const existingRelated =\n existingSection && existingSection.relatedContracts\n ? asList(existingSection.relatedContracts)\n : [];\n if (existingSection && !existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n const op = contracts[contractDef.key] ? 'replace' : 'add';\n sectionChangeset.push({\n op,\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n\n const toRemove = uniqueKeys(existingRelated, 'sectionChanges.modify remove list').filter(\n (key) => !normalized.contractKeys.includes(key)\n );\n for (const contractKey of toRemove) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n\n sectionChangeset.push({\n op: 'replace',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nconst removeKeys = uniqueKeys(removeList, 'sectionChanges.remove');\nfor (const sectionKey of removeKeys) {\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n continue;\n }\n if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n continue;\n }\n\n const related = existingSection.relatedContracts\n ? uniqueKeys(asList(existingSection.relatedContracts), 'sectionChanges.remove relatedContracts')\n : [];\n if (!existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of related) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(sectionKey)\n });\n}\nconst combinedChangeset = sectionChangeset.concat(hasChangeset ? requestChangeset : []);\n\nif (combinedChangeset.length === 0) {\n issues.push('no changes provided');\n}\n\nif (issues.length > 0) {\n return {\n changeset: [],\n events: [\n {\n type: \"Conversation/Proposed Change Invalid\",\n reason: issues.join('; ')\n }\n ]\n }\n}\n\nreturn {\n changeset: combinedChangeset\n};\n",
|
|
17
|
+
value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst isArray = Array.isArray;\n\nconst change = event.message.request;\n\nconst summary = change?.summary;\nif (!summary || typeof summary !== 'string') {\n return invalid('summary is missing');\n}\n\nconst requestChangeset = isArray(change?.changeset) ? change.changeset : [];\nconst sectionChanges = change.sectionChanges;\n\nconst entryPath = (entry) => `${entry?.path || ''}`;\nconst isContractsPath = (p) => p === '/contracts' || p.startsWith('/contracts/');\nconst isProposedChangePath = (p) => p.startsWith('/proposedChange');\n\nconst contracts = document('/contracts') || {};\nconst policy = Object.values(contracts).find((c) => c?.requireSectionChanges !== undefined);\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (\n policyEnabled &&\n requestChangeset.some((e) => isContractsPath(entryPath(e)))\n) {\n return invalid('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n}\n\nif (requestChangeset.some((e) => isProposedChangePath(entryPath(e)))) {\n return invalid('changeset cannot modify /proposedChange');\n}\n\nconst escapePointer = (value) =>\n `${value}`.split('~').join('~0').split('/').join('~1');\n\nconst contractPtr = (key) => '/contracts/' + escapePointer(key);\n\nconst isMetaKey = (key) =>\n key === 'type' || key === 'keyType' || key === 'valueType' || key === 'description';\n\nconst contractKeysFromMap = (contractsMap) =>\n Object.keys(contractsMap || {}).filter((k) => !isMetaKey(k));\n\nconst normalizeSection = (section, contractKeys) => ({\n ...(section || {}),\n type: 'Conversation/Document Section',\n relatedContracts: (section?.relatedContracts?.length ? section.relatedContracts : contractKeys)\n});\n\nconst hasMatchingRelatedContracts = (section, contractKeys) => {\n const related = isArray(section?.relatedContracts)\n ? section.relatedContracts.map((value) => `${value}`)\n : [];\n if (!related.length) {\n return true;\n }\n if (related.length !== contractKeys.length) {\n return false;\n }\n const relatedMap = {};\n for (const value of related) {\n const key = `${value}`;\n relatedMap[key] = (relatedMap[key] || 0) + 1;\n }\n if (Object.keys(relatedMap).length !== contractKeys.length) {\n return false;\n }\n for (const key of contractKeys) {\n if (!relatedMap[key]) {\n return false;\n }\n }\n return true;\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = {};\nconst seenContractKeys = {};\nconst existingContractKeys = {};\nfor (const key of Object.keys(contracts || {}).filter((k) => !isMetaKey(k))) {\n existingContractKeys[key] = true;\n}\n\nconst trackSectionKey = (sectionKey) => {\n if (seenSectionKeys[sectionKey]) {\n return invalid(`section key duplicated in sectionChanges: ${sectionKey}`);\n }\n seenSectionKeys[sectionKey] = true;\n return null;\n};\n\nconst trackContractKey = (sectionKey, contractKey) => {\n const existingSection = seenContractKeys[contractKey];\n if (existingSection && existingSection !== sectionKey) {\n return invalid(`contract key used by multiple sections in request: ${contractKey}`);\n }\n seenContractKeys[contractKey] = sectionKey;\n return null;\n};\n\nconst addList = isArray(sectionChanges?.add) ? sectionChanges.add : [];\nfor (const entry of addList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.add is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n if (existingContractKeys[sectionKey]) {\n return invalid(`contract key already exists at ${contractPtr(sectionKey)}`);\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n if (existingContractKeys[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst modifyList = isArray(sectionChanges?.modify) ? sectionChanges.modify : [];\nfor (const entry of modifyList) {\n const sectionKey = `${entry?.sectionKey || ''}`;\n if (!sectionKey) return invalid('sectionChanges.modify is missing sectionKey');\n\n const sectionKeyDup = trackSectionKey(sectionKey);\n if (sectionKeyDup) return sectionKeyDup;\n\n const existingRelated = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts.map((value) => `${value}`)\n : [];\n const existingRelatedMap = {};\n for (const value of existingRelated) {\n existingRelatedMap[`${value}`] = true;\n }\n\n const contractsMap = entry?.contracts || {};\n const contractKeys = contractKeysFromMap(contractsMap).map((key) => `${key}`);\n\n if (!hasMatchingRelatedContracts(entry?.section, contractKeys)) {\n return invalid('relatedContracts must match contracts');\n }\n\n for (const key of contractKeys) {\n const dup = trackContractKey(sectionKey, key);\n if (dup) return dup;\n if (existingContractKeys[key] && !existingRelatedMap[key]) {\n return invalid(`contract key already exists at ${contractPtr(key)}`);\n }\n }\n\n for (const key of contractKeys) {\n sectionChangeset.push({ op: 'add', path: contractPtr(key), val: contractsMap[key] });\n }\n\n for (const oldKey of existingRelated) {\n if (contractKeys.indexOf(oldKey) === -1) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(oldKey) });\n }\n }\n\n sectionChangeset.push({\n op: 'add',\n path: contractPtr(sectionKey),\n val: normalizeSection(entry?.section, contractKeys)\n });\n}\n\nconst removeList = isArray(sectionChanges?.remove) ? sectionChanges.remove : [];\nfor (const entry of removeList) {\n const sectionKey = `${entry?.sectionKey || entry || ''}`;\n if (!sectionKey) return invalid('sectionChanges.remove is missing sectionKey');\n\n const related = isArray(contracts?.[sectionKey]?.relatedContracts)\n ? contracts[sectionKey].relatedContracts\n : [];\n\n for (const key of related) {\n sectionChangeset.push({ op: 'remove', path: contractPtr(key) });\n }\n sectionChangeset.push({ op: 'remove', path: contractPtr(sectionKey) });\n}\n\nconst combined = sectionChangeset.concat(requestChangeset);\n\nif (combined.length === 0) {\n return invalid('no changes provided');\n}\n\nreturn { changeset: combined };\n",
|
|
18
18
|
},
|
|
19
19
|
name: 'Prepare',
|
|
20
20
|
type: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/ChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,WAAW,EAAE,4DAA4D;IACzE,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE;QACP,WAAW,EAAE,6CAA6C;QAC1D,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH,
|
|
1
|
+
{"version":3,"file":"ChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/ChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,WAAW,EAAE,4DAA4D;IACzE,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE;QACP,WAAW,EAAE,6CAA6C;QAC1D,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH,g1NAAg1N;iBACn1N;gBACD,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;YACD;gBACE,SAAS,EAAE;oBACT,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EAAE,4BAA4B;iBACpC;gBACD,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;SACF;KACF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,8CAA8C;KACvD;CACO,CAAC"}
|
|
@@ -3,7 +3,7 @@ export declare const ProposeChangeOperation: {
|
|
|
3
3
|
readonly name: "Propose Change Operation";
|
|
4
4
|
readonly request: {
|
|
5
5
|
readonly type: {
|
|
6
|
-
readonly blueId: "
|
|
6
|
+
readonly blueId: "FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG";
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
readonly type: {
|
|
@@ -10,7 +10,7 @@ export declare const ProposeChangeWorkflow: {
|
|
|
10
10
|
readonly request: {
|
|
11
11
|
readonly description: "Expected request payload for this workflow.";
|
|
12
12
|
readonly type: {
|
|
13
|
-
readonly blueId: "
|
|
13
|
+
readonly blueId: "FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG";
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
16
|
readonly steps: {
|
|
@@ -19,7 +19,7 @@ export declare const ProposeChangeWorkflow: {
|
|
|
19
19
|
readonly type: {
|
|
20
20
|
readonly blueId: "DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K";
|
|
21
21
|
};
|
|
22
|
-
readonly value: "const issues = [];\n\nconst request = event.message.request || {};\n\nconst changeDescription = request.changeDescription;\nconst rawChangeset = request.changeset;\nconst rawSectionChanges = request.sectionChanges;\nconst requestSectionChanges = rawSectionChanges || {};\n\nconst toText = (value) => {\n const raw = value && value.value ? value.value : value;\n return raw && raw.trim ? raw.trim() : '';\n};\nconst asList = (value) => Array.isArray(value) ? value : [];\nconst hasType = (value) => value && value.type;\nconst escapePointer = (value) => {\n const text = toText(value);\n return text.split('~').join('~0').split('/').join('~1');\n};\nconst requestChangeset = asList(rawChangeset);\n\nconst uniqueKeys = (values, label) => {\n const seen = new Set();\n const output = [];\n for (const value of values) {\n const key = toText(value);\n if (!key) {\n issues.push(label + ' contains invalid key');\n continue;\n }\n if (seen.has(key)) {\n issues.push(label + ' contains duplicate key: ' + key);\n continue;\n }\n seen.add(key);\n output.push(key);\n }\n return output;\n};\n\nconst sameStringSet = (left, right) => {\n if (left.length !== right.length) return false;\n const set = new Set(left);\n if (set.size !== right.length) return false;\n for (const value of right) {\n if (!set.has(value)) return false;\n }\n return true;\n};\n\nconst contracts = Object(document('/contracts') || {});\n\nconst isDocumentSection = (contract) =>\n !!contract && Array.isArray(contract.relatedContracts);\n\nconst isContractsChangePolicy = (contract) => {\n if (!contract) return false;\n return 'requireSectionChanges' in contract;\n};\n\nconst findPolicy = () => {\n for (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isContractsChangePolicy(contract)) {\n return contract;\n }\n }\n return null;\n};\n\nconst policy = findPolicy();\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (!toText(changeDescription)) {\n issues.push('changeDescription is missing');\n}\n\nconst hasChangeset = !!rawChangeset;\nconst hasSectionChanges = !!rawSectionChanges;\n\nif (!hasChangeset && !hasSectionChanges) {\n issues.push('changeset or sectionChanges is required');\n}\n\nconst isContractsPath = (path) => {\n const value = toText(path);\n return value === '/contracts' || value.startsWith('/contracts/');\n};\nif (policyEnabled && hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isContractsPath(entry.path)) {\n issues.push('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n break;\n }\n }\n}\nconst isProposedChangePath = (path) =>\n toText(path).startsWith('/proposedChange');\nif (hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isProposedChangePath(entry.path)) {\n issues.push('changeset cannot modify /proposedChange');\n break;\n }\n }\n}\n\nconst existingSections = {};\nfor (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isDocumentSection(contract)) {\n existingSections[key] = contract;\n }\n}\n\nconst contractIndex = {};\nfor (const sectionKey of Object.keys(existingSections)) {\n const section = existingSections[sectionKey];\n const related = asList(section.relatedContracts);\n for (const relatedKey of related) {\n const contractKey = toText(relatedKey);\n if (!contractKey) continue;\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n contractIndex[contractKey] = null;\n } else if (!contractIndex[contractKey]) {\n contractIndex[contractKey] = sectionKey;\n }\n }\n}\n\nconst normalizeSectionDefinition = (sectionDef, label) => {\n if (!sectionDef) {\n issues.push(label + ' entry must be an object');\n return null;\n }\n const sectionKey = toText(sectionDef.sectionKey);\n if (!sectionKey) {\n issues.push(label + ' sectionKey is missing');\n return null;\n }\n const section = sectionDef.section;\n if (!section) {\n issues.push(label + ' section is missing');\n return null;\n }\n\n const rawContractsMap = sectionDef.contracts && sectionDef.contracts.value\n ? sectionDef.contracts.value\n : sectionDef.contracts || {};\n const contractDefs = [];\n const contractKeys = [];\n for (const [rawKey, contract] of Object.entries(rawContractsMap)) {\n if (\n rawKey === 'type' ||\n rawKey === 'keyType' ||\n rawKey === 'valueType' ||\n rawKey === 'description'\n ) {\n continue;\n }\n const key = toText(rawKey);\n if (!key) {\n issues.push(label + ' contract key is missing');\n continue;\n }\n if (!contract) {\n issues.push(label + ' contract ' + key + ' is missing or invalid');\n continue;\n }\n if (!hasType(contract)) {\n issues.push(label + ' contract ' + key + ' is missing type');\n }\n contractDefs.push({ key, contract });\n contractKeys.push(key);\n }\n\n if (!hasType(section)) {\n issues.push(label + ' section ' + sectionKey + ' is missing type');\n }\n\n const related = section.relatedContracts\n ? uniqueKeys(asList(section.relatedContracts), label + ' section ' + sectionKey + ' relatedContracts')\n : null;\n if (related && !sameStringSet(related, contractKeys)) {\n issues.push(label + ' section ' + sectionKey + ' relatedContracts must match contracts');\n }\n\n const normalizedRelated = related || contractKeys;\n const normalizedSection = Object.assign({}, section, {\n type: 'Conversation/Document Section',\n relatedContracts: normalizedRelated\n });\n\n return {\n sectionKey,\n section: normalizedSection,\n contractDefs,\n contractKeys\n };\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = new Set();\nconst seenContractKeys = new Set();\n\nconst addList = asList(requestSectionChanges.add);\nconst modifyList = asList(requestSectionChanges.modify);\nconst removeList = asList(requestSectionChanges.remove);\n\nfor (const entry of addList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.add');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n if (contracts[sectionKey]) {\n issues.push('section key already exists at /contracts/' + sectionKey);\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contracts[contractKey]) {\n issues.push('contract key already exists at /contracts/' + contractKey);\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nfor (const entry of modifyList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.modify');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n } else if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n }\n\n const existingRelated =\n existingSection && existingSection.relatedContracts\n ? asList(existingSection.relatedContracts)\n : [];\n if (existingSection && !existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n const op = contracts[contractDef.key] ? 'replace' : 'add';\n sectionChangeset.push({\n op,\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n\n const toRemove = uniqueKeys(existingRelated, 'sectionChanges.modify remove list').filter(\n (key) => !normalized.contractKeys.includes(key)\n );\n for (const contractKey of toRemove) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n\n sectionChangeset.push({\n op: 'replace',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nconst removeKeys = uniqueKeys(removeList, 'sectionChanges.remove');\nfor (const sectionKey of removeKeys) {\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n continue;\n }\n if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n continue;\n }\n\n const related = existingSection.relatedContracts\n ? uniqueKeys(asList(existingSection.relatedContracts), 'sectionChanges.remove relatedContracts')\n : [];\n if (!existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of related) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(sectionKey)\n });\n}\nconst combinedChangeset = sectionChangeset.concat(hasChangeset ? requestChangeset : []);\n\nif (combinedChangeset.length === 0) {\n issues.push('no changes provided');\n}\n\nif (issues.length > 0) {\n return {\n changeset: [],\n events: [\n {\n type: \"Conversation/Proposed Change Invalid\",\n reason: issues.join('; ')\n }\n ]\n }\n}\n\nconst postfixValue = currentContract.postfix || '';\nconst path = '/proposedChange' + postfixValue;\n\nif (document(path)) {\n return {\n changeset: [],\n events: [\n {\n type: \"Conversation/Proposed Change Invalid\",\n reason: \"Can not propose change when it already exists at \" + path\n }\n ]\n }\n}\n\nconst proposedPayload = {\n changeDescription\n};\n\nproposedPayload.preparedChangeset = combinedChangeset;\n\nif (hasChangeset) {\n proposedPayload.changeset = requestChangeset;\n}\n\nconst hasSectionChangesData = addList.length || modifyList.length || removeList.length;\nif (hasSectionChangesData) {\n proposedPayload.sectionChanges = rawSectionChanges;\n}\n\nreturn {\n changeset: [{\n op: 'add',\n path,\n val: proposedPayload\n }]\n};\n";
|
|
22
|
+
readonly value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst request = event.message.request;\n\nconst summary = request?.summary;\nif (!summary || typeof summary !== 'string') {\n return invalid('summary is missing');\n}\n\nconst postfixValue = currentContract?.postfix || '';\nconst path = '/proposedChange' + postfixValue;\n\nif (document(path)) {\n return invalid('proposed change already exists at ' + path);\n}\n\nreturn {\n changeset: [{ op: 'add', path, val: request }]\n};\n";
|
|
23
23
|
};
|
|
24
24
|
readonly name: "Prepare";
|
|
25
25
|
readonly type: {
|
|
@@ -10,7 +10,7 @@ export const ProposeChangeWorkflow = {
|
|
|
10
10
|
request: {
|
|
11
11
|
description: 'Expected request payload for this workflow.',
|
|
12
12
|
type: {
|
|
13
|
-
blueId: '
|
|
13
|
+
blueId: 'FW7iYkzig4fepCdwfCdgNJw4DQ1fKwnAUf3YpjgfTPmG',
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
16
|
steps: {
|
|
@@ -20,7 +20,7 @@ export const ProposeChangeWorkflow = {
|
|
|
20
20
|
type: {
|
|
21
21
|
blueId: 'DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K',
|
|
22
22
|
},
|
|
23
|
-
value: "const issues = [];\n\nconst request = event.message.request || {};\n\nconst changeDescription = request.changeDescription;\nconst rawChangeset = request.changeset;\nconst rawSectionChanges = request.sectionChanges;\nconst requestSectionChanges = rawSectionChanges || {};\n\nconst toText = (value) => {\n const raw = value && value.value ? value.value : value;\n return raw && raw.trim ? raw.trim() : '';\n};\nconst asList = (value) => Array.isArray(value) ? value : [];\nconst hasType = (value) => value && value.type;\nconst escapePointer = (value) => {\n const text = toText(value);\n return text.split('~').join('~0').split('/').join('~1');\n};\nconst requestChangeset = asList(rawChangeset);\n\nconst uniqueKeys = (values, label) => {\n const seen = new Set();\n const output = [];\n for (const value of values) {\n const key = toText(value);\n if (!key) {\n issues.push(label + ' contains invalid key');\n continue;\n }\n if (seen.has(key)) {\n issues.push(label + ' contains duplicate key: ' + key);\n continue;\n }\n seen.add(key);\n output.push(key);\n }\n return output;\n};\n\nconst sameStringSet = (left, right) => {\n if (left.length !== right.length) return false;\n const set = new Set(left);\n if (set.size !== right.length) return false;\n for (const value of right) {\n if (!set.has(value)) return false;\n }\n return true;\n};\n\nconst contracts = Object(document('/contracts') || {});\n\nconst isDocumentSection = (contract) =>\n !!contract && Array.isArray(contract.relatedContracts);\n\nconst isContractsChangePolicy = (contract) => {\n if (!contract) return false;\n return 'requireSectionChanges' in contract;\n};\n\nconst findPolicy = () => {\n for (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isContractsChangePolicy(contract)) {\n return contract;\n }\n }\n return null;\n};\n\nconst policy = findPolicy();\nconst policyEnabled = !!policy && policy.requireSectionChanges !== false;\n\nif (!toText(changeDescription)) {\n issues.push('changeDescription is missing');\n}\n\nconst hasChangeset = !!rawChangeset;\nconst hasSectionChanges = !!rawSectionChanges;\n\nif (!hasChangeset && !hasSectionChanges) {\n issues.push('changeset or sectionChanges is required');\n}\n\nconst isContractsPath = (path) => {\n const value = toText(path);\n return value === '/contracts' || value.startsWith('/contracts/');\n};\nif (policyEnabled && hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isContractsPath(entry.path)) {\n issues.push('changeset cannot modify /contracts when Contracts Change Policy is enabled');\n break;\n }\n }\n}\nconst isProposedChangePath = (path) =>\n toText(path).startsWith('/proposedChange');\nif (hasChangeset) {\n for (const entry of requestChangeset) {\n if (entry && isProposedChangePath(entry.path)) {\n issues.push('changeset cannot modify /proposedChange');\n break;\n }\n }\n}\n\nconst existingSections = {};\nfor (const key of Object.keys(contracts)) {\n const contract = contracts[key];\n if (isDocumentSection(contract)) {\n existingSections[key] = contract;\n }\n}\n\nconst contractIndex = {};\nfor (const sectionKey of Object.keys(existingSections)) {\n const section = existingSections[sectionKey];\n const related = asList(section.relatedContracts);\n for (const relatedKey of related) {\n const contractKey = toText(relatedKey);\n if (!contractKey) continue;\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n contractIndex[contractKey] = null;\n } else if (!contractIndex[contractKey]) {\n contractIndex[contractKey] = sectionKey;\n }\n }\n}\n\nconst normalizeSectionDefinition = (sectionDef, label) => {\n if (!sectionDef) {\n issues.push(label + ' entry must be an object');\n return null;\n }\n const sectionKey = toText(sectionDef.sectionKey);\n if (!sectionKey) {\n issues.push(label + ' sectionKey is missing');\n return null;\n }\n const section = sectionDef.section;\n if (!section) {\n issues.push(label + ' section is missing');\n return null;\n }\n\n const rawContractsMap = sectionDef.contracts && sectionDef.contracts.value\n ? sectionDef.contracts.value\n : sectionDef.contracts || {};\n const contractDefs = [];\n const contractKeys = [];\n for (const [rawKey, contract] of Object.entries(rawContractsMap)) {\n if (\n rawKey === 'type' ||\n rawKey === 'keyType' ||\n rawKey === 'valueType' ||\n rawKey === 'description'\n ) {\n continue;\n }\n const key = toText(rawKey);\n if (!key) {\n issues.push(label + ' contract key is missing');\n continue;\n }\n if (!contract) {\n issues.push(label + ' contract ' + key + ' is missing or invalid');\n continue;\n }\n if (!hasType(contract)) {\n issues.push(label + ' contract ' + key + ' is missing type');\n }\n contractDefs.push({ key, contract });\n contractKeys.push(key);\n }\n\n if (!hasType(section)) {\n issues.push(label + ' section ' + sectionKey + ' is missing type');\n }\n\n const related = section.relatedContracts\n ? uniqueKeys(asList(section.relatedContracts), label + ' section ' + sectionKey + ' relatedContracts')\n : null;\n if (related && !sameStringSet(related, contractKeys)) {\n issues.push(label + ' section ' + sectionKey + ' relatedContracts must match contracts');\n }\n\n const normalizedRelated = related || contractKeys;\n const normalizedSection = Object.assign({}, section, {\n type: 'Conversation/Document Section',\n relatedContracts: normalizedRelated\n });\n\n return {\n sectionKey,\n section: normalizedSection,\n contractDefs,\n contractKeys\n };\n};\n\nconst sectionChangeset = [];\nconst seenSectionKeys = new Set();\nconst seenContractKeys = new Set();\n\nconst addList = asList(requestSectionChanges.add);\nconst modifyList = asList(requestSectionChanges.modify);\nconst removeList = asList(requestSectionChanges.remove);\n\nfor (const entry of addList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.add');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n if (contracts[sectionKey]) {\n issues.push('section key already exists at /contracts/' + sectionKey);\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contracts[contractKey]) {\n issues.push('contract key already exists at /contracts/' + contractKey);\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n sectionChangeset.push({\n op: 'add',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nfor (const entry of modifyList) {\n const normalized = normalizeSectionDefinition(entry, 'sectionChanges.modify');\n if (!normalized) continue;\n const sectionKey = normalized.sectionKey;\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n } else if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n }\n\n const existingRelated =\n existingSection && existingSection.relatedContracts\n ? asList(existingSection.relatedContracts)\n : [];\n if (existingSection && !existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of normalized.contractKeys) {\n if (seenContractKeys.has(contractKey)) {\n issues.push('contract key used by multiple sections in request: ' + contractKey);\n continue;\n }\n seenContractKeys.add(contractKey);\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n }\n }\n\n for (const contractDef of normalized.contractDefs) {\n const op = contracts[contractDef.key] ? 'replace' : 'add';\n sectionChangeset.push({\n op,\n path: '/contracts/' + escapePointer(contractDef.key),\n val: contractDef.contract\n });\n }\n\n const toRemove = uniqueKeys(existingRelated, 'sectionChanges.modify remove list').filter(\n (key) => !normalized.contractKeys.includes(key)\n );\n for (const contractKey of toRemove) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n\n sectionChangeset.push({\n op: 'replace',\n path: '/contracts/' + escapePointer(sectionKey),\n val: normalized.section\n });\n}\n\nconst removeKeys = uniqueKeys(removeList, 'sectionChanges.remove');\nfor (const sectionKey of removeKeys) {\n if (seenSectionKeys.has(sectionKey)) {\n issues.push('section key duplicated in sectionChanges: ' + sectionKey);\n continue;\n }\n seenSectionKeys.add(sectionKey);\n\n const existingSection = contracts[sectionKey];\n if (!existingSection) {\n issues.push('section key does not exist at /contracts/' + sectionKey);\n continue;\n }\n if (!isDocumentSection(existingSection)) {\n issues.push('existing section at /contracts/' + sectionKey + ' is not a Document Section');\n continue;\n }\n\n const related = existingSection.relatedContracts\n ? uniqueKeys(asList(existingSection.relatedContracts), 'sectionChanges.remove relatedContracts')\n : [];\n if (!existingSection.relatedContracts) {\n issues.push('existing section ' + sectionKey + ' is missing relatedContracts');\n }\n\n for (const contractKey of related) {\n if (contractIndex[contractKey] && contractIndex[contractKey] !== sectionKey) {\n issues.push('contract key ' + contractKey + ' is linked to another section');\n continue;\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(contractKey)\n });\n }\n sectionChangeset.push({\n op: 'remove',\n path: '/contracts/' + escapePointer(sectionKey)\n });\n}\nconst combinedChangeset = sectionChangeset.concat(hasChangeset ? requestChangeset : []);\n\nif (combinedChangeset.length === 0) {\n issues.push('no changes provided');\n}\n\nif (issues.length > 0) {\n return {\n changeset: [],\n events: [\n {\n type: \"Conversation/Proposed Change Invalid\",\n reason: issues.join('; ')\n }\n ]\n }\n}\n\nconst postfixValue = currentContract.postfix || '';\nconst path = '/proposedChange' + postfixValue;\n\nif (document(path)) {\n return {\n changeset: [],\n events: [\n {\n type: \"Conversation/Proposed Change Invalid\",\n reason: \"Can not propose change when it already exists at \" + path\n }\n ]\n }\n}\n\nconst proposedPayload = {\n changeDescription\n};\n\nproposedPayload.preparedChangeset = combinedChangeset;\n\nif (hasChangeset) {\n proposedPayload.changeset = requestChangeset;\n}\n\nconst hasSectionChangesData = addList.length || modifyList.length || removeList.length;\nif (hasSectionChangesData) {\n proposedPayload.sectionChanges = rawSectionChanges;\n}\n\nreturn {\n changeset: [{\n op: 'add',\n path,\n val: proposedPayload\n }]\n};\n",
|
|
23
|
+
value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst request = event.message.request;\n\nconst summary = request?.summary;\nif (!summary || typeof summary !== 'string') {\n return invalid('summary is missing');\n}\n\nconst postfixValue = currentContract?.postfix || '';\nconst path = '/proposedChange' + postfixValue;\n\nif (document(path)) {\n return invalid('proposed change already exists at ' + path);\n}\n\nreturn {\n changeset: [{ op: 'add', path, val: request }]\n};\n",
|
|
24
24
|
},
|
|
25
25
|
name: 'Prepare',
|
|
26
26
|
type: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProposeChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/ProposeChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,WAAW,EAAE,0DAA0D;IACvE,IAAI,EAAE,yBAAyB;IAC/B,OAAO,EAAE;QACP,WAAW,EACT,iEAAiE;QACnE,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,OAAO,EAAE;QACP,WAAW,EAAE,6CAA6C;QAC1D,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH
|
|
1
|
+
{"version":3,"file":"ProposeChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/ProposeChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,WAAW,EAAE,0DAA0D;IACvE,IAAI,EAAE,yBAAyB;IAC/B,OAAO,EAAE;QACP,WAAW,EACT,iEAAiE;QACnE,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,OAAO,EAAE;QACP,WAAW,EAAE,6CAA6C;QAC1D,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH,gjBAAgjB;iBACnjB;gBACD,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;YACD;gBACE,SAAS,EAAE;oBACT,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EAAE,4BAA4B;iBACpC;gBACD,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;SACF;KACF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,8CAA8C;KACvD;CACO,CAAC"}
|
|
@@ -13,7 +13,7 @@ export declare const RejectChangeWorkflow: {
|
|
|
13
13
|
readonly type: {
|
|
14
14
|
readonly blueId: "DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K";
|
|
15
15
|
};
|
|
16
|
-
readonly value: "const
|
|
16
|
+
readonly value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst postfixValue = currentContract?.postfix || '';\nconst path = '/proposedChange' + postfixValue;\n\nif (!document(path)) {\n return invalid('no proposed change at ' + path);\n}\n\nreturn {\n changeset: [{ op: 'remove', path }]\n};\n";
|
|
17
17
|
};
|
|
18
18
|
readonly name: "Prepare";
|
|
19
19
|
readonly type: {
|
|
@@ -14,7 +14,7 @@ export const RejectChangeWorkflow = {
|
|
|
14
14
|
type: {
|
|
15
15
|
blueId: 'DLRQwz7MQeCrzjy9bohPNwtCxKEBbKaMK65KBrwjfG6K',
|
|
16
16
|
},
|
|
17
|
-
value: "const
|
|
17
|
+
value: "const invalid = (reason) => ({\n changeset: [],\n events: [{ type: 'Conversation/Proposed Change Invalid', reason }]\n});\n\nconst postfixValue = currentContract?.postfix || '';\nconst path = '/proposedChange' + postfixValue;\n\nif (!document(path)) {\n return invalid('no proposed change at ' + path);\n}\n\nreturn {\n changeset: [{ op: 'remove', path }]\n};\n",
|
|
18
18
|
},
|
|
19
19
|
name: 'Prepare',
|
|
20
20
|
type: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RejectChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/RejectChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW,EACT,uEAAuE;IACzE,IAAI,EAAE,wBAAwB;IAC9B,OAAO,EAAE;QACP,WAAW,EACT,iEAAiE;QACnE,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH
|
|
1
|
+
{"version":3,"file":"RejectChangeWorkflow.js","sourceRoot":"","sources":["../../../../src/packages/conversation/contents/RejectChangeWorkflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW,EACT,uEAAuE;IACzE,IAAI,EAAE,wBAAwB;IAC9B,OAAO,EAAE;QACP,WAAW,EACT,iEAAiE;QACnE,IAAI,EAAE;YACJ,MAAM,EAAE,8CAA8C;SACvD;KACF;IACD,KAAK,EAAE;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EACH,+WAA+W;iBAClX;gBACD,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;YACD;gBACE,SAAS,EAAE;oBACT,IAAI,EAAE;wBACJ,MAAM,EAAE,8CAA8C;qBACvD;oBACD,KAAK,EAAE,4BAA4B;iBACpC;gBACD,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE;oBACJ,MAAM,EAAE,8CAA8C;iBACvD;aACF;SACF;KACF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,8CAA8C;KACvD;CACO,CAAC"}
|