From 664ad7752857d6f91bf176ab683ae1f40011f750 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 19 Nov 2024 21:18:32 +0000 Subject: [PATCH 01/90] Linting setup --- package-lock.json | 1587 +++++++++++++++++-- packages/fdc3-agent-proxy/eslint.config.mjs | 12 + packages/fdc3-agent-proxy/package.json | 10 +- packages/fdc3-context/package.json | 1 + packages/fdc3-get-agent/eslint.config.mjs | 12 + packages/fdc3-get-agent/package.json | 9 +- 6 files changed, 1528 insertions(+), 103 deletions(-) create mode 100644 packages/fdc3-agent-proxy/eslint.config.mjs create mode 100644 packages/fdc3-get-agent/eslint.config.mjs diff --git a/package-lock.json b/package-lock.json index 5b94e2954..73a23ce61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,8 @@ "toolbox/fdc3-for-web/fdc3-web-impl", "packages/fdc3-get-agent", "packages/fdc3", - "toolbox/fdc3-for-web/demo", "toolbox/fdc3-for-web/reference-ui", + "toolbox/fdc3-for-web/demo", "toolbox/fdc3-workbench" ], "dependencies": { @@ -2671,6 +2671,14 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/@eslint/js": { + "version": "9.14.0", + "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/object-schema": { "version": "2.1.4", "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", @@ -2775,11 +2783,12 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.13.0", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", + "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -3345,6 +3354,7 @@ "node_modules/@kite9/fdc3-common": { "version": "2.2.0-beta.6", "integrity": "sha512-JQa8WVXWIpHQRMt9CFsxqjfrw2Rq4tVUT8R6r2cJAg1y1Ns+zmpclo/bGi3DVqFyd5PfOEbbiAER/1ll0PXb3A==", + "dev": true, "dependencies": { "@kite9/fdc3": "2.2.0-beta.6" } @@ -3352,6 +3362,7 @@ "node_modules/@kite9/fdc3-common/node_modules/@kite9/fdc3": { "version": "2.2.0-beta.6", "integrity": "sha512-F/fC4Ayp3uBzhBs4x5rp8n4/JSbuGaAHdrfrm/HTipDqsQKdQon4uZsNdMK6USTX1gnpFVy8luSnIddFJey12g==", + "dev": true, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "4.14.1" } @@ -3362,6 +3373,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -7114,15 +7126,16 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "8.57.1", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -7439,6 +7452,7 @@ "node_modules/eslint/node_modules/@eslint/eslintrc": { "version": "2.1.4", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -7458,8 +7472,9 @@ } }, "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "8.57.1", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -7467,6 +7482,7 @@ "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7481,6 +7497,7 @@ "node_modules/eslint/node_modules/espree": { "version": "9.6.1", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "peer": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -7496,6 +7513,7 @@ "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -7510,6 +7528,7 @@ "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -7520,6 +7539,7 @@ "node_modules/eslint/node_modules/globals": { "version": "13.24.0", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -7532,11 +7552,13 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "peer": true }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -7550,6 +7572,7 @@ "node_modules/eslint/node_modules/p-limit": { "version": "3.1.0", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -7563,6 +7586,7 @@ "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -7576,6 +7600,7 @@ "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "peer": true, "engines": { "node": ">=10" }, @@ -14461,6 +14486,224 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.14.0", + "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.14.0", + "@typescript-eslint/parser": "8.14.0", + "@typescript-eslint/utils": "8.14.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.14.0", + "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/type-utils": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.14.0", + "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.14.0", + "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.14.0", + "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.14.0", + "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.14.0", + "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.14.0", + "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.14.0", + "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.14.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/minimatch": { + "version": "9.0.5", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typical": { "version": "4.0.0", "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", @@ -15689,6 +15932,7 @@ } }, "packages/fdc3": { + "name": "@kite9/fdc3", "version": "2.2.0-beta.29", "license": "Apache-2.0", "dependencies": { @@ -15699,6 +15943,7 @@ } }, "packages/fdc3-agent-proxy": { + "name": "@kite9/fdc3-agent-proxy", "version": "2.2.0-beta.29", "license": "Apache-2.0", "dependencies": { @@ -15708,6 +15953,7 @@ "@cucumber/cucumber": "10.3.1", "@cucumber/html-formatter": "11.0.4", "@cucumber/pretty-formatter": "1.0.1", + "@eslint/js": "^9.14.0", "@kite9/testing": "2.2.0-beta.29", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", @@ -15716,11 +15962,12 @@ "@typescript-eslint/eslint-plugin": "7.1.1", "@typescript-eslint/parser": "7.1.0", "cucumber-console-formatter": "1.0.0", - "eslint": "8.57.0", + "eslint": "^9.14.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", "expect": "^29.7.0", + "globals": "^15.12.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", "nyc": "15.1.0", @@ -15729,58 +15976,277 @@ "ts-node": "^10.9.2", "tsx": "^4.19.1", "typescript": "^5.6.3", + "typescript-eslint": "^8.14.0", "uuid": "^9.0.1" } }, - "packages/fdc3-context": { - "version": "2.2.0-beta.29", - "license": "Apache-2.0", - "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", - "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-jest": "28.8.3", - "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", - "quicktype": "23.0.78", - "rimraf": "^6.0.1", - "ts-jest": "29.2.5", - "tslib": "^2.7.0", - "typescript": "~5.5.0" - } - }, - "packages/fdc3-context/node_modules/@eslint/js": { - "version": "9.12.0", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", + "packages/fdc3-agent-proxy/node_modules/@eslint/core": { + "version": "0.7.0", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "packages/fdc3-context/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.9.0", - "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==", + "packages/fdc3-agent-proxy/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/type-utils": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18.18" }, "funding": { - "type": "opencollective", + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "packages/fdc3-agent-proxy/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/fdc3-agent-proxy/node_modules/eslint": { + "version": "9.14.0", + "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.14.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "packages/fdc3-agent-proxy/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/fdc3-agent-proxy/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/fdc3-agent-proxy/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "packages/fdc3-agent-proxy/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-agent-proxy/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "packages/fdc3-agent-proxy/node_modules/glob-parent": { + "version": "6.0.2", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "packages/fdc3-agent-proxy/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "packages/fdc3-agent-proxy/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-agent-proxy/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-agent-proxy/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-context": { + "name": "@kite9/fdc3-context", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", + "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.12.0", + "@types/jest": "29.5.13", + "@typescript-eslint/eslint-plugin": "8.9.0", + "@typescript-eslint/parser": "8.9.0", + "eslint": "9.12.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-jest": "28.8.3", + "eslint-plugin-jsx-a11y": "^6.10.0", + "globals": "^15.11.0", + "mkdirp": "^3.0.1", + "quicktype": "23.0.78", + "rimraf": "^6.0.1", + "ts-jest": "29.2.5", + "tslib": "^2.7.0", + "typescript": "~5.5.0" + } + }, + "packages/fdc3-context/node_modules/@eslint/js": { + "version": "9.12.0", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/fdc3-context/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.9.0", + "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.9.0", + "@typescript-eslint/type-utils": "8.9.0", + "@typescript-eslint/utils": "8.9.0", + "@typescript-eslint/visitor-keys": "8.9.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { @@ -16125,6 +16591,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/fdc3-context/node_modules/mkdirp": { + "version": "3.0.1", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/fdc3-context/node_modules/p-limit": { "version": "3.1.0", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", @@ -16166,6 +16646,7 @@ } }, "packages/fdc3-get-agent": { + "name": "@kite9/fdc3-get-agent", "version": "2.2.0-beta.29", "license": "Apache-2.0", "dependencies": { @@ -16178,36 +16659,257 @@ }, "devDependencies": { "@cucumber/cucumber": "10.3.1", + "@eslint/js": "^9.14.0", "@kite9/fdc3-web-impl": "2.2.0-beta.29", "@kite9/testing": "2.2.0-beta.29", "@types/node": "^20.14.11", "@types/wtfnode": "^0.7.3", + "eslint": "^9.14.0", "expect": "^29.7.0", + "globals": "^15.12.0", "jsonpath-plus": "^10.1.0", "nyc": "15.1.0", "rimraf": "^6.0.1", "tsx": "^4.19.1", "typescript": "^5.6.3", + "typescript-eslint": "^8.14.0", "wtfnode": "^0.9.3" } }, - "packages/fdc3-schema": { - "version": "2.2.0-beta.29", - "license": "Apache-2.0", - "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", - "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-jest": "28.8.3", - "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", - "quicktype": "23.0.78", - "rimraf": "^6.0.1", - "ts-jest": "29.2.5", + "packages/fdc3-get-agent/node_modules/@eslint/core": { + "version": "0.7.0", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/fdc3-get-agent/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "packages/fdc3-get-agent/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/fdc3-get-agent/node_modules/eslint": { + "version": "9.14.0", + "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.14.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "packages/fdc3-get-agent/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/fdc3-get-agent/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/fdc3-get-agent/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "packages/fdc3-get-agent/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-get-agent/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "packages/fdc3-get-agent/node_modules/glob-parent": { + "version": "6.0.2", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "packages/fdc3-get-agent/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "packages/fdc3-get-agent/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-get-agent/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-get-agent/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/fdc3-schema": { + "name": "@kite9/fdc3-schema", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", + "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.12.0", + "@types/jest": "29.5.13", + "@typescript-eslint/eslint-plugin": "8.9.0", + "@typescript-eslint/parser": "8.9.0", + "eslint": "9.12.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-jest": "28.8.3", + "eslint-plugin-jsx-a11y": "^6.10.0", + "globals": "^15.11.0", + "quicktype": "23.0.78", + "rimraf": "^6.0.1", + "ts-jest": "29.2.5", "ts-morph": "^24.0.0", "tslib": "^2.7.0", "typescript": "~5.5.0" @@ -16626,6 +17328,7 @@ } }, "packages/fdc3-standard": { + "name": "@kite9/fdc3-standard", "version": "2.2.0-beta.29", "license": "Apache-2.0", "dependencies": { @@ -17068,6 +17771,7 @@ } }, "packages/testing": { + "name": "@kite9/testing", "version": "2.2.0-beta.29", "license": "Apache-2.0", "dependencies": { @@ -17100,40 +17804,270 @@ "uuid": "^9.0.1" } }, - "toolbox/fdc3-for-web/demo": { - "version": "2.2.0-beta.29", + "packages/testing/node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29", - "@types/uuid": "^10.0.0", - "@types/ws": "^8.5.12", - "express": "^4.21.1", - "socket.io": "^4.8.0", - "socket.io-client": "^4.8.0", - "tsx": "^4.19.1", - "typescript": "^5.6.3", - "uuid": "^9.0.1", - "vite-express": "^0.15.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/node": "^20.16.11", - "nodemon": "^3.1.7", - "rimraf": "^6.0.1", - "vite": "^5.4.9" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "toolbox/fdc3-for-web/fdc3-web-impl": { - "version": "2.2.0-beta.29", - "license": "Apache-2.0", + "packages/testing/node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29", - "@types/uuid": "^10.0.0", - "uuid": "^9.0.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "devDependencies": { - "@cucumber/cucumber": "10.3.1", - "@cucumber/html-formatter": "11.0.4", - "@cucumber/pretty-formatter": "1.0.1", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/testing/node_modules/@eslint/js": { + "version": "8.57.0", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "packages/testing/node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "packages/testing/node_modules/eslint": { + "version": "8.57.0", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/testing/node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/testing/node_modules/espree": { + "version": "9.6.1", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/testing/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/testing/node_modules/glob-parent": { + "version": "6.0.2", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "packages/testing/node_modules/globals": { + "version": "13.24.0", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/testing/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "packages/testing/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/testing/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/testing/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/testing/node_modules/type-fest": { + "version": "0.20.2", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-for-web/demo": { + "name": "@kite9/demo", + "version": "2.2.0-beta.29", + "dependencies": { + "@kite9/fdc3": "2.2.0-beta.29", + "@types/uuid": "^10.0.0", + "@types/ws": "^8.5.12", + "express": "^4.21.1", + "socket.io": "^4.8.0", + "socket.io-client": "^4.8.0", + "tsx": "^4.19.1", + "typescript": "^5.6.3", + "uuid": "^9.0.1", + "vite-express": "^0.15.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.16.11", + "nodemon": "^3.1.7", + "rimraf": "^6.0.1", + "vite": "^5.4.9" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl": { + "name": "@kite9/fdc3-web-impl", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", + "dependencies": { + "@kite9/fdc3-standard": "2.2.0-beta.29", + "@types/uuid": "^10.0.0", + "uuid": "^9.0.1" + }, + "devDependencies": { + "@cucumber/cucumber": "10.3.1", + "@cucumber/html-formatter": "11.0.4", + "@cucumber/pretty-formatter": "1.0.1", "@kite9/fdc3-common": "2.2.0-beta.6", "@kite9/testing": "2.2.0-beta.29", "@types/expect": "24.3.0", @@ -17159,10 +18093,239 @@ "uuid": "^9.0.1" } }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@eslint/js": { + "version": "8.57.0", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/eslint": { + "version": "8.57.0", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/espree": { + "version": "9.6.1", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/glob-parent": { + "version": "6.0.2", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/globals": { + "version": "13.24.0", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/type-fest": { + "version": "0.20.2", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "toolbox/fdc3-for-web/reference-ui": { + "name": "fdc3-for-web-reference-ui", "version": "2.1.1", "dependencies": { - "@kite9/fdc3-common": "2.2.0-beta.6" + "@kite9/fdc3": "2.2.0-beta.29" }, "devDependencies": { "typescript": "^5.3.2", @@ -17206,6 +18369,234 @@ "vite": "^5.4.9", "web-vitals": "^1.1.2" } + }, + "toolbox/fdc3-workbench/node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "toolbox/fdc3-workbench/node_modules/@eslint/js": { + "version": "8.57.0", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "toolbox/fdc3-workbench/node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "toolbox/fdc3-workbench/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "toolbox/fdc3-workbench/node_modules/eslint": { + "version": "8.57.0", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "toolbox/fdc3-workbench/node_modules/espree": { + "version": "9.6.1", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "toolbox/fdc3-workbench/node_modules/find-up": { + "version": "5.0.0", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-workbench/node_modules/glob-parent": { + "version": "6.0.2", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "toolbox/fdc3-workbench/node_modules/globals": { + "version": "13.24.0", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-workbench/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "toolbox/fdc3-workbench/node_modules/locate-path": { + "version": "6.0.0", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-workbench/node_modules/p-limit": { + "version": "3.1.0", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-workbench/node_modules/p-locate": { + "version": "5.0.0", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "toolbox/fdc3-workbench/node_modules/type-fest": { + "version": "0.20.2", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/packages/fdc3-agent-proxy/eslint.config.mjs b/packages/fdc3-agent-proxy/eslint.config.mjs new file mode 100644 index 000000000..e64ccc5a4 --- /dev/null +++ b/packages/fdc3-agent-proxy/eslint.config.mjs @@ -0,0 +1,12 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; + + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + {files: ["**/*.{js,mjs,cjs,ts}"]}, + {languageOptions: { globals: globals.browser }}, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, +]; \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/package.json b/packages/fdc3-agent-proxy/package.json index 39a13b5db..f98e6cb07 100644 --- a/packages/fdc3-agent-proxy/package.json +++ b/packages/fdc3-agent-proxy/package.json @@ -19,7 +19,8 @@ "scripts": { "build": "tsc --module es2022", "test": "tsc && nyc --reporter=lcov --reporter=text --reporter json cucumber-js", - "clean": "rimraf dist cucumber-report.html coverage .nyc_output node_modules test-results.xml" + "clean": "rimraf dist cucumber-report.html coverage .nyc_output node_modules test-results.xml", + "lint": "eslint src/" }, "dependencies": { "@kite9/fdc3-standard": "2.2.0-beta.29" @@ -28,6 +29,7 @@ "@cucumber/cucumber": "10.3.1", "@cucumber/html-formatter": "11.0.4", "@cucumber/pretty-formatter": "1.0.1", + "@eslint/js": "^9.14.0", "@kite9/testing": "2.2.0-beta.29", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", @@ -36,11 +38,12 @@ "@typescript-eslint/eslint-plugin": "7.1.1", "@typescript-eslint/parser": "7.1.0", "cucumber-console-formatter": "1.0.0", - "eslint": "8.57.0", + "eslint": "^9.14.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", "expect": "^29.7.0", + "globals": "^15.12.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", "nyc": "15.1.0", @@ -49,6 +52,7 @@ "ts-node": "^10.9.2", "tsx": "^4.19.1", "typescript": "^5.6.3", + "typescript-eslint": "^8.14.0", "uuid": "^9.0.1" } -} \ No newline at end of file +} diff --git a/packages/fdc3-context/package.json b/packages/fdc3-context/package.json index 4128c9871..d66d48f38 100644 --- a/packages/fdc3-context/package.json +++ b/packages/fdc3-context/package.json @@ -36,6 +36,7 @@ "eslint-plugin-jest": "28.8.3", "eslint-plugin-jsx-a11y": "^6.10.0", "globals": "^15.11.0", + "mkdirp": "^3.0.1", "quicktype": "23.0.78", "rimraf": "^6.0.1", "ts-jest": "29.2.5", diff --git a/packages/fdc3-get-agent/eslint.config.mjs b/packages/fdc3-get-agent/eslint.config.mjs new file mode 100644 index 000000000..e64ccc5a4 --- /dev/null +++ b/packages/fdc3-get-agent/eslint.config.mjs @@ -0,0 +1,12 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; + + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + {files: ["**/*.{js,mjs,cjs,ts}"]}, + {languageOptions: { globals: globals.browser }}, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, +]; \ No newline at end of file diff --git a/packages/fdc3-get-agent/package.json b/packages/fdc3-get-agent/package.json index f5242bfb0..495b5c65c 100644 --- a/packages/fdc3-get-agent/package.json +++ b/packages/fdc3-get-agent/package.json @@ -19,7 +19,8 @@ "scripts": { "build": "tsc --module es2022", "test": "tsc && nyc --reporter=lcov --reporter=text --reporter json cucumber-js", - "clean": "rimraf dist cucumber-report.html coverage .nyc_output node_modules test-results.xml" + "clean": "rimraf dist cucumber-report.html coverage .nyc_output node_modules test-results.xml", + "lint": "eslint src/" }, "dependencies": { "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", @@ -31,16 +32,20 @@ }, "devDependencies": { "@cucumber/cucumber": "10.3.1", + "@eslint/js": "^9.14.0", "@kite9/fdc3-web-impl": "2.2.0-beta.29", "@kite9/testing": "2.2.0-beta.29", "@types/node": "^20.14.11", "@types/wtfnode": "^0.7.3", + "eslint": "^9.14.0", "expect": "^29.7.0", + "globals": "^15.12.0", "jsonpath-plus": "^10.1.0", "nyc": "15.1.0", "rimraf": "^6.0.1", "tsx": "^4.19.1", "typescript": "^5.6.3", + "typescript-eslint": "^8.14.0", "wtfnode": "^0.9.3" } -} \ No newline at end of file +} From 3dd0fd2895ff12a286d5728bfbf0361625d728c6 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 19 Nov 2024 21:26:57 +0000 Subject: [PATCH 02/90] WIP GetAgent refactor --- .../fdc3-agent-proxy/src/BasicDesktopAgent.ts | 17 +- packages/fdc3-agent-proxy/src/Messaging.ts | 107 +- .../src/handshake/DefaultHandshakeSupport.ts | 2 +- .../src/handshake/HandshakeSupport.ts | 2 +- .../src/intents/DefaultIntentSupport.ts | 1 - .../src/listeners/DefaultIntentListener.ts | 2 +- .../src/messaging/AbstractMessaging.ts | 238 +- .../src/messaging/AbstractWebMessaging.ts | 179 +- .../src/messaging/MessagePortMessaging.ts | 18 +- .../src/messaging/message-port.ts | 49 +- .../src/sessionStorage/DesktopAgentDetails.ts | 66 + .../strategies/DesktopAgentPreloadLoader.ts | 53 + .../src/strategies/ElectronEventLoader.ts | 36 - .../src/strategies/FailoverHandler.ts | 104 + .../src/strategies/HelloHandler.ts | 149 + .../strategies/IdentityValidationHandler.ts | 127 + .../fdc3-get-agent/src/strategies/Loader.ts | 33 +- .../src/strategies/PostMessageLoader.ts | 217 +- .../src/strategies/TimeoutLoader.ts | 16 +- .../fdc3-get-agent/src/strategies/getAgent.ts | 152 +- .../fdc3-schema/generated/api/BrowserTypes.ts | 3874 +++++------ .../generated/bridging/BridgingTypes.ts | 6058 ++++++++++++++++- .../fdc3-schema/schemas/api/api.schema.json | 2 +- .../fdc3UserInterfaceHandshake.schema.json | 2 +- .../schemas/api/getInfoRequest.schema.json | 2 +- .../schemas/api/t2sQuicktypeUtil.js | 69 + .../schemas/bridging/common.schema.json | 4 +- packages/fdc3-standard/src/api/GetAgent.ts | 6 +- packages/fdc3-standard/src/ui/Connectable.ts | 2 + .../reference-ui/src/channel_selector.ts | 2 +- 30 files changed, 9132 insertions(+), 2457 deletions(-) create mode 100644 packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts create mode 100644 packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts delete mode 100644 packages/fdc3-get-agent/src/strategies/ElectronEventLoader.ts create mode 100644 packages/fdc3-get-agent/src/strategies/FailoverHandler.ts create mode 100644 packages/fdc3-get-agent/src/strategies/HelloHandler.ts create mode 100644 packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts create mode 100644 packages/fdc3-schema/schemas/api/t2sQuicktypeUtil.js diff --git a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts index 9fd77be3f..caad91ea0 100644 --- a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts +++ b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts @@ -35,7 +35,22 @@ export class BasicDesktopAgent implements DesktopAgent, Connectable { } async getInfo(): Promise { - return this.handshake.getImplementationMetadata() + let impl = await this.handshake.getImplementationMetadata(); + //handle potential null during start-up + //TODO: introduce queuing to prevent early calls + if (!impl) { + impl = { + fdc3Version: "unknown", + provider: "unknown", + optionalFeatures: { + OriginatingAppMetadata: false, + UserChannelMembershipAPIs: false, + DesktopAgentBridging: false + }, + appMetadata: {appId: "unknown"} + }; + } + return impl; } async broadcast(context: Context): Promise { diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index fe56809dc..500653631 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -1,50 +1,61 @@ -import { Connectable, AppIdentifier, ImplementationMetadata } from "@kite9/fdc3-standard"; -import { RegisterableListener } from "./listeners/RegisterableListener"; -import { AddContextListenerRequestMeta } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; +import { Connectable, AppIdentifier, ImplementationMetadata } from '@kite9/fdc3-standard'; +import { RegisterableListener } from './listeners/RegisterableListener'; +import { + AppRequestMessage, + AgentResponseMessage, + WebConnectionProtocolMessage +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export interface Messaging extends Connectable { - - /** - * Source for outgoing message - */ - getSource(): AppIdentifier - - /** - * UUID for outgoing message - */ - createUUID(): string; - - /** - * Post an outgoing message - */ - post(message: object): Promise - - /** - * Registers a listener for incoming messages. - */ - register(l: RegisterableListener): void - - /** - * Unregisters a listener with the id given above - * @param id - */ - unregister(id: string): void - - createMeta(): AddContextListenerRequestMeta - - /** - * Waits for a specific matching message - */ - waitFor(filter: (m: any) => boolean, timeoutErrorMessage?: string): Promise - - /** - * - * @param message Performs a request / response message pass - */ - exchange(message: object, expectedTypeName: string, timeoutErrorMessage?: string): Promise - - /** - * Implementation metadata retrieved through the validation process - */ - getImplementationMetadata(): Promise -} \ No newline at end of file + /** + * Source information to apply to outgoing messages + */ + getSource(): AppIdentifier | null; + + /** + * UUID for outgoing message + */ + createUUID(): string; + + /** + * Post an outgoing message + */ + post(message: object): Promise; + + /** + * Registers a listener for incoming messages. + */ + register(l: RegisterableListener): void; + + /** + * Unregisters a listener with the id given above + * @param id + */ + unregister(id: string): void; + + createMeta(): AppRequestMessage['meta']; + + /** + * Waits for a specific matching message + */ + waitFor( + filter: (m: WebConnectionProtocolMessage | AgentResponseMessage) => boolean, + timeoutErrorMessage?: string + ): Promise; + + /** + * + * @param message Performs a request / response message pass + */ + exchange(message: object, expectedTypeName: string, timeoutErrorMessage?: string): Promise; + + /** + * Implementation metadata retrieved through the validation process + */ + getImplementationMetadata(): Promise; + + /** + * App identification retrieved through the validation process + */ + getAppIdentifier(): Promise; +} diff --git a/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts b/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts index 8a82715f8..68ebcb22b 100644 --- a/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts +++ b/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts @@ -34,7 +34,7 @@ export class DefaultHandshakeSupport implements HandshakeSupport { return this.messaging.disconnect() } - async getImplementationMetadata(): Promise { + async getImplementationMetadata(): Promise { return this.messaging.getImplementationMetadata() } diff --git a/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts b/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts index 913f08273..0d3f0318f 100644 --- a/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts +++ b/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts @@ -6,5 +6,5 @@ import { ImplementationMetadata, Connectable } from "@kite9/fdc3-standard" */ export interface HandshakeSupport extends Connectable { - getImplementationMetadata(): Promise + getImplementationMetadata(): Promise } \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index b981e1d94..43482705e 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -96,7 +96,6 @@ export class DefaultIntentSupport implements IntentSupport { (m.type == 'raiseIntentResultResponse') && (m.meta.requestUuid == messageOut.meta.requestUuid))) - const ir = await convertIntentResult(rp, this.messaging) return ir } diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts index fe9799ec9..58e6e8c86 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts @@ -49,7 +49,7 @@ export class DefaultIntentListener extends AbstractListener { payload: { intentResolution: { intent: m.payload.intent, - source: this.messaging.getSource() + source: this.messaging.getSource()! } } }; diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index b0ecbef53..8da054ce9 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -1,156 +1,100 @@ -import { AppIdentifier, ImplementationMetadata, GetAgentParams } from "@kite9/fdc3-standard"; -import { Messaging } from "../Messaging"; -import { RegisterableListener } from "../listeners/RegisterableListener"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { AddContextListenerRequestMeta } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; - - -type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity -type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse +import { AppIdentifier, ImplementationMetadata } from '@kite9/fdc3-standard'; +import { Messaging } from '../Messaging'; +import { RegisterableListener } from '../listeners/RegisterableListener'; +import { + AgentResponseMessage, + isAgentResponseMessage, + WebConnectionProtocolMessage, + AppRequestMessage +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export abstract class AbstractMessaging implements Messaging { - - private readonly options: GetAgentParams - private readonly connectionAttemptUuid: string - private readonly timeout: number - private readonly actualUrl: string - private appId: AppIdentifier | null = null - private implementationMetadata: ImplementationMetadata | null = null - - abstract createUUID(): string - abstract post(message: object): Promise - - abstract register(l: RegisterableListener): void - abstract unregister(id: string): void - - abstract createMeta(): AddContextListenerRequestMeta - - constructor(options: GetAgentParams, connectionAttemptUuid: string, actualUrl: string, timeout: number = 10016) { - this.options = options - this.connectionAttemptUuid = connectionAttemptUuid - this.timeout = timeout - this.actualUrl = actualUrl - } - - getSource(): AppIdentifier { - return this.appId!! - } - - waitFor(filter: (m: any) => boolean, timeoutErrorMessage?: string): Promise { - const id = this.createUUID() - return new Promise((resolve, reject) => { - var done = false; - const l: RegisterableListener = { - id, - filter: filter, - action: (m) => { - done = true - this.unregister(id) - resolve(m) - } - } as RegisterableListener - - - this.register(l); - - if (timeoutErrorMessage) { - setTimeout(() => { - this.unregister(id) - if (!done) { - console.error(`Rejecting after ${this.timeout}ms with ${timeoutErrorMessage}`) - reject(new Error(timeoutErrorMessage)) - } - }, this.timeout); - } - - }) - } - - - async exchange(message: any, expectedTypeName: string, timeoutErrorMessage?: string): Promise { - const errorMessage = timeoutErrorMessage ?? `Timeout waiting for ${expectedTypeName} with requestUuid ${message.meta.requestUuid}` - const prom = this.waitFor(m => - (m.type == expectedTypeName) - && (m.meta.requestUuid == message.meta.requestUuid), errorMessage) - this.post(message) - const out: any = await prom - if (out?.payload?.error) { - throw new Error(out.payload.error) - } else { - return out - } - } - - /** - * This handles the verify exchange with the da-server, - */ - async connect(): Promise { - const validationResponse = await this.exchangeValidationWithId( - this.createValidationMessage(), - this.connectionAttemptUuid - ) - - this.appId = { - appId: validationResponse.payload.appId, - instanceId: validationResponse.payload.instanceId - } - - this.implementationMetadata = validationResponse.payload.implementationMetadata - - this.storeInstanceUuid(validationResponse) - } - - async disconnect(): Promise { - this.appId = null; - this.implementationMetadata = null; + private appIdentifier: AppIdentifier | null = null; + private implementationMetadata: ImplementationMetadata | null = null; + + abstract createUUID(): string; + abstract post(message: object): Promise; + + abstract register(l: RegisterableListener): void; + abstract unregister(id: string): void; + + abstract createMeta(): AppRequestMessage['meta']; + + abstract getTimeoutMs(): number; + + constructor() {} + + getSource(): AppIdentifier | null { + return this.appIdentifier; + } + + waitFor( + filter: (m: WebConnectionProtocolMessage | AgentResponseMessage) => boolean, + timeoutErrorMessage?: string + ): Promise { + const id = this.createUUID(); + return new Promise((resolve, reject) => { + var done = false; + const l: RegisterableListener = { + id, + filter: filter, + action: m => { + done = true; + this.unregister(id); + resolve(m); + }, + } as RegisterableListener; + + this.register(l); + + if (timeoutErrorMessage) { + setTimeout(() => { + this.unregister(id); + if (!done) { + console.error(`Rejecting after ${this.getTimeoutMs()}ms with ${timeoutErrorMessage}`); + reject(new Error(timeoutErrorMessage)); + } + }, this.getTimeoutMs()); + } + }); + } + + async exchange(message: any, expectedTypeName: string, timeoutErrorMessage?: string): Promise { + const errorMessage = + timeoutErrorMessage ?? `Timeout waiting for ${expectedTypeName} with requestUuid ${message.meta.requestUuid}`; + const prom = this.waitFor((m) => { + if (isAgentResponseMessage(m)) { + return m.type == expectedTypeName && m.meta.requestUuid == message.meta.requestUuid; + } else { + return false; + } + }, errorMessage); + this.post(message); + const out: any = await prom; + if (out?.payload?.error) { + throw new Error(out.payload.error); + } else { + return out; } + } - getImplementationMetadata(): Promise { - return Promise.resolve(this.implementationMetadata!!) - } + async getImplementationMetadata(): Promise { + return this.implementationMetadata; + } - private async exchangeValidationWithId(message: any, connectionAttemptUuid: string): Promise { - const prom = this.waitFor(m => - (m.meta.connectionAttemptUuid == connectionAttemptUuid)) - this.post(message) - const out: any = await prom - if (out?.payload?.message) { - throw new Error(out.payload.message) - } else { - return out - } - } + setImplementationMetadata(impl: ImplementationMetadata | null) { + this.implementationMetadata = impl; + } - /** - * Sends the validate message through the nmessage port - */ - private createValidationMessage(): WebConnectionProtocol4ValidateAppIdentity { - var instanceUuid = this.retrieveInstanceUuid() - - const requestMessage: WebConnectionProtocol4ValidateAppIdentity = { - type: 'WCP4ValidateAppIdentity', - meta: { - connectionAttemptUuid: this.connectionAttemptUuid, - timestamp: new Date() - }, - payload: { - identityUrl: this.options.identityUrl!!, - actualUrl: this.actualUrl, - instanceUuid - } - } - - return requestMessage - } + async getAppIdentifier(): Promise { + return this.appIdentifier; + } - /** - * Used for restoring session details in case of reload - */ - abstract retrieveInstanceUuid(): string | undefined + setAppIdentifier(ident: AppIdentifier | null) { + this.appIdentifier = ident; + } - /** - * Used for caching session details in case of reload - */ - abstract storeInstanceUuid(validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): void + abstract connect(): Promise; -} \ No newline at end of file + abstract disconnect(): Promise; +} diff --git a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts index b1ff8ee15..37ecf511a 100644 --- a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts @@ -1,65 +1,152 @@ -import { DesktopAgentDetails, WebDesktopAgentType, GetAgentParams, } from "@kite9/fdc3-standard"; -import { RegisterableListener, AbstractMessaging } from "@kite9/fdc3-agent-proxy"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { AddContextListenerRequestMeta } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse +import { DesktopAgentDetails, WebDesktopAgentType, GetAgentParams, AppIdentifier, DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX } from '@kite9/fdc3-standard'; +import { RegisterableListener, AbstractMessaging } from '@kite9/fdc3-agent-proxy'; +import { + AppRequestMessage, + WebConnectionProtocolMessage, + AgentResponseMessage, + WebConnectionProtocol4ValidateAppIdentity, + WebConnectionProtocol5ValidateAppIdentitySuccessResponse, + isWebConnectionProtocolMessage +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { storeDesktopAgentDetails, retrieveAllDesktopAgentDetails, retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; -export const DESKTOP_AGENT_SESSION_STORAGE_DETAILS_KEY = "fdc3-desktop-agent-details" /** * Version of Messaging which is able to store details in the SessionState (i.e. works on the web) */ export abstract class AbstractWebMessaging extends AbstractMessaging { + private readonly options: GetAgentParams; + private readonly connectionAttemptUuid: string; + private readonly actualUrl: string; - constructor(options: GetAgentParams, connectionAttemptUuid: string, actualUrl: string, timeout?: number) { - super(options, connectionAttemptUuid, actualUrl, timeout) + constructor(options: GetAgentParams, connectionAttemptUuid: string, actualUrl: string) { + super(); + if (!options.timeoutMs) { + options.timeoutMs = 10016; } + this.options = options; + this.connectionAttemptUuid = connectionAttemptUuid; + this.actualUrl = actualUrl; + } - abstract createUUID(): string - abstract post(message: object): Promise + abstract post(message: object): Promise; - abstract register(l: RegisterableListener): void - abstract unregister(id: string): void + abstract register(l: RegisterableListener): void; + abstract unregister(id: string): void; - abstract createMeta(): AddContextListenerRequestMeta + abstract createMeta(): AppRequestMessage['meta']; - /** - * Note that we also key by the window name as well, in case multiple iframes are using the same session storage. - */ - private sessionKey(): string { - const windowName = globalThis.window.name - const keyName = windowName ? DESKTOP_AGENT_SESSION_STORAGE_DETAILS_KEY + "-" + windowName : DESKTOP_AGENT_SESSION_STORAGE_DETAILS_KEY - return keyName - } + getTimeoutMs(): number { + return this.options.timeoutMs!; + } - /** - * Used to allow session-reconnection - */ - storeInstanceUuid(vr: WebConnectionProtocol5ValidateAppIdentitySuccessResponse) { - const details: DesktopAgentDetails = { - agentType: WebDesktopAgentType.ProxyParent, - instanceUuid: vr.payload.instanceUuid, - appId: vr.payload.appId, - instanceId: vr.payload.instanceId, - } + getSource(): AppIdentifier | null { + return super.getSource(); + } - globalThis.sessionStorage.setItem(this.sessionKey(), JSON.stringify(details)) - } + waitFor(filter: (m: any) => boolean, timeoutErrorMessage?: string): Promise { + return super.waitFor(filter, timeoutErrorMessage); + } - /** - * Stores the instanceUuid in session storage in case session needs reconnecting. - */ - retrieveInstanceUuid(): string | undefined { - const detailsStr = globalThis.sessionStorage.getItem(this.sessionKey()) - - if (detailsStr) { - const details = JSON.parse(detailsStr) as DesktopAgentDetails - if (details.agentType == WebDesktopAgentType.ProxyParent) { - return details.instanceUuid - } + private async exchangeValidationWithId(message: any, connectionAttemptUuid: string): Promise { + const prom = super.waitFor( + (m: WebConnectionProtocolMessage | AgentResponseMessage) => { + if (isWebConnectionProtocolMessage(m)) { + return m.meta.connectionAttemptUuid == connectionAttemptUuid; + } else { + return false; } + } + ); + this.post(message); + const out: any = await prom; + if (out?.payload?.message) { + throw new Error(out.payload.message); + } else { + return out; + } + } + + /** + * This handles the verify exchange with the da-server, + */ + async connect(): Promise { + const validationResponse = + await this.exchangeValidationWithId( + this.createValidationMessage(), + this.connectionAttemptUuid + ); + + super.setAppIdentifier({ + appId: validationResponse.payload.appId, + instanceId: validationResponse.payload.instanceId, + }); + + super.setImplementationMetadata(validationResponse.payload.implementationMetadata); - return undefined; + //TODO: need to do something with the instanceUuid... + + this.storeMyDesktopAgentDetails(validationResponse, /* need to set agent Type and agentUrl if any */) + } + + async disconnect(): Promise { + super.setAppIdentifier(null); + super.setImplementationMetadata(null); + } + + /** + * Sends the validate message through the message port + */ + private createValidationMessage(): WebConnectionProtocol4ValidateAppIdentity { + const requestMessage: WebConnectionProtocol4ValidateAppIdentity = { + type: 'WCP4ValidateAppIdentity', + meta: { + connectionAttemptUuid: this.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + identityUrl: this.options.identityUrl ?? this.actualUrl, + actualUrl: this.actualUrl + } + }; + const persistedDetails = this.retrieveMyDesktopAgentDetails(); + + if (persistedDetails) { + requestMessage.payload.instanceId = persistedDetails.instanceId; + requestMessage.payload.instanceUuid = persistedDetails.instanceUuid; } -} \ No newline at end of file + return requestMessage; + } + + /** Used to persist data on the connection, which can later be used to ensure + * reconnection to the same Desktop Agent and to request the same instanceId. + */ + storeMyDesktopAgentDetails( + validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse, + agentType: WebDesktopAgentType, + agentUrl?: string + ) { + //create the details object to persist + const details: DesktopAgentDetails = { + agentType, + identityUrl: this.options.identityUrl!, + actualUrl: this.actualUrl!, + agentUrl: agentUrl ?? undefined, + appId: validationResponse.payload.appId, + instanceUuid: validationResponse.payload.instanceUuid, + instanceId: validationResponse.payload.instanceId, + }; + + storeDesktopAgentDetails(details); + } + + /** Retrieves persisted data about previous connections for this specific app + * (identified by the identityUrl). Used to ensure reconnection to the same + * agent and to request the same instanceId. + */ + retrieveMyDesktopAgentDetails(): DesktopAgentDetails | null { + return retrieveDesktopAgentDetails(this.options.identityUrl!); + } + +} diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index aa2e40717..3c1779798 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -1,20 +1,22 @@ import { AbstractWebMessaging } from './AbstractWebMessaging' import { RegisterableListener } from "@kite9/fdc3-agent-proxy" -import { GetAgentParams } from "@kite9/fdc3-standard" +import { GetAgentParams, WebDesktopAgentType } from "@kite9/fdc3-standard" import { v4 as uuidv4 } from "uuid" import { BrowserTypes } from "@kite9/fdc3-schema"; -import { AddContextListenerRequestMeta } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake /** - * Details needed to set up the Messaging instance + * Details needed to set up the Messaging instance and Desktop AgentDetails record */ export type ConnectionDetails = { connectionAttemptUuid: string handshake: WebConnectionProtocol3Handshake, messagePort: MessagePort, actualUrl: string, - options: GetAgentParams + options: GetAgentParams, + agentType: WebDesktopAgentType, + agentUrl?: string, } export class MessagePortMessaging extends AbstractWebMessaging { @@ -22,8 +24,8 @@ export class MessagePortMessaging extends AbstractWebMessaging { private readonly cd: ConnectionDetails private readonly listeners: Map = new Map() - constructor(cd: ConnectionDetails, deliveryTimeoutMs?: number) { - super(cd.options, cd.connectionAttemptUuid, cd.actualUrl, deliveryTimeoutMs) + constructor(cd: ConnectionDetails) { + super(cd.options, cd.connectionAttemptUuid, cd.actualUrl); this.cd = cd; this.cd.messagePort.onmessage = (m) => { @@ -52,11 +54,11 @@ export class MessagePortMessaging extends AbstractWebMessaging { this.listeners.delete(id) } - createMeta(): AddContextListenerRequestMeta { + createMeta(): AppRequestMessage['meta'] { return { "requestUuid": this.createUUID(), "timestamp": new Date(), - "source": this.getSource() + "source": super.getSource()! } } diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 778912740..64b3aff7f 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -6,51 +6,62 @@ import { DefaultDesktopAgentChannelSelector } from "../ui/DefaultDesktopAgentCha import { NullIntentResolver } from "../ui/NullIntentResolver"; import { NullChannelSelector } from "../ui/NullChannelSelector"; import { ChannelSelector } from "@kite9/fdc3-standard"; - +import { DesktopAgentSelection } from "../strategies/Loader"; /** * Given a message port, constructs a desktop agent to communicate via that. */ export async function createDesktopAgentAPI(cd: ConnectionDetails): Promise { - cd.messagePort.start() + cd.messagePort.start(); function string(o: string | boolean): string | null { if ((o == true) || (o == false)) { - return null + return null; } else { - return o + return o; } } - const messaging = new MessagePortMessaging(cd) + const messaging = new MessagePortMessaging(cd); - const useResolver = cd.handshake.payload.intentResolverUrl && cd.options.intentResolver - const useSelector = cd.handshake.payload.channelSelectorUrl && cd.options.channelSelector + const useResolver = cd.handshake.payload.intentResolverUrl && cd.options.intentResolver; + const useSelector = cd.handshake.payload.channelSelectorUrl && cd.options.channelSelector; const intentResolver = useResolver ? new DefaultDesktopAgentIntentResolver(string(cd.handshake.payload.intentResolverUrl)) : - new NullIntentResolver() + new NullIntentResolver(); const channelSelector = useSelector ? new DefaultDesktopAgentChannelSelector(string(cd.handshake.payload.channelSelectorUrl)) - : new NullChannelSelector() - - const cs = new DefaultChannelSupport(messaging, channelSelector) - const hs = new DefaultHandshakeSupport(messaging) - const is = new DefaultIntentSupport(messaging, intentResolver) - const as = new DefaultAppSupport(messaging) - const da = new BasicDesktopAgent(hs, cs, is, as, [hs, intentResolver, channelSelector]) - await da.connect() + : new NullChannelSelector(); - await populateChannelSelector(cs, channelSelector) + const hs = new DefaultHandshakeSupport(messaging); + const cs = new DefaultChannelSupport(messaging, channelSelector); + const is = new DefaultIntentSupport(messaging, intentResolver); + const as = new DefaultAppSupport(messaging); + const da = new BasicDesktopAgent(hs, cs, is, as, [hs, intentResolver, channelSelector]); + await da.connect(); - return da -} + await populateChannelSelector(cs, channelSelector); + handleDisconnectOnPageHide(da); + return da; +} async function populateChannelSelector(cs: ChannelSupport, channelSelector: ChannelSelector): Promise { const channel = await cs.getUserChannel() const userChannels = await cs.getUserChannels() channelSelector.updateChannel(channel?.id ?? null, userChannels) } + +function handleDisconnectOnPageHide(da: DesktopAgent) { + globalThis.window.addEventListener("pagehide", (event) => { + //the page is being destroyed, disconnect from the DA + if (!event.persisted) { + if ((da as any).disconnect) { + (da as any).disconnect(); + } + } + }); +} diff --git a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts new file mode 100644 index 000000000..74856979b --- /dev/null +++ b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts @@ -0,0 +1,66 @@ +import { + DesktopAgentDetails, + DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX, +} from '@kite9/fdc3-standard'; +import { v4 as uuidv4 } from 'uuid'; + +export function createUUID(): string { + return uuidv4(); +} + +/** + * Note that we also key by the window name as well, in case multiple iframes are using the same session storage. + */ +export function sessionKey(): string { + //If the window or frame is not named, create and apply a unique name to it + if (!globalThis.window.name) { + globalThis.window.name = createUUID(); + } + const windowName = globalThis.window.name; + const keyName = DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-' + windowName; + return keyName; +} + +/** Used to persist data on the connection, which can later be used to ensure + * reconnection to the same Desktop Agent and to request the same instanceId. + */ +export function storeDesktopAgentDetails(details: DesktopAgentDetails){ + //check if there are existing details in storage to update + let detailsToStore = retrieveAllDesktopAgentDetails(); + if (!detailsToStore) { + detailsToStore = {}; + } + detailsToStore[details.identityUrl] = details; + globalThis.sessionStorage.setItem(sessionKey(), JSON.stringify(detailsToStore)); +} + +/** Retrieves persisted data about previous connections. Used to ensure reconnection + * to the same agent and to request the same instanceId. + */ +export function retrieveAllDesktopAgentDetails(): Record | null { + const detailsStr = globalThis.sessionStorage.getItem(sessionKey()); + + if (detailsStr) { + try { + return JSON.parse(detailsStr) as Record; + } catch (e) { + console.error(`FDC3 connection data couldn't be parsed\nstorage key: ${sessionKey()}\nvalue: ${detailsStr}`); + return null; + } + } else { + return null; + } +} + +/** Retrieves persisted data about previous connections for this specific app + * (identified by the identityUrl). Used to ensure reconnection to the same + * agent and to request the same instanceId. + */ +export function retrieveDesktopAgentDetails(identityUrl: string): DesktopAgentDetails | null { + const allDetails = retrieveAllDesktopAgentDetails(); + if (allDetails) { + return allDetails[identityUrl]; + } else { + return null; + } + } \ No newline at end of file diff --git a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts new file mode 100644 index 000000000..6e05f7dee --- /dev/null +++ b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts @@ -0,0 +1,53 @@ +import { DesktopAgent, WebDesktopAgentType } from "@kite9/fdc3-standard"; +import { GetAgentParams } from "@kite9/fdc3-standard"; +import { DesktopAgentSelection, Loader } from "./Loader"; + +/** + * This approach will resolve the loader promise if the fdc3Ready event occurs. + * This is done by electron implementations setting window.fdc3. + */ +export class DesktopAgentPreloadLoader implements Loader { + + //TODO: listen for the fdc3Ready event. Polling should be a fallback not the default strategy + + done = false + + async poll(endTime: number, resolve: (value: DesktopAgentSelection | void) => void, reject: (reason?: any) => void) { + const timeRemaining = endTime - Date.now() + if (globalThis.window.fdc3 != null) { + + //retrieve appId from DA + const implMetadata = await globalThis.window.fdc3.getInfo(); + + const selection: DesktopAgentSelection = { + agent: globalThis.window.fdc3, + details: { + agentType: WebDesktopAgentType.Preload, + identityUrl: globalThis.window.location.href, + actualUrl: globalThis.window.location.href, + appId: implMetadata.appMetadata.appId, + instanceId: implMetadata.appMetadata.instanceId, + instanceUuid: implMetadata.appMetadata.instanceId // preload DAs don't issue these so repeat the instanceId + } + }; + resolve(selection); + } else if ((timeRemaining > 0) && (this.done == false)) { + setTimeout(() => this.poll(endTime, resolve, reject), 100); + } else { + resolve(); + } + } + + cancel(): void { + this.done = true; + } + + async get(params: GetAgentParams): Promise { + return new Promise((resolve, reject) => { + const endPollTime = Date.now() + (params.timeoutMs! + 500) + // console.log("Starting poll: " + endPollTime + " " + params.timeout + " " + Date.now()) + this.poll(endPollTime, resolve, reject) + }); + } +} + diff --git a/packages/fdc3-get-agent/src/strategies/ElectronEventLoader.ts b/packages/fdc3-get-agent/src/strategies/ElectronEventLoader.ts deleted file mode 100644 index 09a7a6c7e..000000000 --- a/packages/fdc3-get-agent/src/strategies/ElectronEventLoader.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { DesktopAgent } from "@kite9/fdc3-standard"; -import { GetAgentParams } from "@kite9/fdc3-standard"; -import { Loader } from "./Loader"; - -/** - * This approach will resolve the loader promise if the fdc3Ready event occurs. - * This is done by electron implementations setting window.fdc3. - */ -export class ElectronEventLoader implements Loader { - - done = false - - poll(endTime: number, resolve: (value: DesktopAgent | void) => void, reject: (reason?: any) => void) { - const timeRemaining = endTime - Date.now() - if (globalThis.window.fdc3 != null) { - resolve(globalThis.window.fdc3) - } else if ((timeRemaining > 0) && (this.done == false)) { - setTimeout(() => this.poll(endTime, resolve, reject), 100); - } else { - resolve(); - } - } - - cancel(): void { - this.done = true; - } - - get(params: GetAgentParams): Promise { - return new Promise((resolve, reject) => { - const endPollTime = Date.now() + (params.timeoutMs!! + 500) - // console.log("Starting poll: " + endPollTime + " " + params.timeout + " " + Date.now()) - this.poll(endPollTime, resolve, reject) - }); - } -} - diff --git a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts new file mode 100644 index 000000000..d7ac48940 --- /dev/null +++ b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts @@ -0,0 +1,104 @@ +import { WebConnectionProtocol3Handshake } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { GetAgentParams, DesktopAgent, WebDesktopAgentType, AgentError } from '@kite9/fdc3-standard'; +import { createDesktopAgentAPI } from '../messaging/message-port'; +import { DesktopAgentSelection } from './Loader'; + +/** + * This is a variation of the PostMessageLoader used for handling failover. + * If the failover returns a WindowProxy this is used to create a Desktop + * Agent Proxy. If a DesktopAgent is returned directly it is passed through. + * + */ +export async function handleFailover( + options: GetAgentParams, + failover: (args: GetAgentParams) => Promise +): Promise { + return new Promise((resolve, reject) => { + //may be used to validate that handshake messages received came from + // the WindowProxy produced by the failover function + let proxyResult: Window | null = null; + + //listen for handshake messages from frames created by a failover function + const el = (event: MessageEvent) => { + const data = event.data; + if (data?.type == 'WCP3Handshake') { + if (event.source != proxyResult) { + console.warn('Received a Handshake message from invalid source during failover'); + //TODO: decide whether to ignore handshake messages from any source other than providerResult + } + + const handshake = data as WebConnectionProtocol3Handshake; + //clean up the listener on the window + globalThis.window.removeEventListener('message', el); + + const connectionDetails = { + connectionAttemptUuid: handshake.meta.connectionAttemptUuid, + handshake: data, + messagePort: event.ports[0], + options: options, + actualUrl: globalThis.window.location.href, + agentType: WebDesktopAgentType.Failover, + }; + createDesktopAgentAPI(connectionDetails).then((da: DesktopAgent) => { + const desktopAgentSelection: DesktopAgentSelection = { + agent: da, + details: { + agentType: WebDesktopAgentType.Failover, + identityUrl: options.identityUrl ?? connectionDetails.actualUrl, + actualUrl: connectionDetails.actualUrl, + //instanceId, appId etc. added after identityValidation exchange + }, + }; + resolve(desktopAgentSelection); + }); + } else { + console.debug(`Ignoring message unexpected message in FailoverHandler (because its not WCP3Handshake).`, data); + } + }; + + globalThis.window.addEventListener('message', el); + + if (typeof failover === 'function') { + failover(options).then(failoverResult => { + //if the result was a Desktop Agent + if (isDesktopAgent(failoverResult)) { + //clean up the listener on the window + globalThis.window.removeEventListener('message', el); + + //retrieve appId and instanceId from the DA + failoverResult.getInfo().then(implMetadata => { + const desktopAgentSelection: DesktopAgentSelection = { + agent: failoverResult, + details: { + agentType: WebDesktopAgentType.Failover, + identityUrl: globalThis.window.location.href, + actualUrl: globalThis.window.location.href, + appId: implMetadata.appMetadata.appId, + instanceId: implMetadata.appMetadata.instanceId, + instanceUuid: implMetadata.appMetadata.instanceId, // preload DAs don't issue these so repeat the instanceId + } + }; + resolve(desktopAgentSelection); + }); + } else if (isWindow(failoverResult)) { + // is a WindowProxy + //save WindowProxy for validating incoming messages later + proxyResult = failoverResult; + } else { + console.error('Failover function returned an invalid result', failoverResult); + reject(AgentError.InvalidFailover); + } + }); + } else { + reject(AgentError.InvalidFailover); + } + }); +} + +function isDesktopAgent(da: WindowProxy | DesktopAgent): da is DesktopAgent { + return (da as DesktopAgent).getInfo !== undefined; +} + +function isWindow(da: Window | DesktopAgent): da is Window { + return (da as Window).postMessage !== undefined; +} diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts new file mode 100644 index 000000000..ad7a0e2dd --- /dev/null +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -0,0 +1,149 @@ +import { + WebConnectionProtocolMessage, + WebConnectionProtocol1Hello, + isWebConnectionProtocol2LoadURL, + isWebConnectionProtocol3Handshake, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; +import { ConnectionDetails } from '../messaging/MessagePortMessaging'; +import { FDC3_VERSION } from './getAgent'; + +export class HelloHandler { + constructor(options: GetAgentParams, connectionAttemptUuid: string) { + this.options = options; + this.connectionAttemptUuid = connectionAttemptUuid; + this.helloResponseListener = null; + } + + /** Parameters passed to getAgent */ + options: GetAgentParams; + + /** UUID used to filter messages */ + connectionAttemptUuid: string; + + /** Reference to event listener used for responses from Desktop Agents - + * Used to remove them when no longer needed. + * Initialized when + * - listening for hello responses + * - listening for identity validation responses + * */ + helloResponseListener: ((event: MessageEvent) => void) | null; + + /** + * Starts the connection process off by sending a hello message + */ + sendWCP1Hello(w: MessageEventSource, origin: string) { + const requestMessage: WebConnectionProtocol1Hello = { + type: 'WCP1Hello', + meta: { + connectionAttemptUuid: this.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + channelSelector: this.options.channelSelector, + fdc3Version: FDC3_VERSION, + resolver: this.options.intentResolver, + identityUrl: this.options.identityUrl!!, + actualUrl: globalThis.window.location.href, + }, + }; + + w.postMessage(requestMessage, { targetOrigin: origin }); + } + + /** + * The desktop agent requests that the client opens a URL in order to provide a + * message port. + */ + openFrame(url: string) { + const IFRAME_ID = 'fdc3-communications-embedded-iframe'; + + // remove an old one if it's there + const existing = document.getElementById(IFRAME_ID); + if (existing) { + existing.remove(); + } + + // create a new one + var ifrm = document.createElement('iframe'); + ifrm.setAttribute('src', url); + ifrm.setAttribute('id', IFRAME_ID); + ifrm.setAttribute('name', 'FDC3 Communications'); + ifrm.style.width = '0px'; + ifrm.style.height = '0px'; + ifrm.style.border = '0'; + ifrm.style.position = 'fixed'; + + //Wait for the iframe to load... then send it a hello message + ifrm.onload = event => { + if (ifrm.contentWindow) { + this.sendWCP1Hello(ifrm.contentWindow, '*'); + } else { + console.error('iframe does not have a contentWindow, despite firing its load event!'); + } + }; + document.body.appendChild(ifrm); + } + + /** Listen for WCP responses from 'parent' windows and frames and handle them */ + listenForHelloResponses(): Promise { + let agentType = WebDesktopAgentType.ProxyParent; + let agentUrl: string | null = null; + + return new Promise((resolve, _reject) => { + // setup listener for message and retrieve JS URL from it + this.helloResponseListener = (event: MessageEvent) => { + const data = event.data; + if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { + if (isWebConnectionProtocol2LoadURL(data)) { + // in this case, we need to load the URL with the embedded Iframe + const url = data.payload.iframeUrl; + this.openFrame(url); + + //note the iframe URL and desktop agent type have changed + agentType = WebDesktopAgentType.ProxyUrl; + agentUrl = url; + + //n.b event listener remains in place to receive messages from the iframe + } else if (isWebConnectionProtocol3Handshake(data)) { + resolve({ + connectionAttemptUuid: this.connectionAttemptUuid, + handshake: data, + messagePort: event.ports[0], + options: this.options, + actualUrl: globalThis.window.location.href, + agentType: agentType, + agentUrl: agentUrl ?? undefined, + }); + + //remove the event listener as we've received a messagePort to use + if (this.helloResponseListener != null) { + globalThis.window.removeEventListener('message', this.helloResponseListener); + this.helloResponseListener = null; + } + } else { + console.debug( + `Ignoring message unexpected message in PostMessageLoader (because its not WCP2LoadUrl or WCP3Handshake).`, + data + ); + } + } else { + console.warn( + `Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, + data + ); + } + }; + + globalThis.window.addEventListener('message', this.helloResponseListener); + }); + } + + /** Removes listeners so that events are no longer processed */ + cancel() { + if (this.helloResponseListener) { + globalThis.window.removeEventListener('message', this.helloResponseListener); + this.helloResponseListener = null; + } + } +} diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts new file mode 100644 index 000000000..9dc487afb --- /dev/null +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -0,0 +1,127 @@ +import { + WebConnectionProtocol4ValidateAppIdentity, + WebConnectionProtocol5ValidateAppIdentitySuccessResponse, + WebConnectionProtocolMessage, + isWebConnectionProtocol5ValidateAppIdentitySuccessResponse, + isWebConnectionProtocol5ValidateAppIdentityFailedResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { GetAgentParams, AgentError } from '@kite9/fdc3-standard'; +import { retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; + +/** Timeout allowed for id validation to occur and for the DA to respond with details. + * This is additional to the app's specified timeout for discovery - we have already + * found an agent at that point we are just finishing setting up the connection. */ +const ID_VALIDATION_TIMEOUT = 3000; + +export class IdentityValidationHandler { + constructor(mp: MessagePort, options: GetAgentParams, connectionAttemptUuid: string) { + this.messagePort = mp; + this.options = options; + this.connectionAttemptUuid = connectionAttemptUuid; + this.idValidationResponseListener = null; + } + + /** Reference to the MessagePort received. Used to remove listeners when cancelling. */ + messagePort: MessagePort; + + /** Parameters passed to getAgent */ + options: GetAgentParams; + + /** UUID used to filter messages */ + connectionAttemptUuid: string; + + /** Event listener for ID validation response from Desktop Agents over the MessagePort. + * Used to remove them when no longer needed. + * Initialized during the id validation step. + */ + idValidationResponseListener: ((event: MessageEvent) => void) | null; + + /** + * Starts the connection process off by sending a hello message + */ + sendIdValidationMessage() { + const actualUrl = globalThis.window.location.href; + const identityUrl = this.options.identityUrl ?? actualUrl; + + const requestMessage: WebConnectionProtocol4ValidateAppIdentity = { + type: 'WCP4ValidateAppIdentity', + meta: { + connectionAttemptUuid: this.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + identityUrl, + actualUrl, + }, + }; + const persistedDetails = retrieveDesktopAgentDetails(identityUrl); + + if (persistedDetails) { + requestMessage.payload.instanceId = persistedDetails.instanceId; + requestMessage.payload.instanceUuid = persistedDetails.instanceUuid; + } + + this.messagePort.postMessage(requestMessage); + } + + /** Listen for WCP responses over the message port to identity validation messages. */ + listenForIDValidationResponses(): Promise { + return new Promise((resolve, reject) => { + //timeout for id validation only + const timeout = setTimeout(() => { + if (this.idValidationResponseListener) { + //remove the event listener as we won't proceed further + this.messagePort.removeEventListener('message', this.idValidationResponseListener); + } + console.error( + `The Desktop Agent didn't respond to ID validation within ${ID_VALIDATION_TIMEOUT / 1000} seconds` + ); + reject(AgentError.ErrorOnConnect); + }, ID_VALIDATION_TIMEOUT); + + // setup listener for message and retrieve JS URL from it + this.idValidationResponseListener = (event: MessageEvent) => { + const data = event.data; + if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { + if (isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(data)) { + //passed validation + clearTimeout(timeout); + if (this.idValidationResponseListener) { + //remove the event listener as we've received a messagePort to use + this.messagePort.removeEventListener('message', this.idValidationResponseListener); + } + console.debug( + `Validated app identity, appId: ${data.payload.appId}, instanceId: ${data.payload.instanceId}` + ); + resolve(data); + + } else if (isWebConnectionProtocol5ValidateAppIdentityFailedResponse(data)) { + //failed validation... + clearTimeout(timeout); + if (this.idValidationResponseListener) { + //remove the event listener as we've received a messagePort to use + this.messagePort.removeEventListener('message', this.idValidationResponseListener); + } + console.error(`App identity validation failed: ${data.payload.message ?? 'No reason given'}`); + reject(AgentError.AccessDenied); + + } else { + console.debug( + `Ignoring message unexpected message in PostMessageLoader (because its not a WCP5 message).`, + data + ); + } + + } else { + console.debug( + `Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, + data + ); + } + }; + + //listening on a message port + this.messagePort.addEventListener('message', this.idValidationResponseListener); + }); + } +} diff --git a/packages/fdc3-get-agent/src/strategies/Loader.ts b/packages/fdc3-get-agent/src/strategies/Loader.ts index 8c105a7d9..05f1d5288 100644 --- a/packages/fdc3-get-agent/src/strategies/Loader.ts +++ b/packages/fdc3-get-agent/src/strategies/Loader.ts @@ -1,16 +1,31 @@ -import { DesktopAgent } from "@kite9/fdc3-standard" -import { GetAgentParams } from "@kite9/fdc3-standard" +import { DesktopAgent, WebDesktopAgentType } from '@kite9/fdc3-standard'; +import { GetAgentParams } from '@kite9/fdc3-standard'; /** * Represents the common interface for a loading strategy */ export interface Loader { + /** + * Promise will either resolve to a DesktopAgent or _resolve_ to an error (not reject) + */ + get(options: GetAgentParams): Promise; - /** - * Promise will either resolve to a DesktopAgent or _resolve_ to an error (not reject) - */ - get(options: GetAgentParams): Promise + cancel(): void; +} - cancel(): void - -} \ No newline at end of file +/** Specific partial of DesktopAgentDetails defining the details that Loaders + * must return with a DesktopAgent to be put into SessionStorage at the end + * of the process. + */ +export interface DesktopAgentSelection { + agent: DesktopAgent; + details: { + agentType: WebDesktopAgentType; + identityUrl: string; + actualUrl: string; + agentUrl?: string; + appId?: string; + instanceId?: string; + instanceUuid?: string; + }; +} diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 90e5d3f41..ccd301805 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -1,162 +1,107 @@ -import { DesktopAgent, GetAgentParams } from '@kite9/fdc3-standard' +import { AgentError, GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; import { createDesktopAgentAPI } from '../messaging/message-port'; -import { v4 as uuidv4 } from "uuid" +import { v4 as uuidv4 } from 'uuid'; import { ConnectionDetails } from '../messaging/MessagePortMessaging'; -import { Loader } from './Loader'; -import { BrowserTypes } from "@kite9/fdc3-schema"; +import { DesktopAgentSelection, Loader } from './Loader'; import { FDC3_VERSION } from './getAgent'; - -type WebConnectionProtocol1Hello = BrowserTypes.WebConnectionProtocol1Hello -type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL -type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake - -function collectPossibleTargets(w: Window, found: Window[]) { - if (w) { - if (found.indexOf(w) == -1) { - found.push(w); - } - - if (found.indexOf(w.opener) == -1) { - collectPossibleTargets(w.opener, found); - } - - if (found.indexOf(w.parent) == -1) { - collectPossibleTargets(w.parent, found); - } - } -} - +import { retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; +import { isWebConnectionProtocol2LoadURL, isWebConnectionProtocol3Handshake, isWebConnectionProtocol5ValidateAppIdentityFailedResponse, isWebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol1Hello, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocolMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { HelloHandler } from './HelloHandler'; +import { IdentityValidationHandler } from './IdentityValidationHandler'; /** - * Starts the connection process off by sending a hello message + * Recursive search for all possible parent frames (windows) that we may + * target with the WCP. + * @param w window object to search + * @param found window objects found so far */ -function sendWCP1Hello(w: MessageEventSource, options: GetAgentParams, connectionAttemptUuid: string, origin: string) { - const requestMessage: WebConnectionProtocol1Hello = { - type: 'WCP1Hello', - meta: { - connectionAttemptUuid: connectionAttemptUuid, - timestamp: new Date() - }, - payload: { - channelSelector: options.channelSelector, - fdc3Version: FDC3_VERSION, - resolver: options.intentResolver, - identityUrl: options.identityUrl!!, - actualUrl: globalThis.window.location.href - } - } - - w.postMessage(requestMessage, { targetOrigin: origin }); +function collectPossibleTargets(startWindow: Window, found: Window[]) { + _recursePossibleTargets(startWindow, startWindow, found); } -/** - * The desktop agent requests that the client opens a URL in order to provide a message port. - */ -function openFrame(url: string): Window { - const IFRAME_ID = "fdc3-communications-embedded-iframe" - - // remove an old one if it's there - const existing = document.getElementById(IFRAME_ID) - if (existing) { - existing.remove() +function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[]) { + if (w) { + if (found.indexOf(w) == -1 && w != startWindow) { + found.push(w); } - // create a new one - var ifrm = document.createElement("iframe") - ifrm.setAttribute("src", url) - ifrm.setAttribute("id", IFRAME_ID) - ifrm.setAttribute("name", "FDC3 Communications") - ifrm.style.width = "0px" - ifrm.style.height = "0px" - ifrm.style.border = "0" - ifrm.style.position = "fixed" - document.body.appendChild(ifrm) - return ifrm.contentWindow!! -} - -export function helloExchange(options: GetAgentParams, connectionAttemptUuid: string): Promise { - - return new Promise((resolve, _reject) => { - // setup listener for message and retrieve JS URL from it - const el = (event: MessageEvent) => { - const data = event.data; - if (data?.meta?.connectionAttemptUuid == connectionAttemptUuid) { - if (data.type == 'WCP2LoadUrl') { - // in this case, we need to load the URL with the embedded Iframe - openFrame((data as WebConnectionProtocol2LoadURL).payload.iframeUrl); - } else if (data.type == 'WCP3Handshake') { - resolve({ - connectionAttemptUuid: connectionAttemptUuid, - handshake: data, - messagePort: event.ports[0], - options: options, - actualUrl: globalThis.window.location.href - }) - } - } - } - - globalThis.window.addEventListener("message", el) - }); - -} + if (found.indexOf(w.opener) == -1 && w != startWindow) { + _recursePossibleTargets(startWindow, w.opener, found); + } -/** - * This is a variation of the PostMessageLoader used for handling failover. If the failover returns the WindowProxy this is used - * to properly load the desktop agent. - */ -export function handleWindowProxy(options: GetAgentParams, provider: () => Promise): Promise { - return new Promise((resolve, _reject) => { - const el = (event: MessageEvent) => { - const data = event.data; - if (data.type == 'WCP3Handshake') { - const handshake = data as WebConnectionProtocol3Handshake; - globalThis.window.removeEventListener("message", el) - - resolve(createDesktopAgentAPI({ - connectionAttemptUuid: handshake.meta.connectionAttemptUuid, - handshake: data, - messagePort: event.ports[0], - options: options, - actualUrl: globalThis.window.location.href - })) - } - } - - globalThis.window.addEventListener("message", el) - - provider().then((providerResult) => { - if ((providerResult as any).getInfo) { - globalThis.window.removeEventListener("message", el) - resolve(providerResult as DesktopAgent) - } - }) - }) + if (found.indexOf(w.parent) == -1 && w != startWindow) { + _recursePossibleTargets(startWindow, w.parent, found); + } + } } - + //TODO incorporate a timeout here to replace TimeoutLoader + // - would allow timeout to be stopped when message port is received as id validation should be outside of timeout + // although a separate timeout should be used there to avoid stalling if the DA doesn't respond export class PostMessageLoader implements Loader { + connectionAttemptUuid = uuidv4(); + + helloHandler?: HelloHandler; + identityValidationHandler?: IdentityValidationHandler; - connectionAttemptUuid = uuidv4(); - async get(options: GetAgentParams): Promise { - const targets: Window[] = [] - collectPossibleTargets(globalThis.window, targets); + async get(options: GetAgentParams): Promise { + const targets: Window[] = []; + collectPossibleTargets(globalThis.window, targets); - // ok, begin the process - const promise = helloExchange(options, this.connectionAttemptUuid) + this.helloHandler = new HelloHandler(options, this.connectionAttemptUuid); - // use of '*': See https://github.com/finos/FDC3/issues/1316 - targets.forEach((t) => sendWCP1Hello(t, options, this.connectionAttemptUuid, "*")) + // ok, begin the process + const handshakePromise = this.helloHandler.listenForHelloResponses(); - // wait for one of the windows to return the data we need - const data = await promise - return createDesktopAgentAPI(data); + // use of origin '*': See https://github.com/finos/FDC3/issues/1316 + for (let t = 0; t < targets.length; t++) { + this.helloHandler.sendWCP1Hello(targets[t], '*'); } - cancel(): void { + // wait for one of the windows to respond + // This may involve a WCP2LoadUrl response being received + // and an adaptor iframe setup to load it, resolves on + // WCP3Handshake response. + // If no WCP3Handshake is ever received this will not resolve + const connectionDetails = await handshakePromise; + + //perform id validation + this.identityValidationHandler = new IdentityValidationHandler(connectionDetails.messagePort, options, this.connectionAttemptUuid) + const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + this.identityValidationHandler.sendIdValidationMessage(); + + try { + const idDetails = await idValidationPromise; + const desktopAgentSelection: DesktopAgentSelection = { + agent: await createDesktopAgentAPI(connectionDetails), + details: { + agentType: connectionDetails.agentType, + agentUrl: connectionDetails.agentUrl ?? undefined, + identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, + actualUrl: connectionDetails.actualUrl, + appId: idDetails.payload.appId, + instanceId: idDetails.payload.instanceId, + instanceUuid: idDetails.payload.instanceUuid + }, + }; + return desktopAgentSelection; + } catch (e) { + //id validation may have failed + throw e; } + } + cancel(): void { + //remove any event listeners to end processing + if (this.helloHandler) { + this.helloHandler.cancel(); + } + if (this.identityValidationHandler){ + this.identityValidationHandler.cancel(); + } + } } + diff --git a/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts b/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts index 7e6c8306f..7cc91549a 100644 --- a/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts @@ -1,5 +1,5 @@ import { AgentError, DesktopAgent, GetAgentParams } from "@kite9/fdc3-standard"; -import { Loader } from "./Loader"; +import { DesktopAgentSelection, Loader } from "./Loader"; @@ -8,9 +8,11 @@ import { Loader } from "./Loader"; */ export class TimeoutLoader implements Loader { - done = false + done = false; - poll(endTime: number, resolve: (value: DesktopAgent | void) => void, reject: (reason?: any) => void) { + //TODO: replace polling with an actual timeout + + poll(endTime: number, resolve: (value: DesktopAgentSelection | void) => void, reject: (reason?: any) => void) { const timeRemaining = endTime - Date.now() if ((timeRemaining > 0) && (this.done == false)) { @@ -26,10 +28,10 @@ export class TimeoutLoader implements Loader { this.done = true; } - get(params: GetAgentParams): Promise { - return new Promise((resolve, reject) => { - const endPollTime = Date.now() + params.timeoutMs!! - this.poll(endPollTime, resolve, reject) + get(params: GetAgentParams): Promise { + return new Promise((resolve, reject) => { + const endPollTime = Date.now() + params.timeoutMs!!; + this.poll(endPollTime, resolve, reject); }); } } diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 62ed3a596..1dce1c364 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -1,9 +1,11 @@ -import { DesktopAgent, GetAgentType, GetAgentParams, AgentError } from '@kite9/fdc3-standard' -import { ElectronEventLoader } from './ElectronEventLoader' -import { handleWindowProxy, PostMessageLoader } from './PostMessageLoader' +import { DesktopAgent, GetAgentType, GetAgentParams, AgentError, DesktopAgentDetails, WebDesktopAgentType } from '@kite9/fdc3-standard' +import { DesktopAgentPreloadLoader } from './DesktopAgentPreloadLoader' +import { PostMessageLoader } from './PostMessageLoader' import { TimeoutLoader } from './TimeoutLoader' +import { storeDesktopAgentDetails, retrieveAllDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; +import { handleFailover } from './FailoverHandler'; -const DEFAULT_WAIT_FOR_MS = 20000; +const DEFAULT_WAIT_FOR_MS = 750; export const FDC3_VERSION = "2.2" @@ -23,42 +25,102 @@ export function getAgentPromise(): Promise | null { function initAgentPromise(options: GetAgentParams): Promise { - const STRATEGIES = [ - new ElectronEventLoader(), + const DEFAULT_STRATEGIES = [ + new DesktopAgentPreloadLoader(), new PostMessageLoader(), new TimeoutLoader() ] - const promises = STRATEGIES.map(s => s.get(options)); + + //TODO: retrieve persisted data and only use a previous strategy if one exists + const promises = DEFAULT_STRATEGIES.map(s => s.get(options)); return Promise.race(promises) - .then(da => { - // first, cancel the timeout etc. - STRATEGIES.forEach(s => s.cancel()) - - // either the timeout completes first with an error, or one of the other strategies completes with a DesktopAgent. - if (da) { - return da as DesktopAgent - } else { - throw new Error(AgentError.AgentNotFound) - } - }) - .catch(async (error) => { - if (options.failover) { - const o = await handleWindowProxy(options, () => { return options.failover!!(options) }) - return o - } else { - throw error + .then(selection => { + // first, cancel the timeout etc. + DEFAULT_STRATEGIES.forEach(s => s.cancel()) + // either the timeout completes first with an error, or one of the other strategies completes with a DesktopAgent. + if (selection) { + const desktopAgentDetails: DesktopAgentDetails = { + agentType: selection.details.agentType, + identityUrl: selection.details.identityUrl, + actualUrl: selection.details.actualUrl, + agentUrl: selection.details.agentUrl ?? undefined, + appId: selection.details.appId, + instanceId: selection.details.instanceId, + instanceUuid: selection.details.instanceUuid + }; + storeDesktopAgentDetails(desktopAgentDetails); + + return selection.agent; + } else { + throw new Error(AgentError.AgentNotFound) + } + }) + .catch(async (error) => { + if (options.failover != undefined) { + try { + //TODO: ensure a timeout is also applied to the failover, to avoid getting stuck here + const selection = await handleFailover(options, options.failover); + + //store details of the connection in SessionStorage + const desktopAgentDetails: DesktopAgentDetails = { + agentType: WebDesktopAgentType.Failover, + identityUrl: selection.details.identityUrl, + actualUrl: selection.details.actualUrl, + agentUrl: selection.details.agentUrl ?? undefined, + appId: selection.details.appId, + instanceId: selection.details.instanceId, + instanceUuid: selection.details.instanceUuid + }; + storeDesktopAgentDetails(desktopAgentDetails); + + + return selection.agent; + } catch (e) { + console.error("Desktop agent not found. Error reported during failover", e); + throw e; } - }) + } else { + //We didn't manage to find an agent. Suppress any actual error and throw a value from AgentError + console.log("Desktop agent not found. Error reported during discovery", error); + throw new Error(AgentError.AgentNotFound); + } + }); } - /** - * This return an FDC3 API. Should be called by application code. - * - * @param optionsOverride - options to override the default options + * Function used to retrieve an FDC3 Desktop Agent API instance, which + * supports the discovery of a Desktop Agent Preload (a container-injected + * API implementation) or a Desktop Agent Proxy (a Browser-based Desktop Agent + * running in another window or frame). Finally, if no Desktop Agent is found, + * a failover function may be supplied by an app allowing it to start or otherwise + * connect to a Desktop Agent (e.g. by loading a proprietary adaptor that + * returns a `DesktopAgent` implementation or by creating a window or iframe of + * its own that will provide a Desktop Agent Proxy. + * + * @param {GetAgentParams} params Optional parameters object, which + * may include a URL to use for the app's identity, other settings + * that affect the behavior of the getAgent() function and a `failover` + * function that should be run if a Desktop Agent is not detected. + * + * @returns A promise that resolves to a DesktopAgent implementation or + * rejects with an error message from the `AgentError` enumeration if unable to + * return a Desktop Agent implementation. + * + * @example + * const fdc3 = await getAgent(); + * + * // OR + * + * getAgent({ + * identityUrl: "https://example.com/path?param=appName#example", + * channelSelector: false, + * intentResolver: false + * }).then((fdc3) => { + * //do FDC3 stuff here + * }; */ -export const getAgent: GetAgentType = (optionsOverride?: GetAgentParams) => { +export const getAgent: GetAgentType = (params?: GetAgentParams) => { const DEFAULT_OPTIONS: GetAgentParams = { dontSetWindowFdc3: true, @@ -66,34 +128,26 @@ export const getAgent: GetAgentType = (optionsOverride?: GetAgentParams) => { intentResolver: true, timeoutMs: DEFAULT_WAIT_FOR_MS, identityUrl: globalThis.window.location.href - } + }; - const options = { + const options: GetAgentParams = { ...DEFAULT_OPTIONS, - ...optionsOverride - } + ...params + }; - function handleGenericOptions(da: DesktopAgent) { + async function handleSetWindowFdc3(da: DesktopAgent) { if ((!options.dontSetWindowFdc3) && (globalThis.window.fdc3 == null)) { globalThis.window.fdc3 = da; globalThis.window.dispatchEvent(new Event("fdc3Ready")); } - - globalThis.window.addEventListener("pagehide", () => { - if ((da as any).disconnect) { - (da as any).disconnect() - theAgentPromise = null; - } - }) - return da; - } + }; if (!theAgentPromise) { - theAgentPromise = initAgentPromise(options).then(handleGenericOptions) + theAgentPromise = initAgentPromise(options).then(handleSetWindowFdc3); } - return theAgentPromise + return theAgentPromise; } /** @@ -103,12 +157,10 @@ export const getAgent: GetAgentType = (optionsOverride?: GetAgentParams) => { * @returns A DesktopAgent promise. */ export function fdc3Ready(waitForMs = DEFAULT_WAIT_FOR_MS): Promise { - const agent = getAgent({ + return getAgent({ timeoutMs: waitForMs, dontSetWindowFdc3: false, channelSelector: true, intentResolver: true - }) - - return agent + }); } \ No newline at end of file diff --git a/packages/fdc3-schema/generated/api/BrowserTypes.ts b/packages/fdc3-schema/generated/api/BrowserTypes.ts index a924b0bdf..7024414ea 100644 --- a/packages/fdc3-schema/generated/api/BrowserTypes.ts +++ b/packages/fdc3-schema/generated/api/BrowserTypes.ts @@ -1,15 +1,7 @@ // To parse this data: // -// import { Convert, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceChannels, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse } from "./file"; +// import { Convert, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannels, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage } from "./file"; // -// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); -// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); -// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); -// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); -// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); -// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); -// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); -// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // const addContextListenerRequest = Convert.toAddContextListenerRequest(json); // const addContextListenerResponse = Convert.toAddContextListenerResponse(json); // const addEventListenerRequest = Convert.toAddEventListenerRequest(json); @@ -29,8 +21,8 @@ // const createPrivateChannelResponse = Convert.toCreatePrivateChannelResponse(json); // const eventListenerUnsubscribeRequest = Convert.toEventListenerUnsubscribeRequest(json); // const eventListenerUnsubscribeResponse = Convert.toEventListenerUnsubscribeResponse(json); -// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceChannels = Convert.toFdc3UserInterfaceChannels(json); +// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceDrag = Convert.toFdc3UserInterfaceDrag(json); // const fdc3UserInterfaceHandshake = Convert.toFdc3UserInterfaceHandshake(json); // const fdc3UserInterfaceHello = Convert.toFdc3UserInterfaceHello(json); @@ -83,761 +75,244 @@ // const raiseIntentRequest = Convert.toRaiseIntentRequest(json); // const raiseIntentResponse = Convert.toRaiseIntentResponse(json); // const raiseIntentResultResponse = Convert.toRaiseIntentResultResponse(json); +// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); +// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); +// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); +// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); +// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); +// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); +// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); +// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // // These functions will throw an error if the JSON doesn't // match the expected interface, even if the JSON is valid. /** - * Hello message sent by an application to a parent window or frame when attempting to - * establish connectivity to a Desktop Agent. + * A request to add a context listener to a specified Channel OR to the current user + * channel. Where the listener is added to the current user channel (channelId == null), and + * this app has already been added to a user channel, client code should make a subsequent + * request to get the current context of that channel for this listener and then call its + * handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1Hello { +export interface AddContextListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol1HelloPayload; + payload: AddContextListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "WCP1Hello"; + type: "addContextListenerRequest"; } /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1HelloMeta { - connectionAttemptUuid: string; +export interface AddContextListenerRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + */ + source?: AppIdentifier; timestamp: Date; } /** - * The message payload, containing data pertaining to this connection step. + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. + * + * Details of the application instance that broadcast the context. + * + * The App resolution option chosen. + * + * Details of the application instance that raised the intent. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. */ -export interface WebConnectionProtocol1HelloPayload { +export interface AppIdentifier { /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. */ - actualUrl: string; + appId: string; /** - * A flag that may be used to indicate that a channel selector user interface is or is not - * required. Set to `false` if the app includes its own interface for selecting channels or - * does not work with user channels. + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. */ - channelSelector?: boolean; + desktopAgent?: string; /** - * The version of FDC3 API that the app supports. + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. */ - fdc3Version: string; + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface AddContextListenerRequestPayload { /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. + * The id of the channel to add the listener to or `null` indicating that it should listen + * to the current user channel (at the time of broadcast). */ - identityUrl: string; + channelId: null | string; /** - * A flag that may be used to indicate that an intent resolver is or is not required. Set to - * `false` if no intents, or only targeted intents, are raised. + * The type of context to listen for OR `null` indicating that it should listen to all + * context types. */ - intentResolver?: boolean; - [property: string]: any; + contextType: null | string; } /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Response from a Desktop Agent to an application requesting access to it indicating that - * it should load a specified URL into a hidden iframe in order to establish connectivity to - * a Desktop Agent. + * A response to a addContextListener request. Where the listener was added to the current + * user channel (channelId == null), and this app has already been added to a user channel, + * client code should make a subsequent request to get the current context of that channel + * for this listener and then call its handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol2LoadURL { +export interface AddContextListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: WebConnectionProtocol2LoadURLPayload; + payload: AddContextListenerResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "WCP2LoadUrl"; + type: "addContextListenerResponse"; } /** - * The message payload, containing data pertaining to this connection step. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ -export interface WebConnectionProtocol2LoadURLPayload { +export interface AddContextListenerResponseMeta { + requestUuid: string; + responseUuid: string; /** - * A URL which can be used to establish communication with the Desktop Agent, via loading - * the URL into an iframe and restarting the Web Connection protocol with the iframe as the - * target. + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. */ - iframeUrl: string; - [property: string]: any; + source?: AppIdentifier; + timestamp: Date; } /** - * Identifies the type of the connection step message. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ +export interface AddContextListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; +} /** - * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that - * should be used for subsequent communication steps. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface WebConnectionProtocol3Handshake { +export type PurpleError = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to add an event listener for a specified event type to the Desktop Agent. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface AddEventListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol3HandshakePayload; + payload: AddEventListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "WCP3Handshake"; + type: "addEventListenerRequest"; } /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface WebConnectionProtocol3HandshakePayload { - /** - * Indicates whether a channel selector user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the channel selector (as the - * Desktop Agent will handle it another way). - */ - channelSelectorUrl: boolean | string; - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; +export interface AddEventListenerRequestPayload { /** - * Indicates whether an intent resolver user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the intent resolver (as the - * Desktop Agent will handle it another way). + * The type of the event to be listened to or `null` to listen to all event types. */ - intentResolverUrl: boolean | string; + type: "USER_CHANNEL_CHANGED" | null; } /** - * Identifies the type of the connection step message. + * The type of a (non-context and non-intent) event that may be received via the FDC3 API's + * addEventListener function. */ /** - * Identity Validation request from an app attempting to connect to a Desktop Agent. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to an addEventListener request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol4ValidateAppIdentity { +export interface AddEventListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol4ValidateAppIdentityPayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP4ValidateAppIdentity"; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol4ValidateAppIdentityPayload { - /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. - */ - actualUrl: string; - /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. - */ - identityUrl: string; - /** - * If an application has previously connected to the Desktop Agent, it may specify its prior - * instance id and associated instance UUID to request the same same instance Id be assigned. - */ - instanceId?: string; - /** - * Instance UUID associated with the requested instanceId. - */ - instanceUuid?: string; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Message sent by the Desktop Agent to an app if their identity validation fails. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP5ValidateAppIdentityFailedResponse"; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { - message?: string; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Message sent by the Desktop Agent to an app after successful identity validation. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP5ValidateAppIdentityResponse"; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { - /** - * The appId that the app's identity was validated against. - */ - appId: string; - /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - */ - implementationMetadata: ImplementationMetadata; - /** - * The instance Id granted to the application by the Desktop Agent. - */ - instanceId: string; - /** - * Instance UUID associated with the instanceId granted, which may be used to retrieve the - * same instanceId if the app is reloaded or navigates. - */ - instanceUuid: string; -} - -/** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - * - * Includes Metadata for the current application. - * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. - */ -export interface ImplementationMetadata { - /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - */ - appMetadata: AppMetadata; - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; -} - -/** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - * - * Extends an `AppIdentifier`, describing an application or instance of an application, with - * additional descriptive metadata that is usually provided by an FDC3 App Directory that - * the Desktop Agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such - * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon - * and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the - * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. - */ -export interface AppMetadata { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * A longer, multi-paragraph description for the application that could include markup. - */ - description?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * A list of icon URLs for the application that can be used to render UI elements. - */ - icons?: Icon[]; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - /** - * An optional set of, implementation specific, metadata fields that can be used to - * disambiguate instances, such as a window title or screen position. Must only be set if - * `instanceId` is set. - */ - instanceMetadata?: { [key: string]: any }; - /** - * The 'friendly' app name. - * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now - * require an `AppIdentifier` wth `appId` set. - * Note that for display purposes the `title` field should be used, if set, in preference to - * this field. - */ - name?: string; - /** - * The type of output returned for any intent specified during resolution. May express a - * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel - * that will receive a specified type (e.g. "channel"). - */ - resultType?: null | string; - /** - * Images representing the app in common usage scenarios that can be used to render UI - * elements. - */ - screenshots?: Image[]; - /** - * A more user-friendly application title that can be used to render UI elements. - */ - title?: string; - /** - * A tooltip for the application that can be used to render UI elements. - */ - tooltip?: string; - /** - * The Version of the application. - */ - version?: string; -} - -/** - * Describes an Icon images that may be used to represent the application. - */ -export interface Icon { - /** - * The icon dimension, formatted as `x`. - */ - size?: string; - /** - * The icon url. - */ - src: string; - /** - * Icon media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Describes an image file, typically a screenshot, that often represents the application in - * a common usage scenario. - */ -export interface Image { - /** - * Caption for the image. - */ - label?: string; - /** - * The image dimension, formatted as `x`. - */ - size?: string; - /** - * The image url. - */ - src: string; - /** - * Image media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ -export interface OptionalFeatures { - /** - * Used to indicate whether the experimental Desktop Agent Bridging - * feature is implemented by the Desktop Agent. - */ - DesktopAgentBridging: boolean; - /** - * Used to indicate whether the exposure of 'originating app metadata' for - * context and intent messages is supported by the Desktop Agent. - */ - OriginatingAppMetadata: boolean; - /** - * Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent. - */ - UserChannelMembershipAPIs: boolean; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the - * window or navigating). Desktop Agents should close the MessagePort after receiving this - * message, but retain instance details in case the application reconnects (e.g. after a - * navigation event). - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol6Goodbye { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol6GoodbyeMeta; - /** - * Identifies the type of the connection step message. - */ - type: "WCP6Goodbye"; -} - -/** - * Metadata for a Web Connection Protocol message. - */ -export interface WebConnectionProtocol6GoodbyeMeta { - timestamp: Date; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocolMessage { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: ConnectionStepMetadata; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload?: { [key: string]: any }; - /** - * Identifies the type of the connection step message. - */ - type: ConnectionStepMessageType; -} - -/** - * Metadata for a Web Connection Protocol message. - */ -export interface ConnectionStepMetadata { - timestamp: Date; - connectionAttemptUuid?: string; -} - -/** - * Identifies the type of the connection step message. - */ -export type ConnectionStepMessageType = "WCP1Hello" | "WCP2LoadUrl" | "WCP3Handshake" | "WCP4ValidateAppIdentity" | "WCP5ValidateAppIdentityFailedResponse" | "WCP5ValidateAppIdentityResponse" | "WCP6Goodbye"; - -/** - * A request to add a context listener to a specified Channel OR to the current user - * channel. Where the listener is added to the current user channel (channelId == null), and - * this app has already been added to a user channel, client code should make a subsequent - * request to get the current context of that channel for this listener and then call its - * handler with it. - * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AddContextListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddContextListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addContextListenerRequest"; -} - -/** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ -export interface AddContextListenerRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - * - * Details of the application instance that broadcast the context. - * - * The App resolution option chosen. - * - * Details of the application instance that raised the intent. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface AddContextListenerRequestPayload { - /** - * The id of the channel to add the listener to or `null` indicating that it should listen - * to the current user channel (at the time of broadcast). - */ - channelId: null | string; - /** - * The type of context to listen for OR `null` indicating that it should listen to all - * context types. - */ - contextType: null | string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a addContextListener request. Where the listener was added to the current - * user channel (channelId == null), and this app has already been added to a user channel, - * client code should make a subsequent request to get the current context of that channel - * for this listener and then call its handler with it. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. - */ -export interface AddContextListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: AddContextListenerResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "addContextListenerResponse"; -} - -/** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ -export interface AddContextListenerResponseMeta { - requestUuid: string; - responseUuid: string; - /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface AddContextListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; -} - -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type PurpleError = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound"; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to add an event listener for a specified event type to the Desktop Agent. - * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AddEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddEventListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addEventListenerRequest"; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface AddEventListenerRequestPayload { - /** - * The type of the event to be listened to or `null` to listen to all event types. - */ - type: "USER_CHANNEL_CHANGED" | null; -} - -/** - * The type of a (non-context and non-intent) event that may be received via the FDC3 API's - * addEventListener function. - */ - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to an addEventListener request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. - */ -export interface AddEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; + meta: AddContextListenerResponseMeta; /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was @@ -1533,166 +1008,494 @@ export interface EventListenerUnsubscribeRequest { */ meta: AddContextListenerRequestMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: EventListenerUnsubscribeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "eventListenerUnsubscribeRequest"; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface EventListenerUnsubscribeRequestPayload { + listenerUUID: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to an eventListenerUnsubscribe request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface EventListenerUnsubscribeResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "eventListenerUnsubscribeResponse"; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an + * iframe with the channel definitions and current channel selection. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceChannels { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelsPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: "Fdc3UserInterfaceChannels"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceChannelsPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; + /** + * User Channel definitions.```````s + */ + userChannels: Channel[]; +} + +/** + * Identifies the type of the message to or from the user interface frame. + */ + +/** + * Message from a channel selector UI to the DA proxy sent when the channel selection + * changes. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceChannelSelected { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelSelectedPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: "Fdc3UserInterfaceChannelSelected"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceChannelSelectedPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; +} + +/** + * Identifies the type of the message to or from the user interface frame. + */ + +/** + * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user + * is dragging the UI to a new location and providing the offset to apply to the location. + * The DA proxy implementation should limit the location to the current bounds of the + * window's viewport. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceDrag { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceDragPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: "Fdc3UserInterfaceDrag"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceDragPayload { + /** + * The offset to move the frame by. + */ + mouseOffsets: MouseOffsets; +} + +/** + * The offset to move the frame by. + */ +export interface MouseOffsets { + x: number; + y: number; +} + +/** + * Identifies the type of the message to or from the user interface frame. + */ + +/** + * Handshake message sent back to a user interface from the DA proxy code (setup by + * `getAgent()`) over the `MessagePort` provide in the preceding iFrameHello message, + * confirming that it is listening to the `MessagePort` for further communication. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceHandshake { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceHandshakePayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: "Fdc3UserInterfaceHandshake"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceHandshakePayload { + /** + * The version of FDC3 API that the Desktop Agent will provide support for. + */ + fdc3Version: string; +} + +/** + * Identifies the type of the message to or from the user interface frame. + */ + +/** + * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate + * it is ready to communicate, containing initial CSS to set on the iframe, and including an + * appended `MessagePort` to be used for further communication. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceHello { + /** + * The message payload. */ - payload: EventListenerUnsubscribeRequestPayload; + payload: Fdc3UserInterfaceHelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: "eventListenerUnsubscribeRequest"; + type: "Fdc3UserInterfaceHello"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface EventListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface Fdc3UserInterfaceHelloPayload { + /** + * Details about the UI implementation, such as vendor and version, for logging purposes. + */ + implementationDetails: string; + /** + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + */ + initialCSS: InitialCSS; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to an eventListenerUnsubscribe request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. */ -export interface EventListenerUnsubscribeResponse { +export interface InitialCSS { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The initial bottom property to apply to the iframe. */ - meta: AddContextListenerResponseMeta; + bottom?: string; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The initial height of the iframe. */ - payload: BroadcastResponseResponsePayload; + height?: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The initial left property to apply to the iframe. */ - type: "eventListenerUnsubscribeResponse"; + left?: string; + /** + * The maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; + /** + * The transition property to apply to the iframe. + */ + transition?: string; + /** + * The initial width of the iframe. + */ + width?: string; + /** + * The initial zindex to apply to the iframe. + */ + zIndex?: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * Message from a channel selector UI to the DA proxy sent when the channel selection - * changes. - * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceChannelSelected { +export interface Fdc3UserInterfaceMessage { /** * The message payload. */ - payload: Fdc3UserInterfaceChannelSelectedPayload; + payload?: { [key: string]: any }; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceChannelSelected"; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceChannelSelectedPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; + type: Fdc3UserInterfaceMessageType; } /** * Identifies the type of the message to or from the user interface frame. */ +export type Fdc3UserInterfaceMessageType = "Fdc3UserInterfaceHello" | "Fdc3UserInterfaceHandshake" | "Fdc3UserInterfaceRestyle" | "Fdc3UserInterfaceDrag" | "Fdc3UserInterfaceResolve" | "Fdc3UserInterfaceResolveAction" | "Fdc3UserInterfaceChannels" | "Fdc3UserInterfaceChannelSelected"; /** - * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an - * iframe with the channel definitions and current channel selection. + * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the + * resolver data to setup the UI. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceChannels { +export interface Fdc3UserInterfaceResolve { /** * The message payload. */ - payload: Fdc3UserInterfaceChannelsPayload; + payload: Fdc3UserInterfaceResolvePayload; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceChannels"; + type: "Fdc3UserInterfaceResolve"; } /** * The message payload. */ -export interface Fdc3UserInterfaceChannelsPayload { +export interface Fdc3UserInterfaceResolvePayload { /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. + * An array of AppIntent objects defining the resolution options. */ - selected: null | string; + appIntents: AppIntent[]; + context: Context; +} + +/** + * An interface that relates an intent to apps. + * + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. + */ +export interface AppIntent { /** - * User Channel definitions.```````s + * Details of applications that can resolve the intent. */ - userChannels: Channel[]; + apps: AppMetadata[]; + /** + * Details of the intent whose relationship to resolving applications is being described. + */ + intent: IntentMetadata; } /** - * Identifies the type of the message to or from the user interface frame. + * Extends an `AppIdentifier`, describing an application or instance of an application, with + * additional descriptive metadata that is usually provided by an FDC3 App Directory that + * the Desktop Agent connects to. + * + * The additional information from an app directory can aid in rendering UI elements, such + * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon + * and screenshot URLs. + * + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the + * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. + * + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). */ +export interface AppMetadata { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * A longer, multi-paragraph description for the application that could include markup. + */ + description?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * A list of icon URLs for the application that can be used to render UI elements. + */ + icons?: Icon[]; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + /** + * An optional set of, implementation specific, metadata fields that can be used to + * disambiguate instances, such as a window title or screen position. Must only be set if + * `instanceId` is set. + */ + instanceMetadata?: { [key: string]: any }; + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now + * require an `AppIdentifier` wth `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to + * this field. + */ + name?: string; + /** + * The type of output returned for any intent specified during resolution. May express a + * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel + * that will receive a specified type (e.g. "channel"). + */ + resultType?: null | string; + /** + * Images representing the app in common usage scenarios that can be used to render UI + * elements. + */ + screenshots?: Image[]; + /** + * A more user-friendly application title that can be used to render UI elements. + */ + title?: string; + /** + * A tooltip for the application that can be used to render UI elements. + */ + tooltip?: string; + /** + * The Version of the application. + */ + version?: string; +} /** - * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user - * is dragging the UI to a new location and providing the offset to apply to the location. - * The DA proxy implementation should limit the location to the current bounds of the - * window's viewport. - * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * Describes an Icon image that may be used to represent the application. */ -export interface Fdc3UserInterfaceDrag { +export interface Icon { /** - * The message payload. + * The icon dimension, formatted as `x`. */ - payload: Fdc3UserInterfaceDragPayload; + size?: string; /** - * Identifies the type of the message to or from the user interface frame. + * The icon url. */ - type: "Fdc3UserInterfaceDrag"; + src: string; + /** + * Icon media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; } /** - * The message payload. + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. */ -export interface Fdc3UserInterfaceDragPayload { +export interface Image { /** - * The offset to move the frame by. + * Caption for the image. + */ + label?: string; + /** + * The image dimension, formatted as `x`. + */ + size?: string; + /** + * The image url. + */ + src: string; + /** + * Image media type. If not present the Desktop Agent may use the src file extension. */ - mouseOffsets: MouseOffsets; + type?: string; } /** - * The offset to move the frame by. + * Details of the intent whose relationship to resolving applications is being described. + * + * Metadata describing an Intent. */ -export interface MouseOffsets { - x: number; - y: number; +export interface IntentMetadata { + /** + * Display name for the intent. + */ + displayName?: string; + /** + * The unique name of the intent that can be invoked by the raiseIntent call. + */ + name: string; } /** @@ -1700,85 +1503,87 @@ export interface MouseOffsets { */ /** - * Handshake message sent back to a user interface from the DA proxy code (setup by - * `getAgent()`) over the `MessagePort` provided in the preceding Fdc3UserInterfaceHello - * message, confirming that it is listening to the `MessagePort` for further communication. + * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user + * action. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceHandshake { +export interface Fdc3UserInterfaceResolveAction { /** * The message payload. */ - payload: Fdc3UserInterfaceHandshakePayload; + payload: Fdc3UserInterfaceResolveActionPayload; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceHandshake"; + type: "Fdc3UserInterfaceResolveAction"; } /** * The message payload. */ -export interface Fdc3UserInterfaceHandshakePayload { +export interface Fdc3UserInterfaceResolveActionPayload { + action: Action; /** - * The version of FDC3 API that the Desktop Agent will provide support for. + * The App resolution option chosen. */ - fdc3Version: string; + appIdentifier?: AppIdentifier; + /** + * The intent resolved. + */ + intent?: string; } +export type Action = "hover" | "click" | "cancel"; + /** * Identifies the type of the message to or from the user interface frame. */ /** - * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate - * it is ready to communicate, containing initial CSS to set on the iframe, and including an - * appended `MessagePort` to be used for further communication. + * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling + * information to apply to it. Can be used to implement a pop-open or close interaction or + * other transition needed by a UI implementation. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceHello { +export interface Fdc3UserInterfaceRestyle { /** * The message payload. */ - payload: Fdc3UserInterfaceHelloPayload; + payload: Fdc3UserInterfaceRestylePayload; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceHello"; + type: "Fdc3UserInterfaceRestyle"; } /** * The message payload. */ -export interface Fdc3UserInterfaceHelloPayload { - /** - * Details about the UI implementation, such as vendor and version, for logging purposes. - */ - implementationDetails: string; +export interface Fdc3UserInterfaceRestylePayload { /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. */ - initialCSS: InitialCSS; + updatedCSS: UpdatedCSS; } /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. */ -export interface InitialCSS { +export interface UpdatedCSS { /** * The initial bottom property to apply to the iframe. */ bottom?: string; /** - * The initial height of the iframe. + * The updated height of the iframe. */ height?: string; /** @@ -1786,11 +1591,11 @@ export interface InitialCSS { */ left?: string; /** - * The maximum height to apply to the iframe. + * The updated maximum height to apply to the iframe. */ maxHeight?: string; /** - * The maximum with to apply to the iframe. + * The updated maximum with to apply to the iframe. */ maxWidth?: string; /** @@ -1802,15 +1607,15 @@ export interface InitialCSS { */ top?: string; /** - * The transition property to apply to the iframe. + * The updated transition property to apply to the iframe. */ transition?: string; /** - * The initial width of the iframe. + * The updated width of the iframe. */ width?: string; /** - * The initial zindex to apply to the iframe. + * The updated zIndex to apply to the iframe. */ zIndex?: string; [property: string]: any; @@ -1821,222 +1626,335 @@ export interface InitialCSS { */ /** - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request for details of instances of a particular app. + * + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceMessage { +export interface FindInstancesRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload?: { [key: string]: any }; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: Fdc3UserInterfaceMessageType; + payload: FindInstancesRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findInstancesRequest"; } /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ -export type Fdc3UserInterfaceMessageType = "Fdc3UserInterfaceHello" | "Fdc3UserInterfaceHandshake" | "Fdc3UserInterfaceRestyle" | "Fdc3UserInterfaceDrag" | "Fdc3UserInterfaceResolve" | "Fdc3UserInterfaceResolveAction" | "Fdc3UserInterfaceChannels" | "Fdc3UserInterfaceChannelSelected"; +export interface FindInstancesRequestPayload { + app: AppIdentifier; +} /** - * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the - * resolver data to setup the UI. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a findInstances request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceResolve { +export interface FindInstancesResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceResolvePayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: "Fdc3UserInterfaceResolve"; + payload: FindInstancesResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findInstancesResponse"; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + * + * The message payload contains a flag indicating whether the API call was successful, plus + * any return values for the FDC3 API function called, or indicating that the request + * resulted in an error and including a standardized error message. */ -export interface Fdc3UserInterfaceResolvePayload { +export interface FindInstancesResponsePayload { + error?: FindInstancesErrors; + appIdentifiers?: AppMetadata[]; +} + +/** + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + * + * Unique identifier for a `listener` object returned by a Desktop Agent to an app in + * response to addContextListener, addIntentListener or one of the PrivateChannel event + * listeners and used to identify it in messages (e.g. when unsubscribing). + * + * Unique identifier for an event message sent from a Desktop Agent to an app. + * + * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID + * should be used in the first (WCP1Hello) message and should be quoted in all subsequent + * messages to link them to the same connection attempt. + * + * Should be set if the raiseIntent request returned an error. + */ +export type FindInstancesErrors = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request for details of apps available to resolve a particular intent and context pair. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface FindIntentRequest { /** - * An array of AppIntent objects defining the resolution options. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - appIntents: AppIntent[]; - context: Context; + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentRequest"; } /** - * An interface that relates an intent to apps. + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentRequestPayload { + context?: Context; + intent: string; + resultType?: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a findIntent request. * - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface AppIntent { +export interface FindIntentResponse { /** - * Details of applications that can resolve the intent. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - apps: AppMetadata[]; + meta: AddContextListenerResponseMeta; /** - * Details of the intent whose relationship to resolving applications is being described. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - intent: IntentMetadata; + payload: FindIntentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentResponse"; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface FindIntentResponsePayload { + error?: FindInstancesErrors; + appIntent?: AppIntent; } /** - * Details of the intent whose relationship to resolving applications is being described. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request for details of intents and apps available to resolve them for a particular + * context. * - * Metadata describing an Intent. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentMetadata { +export interface FindIntentsByContextRequest { /** - * Display name for the intent. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - displayName?: string; + meta: AddContextListenerRequestMeta; /** - * The unique name of the intent that can be invoked by the raiseIntent call. + * The message payload typically contains the arguments to FDC3 API functions. */ - name: string; + payload: FindIntentsByContextRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentsByContextRequest"; } /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ +export interface FindIntentsByContextRequestPayload { + context: Context; + resultType?: string; +} /** - * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user - * action. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a findIntentsByContext request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceResolveAction { +export interface FindIntentsByContextResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceResolveActionPayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: "Fdc3UserInterfaceResolveAction"; + payload: FindIntentsByContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentsByContextResponse"; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceResolveActionPayload { - action: Action; - /** - * The App resolution option chosen. - */ - appIdentifier?: AppIdentifier; - /** - * The intent resolved. - */ - intent?: string; +export interface FindIntentsByContextResponsePayload { + error?: FindInstancesErrors; + appIntents?: AppIntent[]; } -export type Action = "hover" | "click" | "cancel"; - /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling - * information to apply to it. Can be used to implement a pop-open or close interaction or - * other transition needed by a UI implementation. + * A request for metadata about an app. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceRestyle { +export interface GetAppMetadataRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceRestylePayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: "Fdc3UserInterfaceRestyle"; + payload: GetAppMetadataRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "getAppMetadataRequest"; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceRestylePayload { - /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. - */ - updatedCSS: UpdatedCSS; +export interface GetAppMetadataRequestPayload { + app: AppIdentifier; } /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export interface UpdatedCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The updated height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The updated maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The updated maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; + +/** + * A response to a getAppMetadata request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface GetAppMetadataResponse { /** - * The updated transition property to apply to the iframe. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - transition?: string; + meta: AddContextListenerResponseMeta; /** - * The updated width of the iframe. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - width?: string; + payload: GetAppMetadataResponsePayload; /** - * The updated zIndex to apply to the iframe. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - zIndex?: string; - [property: string]: any; + type: "getAppMetadataResponse"; } /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface GetAppMetadataResponsePayload { + error?: FindInstancesErrors; + appMetadata?: AppMetadata; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request for details of instances of a particular app. + * A request to return the Channel object for the current User channel membership. Returns + * `null` if the app is not joined to a channel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindInstancesRequest { +export interface GetCurrentChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2044,19 +1962,18 @@ export interface FindInstancesRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindInstancesRequestPayload; + payload: GetCurrentChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "findInstancesRequest"; + type: "getCurrentChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindInstancesRequestPayload { - app: AppIdentifier; +export interface GetCurrentChannelRequestPayload { } /** @@ -2065,12 +1982,12 @@ export interface FindInstancesRequestPayload { */ /** - * A response to a findInstances request. + * A response to a getCurrentChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindInstancesResponse { +export interface GetCurrentChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2080,66 +1997,37 @@ export interface FindInstancesResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindInstancesResponsePayload; + payload: GetCurrentChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "findInstancesResponse"; + type: "getCurrentChannelResponse"; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - * - * The message payload contains a flag indicating whether the API call was successful, plus - * any return values for the FDC3 API function called, or indicating that the request - * resulted in an error and including a standardized error message. */ -export interface FindInstancesResponsePayload { - error?: FindInstancesErrors; - appIdentifiers?: AppMetadata[]; +export interface GetCurrentChannelResponsePayload { + error?: ResponsePayloadError; + channel?: Channel | null; } -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - * - * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID - * should be used in the first (WCP1Hello) message and should be quoted in all subsequent - * messages to link them to the same connection attempt. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - * - * Unique identifier for a `listener` object returned by a Desktop Agent to an app in - * response to addContextListener, addIntentListener or one of the PrivateChannel event - * listeners and used to identify it in messages (e.g. when unsubscribing). - * - * Unique identifier for an event message sent from a Desktop Agent to an app. - * - * Should be set if the raiseIntent request returned an error. - */ -export type FindInstancesErrors = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request for details of apps available to resolve a particular intent and context pair. + * A request to return the current context (either of a specified type or most recent + * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if + * one was specified) is available in the channel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentRequest { +export interface GetCurrentContextRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2147,21 +2035,27 @@ export interface FindIntentRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentRequestPayload; + payload: GetCurrentContextRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "findIntentRequest"; + type: "getCurrentContextRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentRequestPayload { - context?: Context; - intent: string; - resultType?: string; +export interface GetCurrentContextRequestPayload { + /** + * The id of the channel to return the current context of. + */ + channelId: string; + /** + * The type of context to return for OR `null` indicating that the most recently broadcast + * context on the channel should be returned. + */ + contextType: null | string; } /** @@ -2170,12 +2064,12 @@ export interface FindIntentRequestPayload { */ /** - * A response to a findIntent request. + * A response to a getCurrentContext request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentResponse { +export interface GetCurrentContextResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2185,12 +2079,12 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentResponsePayload; + payload: GetCurrentContextResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "findIntentResponse"; + type: "getCurrentContextResponse"; } /** @@ -2198,9 +2092,13 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentResponsePayload { - error?: FindInstancesErrors; - appIntent?: AppIntent; +export interface GetCurrentContextResponsePayload { + error?: PurpleError; + /** + * The most recently broadcast context object (of the specified type, if one was specified), + * or `null` if none was available in the channel. + */ + context?: null | Context; } /** @@ -2209,12 +2107,12 @@ export interface FindIntentResponsePayload { */ /** - * A request for details of intents and apps available to resolve them for a particular - * context. + * Request to retrieve information about the FDC3 Desktop Agent implementation and the + * metadata of the calling application according to the Desktop Agent. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentsByContextRequest { +export interface GetInfoRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2222,20 +2120,18 @@ export interface FindIntentsByContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentsByContextRequestPayload; + payload: GetInfoRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "findIntentsByContextRequest"; + type: "getInfoRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentsByContextRequestPayload { - context: Context; - resultType?: string; +export interface GetInfoRequestPayload { } /** @@ -2244,12 +2140,12 @@ export interface FindIntentsByContextRequestPayload { */ /** - * A response to a findIntentsByContext request. + * A response to a getInfo request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentsByContextResponse { +export interface GetInfoResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2259,12 +2155,12 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentsByContextResponsePayload; + payload: GetInfoResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "findIntentsByContextResponse"; + type: "getInfoResponse"; } /** @@ -2272,9 +2168,67 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentsByContextResponsePayload { - error?: FindInstancesErrors; - appIntents?: AppIntent[]; +export interface GetInfoResponsePayload { + error?: ResponsePayloadError; + implementationMetadata?: ImplementationMetadata; +} + +/** + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. + * + * Includes Metadata for the current application. + * + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + */ +export interface ImplementationMetadata { + /** + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). + */ + appMetadata: AppMetadata; + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ +export interface OptionalFeatures { + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + DesktopAgentBridging: boolean; + /** + * Used to indicate whether the exposure of 'originating app metadata' for + * context and intent messages is supported by the Desktop Agent. + */ + OriginatingAppMetadata: boolean; + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + UserChannelMembershipAPIs: boolean; } /** @@ -2283,11 +2237,12 @@ export interface FindIntentsByContextResponsePayload { */ /** - * A request for metadata about an app. + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetAppMetadataRequest { +export interface GetOrCreateChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2295,19 +2250,22 @@ export interface GetAppMetadataRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetAppMetadataRequestPayload; + payload: GetOrCreateChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getAppMetadataRequest"; + type: "getOrCreateChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetAppMetadataRequestPayload { - app: AppIdentifier; +export interface GetOrCreateChannelRequestPayload { + /** + * The id of the channel to return + */ + channelId: string; } /** @@ -2316,12 +2274,12 @@ export interface GetAppMetadataRequestPayload { */ /** - * A response to a getAppMetadata request. + * A response to a getOrCreateChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetAppMetadataResponse { +export interface GetOrCreateChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2331,12 +2289,12 @@ export interface GetAppMetadataResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetAppMetadataResponsePayload; + payload: GetOrCreateChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getAppMetadataResponse"; + type: "getOrCreateChannelResponse"; } /** @@ -2344,9 +2302,9 @@ export interface GetAppMetadataResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetAppMetadataResponsePayload { - error?: FindInstancesErrors; - appMetadata?: AppMetadata; +export interface GetOrCreateChannelResponsePayload { + error?: PurpleError; + channel?: Channel; } /** @@ -2355,12 +2313,11 @@ export interface GetAppMetadataResponsePayload { */ /** - * A request to return the Channel object for the current User channel membership. Returns - * `null` if the app is not joined to a channel. + * Request to retrieve a list of the User Channels available for the app to join. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetCurrentChannelRequest { +export interface GetUserChannelsRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2368,18 +2325,18 @@ export interface GetCurrentChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetCurrentChannelRequestPayload; + payload: GetUserChannelsRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getCurrentChannelRequest"; + type: "getUserChannelsRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentChannelRequestPayload { +export interface GetUserChannelsRequestPayload { } /** @@ -2388,12 +2345,12 @@ export interface GetCurrentChannelRequestPayload { */ /** - * A response to a getCurrentChannel request. + * A response to a getUserChannels request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetCurrentChannelResponse { +export interface GetUserChannelsResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2403,12 +2360,12 @@ export interface GetCurrentChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetCurrentChannelResponsePayload; + payload: GetUserChannelsResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getCurrentChannelResponse"; + type: "getUserChannelsResponse"; } /** @@ -2416,9 +2373,9 @@ export interface GetCurrentChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetCurrentChannelResponsePayload { - error?: ResponsePayloadError; - channel?: Channel | null; +export interface GetUserChannelsResponsePayload { + error?: PurpleError; + userChannels?: Channel[]; } /** @@ -2427,13 +2384,12 @@ export interface GetCurrentChannelResponsePayload { */ /** - * A request to return the current context (either of a specified type or most recent - * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if - * one was specified) is available in the channel. + * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent + * and indicates that an application window or frame is still alive. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetCurrentContextRequest { +export interface HeartbeatAcknowledgementRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2441,70 +2397,106 @@ export interface GetCurrentContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetCurrentContextRequestPayload; + payload: HeartbeatAcknowledgementRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getCurrentContextRequest"; + type: "heartbeatAcknowledgementRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentContextRequestPayload { +export interface HeartbeatAcknowledgementRequestPayload { /** - * The id of the channel to return the current context of. + * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. */ - channelId: string; + heartbeatEventUuid: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is + * alive and that the application should send a heartbeatResponseRequest to the agent in + * response. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface HeartbeatEvent { /** - * The type of context to return for OR `null` indicating that the most recently broadcast - * context on the channel should be returned. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - contextType: null | string; + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: HeartbeatEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "heartbeatEvent"; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface HeartbeatEventPayload { } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a getCurrentContext request. + * An event message from the Desktop Agent to an app indicating that it has been selected to + * resolve a raised intent and context. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface GetCurrentContextResponse { +export interface IntentEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: GetCurrentContextResponsePayload; + payload: IntentEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getCurrentContextResponse"; + type: "intentEvent"; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface GetCurrentContextResponsePayload { - error?: PurpleError; +export interface IntentEventPayload { + /** + * The context object passed with the raised intent. + */ + context: Context; + /** + * The intent that was raised. + */ + intent: string; + /** + * Details of the application instance that raised the intent. + */ + originatingApp?: AppIdentifier; /** - * The most recently broadcast context object (of the specified type, if one was specified), - * or `null` if none was available in the channel. + * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates + * to. */ - context?: null | Context; + raiseIntentRequestUuid: string; } /** @@ -2513,12 +2505,11 @@ export interface GetCurrentContextResponsePayload { */ /** - * Request to retrieve information about the FDC3 Desktop Agent implementation and the - * metadata of the calling application according to the Desktop Agent. + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetInfoRequest { +export interface IntentListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2526,18 +2517,19 @@ export interface GetInfoRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetInfoRequestPayload; + payload: IntentListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getInfoRequest"; + type: "intentListenerUnsubscribeRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetInfoRequestPayload { +export interface IntentListenerUnsubscribeRequestPayload { + listenerUUID: string; } /** @@ -2546,12 +2538,12 @@ export interface GetInfoRequestPayload { */ /** - * A response to a getInfo request. + * A response to a intentListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetInfoResponse { +export interface IntentListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2561,22 +2553,12 @@ export interface GetInfoResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetInfoResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getInfoResponse"; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetInfoResponsePayload { - error?: ResponsePayloadError; - implementationMetadata?: ImplementationMetadata; + type: "intentListenerUnsubscribeResponse"; } /** @@ -2585,12 +2567,13 @@ export interface GetInfoResponsePayload { */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * A request to deliver a result for an intent (which may include a `void` result that just + * indicates that the handler has run, returning no result). The result is tied to the + * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetOrCreateChannelRequest { +export interface IntentResultRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2598,22 +2581,32 @@ export interface GetOrCreateChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetOrCreateChannelRequestPayload; + payload: IntentResultRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getOrCreateChannelRequest"; + type: "intentResultRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetOrCreateChannelRequestPayload { +export interface IntentResultRequestPayload { /** - * The id of the channel to return + * The eventUuid value of the intentEvent that the result being sent relates to. */ - channelId: string; + intentEventUuid: string; + intentResult: IntentResult; + /** + * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + */ + raiseIntentRequestUuid: string; +} + +export interface IntentResult { + context?: Context; + channel?: Channel; } /** @@ -2622,12 +2615,12 @@ export interface GetOrCreateChannelRequestPayload { */ /** - * A response to a getOrCreateChannel request. + * A response to a request to deliver an intent result. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetOrCreateChannelResponse { +export interface IntentResultResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2637,22 +2630,12 @@ export interface GetOrCreateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetOrCreateChannelResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getOrCreateChannelResponse"; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetOrCreateChannelResponsePayload { - error?: PurpleError; - channel?: Channel; + type: "intentResultResponse"; } /** @@ -2661,11 +2644,13 @@ export interface GetOrCreateChannelResponsePayload { */ /** - * Request to retrieve a list of the User Channels available for the app to join. + * Request to join the app to the specified User channel. On successfully joining a channel, + * client code should make subsequent requests to get the current context of that channel + * for all registered context listeners and then call their handlers with it. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetUserChannelsRequest { +export interface JoinUserChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2673,18 +2658,22 @@ export interface GetUserChannelsRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetUserChannelsRequestPayload; + payload: JoinUserChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getUserChannelsRequest"; + type: "joinUserChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetUserChannelsRequestPayload { +export interface JoinUserChannelRequestPayload { + /** + * The id of the channel to join. + */ + channelId: string; } /** @@ -2693,12 +2682,14 @@ export interface GetUserChannelsRequestPayload { */ /** - * A response to a getUserChannels request. + * A response to a joinUserChannel request. On receipt of this response, client code should + * make subsequent requests to get the current context of that channel for all registered + * context listeners and then call their handlers with it. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetUserChannelsResponse { +export interface JoinUserChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2708,12 +2699,12 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetUserChannelsResponsePayload; + payload: JoinUserChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getUserChannelsResponse"; + type: "joinUserChannelResponse"; } /** @@ -2721,9 +2712,8 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetUserChannelsResponsePayload { +export interface JoinUserChannelResponsePayload { error?: PurpleError; - userChannels?: Channel[]; } /** @@ -2732,12 +2722,11 @@ export interface GetUserChannelsResponsePayload { */ /** - * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent - * and indicates that an application window or frame is still alive. + * Request to remove the app from any User channel membership. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface HeartbeatAcknowledgementRequest { +export interface LeaveCurrentChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2745,22 +2734,18 @@ export interface HeartbeatAcknowledgementRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: HeartbeatAcknowledgementRequestPayload; + payload: LeaveCurrentChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "heartbeatAcknowledgementRequest"; + type: "leaveCurrentChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface HeartbeatAcknowledgementRequestPayload { - /** - * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. - */ - heartbeatEventUuid: string; +export interface LeaveCurrentChannelRequestPayload { } /** @@ -2769,82 +2754,36 @@ export interface HeartbeatAcknowledgementRequestPayload { */ /** - * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is - * alive and that the application should send a heartbeatResponseRequest to the agent in - * response. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. - */ -export interface HeartbeatEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: HeartbeatEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "heartbeatEvent"; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface HeartbeatEventPayload { -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that it has been selected to - * resolve a raised intent and context. + * A response to a leaveCurrentChannel request. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentEvent { +export interface LeaveCurrentChannelResponse { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: BroadcastEventMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: IntentEventPayload; + payload: LeaveCurrentChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "intentEvent"; + type: "leaveCurrentChannelResponse"; } /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface IntentEventPayload { - /** - * The context object passed with the raised intent. - */ - context: Context; - /** - * The intent that was raised. - */ - intent: string; - /** - * Details of the application instance that raised the intent. - */ - originatingApp?: AppIdentifier; - /** - * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates - * to. - */ - raiseIntentRequestUuid: string; +export interface LeaveCurrentChannelResponsePayload { + error?: PurpleError; } /** @@ -2853,11 +2792,11 @@ export interface IntentEventPayload { */ /** - * A request to unsubscribe a context listener. + * A request to open an application. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentListenerUnsubscribeRequest { +export interface OpenRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2865,19 +2804,25 @@ export interface IntentListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentListenerUnsubscribeRequestPayload; + payload: OpenRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "intentListenerUnsubscribeRequest"; + type: "openRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface OpenRequestPayload { + app: AppIdentifier; + /** + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. + */ + context?: Context; } /** @@ -2886,12 +2831,12 @@ export interface IntentListenerUnsubscribeRequestPayload { */ /** - * A response to a intentListenerUnsubscribe request. + * A response to a open request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentListenerUnsubscribeResponse { +export interface OpenResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2901,27 +2846,45 @@ export interface IntentListenerUnsubscribeResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: OpenResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "intentListenerUnsubscribeResponse"; + type: "openResponse"; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface OpenResponsePayload { + error?: OpenErrorResponsePayload; + appIdentifier?: AppIdentifier; +} + +/** + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ +export type OpenErrorResponsePayload = "MalformedContext" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; /** - * A request to deliver a result for an intent (which may include a `void` result that just - * indicates that the handler has run, returning no result). The result is tied to the - * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to add an event listener to a specific PrivateChannel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentResultRequest { +export interface PrivateChannelAddEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2929,33 +2892,34 @@ export interface IntentResultRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentResultRequestPayload; + payload: TPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "intentResultRequest"; + type: "privateChannelAddEventListenerRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentResultRequestPayload { +export interface TPayload { /** - * The eventUuid value of the intentEvent that the result being sent relates to. + * The type of PrivateChannel event that the listener should be applied to. */ - intentEventUuid: string; - intentResult: IntentResult; + listenerType: PrivateChannelEventListenerTypes; /** - * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + * The Id of the PrivateChannel that the listener should be added to. */ - raiseIntentRequestUuid: string; + privateChannelId: string; } -export interface IntentResult { - context?: Context; - channel?: Channel; -} +/** + * The type of PrivateChannel event that the listener should be applied to. + * + * Event listener type names for Private Channel events. + */ +export type PrivateChannelEventListenerTypes = "onAddContextListener" | "onUnsubscribe" | "onDisconnect"; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2963,12 +2927,12 @@ export interface IntentResult { */ /** - * A response to a request to deliver an intent result. + * A response to a privateChannelAddEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentResultResponse { +export interface PrivateChannelAddEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2978,12 +2942,23 @@ export interface IntentResultResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: PrivateChannelAddEventListenerResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "intentResultResponse"; + type: "privateChannelAddEventListenerResponse"; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface PrivateChannelAddEventListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; + [property: string]: any; } /** @@ -2992,13 +2967,12 @@ export interface IntentResultResponse { */ /** - * Request to join the app to the specified User channel. On successfully joining a channel, - * client code should make subsequent requests to get the current context of that channel - * for all registered context listeners and then call their handlers with it. + * Request that indicates that a participant will no longer interact with a specified + * `PrivateChannel`. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface JoinUserChannelRequest { +export interface PrivateChannelDisconnectRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3006,20 +2980,20 @@ export interface JoinUserChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: JoinUserChannelRequestPayload; + payload: PrivateChannelDisconnectRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "joinUserChannelRequest"; + type: "privateChannelDisconnectRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface JoinUserChannelRequestPayload { +export interface PrivateChannelDisconnectRequestPayload { /** - * The id of the channel to join. + * The Id of the Channel that should be disconnected from */ channelId: string; } @@ -3030,14 +3004,12 @@ export interface JoinUserChannelRequestPayload { */ /** - * A response to a joinUserChannel request. On receipt of this response, client code should - * make subsequent requests to get the current context of that channel for all registered - * context listeners and then call their handlers with it. + * A response to a privateChannelDisconnect request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface JoinUserChannelResponse { +export interface PrivateChannelDisconnectResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3047,12 +3019,12 @@ export interface JoinUserChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: JoinUserChannelResponsePayload; + payload: PrivateChannelDisconnectResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "joinUserChannelResponse"; + type: "privateChannelDisconnectResponse"; } /** @@ -3060,7 +3032,7 @@ export interface JoinUserChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface JoinUserChannelResponsePayload { +export interface PrivateChannelDisconnectResponsePayload { error?: PurpleError; } @@ -3070,68 +3042,77 @@ export interface JoinUserChannelResponsePayload { */ /** - * Request to remove the app from any User channel membership. + * An event message from the Desktop Agent to an app indicating that another app has added a + * context listener to a specific PrivateChannel. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface LeaveCurrentChannelRequest { +export interface PrivateChannelOnAddContextListenerEvent { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerRequestMeta; + meta: BroadcastEventMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ - payload: LeaveCurrentChannelRequestPayload; + payload: PrivateChannelOnAddContextListenerEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "leaveCurrentChannelRequest"; + type: "privateChannelOnAddContextListenerEvent"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ -export interface LeaveCurrentChannelRequestPayload { +export interface PrivateChannelOnAddContextListenerEventPayload { + /** + * The type of the context listener added to the channel by another app, or null if it will + * listen to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was added to. + */ + privateChannelId: string; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a leaveCurrentChannel request. + * An event message from the Desktop Agent to an app indicating that another app has + * disconnected from a specific PrivateChannel and will no longer interact with it. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface LeaveCurrentChannelResponse { +export interface PrivateChannelOnDisconnectEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: LeaveCurrentChannelResponsePayload; + payload: PrivateChannelOnDisconnectEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "leaveCurrentChannelResponse"; + type: "privateChannelOnDisconnectEvent"; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface LeaveCurrentChannelResponsePayload { - error?: PurpleError; +export interface PrivateChannelOnDisconnectEventPayload { + /** + * The Id of the PrivateChannel that the app has disconnected from. + */ + privateChannelId: string; } /** @@ -3140,11 +3121,53 @@ export interface LeaveCurrentChannelResponsePayload { */ /** - * A request to open an application. + * An event message from the Desktop Agent to an app indicating that another app has + * unsubscribed a context listener from a specific PrivateChannel. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface PrivateChannelOnUnsubscribeEvent { + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: PrivateChannelOnUnsubscribeEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "privateChannelOnUnsubscribeEvent"; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface PrivateChannelOnUnsubscribeEventPayload { + /** + * The type of the context listener unsubscribed from the channel by another app, or null if + * it was listening to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was unsubscribed from. + */ + privateChannelId: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface OpenRequest { +export interface PrivateChannelUnsubscribeEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3152,25 +3175,19 @@ export interface OpenRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: OpenRequestPayload; + payload: PrivateChannelUnsubscribeEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "openRequest"; + type: "privateChannelUnsubscribeEventListenerRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface OpenRequestPayload { - app: AppIdentifier; - /** - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. - */ - context?: Context; +export interface PrivateChannelUnsubscribeEventListenerRequestPayload { + listenerUUID: string; } /** @@ -3179,12 +3196,12 @@ export interface OpenRequestPayload { */ /** - * A response to a open request. + * A response to a privateChannelUnsubscribeEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface OpenResponse { +export interface PrivateChannelUnsubscribeEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3194,45 +3211,25 @@ export interface OpenResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: OpenResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "openResponse"; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface OpenResponsePayload { - error?: OpenErrorResponsePayload; - appIdentifier?: AppIdentifier; + type: "privateChannelUnsubscribeEventListenerResponse"; } -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type OpenErrorResponsePayload = "MalformedContext" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request to add an event listener to a specific PrivateChannel. + * A request to raise an unspecified intent for a specified context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface PrivateChannelAddEventListenerRequest { +export interface RaiseIntentForContextRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3240,47 +3237,34 @@ export interface PrivateChannelAddEventListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: TPayload; + payload: RaiseIntentForContextRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "privateChannelAddEventListenerRequest"; + type: "raiseIntentForContextRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface TPayload { - /** - * The type of PrivateChannel event that the listener should be applied to. - */ - listenerType: PrivateChannelEventListenerTypes; - /** - * The Id of the PrivateChannel that the listener should be added to. - */ - privateChannelId: string; +export interface RaiseIntentForContextRequestPayload { + app?: AppIdentifier; + context: Context; } -/** - * The type of PrivateChannel event that the listener should be applied to. - * - * Event listener type names for Private Channel events. - */ -export type PrivateChannelEventListenerTypes = "onAddContextListener" | "onUnsubscribe" | "onDisconnect"; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * A response to a privateChannelAddEventListener request. + * A response to a raiseIntentForContext request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelAddEventListenerResponse { +export interface RaiseIntentForContextResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3289,24 +3273,89 @@ export interface PrivateChannelAddEventListenerResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). */ - payload: PrivateChannelAddEventListenerResponsePayload; + payload: RaiseIntentForContextResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "privateChannelAddEventListenerResponse"; + type: "raiseIntentForContextResponse"; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). + * + * Response to a raiseIntentForContext request that needs additional resolution (i.e. show + * an intent resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface PrivateChannelAddEventListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; - [property: string]: any; +export interface RaiseIntentForContextResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing + * an intent resolver) before it can be handled. + */ + appIntents?: AppIntent[]; +} + +/** + * Used if the raiseIntent request was successfully resolved. + * + * IntentResolution provides a standard format for data returned upon resolving an intent. + * + * ```javascript + * //resolve a "Chain" type intent + * let resolution = await agent.raiseIntent("intentName", context); + * + * //resolve a "Client-Service" type intent with a data response or a Channel + * let resolution = await agent.raiseIntent("intentName", context); + * try { + * const result = await resolution.getResult(); + * if (result && result.broadcast) { + * console.log(`${resolution.source} returned a channel with id ${result.id}`); + * } else if (result){ + * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); + * } else { + * console.error(`${resolution.source} didn't return data` + * } + * } catch(error) { + * console.error(`${resolution.source} returned an error: ${error}`); + * } + * + * // Use metadata about the resolving app instance to target a further intent + * await agent.raiseIntent("intentName", context, resolution.source); + * ``` + */ +export interface IntentResolution { + /** + * The intent that was raised. May be used to determine which intent the user + * chose in response to `fdc3.raiseIntentForContext()`. + */ + intent: string; + /** + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ + source: AppIdentifier; } /** @@ -3315,12 +3364,11 @@ export interface PrivateChannelAddEventListenerResponsePayload { */ /** - * Request that indicates that a participant will no longer interact with a specified - * `PrivateChannel`. + * A request to raise an intent for a context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface PrivateChannelDisconnectRequest { +export interface RaiseIntentRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3328,22 +3376,21 @@ export interface PrivateChannelDisconnectRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: PrivateChannelDisconnectRequestPayload; + payload: RaiseIntentRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "privateChannelDisconnectRequest"; + type: "raiseIntentRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface PrivateChannelDisconnectRequestPayload { - /** - * The Id of the Channel that should be disconnected from - */ - channelId: string; +export interface RaiseIntentRequestPayload { + app?: AppIdentifier; + context: Context; + intent: string; } /** @@ -3352,12 +3399,12 @@ export interface PrivateChannelDisconnectRequestPayload { */ /** - * A response to a privateChannelDisconnect request. + * A response to a raiseIntent request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelDisconnectResponse { +export interface RaiseIntentResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3366,22 +3413,47 @@ export interface PrivateChannelDisconnectResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). */ - payload: PrivateChannelDisconnectResponsePayload; + payload: RaiseIntentResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "privateChannelDisconnectResponse"; + type: "raiseIntentResponse"; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). + * + * Response to a raiseIntent request that needs additional resolution (i.e. show an intent + * resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface PrivateChannelDisconnectResponsePayload { - error?: PurpleError; +export interface RaiseIntentResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. + */ + appIntent?: AppIntent; } /** @@ -3390,40 +3462,39 @@ export interface PrivateChannelDisconnectResponsePayload { */ /** - * An event message from the Desktop Agent to an app indicating that another app has added a - * context listener to a specific PrivateChannel. + * A secondary response to a request to raise an intent used to deliver the intent result. + * This message should quote the original requestUuid of the raiseIntentRequest message in + * its `meta.requestUuid` field. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelOnAddContextListenerEvent { +export interface RaiseIntentResultResponse { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: BroadcastEventMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: PrivateChannelOnAddContextListenerEventPayload; + payload: RaiseIntentResultResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "privateChannelOnAddContextListenerEvent"; + type: "raiseIntentResultResponse"; } /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface PrivateChannelOnAddContextListenerEventPayload { - /** - * The type of the context listener added to the channel by another app, or null if it will - * listen to all types. - */ - contextType: null | string; - /** - * The Id of the PrivateChannel that the listener was added to. - */ - privateChannelId: string; +export interface RaiseIntentResultResponsePayload { + error?: ResponsePayloadError; + intentResult?: IntentResult; } /** @@ -3432,491 +3503,356 @@ export interface PrivateChannelOnAddContextListenerEventPayload { */ /** - * An event message from the Desktop Agent to an app indicating that another app has - * disconnected from a specific PrivateChannel and will no longer interact with it. + * Hello message sent by an application to a parent window or frame when attempting to + * establish connectivity to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelOnDisconnectEvent { +export interface WebConnectionProtocol1Hello { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for a Web Connection Protocol message. */ - meta: BroadcastEventMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload contains details of the event that the app is being notified about. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelOnDisconnectEventPayload; + payload: WebConnectionProtocol1HelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "privateChannelOnDisconnectEvent"; + type: "WCP1Hello"; } /** - * The message payload contains details of the event that the app is being notified about. + * Metadata for a Web Connection Protocol message. */ -export interface PrivateChannelOnDisconnectEventPayload { - /** - * The Id of the PrivateChannel that the app has disconnected from. - */ - privateChannelId: string; +export interface WebConnectionProtocol1HelloMeta { + connectionAttemptUuid: string; + timestamp: Date; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that another app has - * unsubscribed a context listener from a specific PrivateChannel. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelOnUnsubscribeEvent { +export interface WebConnectionProtocol1HelloPayload { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - meta: BroadcastEventMeta; + actualUrl: string; /** - * The message payload contains details of the event that the app is being notified about. + * A flag that may be used to indicate that a channel selector user interface is or is not + * required. Set to `false` if the app includes its own interface for selecting channels or + * does not work with user channels. */ - payload: PrivateChannelOnUnsubscribeEventPayload; + channelSelector?: boolean; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The version of FDC3 API that the app supports. */ - type: "privateChannelOnUnsubscribeEvent"; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface PrivateChannelOnUnsubscribeEventPayload { + fdc3Version: string; /** - * The type of the context listener unsubscribed from the channel by another app, or null if - * it was listening to all types. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - contextType: null | string; + identityUrl: string; /** - * The Id of the PrivateChannel that the listener was unsubscribed from. + * A flag that may be used to indicate that an intent resolver is or is not required. Set to + * `false` if no intents, or only targeted intents, are raised. */ - privateChannelId: string; + intentResolver?: boolean; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to unsubscribe a context listener. + * Response from a Desktop Agent to an application requesting access to it indicating that + * it should load a specified URL into a hidden iframe in order to establish connectivity to + * a Desktop Agent. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerRequest { +export interface WebConnectionProtocol2LoadURL { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelUnsubscribeEventListenerRequestPayload; + payload: WebConnectionProtocol2LoadURLPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: "privateChannelUnsubscribeEventListenerRequest"; + type: "WCP2LoadUrl"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelUnsubscribeEventListenerRequestPayload { - listenerUUID: string; +export interface WebConnectionProtocol2LoadURLPayload { + /** + * A URL which can be used to establish communication with the Desktop Agent, via loading + * the URL into an iframe and restarting the Web Connection protocol with the iframe as the + * target. + */ + iframeUrl: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a privateChannelUnsubscribeEventListener request. + * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that + * should be used for subsequent communication steps. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerResponse { +export interface WebConnectionProtocol3Handshake { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: BroadcastResponseResponsePayload; + payload: WebConnectionProtocol3HandshakePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "privateChannelUnsubscribeEventListenerResponse"; + type: "WCP3Handshake"; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to raise an unspecified intent for a specified context. - * - * A request message from an FDC3-enabled app to a Desktop Agent. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextRequest { +export interface WebConnectionProtocol3HandshakePayload { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Indicates whether a channel selector user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the channel selector (as the + * Desktop Agent will handle it another way). */ - meta: AddContextListenerRequestMeta; + channelSelectorUrl: boolean | string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The version of FDC3 API that the Desktop Agent will provide support for. */ - payload: RaiseIntentForContextRequestPayload; + fdc3Version: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Indicates whether an intent resolver user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the intent resolver (as the + * Desktop Agent will handle it another way). */ - type: "raiseIntentForContextRequest"; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface RaiseIntentForContextRequestPayload { - app?: AppIdentifier; - context: Context; + intentResolverUrl: boolean | string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntentForContext request. + * Identity Validation request from an app attempting to connect to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentForContextResponse { +export interface WebConnectionProtocol4ValidateAppIdentity { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentForContextResponsePayload; + payload: WebConnectionProtocol4ValidateAppIdentityPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "raiseIntentForContextResponse"; + type: "WCP4ValidateAppIdentity"; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). - * - * Response to a raiseIntentForContext request that needs additional resolution (i.e. show - * an intent resolver UI). - * - * Used if a raiseIntent request resulted in an error. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol4ValidateAppIdentityPayload { /** - * Used if the raiseIntent request was successfully resolved. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - intentResolution?: IntentResolution; + actualUrl: string; /** - * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing - * an intent resolver) before it can be handled. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - appIntents?: AppIntent[]; -} - -/** - * Used if the raiseIntent request was successfully resolved. - * - * IntentResolution provides a standard format for data returned upon resolving an intent. - * - * ```javascript - * //resolve a "Chain" type intent - * let resolution = await agent.raiseIntent("intentName", context); - * - * //resolve a "Client-Service" type intent with a data response or a Channel - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { - * console.log(`${resolution.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return data` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * - * // Use metadata about the resolving app instance to target a further intent - * await agent.raiseIntent("intentName", context, resolution.source); - * ``` - */ -export interface IntentResolution { + identityUrl: string; /** - * The intent that was raised. May be used to determine which intent the user - * chose in response to `fdc3.raiseIntentForContext()`. + * If an application has previously connected to the Desktop Agent, it may specify its prior + * instance id and associated instance UUID to request the same same instance Id be assigned. */ - intent: string; + instanceId?: string; /** - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. + * Instance UUID associated with the requested instanceId. */ - source: AppIdentifier; + instanceUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to raise an intent for a context. + * Message sent by the Desktop Agent to an app if their identity validation fails. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentRequest { +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentRequestPayload; + payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: "raiseIntentRequest"; + type: "WCP5ValidateAppIdentityFailedResponse"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentRequestPayload { - app?: AppIdentifier; - context: Context; - intent: string; +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { + message?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntent request. + * Message sent by the Desktop Agent to an app after successful identity validation. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; + /** + * Identifies the type of the connection step message. + */ + type: "WCP5ValidateAppIdentityResponse"; +} + +/** + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentResponse { +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The appId that the app's identity was validated against. */ - meta: AddContextListenerResponseMeta; + appId: string; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. */ - payload: RaiseIntentResponsePayload; + implementationMetadata: ImplementationMetadata; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The instance Id granted to the application by the Desktop Agent. */ - type: "raiseIntentResponse"; + instanceId: string; + /** + * Instance UUID associated with the instanceId granted, which may be used to retrieve the + * same instanceId if the app is reloaded or navigates. + */ + instanceUuid: string; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). - * - * Response to a raiseIntent request that needs additional resolution (i.e. show an intent - * resolver UI). + * Identifies the type of the connection step message. + */ + +/** + * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the + * window or navigating). Desktop Agents should close the MessagePort after receiving this + * message, but retain instance details in case the application reconnects (e.g. after a + * navigation event). * - * Used if a raiseIntent request resulted in an error. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol6Goodbye { /** - * Used if the raiseIntent request was successfully resolved. + * Metadata for a Web Connection Protocol message. */ - intentResolution?: IntentResolution; + meta: WebConnectionProtocol6GoodbyeMeta; /** - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * Identifies the type of the connection step message. */ - appIntent?: AppIntent; + type: "WCP6Goodbye"; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Metadata for a Web Connection Protocol message. */ +export interface WebConnectionProtocol6GoodbyeMeta { + timestamp: Date; +} /** - * A secondary response to a request to raise an intent used to deliver the intent result. - * This message should quote the original requestUuid of the raiseIntentRequest message in - * its `meta.requestUuid` field. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * Identifies the type of the connection step message. */ -export interface RaiseIntentResultResponse { + +/** + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocolMessage { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: ConnectionStepMetadata; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentResultResponsePayload; + payload?: { [key: string]: any }; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "raiseIntentResultResponse"; + type: ConnectionStepMessageType; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Metadata for a Web Connection Protocol message. */ -export interface RaiseIntentResultResponsePayload { - error?: ResponsePayloadError; - intentResult?: IntentResult; +export interface ConnectionStepMetadata { + timestamp: Date; + connectionAttemptUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ +export type ConnectionStepMessageType = "WCP1Hello" | "WCP2LoadUrl" | "WCP3Handshake" | "WCP4ValidateAppIdentity" | "WCP5ValidateAppIdentityFailedResponse" | "WCP5ValidateAppIdentityResponse" | "WCP6Goodbye"; // Converts JSON strings to/from your types // and asserts the results of JSON.parse at runtime export class Convert { - public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { - return cast(JSON.parse(json), r("WebConnectionProtocol1Hello")); - } - - public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol1Hello")), null, 2); - } - - public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { - return cast(JSON.parse(json), r("WebConnectionProtocol2LoadURL")); - } - - public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol2LoadURL")), null, 2); - } - - public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { - return cast(JSON.parse(json), r("WebConnectionProtocol3Handshake")); - } - - public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol3Handshake")), null, 2); - } - - public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { - return cast(JSON.parse(json), r("WebConnectionProtocol4ValidateAppIdentity")); - } - - public static webConnectionProtocol4ValidateAppIdentityToJson(value: WebConnectionProtocol4ValidateAppIdentity): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol4ValidateAppIdentity")), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json: string): WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")); - } - - public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value: WebConnectionProtocol5ValidateAppIdentityFailedResponse): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json: string): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")); - } - - public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")), null, 2); - } - - public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { - return cast(JSON.parse(json), r("WebConnectionProtocol6Goodbye")); - } - - public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol6Goodbye")), null, 2); - } - - public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { - return cast(JSON.parse(json), r("WebConnectionProtocolMessage")); - } - - public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocolMessage")), null, 2); - } - public static toAddContextListenerRequest(json: string): AddContextListenerRequest { return cast(JSON.parse(json), r("AddContextListenerRequest")); } @@ -4069,14 +4005,6 @@ export class Convert { return JSON.stringify(uncast(value, r("EventListenerUnsubscribeResponse")), null, 2); } - public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { - return cast(JSON.parse(json), r("Fdc3UserInterfaceChannelSelected")); - } - - public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannelSelected")), null, 2); - } - public static toFdc3UserInterfaceChannels(json: string): Fdc3UserInterfaceChannels { return cast(JSON.parse(json), r("Fdc3UserInterfaceChannels")); } @@ -4085,6 +4013,14 @@ export class Convert { return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannels")), null, 2); } + public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { + return cast(JSON.parse(json), r("Fdc3UserInterfaceChannelSelected")); + } + + public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { + return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannelSelected")), null, 2); + } + public static toFdc3UserInterfaceDrag(json: string): Fdc3UserInterfaceDrag { return cast(JSON.parse(json), r("Fdc3UserInterfaceDrag")); } @@ -4493,12 +4429,76 @@ export class Convert { return JSON.stringify(uncast(value, r("RaiseIntentResponse")), null, 2); } - public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { - return cast(JSON.parse(json), r("RaiseIntentResultResponse")); + public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { + return cast(JSON.parse(json), r("RaiseIntentResultResponse")); + } + + public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentResultResponse")), null, 2); + } + + public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { + return cast(JSON.parse(json), r("WebConnectionProtocol1Hello")); + } + + public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol1Hello")), null, 2); + } + + public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { + return cast(JSON.parse(json), r("WebConnectionProtocol2LoadURL")); + } + + public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol2LoadURL")), null, 2); + } + + public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { + return cast(JSON.parse(json), r("WebConnectionProtocol3Handshake")); + } + + public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol3Handshake")), null, 2); + } + + public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { + return cast(JSON.parse(json), r("WebConnectionProtocol4ValidateAppIdentity")); + } + + public static webConnectionProtocol4ValidateAppIdentityToJson(value: WebConnectionProtocol4ValidateAppIdentity): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol4ValidateAppIdentity")), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json: string): WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")); + } + + public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value: WebConnectionProtocol5ValidateAppIdentityFailedResponse): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json: string): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")); + } + + public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")), null, 2); + } + + public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { + return cast(JSON.parse(json), r("WebConnectionProtocol6Goodbye")); + } + + public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol6Goodbye")), null, 2); + } + + public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { + return cast(JSON.parse(json), r("WebConnectionProtocolMessage")); } - public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { - return JSON.stringify(uncast(value, r("RaiseIntentResultResponse")), null, 2); + public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocolMessage")), null, 2); } } @@ -4655,123 +4655,6 @@ function r(name: string) { } const typeMap: any = { - "WebConnectionProtocol1Hello": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol1HelloPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol1HelloType") }, - ], false), - "WebConnectionProtocol1HelloMeta": o([ - { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: "" }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "WebConnectionProtocol1HelloPayload": o([ - { json: "actualUrl", js: "actualUrl", typ: "" }, - { json: "channelSelector", js: "channelSelector", typ: u(undefined, true) }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "identityUrl", js: "identityUrl", typ: "" }, - { json: "intentResolver", js: "intentResolver", typ: u(undefined, true) }, - ], "any"), - "WebConnectionProtocol2LoadURL": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol2LoadURLPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol2LoadURLType") }, - ], false), - "WebConnectionProtocol2LoadURLPayload": o([ - { json: "iframeUrl", js: "iframeUrl", typ: "" }, - ], "any"), - "WebConnectionProtocol3Handshake": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol3HandshakePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol3HandshakeType") }, - ], false), - "WebConnectionProtocol3HandshakePayload": o([ - { json: "channelSelectorUrl", js: "channelSelectorUrl", typ: u(true, "") }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "intentResolverUrl", js: "intentResolverUrl", typ: u(true, "") }, - ], false), - "WebConnectionProtocol4ValidateAppIdentity": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol4ValidateAppIdentityPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol4ValidateAppIdentityType") }, - ], false), - "WebConnectionProtocol4ValidateAppIdentityPayload": o([ - { json: "actualUrl", js: "actualUrl", typ: "" }, - { json: "identityUrl", js: "identityUrl", typ: "" }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - { json: "instanceUuid", js: "instanceUuid", typ: u(undefined, "") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentityFailedResponse": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponseType") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload": o([ - { json: "message", js: "message", typ: u(undefined, "") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentitySuccessResponse": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponseType") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "implementationMetadata", js: "implementationMetadata", typ: r("ImplementationMetadata") }, - { json: "instanceId", js: "instanceId", typ: "" }, - { json: "instanceUuid", js: "instanceUuid", typ: "" }, - ], false), - "ImplementationMetadata": o([ - { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, - { json: "provider", js: "provider", typ: "" }, - { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, - ], false), - "AppMetadata": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "description", js: "description", typ: u(undefined, "") }, - { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, - { json: "icons", js: "icons", typ: u(undefined, a(r("Icon"))) }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - { json: "instanceMetadata", js: "instanceMetadata", typ: u(undefined, m("any")) }, - { json: "name", js: "name", typ: u(undefined, "") }, - { json: "resultType", js: "resultType", typ: u(undefined, u(null, "")) }, - { json: "screenshots", js: "screenshots", typ: u(undefined, a(r("Image"))) }, - { json: "title", js: "title", typ: u(undefined, "") }, - { json: "tooltip", js: "tooltip", typ: u(undefined, "") }, - { json: "version", js: "version", typ: u(undefined, "") }, - ], false), - "Icon": o([ - { json: "size", js: "size", typ: u(undefined, "") }, - { json: "src", js: "src", typ: "" }, - { json: "type", js: "type", typ: u(undefined, "") }, - ], false), - "Image": o([ - { json: "label", js: "label", typ: u(undefined, "") }, - { json: "size", js: "size", typ: u(undefined, "") }, - { json: "src", js: "src", typ: "" }, - { json: "type", js: "type", typ: u(undefined, "") }, - ], false), - "OptionalFeatures": o([ - { json: "DesktopAgentBridging", js: "DesktopAgentBridging", typ: true }, - { json: "OriginatingAppMetadata", js: "OriginatingAppMetadata", typ: true }, - { json: "UserChannelMembershipAPIs", js: "UserChannelMembershipAPIs", typ: true }, - ], false), - "WebConnectionProtocol6Goodbye": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol6GoodbyeMeta") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol6GoodbyeType") }, - ], false), - "WebConnectionProtocol6GoodbyeMeta": o([ - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "WebConnectionProtocolMessage": o([ - { json: "meta", js: "meta", typ: r("ConnectionStepMetadata") }, - { json: "payload", js: "payload", typ: u(undefined, m("any")) }, - { json: "type", js: "type", typ: r("ConnectionStepMessageType") }, - ], false), - "ConnectionStepMetadata": o([ - { json: "timestamp", js: "timestamp", typ: Date }, - { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: u(undefined, "") }, - ], false), "AddContextListenerRequest": o([ { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, { json: "payload", js: "payload", typ: r("AddContextListenerRequestPayload") }, @@ -4969,13 +4852,6 @@ const typeMap: any = { { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, { json: "type", js: "type", typ: r("EventListenerUnsubscribeResponseType") }, ], false), - "Fdc3UserInterfaceChannelSelected": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelSelectedPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelSelectedType") }, - ], false), - "Fdc3UserInterfaceChannelSelectedPayload": o([ - { json: "selected", js: "selected", typ: u(null, "") }, - ], false), "Fdc3UserInterfaceChannels": o([ { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelsPayload") }, { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelsType") }, @@ -4984,6 +4860,13 @@ const typeMap: any = { { json: "selected", js: "selected", typ: u(null, "") }, { json: "userChannels", js: "userChannels", typ: a(r("Channel")) }, ], false), + "Fdc3UserInterfaceChannelSelected": o([ + { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelSelectedPayload") }, + { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelSelectedType") }, + ], false), + "Fdc3UserInterfaceChannelSelectedPayload": o([ + { json: "selected", js: "selected", typ: u(null, "") }, + ], false), "Fdc3UserInterfaceDrag": o([ { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceDragPayload") }, { json: "type", js: "type", typ: r("Fdc3UserInterfaceDragType") }, @@ -5038,6 +4921,31 @@ const typeMap: any = { { json: "apps", js: "apps", typ: a(r("AppMetadata")) }, { json: "intent", js: "intent", typ: r("IntentMetadata") }, ], false), + "AppMetadata": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "description", js: "description", typ: u(undefined, "") }, + { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, + { json: "icons", js: "icons", typ: u(undefined, a(r("Icon"))) }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + { json: "instanceMetadata", js: "instanceMetadata", typ: u(undefined, m("any")) }, + { json: "name", js: "name", typ: u(undefined, "") }, + { json: "resultType", js: "resultType", typ: u(undefined, u(null, "")) }, + { json: "screenshots", js: "screenshots", typ: u(undefined, a(r("Image"))) }, + { json: "title", js: "title", typ: u(undefined, "") }, + { json: "tooltip", js: "tooltip", typ: u(undefined, "") }, + { json: "version", js: "version", typ: u(undefined, "") }, + ], false), + "Icon": o([ + { json: "size", js: "size", typ: u(undefined, "") }, + { json: "src", js: "src", typ: "" }, + { json: "type", js: "type", typ: u(undefined, "") }, + ], false), + "Image": o([ + { json: "label", js: "label", typ: u(undefined, "") }, + { json: "size", js: "size", typ: u(undefined, "") }, + { json: "src", js: "src", typ: "" }, + { json: "type", js: "type", typ: u(undefined, "") }, + ], false), "IntentMetadata": o([ { json: "displayName", js: "displayName", typ: u(undefined, "") }, { json: "name", js: "name", typ: "" }, @@ -5191,6 +5099,18 @@ const typeMap: any = { { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, { json: "implementationMetadata", js: "implementationMetadata", typ: u(undefined, r("ImplementationMetadata")) }, ], false), + "ImplementationMetadata": o([ + { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, + { json: "provider", js: "provider", typ: "" }, + { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, + ], false), + "OptionalFeatures": o([ + { json: "DesktopAgentBridging", js: "DesktopAgentBridging", typ: true }, + { json: "OriginatingAppMetadata", js: "OriginatingAppMetadata", typ: true }, + { json: "UserChannelMembershipAPIs", js: "UserChannelMembershipAPIs", typ: true }, + ], false), "GetOrCreateChannelRequest": o([ { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, { json: "payload", js: "payload", typ: r("GetOrCreateChannelRequestPayload") }, @@ -5456,36 +5376,86 @@ const typeMap: any = { { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, { json: "intentResult", js: "intentResult", typ: u(undefined, r("IntentResult")) }, ], false), - "WebConnectionProtocol1HelloType": [ - "WCP1Hello", - ], - "WebConnectionProtocol2LoadURLType": [ - "WCP2LoadUrl", - ], - "WebConnectionProtocol3HandshakeType": [ - "WCP3Handshake", - ], - "WebConnectionProtocol4ValidateAppIdentityType": [ - "WCP4ValidateAppIdentity", - ], - "WebConnectionProtocol5ValidateAppIdentityFailedResponseType": [ - "WCP5ValidateAppIdentityFailedResponse", - ], - "WebConnectionProtocol5ValidateAppIdentitySuccessResponseType": [ - "WCP5ValidateAppIdentityResponse", - ], - "WebConnectionProtocol6GoodbyeType": [ - "WCP6Goodbye", - ], - "ConnectionStepMessageType": [ - "WCP1Hello", - "WCP2LoadUrl", - "WCP3Handshake", - "WCP4ValidateAppIdentity", - "WCP5ValidateAppIdentityFailedResponse", - "WCP5ValidateAppIdentityResponse", - "WCP6Goodbye", - ], + "WebConnectionProtocol1Hello": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol1HelloPayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol1HelloType") }, + ], false), + "WebConnectionProtocol1HelloMeta": o([ + { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "WebConnectionProtocol1HelloPayload": o([ + { json: "actualUrl", js: "actualUrl", typ: "" }, + { json: "channelSelector", js: "channelSelector", typ: u(undefined, true) }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "identityUrl", js: "identityUrl", typ: "" }, + { json: "intentResolver", js: "intentResolver", typ: u(undefined, true) }, + ], "any"), + "WebConnectionProtocol2LoadURL": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol2LoadURLPayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol2LoadURLType") }, + ], false), + "WebConnectionProtocol2LoadURLPayload": o([ + { json: "iframeUrl", js: "iframeUrl", typ: "" }, + ], "any"), + "WebConnectionProtocol3Handshake": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol3HandshakePayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol3HandshakeType") }, + ], false), + "WebConnectionProtocol3HandshakePayload": o([ + { json: "channelSelectorUrl", js: "channelSelectorUrl", typ: u(true, "") }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "intentResolverUrl", js: "intentResolverUrl", typ: u(true, "") }, + ], false), + "WebConnectionProtocol4ValidateAppIdentity": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol4ValidateAppIdentityPayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol4ValidateAppIdentityType") }, + ], false), + "WebConnectionProtocol4ValidateAppIdentityPayload": o([ + { json: "actualUrl", js: "actualUrl", typ: "" }, + { json: "identityUrl", js: "identityUrl", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + { json: "instanceUuid", js: "instanceUuid", typ: u(undefined, "") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentityFailedResponse": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponseType") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload": o([ + { json: "message", js: "message", typ: u(undefined, "") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentitySuccessResponse": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponseType") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "implementationMetadata", js: "implementationMetadata", typ: r("ImplementationMetadata") }, + { json: "instanceId", js: "instanceId", typ: "" }, + { json: "instanceUuid", js: "instanceUuid", typ: "" }, + ], false), + "WebConnectionProtocol6Goodbye": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol6GoodbyeMeta") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol6GoodbyeType") }, + ], false), + "WebConnectionProtocol6GoodbyeMeta": o([ + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "WebConnectionProtocolMessage": o([ + { json: "meta", js: "meta", typ: r("ConnectionStepMetadata") }, + { json: "payload", js: "payload", typ: u(undefined, m("any")) }, + { json: "type", js: "type", typ: r("ConnectionStepMessageType") }, + ], false), + "ConnectionStepMetadata": o([ + { json: "timestamp", js: "timestamp", typ: Date }, + { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: u(undefined, "") }, + ], false), "AddContextListenerRequestType": [ "addContextListenerRequest", ], @@ -5650,12 +5620,12 @@ const typeMap: any = { "EventListenerUnsubscribeResponseType": [ "eventListenerUnsubscribeResponse", ], - "Fdc3UserInterfaceChannelSelectedType": [ - "Fdc3UserInterfaceChannelSelected", - ], "Fdc3UserInterfaceChannelsType": [ "Fdc3UserInterfaceChannels", ], + "Fdc3UserInterfaceChannelSelectedType": [ + "Fdc3UserInterfaceChannelSelected", + ], "Fdc3UserInterfaceDragType": [ "Fdc3UserInterfaceDrag", ], @@ -5856,96 +5826,38 @@ const typeMap: any = { "RaiseIntentResultResponseType": [ "raiseIntentResultResponse", ], + "WebConnectionProtocol1HelloType": [ + "WCP1Hello", + ], + "WebConnectionProtocol2LoadURLType": [ + "WCP2LoadUrl", + ], + "WebConnectionProtocol3HandshakeType": [ + "WCP3Handshake", + ], + "WebConnectionProtocol4ValidateAppIdentityType": [ + "WCP4ValidateAppIdentity", + ], + "WebConnectionProtocol5ValidateAppIdentityFailedResponseType": [ + "WCP5ValidateAppIdentityFailedResponse", + ], + "WebConnectionProtocol5ValidateAppIdentitySuccessResponseType": [ + "WCP5ValidateAppIdentityResponse", + ], + "WebConnectionProtocol6GoodbyeType": [ + "WCP6Goodbye", + ], + "ConnectionStepMessageType": [ + "WCP1Hello", + "WCP2LoadUrl", + "WCP3Handshake", + "WCP4ValidateAppIdentity", + "WCP5ValidateAppIdentityFailedResponse", + "WCP5ValidateAppIdentityResponse", + "WCP6Goodbye", + ], }; -export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - try { - Convert.webConnectionProtocol1HelloToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = "WebConnectionProtocol1Hello"; - -export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - try { - Convert.webConnectionProtocol2LoadURLToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = "WebConnectionProtocol2LoadURL"; - -export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - try { - Convert.webConnectionProtocol3HandshakeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = "WebConnectionProtocol3Handshake"; - -export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { - try { - Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = "WebConnectionProtocol4ValidateAppIdentity"; - -export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentityFailedResponse"; - -export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentitySuccessResponse"; - -export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - try { - Convert.webConnectionProtocol6GoodbyeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = "WebConnectionProtocol6Goodbye"; - -export function isWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { - try { - Convert.webConnectionProtocolMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; - export function isAddContextListenerRequest(value: any): value is AddContextListenerRequest { try { Convert.addContextListenerRequestToJson(value); @@ -6155,27 +6067,27 @@ export function isEventListenerUnsubscribeResponse(value: any): value is EventLi export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "EventListenerUnsubscribeResponse"; -export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { +export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { try { - Convert.fdc3UserInterfaceChannelSelectedToJson(value); + Convert.fdc3UserInterfaceChannelsToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = "Fdc3UserInterfaceChannelSelected"; +export const FDC3_USER_INTERFACE_CHANNELS_TYPE = "Fdc3UserInterfaceChannels"; -export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { +export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { try { - Convert.fdc3UserInterfaceChannelsToJson(value); + Convert.fdc3UserInterfaceChannelSelectedToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNELS_TYPE = "Fdc3UserInterfaceChannels"; +export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = "Fdc3UserInterfaceChannelSelected"; export function isFdc3UserInterfaceDrag(value: any): value is Fdc3UserInterfaceDrag { try { @@ -6749,9 +6661,97 @@ export function isRaiseIntentResultResponse(value: any): value is RaiseIntentRes export const RAISE_INTENT_RESULT_RESPONSE_TYPE = "RaiseIntentResultResponse"; +export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + try { + Convert.webConnectionProtocol1HelloToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = "WebConnectionProtocol1Hello"; + +export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + try { + Convert.webConnectionProtocol2LoadURLToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = "WebConnectionProtocol2LoadURL"; + +export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + try { + Convert.webConnectionProtocol3HandshakeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = "WebConnectionProtocol3Handshake"; + +export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { + try { + Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = "WebConnectionProtocol4ValidateAppIdentity"; + +export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentityFailedResponse"; + +export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentitySuccessResponse"; + +export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + try { + Convert.webConnectionProtocol6GoodbyeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = "WebConnectionProtocol6Goodbye"; + +export function isWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { + try { + Convert.webConnectionProtocolMessageToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; + export type RequestMessage = AddContextListenerRequest | AddEventListenerRequest | AddIntentListenerRequest | BroadcastRequest | ContextListenerUnsubscribeRequest | CreatePrivateChannelRequest | EventListenerUnsubscribeRequest | FindInstancesRequest | FindIntentRequest | FindIntentsByContextRequest | GetAppMetadataRequest | GetCurrentChannelRequest | GetCurrentContextRequest | GetInfoRequest | GetOrCreateChannelRequest | GetUserChannelsRequest | HeartbeatAcknowledgementRequest | IntentListenerUnsubscribeRequest | IntentResultRequest | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest | PrivateChannelAddEventListenerRequest | PrivateChannelDisconnectRequest | PrivateChannelUnsubscribeEventListenerRequest | RaiseIntentForContextRequest | RaiseIntentRequest; -export type ResponseMessage = WebConnectionProtocol5ValidateAppIdentityFailedResponse | WebConnectionProtocol5ValidateAppIdentitySuccessResponse | AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse; +export type ResponseMessage = AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse | WebConnectionProtocol5ValidateAppIdentityFailedResponse | WebConnectionProtocol5ValidateAppIdentitySuccessResponse; export type EventMessage = BroadcastEvent | ChannelChangedEvent | HeartbeatEvent | IntentEvent | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnDisconnectEvent | PrivateChannelOnUnsubscribeEvent; diff --git a/packages/fdc3-schema/generated/bridging/BridgingTypes.ts b/packages/fdc3-schema/generated/bridging/BridgingTypes.ts index b8c5c09d3..4a7b7e98a 100644 --- a/packages/fdc3-schema/generated/bridging/BridgingTypes.ts +++ b/packages/fdc3-schema/generated/bridging/BridgingTypes.ts @@ -1 +1,6057 @@ -export const something = "" \ No newline at end of file +// To parse this data: +// +// import { Convert, AgentErrorResponseMessage, AgentRequestMessage, AgentResponseMessage, BridgeErrorResponseMessage, BridgeRequestMessage, BridgeResponseMessage, BroadcastAgentRequest, BroadcastBridgeRequest, ConnectionStepMessage, ConnectionStep2Hello, ConnectionStep3Handshake, ConnectionStep4AuthenticationFailed, ConnectionStep6ConnectedAgentsUpdate, FindInstancesAgentErrorResponse, FindInstancesAgentRequest, FindInstancesAgentResponse, FindInstancesBridgeErrorResponse, FindInstancesBridgeRequest, FindInstancesBridgeResponse, FindIntentAgentErrorResponse, FindIntentAgentRequest, FindIntentAgentResponse, FindIntentBridgeErrorResponse, FindIntentBridgeRequest, FindIntentBridgeResponse, FindIntentsByContextAgentErrorResponse, FindIntentsByContextAgentRequest, FindIntentsByContextAgentResponse, FindIntentsByContextBridgeErrorResponse, FindIntentsByContextBridgeRequest, FindIntentsByContextBridgeResponse, GetAppMetadataAgentErrorResponse, GetAppMetadataAgentRequest, GetAppMetadataAgentResponse, GetAppMetadataBridgeErrorResponse, GetAppMetadataBridgeRequest, GetAppMetadataBridgeResponse, OpenAgentErrorResponse, OpenAgentRequest, OpenAgentResponse, OpenBridgeErrorResponse, OpenBridgeRequest, OpenBridgeResponse, PrivateChannelBroadcastAgentRequest, PrivateChannelBroadcastBridgeRequest, PrivateChannelEventListenerAddedAgentRequest, PrivateChannelEventListenerAddedBridgeRequest, PrivateChannelEventListenerRemovedAgentRequest, PrivateChannelEventListenerRemovedBridgeRequest, PrivateChannelOnAddContextListenerAgentRequest, PrivateChannelOnAddContextListenerBridgeRequest, PrivateChannelOnDisconnectAgentRequest, PrivateChannelOnDisconnectBridgeRequest, PrivateChannelOnUnsubscribeAgentRequest, PrivateChannelOnUnsubscribeBridgeRequest, RaiseIntentAgentErrorResponse, RaiseIntentAgentRequest, RaiseIntentAgentResponse, RaiseIntentBridgeErrorResponse, RaiseIntentBridgeRequest, RaiseIntentBridgeResponse, RaiseIntentResultAgentErrorResponse, RaiseIntentResultAgentResponse, RaiseIntentResultBridgeErrorResponse, RaiseIntentResultBridgeResponse } from "./file"; +// +// const agentErrorResponseMessage = Convert.toAgentErrorResponseMessage(json); +// const agentRequestMessage = Convert.toAgentRequestMessage(json); +// const agentResponseMessage = Convert.toAgentResponseMessage(json); +// const bridgeErrorResponseMessage = Convert.toBridgeErrorResponseMessage(json); +// const bridgeRequestMessage = Convert.toBridgeRequestMessage(json); +// const bridgeResponseMessage = Convert.toBridgeResponseMessage(json); +// const broadcastAgentRequest = Convert.toBroadcastAgentRequest(json); +// const broadcastBridgeRequest = Convert.toBroadcastBridgeRequest(json); +// const bridgeCommonDefinitions = Convert.toBridgeCommonDefinitions(json); +// const connectionStepMessage = Convert.toConnectionStepMessage(json); +// const connectionStep2Hello = Convert.toConnectionStep2Hello(json); +// const connectionStep3Handshake = Convert.toConnectionStep3Handshake(json); +// const connectionStep4AuthenticationFailed = Convert.toConnectionStep4AuthenticationFailed(json); +// const connectionStep6ConnectedAgentsUpdate = Convert.toConnectionStep6ConnectedAgentsUpdate(json); +// const findInstancesAgentErrorResponse = Convert.toFindInstancesAgentErrorResponse(json); +// const findInstancesAgentRequest = Convert.toFindInstancesAgentRequest(json); +// const findInstancesAgentResponse = Convert.toFindInstancesAgentResponse(json); +// const findInstancesBridgeErrorResponse = Convert.toFindInstancesBridgeErrorResponse(json); +// const findInstancesBridgeRequest = Convert.toFindInstancesBridgeRequest(json); +// const findInstancesBridgeResponse = Convert.toFindInstancesBridgeResponse(json); +// const findIntentAgentErrorResponse = Convert.toFindIntentAgentErrorResponse(json); +// const findIntentAgentRequest = Convert.toFindIntentAgentRequest(json); +// const findIntentAgentResponse = Convert.toFindIntentAgentResponse(json); +// const findIntentBridgeErrorResponse = Convert.toFindIntentBridgeErrorResponse(json); +// const findIntentBridgeRequest = Convert.toFindIntentBridgeRequest(json); +// const findIntentBridgeResponse = Convert.toFindIntentBridgeResponse(json); +// const findIntentsByContextAgentErrorResponse = Convert.toFindIntentsByContextAgentErrorResponse(json); +// const findIntentsByContextAgentRequest = Convert.toFindIntentsByContextAgentRequest(json); +// const findIntentsByContextAgentResponse = Convert.toFindIntentsByContextAgentResponse(json); +// const findIntentsByContextBridgeErrorResponse = Convert.toFindIntentsByContextBridgeErrorResponse(json); +// const findIntentsByContextBridgeRequest = Convert.toFindIntentsByContextBridgeRequest(json); +// const findIntentsByContextBridgeResponse = Convert.toFindIntentsByContextBridgeResponse(json); +// const getAppMetadataAgentErrorResponse = Convert.toGetAppMetadataAgentErrorResponse(json); +// const getAppMetadataAgentRequest = Convert.toGetAppMetadataAgentRequest(json); +// const getAppMetadataAgentResponse = Convert.toGetAppMetadataAgentResponse(json); +// const getAppMetadataBridgeErrorResponse = Convert.toGetAppMetadataBridgeErrorResponse(json); +// const getAppMetadataBridgeRequest = Convert.toGetAppMetadataBridgeRequest(json); +// const getAppMetadataBridgeResponse = Convert.toGetAppMetadataBridgeResponse(json); +// const openAgentErrorResponse = Convert.toOpenAgentErrorResponse(json); +// const openAgentRequest = Convert.toOpenAgentRequest(json); +// const openAgentResponse = Convert.toOpenAgentResponse(json); +// const openBridgeErrorResponse = Convert.toOpenBridgeErrorResponse(json); +// const openBridgeRequest = Convert.toOpenBridgeRequest(json); +// const openBridgeResponse = Convert.toOpenBridgeResponse(json); +// const privateChannelBroadcastAgentRequest = Convert.toPrivateChannelBroadcastAgentRequest(json); +// const privateChannelBroadcastBridgeRequest = Convert.toPrivateChannelBroadcastBridgeRequest(json); +// const privateChannelEventListenerAddedAgentRequest = Convert.toPrivateChannelEventListenerAddedAgentRequest(json); +// const privateChannelEventListenerAddedBridgeRequest = Convert.toPrivateChannelEventListenerAddedBridgeRequest(json); +// const privateChannelEventListenerRemovedAgentRequest = Convert.toPrivateChannelEventListenerRemovedAgentRequest(json); +// const privateChannelEventListenerRemovedBridgeRequest = Convert.toPrivateChannelEventListenerRemovedBridgeRequest(json); +// const privateChannelOnAddContextListenerAgentRequest = Convert.toPrivateChannelOnAddContextListenerAgentRequest(json); +// const privateChannelOnAddContextListenerBridgeRequest = Convert.toPrivateChannelOnAddContextListenerBridgeRequest(json); +// const privateChannelOnDisconnectAgentRequest = Convert.toPrivateChannelOnDisconnectAgentRequest(json); +// const privateChannelOnDisconnectBridgeRequest = Convert.toPrivateChannelOnDisconnectBridgeRequest(json); +// const privateChannelOnUnsubscribeAgentRequest = Convert.toPrivateChannelOnUnsubscribeAgentRequest(json); +// const privateChannelOnUnsubscribeBridgeRequest = Convert.toPrivateChannelOnUnsubscribeBridgeRequest(json); +// const raiseIntentAgentErrorResponse = Convert.toRaiseIntentAgentErrorResponse(json); +// const raiseIntentAgentRequest = Convert.toRaiseIntentAgentRequest(json); +// const raiseIntentAgentResponse = Convert.toRaiseIntentAgentResponse(json); +// const raiseIntentBridgeErrorResponse = Convert.toRaiseIntentBridgeErrorResponse(json); +// const raiseIntentBridgeRequest = Convert.toRaiseIntentBridgeRequest(json); +// const raiseIntentBridgeResponse = Convert.toRaiseIntentBridgeResponse(json); +// const raiseIntentResultAgentErrorResponse = Convert.toRaiseIntentResultAgentErrorResponse(json); +// const raiseIntentResultAgentResponse = Convert.toRaiseIntentResultAgentResponse(json); +// const raiseIntentResultBridgeErrorResponse = Convert.toRaiseIntentResultBridgeErrorResponse(json); +// const raiseIntentResultBridgeResponse = Convert.toRaiseIntentResultBridgeResponse(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +/** + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface AgentErrorResponseMessage { + meta: AgentResponseMetadata; + /** + * Error message payload containing an standardized error string. + */ + payload: ErrorResponseMessagePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: ResponseMessageType; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface AgentResponseMetadata { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface ErrorResponseMessagePayload { + error: ResponseErrorDetail; + [property: string]: any; +} + +/** + * Array of error message strings for responses that were not returned to the bridge before + * the timeout or because an error occurred. Should be the same length as the `errorSources` + * array and ordered the same. May be omitted if all sources responded without errors. + * + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + */ +export type ResponseErrorDetail = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "IntentHandlerRejected" | "NoResultReturned" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ +export type ResponseMessageType = "findInstancesResponse" | "findIntentResponse" | "findIntentsByContextResponse" | "getAppMetadataResponse" | "openResponse" | "raiseIntentResponse" | "raiseIntentResultResponse"; + +/** + * A request message from a Desktop Agent to the Bridge. + */ +export interface AgentRequestMessage { + meta: AgentRequestMetadata; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: { [key: string]: any }; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: RequestMessageType; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface AgentRequestMetadata { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: BridgeParticipantIdentifier; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceIdentifier; + timestamp: Date; +} + +/** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + * + * Represents identifiers that MUST include the Desktop Agent name and MAY identify a + * specific app or instance. + * + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ +export interface BridgeParticipantIdentifier { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + * + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent: string; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId?: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + * + * Field that represents the source application that a request or response was received + * from, or the source Desktop Agent if it issued the request or response itself. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + */ +export interface SourceIdentifier { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + * + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + */ + desktopAgent?: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ +export type RequestMessageType = "broadcastRequest" | "findInstancesRequest" | "findIntentRequest" | "findIntentsByContextRequest" | "getAppMetadataRequest" | "openRequest" | "PrivateChannel.broadcast" | "PrivateChannel.eventListenerAdded" | "PrivateChannel.eventListenerRemoved" | "PrivateChannel.onAddContextListener" | "PrivateChannel.onDisconnect" | "PrivateChannel.onUnsubscribe" | "raiseIntentRequest"; + +/** + * A response message from a Desktop Agent to the Bridge. + */ +export interface AgentResponseMessage { + meta: AgentResponseMetadata; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: { [key: string]: any }; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: ResponseMessageType; +} + +/** + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface BridgeErrorResponseMessage { + meta: BridgeErrorResponseMessageMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: ResponseErrorMessagePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: string; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface BridgeErrorResponseMessageMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + */ +export interface DesktopAgentIdentifier { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + */ + desktopAgent: string; + [property: string]: any; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface ResponseErrorMessagePayload { + error?: ResponseErrorDetail; + [property: string]: any; +} + +/** + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface BridgeRequestMessage { + meta: BridgeRequestMetadata; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: { [key: string]: any }; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: string; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface BridgeRequestMetadata { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: BridgeParticipantIdentifier; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: BridgeParticipantIdentifier; + timestamp: Date; +} + +/** + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface BridgeResponseMessage { + meta: BridgeResponseMessageMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: { [key: string]: any }; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: string; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface BridgeResponseMessageMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * A request to broadcast context on a channel. + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface BroadcastAgentRequest { + meta: BroadcastAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: BroadcastAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "broadcastRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface BroadcastAgentRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source: SourceObject; + timestamp: Date; +} + +/** + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + * + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + * + * Field that represents the source application that a request or response was received + * from, or the source Desktop Agent if it issued the request or response itself. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + */ +export interface SourceObject { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + * + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + */ + desktopAgent?: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface BroadcastAgentRequestPayload { + /** + * The Id of the Channel that the broadcast was sent on. + */ + channelId: string; + /** + * The context object that is to be broadcast. + */ + context: Context; +} + +/** + * The context object that is to be broadcast. + * + * The context object that was the payload of a broadcast message. + * + * The `fdc3.context` type defines the basic contract or "shape" for all data exchanged by + * FDC3 operations. As such, it is not really meant to be used on its own, but is imported + * by more specific type definitions (standardized or custom) to provide the structure and + * properties shared by all FDC3 context data types. + * + * The key element of FDC3 context types is their mandatory `type` property, which is used + * to identify what type of data the object represents, and what shape it has. + * + * The FDC3 context type, and all derived types, define the minimum set of fields a context + * data object of a particular type can be expected to have, but this can always be extended + * with custom fields as appropriate. + */ +export interface Context { + /** + * Context data objects may include a set of equivalent key-value pairs that can be used to + * help applications identify and look up the context type they receive in their own domain. + * The idea behind this design is that applications can provide as many equivalent + * identifiers to a target application as possible, e.g. an instrument may be represented by + * an ISIN, CUSIP or Bloomberg identifier. + * + * Identifiers do not make sense for all types of data, so the `id` property is therefore + * optional, but some derived types may choose to require at least one identifier. + * Identifier values SHOULD always be of type string. + */ + id?: { [key: string]: any }; + /** + * Context data objects may include a name property that can be used for more information, + * or display purposes. Some derived types may require the name object as mandatory, + * depending on use case. + */ + name?: string; + /** + * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 + * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present + * to route shared context data appropriately. + * + * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data + * types they support in an FDC3 [App + * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery + * and routing. + * + * Standardized FDC3 context types have well-known `type` properties prefixed with the + * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and + * used by a particular organization, the convention is to prefix them with an + * organization-specific namespace, e.g. `blackrock.fund`. + * + * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more + * information about context data types. + */ + type: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to broadcast context on a channel. + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface BroadcastBridgeRequest { + meta: BroadcastBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: BroadcastBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "broadcastRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface BroadcastBridgeRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + * + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + * + * Represents identifiers that MUST include the Desktop Agent name and MAY identify a + * specific app or instance. + * + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + */ +export interface MetaSource { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + * + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + */ + desktopAgent: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface BroadcastBridgeRequestPayload { + /** + * The Id of the Channel that the broadcast was sent on. + */ + channelId: string; + /** + * The context object that is to be broadcast. + */ + context: Context; +} + +/** + * A message used during the connection flow for a Desktop Agent to the Bridge. Used for + * messages sent in either direction. + */ +export interface ConnectionStepMessage { + meta: ConnectionStepMetadata; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: { [key: string]: any }; + /** + * Identifies the type of the connection step message. + */ + type: ConnectionStepMessageType; +} + +/** + * Metadata for this connection step message. + */ +export interface ConnectionStepMetadata { + requestUuid?: string; + responseUuid?: string; + timestamp: Date; +} + +/** + * Identifies the type of the connection step message. + */ +export type ConnectionStepMessageType = "hello" | "handshake" | "authenticationFailed" | "connectedAgentsUpdate"; + +/** + * Hello message sent by the Bridge to anyone connecting to the Bridge (enables + * identification as a bridge and confirmation of whether authentication is required) + * + * A message used during the connection flow for a Desktop Agent to the Bridge. Used for + * messages sent in either direction. + */ +export interface ConnectionStep2Hello { + meta: ConnectionStep2HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: ConnectionStep2HelloPayload; + /** + * Identifies the type of the connection step message. + */ + type: "hello"; +} + +/** + * Metadata for this connection step message. + */ +export interface ConnectionStep2HelloMeta { + timestamp: Date; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface ConnectionStep2HelloPayload { + /** + * A flag indicating whether the Desktop Agent Bridge requires authentication or not. + */ + authRequired: boolean; + /** + * An optional Desktop Agent Bridge JWT authentication token if the Desktop Agent want to + * authenticate a bridge. + */ + authToken?: string; + /** + * The version of the Bridge + */ + desktopAgentBridgeVersion: string; + /** + * The FDC3 versions supported by the Bridge + */ + supportedFDC3Versions: string[]; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Handshake message sent by the Desktop Agent to the Bridge (including requested name, + * channel state and authentication data) + * + * A message used during the connection flow for a Desktop Agent to the Bridge. Used for + * messages sent in either direction. + */ +export interface ConnectionStep3Handshake { + meta: ConnectionStep3HandshakeMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: ConnectionStep3HandshakePayload; + /** + * Identifies the type of the connection step message. + */ + type: "handshake"; +} + +/** + * Metadata for this connection step message. + */ +export interface ConnectionStep3HandshakeMeta { + requestUuid: string; + timestamp: Date; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface ConnectionStep3HandshakePayload { + authToken?: string; + /** + * The current state of the Desktop Agent's App and User channels (exclude any Private + * channels), as a mapping of channel id to an array of Context objects, one per type found + * in the channel, most recent first. + */ + channelsState: { [key: string]: Context[] }; + /** + * Desktop Agent ImplementationMetadata trying to connect to the bridge. + */ + implementationMetadata: ConnectingAgentImplementationMetadata; + /** + * The requested Desktop Agent name + */ + requestedName: string; +} + +/** + * Desktop Agent ImplementationMetadata trying to connect to the bridge. + * + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + */ +export interface ConnectingAgentImplementationMetadata { + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ +export interface OptionalFeatures { + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + DesktopAgentBridging: boolean; + /** + * Used to indicate whether the exposure of 'originating app metadata' for + * context and intent messages is supported by the Desktop Agent. + */ + OriginatingAppMetadata: boolean; + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + UserChannelMembershipAPIs: boolean; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Message sent by Bridge to Desktop Agent if their authentication fails. + * + * A message used during the connection flow for a Desktop Agent to the Bridge. Used for + * messages sent in either direction. + */ +export interface ConnectionStep4AuthenticationFailed { + meta: ConnectionStep4AuthenticationFailedMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: ConnectionStep4AuthenticationFailedPayload; + /** + * Identifies the type of the connection step message. + */ + type: "authenticationFailed"; +} + +/** + * Metadata for this connection step message. + */ +export interface ConnectionStep4AuthenticationFailedMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface ConnectionStep4AuthenticationFailedPayload { + message?: string; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Message sent by Bridge to all Desktop Agent when an agent joins or leaves the bridge, + * includes the details of all agents, the change made and the expected channel state for + * all agents. + * + * A message used during the connection flow for a Desktop Agent to the Bridge. Used for + * messages sent in either direction. + */ +export interface ConnectionStep6ConnectedAgentsUpdate { + meta: ConnectionStep6ConnectedAgentsUpdateMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: ConnectionStep6ConnectedAgentsUpdatePayload; + /** + * Identifies the type of the connection step message. + */ + type: "connectedAgentsUpdate"; +} + +/** + * Metadata for this connection step message. + */ +export interface ConnectionStep6ConnectedAgentsUpdateMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface ConnectionStep6ConnectedAgentsUpdatePayload { + /** + * Should be set when an agent first connects to the bridge and provide its assigned name. + */ + addAgent?: string; + /** + * Desktop Agent Bridge implementation metadata of all connected agents. + */ + allAgents: DesktopAgentImplementationMetadata[]; + /** + * The updated state of channels that should be adopted by the agents. Should only be set + * when an agent is connecting to the bridge. + */ + channelsState?: { [key: string]: Context[] }; + /** + * Should be set when an agent disconnects from the bridge and provide the name that no + * longer is assigned. + */ + removeAgent?: string; +} + +/** + * Includes the name assigned to the Desktop Agent by the Bridge. + * + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + */ +export interface DesktopAgentImplementationMetadata { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a particular Desktop + * Agent. + */ + desktopAgent: string; + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * A response to a findInstances request that contains an error. + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface FindInstancesAgentErrorResponse { + meta: FindInstancesAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: PayloadClass; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findInstancesResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface FindInstancesAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface PayloadClass { + error: FindInstancesErrors; +} + +/** + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + * + * Should be set if the raiseIntent request returned an error. + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + * + * Array of error message strings for responses that were not returned to the bridge before + * the timeout or because an error occurred. Should be the same length as the `errorSources` + * array and ordered the same. May be omitted if all sources responded without errors. + * + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + */ +export type FindInstancesErrors = "DesktopAgentNotFound" | "IntentDeliveryFailed" | "MalformedContext" | "NoAppsFound" | "ResolverTimeout" | "ResolverUnavailable" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request for details of instances of a particular app + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface FindInstancesAgentRequest { + meta: FindInstancesAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindInstancesAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findInstancesRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface FindInstancesAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: DestinationObject; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceIdentifier; + timestamp: Date; +} + +/** + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + * + * Represents identifiers that MUST include the Desktop Agent name and MAY identify a + * specific app or instance. + * + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + * + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ +export interface DestinationObject { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + * + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent: string; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId?: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindInstancesAgentRequestPayload { + app: AppIdentifier; +} + +/** + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ +export interface AppIdentifier { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A response to a findInstances request. + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface FindInstancesAgentResponse { + meta: AgentResponseMetadata; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: FindInstancesAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findInstancesResponse"; +} + +/** + * The message payload contains a flag indicating whether the API call was successful, plus + * any return values for the FDC3 API function called, or indicating that the request + * resulted in an error and including a standardized error message. + * + * The message payload typically contains return values for FDC3 API functions. + */ +export interface FindInstancesAgentResponsePayload { + appIdentifiers: AppMetadata[]; +} + +/** + * Extends an `AppIdentifier`, describing an application or instance of an application, with + * additional descriptive metadata that is usually provided by an FDC3 App Directory that + * the Desktop Agent connects to. + * + * The additional information from an app directory can aid in rendering UI elements, such + * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon + * and screenshot URLs. + * + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the + * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. + */ +export interface AppMetadata { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * A longer, multi-paragraph description for the application that could include markup. + */ + description?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * A list of icon URLs for the application that can be used to render UI elements. + */ + icons?: Icon[]; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + /** + * An optional set of, implementation specific, metadata fields that can be used to + * disambiguate instances, such as a window title or screen position. Must only be set if + * `instanceId` is set. + */ + instanceMetadata?: { [key: string]: any }; + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now + * require an `AppIdentifier` wth `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to + * this field. + */ + name?: string; + /** + * The type of output returned for any intent specified during resolution. May express a + * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel + * that will receive a specified type (e.g. "channel"). + */ + resultType?: null | string; + /** + * Images representing the app in common usage scenarios that can be used to render UI + * elements. + */ + screenshots?: Image[]; + /** + * A more user-friendly application title that can be used to render UI elements. + */ + title?: string; + /** + * A tooltip for the application that can be used to render UI elements. + */ + tooltip?: string; + /** + * The Version of the application. + */ + version?: string; +} + +/** + * Describes an Icon image that may be used to represent the application. + */ +export interface Icon { + /** + * The icon dimension, formatted as `x`. + */ + size?: string; + /** + * The icon url. + */ + src: string; + /** + * Icon media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; +} + +/** + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. + */ +export interface Image { + /** + * Caption for the image. + */ + label?: string; + /** + * The image dimension, formatted as `x`. + */ + size?: string; + /** + * The image url. + */ + src: string; + /** + * Image media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; +} + +/** + * A response to a findInstances request that contains an error. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface FindInstancesBridgeErrorResponse { + meta: FindInstancesBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: MessagePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findInstancesResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface FindInstancesBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface MessagePayload { + error: FindInstancesErrors; +} + +/** + * A request for details of instances of a particular app + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface FindInstancesBridgeRequest { + meta: FindInstancesBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindInstancesBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findInstancesRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface FindInstancesBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: DestinationObject; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSourceObject; + timestamp: Date; +} + +/** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + * + * Field that represents the source application that a request or response was received + * from, or the source Desktop Agent if it issued the request or response itself. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + * + * Represents identifiers that MUST include the Desktop Agent name and MAY identify a + * specific app or instance. + * + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + * + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + */ +export interface MetaSourceObject { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + * + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + */ + desktopAgent: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindInstancesBridgeRequestPayload { + app: AppIdentifier; +} + +/** + * A response to a findInstances request. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface FindInstancesBridgeResponse { + meta: BridgeResponseMessageMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: FindInstancesBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findInstancesResponse"; +} + +/** + * The message payload contains a flag indicating whether the API call was successful, plus + * any return values for the FDC3 API function called, or indicating that the request + * resulted in an error and including a standardized error message. + * + * The message payload typically contains return values for FDC3 API functions. + */ +export interface FindInstancesBridgeResponsePayload { + appIdentifiers: AppMetadata[]; +} + +/** + * A response to a findIntent request that contains an error. + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface FindIntentAgentErrorResponse { + meta: FindIntentAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: FindIntentAgentErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface FindIntentAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface FindIntentAgentErrorResponsePayload { + error: FindInstancesErrors; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request for details of apps available to resolve a particular intent and context pair. + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface FindIntentAgentRequest { + meta: FindIntentAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface FindIntentAgentRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceIdentifier; + timestamp: Date; + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: BridgeParticipantIdentifier; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentAgentRequestPayload { + context?: Context; + intent: string; + resultType?: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A response to a findIntent request. + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface FindIntentAgentResponse { + meta: FindIntentAgentResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: FindIntentAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface FindIntentAgentResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface FindIntentAgentResponsePayload { + appIntent: AppIntent; +} + +/** + * An interface that relates an intent to apps. + */ +export interface AppIntent { + /** + * Details of applications that can resolve the intent. + */ + apps: AppMetadata[]; + /** + * Details of the intent whose relationship to resolving applications is being described. + */ + intent: IntentMetadata; +} + +/** + * Details of the intent whose relationship to resolving applications is being described. + * + * Metadata describing an Intent. + */ +export interface IntentMetadata { + /** + * Display name for the intent. + */ + displayName?: string; + /** + * The unique name of the intent that can be invoked by the raiseIntent call. + */ + name: string; +} + +/** + * A response to a findIntent request that contains an error. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface FindIntentBridgeErrorResponse { + meta: FindIntentBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: FindIntentBridgeErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface FindIntentBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface FindIntentBridgeErrorResponsePayload { + error: FindInstancesErrors; +} + +/** + * A request for details of apps available to resolve a particular intent and context pair. + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface FindIntentBridgeRequest { + meta: FindIntentBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface FindIntentBridgeRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: BridgeParticipantIdentifier; + timestamp: Date; + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: BridgeParticipantIdentifier; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentBridgeRequestPayload { + context?: Context; + intent: string; + resultType?: string; +} + +/** + * A response to a findIntent request. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface FindIntentBridgeResponse { + meta: FindIntentBridgeResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: FindIntentBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface FindIntentBridgeResponseMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface FindIntentBridgeResponsePayload { + appIntent: AppIntent; +} + +/** + * A response to a findIntentsByContext request that contains an error. + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface FindIntentsByContextAgentErrorResponse { + meta: FindIntentsByContextAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: FindIntentsByContextAgentErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentsByContextResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface FindIntentsByContextAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface FindIntentsByContextAgentErrorResponsePayload { + error: FindInstancesErrors; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request for details of intents and apps available to resolve them for a particular + * context. + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface FindIntentsByContextAgentRequest { + meta: FindIntentsByContextAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentsByContextAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentsByContextRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface FindIntentsByContextAgentRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: BridgeParticipantIdentifier; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentsByContextAgentRequestPayload { + context: Context; + resultType?: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A response to a findIntentsByContext request. + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface FindIntentsByContextAgentResponse { + meta: FindIntentsByContextAgentResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: FindIntentsByContextAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentsByContextResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface FindIntentsByContextAgentResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface FindIntentsByContextAgentResponsePayload { + appIntents: AppIntent[]; +} + +/** + * A response to a findIntentsByContext request that contains an error. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface FindIntentsByContextBridgeErrorResponse { + meta: FindIntentsByContextBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: FindIntentsByContextBridgeErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentsByContextResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface FindIntentsByContextBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface FindIntentsByContextBridgeErrorResponsePayload { + error: FindInstancesErrors; +} + +/** + * A request for details of intents and apps available to resolve them for a particular + * context. + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface FindIntentsByContextBridgeRequest { + meta: FindIntentsByContextBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentsByContextBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentsByContextRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface FindIntentsByContextBridgeRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: BridgeParticipantIdentifier; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentsByContextBridgeRequestPayload { + context: Context; + resultType?: string; +} + +/** + * A response to a findIntentsByContext request. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface FindIntentsByContextBridgeResponse { + meta: FindIntentsByContextBridgeResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: FindIntentsByContextBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentsByContextResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface FindIntentsByContextBridgeResponseMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface FindIntentsByContextBridgeResponsePayload { + appIntents: AppIntent[]; +} + +/** + * A response to a getAppMetadata request that contains an error. + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface GetAppMetadataAgentErrorResponse { + meta: GetAppMetadataAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: GetAppMetadataAgentErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "getAppMetadataResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface GetAppMetadataAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface GetAppMetadataAgentErrorResponsePayload { + error: FindInstancesErrors; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request for metadata about an app + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface GetAppMetadataAgentRequest { + meta: GetAppMetadataAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetAppMetadataAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "getAppMetadataRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface GetAppMetadataAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: DestinationObject; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceIdentifier; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface GetAppMetadataAgentRequestPayload { + app: AppObject; +} + +/** + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ +export interface AppObject { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + * + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent: string; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A response to a getAppMetadata request. + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface GetAppMetadataAgentResponse { + meta: GetAppMetadataAgentResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: GetAppMetadataAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "getAppMetadataResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface GetAppMetadataAgentResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface GetAppMetadataAgentResponsePayload { + appMetadata: AppMetadata; +} + +/** + * A response to a getAppMetadata request that contains an error. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface GetAppMetadataBridgeErrorResponse { + meta: GetAppMetadataBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: GetAppMetadataBridgeErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "getAppMetadataResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface GetAppMetadataBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface GetAppMetadataBridgeErrorResponsePayload { + error: FindInstancesErrors; +} + +/** + * A request for metadata about an app + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface GetAppMetadataBridgeRequest { + meta: GetAppMetadataBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetAppMetadataBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "getAppMetadataRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface GetAppMetadataBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: DestinationObject; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface GetAppMetadataBridgeRequestPayload { + app: AppObject; +} + +/** + * A response to a getAppMetadata request. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface GetAppMetadataBridgeResponse { + meta: GetAppMetadataBridgeResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: GetAppMetadataBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "getAppMetadataResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface GetAppMetadataBridgeResponseMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface GetAppMetadataBridgeResponsePayload { + appMetadata: AppMetadata; +} + +/** + * A response to an open request that contains an error + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface OpenAgentErrorResponse { + meta: OpenAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: OpenAgentErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "openResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface OpenAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface OpenAgentErrorResponsePayload { + error: OpenErrorResponsePayload; +} + +/** + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Array of error message strings for responses that were not returned to the bridge before + * the timeout or because an error occurred. Should be the same length as the `errorSources` + * array and ordered the same. May be omitted if all sources responded without errors. + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + */ +export type OpenErrorResponsePayload = "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "MalformedContext" | "ResolverUnavailable" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to open an application + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface OpenAgentRequest { + meta: OpenAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: OpenAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "openRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface OpenAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: DestinationObject; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface OpenAgentRequestPayload { + /** + * The application to open on the specified Desktop Agent + */ + app: AppToOpen; + context?: Context; +} + +/** + * The application to open on the specified Desktop Agent + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ +export interface AppToOpen { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + * + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent: string; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A response to an open request + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface OpenAgentResponse { + meta: OpenAgentResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: OpenAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "openResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface OpenAgentResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface OpenAgentResponsePayload { + appIdentifier: AppIdentifier; +} + +/** + * A response to an open request that contains an error + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface OpenBridgeErrorResponse { + meta: OpenBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: OpenBridgeErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "openResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface OpenBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface OpenBridgeErrorResponsePayload { + error: OpenErrorResponsePayload; +} + +/** + * A request to open an application + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface OpenBridgeRequest { + meta: OpenBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: OpenBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "openRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface OpenBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: DestinationObject; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface OpenBridgeRequestPayload { + /** + * The application to open on the specified Desktop Agent + */ + app: AppToOpen; + context?: Context; +} + +/** + * A response to an open request + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface OpenBridgeResponse { + meta: OpenBridgeResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: OpenBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "openResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface OpenBridgeResponseMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface OpenBridgeResponsePayload { + appIdentifier: AppIdentifier; +} + +/** + * A request to broadcast on a PrivateChannel. + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface PrivateChannelBroadcastAgentRequest { + meta: PrivateChannelBroadcastAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelBroadcastAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.broadcast"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface PrivateChannelBroadcastAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; +} + +/** + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + * + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + * + * Represents identifiers that MUST include the Desktop Agent name and MAY identify a + * specific app or instance. + * + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ +export interface MetaDestination { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + * + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent: string; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelBroadcastAgentRequestPayload { + /** + * The Id of the PrivateChannel that the broadcast was sent on + */ + channelId: string; + /** + * The context object that was the payload of a broadcast message. + */ + context: Context; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to broadcast on a PrivateChannel. + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface PrivateChannelBroadcastBridgeRequest { + meta: PrivateChannelBroadcastBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelBroadcastBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.broadcast"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface PrivateChannelBroadcastBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelBroadcastBridgeRequestPayload { + /** + * The Id of the PrivateChannel that the broadcast was sent on + */ + channelId: string; + /** + * The context object that was the payload of a broadcast message. + */ + context: Context; +} + +/** + * A request to forward on an EventListenerAdded event, relating to a PrivateChannel + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface PrivateChannelEventListenerAddedAgentRequest { + meta: PrivateChannelEventListenerAddedAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelEventListenerAddedAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.eventListenerAdded"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface PrivateChannelEventListenerAddedAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelEventListenerAddedAgentRequestPayload { + /** + * The id of the PrivateChannel that the event listener was added to. + */ + channelId: string; + listenerType: PrivateChannelEventListenerTypes; +} + +/** + * Event listener type names for Private Channel events. + */ +export type PrivateChannelEventListenerTypes = "onAddContextListener" | "onUnsubscribe" | "onDisconnect"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to forward on an EventListenerAdded event, relating to a PrivateChannel + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface PrivateChannelEventListenerAddedBridgeRequest { + meta: PrivateChannelEventListenerAddedBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelEventListenerAddedBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.eventListenerAdded"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface PrivateChannelEventListenerAddedBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelEventListenerAddedBridgeRequestPayload { + /** + * The id of the PrivateChannel that the event listener was added to. + */ + channelId: string; + listenerType: PrivateChannelEventListenerTypes; +} + +/** + * A request to forward on an EventListenerRemoved event, relating to a PrivateChannel + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface PrivateChannelEventListenerRemovedAgentRequest { + meta: PrivateChannelEventListenerRemovedAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelEventListenerRemovedAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.eventListenerRemoved"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface PrivateChannelEventListenerRemovedAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelEventListenerRemovedAgentRequestPayload { + /** + * The id of the PrivateChannel that the event listener was removed from. + */ + channelId: string; + listenerType: PrivateChannelEventListenerTypes; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to forward on an EventListenerRemoved event, relating to a PrivateChannel + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface PrivateChannelEventListenerRemovedBridgeRequest { + meta: PrivateChannelEventListenerRemovedBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelEventListenerRemovedBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.eventListenerRemoved"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface PrivateChannelEventListenerRemovedBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelEventListenerRemovedBridgeRequestPayload { + /** + * The id of the PrivateChannel that the event listener was removed from. + */ + channelId: string; + listenerType: PrivateChannelEventListenerTypes; +} + +/** + * A request to forward on an AddContextListener event, relating to a PrivateChannel + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface PrivateChannelOnAddContextListenerAgentRequest { + meta: PrivateChannelOnAddContextListenerAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelOnAddContextListenerAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.onAddContextListener"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface PrivateChannelOnAddContextListenerAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelOnAddContextListenerAgentRequestPayload { + /** + * The id of the PrivateChannel that the context listener was added to. + */ + channelId: string; + /** + * The type of the context listener added. Should be null for an untyped listener. + */ + contextType: null | string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to forward on an AddContextListener event, relating to a PrivateChannel + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface PrivateChannelOnAddContextListenerBridgeRequest { + meta: PrivateChannelOnAddContextListenerBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelOnAddContextListenerBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.onAddContextListener"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface PrivateChannelOnAddContextListenerBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelOnAddContextListenerBridgeRequestPayload { + /** + * The id of the PrivateChannel that the context listener was added to. + */ + channelId: string; + /** + * The type of the context listener added. Should be null for an untyped listener. + */ + contextType: null | string; +} + +/** + * A request to forward on a Disconnect event, relating to a PrivateChannel + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface PrivateChannelOnDisconnectAgentRequest { + meta: PrivateChannelOnDisconnectAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelOnDisconnectAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.onDisconnect"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface PrivateChannelOnDisconnectAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelOnDisconnectAgentRequestPayload { + /** + * The id of the PrivateChannel that the agent discconnected from. + */ + channelId: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to forward on a Disconnect event, relating to a PrivateChannel + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface PrivateChannelOnDisconnectBridgeRequest { + meta: PrivateChannelOnDisconnectBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelOnDisconnectBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.onDisconnect"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface PrivateChannelOnDisconnectBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelOnDisconnectBridgeRequestPayload { + /** + * The id of the PrivateChannel that the agent discconnected from. + */ + channelId: string; +} + +/** + * A request to forward on an Unsubscribe event, relating to a PrivateChannel + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface PrivateChannelOnUnsubscribeAgentRequest { + meta: PrivateChannelOnUnsubscribeAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelOnUnsubscribeAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.onUnsubscribe"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface PrivateChannelOnUnsubscribeAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source?: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelOnUnsubscribeAgentRequestPayload { + /** + * The id of the PrivateChannel that the context listener was unsubscribed from. + */ + channelId: string; + /** + * The type of the context listener that was unsubscribed. Should be null for an untyped + * listener. + */ + contextType: null | string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to forward on an Unsubscribe event, relating to a PrivateChannel + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface PrivateChannelOnUnsubscribeBridgeRequest { + meta: ERequestMetadata; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelOnUnsubscribeBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "PrivateChannel.onUnsubscribe"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface ERequestMetadata { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination?: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface PrivateChannelOnUnsubscribeBridgeRequestPayload { + /** + * The id of the PrivateChannel that the context listener was unsubscribed from. + */ + channelId: string; + /** + * The type of the context listener that was unsubscribed. Should be null for an untyped + * listener. + */ + contextType: null | string; +} + +/** + * A response to a request to raise an intent that contains an error. + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface RaiseIntentAgentErrorResponse { + meta: RaiseIntentAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: RaiseIntentAgentErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface RaiseIntentAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Used if a raiseIntent request resulted in an error. + * + * Error message payload containing an standardized error string. + */ +export interface RaiseIntentAgentErrorResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error: FindInstancesErrors; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A request to raise an intent. + * + * A request message from a Desktop Agent to the Bridge. + */ +export interface RaiseIntentAgentRequest { + meta: RaiseIntentAgentRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: RaiseIntentAgentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "raiseIntentRequest"; +} + +/** + * Metadata for a request message sent by Desktop Agents to the Bridge. + */ +export interface RaiseIntentAgentRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. + */ + source: SourceObject; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface RaiseIntentAgentRequestPayload { + app: AppDestinationIdentifier; + context: Context; + intent: string; +} + +/** + * Field that represents a destination App on a remote Desktop Agent that a request is to be + * sent to. + * + * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios + * where a request needs to be directed to a Desktop Agent rather than a specific app, or a + * response message is returned by the Desktop Agent (or more specifically its resolver) + * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no + * app details are available or are appropriate. + * + * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge + * before the timeout or because an error occurred. May be omitted if all sources responded + * without errors. MUST include the `desktopAgent` field when returned by the bridge. + * + * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. + * Will contain a single value for individual responses and multiple values for responses + * that were collated by the bridge. May be omitted if all sources errored. MUST include the + * `desktopAgent` field when returned by the bridge. + * + * Field that represents a destination Desktop Agent that a request is to be sent to. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that a request or response was received + * from. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ +export interface AppDestinationIdentifier { + /** + * Used in Desktop Agent Bridging to attribute or target a message to a + * particular Desktop Agent. + * + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent: string; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A response to a request to raise an intent. + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface RaiseIntentAgentResponse { + meta: RaiseIntentAgentResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: RaiseIntentAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface RaiseIntentAgentResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface RaiseIntentAgentResponsePayload { + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution: IntentResolution; +} + +/** + * Used if the raiseIntent request was successfully resolved. + * + * IntentResolution provides a standard format for data returned upon resolving an intent. + * + * ```javascript + * //resolve a "Chain" type intent + * let resolution = await agent.raiseIntent("intentName", context); + * + * //resolve a "Client-Service" type intent with a data response or a Channel + * let resolution = await agent.raiseIntent("intentName", context); + * try { + * const result = await resolution.getResult(); + * if (result && result.broadcast) { + * console.log(`${resolution.source} returned a channel with id ${result.id}`); + * } else if (result){ + * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); + * } else { + * console.error(`${resolution.source} didn't return data` + * } + * } catch(error) { + * console.error(`${resolution.source} returned an error: ${error}`); + * } + * + * // Use metadata about the resolving app instance to target a further intent + * await agent.raiseIntent("intentName", context, resolution.source); + * ``` + */ +export interface IntentResolution { + /** + * The intent that was raised. May be used to determine which intent the user + * chose in response to `fdc3.raiseIntentForContext()`. + */ + intent: string; + /** + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ + source: AppIdentifier; +} + +/** + * A response to a request to raise an intent that contains an error. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface RaiseIntentBridgeErrorResponse { + meta: RaiseIntentBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: RaiseIntentBridgeErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface RaiseIntentBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Used if a raiseIntent request resulted in an error. + * + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface RaiseIntentBridgeErrorResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error: FindInstancesErrors; +} + +/** + * A request to raise an intent. + * + * A request message forwarded from the Bridge onto a Desktop Agent connected to it. + */ +export interface RaiseIntentBridgeRequest { + meta: RaiseIntentBridgeRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: RaiseIntentBridgeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "raiseIntentRequest"; +} + +/** + * Metadata required in a request message forwarded on by the Bridge + */ +export interface RaiseIntentBridgeRequestMeta { + /** + * Optional field that represents the destination that the request should be routed to. Must + * be set by the Desktop Agent for API calls that include a target app parameter and must + * include the name of the Desktop Agent hosting the target application. + */ + destination: MetaDestination; + requestUuid: string; + /** + * Field that represents the source application that the request was received from, or the + * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST + * be set by the bridge. + */ + source: MetaSource; + timestamp: Date; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface RaiseIntentBridgeRequestPayload { + app: AppDestinationIdentifier; + context: Context; + intent: string; +} + +/** + * A response to a request to raise an intent. + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface RaiseIntentBridgeResponse { + meta: RaiseIntentBridgeResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: RaiseIntentBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface RaiseIntentBridgeResponseMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface RaiseIntentBridgeResponsePayload { + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution: IntentResolution; +} + +/** + * A secondary response to a request to raise an intent used to deliver the intent result, + * which contains an error + * + * A response message from a Desktop Agent to the Bridge containing an error, to be used in + * preference to the standard response when an error needs to be returned. + */ +export interface RaiseIntentResultAgentErrorResponse { + meta: RaiseIntentResultAgentErrorResponseMeta; + /** + * Error message payload containing an standardized error string. + */ + payload: RaiseIntentResultAgentErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResultResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface RaiseIntentResultAgentErrorResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * Error message payload containing an standardized error string. + */ +export interface RaiseIntentResultAgentErrorResponsePayload { + error: RaiseIntentResultErrorMessage; +} + +/** + * Array of error message strings for responses that were not returned to the bridge before + * the timeout or because an error occurred. Should be the same length as the `errorSources` + * array and ordered the same. May be omitted if all sources responded without errors. + * + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + */ +export type RaiseIntentResultErrorMessage = "IntentHandlerRejected" | "NoResultReturned" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + */ + +/** + * A secondary response to a request to raise an intent used to deliver the intent result + * + * A response message from a Desktop Agent to the Bridge. + */ +export interface RaiseIntentResultAgentResponse { + meta: RaiseIntentResultAgentResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: RaiseIntentResultAgentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResultResponse"; +} + +/** + * Metadata for a response messages sent by a Desktop Agent to the Bridge + */ +export interface RaiseIntentResultAgentResponseMeta { + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface RaiseIntentResultAgentResponsePayload { + intentResult: IntentResult; +} + +export interface IntentResult { + context?: Context; + channel?: Channel; +} + +/** + * Represents a context channel that applications can use to send and receive + * context data. + * + * Please note that There are differences in behavior when you interact with a + * User channel via the `DesktopAgent` interface and the `Channel` interface. + * Specifically, when 'joining' a User channel or adding a context listener + * when already joined to a channel via the `DesktopAgent` interface, existing + * context (matching the type of the context listener) on the channel is + * received by the context listener immediately. Whereas, when a context + * listener is added via the Channel interface, context is not received + * automatically, but may be retrieved manually via the `getCurrentContext()` + * function. + */ +export interface Channel { + /** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + */ + displayMetadata?: DisplayMetadata; + /** + * Constant that uniquely identifies this channel. + */ + id: string; + /** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ + type: Type; +} + +/** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + * + * A system channel will be global enough to have a presence across many apps. This gives us + * some hints + * to render them in a standard way. It is assumed it may have other properties too, but if + * it has these, + * this is their meaning. + */ +export interface DisplayMetadata { + /** + * The color that should be associated within this channel when displaying this channel in a + * UI, e.g: `0xFF0000`. + */ + color?: string; + /** + * A URL of an image that can be used to display this channel. + */ + glyph?: string; + /** + * A user-readable name for this channel, e.g: `"Red"`. + */ + name?: string; +} + +/** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ +export type Type = "app" | "private" | "user"; + +/** + * A secondary response to a request to raise an intent used to deliver the intent result, + * which contains an error + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request, used where all connected agents returned errors. + */ +export interface RaiseIntentResultBridgeErrorResponse { + meta: RaiseIntentResultBridgeErrorResponseMeta; + /** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ + payload: RaiseIntentResultBridgeErrorResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResultResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface RaiseIntentResultBridgeErrorResponseMeta { + errorDetails: ResponseErrorDetail[]; + errorSources: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + timestamp: Date; +} + +/** + * The error message payload contains details of an error return to the app or agent that + * raised the original request. + */ +export interface RaiseIntentResultBridgeErrorResponsePayload { + error: RaiseIntentResultErrorMessage; +} + +/** + * A secondary response to a request to raise an intent used to deliver the intent result + * + * A response message from the Bridge back to the original Desktop Agent that raised the + * request. + */ +export interface RaiseIntentResultBridgeResponse { + meta: RaiseIntentResultBridgeResponseMeta; + /** + * The message payload typically contains return values for FDC3 API functions. + */ + payload: RaiseIntentResultBridgeResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "raiseIntentResultResponse"; +} + +/** + * Metadata required in a response message collated and/or forwarded on by the Bridge + */ +export interface RaiseIntentResultBridgeResponseMeta { + errorDetails?: ResponseErrorDetail[]; + errorSources?: DesktopAgentIdentifier[]; + requestUuid: string; + responseUuid: string; + sources?: DesktopAgentIdentifier[]; + timestamp: Date; +} + +/** + * The message payload typically contains return values for FDC3 API functions. + */ +export interface RaiseIntentResultBridgeResponsePayload { + intentResult: IntentResult; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toAgentErrorResponseMessage(json: string): AgentErrorResponseMessage { + return cast(JSON.parse(json), r("AgentErrorResponseMessage")); + } + + public static agentErrorResponseMessageToJson(value: AgentErrorResponseMessage): string { + return JSON.stringify(uncast(value, r("AgentErrorResponseMessage")), null, 2); + } + + public static toAgentRequestMessage(json: string): AgentRequestMessage { + return cast(JSON.parse(json), r("AgentRequestMessage")); + } + + public static agentRequestMessageToJson(value: AgentRequestMessage): string { + return JSON.stringify(uncast(value, r("AgentRequestMessage")), null, 2); + } + + public static toAgentResponseMessage(json: string): AgentResponseMessage { + return cast(JSON.parse(json), r("AgentResponseMessage")); + } + + public static agentResponseMessageToJson(value: AgentResponseMessage): string { + return JSON.stringify(uncast(value, r("AgentResponseMessage")), null, 2); + } + + public static toBridgeErrorResponseMessage(json: string): BridgeErrorResponseMessage { + return cast(JSON.parse(json), r("BridgeErrorResponseMessage")); + } + + public static bridgeErrorResponseMessageToJson(value: BridgeErrorResponseMessage): string { + return JSON.stringify(uncast(value, r("BridgeErrorResponseMessage")), null, 2); + } + + public static toBridgeRequestMessage(json: string): BridgeRequestMessage { + return cast(JSON.parse(json), r("BridgeRequestMessage")); + } + + public static bridgeRequestMessageToJson(value: BridgeRequestMessage): string { + return JSON.stringify(uncast(value, r("BridgeRequestMessage")), null, 2); + } + + public static toBridgeResponseMessage(json: string): BridgeResponseMessage { + return cast(JSON.parse(json), r("BridgeResponseMessage")); + } + + public static bridgeResponseMessageToJson(value: BridgeResponseMessage): string { + return JSON.stringify(uncast(value, r("BridgeResponseMessage")), null, 2); + } + + public static toBroadcastAgentRequest(json: string): BroadcastAgentRequest { + return cast(JSON.parse(json), r("BroadcastAgentRequest")); + } + + public static broadcastAgentRequestToJson(value: BroadcastAgentRequest): string { + return JSON.stringify(uncast(value, r("BroadcastAgentRequest")), null, 2); + } + + public static toBroadcastBridgeRequest(json: string): BroadcastBridgeRequest { + return cast(JSON.parse(json), r("BroadcastBridgeRequest")); + } + + public static broadcastBridgeRequestToJson(value: BroadcastBridgeRequest): string { + return JSON.stringify(uncast(value, r("BroadcastBridgeRequest")), null, 2); + } + + public static toBridgeCommonDefinitions(json: string): { [key: string]: any } { + return cast(JSON.parse(json), m("any")); + } + + public static bridgeCommonDefinitionsToJson(value: { [key: string]: any }): string { + return JSON.stringify(uncast(value, m("any")), null, 2); + } + + public static toConnectionStepMessage(json: string): ConnectionStepMessage { + return cast(JSON.parse(json), r("ConnectionStepMessage")); + } + + public static connectionStepMessageToJson(value: ConnectionStepMessage): string { + return JSON.stringify(uncast(value, r("ConnectionStepMessage")), null, 2); + } + + public static toConnectionStep2Hello(json: string): ConnectionStep2Hello { + return cast(JSON.parse(json), r("ConnectionStep2Hello")); + } + + public static connectionStep2HelloToJson(value: ConnectionStep2Hello): string { + return JSON.stringify(uncast(value, r("ConnectionStep2Hello")), null, 2); + } + + public static toConnectionStep3Handshake(json: string): ConnectionStep3Handshake { + return cast(JSON.parse(json), r("ConnectionStep3Handshake")); + } + + public static connectionStep3HandshakeToJson(value: ConnectionStep3Handshake): string { + return JSON.stringify(uncast(value, r("ConnectionStep3Handshake")), null, 2); + } + + public static toConnectionStep4AuthenticationFailed(json: string): ConnectionStep4AuthenticationFailed { + return cast(JSON.parse(json), r("ConnectionStep4AuthenticationFailed")); + } + + public static connectionStep4AuthenticationFailedToJson(value: ConnectionStep4AuthenticationFailed): string { + return JSON.stringify(uncast(value, r("ConnectionStep4AuthenticationFailed")), null, 2); + } + + public static toConnectionStep6ConnectedAgentsUpdate(json: string): ConnectionStep6ConnectedAgentsUpdate { + return cast(JSON.parse(json), r("ConnectionStep6ConnectedAgentsUpdate")); + } + + public static connectionStep6ConnectedAgentsUpdateToJson(value: ConnectionStep6ConnectedAgentsUpdate): string { + return JSON.stringify(uncast(value, r("ConnectionStep6ConnectedAgentsUpdate")), null, 2); + } + + public static toFindInstancesAgentErrorResponse(json: string): FindInstancesAgentErrorResponse { + return cast(JSON.parse(json), r("FindInstancesAgentErrorResponse")); + } + + public static findInstancesAgentErrorResponseToJson(value: FindInstancesAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("FindInstancesAgentErrorResponse")), null, 2); + } + + public static toFindInstancesAgentRequest(json: string): FindInstancesAgentRequest { + return cast(JSON.parse(json), r("FindInstancesAgentRequest")); + } + + public static findInstancesAgentRequestToJson(value: FindInstancesAgentRequest): string { + return JSON.stringify(uncast(value, r("FindInstancesAgentRequest")), null, 2); + } + + public static toFindInstancesAgentResponse(json: string): FindInstancesAgentResponse { + return cast(JSON.parse(json), r("FindInstancesAgentResponse")); + } + + public static findInstancesAgentResponseToJson(value: FindInstancesAgentResponse): string { + return JSON.stringify(uncast(value, r("FindInstancesAgentResponse")), null, 2); + } + + public static toFindInstancesBridgeErrorResponse(json: string): FindInstancesBridgeErrorResponse { + return cast(JSON.parse(json), r("FindInstancesBridgeErrorResponse")); + } + + public static findInstancesBridgeErrorResponseToJson(value: FindInstancesBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("FindInstancesBridgeErrorResponse")), null, 2); + } + + public static toFindInstancesBridgeRequest(json: string): FindInstancesBridgeRequest { + return cast(JSON.parse(json), r("FindInstancesBridgeRequest")); + } + + public static findInstancesBridgeRequestToJson(value: FindInstancesBridgeRequest): string { + return JSON.stringify(uncast(value, r("FindInstancesBridgeRequest")), null, 2); + } + + public static toFindInstancesBridgeResponse(json: string): FindInstancesBridgeResponse { + return cast(JSON.parse(json), r("FindInstancesBridgeResponse")); + } + + public static findInstancesBridgeResponseToJson(value: FindInstancesBridgeResponse): string { + return JSON.stringify(uncast(value, r("FindInstancesBridgeResponse")), null, 2); + } + + public static toFindIntentAgentErrorResponse(json: string): FindIntentAgentErrorResponse { + return cast(JSON.parse(json), r("FindIntentAgentErrorResponse")); + } + + public static findIntentAgentErrorResponseToJson(value: FindIntentAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("FindIntentAgentErrorResponse")), null, 2); + } + + public static toFindIntentAgentRequest(json: string): FindIntentAgentRequest { + return cast(JSON.parse(json), r("FindIntentAgentRequest")); + } + + public static findIntentAgentRequestToJson(value: FindIntentAgentRequest): string { + return JSON.stringify(uncast(value, r("FindIntentAgentRequest")), null, 2); + } + + public static toFindIntentAgentResponse(json: string): FindIntentAgentResponse { + return cast(JSON.parse(json), r("FindIntentAgentResponse")); + } + + public static findIntentAgentResponseToJson(value: FindIntentAgentResponse): string { + return JSON.stringify(uncast(value, r("FindIntentAgentResponse")), null, 2); + } + + public static toFindIntentBridgeErrorResponse(json: string): FindIntentBridgeErrorResponse { + return cast(JSON.parse(json), r("FindIntentBridgeErrorResponse")); + } + + public static findIntentBridgeErrorResponseToJson(value: FindIntentBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("FindIntentBridgeErrorResponse")), null, 2); + } + + public static toFindIntentBridgeRequest(json: string): FindIntentBridgeRequest { + return cast(JSON.parse(json), r("FindIntentBridgeRequest")); + } + + public static findIntentBridgeRequestToJson(value: FindIntentBridgeRequest): string { + return JSON.stringify(uncast(value, r("FindIntentBridgeRequest")), null, 2); + } + + public static toFindIntentBridgeResponse(json: string): FindIntentBridgeResponse { + return cast(JSON.parse(json), r("FindIntentBridgeResponse")); + } + + public static findIntentBridgeResponseToJson(value: FindIntentBridgeResponse): string { + return JSON.stringify(uncast(value, r("FindIntentBridgeResponse")), null, 2); + } + + public static toFindIntentsByContextAgentErrorResponse(json: string): FindIntentsByContextAgentErrorResponse { + return cast(JSON.parse(json), r("FindIntentsByContextAgentErrorResponse")); + } + + public static findIntentsByContextAgentErrorResponseToJson(value: FindIntentsByContextAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("FindIntentsByContextAgentErrorResponse")), null, 2); + } + + public static toFindIntentsByContextAgentRequest(json: string): FindIntentsByContextAgentRequest { + return cast(JSON.parse(json), r("FindIntentsByContextAgentRequest")); + } + + public static findIntentsByContextAgentRequestToJson(value: FindIntentsByContextAgentRequest): string { + return JSON.stringify(uncast(value, r("FindIntentsByContextAgentRequest")), null, 2); + } + + public static toFindIntentsByContextAgentResponse(json: string): FindIntentsByContextAgentResponse { + return cast(JSON.parse(json), r("FindIntentsByContextAgentResponse")); + } + + public static findIntentsByContextAgentResponseToJson(value: FindIntentsByContextAgentResponse): string { + return JSON.stringify(uncast(value, r("FindIntentsByContextAgentResponse")), null, 2); + } + + public static toFindIntentsByContextBridgeErrorResponse(json: string): FindIntentsByContextBridgeErrorResponse { + return cast(JSON.parse(json), r("FindIntentsByContextBridgeErrorResponse")); + } + + public static findIntentsByContextBridgeErrorResponseToJson(value: FindIntentsByContextBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("FindIntentsByContextBridgeErrorResponse")), null, 2); + } + + public static toFindIntentsByContextBridgeRequest(json: string): FindIntentsByContextBridgeRequest { + return cast(JSON.parse(json), r("FindIntentsByContextBridgeRequest")); + } + + public static findIntentsByContextBridgeRequestToJson(value: FindIntentsByContextBridgeRequest): string { + return JSON.stringify(uncast(value, r("FindIntentsByContextBridgeRequest")), null, 2); + } + + public static toFindIntentsByContextBridgeResponse(json: string): FindIntentsByContextBridgeResponse { + return cast(JSON.parse(json), r("FindIntentsByContextBridgeResponse")); + } + + public static findIntentsByContextBridgeResponseToJson(value: FindIntentsByContextBridgeResponse): string { + return JSON.stringify(uncast(value, r("FindIntentsByContextBridgeResponse")), null, 2); + } + + public static toGetAppMetadataAgentErrorResponse(json: string): GetAppMetadataAgentErrorResponse { + return cast(JSON.parse(json), r("GetAppMetadataAgentErrorResponse")); + } + + public static getAppMetadataAgentErrorResponseToJson(value: GetAppMetadataAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("GetAppMetadataAgentErrorResponse")), null, 2); + } + + public static toGetAppMetadataAgentRequest(json: string): GetAppMetadataAgentRequest { + return cast(JSON.parse(json), r("GetAppMetadataAgentRequest")); + } + + public static getAppMetadataAgentRequestToJson(value: GetAppMetadataAgentRequest): string { + return JSON.stringify(uncast(value, r("GetAppMetadataAgentRequest")), null, 2); + } + + public static toGetAppMetadataAgentResponse(json: string): GetAppMetadataAgentResponse { + return cast(JSON.parse(json), r("GetAppMetadataAgentResponse")); + } + + public static getAppMetadataAgentResponseToJson(value: GetAppMetadataAgentResponse): string { + return JSON.stringify(uncast(value, r("GetAppMetadataAgentResponse")), null, 2); + } + + public static toGetAppMetadataBridgeErrorResponse(json: string): GetAppMetadataBridgeErrorResponse { + return cast(JSON.parse(json), r("GetAppMetadataBridgeErrorResponse")); + } + + public static getAppMetadataBridgeErrorResponseToJson(value: GetAppMetadataBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("GetAppMetadataBridgeErrorResponse")), null, 2); + } + + public static toGetAppMetadataBridgeRequest(json: string): GetAppMetadataBridgeRequest { + return cast(JSON.parse(json), r("GetAppMetadataBridgeRequest")); + } + + public static getAppMetadataBridgeRequestToJson(value: GetAppMetadataBridgeRequest): string { + return JSON.stringify(uncast(value, r("GetAppMetadataBridgeRequest")), null, 2); + } + + public static toGetAppMetadataBridgeResponse(json: string): GetAppMetadataBridgeResponse { + return cast(JSON.parse(json), r("GetAppMetadataBridgeResponse")); + } + + public static getAppMetadataBridgeResponseToJson(value: GetAppMetadataBridgeResponse): string { + return JSON.stringify(uncast(value, r("GetAppMetadataBridgeResponse")), null, 2); + } + + public static toOpenAgentErrorResponse(json: string): OpenAgentErrorResponse { + return cast(JSON.parse(json), r("OpenAgentErrorResponse")); + } + + public static openAgentErrorResponseToJson(value: OpenAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("OpenAgentErrorResponse")), null, 2); + } + + public static toOpenAgentRequest(json: string): OpenAgentRequest { + return cast(JSON.parse(json), r("OpenAgentRequest")); + } + + public static openAgentRequestToJson(value: OpenAgentRequest): string { + return JSON.stringify(uncast(value, r("OpenAgentRequest")), null, 2); + } + + public static toOpenAgentResponse(json: string): OpenAgentResponse { + return cast(JSON.parse(json), r("OpenAgentResponse")); + } + + public static openAgentResponseToJson(value: OpenAgentResponse): string { + return JSON.stringify(uncast(value, r("OpenAgentResponse")), null, 2); + } + + public static toOpenBridgeErrorResponse(json: string): OpenBridgeErrorResponse { + return cast(JSON.parse(json), r("OpenBridgeErrorResponse")); + } + + public static openBridgeErrorResponseToJson(value: OpenBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("OpenBridgeErrorResponse")), null, 2); + } + + public static toOpenBridgeRequest(json: string): OpenBridgeRequest { + return cast(JSON.parse(json), r("OpenBridgeRequest")); + } + + public static openBridgeRequestToJson(value: OpenBridgeRequest): string { + return JSON.stringify(uncast(value, r("OpenBridgeRequest")), null, 2); + } + + public static toOpenBridgeResponse(json: string): OpenBridgeResponse { + return cast(JSON.parse(json), r("OpenBridgeResponse")); + } + + public static openBridgeResponseToJson(value: OpenBridgeResponse): string { + return JSON.stringify(uncast(value, r("OpenBridgeResponse")), null, 2); + } + + public static toPrivateChannelBroadcastAgentRequest(json: string): PrivateChannelBroadcastAgentRequest { + return cast(JSON.parse(json), r("PrivateChannelBroadcastAgentRequest")); + } + + public static privateChannelBroadcastAgentRequestToJson(value: PrivateChannelBroadcastAgentRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelBroadcastAgentRequest")), null, 2); + } + + public static toPrivateChannelBroadcastBridgeRequest(json: string): PrivateChannelBroadcastBridgeRequest { + return cast(JSON.parse(json), r("PrivateChannelBroadcastBridgeRequest")); + } + + public static privateChannelBroadcastBridgeRequestToJson(value: PrivateChannelBroadcastBridgeRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelBroadcastBridgeRequest")), null, 2); + } + + public static toPrivateChannelEventListenerAddedAgentRequest(json: string): PrivateChannelEventListenerAddedAgentRequest { + return cast(JSON.parse(json), r("PrivateChannelEventListenerAddedAgentRequest")); + } + + public static privateChannelEventListenerAddedAgentRequestToJson(value: PrivateChannelEventListenerAddedAgentRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelEventListenerAddedAgentRequest")), null, 2); + } + + public static toPrivateChannelEventListenerAddedBridgeRequest(json: string): PrivateChannelEventListenerAddedBridgeRequest { + return cast(JSON.parse(json), r("PrivateChannelEventListenerAddedBridgeRequest")); + } + + public static privateChannelEventListenerAddedBridgeRequestToJson(value: PrivateChannelEventListenerAddedBridgeRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelEventListenerAddedBridgeRequest")), null, 2); + } + + public static toPrivateChannelEventListenerRemovedAgentRequest(json: string): PrivateChannelEventListenerRemovedAgentRequest { + return cast(JSON.parse(json), r("PrivateChannelEventListenerRemovedAgentRequest")); + } + + public static privateChannelEventListenerRemovedAgentRequestToJson(value: PrivateChannelEventListenerRemovedAgentRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelEventListenerRemovedAgentRequest")), null, 2); + } + + public static toPrivateChannelEventListenerRemovedBridgeRequest(json: string): PrivateChannelEventListenerRemovedBridgeRequest { + return cast(JSON.parse(json), r("PrivateChannelEventListenerRemovedBridgeRequest")); + } + + public static privateChannelEventListenerRemovedBridgeRequestToJson(value: PrivateChannelEventListenerRemovedBridgeRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelEventListenerRemovedBridgeRequest")), null, 2); + } + + public static toPrivateChannelOnAddContextListenerAgentRequest(json: string): PrivateChannelOnAddContextListenerAgentRequest { + return cast(JSON.parse(json), r("PrivateChannelOnAddContextListenerAgentRequest")); + } + + public static privateChannelOnAddContextListenerAgentRequestToJson(value: PrivateChannelOnAddContextListenerAgentRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelOnAddContextListenerAgentRequest")), null, 2); + } + + public static toPrivateChannelOnAddContextListenerBridgeRequest(json: string): PrivateChannelOnAddContextListenerBridgeRequest { + return cast(JSON.parse(json), r("PrivateChannelOnAddContextListenerBridgeRequest")); + } + + public static privateChannelOnAddContextListenerBridgeRequestToJson(value: PrivateChannelOnAddContextListenerBridgeRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelOnAddContextListenerBridgeRequest")), null, 2); + } + + public static toPrivateChannelOnDisconnectAgentRequest(json: string): PrivateChannelOnDisconnectAgentRequest { + return cast(JSON.parse(json), r("PrivateChannelOnDisconnectAgentRequest")); + } + + public static privateChannelOnDisconnectAgentRequestToJson(value: PrivateChannelOnDisconnectAgentRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelOnDisconnectAgentRequest")), null, 2); + } + + public static toPrivateChannelOnDisconnectBridgeRequest(json: string): PrivateChannelOnDisconnectBridgeRequest { + return cast(JSON.parse(json), r("PrivateChannelOnDisconnectBridgeRequest")); + } + + public static privateChannelOnDisconnectBridgeRequestToJson(value: PrivateChannelOnDisconnectBridgeRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelOnDisconnectBridgeRequest")), null, 2); + } + + public static toPrivateChannelOnUnsubscribeAgentRequest(json: string): PrivateChannelOnUnsubscribeAgentRequest { + return cast(JSON.parse(json), r("PrivateChannelOnUnsubscribeAgentRequest")); + } + + public static privateChannelOnUnsubscribeAgentRequestToJson(value: PrivateChannelOnUnsubscribeAgentRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelOnUnsubscribeAgentRequest")), null, 2); + } + + public static toPrivateChannelOnUnsubscribeBridgeRequest(json: string): PrivateChannelOnUnsubscribeBridgeRequest { + return cast(JSON.parse(json), r("PrivateChannelOnUnsubscribeBridgeRequest")); + } + + public static privateChannelOnUnsubscribeBridgeRequestToJson(value: PrivateChannelOnUnsubscribeBridgeRequest): string { + return JSON.stringify(uncast(value, r("PrivateChannelOnUnsubscribeBridgeRequest")), null, 2); + } + + public static toRaiseIntentAgentErrorResponse(json: string): RaiseIntentAgentErrorResponse { + return cast(JSON.parse(json), r("RaiseIntentAgentErrorResponse")); + } + + public static raiseIntentAgentErrorResponseToJson(value: RaiseIntentAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentAgentErrorResponse")), null, 2); + } + + public static toRaiseIntentAgentRequest(json: string): RaiseIntentAgentRequest { + return cast(JSON.parse(json), r("RaiseIntentAgentRequest")); + } + + public static raiseIntentAgentRequestToJson(value: RaiseIntentAgentRequest): string { + return JSON.stringify(uncast(value, r("RaiseIntentAgentRequest")), null, 2); + } + + public static toRaiseIntentAgentResponse(json: string): RaiseIntentAgentResponse { + return cast(JSON.parse(json), r("RaiseIntentAgentResponse")); + } + + public static raiseIntentAgentResponseToJson(value: RaiseIntentAgentResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentAgentResponse")), null, 2); + } + + public static toRaiseIntentBridgeErrorResponse(json: string): RaiseIntentBridgeErrorResponse { + return cast(JSON.parse(json), r("RaiseIntentBridgeErrorResponse")); + } + + public static raiseIntentBridgeErrorResponseToJson(value: RaiseIntentBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentBridgeErrorResponse")), null, 2); + } + + public static toRaiseIntentBridgeRequest(json: string): RaiseIntentBridgeRequest { + return cast(JSON.parse(json), r("RaiseIntentBridgeRequest")); + } + + public static raiseIntentBridgeRequestToJson(value: RaiseIntentBridgeRequest): string { + return JSON.stringify(uncast(value, r("RaiseIntentBridgeRequest")), null, 2); + } + + public static toRaiseIntentBridgeResponse(json: string): RaiseIntentBridgeResponse { + return cast(JSON.parse(json), r("RaiseIntentBridgeResponse")); + } + + public static raiseIntentBridgeResponseToJson(value: RaiseIntentBridgeResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentBridgeResponse")), null, 2); + } + + public static toRaiseIntentResultAgentErrorResponse(json: string): RaiseIntentResultAgentErrorResponse { + return cast(JSON.parse(json), r("RaiseIntentResultAgentErrorResponse")); + } + + public static raiseIntentResultAgentErrorResponseToJson(value: RaiseIntentResultAgentErrorResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentResultAgentErrorResponse")), null, 2); + } + + public static toRaiseIntentResultAgentResponse(json: string): RaiseIntentResultAgentResponse { + return cast(JSON.parse(json), r("RaiseIntentResultAgentResponse")); + } + + public static raiseIntentResultAgentResponseToJson(value: RaiseIntentResultAgentResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentResultAgentResponse")), null, 2); + } + + public static toRaiseIntentResultBridgeErrorResponse(json: string): RaiseIntentResultBridgeErrorResponse { + return cast(JSON.parse(json), r("RaiseIntentResultBridgeErrorResponse")); + } + + public static raiseIntentResultBridgeErrorResponseToJson(value: RaiseIntentResultBridgeErrorResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentResultBridgeErrorResponse")), null, 2); + } + + public static toRaiseIntentResultBridgeResponse(json: string): RaiseIntentResultBridgeResponse { + return cast(JSON.parse(json), r("RaiseIntentResultBridgeResponse")); + } + + public static raiseIntentResultBridgeResponseToJson(value: RaiseIntentResultBridgeResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentResultBridgeResponse")), null, 2); + } +} + +function invalidValue(typ: any, val: any, key: any, parent: any = ''): never { + const prettyTyp = prettyTypeName(typ); + const parentText = parent ? ` on ${parent}` : ''; + const keyText = key ? ` for key "${key}"` : ''; + throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`); +} + +function prettyTypeName(typ: any): string { + if (Array.isArray(typ)) { + if (typ.length === 2 && typ[0] === undefined) { + return `an optional ${prettyTypeName(typ[1])}`; + } else { + return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`; + } + } else if (typeof typ === "object" && typ.literal !== undefined) { + return typ.literal; + } else { + return typeof typ; + } +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val, key, parent); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val, key, parent); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases.map(a => { return l(a); }), val, key, parent); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue(l("Date"), val, key, parent); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue(l(ref || "object"), val, key, parent); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps, key, ref); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps, key, ref); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val, key, parent); + } + if (typ === false) return invalidValue(typ, val, key, parent); + let ref: any = undefined; + while (typeof typ === "object" && typ.ref !== undefined) { + ref = typ.ref; + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val, key, parent); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function l(typ: any) { + return { literal: typ }; +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "AgentErrorResponseMessage": o([ + { json: "meta", js: "meta", typ: r("AgentResponseMetadata") }, + { json: "payload", js: "payload", typ: r("ErrorResponseMessagePayload") }, + { json: "type", js: "type", typ: r("ResponseMessageType") }, + ], false), + "AgentResponseMetadata": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "ErrorResponseMessagePayload": o([ + { json: "error", js: "error", typ: r("ResponseErrorDetail") }, + ], "any"), + "AgentRequestMessage": o([ + { json: "meta", js: "meta", typ: r("AgentRequestMetadata") }, + { json: "payload", js: "payload", typ: m("any") }, + { json: "type", js: "type", typ: r("RequestMessageType") }, + ], false), + "AgentRequestMetadata": o([ + { json: "destination", js: "destination", typ: u(undefined, r("BridgeParticipantIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceIdentifier")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "BridgeParticipantIdentifier": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "appId", js: "appId", typ: u(undefined, "") }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "SourceIdentifier": o([ + { json: "appId", js: "appId", typ: u(undefined, "") }, + { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "AgentResponseMessage": o([ + { json: "meta", js: "meta", typ: r("AgentResponseMetadata") }, + { json: "payload", js: "payload", typ: m("any") }, + { json: "type", js: "type", typ: r("ResponseMessageType") }, + ], false), + "BridgeErrorResponseMessage": o([ + { json: "meta", js: "meta", typ: r("BridgeErrorResponseMessageMeta") }, + { json: "payload", js: "payload", typ: r("ResponseErrorMessagePayload") }, + { json: "type", js: "type", typ: "" }, + ], false), + "BridgeErrorResponseMessageMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "DesktopAgentIdentifier": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + ], "any"), + "ResponseErrorMessagePayload": o([ + { json: "error", js: "error", typ: u(undefined, r("ResponseErrorDetail")) }, + ], "any"), + "BridgeRequestMessage": o([ + { json: "meta", js: "meta", typ: r("BridgeRequestMetadata") }, + { json: "payload", js: "payload", typ: m("any") }, + { json: "type", js: "type", typ: "" }, + ], false), + "BridgeRequestMetadata": o([ + { json: "destination", js: "destination", typ: u(undefined, r("BridgeParticipantIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("BridgeParticipantIdentifier") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "BridgeResponseMessage": o([ + { json: "meta", js: "meta", typ: r("BridgeResponseMessageMeta") }, + { json: "payload", js: "payload", typ: m("any") }, + { json: "type", js: "type", typ: "" }, + ], false), + "BridgeResponseMessageMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "BroadcastAgentRequest": o([ + { json: "meta", js: "meta", typ: r("BroadcastAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("BroadcastAgentRequestPayload") }, + { json: "type", js: "type", typ: r("BroadcastAgentRequestType") }, + ], false), + "BroadcastAgentRequestMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("SourceObject") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "SourceObject": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "BroadcastAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "context", js: "context", typ: r("Context") }, + ], false), + "Context": o([ + { json: "id", js: "id", typ: u(undefined, m("any")) }, + { json: "name", js: "name", typ: u(undefined, "") }, + { json: "type", js: "type", typ: "" }, + ], "any"), + "BroadcastBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("BroadcastBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("BroadcastBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("BroadcastAgentRequestType") }, + ], false), + "BroadcastBridgeRequestMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "MetaSource": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "BroadcastBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "context", js: "context", typ: r("Context") }, + ], false), + "ConnectionStepMessage": o([ + { json: "meta", js: "meta", typ: r("ConnectionStepMetadata") }, + { json: "payload", js: "payload", typ: m("any") }, + { json: "type", js: "type", typ: r("ConnectionStepMessageType") }, + ], false), + "ConnectionStepMetadata": o([ + { json: "requestUuid", js: "requestUuid", typ: u(undefined, "") }, + { json: "responseUuid", js: "responseUuid", typ: u(undefined, "") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "ConnectionStep2Hello": o([ + { json: "meta", js: "meta", typ: r("ConnectionStep2HelloMeta") }, + { json: "payload", js: "payload", typ: r("ConnectionStep2HelloPayload") }, + { json: "type", js: "type", typ: r("ConnectionStep2HelloType") }, + ], false), + "ConnectionStep2HelloMeta": o([ + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "ConnectionStep2HelloPayload": o([ + { json: "authRequired", js: "authRequired", typ: true }, + { json: "authToken", js: "authToken", typ: u(undefined, "") }, + { json: "desktopAgentBridgeVersion", js: "desktopAgentBridgeVersion", typ: "" }, + { json: "supportedFDC3Versions", js: "supportedFDC3Versions", typ: a("") }, + ], false), + "ConnectionStep3Handshake": o([ + { json: "meta", js: "meta", typ: r("ConnectionStep3HandshakeMeta") }, + { json: "payload", js: "payload", typ: r("ConnectionStep3HandshakePayload") }, + { json: "type", js: "type", typ: r("ConnectionStep3HandshakeType") }, + ], false), + "ConnectionStep3HandshakeMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "ConnectionStep3HandshakePayload": o([ + { json: "authToken", js: "authToken", typ: u(undefined, "") }, + { json: "channelsState", js: "channelsState", typ: m(a(r("Context"))) }, + { json: "implementationMetadata", js: "implementationMetadata", typ: r("ConnectingAgentImplementationMetadata") }, + { json: "requestedName", js: "requestedName", typ: "" }, + ], false), + "ConnectingAgentImplementationMetadata": o([ + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, + { json: "provider", js: "provider", typ: "" }, + { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, + ], false), + "OptionalFeatures": o([ + { json: "DesktopAgentBridging", js: "DesktopAgentBridging", typ: true }, + { json: "OriginatingAppMetadata", js: "OriginatingAppMetadata", typ: true }, + { json: "UserChannelMembershipAPIs", js: "UserChannelMembershipAPIs", typ: true }, + ], false), + "ConnectionStep4AuthenticationFailed": o([ + { json: "meta", js: "meta", typ: r("ConnectionStep4AuthenticationFailedMeta") }, + { json: "payload", js: "payload", typ: r("ConnectionStep4AuthenticationFailedPayload") }, + { json: "type", js: "type", typ: r("ConnectionStep4AuthenticationFailedType") }, + ], false), + "ConnectionStep4AuthenticationFailedMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "ConnectionStep4AuthenticationFailedPayload": o([ + { json: "message", js: "message", typ: u(undefined, "") }, + ], false), + "ConnectionStep6ConnectedAgentsUpdate": o([ + { json: "meta", js: "meta", typ: r("ConnectionStep6ConnectedAgentsUpdateMeta") }, + { json: "payload", js: "payload", typ: r("ConnectionStep6ConnectedAgentsUpdatePayload") }, + { json: "type", js: "type", typ: r("ConnectionStep6ConnectedAgentsUpdateType") }, + ], false), + "ConnectionStep6ConnectedAgentsUpdateMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "ConnectionStep6ConnectedAgentsUpdatePayload": o([ + { json: "addAgent", js: "addAgent", typ: u(undefined, "") }, + { json: "allAgents", js: "allAgents", typ: a(r("DesktopAgentImplementationMetadata")) }, + { json: "channelsState", js: "channelsState", typ: u(undefined, m(a(r("Context")))) }, + { json: "removeAgent", js: "removeAgent", typ: u(undefined, "") }, + ], false), + "DesktopAgentImplementationMetadata": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, + { json: "provider", js: "provider", typ: "" }, + { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, + ], false), + "FindInstancesAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("FindInstancesAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("PayloadClass") }, + { json: "type", js: "type", typ: r("FindInstancesAgentErrorResponseType") }, + ], false), + "FindInstancesAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PayloadClass": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "FindInstancesAgentRequest": o([ + { json: "meta", js: "meta", typ: r("FindInstancesAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("FindInstancesAgentRequestPayload") }, + { json: "type", js: "type", typ: r("FindInstancesAgentRequestType") }, + ], false), + "FindInstancesAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("DestinationObject")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceIdentifier")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "DestinationObject": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "appId", js: "appId", typ: u(undefined, "") }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "FindInstancesAgentRequestPayload": o([ + { json: "app", js: "app", typ: r("AppIdentifier") }, + ], false), + "AppIdentifier": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "FindInstancesAgentResponse": o([ + { json: "meta", js: "meta", typ: r("AgentResponseMetadata") }, + { json: "payload", js: "payload", typ: r("FindInstancesAgentResponsePayload") }, + { json: "type", js: "type", typ: r("FindInstancesAgentErrorResponseType") }, + ], false), + "FindInstancesAgentResponsePayload": o([ + { json: "appIdentifiers", js: "appIdentifiers", typ: a(r("AppMetadata")) }, + ], false), + "AppMetadata": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "description", js: "description", typ: u(undefined, "") }, + { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, + { json: "icons", js: "icons", typ: u(undefined, a(r("Icon"))) }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + { json: "instanceMetadata", js: "instanceMetadata", typ: u(undefined, m("any")) }, + { json: "name", js: "name", typ: u(undefined, "") }, + { json: "resultType", js: "resultType", typ: u(undefined, u(null, "")) }, + { json: "screenshots", js: "screenshots", typ: u(undefined, a(r("Image"))) }, + { json: "title", js: "title", typ: u(undefined, "") }, + { json: "tooltip", js: "tooltip", typ: u(undefined, "") }, + { json: "version", js: "version", typ: u(undefined, "") }, + ], false), + "Icon": o([ + { json: "size", js: "size", typ: u(undefined, "") }, + { json: "src", js: "src", typ: "" }, + { json: "type", js: "type", typ: u(undefined, "") }, + ], false), + "Image": o([ + { json: "label", js: "label", typ: u(undefined, "") }, + { json: "size", js: "size", typ: u(undefined, "") }, + { json: "src", js: "src", typ: "" }, + { json: "type", js: "type", typ: u(undefined, "") }, + ], false), + "FindInstancesBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("FindInstancesBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("MessagePayload") }, + { json: "type", js: "type", typ: r("FindInstancesAgentErrorResponseType") }, + ], false), + "FindInstancesBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "MessagePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "FindInstancesBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("FindInstancesBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("FindInstancesBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("FindInstancesAgentRequestType") }, + ], false), + "FindInstancesBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("DestinationObject")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSourceObject") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "MetaSourceObject": o([ + { json: "appId", js: "appId", typ: u(undefined, "") }, + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "FindInstancesBridgeRequestPayload": o([ + { json: "app", js: "app", typ: r("AppIdentifier") }, + ], false), + "FindInstancesBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("BridgeResponseMessageMeta") }, + { json: "payload", js: "payload", typ: r("FindInstancesBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("FindInstancesAgentErrorResponseType") }, + ], false), + "FindInstancesBridgeResponsePayload": o([ + { json: "appIdentifiers", js: "appIdentifiers", typ: a(r("AppMetadata")) }, + ], false), + "FindIntentAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentAgentErrorResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentAgentErrorResponseType") }, + ], false), + "FindIntentAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentAgentErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "FindIntentAgentRequest": o([ + { json: "meta", js: "meta", typ: r("FindIntentAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentAgentRequestPayload") }, + { json: "type", js: "type", typ: r("FindIntentAgentRequestType") }, + ], false), + "FindIntentAgentRequestMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceIdentifier")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + { json: "destination", js: "destination", typ: u(undefined, r("BridgeParticipantIdentifier")) }, + ], false), + "FindIntentAgentRequestPayload": o([ + { json: "context", js: "context", typ: u(undefined, r("Context")) }, + { json: "intent", js: "intent", typ: "" }, + { json: "resultType", js: "resultType", typ: u(undefined, "") }, + ], false), + "FindIntentAgentResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentAgentResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentAgentResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentAgentErrorResponseType") }, + ], false), + "FindIntentAgentResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentAgentResponsePayload": o([ + { json: "appIntent", js: "appIntent", typ: r("AppIntent") }, + ], false), + "AppIntent": o([ + { json: "apps", js: "apps", typ: a(r("AppMetadata")) }, + { json: "intent", js: "intent", typ: r("IntentMetadata") }, + ], false), + "IntentMetadata": o([ + { json: "displayName", js: "displayName", typ: u(undefined, "") }, + { json: "name", js: "name", typ: "" }, + ], false), + "FindIntentBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentBridgeErrorResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentAgentErrorResponseType") }, + ], false), + "FindIntentBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentBridgeErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "FindIntentBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("FindIntentBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("FindIntentAgentRequestType") }, + ], false), + "FindIntentBridgeRequestMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("BridgeParticipantIdentifier") }, + { json: "timestamp", js: "timestamp", typ: Date }, + { json: "destination", js: "destination", typ: u(undefined, r("BridgeParticipantIdentifier")) }, + ], false), + "FindIntentBridgeRequestPayload": o([ + { json: "context", js: "context", typ: u(undefined, r("Context")) }, + { json: "intent", js: "intent", typ: "" }, + { json: "resultType", js: "resultType", typ: u(undefined, "") }, + ], false), + "FindIntentBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentBridgeResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentAgentErrorResponseType") }, + ], false), + "FindIntentBridgeResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentBridgeResponsePayload": o([ + { json: "appIntent", js: "appIntent", typ: r("AppIntent") }, + ], false), + "FindIntentsByContextAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentsByContextAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentsByContextAgentErrorResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentsByContextAgentErrorResponseType") }, + ], false), + "FindIntentsByContextAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentsByContextAgentErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "FindIntentsByContextAgentRequest": o([ + { json: "meta", js: "meta", typ: r("FindIntentsByContextAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentsByContextAgentRequestPayload") }, + { json: "type", js: "type", typ: r("FindIntentsByContextAgentRequestType") }, + ], false), + "FindIntentsByContextAgentRequestMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + { json: "destination", js: "destination", typ: u(undefined, r("BridgeParticipantIdentifier")) }, + ], false), + "FindIntentsByContextAgentRequestPayload": o([ + { json: "context", js: "context", typ: r("Context") }, + { json: "resultType", js: "resultType", typ: u(undefined, "") }, + ], false), + "FindIntentsByContextAgentResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentsByContextAgentResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentsByContextAgentResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentsByContextAgentErrorResponseType") }, + ], false), + "FindIntentsByContextAgentResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentsByContextAgentResponsePayload": o([ + { json: "appIntents", js: "appIntents", typ: a(r("AppIntent")) }, + ], false), + "FindIntentsByContextBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentsByContextBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentsByContextBridgeErrorResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentsByContextAgentErrorResponseType") }, + ], false), + "FindIntentsByContextBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentsByContextBridgeErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "FindIntentsByContextBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("FindIntentsByContextBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentsByContextBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("FindIntentsByContextAgentRequestType") }, + ], false), + "FindIntentsByContextBridgeRequestMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + { json: "destination", js: "destination", typ: u(undefined, r("BridgeParticipantIdentifier")) }, + ], false), + "FindIntentsByContextBridgeRequestPayload": o([ + { json: "context", js: "context", typ: r("Context") }, + { json: "resultType", js: "resultType", typ: u(undefined, "") }, + ], false), + "FindIntentsByContextBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("FindIntentsByContextBridgeResponseMeta") }, + { json: "payload", js: "payload", typ: r("FindIntentsByContextBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("FindIntentsByContextAgentErrorResponseType") }, + ], false), + "FindIntentsByContextBridgeResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "FindIntentsByContextBridgeResponsePayload": o([ + { json: "appIntents", js: "appIntents", typ: a(r("AppIntent")) }, + ], false), + "GetAppMetadataAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("GetAppMetadataAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("GetAppMetadataAgentErrorResponsePayload") }, + { json: "type", js: "type", typ: r("GetAppMetadataAgentErrorResponseType") }, + ], false), + "GetAppMetadataAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "GetAppMetadataAgentErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "GetAppMetadataAgentRequest": o([ + { json: "meta", js: "meta", typ: r("GetAppMetadataAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("GetAppMetadataAgentRequestPayload") }, + { json: "type", js: "type", typ: r("GetAppMetadataAgentRequestType") }, + ], false), + "GetAppMetadataAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("DestinationObject")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceIdentifier")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "GetAppMetadataAgentRequestPayload": o([ + { json: "app", js: "app", typ: r("AppObject") }, + ], false), + "AppObject": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "appId", js: "appId", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "GetAppMetadataAgentResponse": o([ + { json: "meta", js: "meta", typ: r("GetAppMetadataAgentResponseMeta") }, + { json: "payload", js: "payload", typ: r("GetAppMetadataAgentResponsePayload") }, + { json: "type", js: "type", typ: r("GetAppMetadataAgentErrorResponseType") }, + ], false), + "GetAppMetadataAgentResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "GetAppMetadataAgentResponsePayload": o([ + { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, + ], false), + "GetAppMetadataBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("GetAppMetadataBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("GetAppMetadataBridgeErrorResponsePayload") }, + { json: "type", js: "type", typ: r("GetAppMetadataAgentErrorResponseType") }, + ], false), + "GetAppMetadataBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "GetAppMetadataBridgeErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "GetAppMetadataBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("GetAppMetadataBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("GetAppMetadataBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("GetAppMetadataAgentRequestType") }, + ], false), + "GetAppMetadataBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("DestinationObject")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSourceObject") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "GetAppMetadataBridgeRequestPayload": o([ + { json: "app", js: "app", typ: r("AppObject") }, + ], false), + "GetAppMetadataBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("GetAppMetadataBridgeResponseMeta") }, + { json: "payload", js: "payload", typ: r("GetAppMetadataBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("GetAppMetadataAgentErrorResponseType") }, + ], false), + "GetAppMetadataBridgeResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "GetAppMetadataBridgeResponsePayload": o([ + { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, + ], false), + "OpenAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("OpenAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("OpenAgentErrorResponsePayload") }, + { json: "type", js: "type", typ: r("OpenAgentErrorResponseType") }, + ], false), + "OpenAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "OpenAgentErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("OpenErrorResponsePayload") }, + ], false), + "OpenAgentRequest": o([ + { json: "meta", js: "meta", typ: r("OpenAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("OpenAgentRequestPayload") }, + { json: "type", js: "type", typ: r("OpenAgentRequestType") }, + ], false), + "OpenAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("DestinationObject")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("SourceObject") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "OpenAgentRequestPayload": o([ + { json: "app", js: "app", typ: r("AppToOpen") }, + { json: "context", js: "context", typ: u(undefined, r("Context")) }, + ], false), + "AppToOpen": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "appId", js: "appId", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "OpenAgentResponse": o([ + { json: "meta", js: "meta", typ: r("OpenAgentResponseMeta") }, + { json: "payload", js: "payload", typ: r("OpenAgentResponsePayload") }, + { json: "type", js: "type", typ: r("OpenAgentErrorResponseType") }, + ], false), + "OpenAgentResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "OpenAgentResponsePayload": o([ + { json: "appIdentifier", js: "appIdentifier", typ: r("AppIdentifier") }, + ], false), + "OpenBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("OpenBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("OpenBridgeErrorResponsePayload") }, + { json: "type", js: "type", typ: r("OpenAgentErrorResponseType") }, + ], false), + "OpenBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "OpenBridgeErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("OpenErrorResponsePayload") }, + ], false), + "OpenBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("OpenBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("OpenBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("OpenAgentRequestType") }, + ], false), + "OpenBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("DestinationObject")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "OpenBridgeRequestPayload": o([ + { json: "app", js: "app", typ: r("AppToOpen") }, + { json: "context", js: "context", typ: u(undefined, r("Context")) }, + ], false), + "OpenBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("OpenBridgeResponseMeta") }, + { json: "payload", js: "payload", typ: r("OpenBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("OpenAgentErrorResponseType") }, + ], false), + "OpenBridgeResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "OpenBridgeResponsePayload": o([ + { json: "appIdentifier", js: "appIdentifier", typ: r("AppIdentifier") }, + ], false), + "PrivateChannelBroadcastAgentRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelBroadcastAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelBroadcastAgentRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelBroadcastAgentRequestType") }, + ], false), + "PrivateChannelBroadcastAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "MetaDestination": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "appId", js: "appId", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "PrivateChannelBroadcastAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "context", js: "context", typ: r("Context") }, + ], false), + "PrivateChannelBroadcastBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelBroadcastBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelBroadcastBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelBroadcastAgentRequestType") }, + ], false), + "PrivateChannelBroadcastBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelBroadcastBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "context", js: "context", typ: r("Context") }, + ], false), + "PrivateChannelEventListenerAddedAgentRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelEventListenerAddedAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelEventListenerAddedAgentRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelEventListenerAddedAgentRequestType") }, + ], false), + "PrivateChannelEventListenerAddedAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelEventListenerAddedAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "listenerType", js: "listenerType", typ: r("PrivateChannelEventListenerTypes") }, + ], false), + "PrivateChannelEventListenerAddedBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelEventListenerAddedBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelEventListenerAddedBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelEventListenerAddedAgentRequestType") }, + ], false), + "PrivateChannelEventListenerAddedBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelEventListenerAddedBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "listenerType", js: "listenerType", typ: r("PrivateChannelEventListenerTypes") }, + ], false), + "PrivateChannelEventListenerRemovedAgentRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelEventListenerRemovedAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelEventListenerRemovedAgentRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelEventListenerRemovedAgentRequestType") }, + ], false), + "PrivateChannelEventListenerRemovedAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelEventListenerRemovedAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "listenerType", js: "listenerType", typ: r("PrivateChannelEventListenerTypes") }, + ], false), + "PrivateChannelEventListenerRemovedBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelEventListenerRemovedBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelEventListenerRemovedBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelEventListenerRemovedAgentRequestType") }, + ], false), + "PrivateChannelEventListenerRemovedBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelEventListenerRemovedBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "listenerType", js: "listenerType", typ: r("PrivateChannelEventListenerTypes") }, + ], false), + "PrivateChannelOnAddContextListenerAgentRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelOnAddContextListenerAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelOnAddContextListenerAgentRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelOnAddContextListenerAgentRequestType") }, + ], false), + "PrivateChannelOnAddContextListenerAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelOnAddContextListenerAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "contextType", js: "contextType", typ: u(null, "") }, + ], false), + "PrivateChannelOnAddContextListenerBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelOnAddContextListenerBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelOnAddContextListenerBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelOnAddContextListenerAgentRequestType") }, + ], false), + "PrivateChannelOnAddContextListenerBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelOnAddContextListenerBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "contextType", js: "contextType", typ: u(null, "") }, + ], false), + "PrivateChannelOnDisconnectAgentRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelOnDisconnectAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelOnDisconnectAgentRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelOnDisconnectAgentRequestType") }, + ], false), + "PrivateChannelOnDisconnectAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelOnDisconnectAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + ], false), + "PrivateChannelOnDisconnectBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelOnDisconnectBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelOnDisconnectBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelOnDisconnectAgentRequestType") }, + ], false), + "PrivateChannelOnDisconnectBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelOnDisconnectBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + ], false), + "PrivateChannelOnUnsubscribeAgentRequest": o([ + { json: "meta", js: "meta", typ: r("PrivateChannelOnUnsubscribeAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("PrivateChannelOnUnsubscribeAgentRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelOnUnsubscribeAgentRequestType") }, + ], false), + "PrivateChannelOnUnsubscribeAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: u(undefined, r("SourceObject")) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelOnUnsubscribeAgentRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "contextType", js: "contextType", typ: u(null, "") }, + ], false), + "PrivateChannelOnUnsubscribeBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("ERequestMetadata") }, + { json: "payload", js: "payload", typ: r("PrivateChannelOnUnsubscribeBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("PrivateChannelOnUnsubscribeAgentRequestType") }, + ], false), + "ERequestMetadata": o([ + { json: "destination", js: "destination", typ: u(undefined, r("MetaDestination")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "PrivateChannelOnUnsubscribeBridgeRequestPayload": o([ + { json: "channelId", js: "channelId", typ: "" }, + { json: "contextType", js: "contextType", typ: u(null, "") }, + ], false), + "RaiseIntentAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentAgentErrorResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentAgentErrorResponseType") }, + ], false), + "RaiseIntentAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentAgentErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "RaiseIntentAgentRequest": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentAgentRequestMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentAgentRequestPayload") }, + { json: "type", js: "type", typ: r("RaiseIntentAgentRequestType") }, + ], false), + "RaiseIntentAgentRequestMeta": o([ + { json: "destination", js: "destination", typ: r("MetaDestination") }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("SourceObject") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentAgentRequestPayload": o([ + { json: "app", js: "app", typ: r("AppDestinationIdentifier") }, + { json: "context", js: "context", typ: r("Context") }, + { json: "intent", js: "intent", typ: "" }, + ], false), + "AppDestinationIdentifier": o([ + { json: "desktopAgent", js: "desktopAgent", typ: "" }, + { json: "appId", js: "appId", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + ], "any"), + "RaiseIntentAgentResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentAgentResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentAgentResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentAgentErrorResponseType") }, + ], false), + "RaiseIntentAgentResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentAgentResponsePayload": o([ + { json: "intentResolution", js: "intentResolution", typ: r("IntentResolution") }, + ], false), + "IntentResolution": o([ + { json: "intent", js: "intent", typ: "" }, + { json: "source", js: "source", typ: r("AppIdentifier") }, + ], false), + "RaiseIntentBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentBridgeErrorResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentAgentErrorResponseType") }, + ], false), + "RaiseIntentBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentBridgeErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("FindInstancesErrors") }, + ], false), + "RaiseIntentBridgeRequest": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentBridgeRequestMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentBridgeRequestPayload") }, + { json: "type", js: "type", typ: r("RaiseIntentAgentRequestType") }, + ], false), + "RaiseIntentBridgeRequestMeta": o([ + { json: "destination", js: "destination", typ: r("MetaDestination") }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "source", js: "source", typ: r("MetaSource") }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentBridgeRequestPayload": o([ + { json: "app", js: "app", typ: r("AppDestinationIdentifier") }, + { json: "context", js: "context", typ: r("Context") }, + { json: "intent", js: "intent", typ: "" }, + ], false), + "RaiseIntentBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentBridgeResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentAgentErrorResponseType") }, + ], false), + "RaiseIntentBridgeResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentBridgeResponsePayload": o([ + { json: "intentResolution", js: "intentResolution", typ: r("IntentResolution") }, + ], false), + "RaiseIntentResultAgentErrorResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentResultAgentErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentResultAgentErrorResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentResultAgentErrorResponseType") }, + ], false), + "RaiseIntentResultAgentErrorResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentResultAgentErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("RaiseIntentResultErrorMessage") }, + ], false), + "RaiseIntentResultAgentResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentResultAgentResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentResultAgentResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentResultAgentErrorResponseType") }, + ], false), + "RaiseIntentResultAgentResponseMeta": o([ + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentResultAgentResponsePayload": o([ + { json: "intentResult", js: "intentResult", typ: r("IntentResult") }, + ], false), + "IntentResult": o([ + { json: "context", js: "context", typ: u(undefined, r("Context")) }, + { json: "channel", js: "channel", typ: u(undefined, r("Channel")) }, + ], false), + "Channel": o([ + { json: "displayMetadata", js: "displayMetadata", typ: u(undefined, r("DisplayMetadata")) }, + { json: "id", js: "id", typ: "" }, + { json: "type", js: "type", typ: r("Type") }, + ], false), + "DisplayMetadata": o([ + { json: "color", js: "color", typ: u(undefined, "") }, + { json: "glyph", js: "glyph", typ: u(undefined, "") }, + { json: "name", js: "name", typ: u(undefined, "") }, + ], false), + "RaiseIntentResultBridgeErrorResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentResultBridgeErrorResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentResultBridgeErrorResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentResultAgentErrorResponseType") }, + ], false), + "RaiseIntentResultBridgeErrorResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: a(r("ResponseErrorDetail")) }, + { json: "errorSources", js: "errorSources", typ: a(r("DesktopAgentIdentifier")) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentResultBridgeErrorResponsePayload": o([ + { json: "error", js: "error", typ: r("RaiseIntentResultErrorMessage") }, + ], false), + "RaiseIntentResultBridgeResponse": o([ + { json: "meta", js: "meta", typ: r("RaiseIntentResultBridgeResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentResultBridgeResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentResultAgentErrorResponseType") }, + ], false), + "RaiseIntentResultBridgeResponseMeta": o([ + { json: "errorDetails", js: "errorDetails", typ: u(undefined, a(r("ResponseErrorDetail"))) }, + { json: "errorSources", js: "errorSources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "requestUuid", js: "requestUuid", typ: "" }, + { json: "responseUuid", js: "responseUuid", typ: "" }, + { json: "sources", js: "sources", typ: u(undefined, a(r("DesktopAgentIdentifier"))) }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "RaiseIntentResultBridgeResponsePayload": o([ + { json: "intentResult", js: "intentResult", typ: r("IntentResult") }, + ], false), + "ResponseErrorDetail": [ + "AccessDenied", + "AgentDisconnected", + "AppNotFound", + "AppTimeout", + "CreationFailed", + "DesktopAgentNotFound", + "ErrorOnLaunch", + "IntentDeliveryFailed", + "IntentHandlerRejected", + "MalformedContext", + "MalformedMessage", + "NoAppsFound", + "NoChannelFound", + "NoResultReturned", + "NotConnectedToBridge", + "ResolverTimeout", + "ResolverUnavailable", + "ResponseToBridgeTimedOut", + "TargetAppUnavailable", + "TargetInstanceUnavailable", + "UserCancelledResolution", + ], + "ResponseMessageType": [ + "findInstancesResponse", + "findIntentResponse", + "findIntentsByContextResponse", + "getAppMetadataResponse", + "openResponse", + "raiseIntentResponse", + "raiseIntentResultResponse", + ], + "RequestMessageType": [ + "broadcastRequest", + "findInstancesRequest", + "findIntentRequest", + "findIntentsByContextRequest", + "getAppMetadataRequest", + "openRequest", + "PrivateChannel.broadcast", + "PrivateChannel.eventListenerAdded", + "PrivateChannel.eventListenerRemoved", + "PrivateChannel.onAddContextListener", + "PrivateChannel.onDisconnect", + "PrivateChannel.onUnsubscribe", + "raiseIntentRequest", + ], + "BroadcastAgentRequestType": [ + "broadcastRequest", + ], + "ConnectionStepMessageType": [ + "authenticationFailed", + "connectedAgentsUpdate", + "handshake", + "hello", + ], + "ConnectionStep2HelloType": [ + "hello", + ], + "ConnectionStep3HandshakeType": [ + "handshake", + ], + "ConnectionStep4AuthenticationFailedType": [ + "authenticationFailed", + ], + "ConnectionStep6ConnectedAgentsUpdateType": [ + "connectedAgentsUpdate", + ], + "FindInstancesErrors": [ + "AgentDisconnected", + "DesktopAgentNotFound", + "IntentDeliveryFailed", + "MalformedContext", + "MalformedMessage", + "NoAppsFound", + "NotConnectedToBridge", + "ResolverTimeout", + "ResolverUnavailable", + "ResponseToBridgeTimedOut", + "TargetAppUnavailable", + "TargetInstanceUnavailable", + "UserCancelledResolution", + ], + "FindInstancesAgentErrorResponseType": [ + "findInstancesResponse", + ], + "FindInstancesAgentRequestType": [ + "findInstancesRequest", + ], + "FindIntentAgentErrorResponseType": [ + "findIntentResponse", + ], + "FindIntentAgentRequestType": [ + "findIntentRequest", + ], + "FindIntentsByContextAgentErrorResponseType": [ + "findIntentsByContextResponse", + ], + "FindIntentsByContextAgentRequestType": [ + "findIntentsByContextRequest", + ], + "GetAppMetadataAgentErrorResponseType": [ + "getAppMetadataResponse", + ], + "GetAppMetadataAgentRequestType": [ + "getAppMetadataRequest", + ], + "OpenErrorResponsePayload": [ + "AgentDisconnected", + "AppNotFound", + "AppTimeout", + "DesktopAgentNotFound", + "ErrorOnLaunch", + "MalformedContext", + "MalformedMessage", + "NotConnectedToBridge", + "ResolverUnavailable", + "ResponseToBridgeTimedOut", + ], + "OpenAgentErrorResponseType": [ + "openResponse", + ], + "OpenAgentRequestType": [ + "openRequest", + ], + "PrivateChannelBroadcastAgentRequestType": [ + "PrivateChannel.broadcast", + ], + "PrivateChannelEventListenerTypes": [ + "onAddContextListener", + "onDisconnect", + "onUnsubscribe", + ], + "PrivateChannelEventListenerAddedAgentRequestType": [ + "PrivateChannel.eventListenerAdded", + ], + "PrivateChannelEventListenerRemovedAgentRequestType": [ + "PrivateChannel.eventListenerRemoved", + ], + "PrivateChannelOnAddContextListenerAgentRequestType": [ + "PrivateChannel.onAddContextListener", + ], + "PrivateChannelOnDisconnectAgentRequestType": [ + "PrivateChannel.onDisconnect", + ], + "PrivateChannelOnUnsubscribeAgentRequestType": [ + "PrivateChannel.onUnsubscribe", + ], + "RaiseIntentAgentErrorResponseType": [ + "raiseIntentResponse", + ], + "RaiseIntentAgentRequestType": [ + "raiseIntentRequest", + ], + "RaiseIntentResultErrorMessage": [ + "AgentDisconnected", + "IntentHandlerRejected", + "MalformedMessage", + "NoResultReturned", + "NotConnectedToBridge", + "ResponseToBridgeTimedOut", + ], + "RaiseIntentResultAgentErrorResponseType": [ + "raiseIntentResultResponse", + ], + "Type": [ + "app", + "private", + "user", + ], +}; diff --git a/packages/fdc3-schema/schemas/api/api.schema.json b/packages/fdc3-schema/schemas/api/api.schema.json index c395d308a..7f1fcf0ad 100644 --- a/packages/fdc3-schema/schemas/api/api.schema.json +++ b/packages/fdc3-schema/schemas/api/api.schema.json @@ -30,7 +30,7 @@ ] }, "Icon": { - "description": "Describes an Icon images that may be used to represent the application.", + "description": "Describes an Icon image that may be used to represent the application.", "title": "Icon", "type": "object", "properties": { diff --git a/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json b/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json index 29fa74150..9b4fb181f 100644 --- a/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json +++ b/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://fdc3.finos.org/schemas/next/api/fdc3UserInterfaceHandshake.schema.json", "title": "Fdc3 UserInterface Handshake", - "description": "Handshake message sent back to a user interface from the DA proxy code (setup by `getAgent()`) over the `MessagePort` provided in the preceding Fdc3UserInterfaceHello message, confirming that it is listening to the `MessagePort` for further communication.", + "description": "Handshake message sent back to a user interface from the DA proxy code (setup by `getAgent()`) over the `MessagePort` provide in the preceding iFrameHello message, confirming that it is listening to the `MessagePort` for further communication.", "type": "object", "allOf": [ { diff --git a/packages/fdc3-schema/schemas/api/getInfoRequest.schema.json b/packages/fdc3-schema/schemas/api/getInfoRequest.schema.json index e4f662762..c8158cf6f 100644 --- a/packages/fdc3-schema/schemas/api/getInfoRequest.schema.json +++ b/packages/fdc3-schema/schemas/api/getInfoRequest.schema.json @@ -3,7 +3,7 @@ "$id": "https://fdc3.finos.org/schemas/next/api/getInfoRequest.schema.json", "type": "object", "title": "GetInfo Request", - "description": "Request to retrieve information about the FDC3 Desktop Agent implementation and the metadata of the calling application according to the Desktop Agent.", + "description": "Request to retrieve information about the FDC3 Desktop Agent implementation and the metadata of the calling application according to the Desktop Agent.", "allOf": [ { "$ref": "appRequest.schema.json" diff --git a/packages/fdc3-schema/schemas/api/t2sQuicktypeUtil.js b/packages/fdc3-schema/schemas/api/t2sQuicktypeUtil.js new file mode 100644 index 000000000..54816c0e0 --- /dev/null +++ b/packages/fdc3-schema/schemas/api/t2sQuicktypeUtil.js @@ -0,0 +1,69 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright FINOS FDC3 contributors - see NOTICE file + */ + +/** Utility for preparing arguments to quicktype, which workaround a specific + * quicktype bug in command line argument handling (where a directory is used + * as input the source language argument is ignored which causes our schemas + * to be interpreted as JSON input, rather than JSONSchema). + * Bug issue: + * */ + +const path = require('path'); +const fs = require('fs'); +const exec = require('child_process').exec; + +const args = process.argv.slice(2); +const outputPath = args.pop(); +const inputs = args; + +console.log('Inputs: ' + inputs.join(' | ')); +console.log('Output path argument: ' + outputPath); + +let source = ''; + +let dirIndex = 0; + +const excludedTypes = [ + 'DesktopAgent.ts', + 'Listener.ts', + 'Methods.ts', + 'PrivateChannel.ts', + 'Types.ts', + 'RecommendedChannels.ts', +]; + +let sources = ''; + +while (dirIndex < inputs.length) { + if (inputs[dirIndex].endsWith('.ts')) { + sources += `--src ${path.join(inputs[dirIndex])} `; + } else { + fs.readdirSync(inputs[dirIndex], { withFileTypes: true }).forEach(file => { + if (file.isDirectory()) { + inputs.push(path.join(inputs[dirIndex], file.name)); + } else { + if (!excludedTypes.includes(file.name)) { + sources += `--src ${path.join(inputs[dirIndex], file.name)} `; + } + } + }); + } + dirIndex++; +} + +// Normalise path to local quicktype executable. +const quicktypeExec = ['.', 'node_modules', '.bin', 'quicktype'].join(path.sep); + +const command = `${quicktypeExec} -l schema -o ${outputPath} ${sources}`; +console.log('command to run: ' + command); + +exec(command, function(error, stdout, stderr) { + if (stdout) { + console.log(stdout); + } + if (stderr) { + console.log(stderr); + } +}); diff --git a/packages/fdc3-schema/schemas/bridging/common.schema.json b/packages/fdc3-schema/schemas/bridging/common.schema.json index 3420ff166..86846c717 100644 --- a/packages/fdc3-schema/schemas/bridging/common.schema.json +++ b/packages/fdc3-schema/schemas/bridging/common.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://fdc3.finos.org/schemas/next/api/common.schema.json", + "$id": "https://fdc3.finos.org/schemas/next/bridging/common.schema.json", "title": "Bridge Common definitions", "type": "object", "description": "Common definitions that are referenced only in the Bridging wire protocol schemas", @@ -82,7 +82,7 @@ "title": "Response Error Details", "type": "array", "items": { - "$ref": "#/$defs/ErrorMessages" + "$ref": "../api/common.schema.json#/$defs/ErrorMessages" }, "description": "Array of error message strings for responses that were not returned to the bridge before the timeout or because an error occurred. Should be the same length as the `errorSources` array and ordered the same. May be omitted if all sources responded without errors." }, diff --git a/packages/fdc3-standard/src/api/GetAgent.ts b/packages/fdc3-standard/src/api/GetAgent.ts index fd87d8c99..fdf09b357 100644 --- a/packages/fdc3-standard/src/api/GetAgent.ts +++ b/packages/fdc3-standard/src/api/GetAgent.ts @@ -103,11 +103,11 @@ export type DesktopAgentDetails = { /** The URL that was previously sent to the Desktop Agent * to establish the app's identity.*/ - identityUrl?: string; + identityUrl: string; /** The current URL at the time of the last connection to * a Desktop Agent.*/ - actualUrl?: string; + actualUrl: string; /** Optional URL field that should be used to store any * URL that was used to connect to a Desktop Agent. URLs @@ -159,3 +159,5 @@ export enum WebDesktopAgentType { * function that was passed by the application. */ Failover = 'FAILOVER', } + +export const DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX = 'fdc3-desktop-agent-details'; diff --git a/packages/fdc3-standard/src/ui/Connectable.ts b/packages/fdc3-standard/src/ui/Connectable.ts index 3459e7028..3fcea6b18 100644 --- a/packages/fdc3-standard/src/ui/Connectable.ts +++ b/packages/fdc3-standard/src/ui/Connectable.ts @@ -1,3 +1,5 @@ + +//TODO: move this out of fdc3-standard into another package - its an implementation detail of GetAgent export interface Connectable { connect(): Promise diff --git a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts index 951dc4f41..f92b45a99 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts @@ -1,5 +1,5 @@ import { IframeChannelsPayload, Channel } from "@kite9/fdc3-common"; -import { FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE, FDC3_USER_INTERFACE_CHANNELS_TYPE, FDC3_USER_INTERFACE_HANDSHAKE_TYPE, FDC3_USER_INTERFACE_HELLO_TYPE, FDC3_USER_INTERFACE_RESTYLE_TYPE, Fdc3UserInterfaceHello, Fdc3UserInterfaceRestyle, isFdc3UserInterfaceChannels, isFdc3UserInterfaceHandshake } from "@kite9/fdc3-schema/dist/generated/api/BrowserTypes"; +import { FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE, FDC3_USER_INTERFACE_CHANNELS_TYPE, FDC3_USER_INTERFACE_HANDSHAKE_TYPE, FDC3_USER_INTERFACE_HELLO_TYPE, FDC3_USER_INTERFACE_RESTYLE_TYPE, Fdc3UserInterfaceHello, Fdc3UserInterfaceRestyle } from "@kite9/fdc3-schema/dist/generated/api/BrowserTypes"; const fillChannels = (data: Channel[], selected: string | null, messageClickedChannel: (s: string | null) => void) => { const list = document.getElementById('list')!!; From 26147914b5c317bd2c601db8eec3be059dc2f733 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 19 Nov 2024 23:20:16 +0000 Subject: [PATCH 03/90] Better encapsulate handshake and identity messaging and reuse in failover handling --- .../fdc3-agent-proxy/src/BasicDesktopAgent.ts | 3 +- .../src/messaging/AbstractWebMessaging.ts | 112 +++++------ .../strategies/DesktopAgentPreloadLoader.ts | 11 +- .../src/strategies/FailoverHandler.ts | 187 ++++++++++-------- .../src/strategies/HelloHandler.ts | 31 +-- .../strategies/IdentityValidationHandler.ts | 8 +- .../src/strategies/PostMessageLoader.ts | 6 +- .../fdc3-get-agent/src/strategies/getAgent.ts | 11 +- 8 files changed, 198 insertions(+), 171 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts index caad91ea0..6d20ff2b6 100644 --- a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts +++ b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts @@ -38,7 +38,8 @@ export class BasicDesktopAgent implements DesktopAgent, Connectable { let impl = await this.handshake.getImplementationMetadata(); //handle potential null during start-up //TODO: introduce queuing to prevent early calls - if (!impl) { + if (!impl) { + console.error("Implementation data was not available"); impl = { fdc3Version: "unknown", provider: "unknown", diff --git a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts index 37ecf511a..1a0c93a8f 100644 --- a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts @@ -44,10 +44,6 @@ export abstract class AbstractWebMessaging extends AbstractMessaging { return super.getSource(); } - waitFor(filter: (m: any) => boolean, timeoutErrorMessage?: string): Promise { - return super.waitFor(filter, timeoutErrorMessage); - } - private async exchangeValidationWithId(message: any, connectionAttemptUuid: string): Promise { const prom = super.waitFor( (m: WebConnectionProtocolMessage | AgentResponseMessage) => { @@ -84,9 +80,9 @@ export abstract class AbstractWebMessaging extends AbstractMessaging { super.setImplementationMetadata(validationResponse.payload.implementationMetadata); - //TODO: need to do something with the instanceUuid... + // //TODO: need to do something with the instanceUuid... - this.storeMyDesktopAgentDetails(validationResponse, /* need to set agent Type and agentUrl if any */) + // this.storeMyDesktopAgentDetails(validationResponse, /* need to set agent Type and agentUrl if any */) } async disconnect(): Promise { @@ -94,59 +90,59 @@ export abstract class AbstractWebMessaging extends AbstractMessaging { super.setImplementationMetadata(null); } - /** - * Sends the validate message through the message port - */ - private createValidationMessage(): WebConnectionProtocol4ValidateAppIdentity { - const requestMessage: WebConnectionProtocol4ValidateAppIdentity = { - type: 'WCP4ValidateAppIdentity', - meta: { - connectionAttemptUuid: this.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - identityUrl: this.options.identityUrl ?? this.actualUrl, - actualUrl: this.actualUrl - } - }; - const persistedDetails = this.retrieveMyDesktopAgentDetails(); + // /** + // * Sends the validate message through the message port + // */ + // private createValidationMessage(): WebConnectionProtocol4ValidateAppIdentity { + // const requestMessage: WebConnectionProtocol4ValidateAppIdentity = { + // type: 'WCP4ValidateAppIdentity', + // meta: { + // connectionAttemptUuid: this.connectionAttemptUuid, + // timestamp: new Date(), + // }, + // payload: { + // identityUrl: this.options.identityUrl ?? this.actualUrl, + // actualUrl: this.actualUrl + // } + // }; + // const persistedDetails = this.retrieveMyDesktopAgentDetails(); - if (persistedDetails) { - requestMessage.payload.instanceId = persistedDetails.instanceId; - requestMessage.payload.instanceUuid = persistedDetails.instanceUuid; - } - - return requestMessage; - } - - /** Used to persist data on the connection, which can later be used to ensure - * reconnection to the same Desktop Agent and to request the same instanceId. - */ - storeMyDesktopAgentDetails( - validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse, - agentType: WebDesktopAgentType, - agentUrl?: string - ) { - //create the details object to persist - const details: DesktopAgentDetails = { - agentType, - identityUrl: this.options.identityUrl!, - actualUrl: this.actualUrl!, - agentUrl: agentUrl ?? undefined, - appId: validationResponse.payload.appId, - instanceUuid: validationResponse.payload.instanceUuid, - instanceId: validationResponse.payload.instanceId, - }; + // if (persistedDetails) { + // requestMessage.payload.instanceId = persistedDetails.instanceId; + // requestMessage.payload.instanceUuid = persistedDetails.instanceUuid; + // } + + // return requestMessage; + // } + + // /** Used to persist data on the connection, which can later be used to ensure + // * reconnection to the same Desktop Agent and to request the same instanceId. + // */ + // storeMyDesktopAgentDetails( + // validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse, + // agentType: WebDesktopAgentType, + // agentUrl?: string + // ) { + // //create the details object to persist + // const details: DesktopAgentDetails = { + // agentType, + // identityUrl: this.options.identityUrl!, + // actualUrl: this.actualUrl!, + // agentUrl: agentUrl ?? undefined, + // appId: validationResponse.payload.appId, + // instanceUuid: validationResponse.payload.instanceUuid, + // instanceId: validationResponse.payload.instanceId, + // }; - storeDesktopAgentDetails(details); - } - - /** Retrieves persisted data about previous connections for this specific app - * (identified by the identityUrl). Used to ensure reconnection to the same - * agent and to request the same instanceId. - */ - retrieveMyDesktopAgentDetails(): DesktopAgentDetails | null { - return retrieveDesktopAgentDetails(this.options.identityUrl!); - } + // storeDesktopAgentDetails(details); + // } + + // /** Retrieves persisted data about previous connections for this specific app + // * (identified by the identityUrl). Used to ensure reconnection to the same + // * agent and to request the same instanceId. + // */ + // retrieveMyDesktopAgentDetails(): DesktopAgentDetails | null { + // return retrieveDesktopAgentDetails(this.options.identityUrl!); + // } } diff --git a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts index 6e05f7dee..e9ab6c87e 100644 --- a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts @@ -26,10 +26,15 @@ export class DesktopAgentPreloadLoader implements Loader { identityUrl: globalThis.window.location.href, actualUrl: globalThis.window.location.href, appId: implMetadata.appMetadata.appId, - instanceId: implMetadata.appMetadata.instanceId, - instanceUuid: implMetadata.appMetadata.instanceId // preload DAs don't issue these so repeat the instanceId - } + instanceId: implMetadata.appMetadata.instanceId ?? "unknown", + instanceUuid: implMetadata.appMetadata.instanceId ?? "unknown" // TODO: preload DAs don't issue these so repeat the instanceId + } }; + + if (selection.details.instanceId === "unknown"){ + console.warn("The DesktopAgent did not return an instanceId in the app's metadata", implMetadata); + } + resolve(selection); } else if ((timeRemaining > 0) && (this.done == false)) { setTimeout(() => this.poll(endTime, resolve, reject), 100); diff --git a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts index d7ac48940..e647e6d82 100644 --- a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts @@ -1,104 +1,123 @@ -import { WebConnectionProtocol3Handshake } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { GetAgentParams, DesktopAgent, WebDesktopAgentType, AgentError } from '@kite9/fdc3-standard'; import { createDesktopAgentAPI } from '../messaging/message-port'; import { DesktopAgentSelection } from './Loader'; +import { v4 as uuidv4 } from 'uuid'; +import { HelloHandler } from './HelloHandler'; +import { IdentityValidationHandler } from './IdentityValidationHandler'; -/** - * This is a variation of the PostMessageLoader used for handling failover. - * If the failover returns a WindowProxy this is used to create a Desktop - * Agent Proxy. If a DesktopAgent is returned directly it is passed through. - * - */ -export async function handleFailover( - options: GetAgentParams, - failover: (args: GetAgentParams) => Promise -): Promise { - return new Promise((resolve, reject) => { - //may be used to validate that handshake messages received came from - // the WindowProxy produced by the failover function - let proxyResult: Window | null = null; +/** TypeGuard for a Desktop Agent */ +function isDesktopAgent(da: WindowProxy | DesktopAgent): da is DesktopAgent { + return (da as DesktopAgent).getInfo !== undefined; +} - //listen for handshake messages from frames created by a failover function - const el = (event: MessageEvent) => { - const data = event.data; - if (data?.type == 'WCP3Handshake') { - if (event.source != proxyResult) { - console.warn('Received a Handshake message from invalid source during failover'); - //TODO: decide whether to ignore handshake messages from any source other than providerResult - } +/** TypeGuard for a Window */ +function isWindow(da: Window | DesktopAgent): da is Window { + return (da as Window).postMessage !== undefined; +} - const handshake = data as WebConnectionProtocol3Handshake; - //clean up the listener on the window - globalThis.window.removeEventListener('message', el); +export class FailoverHandler { + constructor(options: GetAgentParams) { + this.options = options; + this.connectionAttemptUuid = uuidv4(); // we use a different connectionAttemptUuid to differnetiate from any (failed) messaging to a parent window + this.helloHandler = new HelloHandler(this.options, this.connectionAttemptUuid, WebDesktopAgentType.Failover); + } - const connectionDetails = { - connectionAttemptUuid: handshake.meta.connectionAttemptUuid, - handshake: data, - messagePort: event.ports[0], - options: options, - actualUrl: globalThis.window.location.href, - agentType: WebDesktopAgentType.Failover, - }; - createDesktopAgentAPI(connectionDetails).then((da: DesktopAgent) => { - const desktopAgentSelection: DesktopAgentSelection = { - agent: da, - details: { - agentType: WebDesktopAgentType.Failover, - identityUrl: options.identityUrl ?? connectionDetails.actualUrl, - actualUrl: connectionDetails.actualUrl, - //instanceId, appId etc. added after identityValidation exchange - }, - }; - resolve(desktopAgentSelection); - }); - } else { - console.debug(`Ignoring message unexpected message in FailoverHandler (because its not WCP3Handshake).`, data); - } - }; + /** Parameters passed to getAgent */ + options: GetAgentParams; + + /** UUID used to filter messages */ + connectionAttemptUuid: string; + + /** Handler class for hello/handshake messages */ + helloHandler: HelloHandler; + + /** Handler class for identity validation steps used for Desktop Agent Proxies */ + identityValidationHandler?: IdentityValidationHandler; + + /** + * This is a variation of the PostMessageLoader used for handling failover. + * If the failover returns a WindowProxy this is used to create a Desktop + * Agent Proxy. If a DesktopAgent is returned directly it is passed through. + * + */ + async handleFailover(): Promise { + try { + //set-up a event listeners in case the failover returns a Window that wants to message us + const handshakePromise = this.helloHandler.listenForHelloResponses(); - globalThis.window.addEventListener('message', el); + //Run the failover function + if (typeof this.options.failover === 'function') { + const failoverResult = await this.options.failover(this.options); - if (typeof failover === 'function') { - failover(options).then(failoverResult => { //if the result was a Desktop Agent if (isDesktopAgent(failoverResult)) { - //clean up the listener on the window - globalThis.window.removeEventListener('message', el); + this.cancel(); //retrieve appId and instanceId from the DA - failoverResult.getInfo().then(implMetadata => { - const desktopAgentSelection: DesktopAgentSelection = { - agent: failoverResult, - details: { - agentType: WebDesktopAgentType.Failover, - identityUrl: globalThis.window.location.href, - actualUrl: globalThis.window.location.href, - appId: implMetadata.appMetadata.appId, - instanceId: implMetadata.appMetadata.instanceId, - instanceUuid: implMetadata.appMetadata.instanceId, // preload DAs don't issue these so repeat the instanceId - } - }; - resolve(desktopAgentSelection); - }); + const implMetadata = await failoverResult.getInfo(); + const desktopAgentSelection: DesktopAgentSelection = { + agent: failoverResult, + details: { + agentType: WebDesktopAgentType.Failover, + identityUrl: globalThis.window.location.href, + actualUrl: globalThis.window.location.href, + appId: implMetadata.appMetadata.appId, + instanceId: implMetadata.appMetadata.instanceId ?? "unknown", + instanceUuid: implMetadata.appMetadata.instanceId ?? "unknown", // preload DAs don't issue these so repeat the instanceId + }, + }; + return desktopAgentSelection; + } else if (isWindow(failoverResult)) { - // is a WindowProxy - //save WindowProxy for validating incoming messages later - proxyResult = failoverResult; + //if the result was a Window/WindowProxy + //send a hello message + this.helloHandler.sendWCP1Hello(failoverResult, '*'); } else { console.error('Failover function returned an invalid result', failoverResult); - reject(AgentError.InvalidFailover); + throw new Error(AgentError.InvalidFailover); } - }); - } else { - reject(AgentError.InvalidFailover); + } else { + throw new Error(AgentError.InvalidFailover); + } + + //if we received a WindowProxy from failover, and it sent us a handshake, try to validate its identity + const connectionDetails = await handshakePromise; + try { + this.identityValidationHandler = new IdentityValidationHandler(connectionDetails.messagePort, this.options, this.connectionAttemptUuid) + const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + this.identityValidationHandler.sendIdValidationMessage() + const idDetails = await idValidationPromise; + const desktopAgentSelection: DesktopAgentSelection = { + agent: await createDesktopAgentAPI(connectionDetails), + details: { + agentType: connectionDetails.agentType, + agentUrl: connectionDetails.agentUrl ?? undefined, + identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, + actualUrl: connectionDetails.actualUrl, + appId: idDetails.payload.appId, + instanceId: idDetails.payload.instanceId, + instanceUuid: idDetails.payload.instanceUuid + }, + }; + + return desktopAgentSelection; + } catch (e) { + //identity validation may have failed + throw e; + } } - }); -} + finally { + //cleanup any remaining listeners + this.cancel(); + } + } -function isDesktopAgent(da: WindowProxy | DesktopAgent): da is DesktopAgent { - return (da as DesktopAgent).getInfo !== undefined; -} + /** Removes listeners so that events are no longer processed */ + cancel() { + this.helloHandler.cancel(); + if (this.identityValidationHandler){ + this.identityValidationHandler.cancel(); + } + } -function isWindow(da: Window | DesktopAgent): da is Window { - return (da as Window).postMessage !== undefined; -} +} \ No newline at end of file diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index ad7a0e2dd..0396b000f 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -9,9 +9,10 @@ import { ConnectionDetails } from '../messaging/MessagePortMessaging'; import { FDC3_VERSION } from './getAgent'; export class HelloHandler { - constructor(options: GetAgentParams, connectionAttemptUuid: string) { + constructor(options: GetAgentParams, connectionAttemptUuid: string, agentType: WebDesktopAgentType = WebDesktopAgentType.ProxyParent) { this.options = options; this.connectionAttemptUuid = connectionAttemptUuid; + this.agentType = agentType; this.helloResponseListener = null; } @@ -21,6 +22,12 @@ export class HelloHandler { /** UUID used to filter messages */ connectionAttemptUuid: string; + /** The agentType to set, which may change if we're asked to load a URL into an iframe */ + agentType: WebDesktopAgentType; + + /** If we're asked to load a URL into an iframe, it is stored here to be saved in Session Storage */ + agentUrl: string | null = null; + /** Reference to event listener used for responses from Desktop Agents - * Used to remove them when no longer needed. * Initialized when @@ -52,8 +59,8 @@ export class HelloHandler { } /** - * The desktop agent requests that the client opens a URL in order to provide a - * message port. + * Handle a request from a desktop agent that the client loads an adaptor URL + * into an iframe instead of working with the parent window. */ openFrame(url: string) { const IFRAME_ID = 'fdc3-communications-embedded-iframe'; @@ -87,9 +94,6 @@ export class HelloHandler { /** Listen for WCP responses from 'parent' windows and frames and handle them */ listenForHelloResponses(): Promise { - let agentType = WebDesktopAgentType.ProxyParent; - let agentUrl: string | null = null; - return new Promise((resolve, _reject) => { // setup listener for message and retrieve JS URL from it this.helloResponseListener = (event: MessageEvent) => { @@ -101,8 +105,8 @@ export class HelloHandler { this.openFrame(url); //note the iframe URL and desktop agent type have changed - agentType = WebDesktopAgentType.ProxyUrl; - agentUrl = url; + this.agentType = WebDesktopAgentType.ProxyUrl; + this.agentUrl = url; //n.b event listener remains in place to receive messages from the iframe } else if (isWebConnectionProtocol3Handshake(data)) { @@ -112,18 +116,15 @@ export class HelloHandler { messagePort: event.ports[0], options: this.options, actualUrl: globalThis.window.location.href, - agentType: agentType, - agentUrl: agentUrl ?? undefined, + agentType: this.agentType, + agentUrl: this.agentUrl ?? undefined, }); //remove the event listener as we've received a messagePort to use - if (this.helloResponseListener != null) { - globalThis.window.removeEventListener('message', this.helloResponseListener); - this.helloResponseListener = null; - } + this.cancel(); } else { console.debug( - `Ignoring message unexpected message in PostMessageLoader (because its not WCP2LoadUrl or WCP3Handshake).`, + `Ignoring message unexpected message in HelloHandler (because its not WCP2LoadUrl or WCP3Handshake).`, data ); } diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts index 9dc487afb..80a4c6f86 100644 --- a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -111,7 +111,7 @@ export class IdentityValidationHandler { data ); } - + } else { console.debug( `Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, @@ -124,4 +124,10 @@ export class IdentityValidationHandler { this.messagePort.addEventListener('message', this.idValidationResponseListener); }); } + + cancel(): void { + if (this.idValidationResponseListener) { + this.messagePort.removeEventListener('message', this.idValidationResponseListener); + } + } } diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index ccd301805..124fcdd86 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -1,11 +1,7 @@ -import { AgentError, GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; +import { GetAgentParams } from '@kite9/fdc3-standard'; import { createDesktopAgentAPI } from '../messaging/message-port'; import { v4 as uuidv4 } from 'uuid'; -import { ConnectionDetails } from '../messaging/MessagePortMessaging'; import { DesktopAgentSelection, Loader } from './Loader'; -import { FDC3_VERSION } from './getAgent'; -import { retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; -import { isWebConnectionProtocol2LoadURL, isWebConnectionProtocol3Handshake, isWebConnectionProtocol5ValidateAppIdentityFailedResponse, isWebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol1Hello, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocolMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { HelloHandler } from './HelloHandler'; import { IdentityValidationHandler } from './IdentityValidationHandler'; diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 1dce1c364..1a3dcae69 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -3,7 +3,7 @@ import { DesktopAgentPreloadLoader } from './DesktopAgentPreloadLoader' import { PostMessageLoader } from './PostMessageLoader' import { TimeoutLoader } from './TimeoutLoader' import { storeDesktopAgentDetails, retrieveAllDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; -import { handleFailover } from './FailoverHandler'; +import { FailoverHandler } from './FailoverHandler'; const DEFAULT_WAIT_FOR_MS = 750; @@ -59,8 +59,12 @@ function initAgentPromise(options: GetAgentParams): Promise { .catch(async (error) => { if (options.failover != undefined) { try { - //TODO: ensure a timeout is also applied to the failover, to avoid getting stuck here - const selection = await handleFailover(options, options.failover); + //TODO: consider adding a timeout for the failover, to avoid getting stuck here + // However there is an argument to be made for hanging out in case the + // function eventually returns, e.g. after an external DA started up + + const failoverHandler = new FailoverHandler(options); + const selection = await failoverHandler.handleFailover(); //store details of the connection in SessionStorage const desktopAgentDetails: DesktopAgentDetails = { @@ -74,7 +78,6 @@ function initAgentPromise(options: GetAgentParams): Promise { }; storeDesktopAgentDetails(desktopAgentDetails); - return selection.agent; } catch (e) { console.error("Desktop agent not found. Error reported during failover", e); From 9fa5f1e2d5fd19e46332f20cc339360a2d375316 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 20 Nov 2024 00:52:24 +0000 Subject: [PATCH 04/90] Adding timeouts to loaders and eliminating TimeoutLoader Individual timeouts allow for steps that our outside the timeout (identity validation) --- .../strategies/DesktopAgentPreloadLoader.ts | 104 +++++++++------ .../fdc3-get-agent/src/strategies/Loader.ts | 10 +- .../src/strategies/PostMessageLoader.ts | 120 ++++++++++-------- .../src/strategies/TimeoutLoader.ts | 37 ------ .../fdc3-get-agent/src/strategies/getAgent.ts | 120 ++++++++++-------- packages/fdc3-standard/src/api/GetAgent.ts | 4 +- 6 files changed, 211 insertions(+), 184 deletions(-) delete mode 100644 packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts diff --git a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts index e9ab6c87e..8a800542c 100644 --- a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts @@ -1,58 +1,88 @@ -import { DesktopAgent, WebDesktopAgentType } from "@kite9/fdc3-standard"; +import { AgentError, DEFAULT_TIMEOUT_MS, DesktopAgent, WebDesktopAgentType } from "@kite9/fdc3-standard"; import { GetAgentParams } from "@kite9/fdc3-standard"; import { DesktopAgentSelection, Loader } from "./Loader"; /** * This approach will resolve the loader promise if the fdc3Ready event occurs. - * This is done by electron implementations setting window.fdc3. + * This is done by Desktop Agent Preload implementations setting window.fdc3. */ export class DesktopAgentPreloadLoader implements Loader { + + /** Variable used to end polling */ + done: boolean = false; + /** Reference to the handler for the fdc3Ready event (used to remove it) */ + readyEventHandler: (() => void) | null = null; + /** Overall timeout */ + timeout: NodeJS.Timeout | null = null; - //TODO: listen for the fdc3Ready event. Polling should be a fallback not the default strategy + async poll(resolve: (value: DesktopAgentSelection) => void) { + if (globalThis.window.fdc3) { + this.prepareSelection(globalThis.window.fdc3, resolve); + } else { + if (!this.done) { + setTimeout(() => this.poll(resolve), 100); + } + } + } - done = false + async prepareSelection(fdc3: DesktopAgent, resolve: (value: DesktopAgentSelection) => void) { + //stop polling and listening for fdc3Ready + this.cancel(); - async poll(endTime: number, resolve: (value: DesktopAgentSelection | void) => void, reject: (reason?: any) => void) { - const timeRemaining = endTime - Date.now() - if (globalThis.window.fdc3 != null) { + //retrieve appId from DA + const implMetadata = await fdc3.getInfo(); + const selection: DesktopAgentSelection = { + agent: fdc3, + details: { + agentType: WebDesktopAgentType.Preload, + identityUrl: globalThis.window.location.href, + actualUrl: globalThis.window.location.href, + appId: implMetadata.appMetadata.appId, + instanceId: implMetadata.appMetadata.instanceId ?? "unknown", + instanceUuid: implMetadata.appMetadata.instanceId ?? "unknown" // preload DAs don't issue these so repeat the instanceId + } + }; - //retrieve appId from DA - const implMetadata = await globalThis.window.fdc3.getInfo(); + if (selection.details.instanceId === "unknown"){ + console.warn("The DesktopAgent did not return an instanceId in the app's metadata", implMetadata); + } + + resolve(selection); + } - const selection: DesktopAgentSelection = { - agent: globalThis.window.fdc3, - details: { - agentType: WebDesktopAgentType.Preload, - identityUrl: globalThis.window.location.href, - actualUrl: globalThis.window.location.href, - appId: implMetadata.appMetadata.appId, - instanceId: implMetadata.appMetadata.instanceId ?? "unknown", - instanceUuid: implMetadata.appMetadata.instanceId ?? "unknown" // TODO: preload DAs don't issue these so repeat the instanceId - } - }; + get(options: GetAgentParams): Promise { + return new Promise((resolve, reject) => { + //do an initial check + if (globalThis.window.fdc3) { + this.prepareSelection(globalThis.window.fdc3, resolve); + } else { + //setup a timeout so that we can reject if don't find anything + this.timeout = setTimeout(() => { + reject(new Error(AgentError.AgentNotFound)); + }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); + + //listen for the fdc3Ready event + this.readyEventHandler = () => { + if (globalThis.window.fdc3) { + this.prepareSelection(globalThis.window.fdc3, resolve); + } + }; + globalThis.window.addEventListener('fdc3Ready',this.readyEventHandler); - if (selection.details.instanceId === "unknown"){ - console.warn("The DesktopAgent did not return an instanceId in the app's metadata", implMetadata); + //also do polling (just in case) + this.poll(resolve); } - - resolve(selection); - } else if ((timeRemaining > 0) && (this.done == false)) { - setTimeout(() => this.poll(endTime, resolve, reject), 100); - } else { - resolve(); - } + }); } cancel(): void { this.done = true; - } - - async get(params: GetAgentParams): Promise { - return new Promise((resolve, reject) => { - const endPollTime = Date.now() + (params.timeoutMs! + 500) - // console.log("Starting poll: " + endPollTime + " " + params.timeout + " " + Date.now()) - this.poll(endPollTime, resolve, reject) - }); + if (this.timeout) { + clearTimeout(this.timeout); + } + if (this.readyEventHandler) { + globalThis.window.removeEventListener('fdc3Ready', this.readyEventHandler); + } } } diff --git a/packages/fdc3-get-agent/src/strategies/Loader.ts b/packages/fdc3-get-agent/src/strategies/Loader.ts index 05f1d5288..135955190 100644 --- a/packages/fdc3-get-agent/src/strategies/Loader.ts +++ b/packages/fdc3-get-agent/src/strategies/Loader.ts @@ -6,9 +6,9 @@ import { GetAgentParams } from '@kite9/fdc3-standard'; */ export interface Loader { /** - * Promise will either resolve to a DesktopAgent or _resolve_ to an error (not reject) + * Promise will either resolve to a DesktopAgent or reject with an error */ - get(options: GetAgentParams): Promise; + get(options: GetAgentParams): Promise; cancel(): void; } @@ -24,8 +24,8 @@ export interface DesktopAgentSelection { identityUrl: string; actualUrl: string; agentUrl?: string; - appId?: string; - instanceId?: string; - instanceUuid?: string; + appId: string; + instanceId: string; + instanceUuid: string; }; } diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 124fcdd86..02a82337e 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -1,4 +1,4 @@ -import { GetAgentParams } from '@kite9/fdc3-standard'; +import { AgentError, DEFAULT_TIMEOUT_MS, GetAgentParams } from '@kite9/fdc3-standard'; import { createDesktopAgentAPI } from '../messaging/message-port'; import { v4 as uuidv4 } from 'uuid'; import { DesktopAgentSelection, Loader } from './Loader'; @@ -31,65 +31,83 @@ function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[] } } - //TODO incorporate a timeout here to replace TimeoutLoader - // - would allow timeout to be stopped when message port is received as id validation should be outside of timeout - // although a separate timeout should be used there to avoid stalling if the DA doesn't respond export class PostMessageLoader implements Loader { connectionAttemptUuid = uuidv4(); helloHandler?: HelloHandler; identityValidationHandler?: IdentityValidationHandler; - - async get(options: GetAgentParams): Promise { - const targets: Window[] = []; - collectPossibleTargets(globalThis.window, targets); - - this.helloHandler = new HelloHandler(options, this.connectionAttemptUuid); - - // ok, begin the process - const handshakePromise = this.helloHandler.listenForHelloResponses(); - - // use of origin '*': See https://github.com/finos/FDC3/issues/1316 - for (let t = 0; t < targets.length; t++) { - this.helloHandler.sendWCP1Hello(targets[t], '*'); - } - - // wait for one of the windows to respond - // This may involve a WCP2LoadUrl response being received - // and an adaptor iframe setup to load it, resolves on - // WCP3Handshake response. - // If no WCP3Handshake is ever received this will not resolve - const connectionDetails = await handshakePromise; - - //perform id validation - this.identityValidationHandler = new IdentityValidationHandler(connectionDetails.messagePort, options, this.connectionAttemptUuid) - const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); - this.identityValidationHandler.sendIdValidationMessage(); - - try { - const idDetails = await idValidationPromise; - const desktopAgentSelection: DesktopAgentSelection = { - agent: await createDesktopAgentAPI(connectionDetails), - details: { - agentType: connectionDetails.agentType, - agentUrl: connectionDetails.agentUrl ?? undefined, - identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, - actualUrl: connectionDetails.actualUrl, - appId: idDetails.payload.appId, - instanceId: idDetails.payload.instanceId, - instanceUuid: idDetails.payload.instanceUuid - }, - }; - - return desktopAgentSelection; - } catch (e) { - //id validation may have failed - throw e; - } + /** Initial timeout (released once a MessagePort is received - additional steps are outside timeout) */ + timeout: NodeJS.Timeout | null = null; + + get(options: GetAgentParams): Promise { + return new Promise(async (resolve, reject) => { + + //setup a timeout so we can reject if it runs out + this.timeout = setTimeout(() => { + this.cancel(); + reject(new Error(AgentError.AgentNotFound)); + }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); + + const targets: Window[] = []; + collectPossibleTargets(globalThis.window, targets); + + this.helloHandler = new HelloHandler(options, this.connectionAttemptUuid); + + // ok, begin the process + const handshakePromise = this.helloHandler.listenForHelloResponses(); + + // use of origin '*': See https://github.com/finos/FDC3/issues/1316 + for (let t = 0; t < targets.length; t++) { + this.helloHandler.sendWCP1Hello(targets[t], '*'); + } + + // wait for one of the windows to respond + // This may involve a WCP2LoadUrl response being received + // and an adaptor iframe setup to load it, resolves on + // WCP3Handshake response. + // If no WCP3Handshake is ever received this will not resolve + const connectionDetails = await handshakePromise; + + //cancel the initial timeout as we got a handshake response + if (this.timeout) { + clearTimeout(this.timeout); + } + + //perform id validation + this.identityValidationHandler = new IdentityValidationHandler(connectionDetails.messagePort, options, this.connectionAttemptUuid) + const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + this.identityValidationHandler.sendIdValidationMessage(); + + try { + const idDetails = await idValidationPromise; + const desktopAgentSelection: DesktopAgentSelection = { + agent: await createDesktopAgentAPI(connectionDetails), + details: { + agentType: connectionDetails.agentType, + agentUrl: connectionDetails.agentUrl ?? undefined, + identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, + actualUrl: connectionDetails.actualUrl, + appId: idDetails.payload.appId, + instanceId: idDetails.payload.instanceId, + instanceUuid: idDetails.payload.instanceUuid + }, + }; + + resolve(desktopAgentSelection); + } catch (e) { + //id validation may have failed + reject(e); + } + }); } cancel(): void { + //cancel the timeout + if (this.timeout) { + clearTimeout(this.timeout); + } + //remove any event listeners to end processing if (this.helloHandler) { this.helloHandler.cancel(); diff --git a/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts b/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts deleted file mode 100644 index 7cc91549a..000000000 --- a/packages/fdc3-get-agent/src/strategies/TimeoutLoader.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { AgentError, DesktopAgent, GetAgentParams } from "@kite9/fdc3-standard"; -import { DesktopAgentSelection, Loader } from "./Loader"; - - - -/** - * This loader handles timing out. - */ -export class TimeoutLoader implements Loader { - - done = false; - - //TODO: replace polling with an actual timeout - - poll(endTime: number, resolve: (value: DesktopAgentSelection | void) => void, reject: (reason?: any) => void) { - const timeRemaining = endTime - Date.now() - - if ((timeRemaining > 0) && (this.done == false)) { - setTimeout(() => this.poll(endTime, resolve, reject), 100); - } else if (this.done == false) { - reject(new Error(AgentError.AgentNotFound)); - } else { - resolve(); - } - } - - cancel(): void { - this.done = true; - } - - get(params: GetAgentParams): Promise { - return new Promise((resolve, reject) => { - const endPollTime = Date.now() + params.timeoutMs!!; - this.poll(endPollTime, resolve, reject); - }); - } -} diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 1a3dcae69..2968f5b9e 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -1,14 +1,19 @@ -import { DesktopAgent, GetAgentType, GetAgentParams, AgentError, DesktopAgentDetails, WebDesktopAgentType } from '@kite9/fdc3-standard' -import { DesktopAgentPreloadLoader } from './DesktopAgentPreloadLoader' -import { PostMessageLoader } from './PostMessageLoader' -import { TimeoutLoader } from './TimeoutLoader' -import { storeDesktopAgentDetails, retrieveAllDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; +import { DesktopAgent, GetAgentType, GetAgentParams, AgentError, DesktopAgentDetails, WebDesktopAgentType, DEFAULT_TIMEOUT_MS } from '@kite9/fdc3-standard'; +import { DesktopAgentPreloadLoader } from './DesktopAgentPreloadLoader'; +import { PostMessageLoader } from './PostMessageLoader'; +import { storeDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; import { FailoverHandler } from './FailoverHandler'; -const DEFAULT_WAIT_FOR_MS = 750; - export const FDC3_VERSION = "2.2" +// TypeGuards used to examine results of Loaders +const isRejected = (input: PromiseSettledResult): input is PromiseRejectedResult => + input.status === 'rejected' + +const isFulfilled = (input: PromiseSettledResult): input is PromiseFulfilledResult => + input.status === 'fulfilled' + + /** * For now, we only allow a single call to getAgent per application, so * we keep track of the promise we use here. @@ -27,19 +32,21 @@ function initAgentPromise(options: GetAgentParams): Promise { const DEFAULT_STRATEGIES = [ new DesktopAgentPreloadLoader(), - new PostMessageLoader(), - new TimeoutLoader() - ] + new PostMessageLoader() + ]; + + //TODO: retrieve persisted data and only use a previous strategy if one exists const promises = DEFAULT_STRATEGIES.map(s => s.get(options)); - - return Promise.race(promises) - .then(selection => { - // first, cancel the timeout etc. - DEFAULT_STRATEGIES.forEach(s => s.cancel()) - // either the timeout completes first with an error, or one of the other strategies completes with a DesktopAgent. - if (selection) { + + return Promise.allSettled(promises) + .then(async results => { + //review results + const daResult = results.find(isFulfilled); + + if (daResult) { + const selection = daResult.value; const desktopAgentDetails: DesktopAgentDetails = { agentType: selection.details.agentType, identityUrl: selection.details.identityUrl, @@ -53,40 +60,46 @@ function initAgentPromise(options: GetAgentParams): Promise { return selection.agent; } else { - throw new Error(AgentError.AgentNotFound) - } - }) - .catch(async (error) => { - if (options.failover != undefined) { - try { - //TODO: consider adding a timeout for the failover, to avoid getting stuck here - // However there is an argument to be made for hanging out in case the - // function eventually returns, e.g. after an external DA started up - - const failoverHandler = new FailoverHandler(options); - const selection = await failoverHandler.handleFailover(); - - //store details of the connection in SessionStorage - const desktopAgentDetails: DesktopAgentDetails = { - agentType: WebDesktopAgentType.Failover, - identityUrl: selection.details.identityUrl, - actualUrl: selection.details.actualUrl, - agentUrl: selection.details.agentUrl ?? undefined, - appId: selection.details.appId, - instanceId: selection.details.instanceId, - instanceUuid: selection.details.instanceUuid - }; - storeDesktopAgentDetails(desktopAgentDetails); - - return selection.agent; - } catch (e) { - console.error("Desktop agent not found. Error reported during failover", e); - throw e; + //if we received any error other than AgentError.AgentNotFound, throw it + const errors = results.filter(isRejected); + const error = errors.find((aRejection) => { + aRejection.reason?.message !== AgentError.AgentNotFound; + }); + if (error){ + throw error; + + } else if (options.failover != undefined) { + //Proceed with the failover + try { + //TODO: consider adding a timeout for the failover, to avoid getting stuck here + // However there is an argument to be made for hanging out in case the + // function eventually returns, e.g. after an external DA started up + + const failoverHandler = new FailoverHandler(options); + const selection = await failoverHandler.handleFailover(); + + //store details of the connection in SessionStorage + const desktopAgentDetails: DesktopAgentDetails = { + agentType: WebDesktopAgentType.Failover, + identityUrl: selection.details.identityUrl, + actualUrl: selection.details.actualUrl, + agentUrl: selection.details.agentUrl ?? undefined, + appId: selection.details.appId, + instanceId: selection.details.instanceId, + instanceUuid: selection.details.instanceUuid + }; + storeDesktopAgentDetails(desktopAgentDetails); + + return selection.agent; + } catch (e) { + console.error("Desktop agent not found. Error reported during failover", e); + throw e; + } + } else { + //We didn't manage to find an agent. Suppress any actual error and throw a value from AgentError + console.log("Desktop agent not found. Error reported during discovery", error); + throw new Error(AgentError.AgentNotFound); } - } else { - //We didn't manage to find an agent. Suppress any actual error and throw a value from AgentError - console.log("Desktop agent not found. Error reported during discovery", error); - throw new Error(AgentError.AgentNotFound); } }); } @@ -129,7 +142,7 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { dontSetWindowFdc3: true, channelSelector: true, intentResolver: true, - timeoutMs: DEFAULT_WAIT_FOR_MS, + timeoutMs: DEFAULT_TIMEOUT_MS, identityUrl: globalThis.window.location.href }; @@ -154,12 +167,13 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { } /** - * Replaces the original fdc3Ready function from FDC3 2.0 with a new one that uses the new getAgent function. + * Replaces the original fdc3Ready function from FDC3 2.0 with a new one that uses the + * new getAgent function. * * @param waitForMs Amount of time to wait before failing the promise (20 seconds is the default). * @returns A DesktopAgent promise. */ -export function fdc3Ready(waitForMs = DEFAULT_WAIT_FOR_MS): Promise { +export function fdc3Ready(waitForMs = DEFAULT_TIMEOUT_MS): Promise { return getAgent({ timeoutMs: waitForMs, dontSetWindowFdc3: false, diff --git a/packages/fdc3-standard/src/api/GetAgent.ts b/packages/fdc3-standard/src/api/GetAgent.ts index fdf09b357..92d9ef1c1 100644 --- a/packages/fdc3-standard/src/api/GetAgent.ts +++ b/packages/fdc3-standard/src/api/GetAgent.ts @@ -44,7 +44,7 @@ export type GetAgentType = (params?: GetAgentParams) => Promise; * * @property {number} timeoutMs Number of milliseconds to allow for an FDC3 * implementation to be found before calling the failover function or - * rejecting (default 750). Note that the timeout is cancelled as soon as a + * rejecting (default 1000). Note that the timeout is cancelled as soon as a * Desktop Agent is detected. There may be additional set-up steps to perform * which will happen outside the timeout. * @@ -161,3 +161,5 @@ export enum WebDesktopAgentType { } export const DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX = 'fdc3-desktop-agent-details'; + +export const DEFAULT_TIMEOUT_MS = 1000; From ae5ef1e5b2492a3965612e58f4aff5155f0706b8 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 20 Nov 2024 01:56:51 +0000 Subject: [PATCH 05/90] Limit connection strategies based on persisted data --- .../fdc3-get-agent/src/strategies/getAgent.ts | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 2968f5b9e..359f8ce76 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -1,8 +1,9 @@ import { DesktopAgent, GetAgentType, GetAgentParams, AgentError, DesktopAgentDetails, WebDesktopAgentType, DEFAULT_TIMEOUT_MS } from '@kite9/fdc3-standard'; import { DesktopAgentPreloadLoader } from './DesktopAgentPreloadLoader'; import { PostMessageLoader } from './PostMessageLoader'; -import { storeDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; +import { retrieveDesktopAgentDetails, storeDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; import { FailoverHandler } from './FailoverHandler'; +import { Loader } from './Loader'; export const FDC3_VERSION = "2.2" @@ -30,15 +31,37 @@ export function getAgentPromise(): Promise | null { function initAgentPromise(options: GetAgentParams): Promise { - const DEFAULT_STRATEGIES = [ - new DesktopAgentPreloadLoader(), - new PostMessageLoader() - ]; - - + let strategies: Loader[]; + + //Retrieve persisted connection data limit to a previous strategy if one exists + const persistedData = retrieveDesktopAgentDetails(options.identityUrl ?? globalThis.window.location.href); + if (persistedData) { + switch (persistedData.agentType) { + case WebDesktopAgentType.Preload: + strategies = [new DesktopAgentPreloadLoader()]; + break; + case WebDesktopAgentType.ProxyParent: + case WebDesktopAgentType.ProxyUrl: + //TODO: make use of persisted agentUrl + strategies = [new PostMessageLoader()]; + break; + case WebDesktopAgentType.Failover: + strategies = []; + break; + default: + strategies = [ + new DesktopAgentPreloadLoader(), + new PostMessageLoader() + ]; + } + } else { + strategies = [ + new DesktopAgentPreloadLoader(), + new PostMessageLoader() + ]; + } - //TODO: retrieve persisted data and only use a previous strategy if one exists - const promises = DEFAULT_STRATEGIES.map(s => s.get(options)); + const promises = strategies.map(s => s.get(options)); return Promise.allSettled(promises) .then(async results => { From f8a27611937a66fa6a205f90d67c10b0d5db71e8 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 20 Nov 2024 13:40:55 +0000 Subject: [PATCH 06/90] use a previously persisted agentUrl in PostMessageLoader if available --- .../src/strategies/PostMessageLoader.ts | 34 +++++++++++++++---- .../fdc3-get-agent/src/strategies/getAgent.ts | 8 +++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 02a82337e..b3df2b7b1 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -31,7 +31,19 @@ function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[] } } +/** Loader for Desktop Agent Proxy implementations. Attempts to + * connect to parent windows or frames via teh Web Connection Protocol, + * which may include setting up an iframe to load an adaptor URL. + * A previously persisted adaptor URL may be passed to skip the + * discovery of parent windows and to move straight to loading that. + */ export class PostMessageLoader implements Loader { + + constructor(previousUrl?: string) { + this.previousUrl = previousUrl ?? null; + } + + previousUrl: string | null; connectionAttemptUuid = uuidv4(); helloHandler?: HelloHandler; @@ -49,17 +61,27 @@ export class PostMessageLoader implements Loader { reject(new Error(AgentError.AgentNotFound)); }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); - const targets: Window[] = []; - collectPossibleTargets(globalThis.window, targets); - + this.helloHandler = new HelloHandler(options, this.connectionAttemptUuid); // ok, begin the process const handshakePromise = this.helloHandler.listenForHelloResponses(); - // use of origin '*': See https://github.com/finos/FDC3/issues/1316 - for (let t = 0; t < targets.length; t++) { - this.helloHandler.sendWCP1Hello(targets[t], '*'); + if (this.previousUrl) { + console.debug(`Loading previously used adaptor URL: ${this.previousUrl}`); + + //skip looking for target parent windows and open an iframe immediately + this.helloHandler.openFrame(this.previousUrl); + + } else { + //collect target parent window references + const targets: Window[] = []; + collectPossibleTargets(globalThis.window, targets); + + // use of origin '*': See https://github.com/finos/FDC3/issues/1316 + for (let t = 0; t < targets.length; t++) { + this.helloHandler.sendWCP1Hello(targets[t], '*'); + } } // wait for one of the windows to respond diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 359f8ce76..04f63dfe8 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -40,9 +40,11 @@ function initAgentPromise(options: GetAgentParams): Promise { case WebDesktopAgentType.Preload: strategies = [new DesktopAgentPreloadLoader()]; break; - case WebDesktopAgentType.ProxyParent: case WebDesktopAgentType.ProxyUrl: - //TODO: make use of persisted agentUrl + //agentUrl will only be used by PostMessageLoader if not falsey + strategies = [new PostMessageLoader(persistedData.agentUrl)]; + break; + case WebDesktopAgentType.ProxyParent: strategies = [new PostMessageLoader()]; break; case WebDesktopAgentType.Failover: @@ -119,7 +121,7 @@ function initAgentPromise(options: GetAgentParams): Promise { throw e; } } else { - //We didn't manage to find an agent. Suppress any actual error and throw a value from AgentError + //We didn't manage to find an agent. console.log("Desktop agent not found. Error reported during discovery", error); throw new Error(AgentError.AgentNotFound); } From c8e9dff8a67a5a2ffee07e574b070b1bfca15670 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 20 Nov 2024 16:46:22 +0000 Subject: [PATCH 07/90] typing on waitFor and exchange + some cleanup in AbstractWebMessaging (which needs further work) --- .../src/messaging/AbstractMessaging.ts | 4 +-- .../src/messaging/AbstractWebMessaging.ts | 27 ++----------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index 8da054ce9..32603c9cf 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -29,7 +29,7 @@ export abstract class AbstractMessaging implements Messaging { } waitFor( - filter: (m: WebConnectionProtocolMessage | AgentResponseMessage) => boolean, + filter: (m: AgentResponseMessage) => boolean, timeoutErrorMessage?: string ): Promise { const id = this.createUUID(); @@ -59,7 +59,7 @@ export abstract class AbstractMessaging implements Messaging { }); } - async exchange(message: any, expectedTypeName: string, timeoutErrorMessage?: string): Promise { + async exchange(message: AppRequestMessage, expectedTypeName: string, timeoutErrorMessage?: string): Promise { const errorMessage = timeoutErrorMessage ?? `Timeout waiting for ${expectedTypeName} with requestUuid ${message.meta.requestUuid}`; const prom = this.waitFor((m) => { diff --git a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts index 1a0c93a8f..4fd336754 100644 --- a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts @@ -1,14 +1,12 @@ -import { DesktopAgentDetails, WebDesktopAgentType, GetAgentParams, AppIdentifier, DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX } from '@kite9/fdc3-standard'; +import { GetAgentParams, AppIdentifier } from '@kite9/fdc3-standard'; import { RegisterableListener, AbstractMessaging } from '@kite9/fdc3-agent-proxy'; import { AppRequestMessage, WebConnectionProtocolMessage, AgentResponseMessage, - WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, isWebConnectionProtocolMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -import { storeDesktopAgentDetails, retrieveAllDesktopAgentDetails, retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; /** @@ -17,16 +15,14 @@ import { storeDesktopAgentDetails, retrieveAllDesktopAgentDetails, retrieveDeskt export abstract class AbstractWebMessaging extends AbstractMessaging { private readonly options: GetAgentParams; private readonly connectionAttemptUuid: string; - private readonly actualUrl: string; - constructor(options: GetAgentParams, connectionAttemptUuid: string, actualUrl: string) { + constructor(options: GetAgentParams, connectionAttemptUuid: string) { super(); if (!options.timeoutMs) { options.timeoutMs = 10016; } this.options = options; this.connectionAttemptUuid = connectionAttemptUuid; - this.actualUrl = actualUrl; } abstract post(message: object): Promise; @@ -44,25 +40,6 @@ export abstract class AbstractWebMessaging extends AbstractMessaging { return super.getSource(); } - private async exchangeValidationWithId(message: any, connectionAttemptUuid: string): Promise { - const prom = super.waitFor( - (m: WebConnectionProtocolMessage | AgentResponseMessage) => { - if (isWebConnectionProtocolMessage(m)) { - return m.meta.connectionAttemptUuid == connectionAttemptUuid; - } else { - return false; - } - } - ); - this.post(message); - const out: any = await prom; - if (out?.payload?.message) { - throw new Error(out.payload.message); - } else { - return out; - } - } - /** * This handles the verify exchange with the da-server, */ From 4aaa9419fd8420d3ae9173b943c7a29fdb31935e Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 22 Nov 2024 14:36:37 +0000 Subject: [PATCH 08/90] Further cleanup of Messaging and Listeners, additional typing ImplementationMetadata is now passed into AbstractMessaging's constructor and getting close to eliminating AbstractWebMessaging. Correcting typing and generics on a number of functions (replacing any and unqualified generics) --- packages/fdc3-agent-proxy/src/Messaging.ts | 25 ++- .../src/channels/DefaultPrivateChannel.ts | 172 ++++++++++-------- .../src/listeners/AbstractListener.ts | 125 +++++++------ .../src/listeners/DefaultContextListener.ts | 93 +++++----- .../src/listeners/DefaultIntentListener.ts | 36 ++-- .../src/listeners/EventListener.ts | 5 +- .../listeners/PrivateChannelEventListener.ts | 116 +++++++----- .../src/messaging/AbstractMessaging.ts | 37 ++-- .../src/messaging/AbstractWebMessaging.ts | 91 +-------- .../src/messaging/MessagePortMessaging.ts | 26 +-- 10 files changed, 343 insertions(+), 383 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index 500653631..dc133c5e0 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -2,18 +2,13 @@ import { Connectable, AppIdentifier, ImplementationMetadata } from '@kite9/fdc3- import { RegisterableListener } from './listeners/RegisterableListener'; import { AppRequestMessage, - AgentResponseMessage, - WebConnectionProtocolMessage + AgentResponseMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export interface Messaging extends Connectable { - /** - * Source information to apply to outgoing messages - */ - getSource(): AppIdentifier | null; /** - * UUID for outgoing message + * Creates UUIDs used in outgoing messages */ createUUID(): string; @@ -28,18 +23,19 @@ export interface Messaging extends Connectable { register(l: RegisterableListener): void; /** - * Unregisters a listener with the id given above + * Unregister a listener with the given id * @param id */ unregister(id: string): void; + /** Create a metadata element to attach to outgoing messages. */ createMeta(): AppRequestMessage['meta']; /** * Waits for a specific matching message */ - waitFor( - filter: (m: WebConnectionProtocolMessage | AgentResponseMessage) => boolean, + waitFor( + filter: (m: AgentResponseMessage) => boolean, timeoutErrorMessage?: string ): Promise; @@ -47,15 +43,16 @@ export interface Messaging extends Connectable { * * @param message Performs a request / response message pass */ - exchange(message: object, expectedTypeName: string, timeoutErrorMessage?: string): Promise; + exchange(message: object, expectedTypeName: string, timeoutErrorMessage?: string): Promise; /** * Implementation metadata retrieved through the validation process */ - getImplementationMetadata(): Promise; + getImplementationMetadata(): ImplementationMetadata; /** - * App identification retrieved through the validation process + * App identification used to provide source information used in + * message meta elements, IntentResolution etc.. */ - getAppIdentifier(): Promise; + getAppIdentifier(): AppIdentifier; } diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts index 7260842b5..df1f01a3a 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts @@ -1,89 +1,109 @@ -import { ApiEvent, ContextHandler, EventHandler, Listener, PrivateChannel, PrivateChannelEventTypes } from "@kite9/fdc3-standard"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { DefaultChannel } from "./DefaultChannel"; -import { Messaging } from "../Messaging"; -import { PrivateChannelEventListenerType, PrivateChannelEventListenerVoid } from "../listeners/PrivateChannelEventListener"; -import { DefaultContextListener } from "../listeners/DefaultContextListener"; +import { + ApiEvent, + ContextHandler, + EventHandler, + Listener, + PrivateChannel, + PrivateChannelEventTypes, +} from '@kite9/fdc3-standard'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +import { DefaultChannel } from './DefaultChannel'; +import { Messaging } from '../Messaging'; +import { + PrivateChannelAddContextEventListener, + PrivateChannelDisconnectEventListener, + PrivateChannelUnsubscribeEventListener, +} from '../listeners/PrivateChannelEventListener'; +import { DefaultContextListener } from '../listeners/DefaultContextListener'; +import { RegisterableListener } from '../listeners/RegisterableListener'; -type PrivateChannelDisconnectRequest = BrowserTypes.PrivateChannelDisconnectRequest -type PrivateChannelDisconnectResponse = BrowserTypes.PrivateChannelDisconnectResponse +type PrivateChannelDisconnectRequest = BrowserTypes.PrivateChannelDisconnectRequest; +type PrivateChannelDisconnectResponse = BrowserTypes.PrivateChannelDisconnectResponse; export class DefaultPrivateChannel extends DefaultChannel implements PrivateChannel { + constructor(messaging: Messaging, id: string) { + super(messaging, id, 'private'); + } - constructor(messaging: Messaging, id: string) { - super(messaging, id, "private") + async addEventListener(type: PrivateChannelEventTypes | null, handler: EventHandler): Promise { + function wrapEventHandlerString(): (m: string | null) => void { + return (m: string | null) => { + handler({ + type, + details: m, + } as ApiEvent); + }; } - async addEventListener(type: PrivateChannelEventTypes | null, handler: EventHandler): Promise { - - function wrapEventHandlerString(): (m: string) => void { - return (m: string) => { - handler({ - type, - details: m - } as ApiEvent) - } - } - - function wrapEventHandlerVoid(): () => void { - return () => { - handler({ - type - } as ApiEvent) - } - } - - if (type) { - switch (type) { - case "addContextListener": - const a = new PrivateChannelEventListenerType(this.messaging, this.id, "onAddContextListener", wrapEventHandlerString()); - await a.register() - return a; - case "unsubscribe": - const u = new PrivateChannelEventListenerType(this.messaging, this.id, "onUnsubscribe", wrapEventHandlerString()); - await u.register() - return u; - case "disconnect": - const d = new PrivateChannelEventListenerVoid(this.messaging, this.id, wrapEventHandlerVoid()); - await d.register() - return d; - } - } - - throw new Error("Unsupported event type: " + type) + function wrapEventHandlerVoid(): () => void { + return () => { + handler({ + type, + } as ApiEvent); + }; } - onAddContextListener(handler: (contextType?: string | undefined) => void): Listener { - const l = new PrivateChannelEventListenerType(this.messaging, this.id, "onAddContextListener", handler); - l.register() - return l; + if (type) { + let a: RegisterableListener; + switch (type) { + case 'addContextListener': + a = new PrivateChannelAddContextEventListener(this.messaging, this.id, wrapEventHandlerString()); + break; + case 'unsubscribe': + a = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, wrapEventHandlerString()); + break; + case 'disconnect': + a = new PrivateChannelDisconnectEventListener(this.messaging, this.id, wrapEventHandlerVoid()); + break; + } + await a.register(); + return a; } - onUnsubscribe(handler: (contextType?: string | undefined) => void): Listener { - const l = new PrivateChannelEventListenerType(this.messaging, this.id, "onUnsubscribe", handler); - l.register() - return l; - } + throw new Error('Unsupported event type: ' + type); + } - onDisconnect(handler: () => void): Listener { - const l = new PrivateChannelEventListenerVoid(this.messaging, this.id, handler); - l.register() - return l; - } + //implementations of the deprecated listener functions + onAddContextListener(handler: (contextType?: string) => void): Listener { + const l = new PrivateChannelAddContextEventListener(this.messaging, this.id, (contextType: string | null) => { + //Adapt handler type for differences between addEventListener and onAddContextListener handler types + handler(contextType !== null ? contextType : undefined); + }); + l.register(); + return l; + } - async disconnect(): Promise { - await this.messaging.exchange({ - meta: this.messaging.createMeta(), - payload: { - channelId: this.id, - }, - type: "privateChannelDisconnectRequest" - } as PrivateChannelDisconnectRequest, 'privateChannelDisconnectResponse') - } + onUnsubscribe(handler: (contextType?: string) => void): Listener { + const l = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, (contextType: string | null) => { + //Adapt handler type differences between addEventListener and onUnsubscribe handler types + handler(contextType !== null ? contextType : undefined); + }); + l.register(); + return l; + } - async addContextListenerInner(contextType: string | null, theHandler: ContextHandler): Promise { - const listener = new DefaultContextListener(this.messaging, this.id, contextType, theHandler); - await listener.register() - return listener - } -} \ No newline at end of file + onDisconnect(handler: () => void): Listener { + const l = new PrivateChannelDisconnectEventListener(this.messaging, this.id, handler); + l.register(); + return l; + } + + async disconnect(): Promise { + await this.messaging.exchange( + { + meta: this.messaging.createMeta(), + payload: { + channelId: this.id, + }, + type: 'privateChannelDisconnectRequest', + } as PrivateChannelDisconnectRequest, + 'privateChannelDisconnectResponse' + ); + } + + async addContextListenerInner(contextType: string | null, theHandler: ContextHandler): Promise { + const listener = new DefaultContextListener(this.messaging, this.id, contextType, theHandler); + await listener.register(); + return listener; + } +} diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 548e24feb..578b5b79e 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -1,67 +1,82 @@ -import { Messaging } from "../Messaging" -import { RegisterableListener } from "./RegisterableListener" +import { + AgentEventMessage, + AgentResponseMessage, + AppRequestMessage, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { Messaging } from '../Messaging'; +import { RegisterableListener } from './RegisterableListener'; /** * Common to all listeners - they need to be registered and unregistered with messaging and also - * send notification messsages when connected and disconnected + * send notification messages when connected and disconnected */ export abstract class AbstractListener implements RegisterableListener { + readonly messaging: Messaging; + private readonly subscribeRequestType: AppRequestMessage['type']; + private readonly subscribeResponseType: AgentResponseMessage['type']; + private readonly unsubscribeRequestType: AppRequestMessage['type']; + private readonly unsubscribeResponseType: AgentResponseMessage['type']; + private readonly payloadDetails: Record; + id: string | null = null; + readonly handler: X; - readonly messaging: Messaging - private readonly subscribeType: string - private readonly unsubscribeType: string - private readonly payloadDetails: Record - id: string | null = null - readonly handler: X + constructor( + messaging: Messaging, + payloadDetails: Record, + handler: X, + subscribeRequestType: AppRequestMessage['type'], + subscribeResponseType: AgentResponseMessage['type'], + unsubscribeRequestType: AppRequestMessage['type'], + unsubscribeResponseType: AgentResponseMessage['type'] + ) { + this.messaging = messaging; + this.handler = handler; + this.payloadDetails = payloadDetails; + this.subscribeRequestType = subscribeRequestType; + this.subscribeResponseType = subscribeResponseType; + this.unsubscribeRequestType = unsubscribeRequestType; + this.unsubscribeResponseType = unsubscribeResponseType; + } - constructor(messaging: Messaging, payloadDetails: Record, handler: X, subscribeType: string, unsubscribeType: string) { - this.messaging = messaging - this.handler = handler - this.payloadDetails = payloadDetails - this.subscribeType = subscribeType - this.unsubscribeType = unsubscribeType - } - - abstract filter(m: any): boolean - - abstract action(m: any): void - - async listenerNotification(type: string): Promise { - const requestType = type + "Request" - const responseType = type + "Response" - var notificationMessage: any - if (this.id) { - notificationMessage = { - meta: this.messaging.createMeta(), - payload: { - listenerUUID: this.id - }, - type: requestType - } - } else { - // send subscription notification - notificationMessage = { - meta: this.messaging.createMeta(), - payload: { - ...this.payloadDetails - }, - type: requestType - } - } + abstract filter(m: AgentEventMessage): boolean; - const response = await this.messaging.exchange(notificationMessage, responseType!!) - return response?.payload?.listenerUUID ?? null + abstract action(m: AgentEventMessage): void; + async listenerNotification( + requestType: AppRequestMessage['type'], + responseType: AgentResponseMessage['type'] + ): Promise { + let notificationMessage: AppRequestMessage; + if (this.id) { + notificationMessage = { + meta: this.messaging.createMeta(), + payload: { + listenerUUID: this.id, + }, + type: requestType, + }; + } else { + // send subscription notification + notificationMessage = { + meta: this.messaging.createMeta(), + payload: { + ...this.payloadDetails, + }, + type: requestType, + }; } - async unsubscribe(): Promise { - this.messaging.unregister(this.id!!) - await this.listenerNotification(this.unsubscribeType) - } + const response = await this.messaging.exchange(notificationMessage, responseType!); + return response?.payload?.listenerUUID ?? null; + } - async register() { - const id = await this.listenerNotification(this.subscribeType)!! - this.id = id - this.messaging.register(this) - } -} \ No newline at end of file + async unsubscribe(): Promise { + this.messaging.unregister(this.id!); + await this.listenerNotification(this.unsubscribeRequestType, this.unsubscribeResponseType); + } + + async register() { + this.id = await this.listenerNotification(this.subscribeRequestType, this.subscribeResponseType); + this.messaging.register(this); + } +} diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts index b522b0296..5cc2ac7a1 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts @@ -1,50 +1,57 @@ -import { ContextHandler, Channel } from "@kite9/fdc3-standard"; -import { Messaging } from "../Messaging"; -import { AbstractListener } from "./AbstractListener"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { FollowingContextListener } from "./FollowingContextListener"; - -type BroadcastEvent = BrowserTypes.BroadcastEvent +import { ContextHandler, Channel } from '@kite9/fdc3-standard'; +import { Messaging } from '../Messaging'; +import { AbstractListener } from './AbstractListener'; +import { FollowingContextListener } from './FollowingContextListener'; +import { BroadcastEvent } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class DefaultContextListener extends AbstractListener implements FollowingContextListener { + private channelId: string | null; + private readonly messageType: string; + private readonly contextType: string | null; - private channelId: string | null - private readonly messageType: string - private readonly contextType: string | null + constructor( + messaging: Messaging, + channelId: string | null, + contextType: string | null, + handler: ContextHandler, + messageType: string = 'broadcastEvent' + ) { + super( + messaging, + { channelId, contextType }, + handler, + 'addContextListenerRequest', + 'addContextListenerResponse', + 'contextListenerUnsubscribeRequest', + 'contextListenerUnsubscribeResponse' + ); + this.channelId = channelId; + this.messageType = messageType; + this.contextType = contextType; + } - constructor(messaging: Messaging, - channelId: string | null, - contextType: string | null, - handler: ContextHandler, - messageType: string = "broadcastEvent", - subscribeType: string = "addContextListener", - unsubscribeType: string = "contextListenerUnsubscribe") { - super(messaging, { channelId, contextType }, handler, subscribeType, unsubscribeType) - this.channelId = channelId - this.messageType = messageType - this.contextType = contextType + async changeChannel(channel: Channel | null): Promise { + if (channel == null) { + this.channelId = null; + return; + } else { + this.channelId = channel.id; + const context = await channel.getCurrentContext(this.contextType ?? undefined); + if (context) { + this.handler(context); + } } + } - async changeChannel(channel: Channel | null): Promise { - if (channel == null) { - this.channelId = null - return - } else { - this.channelId = channel.id - const context = await channel.getCurrentContext(this.contextType ?? undefined) - if (context) { - this.handler(context) - } - } - } + filter(m: BroadcastEvent): boolean { + return ( + m.type == this.messageType && + m.payload.channelId == this.channelId && + (m.payload.context?.type == this.contextType || this.contextType == null) + ); + } - filter(m: BroadcastEvent): boolean { - return (m.type == this.messageType) - && (m.payload.channelId == this.channelId) - && ((m.payload.context?.type == this.contextType) || (this.contextType == null)); - } - - action(m: any): void { - this.handler(m.payload.context) - } -} \ No newline at end of file + action(m: BroadcastEvent): void { + this.handler(m.payload.context); + } +} diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts index 58e6e8c86..5ffdc59b5 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts @@ -2,13 +2,7 @@ import { IntentHandler, IntentResult, AppIdentifier } from "@kite9/fdc3-standard import { Context } from "@kite9/fdc3-context"; import { Messaging } from "../Messaging"; import { AbstractListener } from "./AbstractListener"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type RaiseIntentResponse = BrowserTypes.RaiseIntentResponse -type IntentResultResponse = BrowserTypes.IntentResultResponse -type BridgeIntentResult = BrowserTypes.IntentResult -type IntentEvent = BrowserTypes.IntentEvent -type IntentResultRequest = BrowserTypes.IntentResultRequest +import { IntentEvent, IntentResultRequest, IntentResultResponse, RaiseIntentResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export class DefaultIntentListener extends AbstractListener { @@ -18,22 +12,24 @@ export class DefaultIntentListener extends AbstractListener { super(messaging, { intent }, action, - "addIntentListener", - "intentListenerUnsubscribe") - - this.intent = intent + "addIntentListenerRequest", + "addIntentListenerResponse", + "intentListenerUnsubscribeRequest", + "intentListenerUnsubscribeResponse" + ); + this.intent = intent; } filter(m: IntentEvent): boolean { - return (m.type == 'intentEvent') && (m.payload.intent == this.intent) + return (m.type == 'intentEvent') && (m.payload.intent == this.intent); } action(m: IntentEvent): void { - this.handleIntentResponse(m) + this.handleIntentResponse(m); const done = this.handler(m.payload.context, { source: m.payload.originatingApp as AppIdentifier - }) + }); this.handleIntentResult(done, m); } @@ -49,7 +45,7 @@ export class DefaultIntentListener extends AbstractListener { payload: { intentResolution: { intent: m.payload.intent, - source: this.messaging.getSource()! + source: this.messaging.getAppIdentifier() } } }; @@ -70,7 +66,7 @@ export class DefaultIntentListener extends AbstractListener { } }; - return out + return out; } private handleIntentResult(done: Promise | void, m: IntentEvent) { @@ -86,11 +82,9 @@ export class DefaultIntentListener extends AbstractListener { } } -function convertIntentResult(intentResult: IntentResult): BridgeIntentResult { - if (intentResult == null) { - return { - // empty result - } +function convertIntentResult(intentResult: IntentResult): IntentResultRequest["payload"]["intentResult"] { + if (!intentResult) { //consider any falsey result to be void... + return {}; // void result } switch (intentResult.type) { case 'user': diff --git a/packages/fdc3-agent-proxy/src/listeners/EventListener.ts b/packages/fdc3-agent-proxy/src/listeners/EventListener.ts index 0da47437c..941fba702 100644 --- a/packages/fdc3-agent-proxy/src/listeners/EventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/EventListener.ts @@ -1,6 +1,7 @@ import { ApiEvent, EventHandler } from "@kite9/fdc3-standard"; import { Messaging } from "../Messaging"; import { RegisterableListener } from "./RegisterableListener"; +import { AgentEventMessage } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export class EventListener implements RegisterableListener { @@ -16,11 +17,11 @@ export class EventListener implements RegisterableListener { this.handler = handler } - filter(m: any): boolean { + filter(m: AgentEventMessage): boolean { return m.type === this.type } - action(m: any): void { + action(m: AgentEventMessage): void { if (m.type === this.type) { this.handler({ type: this.type, diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index 798a5cfba..a0312d798 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -1,64 +1,80 @@ -import { Messaging } from "../Messaging" -import { AbstractListener } from "./AbstractListener" +import { + PrivateChannelOnAddContextListenerEvent, + PrivateChannelOnDisconnectEvent, + PrivateChannelOnUnsubscribeEvent, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { Messaging } from '../Messaging'; +import { AbstractListener } from './AbstractListener'; +import { PrivateChannelEventTypes } from '@kite9/fdc3-standard'; -type EVENT_TYPES_WITH_TYPE_HANDLER = "onAddContextListener" | "onUnsubscribe" -export type EVENT_TYPES = EVENT_TYPES_WITH_TYPE_HANDLER | "onDisconnect" +type PrivateChannelEventMessages = + | PrivateChannelOnAddContextListenerEvent + | PrivateChannelOnUnsubscribeEvent + | PrivateChannelOnDisconnectEvent; +type PrivateChannelEventMessageTypes = PrivateChannelEventMessages['type']; -const EVENT_NAMES: { [k: string]: string } = { - onAddContextListener: "privateChannelOnAddContextListenerEvent", - onDisconnect: "privateChannelOnDisconnectEvent", - onUnsubscribe: "privateChannelOnUnsubscribeEvent" -} +abstract class AbstractPrivateChannelEventListener< + X extends (() => void) | ((s: string | null) => void), +> extends AbstractListener { + readonly privateChannelId: string; + readonly eventMessageType: PrivateChannelEventMessageTypes; + readonly eventType: PrivateChannelEventTypes; -abstract class AbstractPrivateChannelEventListener extends AbstractListener { + constructor( + messaging: Messaging, + privateChannelId: string, + eventMessageType: PrivateChannelEventMessageTypes, + eventType: PrivateChannelEventTypes, + handler: X + ) { + super( + messaging, + { privateChannelId, eventMessageType }, + handler, + 'privateChannelAddEventListenerRequest', + 'privateChannelAddEventListenerResponse', + 'privateChannelUnsubscribeEventListenerRequest', + 'privateChannelUnsubscribeEventListenerResponse' + ); + this.privateChannelId = privateChannelId; + this.eventMessageType = eventMessageType; + this.eventType = eventType; + } - readonly privateChannelId: string - readonly listenerType: string + filter(m: PrivateChannelEventMessages) { + return m.type == this.eventMessageType && this.privateChannelId == m.payload.privateChannelId; + } - constructor( - messaging: Messaging, - privateChannelId: string, - listenerType: string, - handler: X) { - super(messaging, { privateChannelId, listenerType }, handler, "privateChannelAddEventListener", "privateChannelUnsubscribeEventListener") - this.privateChannelId = privateChannelId; - this.listenerType = listenerType - } + abstract action(m: PrivateChannelEventMessages): void; +} - filter(m: any) { - return (m.type == EVENT_NAMES[this.listenerType]) && (this.privateChannelId == m.payload.privateChannelId); - } +export class PrivateChannelDisconnectEventListener extends AbstractPrivateChannelEventListener<() => void> { + constructor(messaging: Messaging, channelId: string, handler: () => void) { + super(messaging, channelId, 'privateChannelOnDisconnectEvent', 'disconnect', handler); + } - abstract action(m: any): void + // eslint-disable-next-line @typescript-eslint/no-unused-vars + action(_m: PrivateChannelOnDisconnectEvent): void { + this.handler(); + } } -export class PrivateChannelEventListenerVoid extends AbstractPrivateChannelEventListener<() => void> { - - constructor( - messaging: Messaging, - channelId: string, - handler: () => void) { - super(messaging, channelId, "onDisconnect", handler) +export class PrivateChannelAddContextEventListener extends AbstractPrivateChannelEventListener<(contextType: string | null) => void> { + constructor(messaging: Messaging, channelId: string, handler: (contextType: string | null) => void) { + super(messaging, channelId, 'privateChannelOnAddContextListenerEvent', 'addContextListener', handler); } - - action(_m: any): void { - this.handler() + + action(m: PrivateChannelOnAddContextListenerEvent): void { + this.handler(m.payload.contextType); } + } -} - -export class PrivateChannelEventListenerType extends AbstractPrivateChannelEventListener<(m: string) => void> { - - constructor( - messaging: Messaging, - channelId: string, - listenerType: EVENT_TYPES_WITH_TYPE_HANDLER, - handler: (s: string) => void) { - super(messaging, channelId, listenerType, handler) + export class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChannelEventListener<(contextType: string | null) => void> { + constructor(messaging: Messaging, channelId: string, handler: (contextType: string | null) => void) { + super(messaging, channelId, 'privateChannelOnUnsubscribeEvent', 'unsubscribe', handler); } - - action(m: any): void { - this.handler(m.payload.contextType) + + action(m: PrivateChannelOnAddContextListenerEvent): void { + this.handler(m.payload.contextType); } - -} \ No newline at end of file + } diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index 32603c9cf..badc41432 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -4,13 +4,11 @@ import { RegisterableListener } from '../listeners/RegisterableListener'; import { AgentResponseMessage, isAgentResponseMessage, - WebConnectionProtocolMessage, AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export abstract class AbstractMessaging implements Messaging { - private appIdentifier: AppIdentifier | null = null; - private implementationMetadata: ImplementationMetadata | null = null; + private implementationMetadata: ImplementationMetadata; abstract createUUID(): string; abstract post(message: object): Promise; @@ -22,19 +20,17 @@ export abstract class AbstractMessaging implements Messaging { abstract getTimeoutMs(): number; - constructor() {} - - getSource(): AppIdentifier | null { - return this.appIdentifier; + constructor(implementationMetadata: ImplementationMetadata) { + this.implementationMetadata = implementationMetadata; } - waitFor( + waitFor( filter: (m: AgentResponseMessage) => boolean, timeoutErrorMessage?: string ): Promise { const id = this.createUUID(); return new Promise((resolve, reject) => { - var done = false; + let done = false; const l: RegisterableListener = { id, filter: filter, @@ -59,10 +55,10 @@ export abstract class AbstractMessaging implements Messaging { }); } - async exchange(message: AppRequestMessage, expectedTypeName: string, timeoutErrorMessage?: string): Promise { + async exchange(message: AppRequestMessage, expectedTypeName: string, timeoutErrorMessage?: string): Promise { const errorMessage = timeoutErrorMessage ?? `Timeout waiting for ${expectedTypeName} with requestUuid ${message.meta.requestUuid}`; - const prom = this.waitFor((m) => { + const prom = this.waitFor((m) => { if (isAgentResponseMessage(m)) { return m.type == expectedTypeName && m.meta.requestUuid == message.meta.requestUuid; } else { @@ -70,7 +66,7 @@ export abstract class AbstractMessaging implements Messaging { } }, errorMessage); this.post(message); - const out: any = await prom; + const out: X = await prom; if (out?.payload?.error) { throw new Error(out.payload.error); } else { @@ -78,20 +74,15 @@ export abstract class AbstractMessaging implements Messaging { } } - async getImplementationMetadata(): Promise { + getImplementationMetadata(): ImplementationMetadata { return this.implementationMetadata; } - setImplementationMetadata(impl: ImplementationMetadata | null) { - this.implementationMetadata = impl; - } - - async getAppIdentifier(): Promise { - return this.appIdentifier; - } - - setAppIdentifier(ident: AppIdentifier | null) { - this.appIdentifier = ident; + getAppIdentifier(): AppIdentifier { + return { + appId: this.implementationMetadata.appMetadata.appId, + instanceId: this.implementationMetadata.appMetadata.instanceId + }; } abstract connect(): Promise; diff --git a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts index 4fd336754..38dc7386a 100644 --- a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts @@ -1,11 +1,7 @@ -import { GetAgentParams, AppIdentifier } from '@kite9/fdc3-standard'; +import { GetAgentParams, ImplementationMetadata } from '@kite9/fdc3-standard'; import { RegisterableListener, AbstractMessaging } from '@kite9/fdc3-agent-proxy'; import { - AppRequestMessage, - WebConnectionProtocolMessage, - AgentResponseMessage, - WebConnectionProtocol5ValidateAppIdentitySuccessResponse, - isWebConnectionProtocolMessage + AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; @@ -14,15 +10,13 @@ import { */ export abstract class AbstractWebMessaging extends AbstractMessaging { private readonly options: GetAgentParams; - private readonly connectionAttemptUuid: string; - constructor(options: GetAgentParams, connectionAttemptUuid: string) { - super(); + constructor(options: GetAgentParams, implMetadata: ImplementationMetadata) { + super(implMetadata); if (!options.timeoutMs) { options.timeoutMs = 10016; } this.options = options; - this.connectionAttemptUuid = connectionAttemptUuid; } abstract post(message: object): Promise; @@ -36,90 +30,15 @@ export abstract class AbstractWebMessaging extends AbstractMessaging { return this.options.timeoutMs!; } - getSource(): AppIdentifier | null { - return super.getSource(); - } - /** * This handles the verify exchange with the da-server, */ async connect(): Promise { - const validationResponse = - await this.exchangeValidationWithId( - this.createValidationMessage(), - this.connectionAttemptUuid - ); - - super.setAppIdentifier({ - appId: validationResponse.payload.appId, - instanceId: validationResponse.payload.instanceId, - }); - - super.setImplementationMetadata(validationResponse.payload.implementationMetadata); - - // //TODO: need to do something with the instanceUuid... - // this.storeMyDesktopAgentDetails(validationResponse, /* need to set agent Type and agentUrl if any */) } async disconnect(): Promise { - super.setAppIdentifier(null); - super.setImplementationMetadata(null); - } - - // /** - // * Sends the validate message through the message port - // */ - // private createValidationMessage(): WebConnectionProtocol4ValidateAppIdentity { - // const requestMessage: WebConnectionProtocol4ValidateAppIdentity = { - // type: 'WCP4ValidateAppIdentity', - // meta: { - // connectionAttemptUuid: this.connectionAttemptUuid, - // timestamp: new Date(), - // }, - // payload: { - // identityUrl: this.options.identityUrl ?? this.actualUrl, - // actualUrl: this.actualUrl - // } - // }; - // const persistedDetails = this.retrieveMyDesktopAgentDetails(); - - // if (persistedDetails) { - // requestMessage.payload.instanceId = persistedDetails.instanceId; - // requestMessage.payload.instanceUuid = persistedDetails.instanceUuid; - // } - - // return requestMessage; - // } - // /** Used to persist data on the connection, which can later be used to ensure - // * reconnection to the same Desktop Agent and to request the same instanceId. - // */ - // storeMyDesktopAgentDetails( - // validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse, - // agentType: WebDesktopAgentType, - // agentUrl?: string - // ) { - // //create the details object to persist - // const details: DesktopAgentDetails = { - // agentType, - // identityUrl: this.options.identityUrl!, - // actualUrl: this.actualUrl!, - // agentUrl: agentUrl ?? undefined, - // appId: validationResponse.payload.appId, - // instanceUuid: validationResponse.payload.instanceUuid, - // instanceId: validationResponse.payload.instanceId, - // }; - - // storeDesktopAgentDetails(details); - // } - - // /** Retrieves persisted data about previous connections for this specific app - // * (identified by the identityUrl). Used to ensure reconnection to the same - // * agent and to request the same instanceId. - // */ - // retrieveMyDesktopAgentDetails(): DesktopAgentDetails | null { - // return retrieveDesktopAgentDetails(this.options.identityUrl!); - // } + } } diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 3c1779798..3479f18d5 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -1,6 +1,6 @@ import { AbstractWebMessaging } from './AbstractWebMessaging' import { RegisterableListener } from "@kite9/fdc3-agent-proxy" -import { GetAgentParams, WebDesktopAgentType } from "@kite9/fdc3-standard" +import { GetAgentParams, ImplementationMetadata, WebDesktopAgentType } from "@kite9/fdc3-standard" import { v4 as uuidv4 } from "uuid" import { BrowserTypes } from "@kite9/fdc3-schema"; import { AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; @@ -24,12 +24,12 @@ export class MessagePortMessaging extends AbstractWebMessaging { private readonly cd: ConnectionDetails private readonly listeners: Map = new Map() - constructor(cd: ConnectionDetails) { - super(cd.options, cd.connectionAttemptUuid, cd.actualUrl); + constructor(cd: ConnectionDetails, impl: ImplementationMetadata) { + super(cd.options, impl); this.cd = cd; this.cd.messagePort.onmessage = (m) => { - this.listeners.forEach((v, _k) => { + this.listeners.forEach((v) => { if (v.filter(m.data)) { v.action(m.data) } @@ -47,7 +47,7 @@ export class MessagePortMessaging extends AbstractWebMessaging { } register(l: RegisterableListener): void { - this.listeners.set(l.id!!, l) + this.listeners.set(l.id!, l) } unregister(id: string): void { @@ -58,17 +58,17 @@ export class MessagePortMessaging extends AbstractWebMessaging { return { "requestUuid": this.createUUID(), "timestamp": new Date(), - "source": super.getSource()! + "source": super.getAppIdentifier() } } - waitFor(filter: (m: any) => boolean, timeoutErrorMessage?: string): Promise { - // console.log("Waiting for", filter, timeoutErrorMessage) - return super.waitFor(filter, timeoutErrorMessage).then((v: any) => { - // console.log("Wait over ", v, timeoutErrorMessage) - return v; - }) - } + // waitFor(filter: (m: AgentResponseMessage) => boolean, timeoutErrorMessage?: string): Promise { + // // console.log("Waiting for", filter, timeoutErrorMessage) + // return super.waitFor(filter, timeoutErrorMessage).then((v: X) => { + // // console.log("Wait over ", v, timeoutErrorMessage) + // return v; + // }) + // } async disconnect(): Promise { await super.disconnect() From f4713c4ee74efca705f7295806a64d68d3cf3714 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 25 Nov 2024 14:21:36 +0000 Subject: [PATCH 09/90] Cleanup and simplify AbstractListener --- .../src/listeners/AbstractListener.ts | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 578b5b79e..4ba106d46 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -42,41 +42,37 @@ export abstract class AbstractListener implements RegisterableListener { abstract action(m: AgentEventMessage): void; - async listenerNotification( - requestType: AppRequestMessage['type'], - responseType: AgentResponseMessage['type'] - ): Promise { - let notificationMessage: AppRequestMessage; + async unsubscribe(): Promise { if (this.id) { - notificationMessage = { - meta: this.messaging.createMeta(), - payload: { - listenerUUID: this.id, - }, - type: requestType, - }; + this.messaging.unregister(this.id!); + const notificationMessage: AppRequestMessage = { + meta: this.messaging.createMeta(), + payload: { + listenerUUID: this.id, + }, + type: this.unsubscribeRequestType, + }; + await this.messaging.exchange(notificationMessage, this.unsubscribeResponseType); + return; } else { - // send subscription notification - notificationMessage = { + console.error("This listener doesn't have an id and hence can't be removed!"); + } + } + + async register(): Promise { + const notificationMessage: AppRequestMessage = { meta: this.messaging.createMeta(), payload: { ...this.payloadDetails, }, - type: requestType, + type: this.subscribeRequestType, }; - } - - const response = await this.messaging.exchange(notificationMessage, responseType!); - return response?.payload?.listenerUUID ?? null; - } - - async unsubscribe(): Promise { - this.messaging.unregister(this.id!); - await this.listenerNotification(this.unsubscribeRequestType, this.unsubscribeResponseType); - } + const response = await this.messaging.exchange(notificationMessage, this.subscribeResponseType); + this.id = (response?.payload?.listenerUUID) ?? null; - async register() { - this.id = await this.listenerNotification(this.subscribeRequestType, this.subscribeResponseType); - this.messaging.register(this); + if (!this.id){ + console.error("The Desktop Agent's response did not include a listenerUUID, which will mean this listener can't be removed!", response); + } + this.messaging.register(this); } } From fb7c0b78aafa1afb529991085566e9fe8f1afe9e Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 25 Nov 2024 17:31:03 +0000 Subject: [PATCH 10/90] Refactor PrivateChannel event listener support --- .../src/channels/DefaultPrivateChannel.ts | 77 +++++----- .../listeners/PrivateChannelEventListener.ts | 137 +++++++++++++----- 2 files changed, 134 insertions(+), 80 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts index df1f01a3a..96bf7b5d5 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts @@ -10,6 +10,7 @@ import { BrowserTypes } from '@kite9/fdc3-schema'; import { DefaultChannel } from './DefaultChannel'; import { Messaging } from '../Messaging'; import { + PrivateChannelNullEventListener, PrivateChannelAddContextEventListener, PrivateChannelDisconnectEventListener, PrivateChannelUnsubscribeEventListener, @@ -26,64 +27,54 @@ export class DefaultPrivateChannel extends DefaultChannel implements PrivateChan } async addEventListener(type: PrivateChannelEventTypes | null, handler: EventHandler): Promise { - function wrapEventHandlerString(): (m: string | null) => void { - return (m: string | null) => { - handler({ - type, - details: m, - } as ApiEvent); - }; + let a: RegisterableListener; + switch (type) { + case 'addContextListener': + a = new PrivateChannelAddContextEventListener(this.messaging, this.id, handler); + break; + case 'unsubscribe': + a = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, handler); + break; + case 'disconnect': + a = new PrivateChannelDisconnectEventListener(this.messaging, this.id, handler); + break; + case null: + a = new PrivateChannelNullEventListener(this.messaging, this.id, handler); + break; + default: + throw new Error('Unsupported event type: ' + type); } - - function wrapEventHandlerVoid(): () => void { - return () => { - handler({ - type, - } as ApiEvent); - }; - } - - if (type) { - let a: RegisterableListener; - switch (type) { - case 'addContextListener': - a = new PrivateChannelAddContextEventListener(this.messaging, this.id, wrapEventHandlerString()); - break; - case 'unsubscribe': - a = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, wrapEventHandlerString()); - break; - case 'disconnect': - a = new PrivateChannelDisconnectEventListener(this.messaging, this.id, wrapEventHandlerVoid()); - break; - } - await a.register(); - return a; - } - - throw new Error('Unsupported event type: ' + type); + await a.register(); + return a; } //implementations of the deprecated listener functions onAddContextListener(handler: (contextType?: string) => void): Listener { - const l = new PrivateChannelAddContextEventListener(this.messaging, this.id, (contextType: string | null) => { - //Adapt handler type for differences between addEventListener and onAddContextListener handler types - handler(contextType !== null ? contextType : undefined); - }); + //Adapt handler type for differences between addEventListener and onAddContextListener handler types + const adapterHandler: EventHandler = (event: ApiEvent) => { + handler(event.details.contextType ?? undefined); + }; + const l = new PrivateChannelAddContextEventListener(this.messaging, this.id, adapterHandler); l.register(); return l; } onUnsubscribe(handler: (contextType?: string) => void): Listener { - const l = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, (contextType: string | null) => { - //Adapt handler type differences between addEventListener and onUnsubscribe handler types - handler(contextType !== null ? contextType : undefined); - }); + //Adapt handler type for differences between addEventListener and onUnsubscribeListener handler types + const adapterHandler: EventHandler = (event: ApiEvent) => { + handler(event.details.contextType ?? undefined); + }; + const l = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, adapterHandler); l.register(); return l; } onDisconnect(handler: () => void): Listener { - const l = new PrivateChannelDisconnectEventListener(this.messaging, this.id, handler); + //Adapt handler type for differences between addEventListener and onDisconnectListener handler types + const adapterHandler: EventHandler = (_event: ApiEvent) => { + handler(); + }; + const l = new PrivateChannelDisconnectEventListener(this.messaging, this.id, adapterHandler); l.register(); return l; } diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index a0312d798..a64edd1ad 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -5,7 +5,7 @@ import { } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Messaging } from '../Messaging'; import { AbstractListener } from './AbstractListener'; -import { PrivateChannelEventTypes } from '@kite9/fdc3-standard'; +import { EventHandler, PrivateChannelAddContextListenerEvent, PrivateChannelDisconnectEvent, PrivateChannelEvent, PrivateChannelEventTypes, PrivateChannelUnsubscribeEvent } from '@kite9/fdc3-standard'; type PrivateChannelEventMessages = | PrivateChannelOnAddContextListenerEvent @@ -13,23 +13,20 @@ type PrivateChannelEventMessages = | PrivateChannelOnDisconnectEvent; type PrivateChannelEventMessageTypes = PrivateChannelEventMessages['type']; -abstract class AbstractPrivateChannelEventListener< - X extends (() => void) | ((s: string | null) => void), -> extends AbstractListener { +abstract class AbstractPrivateChannelEventListener extends AbstractListener<(msg: PrivateChannelEventMessages) => void> { readonly privateChannelId: string; - readonly eventMessageType: PrivateChannelEventMessageTypes; - readonly eventType: PrivateChannelEventTypes; + readonly eventMessageTypes: PrivateChannelEventMessageTypes[]; constructor( messaging: Messaging, privateChannelId: string, - eventMessageType: PrivateChannelEventMessageTypes, - eventType: PrivateChannelEventTypes, - handler: X + eventMessageTypes: PrivateChannelEventMessageTypes[], + eventType: PrivateChannelEventTypes | null, + handler: (msg: PrivateChannelEventMessages) => void ) { super( messaging, - { privateChannelId, eventMessageType }, + { privateChannelId, listenerType: eventType }, handler, 'privateChannelAddEventListenerRequest', 'privateChannelAddEventListenerResponse', @@ -37,44 +34,110 @@ abstract class AbstractPrivateChannelEventListener< 'privateChannelUnsubscribeEventListenerResponse' ); this.privateChannelId = privateChannelId; - this.eventMessageType = eventMessageType; - this.eventType = eventType; + this.eventMessageTypes = eventMessageTypes; } - filter(m: PrivateChannelEventMessages) { - return m.type == this.eventMessageType && this.privateChannelId == m.payload.privateChannelId; + filter(m: PrivateChannelEventMessages): boolean { + return this.eventMessageTypes.includes(m.type) && this.privateChannelId == m.payload.privateChannelId; } - abstract action(m: PrivateChannelEventMessages): void; + action(m: PrivateChannelEventMessages): void { + this.handler(m); + } } -export class PrivateChannelDisconnectEventListener extends AbstractPrivateChannelEventListener<() => void> { - constructor(messaging: Messaging, channelId: string, handler: () => void) { - super(messaging, channelId, 'privateChannelOnDisconnectEvent', 'disconnect', handler); +export class PrivateChannelNullEventListener extends AbstractPrivateChannelEventListener { + constructor(messaging: Messaging, channelId: string, handler: EventHandler) { + const wrappedHandler = (msg: PrivateChannelEventMessages) => { + let type: PrivateChannelEventTypes; + let details: PrivateChannelAddContextListenerEvent["details"] | PrivateChannelUnsubscribeEvent["details"] | PrivateChannelDisconnectEvent["details"] + switch (msg.type) { + case "privateChannelOnAddContextListenerEvent": + type = "addContextListener"; + details = { contextType: msg.payload.contextType } + break; + case "privateChannelOnUnsubscribeEvent": + type = "unsubscribe"; + details = { contextType: msg.payload.contextType } + break; + case "privateChannelOnDisconnectEvent": + type = "disconnect"; + details: null + break; + } + + const event: PrivateChannelEvent = { + type, + details + }; + handler(event); + }; + + super( + messaging, + channelId, + [ + 'privateChannelOnAddContextListenerEvent', + 'privateChannelOnUnsubscribeEvent', + 'privateChannelOnDisconnectEvent', + ], + 'addContextListener', + wrappedHandler + ); } +} + +export class PrivateChannelDisconnectEventListener extends AbstractPrivateChannelEventListener { + constructor(messaging: Messaging, channelId: string, handler: EventHandler) { + const wrappedHandler = (msg: PrivateChannelEventMessages) => { + if (msg.type === "privateChannelOnDisconnectEvent") { + const event: PrivateChannelDisconnectEvent = { + type: "disconnect", + details: null + }; + handler(event); + } else { + console.error("PrivateChannelDisconnectEventListener was called for a different message type!", msg); + } + + }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - action(_m: PrivateChannelOnDisconnectEvent): void { - this.handler(); + super(messaging, channelId, ['privateChannelOnDisconnectEvent'], 'disconnect', wrappedHandler); } } -export class PrivateChannelAddContextEventListener extends AbstractPrivateChannelEventListener<(contextType: string | null) => void> { - constructor(messaging: Messaging, channelId: string, handler: (contextType: string | null) => void) { - super(messaging, channelId, 'privateChannelOnAddContextListenerEvent', 'addContextListener', handler); - } - - action(m: PrivateChannelOnAddContextListenerEvent): void { - this.handler(m.payload.contextType); - } +export class PrivateChannelAddContextEventListener extends AbstractPrivateChannelEventListener { + constructor(messaging: Messaging, channelId: string, handler: EventHandler) { + const wrappedHandler = (msg: PrivateChannelEventMessages) => { + if (msg.type === "privateChannelOnAddContextListenerEvent") { + const event: PrivateChannelAddContextListenerEvent = { + type: "addContextListener", + details: { contextType: msg.payload.contextType } + }; + handler(event); + } else { + console.error("PrivateChannelDisconnectEventListener was called for a different message type!", msg); + } + + }; + super(messaging, channelId, ['privateChannelOnAddContextListenerEvent'], 'addContextListener', wrappedHandler); } +} - export class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChannelEventListener<(contextType: string | null) => void> { - constructor(messaging: Messaging, channelId: string, handler: (contextType: string | null) => void) { - super(messaging, channelId, 'privateChannelOnUnsubscribeEvent', 'unsubscribe', handler); - } - - action(m: PrivateChannelOnAddContextListenerEvent): void { - this.handler(m.payload.contextType); - } +export class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChannelEventListener { + constructor(messaging: Messaging, channelId: string, handler: EventHandler) { + const wrappedHandler = (msg: PrivateChannelEventMessages) => { + if (msg.type === "privateChannelOnUnsubscribeEvent") { + const event: PrivateChannelUnsubscribeEvent = { + type: "unsubscribe", + details: { contextType: msg.payload.contextType } + }; + handler(event); + } else { + console.error("PrivateChannelDisconnectEventListener was called for a different message type!", msg); + } + + }; + super(messaging, channelId, ['privateChannelOnUnsubscribeEvent'], 'unsubscribe', wrappedHandler); } +} From 23f8ad19e710abb65509ae26a6d4bcd7105b1b06 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 26 Nov 2024 14:04:48 +0000 Subject: [PATCH 11/90] Messaging refactor - Eliminate AbstractWebMessaging - Messaging is no longer a Connectable (as the connection is provided to it - was previously a no-op) - Handling getInfo via a message exchange rather than passing down through connection flow - Messaging implementations no longer handle implementationMetadata, instead holding the AppIdentifier directly - Renamed HandshakeSupport HeartbeatSupport as its no longer involved in holding implementaiton metadata. - Improving typing and error handling (defensive coding) in get-agent-proxy --- .../fdc3-agent-proxy/src/BasicDesktopAgent.ts | 44 ++---- packages/fdc3-agent-proxy/src/Messaging.ts | 12 +- .../fdc3-agent-proxy/src/apps/AppSupport.ts | 10 +- .../src/apps/DefaultAppSupport.ts | 61 ++++++-- .../src/channels/ChannelSupport.ts | 16 +-- .../src/channels/DefaultChannel.ts | 134 +++++++++--------- .../src/handshake/DefaultHandshakeSupport.ts | 41 ------ .../src/handshake/HandshakeSupport.ts | 10 -- .../src/heartbeat/DefaultHeartbeatSupport.ts | 34 +++++ .../src/heartbeat/HeartbeatSupport.ts | 5 + packages/fdc3-agent-proxy/src/index.ts | 6 +- .../src/messaging/AbstractMessaging.ts | 18 +-- .../src/messaging/AbstractWebMessaging.ts | 44 ------ .../src/messaging/MessagePortMessaging.ts | 24 ++-- .../src/messaging/message-port.ts | 12 +- .../src/strategies/FailoverHandler.ts | 9 +- .../src/strategies/PostMessageLoader.ts | 10 +- packages/fdc3-standard/src/ui/Connectable.ts | 2 +- 18 files changed, 229 insertions(+), 263 deletions(-) delete mode 100644 packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts delete mode 100644 packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts create mode 100644 packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts create mode 100644 packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts delete mode 100644 packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts diff --git a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts index 6d20ff2b6..4e217ac64 100644 --- a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts +++ b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts @@ -2,9 +2,9 @@ import { AppIdentifier, AppMetadata, ContextHandler, DesktopAgent, EventHandler, import { ChannelSupport } from "./channels/ChannelSupport"; import { AppSupport } from "./apps/AppSupport"; import { IntentSupport } from "./intents/IntentSupport"; -import { HandshakeSupport } from "./handshake/HandshakeSupport"; import { Connectable } from "@kite9/fdc3-standard"; import { Context } from "@kite9/fdc3-context"; +import { HeartbeatSupport } from "./heartbeat/HeartbeatSupport"; /** * This splits out the functionality of the desktop agent into @@ -12,18 +12,18 @@ import { Context } from "@kite9/fdc3-context"; */ export class BasicDesktopAgent implements DesktopAgent, Connectable { - readonly handshake: HandshakeSupport - readonly channels: ChannelSupport - readonly intents: IntentSupport - readonly apps: AppSupport - readonly connectables: Connectable[] + readonly heartbeat: HeartbeatSupport; + readonly channels: ChannelSupport; + readonly intents: IntentSupport; + readonly apps: AppSupport; + readonly connectables: Connectable[]; - constructor(handshake: HandshakeSupport, channels: ChannelSupport, intents: IntentSupport, apps: AppSupport, connectables: Connectable[]) { - this.handshake = handshake - this.intents = intents - this.channels = channels - this.apps = apps - this.connectables = connectables + constructor(heartbeat: HeartbeatSupport, channels: ChannelSupport, intents: IntentSupport, apps: AppSupport, connectables: Connectable[]) { + this.heartbeat = heartbeat; + this.intents = intents; + this.channels = channels; + this.apps = apps; + this.connectables = connectables; } async addEventListener(type: FDC3EventTypes | null, handler: EventHandler): Promise { @@ -34,24 +34,8 @@ export class BasicDesktopAgent implements DesktopAgent, Connectable { } } - async getInfo(): Promise { - let impl = await this.handshake.getImplementationMetadata(); - //handle potential null during start-up - //TODO: introduce queuing to prevent early calls - if (!impl) { - console.error("Implementation data was not available"); - impl = { - fdc3Version: "unknown", - provider: "unknown", - optionalFeatures: { - OriginatingAppMetadata: false, - UserChannelMembershipAPIs: false, - DesktopAgentBridging: false - }, - appMetadata: {appId: "unknown"} - }; - } - return impl; + getInfo(): Promise { + return this.apps.getImplementationMetadata(); } async broadcast(context: Context): Promise { diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index dc133c5e0..754cc6e65 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -1,11 +1,11 @@ -import { Connectable, AppIdentifier, ImplementationMetadata } from '@kite9/fdc3-standard'; +import { /*Connectable,*/ AppIdentifier, ImplementationMetadata } from '@kite9/fdc3-standard'; import { RegisterableListener } from './listeners/RegisterableListener'; import { AppRequestMessage, AgentResponseMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -export interface Messaging extends Connectable { +export interface Messaging /*extends Connectable*/ { /** * Creates UUIDs used in outgoing messages @@ -45,14 +45,12 @@ export interface Messaging extends Connectable { */ exchange(message: object, expectedTypeName: string, timeoutErrorMessage?: string): Promise; - /** - * Implementation metadata retrieved through the validation process - */ - getImplementationMetadata(): ImplementationMetadata; - /** * App identification used to provide source information used in * message meta elements, IntentResolution etc.. */ getAppIdentifier(): AppIdentifier; + + /** Disconnects the underlying message transport. */ + disconnect(): Promise } diff --git a/packages/fdc3-agent-proxy/src/apps/AppSupport.ts b/packages/fdc3-agent-proxy/src/apps/AppSupport.ts index faa61e9c8..c7039c66d 100644 --- a/packages/fdc3-agent-proxy/src/apps/AppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/AppSupport.ts @@ -1,13 +1,15 @@ -import { AppIdentifier, AppMetadata } from "@kite9/fdc3-standard"; +import { AppIdentifier, AppMetadata, ImplementationMetadata } from "@kite9/fdc3-standard"; import { Context } from "@kite9/fdc3-context"; export interface AppSupport { - findInstances(app: AppIdentifier): Promise> + findInstances(app: AppIdentifier): Promise>; - getAppMetadata(app: AppIdentifier): Promise + getAppMetadata(app: AppIdentifier): Promise; - open(app: AppIdentifier, context?: Context): Promise + open(app: AppIdentifier, context?: Context): Promise; + + getImplementationMetadata(): Promise; } \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts index 074d7dcd7..d267b3944 100644 --- a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts @@ -1,8 +1,9 @@ -import { AppIdentifier, AppMetadata, OpenError } from "@kite9/fdc3-standard"; +import { AppIdentifier, AppMetadata, ImplementationMetadata, OpenError, ResolveError } from "@kite9/fdc3-standard"; import { Context } from "@kite9/fdc3-context"; import { AppSupport } from "./AppSupport"; import { Messaging } from "../Messaging"; import { BrowserTypes } from "@kite9/fdc3-schema" +import { GetInfoRequest, GetInfoResponse, OpenResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; type FindInstancesRequest = BrowserTypes.FindInstancesRequest type GetAppMetadataResponse = BrowserTypes.GetAppMetadataResponse @@ -24,11 +25,11 @@ export class DefaultAppSupport implements AppSupport { payload: { app }, - meta: this.messaging.createMeta() as any - } + meta: this.messaging.createMeta() + }; return this.messaging.exchange(request, "findInstancesResponse").then(d => { - return d.payload.appIdentifiers!! + return d.payload.appIdentifiers ?? []; }); } @@ -38,16 +39,21 @@ export class DefaultAppSupport implements AppSupport { payload: { app: app as AppIdentifier }, - meta: this.messaging.createMeta() as any + meta: this.messaging.createMeta() } return this.messaging.exchange(request, "getAppMetadataResponse").then(d => { - return d.payload.appMetadata!! + if (d.payload.appMetadata){ + return d.payload.appMetadata; + } else { + //should never happen as an error returned will be thrown + throw new Error(ResolveError.TargetAppUnavailable); + } }); } async open(app: AppIdentifier, context?: Context | undefined): Promise { - const request = { + const request: OpenRequest = { type: "openRequest", payload: { app: { @@ -56,11 +62,44 @@ export class DefaultAppSupport implements AppSupport { }, context }, - meta: this.messaging.createMeta() as any - } as OpenRequest + meta: this.messaging.createMeta() + }; + + const out = await this.messaging.exchange(request, "openResponse", OpenError.AppTimeout); + if (out.payload.appIdentifier) { + return out.payload.appIdentifier; + } else { + //should never happen as an error returned will be thrown + throw new Error(OpenError.AppNotFound); + } + + } + + async getImplementationMetadata(): Promise { + const request: GetInfoRequest = { + type: "getInfoRequest", + payload: {}, + meta: this.messaging.createMeta() + } - const out = await this.messaging.exchange(request, "openResponse", OpenError.AppTimeout) - return out.payload.appIdentifier + const out = await this.messaging.exchange(request, "getInfoResponse", OpenError.AppTimeout); + if (out.payload.implementationMetadata) { + return out.payload.implementationMetadata; + } else { + //should never happen as an error returned will be thrown + const unknownImpl: ImplementationMetadata = { + fdc3Version: "unknown", + provider: "unknown", + appMetadata: {appId: "unknown", instanceId: "unknown" }, + optionalFeatures: { + OriginatingAppMetadata: false, + UserChannelMembershipAPIs: false, + DesktopAgentBridging: false + } + }; + return unknownImpl; + } + } } \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts index 840d5baec..5ff844e17 100644 --- a/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts @@ -2,19 +2,19 @@ import { Channel, ContextHandler, EventHandler, Listener, PrivateChannel } from export interface ChannelSupport { - getUserChannel(): Promise + getUserChannel(): Promise; - getUserChannels(): Promise + getUserChannels(): Promise; - getOrCreate(id: string): Promise + getOrCreate(id: string): Promise; - createPrivateChannel(): Promise + createPrivateChannel(): Promise; - leaveUserChannel(): Promise + leaveUserChannel(): Promise; - joinUserChannel(id: string): Promise + joinUserChannel(id: string): Promise; - addContextListener(handler: ContextHandler, type: string | null): Promise + addContextListener(handler: ContextHandler, type: string | null): Promise; - addChannelChangedEventHandler(handler: EventHandler): Promise + addChannelChangedEventHandler(handler: EventHandler): Promise; } \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index 92e06f5ad..b3c7d866f 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -1,78 +1,82 @@ -import { ContextHandler, DisplayMetadata, Listener, Channel } from "@kite9/fdc3-standard" -import { Context } from "@kite9/fdc3-context"; +import { ContextHandler, DisplayMetadata, Listener, Channel } from '@kite9/fdc3-standard'; +import { Context } from '@kite9/fdc3-context'; -import { Messaging } from "../Messaging" -import { DefaultContextListener } from "../listeners/DefaultContextListener" -import { BrowserTypes } from "@kite9/fdc3-schema" +import { Messaging } from '../Messaging'; +import { DefaultContextListener } from '../listeners/DefaultContextListener'; +import { BrowserTypes } from '@kite9/fdc3-schema'; -type BroadcastRequest = BrowserTypes.BroadcastRequest -type BroadcastResponse = BrowserTypes.BroadcastResponse -type GetCurrentContextResponse = BrowserTypes.GetCurrentContextResponse -type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest +type BroadcastRequest = BrowserTypes.BroadcastRequest; +type BroadcastResponse = BrowserTypes.BroadcastResponse; +type GetCurrentContextResponse = BrowserTypes.GetCurrentContextResponse; +type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest; export class DefaultChannel implements Channel { + readonly messaging: Messaging; + readonly id: string; + readonly type: 'user' | 'app' | 'private'; + readonly displayMetadata?: DisplayMetadata | undefined; - readonly messaging: Messaging - readonly id: string - readonly type: "user" | "app" | "private" - readonly displayMetadata?: DisplayMetadata | undefined; + constructor(messaging: Messaging, id: string, type: 'user' | 'app' | 'private', displayMetadata?: DisplayMetadata) { + this.messaging = messaging; + this.id = id; + this.type = type; + this.displayMetadata = displayMetadata; + } - constructor(messaging: Messaging, id: string, type: "user" | "app" | "private", displayMetadata?: DisplayMetadata) { - this.messaging = messaging - this.id = id - this.type = type - this.displayMetadata = displayMetadata - } - - async broadcast(context: Context): Promise { - const done = await this.messaging.exchange({ - meta: this.messaging.createMeta(), - payload: { - channelId: this.id, - context - }, - type: "broadcastRequest" - } as BroadcastRequest, 'broadcastResponse') - console.log("broadcast done", done) - } - - async getCurrentContext(contextType?: string | undefined): Promise { - // first, ensure channel state is up-to-date - const response = await this.messaging.exchange({ - meta: this.messaging.createMeta(), - payload: { - channelId: this.id, - contextType: contextType ?? null - }, - type: "getCurrentContextRequest" - } as GetCurrentContextRequest, 'getCurrentContextResponse') + async broadcast(context: Context): Promise { + const done = await this.messaging.exchange( + { + meta: this.messaging.createMeta(), + payload: { + channelId: this.id, + context, + }, + type: 'broadcastRequest', + } as BroadcastRequest, + 'broadcastResponse' + ); + console.log('broadcast done', done); + } - return response.payload.context ?? null - } + async getCurrentContext(contextType?: string | undefined): Promise { + // first, ensure channel state is up-to-date + const response = await this.messaging.exchange( + { + meta: this.messaging.createMeta(), + payload: { + channelId: this.id, + contextType: contextType ?? null, + }, + type: 'getCurrentContextRequest', + } as GetCurrentContextRequest, + 'getCurrentContextResponse' + ); - async addContextListener(contextType: any, handler?: ContextHandler): Promise { - let theContextType: string | null - let theHandler: ContextHandler + return response.payload.context ?? null; + } - if (contextType == null) { - theContextType = null; - theHandler = handler as ContextHandler; - } else if (typeof contextType === 'string') { - theContextType = contextType - theHandler = handler as ContextHandler; - } else { - // deprecated one-arg version - theContextType = null; - theHandler = contextType as ContextHandler; - } + async addContextListener(contextType: any, handler?: ContextHandler): Promise { + let theContextType: string | null; + let theHandler: ContextHandler; - return await this.addContextListenerInner(theContextType, theHandler); + if (contextType == null) { + theContextType = null; + theHandler = handler as ContextHandler; + } else if (typeof contextType === 'string') { + theContextType = contextType; + theHandler = handler as ContextHandler; + } else { + // deprecated one-arg version + theContextType = null; + theHandler = contextType as ContextHandler; } - async addContextListenerInner(contextType: string | null, theHandler: ContextHandler): Promise { - const listener = new DefaultContextListener(this.messaging, this.id, contextType, theHandler); - await listener.register() - return listener - } -} + return await this.addContextListenerInner(theContextType, theHandler); + } + async addContextListenerInner(contextType: string | null, theHandler: ContextHandler): Promise { + const listener = new DefaultContextListener(this.messaging, this.id, contextType, theHandler); + await listener.register(); + return listener; + } +} diff --git a/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts b/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts deleted file mode 100644 index 68ebcb22b..000000000 --- a/packages/fdc3-agent-proxy/src/handshake/DefaultHandshakeSupport.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -import { HeartbeatListener } from "../listeners/HeartbeatListener"; -import { Messaging } from "../Messaging"; -import { HandshakeSupport } from "./HandshakeSupport"; -import { ImplementationMetadata } from "@kite9/fdc3-standard"; - -/** - * Handles connection, disconnection and heartbeats for the proxy. - * This will possibly eventually need extending to allow for auth handshaking. - */ -export class DefaultHandshakeSupport implements HandshakeSupport { - - readonly messaging: Messaging - private heartbeatListener: HeartbeatListener | null = null - - constructor(messaging: Messaging) { - this.messaging = messaging - } - - async connect(): Promise { - await this.messaging.connect() - this.heartbeatListener = new HeartbeatListener(this.messaging) - this.heartbeatListener.register() - } - - async disconnect(): Promise { - await this.heartbeatListener?.unsubscribe() - await this.messaging.post({ - type: 'WCP6Goodbye', - meta: { - timestamp: new Date(), - } - } as WebConnectionProtocol6Goodbye) - return this.messaging.disconnect() - } - - async getImplementationMetadata(): Promise { - return this.messaging.getImplementationMetadata() - } - -} \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts b/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts deleted file mode 100644 index 0d3f0318f..000000000 --- a/packages/fdc3-agent-proxy/src/handshake/HandshakeSupport.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ImplementationMetadata, Connectable } from "@kite9/fdc3-standard" - -/** - * Handles messaging around connection and disconnection of the proxy - * to the server. - */ -export interface HandshakeSupport extends Connectable { - - getImplementationMetadata(): Promise -} \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts new file mode 100644 index 000000000..18e11244a --- /dev/null +++ b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts @@ -0,0 +1,34 @@ +import { WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; +import { HeartbeatListener } from "../listeners/HeartbeatListener"; +import { Messaging } from "../Messaging"; +import { HeartbeatSupport } from ".."; + +/** + * Handles disconnection and heartbeats for the proxy. + */ +export class DefaultHeartbeatSupport implements HeartbeatSupport { + + readonly messaging: Messaging; + private heartbeatListener: HeartbeatListener | null = null; + + constructor(messaging: Messaging) { + this.messaging = messaging; + } + + async connect(): Promise { + this.heartbeatListener = new HeartbeatListener(this.messaging); + this.heartbeatListener.register(); + } + + async disconnect(): Promise { + await this.heartbeatListener?.unsubscribe(); + await this.messaging.post({ + type: 'WCP6Goodbye', + meta: { + timestamp: new Date(), + } + } as WebConnectionProtocol6Goodbye); + return this.messaging.disconnect(); + } + +} \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts b/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts new file mode 100644 index 000000000..c195ec1bd --- /dev/null +++ b/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts @@ -0,0 +1,5 @@ +import { Connectable } from "@kite9/fdc3-standard"; + +export interface HeartbeatSupport extends Connectable { + +} \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/index.ts b/packages/fdc3-agent-proxy/src/index.ts index 052dae607..46d041ce3 100644 --- a/packages/fdc3-agent-proxy/src/index.ts +++ b/packages/fdc3-agent-proxy/src/index.ts @@ -13,8 +13,7 @@ import { RegisterableListener } from "./listeners/RegisterableListener"; import { DefaultAppSupport } from "./apps/DefaultAppSupport"; import { AppSupport } from "./apps/AppSupport"; -import { HandshakeSupport } from "./handshake/HandshakeSupport"; -import { DefaultHandshakeSupport } from "./handshake/DefaultHandshakeSupport"; +import { DefaultHeartbeatSupport } from "./heartbeat/DefaultHeartbeatSupport"; import { Connectable } from "@kite9/fdc3-standard"; @@ -29,8 +28,7 @@ export { DefaultAppSupport, DefaultChannelSupport, DefaultIntentSupport, - type HandshakeSupport, - DefaultHandshakeSupport, + DefaultHeartbeatSupport, RegisterableListener, Connectable, } \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index badc41432..77aed6261 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -8,7 +8,8 @@ import { } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export abstract class AbstractMessaging implements Messaging { - private implementationMetadata: ImplementationMetadata; + // private implementationMetadata: ImplementationMetadata; + private appIdentifier: AppIdentifier; abstract createUUID(): string; abstract post(message: object): Promise; @@ -20,8 +21,8 @@ export abstract class AbstractMessaging implements Messaging { abstract getTimeoutMs(): number; - constructor(implementationMetadata: ImplementationMetadata) { - this.implementationMetadata = implementationMetadata; + constructor(appIdentifier: AppIdentifier) { + this.appIdentifier = appIdentifier; } waitFor( @@ -74,18 +75,9 @@ export abstract class AbstractMessaging implements Messaging { } } - getImplementationMetadata(): ImplementationMetadata { - return this.implementationMetadata; - } - getAppIdentifier(): AppIdentifier { - return { - appId: this.implementationMetadata.appMetadata.appId, - instanceId: this.implementationMetadata.appMetadata.instanceId - }; + return this.appIdentifier; } - abstract connect(): Promise; - abstract disconnect(): Promise; } diff --git a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts b/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts deleted file mode 100644 index 38dc7386a..000000000 --- a/packages/fdc3-get-agent/src/messaging/AbstractWebMessaging.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { GetAgentParams, ImplementationMetadata } from '@kite9/fdc3-standard'; -import { RegisterableListener, AbstractMessaging } from '@kite9/fdc3-agent-proxy'; -import { - AppRequestMessage -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; - - -/** - * Version of Messaging which is able to store details in the SessionState (i.e. works on the web) - */ -export abstract class AbstractWebMessaging extends AbstractMessaging { - private readonly options: GetAgentParams; - - constructor(options: GetAgentParams, implMetadata: ImplementationMetadata) { - super(implMetadata); - if (!options.timeoutMs) { - options.timeoutMs = 10016; - } - this.options = options; - } - - abstract post(message: object): Promise; - - abstract register(l: RegisterableListener): void; - abstract unregister(id: string): void; - - abstract createMeta(): AppRequestMessage['meta']; - - getTimeoutMs(): number { - return this.options.timeoutMs!; - } - - /** - * This handles the verify exchange with the da-server, - */ - async connect(): Promise { - - } - - async disconnect(): Promise { - - } - -} diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 3479f18d5..470ea183d 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -1,6 +1,5 @@ -import { AbstractWebMessaging } from './AbstractWebMessaging' -import { RegisterableListener } from "@kite9/fdc3-agent-proxy" -import { GetAgentParams, ImplementationMetadata, WebDesktopAgentType } from "@kite9/fdc3-standard" +import { AbstractMessaging, RegisterableListener } from "@kite9/fdc3-agent-proxy" +import { AppIdentifier, GetAgentParams, ImplementationMetadata, WebDesktopAgentType } from "@kite9/fdc3-standard" import { v4 as uuidv4 } from "uuid" import { BrowserTypes } from "@kite9/fdc3-schema"; import { AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; @@ -19,13 +18,14 @@ export type ConnectionDetails = { agentUrl?: string, } -export class MessagePortMessaging extends AbstractWebMessaging { +const DEFAULT_TIMEOUT = 10016; +export class MessagePortMessaging extends AbstractMessaging { private readonly cd: ConnectionDetails private readonly listeners: Map = new Map() - constructor(cd: ConnectionDetails, impl: ImplementationMetadata) { - super(cd.options, impl); + constructor(cd: ConnectionDetails, appIdentifier: AppIdentifier) { + super(appIdentifier); this.cd = cd; this.cd.messagePort.onmessage = (m) => { @@ -62,16 +62,12 @@ export class MessagePortMessaging extends AbstractWebMessaging { } } - // waitFor(filter: (m: AgentResponseMessage) => boolean, timeoutErrorMessage?: string): Promise { - // // console.log("Waiting for", filter, timeoutErrorMessage) - // return super.waitFor(filter, timeoutErrorMessage).then((v: X) => { - // // console.log("Wait over ", v, timeoutErrorMessage) - // return v; - // }) - // } + getTimeoutMs(): number { + return this.cd.options.timeoutMs ?? DEFAULT_TIMEOUT; + } async disconnect(): Promise { - await super.disconnect() + await this.disconnect() this.cd.messagePort.close() } } diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 64b3aff7f..68b4b7f3c 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -1,16 +1,16 @@ -import { DesktopAgent } from "@kite9/fdc3-standard"; -import { BasicDesktopAgent, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, DefaultHandshakeSupport, ChannelSupport } from "@kite9/fdc3-agent-proxy"; +import { AppIdentifier, DesktopAgent } from "@kite9/fdc3-standard"; +import { BasicDesktopAgent, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, ChannelSupport, DefaultHeartbeatSupport } from "@kite9/fdc3-agent-proxy"; import { ConnectionDetails, MessagePortMessaging } from "./MessagePortMessaging"; import { DefaultDesktopAgentIntentResolver } from "../ui/DefaultDesktopAgentIntentResolver"; import { DefaultDesktopAgentChannelSelector } from "../ui/DefaultDesktopAgentChannelSelector"; import { NullIntentResolver } from "../ui/NullIntentResolver"; import { NullChannelSelector } from "../ui/NullChannelSelector"; import { ChannelSelector } from "@kite9/fdc3-standard"; -import { DesktopAgentSelection } from "../strategies/Loader"; + /** * Given a message port, constructs a desktop agent to communicate via that. */ -export async function createDesktopAgentAPI(cd: ConnectionDetails): Promise { +export async function createDesktopAgentAPI(cd: ConnectionDetails, appIdentifier: AppIdentifier): Promise { cd.messagePort.start(); @@ -22,7 +22,7 @@ export async function createDesktopAgentAPI(cd: ConnectionDetails): Promise From 070a413febbb1b334f36c15960fb8d76a8782fc5 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 26 Nov 2024 14:55:01 +0000 Subject: [PATCH 12/90] Corrections to PrivateChannelAddEventListenerRequest --- .../privateChannelAddEventListenerRequest.schema.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json b/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json index a57584996..72057d724 100644 --- a/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json +++ b/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json @@ -38,11 +38,14 @@ }, "listenerType": { "title": "Event listener type", - "description": "The type of PrivateChannel event that the listener should be applied to.", - "oneOf": [ + "description": "The type of PrivateChannel event that the listener should be applied to, or null for all event types.", + "oneOf" : [ { "$ref": "common.schema.json#/$defs/PrivateChannelEventListenerTypes" }, - { "type": "null" } + { + "type": "null" + } ] + } }, "additionalProperties": false, From 06c6c9c9141c493b20a2fcf9edcb645022cfe9d5 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 26 Nov 2024 19:03:27 +0000 Subject: [PATCH 13/90] More typing work on Listener and PrivateChannel events --- packages/fdc3-agent-proxy/src/Messaging.ts | 2 +- .../src/heartbeat/DefaultHeartbeatSupport.ts | 2 +- .../src/listeners/AbstractListener.ts | 116 +- .../src/listeners/DefaultContextListener.ts | 4 +- .../src/listeners/DefaultIntentListener.ts | 4 +- .../listeners/PrivateChannelEventListener.ts | 3 +- .../src/messaging/AbstractMessaging.ts | 11 +- .../src/messaging/MessagePortMessaging.ts | 2 +- .../src/strategies/HelloHandler.ts | 2 +- .../fdc3-schema/generated/api/BrowserTypes.ts | 1005 +++++++++++++---- .../fdc3-schema/schemas/api/api.schema.json | 27 + .../schemas/api/common.schema.json | 10 - ...ChannelAddEventListenerRequest.schema.json | 5 +- ...hannelAddEventListenerResponse.schema.json | 3 +- .../src/handlers/BroadcastHandler.ts | 21 +- 15 files changed, 929 insertions(+), 288 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index 754cc6e65..5c8b66dab 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -1,4 +1,4 @@ -import { /*Connectable,*/ AppIdentifier, ImplementationMetadata } from '@kite9/fdc3-standard'; +import { AppIdentifier } from '@kite9/fdc3-standard'; import { RegisterableListener } from './listeners/RegisterableListener'; import { AppRequestMessage, diff --git a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts index 18e11244a..22eee5db2 100644 --- a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts +++ b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts @@ -1,7 +1,7 @@ import { WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { HeartbeatListener } from "../listeners/HeartbeatListener"; import { Messaging } from "../Messaging"; -import { HeartbeatSupport } from ".."; +import { HeartbeatSupport } from "./HeartbeatSupport"; /** * Handles disconnection and heartbeats for the proxy. diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 4ba106d46..25354936e 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -1,37 +1,72 @@ import { AgentEventMessage, - AgentResponseMessage, - AppRequestMessage, + AddContextListenerRequest, + AddIntentListenerRequest, + AddEventListenerRequest, + PrivateChannelAddEventListenerRequest, + AddIntentListenerResponse, + AddContextListenerResponse, + AddEventListenerResponse, + ContextListenerUnsubscribeRequest, + IntentListenerUnsubscribeRequest, + EventListenerUnsubscribeRequest, + PrivateChannelAddEventListenerResponse, + PrivateChannelUnsubscribeEventListenerRequest, + ContextListenerUnsubscribeResponse, + IntentListenerUnsubscribeResponse, + EventListenerUnsubscribeResponse, + PrivateChannelUnsubscribeEventListenerResponse, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Messaging } from '../Messaging'; import { RegisterableListener } from './RegisterableListener'; +type SubscriptionRequest = + | AddContextListenerRequest + | AddIntentListenerRequest + | AddEventListenerRequest + | PrivateChannelAddEventListenerRequest; +type SubscriptionResponse = + | AddContextListenerResponse + | AddIntentListenerResponse + | AddEventListenerResponse + | PrivateChannelAddEventListenerResponse; +type UnsubscribeRequest = + | ContextListenerUnsubscribeRequest + | IntentListenerUnsubscribeRequest + | EventListenerUnsubscribeRequest + | PrivateChannelUnsubscribeEventListenerRequest; +type UnsubscribeResponse = + | ContextListenerUnsubscribeResponse + | IntentListenerUnsubscribeResponse + | EventListenerUnsubscribeResponse + | PrivateChannelUnsubscribeEventListenerResponse; + /** * Common to all listeners - they need to be registered and unregistered with messaging and also * send notification messages when connected and disconnected */ -export abstract class AbstractListener implements RegisterableListener { +export abstract class AbstractListener implements RegisterableListener { readonly messaging: Messaging; - private readonly subscribeRequestType: AppRequestMessage['type']; - private readonly subscribeResponseType: AgentResponseMessage['type']; - private readonly unsubscribeRequestType: AppRequestMessage['type']; - private readonly unsubscribeResponseType: AgentResponseMessage['type']; - private readonly payloadDetails: Record; + private readonly subscribeRequestType: Y['type']; + private readonly subscribeResponseType: SubscriptionResponse['type']; + private readonly unsubscribeRequestType: UnsubscribeRequest['type']; + private readonly unsubscribeResponseType: UnsubscribeResponse['type']; + private readonly subscriptionPayload: Y['payload']; id: string | null = null; readonly handler: X; constructor( messaging: Messaging, - payloadDetails: Record, + subscriptionPayload: Y['payload'], handler: X, - subscribeRequestType: AppRequestMessage['type'], - subscribeResponseType: AgentResponseMessage['type'], - unsubscribeRequestType: AppRequestMessage['type'], - unsubscribeResponseType: AgentResponseMessage['type'] + subscribeRequestType: Y['type'], + subscribeResponseType: SubscriptionResponse['type'], + unsubscribeRequestType: UnsubscribeRequest['type'], + unsubscribeResponseType: UnsubscribeResponse['type'] ) { this.messaging = messaging; this.handler = handler; - this.payloadDetails = payloadDetails; + this.subscriptionPayload = subscriptionPayload; this.subscribeRequestType = subscribeRequestType; this.subscribeResponseType = subscribeResponseType; this.unsubscribeRequestType = unsubscribeRequestType; @@ -44,35 +79,40 @@ export abstract class AbstractListener implements RegisterableListener { async unsubscribe(): Promise { if (this.id) { - this.messaging.unregister(this.id!); - const notificationMessage: AppRequestMessage = { - meta: this.messaging.createMeta(), - payload: { - listenerUUID: this.id, - }, - type: this.unsubscribeRequestType, - }; - await this.messaging.exchange(notificationMessage, this.unsubscribeResponseType); - return; + this.messaging.unregister(this.id!); + const unsubscribeMessage: UnsubscribeRequest = { + meta: this.messaging.createMeta(), + payload: { + listenerUUID: this.id, + }, + type: this.unsubscribeRequestType, + }; + await this.messaging.exchange(unsubscribeMessage, this.unsubscribeResponseType); + return; } else { - console.error("This listener doesn't have an id and hence can't be removed!"); + console.error("This listener doesn't have an id and hence can't be removed!"); } } async register(): Promise { - const notificationMessage: AppRequestMessage = { - meta: this.messaging.createMeta(), - payload: { - ...this.payloadDetails, - }, - type: this.subscribeRequestType, - }; - const response = await this.messaging.exchange(notificationMessage, this.subscribeResponseType); - this.id = (response?.payload?.listenerUUID) ?? null; + const subscribeMessage: Y = { + meta: this.messaging.createMeta(), + payload: this.subscriptionPayload, + type: this.subscribeRequestType, + } as Y; - if (!this.id){ - console.error("The Desktop Agent's response did not include a listenerUUID, which will mean this listener can't be removed!", response); - } - this.messaging.register(this); + const response = await this.messaging.exchange( + subscribeMessage, + this.subscribeResponseType + ); + this.id = response?.payload?.listenerUUID ?? null; + + if (!this.id) { + console.error( + "The Desktop Agent's response did not include a listenerUUID, which will mean this listener can't be removed!", + response + ); + } + this.messaging.register(this); } } diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts index 5cc2ac7a1..eb6747603 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts @@ -2,9 +2,9 @@ import { ContextHandler, Channel } from '@kite9/fdc3-standard'; import { Messaging } from '../Messaging'; import { AbstractListener } from './AbstractListener'; import { FollowingContextListener } from './FollowingContextListener'; -import { BroadcastEvent } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AddContextListenerRequest, BroadcastEvent } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -export class DefaultContextListener extends AbstractListener implements FollowingContextListener { +export class DefaultContextListener extends AbstractListener implements FollowingContextListener { private channelId: string | null; private readonly messageType: string; private readonly contextType: string | null; diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts index 5ffdc59b5..dae84eb12 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts @@ -2,9 +2,9 @@ import { IntentHandler, IntentResult, AppIdentifier } from "@kite9/fdc3-standard import { Context } from "@kite9/fdc3-context"; import { Messaging } from "../Messaging"; import { AbstractListener } from "./AbstractListener"; -import { IntentEvent, IntentResultRequest, IntentResultResponse, RaiseIntentResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; +import { AddIntentListenerRequest, IntentEvent, IntentResultRequest, IntentResultResponse, RaiseIntentResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -export class DefaultIntentListener extends AbstractListener { +export class DefaultIntentListener extends AbstractListener { readonly intent: string diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index a64edd1ad..5a7e72e89 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -1,4 +1,5 @@ import { + PrivateChannelAddEventListenerRequest, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, @@ -13,7 +14,7 @@ type PrivateChannelEventMessages = | PrivateChannelOnDisconnectEvent; type PrivateChannelEventMessageTypes = PrivateChannelEventMessages['type']; -abstract class AbstractPrivateChannelEventListener extends AbstractListener<(msg: PrivateChannelEventMessages) => void> { +abstract class AbstractPrivateChannelEventListener extends AbstractListener<(msg: PrivateChannelEventMessages) => void, PrivateChannelAddEventListenerRequest> { readonly privateChannelId: string; readonly eventMessageTypes: PrivateChannelEventMessageTypes[]; diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index 77aed6261..118896def 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -1,9 +1,8 @@ -import { AppIdentifier, ImplementationMetadata } from '@kite9/fdc3-standard'; +import { AppIdentifier } from '@kite9/fdc3-standard'; import { Messaging } from '../Messaging'; import { RegisterableListener } from '../listeners/RegisterableListener'; import { AgentResponseMessage, - isAgentResponseMessage, AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; @@ -56,15 +55,11 @@ export abstract class AbstractMessaging implements Messaging { }); } - async exchange(message: AppRequestMessage, expectedTypeName: string, timeoutErrorMessage?: string): Promise { + async exchange(message: AppRequestMessage, expectedTypeName: AgentResponseMessage["type"], timeoutErrorMessage?: string): Promise { const errorMessage = timeoutErrorMessage ?? `Timeout waiting for ${expectedTypeName} with requestUuid ${message.meta.requestUuid}`; const prom = this.waitFor((m) => { - if (isAgentResponseMessage(m)) { - return m.type == expectedTypeName && m.meta.requestUuid == message.meta.requestUuid; - } else { - return false; - } + return m.type == expectedTypeName && m.meta.requestUuid == message.meta.requestUuid; }, errorMessage); this.post(message); const out: X = await prom; diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 470ea183d..2443c1409 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -1,5 +1,5 @@ import { AbstractMessaging, RegisterableListener } from "@kite9/fdc3-agent-proxy" -import { AppIdentifier, GetAgentParams, ImplementationMetadata, WebDesktopAgentType } from "@kite9/fdc3-standard" +import { AppIdentifier, GetAgentParams, WebDesktopAgentType } from "@kite9/fdc3-standard" import { v4 as uuidv4 } from "uuid" import { BrowserTypes } from "@kite9/fdc3-schema"; import { AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index 0396b000f..dddb7d702 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -82,7 +82,7 @@ export class HelloHandler { ifrm.style.position = 'fixed'; //Wait for the iframe to load... then send it a hello message - ifrm.onload = event => { + ifrm.onload = _event => { if (ifrm.contentWindow) { this.sendWCP1Hello(ifrm.contentWindow, '*'); } else { diff --git a/packages/fdc3-schema/generated/api/BrowserTypes.ts b/packages/fdc3-schema/generated/api/BrowserTypes.ts index 077c03bbb..3b71a09d8 100644 --- a/packages/fdc3-schema/generated/api/BrowserTypes.ts +++ b/packages/fdc3-schema/generated/api/BrowserTypes.ts @@ -403,7 +403,7 @@ export interface AddIntentListenerResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: AddIntentListenerResponsePayload; + payload: PayloadObject; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. @@ -416,7 +416,7 @@ export interface AddIntentListenerResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface AddIntentListenerResponsePayload { +export interface PayloadObject { error?: FluffyError; listenerUUID?: string; [property: string]: any; @@ -432,30 +432,6 @@ export interface AddIntentListenerResponsePayload { */ export type FluffyError = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution"; -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A message from a Desktop Agent to an FDC3-enabled app representing an event. - */ -export interface AgentEventMessage { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: AgentEventMessageMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: EventMessageType; -} - /** * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ @@ -470,28 +446,6 @@ export interface AgentEventMessageMeta { */ export type EventMessageType = "addEventListenerEvent" | "broadcastEvent" | "channelChangedEvent" | "heartbeatEvent" | "intentEvent" | "privateChannelOnAddContextListenerEvent" | "privateChannelOnDisconnectEvent" | "privateChannelOnUnsubscribeEvent"; -/** - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. - */ -export interface AgentResponseMessage { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AgentResponseMessageMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: AgentResponseMessageResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: ResponseMessageType; -} - /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -522,25 +476,6 @@ export interface AgentResponseMessageResponsePayload { */ export type ResponseMessageType = "addContextListenerResponse" | "addEventListenerResponse" | "addIntentListenerResponse" | "broadcastResponse" | "contextListenerUnsubscribeResponse" | "createPrivateChannelResponse" | "eventListenerUnsubscribeResponse" | "findInstancesResponse" | "findIntentResponse" | "findIntentsByContextResponse" | "getAppMetadataResponse" | "getCurrentChannelResponse" | "getCurrentContextResponse" | "getInfoResponse" | "getOrCreateChannelResponse" | "getUserChannelsResponse" | "intentListenerUnsubscribeResponse" | "intentResultResponse" | "joinUserChannelResponse" | "leaveCurrentChannelResponse" | "openResponse" | "privateChannelAddEventListenerResponse" | "privateChannelDisconnectResponse" | "privateChannelUnsubscribeEventListenerResponse" | "raiseIntentForContextResponse" | "raiseIntentResponse" | "raiseIntentResultResponse"; -/** - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AppRequestMessage { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AppRequestMessageMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: RequestMessageType; -} - /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2892,7 +2827,7 @@ export interface PrivateChannelAddEventListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: TPayload; + payload: PrivateChannelAddEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. @@ -2903,11 +2838,12 @@ export interface PrivateChannelAddEventListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface TPayload { +export interface PrivateChannelAddEventListenerRequestPayload { /** - * The type of PrivateChannel event that the listener should be applied to. + * The type of PrivateChannel event that the listener should be applied to, or null for all + * event types. */ - listenerType: PrivateChannelEventListenerTypes | null; + listenerType: PrivateChannelEventType | null; /** * The Id of the PrivateChannel that the listener should be added to. */ @@ -2915,9 +2851,9 @@ export interface TPayload { } /** - * Event listener type names for Private Channel events. + * Type defining valid type strings for Private Channel events. */ -export type PrivateChannelEventListenerTypes = "onAddContextListener" | "onUnsubscribe" | "onDisconnect"; +export type PrivateChannelEventType = "addContextListener" | "unsubscribe" | "disconnect"; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2956,7 +2892,6 @@ export interface PrivateChannelAddEventListenerResponse { export interface PrivateChannelAddEventListenerResponsePayload { error?: PurpleError; listenerUUID?: string; - [property: string]: any; } /** @@ -4714,10 +4649,10 @@ const typeMap: any = { ], false), "AddIntentListenerResponse": o([ { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("AddIntentListenerResponsePayload") }, + { json: "payload", js: "payload", typ: r("PayloadObject") }, { json: "type", js: "type", typ: r("AddIntentListenerResponseType") }, ], false), - "AddIntentListenerResponsePayload": o([ + "PayloadObject": o([ { json: "error", js: "error", typ: u(undefined, r("FluffyError")) }, { json: "listenerUUID", js: "listenerUUID", typ: u(undefined, "") }, ], "any"), @@ -5251,11 +5186,11 @@ const typeMap: any = { ], false), "PrivateChannelAddEventListenerRequest": o([ { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("TPayload") }, + { json: "payload", js: "payload", typ: r("PrivateChannelAddEventListenerRequestPayload") }, { json: "type", js: "type", typ: r("PrivateChannelAddEventListenerRequestType") }, ], false), - "TPayload": o([ - { json: "listenerType", js: "listenerType", typ: u(r("PrivateChannelEventListenerTypes"), null) }, + "PrivateChannelAddEventListenerRequestPayload": o([ + { json: "listenerType", js: "listenerType", typ: u(r("PrivateChannelEventType"), null) }, { json: "privateChannelId", js: "privateChannelId", typ: "" }, ], false), "PrivateChannelAddEventListenerResponse": o([ @@ -5266,7 +5201,7 @@ const typeMap: any = { "PrivateChannelAddEventListenerResponsePayload": o([ { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, { json: "listenerUUID", js: "listenerUUID", typ: u(undefined, "") }, - ], "any"), + ], false), "PrivateChannelDisconnectRequest": o([ { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, { json: "payload", js: "payload", typ: r("PrivateChannelDisconnectRequestPayload") }, @@ -5777,10 +5712,10 @@ const typeMap: any = { "OpenResponseType": [ "openResponse", ], - "PrivateChannelEventListenerTypes": [ - "onAddContextListener", - "onDisconnect", - "onUnsubscribe", + "PrivateChannelEventType": [ + "addContextListener", + "disconnect", + "unsubscribe", ], "PrivateChannelAddEventListenerRequestType": [ "privateChannelAddEventListenerRequest", @@ -5856,7 +5791,23 @@ const typeMap: any = { ], }; +export type AppRequestMessage = AddContextListenerRequest | AddEventListenerRequest | AddIntentListenerRequest | BroadcastRequest | ContextListenerUnsubscribeRequest | CreatePrivateChannelRequest | EventListenerUnsubscribeRequest | FindInstancesRequest | FindIntentRequest | FindIntentsByContextRequest | GetAppMetadataRequest | GetCurrentChannelRequest | GetCurrentContextRequest | GetInfoRequest | GetOrCreateChannelRequest | GetUserChannelsRequest | HeartbeatAcknowledgementRequest | IntentListenerUnsubscribeRequest | IntentResultRequest | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest | PrivateChannelAddEventListenerRequest | PrivateChannelDisconnectRequest | PrivateChannelUnsubscribeEventListenerRequest | RaiseIntentForContextRequest | RaiseIntentRequest; + +export type AgentResponseMessage = AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse; + +export type AgentEventMessage = BroadcastEvent | ChannelChangedEvent | HeartbeatEvent | IntentEvent | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnDisconnectEvent | PrivateChannelOnUnsubscribeEvent; + +/** + * Returns true if the value has a type property with value 'addContextListenerRequest'. This is a fast check that does not check the format of the message + */ export function isAddContextListenerRequest(value: any): value is AddContextListenerRequest { + return value != null && value.type === 'addContextListenerRequest'; +} + +/** + * Returns true if value is a valid AddContextListenerRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidAddContextListenerRequest(value: any): value is AddContextListenerRequest { try { Convert.addContextListenerRequestToJson(value); return true; @@ -5867,7 +5818,17 @@ export function isAddContextListenerRequest(value: any): value is AddContextList export const ADD_CONTEXT_LISTENER_REQUEST_TYPE = "AddContextListenerRequest"; +/** + * Returns true if the value has a type property with value 'addContextListenerResponse'. This is a fast check that does not check the format of the message + */ export function isAddContextListenerResponse(value: any): value is AddContextListenerResponse { + return value != null && value.type === 'addContextListenerResponse'; +} + +/** + * Returns true if value is a valid AddContextListenerResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidAddContextListenerResponse(value: any): value is AddContextListenerResponse { try { Convert.addContextListenerResponseToJson(value); return true; @@ -5878,7 +5839,17 @@ export function isAddContextListenerResponse(value: any): value is AddContextLis export const ADD_CONTEXT_LISTENER_RESPONSE_TYPE = "AddContextListenerResponse"; +/** + * Returns true if the value has a type property with value 'addEventListenerRequest'. This is a fast check that does not check the format of the message + */ export function isAddEventListenerRequest(value: any): value is AddEventListenerRequest { + return value != null && value.type === 'addEventListenerRequest'; +} + +/** + * Returns true if value is a valid AddEventListenerRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidAddEventListenerRequest(value: any): value is AddEventListenerRequest { try { Convert.addEventListenerRequestToJson(value); return true; @@ -5889,7 +5860,17 @@ export function isAddEventListenerRequest(value: any): value is AddEventListener export const ADD_EVENT_LISTENER_REQUEST_TYPE = "AddEventListenerRequest"; +/** + * Returns true if the value has a type property with value 'addEventListenerResponse'. This is a fast check that does not check the format of the message + */ export function isAddEventListenerResponse(value: any): value is AddEventListenerResponse { + return value != null && value.type === 'addEventListenerResponse'; +} + +/** + * Returns true if value is a valid AddEventListenerResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidAddEventListenerResponse(value: any): value is AddEventListenerResponse { try { Convert.addEventListenerResponseToJson(value); return true; @@ -5900,7 +5881,17 @@ export function isAddEventListenerResponse(value: any): value is AddEventListene export const ADD_EVENT_LISTENER_RESPONSE_TYPE = "AddEventListenerResponse"; +/** + * Returns true if the value has a type property with value 'addIntentListenerRequest'. This is a fast check that does not check the format of the message + */ export function isAddIntentListenerRequest(value: any): value is AddIntentListenerRequest { + return value != null && value.type === 'addIntentListenerRequest'; +} + +/** + * Returns true if value is a valid AddIntentListenerRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidAddIntentListenerRequest(value: any): value is AddIntentListenerRequest { try { Convert.addIntentListenerRequestToJson(value); return true; @@ -5911,51 +5902,38 @@ export function isAddIntentListenerRequest(value: any): value is AddIntentListen export const ADD_INTENT_LISTENER_REQUEST_TYPE = "AddIntentListenerRequest"; +/** + * Returns true if the value has a type property with value 'addIntentListenerResponse'. This is a fast check that does not check the format of the message + */ export function isAddIntentListenerResponse(value: any): value is AddIntentListenerResponse { - try { - Convert.addIntentListenerResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const ADD_INTENT_LISTENER_RESPONSE_TYPE = "AddIntentListenerResponse"; - -export function isAgentEventMessage(value: any): value is AgentEventMessage { - try { - Convert.agentEventMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } + return value != null && value.type === 'addIntentListenerResponse'; } -export const AGENT_EVENT_MESSAGE_TYPE = "AgentEventMessage"; - -export function isAgentResponseMessage(value: any): value is AgentResponseMessage { +/** + * Returns true if value is a valid AddIntentListenerResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidAddIntentListenerResponse(value: any): value is AddIntentListenerResponse { try { - Convert.agentResponseMessageToJson(value); + Convert.addIntentListenerResponseToJson(value); return true; } catch (_e: any) { return false; } } -export const AGENT_RESPONSE_MESSAGE_TYPE = "AgentResponseMessage"; +export const ADD_INTENT_LISTENER_RESPONSE_TYPE = "AddIntentListenerResponse"; -export function isAppRequestMessage(value: any): value is AppRequestMessage { - try { - Convert.appRequestMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } +/** + * Returns true if the value has a type property with value 'broadcastEvent'. This is a fast check that does not check the format of the message + */ +export function isBroadcastEvent(value: any): value is BroadcastEvent { + return value != null && value.type === 'broadcastEvent'; } -export const APP_REQUEST_MESSAGE_TYPE = "AppRequestMessage"; - -export function isBroadcastEvent(value: any): value is BroadcastEvent { +/** + * Returns true if value is a valid BroadcastEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidBroadcastEvent(value: any): value is BroadcastEvent { try { Convert.broadcastEventToJson(value); return true; @@ -5966,7 +5944,17 @@ export function isBroadcastEvent(value: any): value is BroadcastEvent { export const BROADCAST_EVENT_TYPE = "BroadcastEvent"; +/** + * Returns true if the value has a type property with value 'broadcastRequest'. This is a fast check that does not check the format of the message + */ export function isBroadcastRequest(value: any): value is BroadcastRequest { + return value != null && value.type === 'broadcastRequest'; +} + +/** + * Returns true if value is a valid BroadcastRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidBroadcastRequest(value: any): value is BroadcastRequest { try { Convert.broadcastRequestToJson(value); return true; @@ -5977,7 +5965,17 @@ export function isBroadcastRequest(value: any): value is BroadcastRequest { export const BROADCAST_REQUEST_TYPE = "BroadcastRequest"; +/** + * Returns true if the value has a type property with value 'broadcastResponse'. This is a fast check that does not check the format of the message + */ export function isBroadcastResponse(value: any): value is BroadcastResponse { + return value != null && value.type === 'broadcastResponse'; +} + +/** + * Returns true if value is a valid BroadcastResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidBroadcastResponse(value: any): value is BroadcastResponse { try { Convert.broadcastResponseToJson(value); return true; @@ -5988,7 +5986,17 @@ export function isBroadcastResponse(value: any): value is BroadcastResponse { export const BROADCAST_RESPONSE_TYPE = "BroadcastResponse"; +/** + * Returns true if the value has a type property with value 'channelChangedEvent'. This is a fast check that does not check the format of the message + */ export function isChannelChangedEvent(value: any): value is ChannelChangedEvent { + return value != null && value.type === 'channelChangedEvent'; +} + +/** + * Returns true if value is a valid ChannelChangedEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidChannelChangedEvent(value: any): value is ChannelChangedEvent { try { Convert.channelChangedEventToJson(value); return true; @@ -5999,7 +6007,17 @@ export function isChannelChangedEvent(value: any): value is ChannelChangedEvent export const CHANNEL_CHANGED_EVENT_TYPE = "ChannelChangedEvent"; +/** + * Returns true if the value has a type property with value 'contextListenerUnsubscribeRequest'. This is a fast check that does not check the format of the message + */ export function isContextListenerUnsubscribeRequest(value: any): value is ContextListenerUnsubscribeRequest { + return value != null && value.type === 'contextListenerUnsubscribeRequest'; +} + +/** + * Returns true if value is a valid ContextListenerUnsubscribeRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidContextListenerUnsubscribeRequest(value: any): value is ContextListenerUnsubscribeRequest { try { Convert.contextListenerUnsubscribeRequestToJson(value); return true; @@ -6010,7 +6028,17 @@ export function isContextListenerUnsubscribeRequest(value: any): value is Contex export const CONTEXT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = "ContextListenerUnsubscribeRequest"; +/** + * Returns true if the value has a type property with value 'contextListenerUnsubscribeResponse'. This is a fast check that does not check the format of the message + */ export function isContextListenerUnsubscribeResponse(value: any): value is ContextListenerUnsubscribeResponse { + return value != null && value.type === 'contextListenerUnsubscribeResponse'; +} + +/** + * Returns true if value is a valid ContextListenerUnsubscribeResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidContextListenerUnsubscribeResponse(value: any): value is ContextListenerUnsubscribeResponse { try { Convert.contextListenerUnsubscribeResponseToJson(value); return true; @@ -6021,7 +6049,17 @@ export function isContextListenerUnsubscribeResponse(value: any): value is Conte export const CONTEXT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "ContextListenerUnsubscribeResponse"; +/** + * Returns true if the value has a type property with value 'createPrivateChannelRequest'. This is a fast check that does not check the format of the message + */ export function isCreatePrivateChannelRequest(value: any): value is CreatePrivateChannelRequest { + return value != null && value.type === 'createPrivateChannelRequest'; +} + +/** + * Returns true if value is a valid CreatePrivateChannelRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidCreatePrivateChannelRequest(value: any): value is CreatePrivateChannelRequest { try { Convert.createPrivateChannelRequestToJson(value); return true; @@ -6032,7 +6070,17 @@ export function isCreatePrivateChannelRequest(value: any): value is CreatePrivat export const CREATE_PRIVATE_CHANNEL_REQUEST_TYPE = "CreatePrivateChannelRequest"; +/** + * Returns true if the value has a type property with value 'createPrivateChannelResponse'. This is a fast check that does not check the format of the message + */ export function isCreatePrivateChannelResponse(value: any): value is CreatePrivateChannelResponse { + return value != null && value.type === 'createPrivateChannelResponse'; +} + +/** + * Returns true if value is a valid CreatePrivateChannelResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidCreatePrivateChannelResponse(value: any): value is CreatePrivateChannelResponse { try { Convert.createPrivateChannelResponseToJson(value); return true; @@ -6043,7 +6091,17 @@ export function isCreatePrivateChannelResponse(value: any): value is CreatePriva export const CREATE_PRIVATE_CHANNEL_RESPONSE_TYPE = "CreatePrivateChannelResponse"; +/** + * Returns true if the value has a type property with value 'eventListenerUnsubscribeRequest'. This is a fast check that does not check the format of the message + */ export function isEventListenerUnsubscribeRequest(value: any): value is EventListenerUnsubscribeRequest { + return value != null && value.type === 'eventListenerUnsubscribeRequest'; +} + +/** + * Returns true if value is a valid EventListenerUnsubscribeRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidEventListenerUnsubscribeRequest(value: any): value is EventListenerUnsubscribeRequest { try { Convert.eventListenerUnsubscribeRequestToJson(value); return true; @@ -6054,7 +6112,17 @@ export function isEventListenerUnsubscribeRequest(value: any): value is EventLis export const EVENT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = "EventListenerUnsubscribeRequest"; +/** + * Returns true if the value has a type property with value 'eventListenerUnsubscribeResponse'. This is a fast check that does not check the format of the message + */ export function isEventListenerUnsubscribeResponse(value: any): value is EventListenerUnsubscribeResponse { + return value != null && value.type === 'eventListenerUnsubscribeResponse'; +} + +/** + * Returns true if value is a valid EventListenerUnsubscribeResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidEventListenerUnsubscribeResponse(value: any): value is EventListenerUnsubscribeResponse { try { Convert.eventListenerUnsubscribeResponseToJson(value); return true; @@ -6065,7 +6133,17 @@ export function isEventListenerUnsubscribeResponse(value: any): value is EventLi export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "EventListenerUnsubscribeResponse"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { + return value != null && value.type === 'Fdc3UserInterfaceChannels'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { try { Convert.fdc3UserInterfaceChannelsToJson(value); return true; @@ -6076,7 +6154,17 @@ export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterf export const FDC3_USER_INTERFACE_CHANNELS_TYPE = "Fdc3UserInterfaceChannels"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { + return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { try { Convert.fdc3UserInterfaceChannelSelectedToJson(value); return true; @@ -6087,7 +6175,17 @@ export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3Use export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = "Fdc3UserInterfaceChannelSelected"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceDrag'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceDrag(value: any): value is Fdc3UserInterfaceDrag { + return value != null && value.type === 'Fdc3UserInterfaceDrag'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceDrag. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceDrag(value: any): value is Fdc3UserInterfaceDrag { try { Convert.fdc3UserInterfaceDragToJson(value); return true; @@ -6098,7 +6196,17 @@ export function isFdc3UserInterfaceDrag(value: any): value is Fdc3UserInterfaceD export const FDC3_USER_INTERFACE_DRAG_TYPE = "Fdc3UserInterfaceDrag"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceHandshake'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceHandshake(value: any): value is Fdc3UserInterfaceHandshake { + return value != null && value.type === 'Fdc3UserInterfaceHandshake'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceHandshake. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceHandshake(value: any): value is Fdc3UserInterfaceHandshake { try { Convert.fdc3UserInterfaceHandshakeToJson(value); return true; @@ -6109,7 +6217,17 @@ export function isFdc3UserInterfaceHandshake(value: any): value is Fdc3UserInter export const FDC3_USER_INTERFACE_HANDSHAKE_TYPE = "Fdc3UserInterfaceHandshake"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceHello'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceHello(value: any): value is Fdc3UserInterfaceHello { + return value != null && value.type === 'Fdc3UserInterfaceHello'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceHello. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceHello(value: any): value is Fdc3UserInterfaceHello { try { Convert.fdc3UserInterfaceHelloToJson(value); return true; @@ -6120,7 +6238,10 @@ export function isFdc3UserInterfaceHello(value: any): value is Fdc3UserInterface export const FDC3_USER_INTERFACE_HELLO_TYPE = "Fdc3UserInterfaceHello"; -export function isFdc3UserInterfaceMessage(value: any): value is Fdc3UserInterfaceMessage { +/** + * Returns true if value is a valid Fdc3UserInterfaceMessage. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceMessage(value: any): value is Fdc3UserInterfaceMessage { try { Convert.fdc3UserInterfaceMessageToJson(value); return true; @@ -6131,7 +6252,17 @@ export function isFdc3UserInterfaceMessage(value: any): value is Fdc3UserInterfa export const FDC3_USER_INTERFACE_MESSAGE_TYPE = "Fdc3UserInterfaceMessage"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceResolve'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceResolve(value: any): value is Fdc3UserInterfaceResolve { + return value != null && value.type === 'Fdc3UserInterfaceResolve'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceResolve. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceResolve(value: any): value is Fdc3UserInterfaceResolve { try { Convert.fdc3UserInterfaceResolveToJson(value); return true; @@ -6142,7 +6273,17 @@ export function isFdc3UserInterfaceResolve(value: any): value is Fdc3UserInterfa export const FDC3_USER_INTERFACE_RESOLVE_TYPE = "Fdc3UserInterfaceResolve"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceResolveAction'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceResolveAction(value: any): value is Fdc3UserInterfaceResolveAction { + return value != null && value.type === 'Fdc3UserInterfaceResolveAction'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceResolveAction. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceResolveAction(value: any): value is Fdc3UserInterfaceResolveAction { try { Convert.fdc3UserInterfaceResolveActionToJson(value); return true; @@ -6153,7 +6294,17 @@ export function isFdc3UserInterfaceResolveAction(value: any): value is Fdc3UserI export const FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE = "Fdc3UserInterfaceResolveAction"; +/** + * Returns true if the value has a type property with value 'Fdc3UserInterfaceRestyle'. This is a fast check that does not check the format of the message + */ export function isFdc3UserInterfaceRestyle(value: any): value is Fdc3UserInterfaceRestyle { + return value != null && value.type === 'Fdc3UserInterfaceRestyle'; +} + +/** + * Returns true if value is a valid Fdc3UserInterfaceRestyle. This checks the type against the json schema for the message and will be slower + */ +export function isValidFdc3UserInterfaceRestyle(value: any): value is Fdc3UserInterfaceRestyle { try { Convert.fdc3UserInterfaceRestyleToJson(value); return true; @@ -6164,7 +6315,17 @@ export function isFdc3UserInterfaceRestyle(value: any): value is Fdc3UserInterfa export const FDC3_USER_INTERFACE_RESTYLE_TYPE = "Fdc3UserInterfaceRestyle"; +/** + * Returns true if the value has a type property with value 'findInstancesRequest'. This is a fast check that does not check the format of the message + */ export function isFindInstancesRequest(value: any): value is FindInstancesRequest { + return value != null && value.type === 'findInstancesRequest'; +} + +/** + * Returns true if value is a valid FindInstancesRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidFindInstancesRequest(value: any): value is FindInstancesRequest { try { Convert.findInstancesRequestToJson(value); return true; @@ -6175,7 +6336,17 @@ export function isFindInstancesRequest(value: any): value is FindInstancesReques export const FIND_INSTANCES_REQUEST_TYPE = "FindInstancesRequest"; +/** + * Returns true if the value has a type property with value 'findInstancesResponse'. This is a fast check that does not check the format of the message + */ export function isFindInstancesResponse(value: any): value is FindInstancesResponse { + return value != null && value.type === 'findInstancesResponse'; +} + +/** + * Returns true if value is a valid FindInstancesResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidFindInstancesResponse(value: any): value is FindInstancesResponse { try { Convert.findInstancesResponseToJson(value); return true; @@ -6186,7 +6357,17 @@ export function isFindInstancesResponse(value: any): value is FindInstancesRespo export const FIND_INSTANCES_RESPONSE_TYPE = "FindInstancesResponse"; +/** + * Returns true if the value has a type property with value 'findIntentRequest'. This is a fast check that does not check the format of the message + */ export function isFindIntentRequest(value: any): value is FindIntentRequest { + return value != null && value.type === 'findIntentRequest'; +} + +/** + * Returns true if value is a valid FindIntentRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidFindIntentRequest(value: any): value is FindIntentRequest { try { Convert.findIntentRequestToJson(value); return true; @@ -6197,7 +6378,17 @@ export function isFindIntentRequest(value: any): value is FindIntentRequest { export const FIND_INTENT_REQUEST_TYPE = "FindIntentRequest"; +/** + * Returns true if the value has a type property with value 'findIntentResponse'. This is a fast check that does not check the format of the message + */ export function isFindIntentResponse(value: any): value is FindIntentResponse { + return value != null && value.type === 'findIntentResponse'; +} + +/** + * Returns true if value is a valid FindIntentResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidFindIntentResponse(value: any): value is FindIntentResponse { try { Convert.findIntentResponseToJson(value); return true; @@ -6208,10 +6399,20 @@ export function isFindIntentResponse(value: any): value is FindIntentResponse { export const FIND_INTENT_RESPONSE_TYPE = "FindIntentResponse"; +/** + * Returns true if the value has a type property with value 'findIntentsByContextRequest'. This is a fast check that does not check the format of the message + */ export function isFindIntentsByContextRequest(value: any): value is FindIntentsByContextRequest { - try { - Convert.findIntentsByContextRequestToJson(value); - return true; + return value != null && value.type === 'findIntentsByContextRequest'; +} + +/** + * Returns true if value is a valid FindIntentsByContextRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidFindIntentsByContextRequest(value: any): value is FindIntentsByContextRequest { + try { + Convert.findIntentsByContextRequestToJson(value); + return true; } catch (_e: any) { return false; } @@ -6219,7 +6420,17 @@ export function isFindIntentsByContextRequest(value: any): value is FindIntentsB export const FIND_INTENTS_BY_CONTEXT_REQUEST_TYPE = "FindIntentsByContextRequest"; +/** + * Returns true if the value has a type property with value 'findIntentsByContextResponse'. This is a fast check that does not check the format of the message + */ export function isFindIntentsByContextResponse(value: any): value is FindIntentsByContextResponse { + return value != null && value.type === 'findIntentsByContextResponse'; +} + +/** + * Returns true if value is a valid FindIntentsByContextResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidFindIntentsByContextResponse(value: any): value is FindIntentsByContextResponse { try { Convert.findIntentsByContextResponseToJson(value); return true; @@ -6230,7 +6441,17 @@ export function isFindIntentsByContextResponse(value: any): value is FindIntents export const FIND_INTENTS_BY_CONTEXT_RESPONSE_TYPE = "FindIntentsByContextResponse"; +/** + * Returns true if the value has a type property with value 'getAppMetadataRequest'. This is a fast check that does not check the format of the message + */ export function isGetAppMetadataRequest(value: any): value is GetAppMetadataRequest { + return value != null && value.type === 'getAppMetadataRequest'; +} + +/** + * Returns true if value is a valid GetAppMetadataRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetAppMetadataRequest(value: any): value is GetAppMetadataRequest { try { Convert.getAppMetadataRequestToJson(value); return true; @@ -6241,7 +6462,17 @@ export function isGetAppMetadataRequest(value: any): value is GetAppMetadataRequ export const GET_APP_METADATA_REQUEST_TYPE = "GetAppMetadataRequest"; +/** + * Returns true if the value has a type property with value 'getAppMetadataResponse'. This is a fast check that does not check the format of the message + */ export function isGetAppMetadataResponse(value: any): value is GetAppMetadataResponse { + return value != null && value.type === 'getAppMetadataResponse'; +} + +/** + * Returns true if value is a valid GetAppMetadataResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetAppMetadataResponse(value: any): value is GetAppMetadataResponse { try { Convert.getAppMetadataResponseToJson(value); return true; @@ -6252,7 +6483,17 @@ export function isGetAppMetadataResponse(value: any): value is GetAppMetadataRes export const GET_APP_METADATA_RESPONSE_TYPE = "GetAppMetadataResponse"; +/** + * Returns true if the value has a type property with value 'getCurrentChannelRequest'. This is a fast check that does not check the format of the message + */ export function isGetCurrentChannelRequest(value: any): value is GetCurrentChannelRequest { + return value != null && value.type === 'getCurrentChannelRequest'; +} + +/** + * Returns true if value is a valid GetCurrentChannelRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetCurrentChannelRequest(value: any): value is GetCurrentChannelRequest { try { Convert.getCurrentChannelRequestToJson(value); return true; @@ -6263,7 +6504,17 @@ export function isGetCurrentChannelRequest(value: any): value is GetCurrentChann export const GET_CURRENT_CHANNEL_REQUEST_TYPE = "GetCurrentChannelRequest"; +/** + * Returns true if the value has a type property with value 'getCurrentChannelResponse'. This is a fast check that does not check the format of the message + */ export function isGetCurrentChannelResponse(value: any): value is GetCurrentChannelResponse { + return value != null && value.type === 'getCurrentChannelResponse'; +} + +/** + * Returns true if value is a valid GetCurrentChannelResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetCurrentChannelResponse(value: any): value is GetCurrentChannelResponse { try { Convert.getCurrentChannelResponseToJson(value); return true; @@ -6274,7 +6525,17 @@ export function isGetCurrentChannelResponse(value: any): value is GetCurrentChan export const GET_CURRENT_CHANNEL_RESPONSE_TYPE = "GetCurrentChannelResponse"; +/** + * Returns true if the value has a type property with value 'getCurrentContextRequest'. This is a fast check that does not check the format of the message + */ export function isGetCurrentContextRequest(value: any): value is GetCurrentContextRequest { + return value != null && value.type === 'getCurrentContextRequest'; +} + +/** + * Returns true if value is a valid GetCurrentContextRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetCurrentContextRequest(value: any): value is GetCurrentContextRequest { try { Convert.getCurrentContextRequestToJson(value); return true; @@ -6285,7 +6546,17 @@ export function isGetCurrentContextRequest(value: any): value is GetCurrentConte export const GET_CURRENT_CONTEXT_REQUEST_TYPE = "GetCurrentContextRequest"; +/** + * Returns true if the value has a type property with value 'getCurrentContextResponse'. This is a fast check that does not check the format of the message + */ export function isGetCurrentContextResponse(value: any): value is GetCurrentContextResponse { + return value != null && value.type === 'getCurrentContextResponse'; +} + +/** + * Returns true if value is a valid GetCurrentContextResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetCurrentContextResponse(value: any): value is GetCurrentContextResponse { try { Convert.getCurrentContextResponseToJson(value); return true; @@ -6296,7 +6567,17 @@ export function isGetCurrentContextResponse(value: any): value is GetCurrentCont export const GET_CURRENT_CONTEXT_RESPONSE_TYPE = "GetCurrentContextResponse"; +/** + * Returns true if the value has a type property with value 'getInfoRequest'. This is a fast check that does not check the format of the message + */ export function isGetInfoRequest(value: any): value is GetInfoRequest { + return value != null && value.type === 'getInfoRequest'; +} + +/** + * Returns true if value is a valid GetInfoRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetInfoRequest(value: any): value is GetInfoRequest { try { Convert.getInfoRequestToJson(value); return true; @@ -6307,7 +6588,17 @@ export function isGetInfoRequest(value: any): value is GetInfoRequest { export const GET_INFO_REQUEST_TYPE = "GetInfoRequest"; +/** + * Returns true if the value has a type property with value 'getInfoResponse'. This is a fast check that does not check the format of the message + */ export function isGetInfoResponse(value: any): value is GetInfoResponse { + return value != null && value.type === 'getInfoResponse'; +} + +/** + * Returns true if value is a valid GetInfoResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetInfoResponse(value: any): value is GetInfoResponse { try { Convert.getInfoResponseToJson(value); return true; @@ -6318,7 +6609,17 @@ export function isGetInfoResponse(value: any): value is GetInfoResponse { export const GET_INFO_RESPONSE_TYPE = "GetInfoResponse"; +/** + * Returns true if the value has a type property with value 'getOrCreateChannelRequest'. This is a fast check that does not check the format of the message + */ export function isGetOrCreateChannelRequest(value: any): value is GetOrCreateChannelRequest { + return value != null && value.type === 'getOrCreateChannelRequest'; +} + +/** + * Returns true if value is a valid GetOrCreateChannelRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetOrCreateChannelRequest(value: any): value is GetOrCreateChannelRequest { try { Convert.getOrCreateChannelRequestToJson(value); return true; @@ -6329,7 +6630,17 @@ export function isGetOrCreateChannelRequest(value: any): value is GetOrCreateCha export const GET_OR_CREATE_CHANNEL_REQUEST_TYPE = "GetOrCreateChannelRequest"; +/** + * Returns true if the value has a type property with value 'getOrCreateChannelResponse'. This is a fast check that does not check the format of the message + */ export function isGetOrCreateChannelResponse(value: any): value is GetOrCreateChannelResponse { + return value != null && value.type === 'getOrCreateChannelResponse'; +} + +/** + * Returns true if value is a valid GetOrCreateChannelResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetOrCreateChannelResponse(value: any): value is GetOrCreateChannelResponse { try { Convert.getOrCreateChannelResponseToJson(value); return true; @@ -6340,7 +6651,17 @@ export function isGetOrCreateChannelResponse(value: any): value is GetOrCreateCh export const GET_OR_CREATE_CHANNEL_RESPONSE_TYPE = "GetOrCreateChannelResponse"; +/** + * Returns true if the value has a type property with value 'getUserChannelsRequest'. This is a fast check that does not check the format of the message + */ export function isGetUserChannelsRequest(value: any): value is GetUserChannelsRequest { + return value != null && value.type === 'getUserChannelsRequest'; +} + +/** + * Returns true if value is a valid GetUserChannelsRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetUserChannelsRequest(value: any): value is GetUserChannelsRequest { try { Convert.getUserChannelsRequestToJson(value); return true; @@ -6351,7 +6672,17 @@ export function isGetUserChannelsRequest(value: any): value is GetUserChannelsRe export const GET_USER_CHANNELS_REQUEST_TYPE = "GetUserChannelsRequest"; +/** + * Returns true if the value has a type property with value 'getUserChannelsResponse'. This is a fast check that does not check the format of the message + */ export function isGetUserChannelsResponse(value: any): value is GetUserChannelsResponse { + return value != null && value.type === 'getUserChannelsResponse'; +} + +/** + * Returns true if value is a valid GetUserChannelsResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidGetUserChannelsResponse(value: any): value is GetUserChannelsResponse { try { Convert.getUserChannelsResponseToJson(value); return true; @@ -6362,7 +6693,17 @@ export function isGetUserChannelsResponse(value: any): value is GetUserChannelsR export const GET_USER_CHANNELS_RESPONSE_TYPE = "GetUserChannelsResponse"; +/** + * Returns true if the value has a type property with value 'heartbeatAcknowledgementRequest'. This is a fast check that does not check the format of the message + */ export function isHeartbeatAcknowledgementRequest(value: any): value is HeartbeatAcknowledgementRequest { + return value != null && value.type === 'heartbeatAcknowledgementRequest'; +} + +/** + * Returns true if value is a valid HeartbeatAcknowledgementRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidHeartbeatAcknowledgementRequest(value: any): value is HeartbeatAcknowledgementRequest { try { Convert.heartbeatAcknowledgementRequestToJson(value); return true; @@ -6373,7 +6714,17 @@ export function isHeartbeatAcknowledgementRequest(value: any): value is Heartbea export const HEARTBEAT_ACKNOWLEDGEMENT_REQUEST_TYPE = "HeartbeatAcknowledgementRequest"; +/** + * Returns true if the value has a type property with value 'heartbeatEvent'. This is a fast check that does not check the format of the message + */ export function isHeartbeatEvent(value: any): value is HeartbeatEvent { + return value != null && value.type === 'heartbeatEvent'; +} + +/** + * Returns true if value is a valid HeartbeatEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidHeartbeatEvent(value: any): value is HeartbeatEvent { try { Convert.heartbeatEventToJson(value); return true; @@ -6384,7 +6735,17 @@ export function isHeartbeatEvent(value: any): value is HeartbeatEvent { export const HEARTBEAT_EVENT_TYPE = "HeartbeatEvent"; +/** + * Returns true if the value has a type property with value 'intentEvent'. This is a fast check that does not check the format of the message + */ export function isIntentEvent(value: any): value is IntentEvent { + return value != null && value.type === 'intentEvent'; +} + +/** + * Returns true if value is a valid IntentEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidIntentEvent(value: any): value is IntentEvent { try { Convert.intentEventToJson(value); return true; @@ -6395,7 +6756,17 @@ export function isIntentEvent(value: any): value is IntentEvent { export const INTENT_EVENT_TYPE = "IntentEvent"; +/** + * Returns true if the value has a type property with value 'intentListenerUnsubscribeRequest'. This is a fast check that does not check the format of the message + */ export function isIntentListenerUnsubscribeRequest(value: any): value is IntentListenerUnsubscribeRequest { + return value != null && value.type === 'intentListenerUnsubscribeRequest'; +} + +/** + * Returns true if value is a valid IntentListenerUnsubscribeRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidIntentListenerUnsubscribeRequest(value: any): value is IntentListenerUnsubscribeRequest { try { Convert.intentListenerUnsubscribeRequestToJson(value); return true; @@ -6406,7 +6777,17 @@ export function isIntentListenerUnsubscribeRequest(value: any): value is IntentL export const INTENT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = "IntentListenerUnsubscribeRequest"; +/** + * Returns true if the value has a type property with value 'intentListenerUnsubscribeResponse'. This is a fast check that does not check the format of the message + */ export function isIntentListenerUnsubscribeResponse(value: any): value is IntentListenerUnsubscribeResponse { + return value != null && value.type === 'intentListenerUnsubscribeResponse'; +} + +/** + * Returns true if value is a valid IntentListenerUnsubscribeResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidIntentListenerUnsubscribeResponse(value: any): value is IntentListenerUnsubscribeResponse { try { Convert.intentListenerUnsubscribeResponseToJson(value); return true; @@ -6417,7 +6798,17 @@ export function isIntentListenerUnsubscribeResponse(value: any): value is Intent export const INTENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "IntentListenerUnsubscribeResponse"; +/** + * Returns true if the value has a type property with value 'intentResultRequest'. This is a fast check that does not check the format of the message + */ export function isIntentResultRequest(value: any): value is IntentResultRequest { + return value != null && value.type === 'intentResultRequest'; +} + +/** + * Returns true if value is a valid IntentResultRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidIntentResultRequest(value: any): value is IntentResultRequest { try { Convert.intentResultRequestToJson(value); return true; @@ -6428,7 +6819,17 @@ export function isIntentResultRequest(value: any): value is IntentResultRequest export const INTENT_RESULT_REQUEST_TYPE = "IntentResultRequest"; +/** + * Returns true if the value has a type property with value 'intentResultResponse'. This is a fast check that does not check the format of the message + */ export function isIntentResultResponse(value: any): value is IntentResultResponse { + return value != null && value.type === 'intentResultResponse'; +} + +/** + * Returns true if value is a valid IntentResultResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidIntentResultResponse(value: any): value is IntentResultResponse { try { Convert.intentResultResponseToJson(value); return true; @@ -6439,7 +6840,17 @@ export function isIntentResultResponse(value: any): value is IntentResultRespons export const INTENT_RESULT_RESPONSE_TYPE = "IntentResultResponse"; +/** + * Returns true if the value has a type property with value 'joinUserChannelRequest'. This is a fast check that does not check the format of the message + */ export function isJoinUserChannelRequest(value: any): value is JoinUserChannelRequest { + return value != null && value.type === 'joinUserChannelRequest'; +} + +/** + * Returns true if value is a valid JoinUserChannelRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidJoinUserChannelRequest(value: any): value is JoinUserChannelRequest { try { Convert.joinUserChannelRequestToJson(value); return true; @@ -6450,7 +6861,17 @@ export function isJoinUserChannelRequest(value: any): value is JoinUserChannelRe export const JOIN_USER_CHANNEL_REQUEST_TYPE = "JoinUserChannelRequest"; +/** + * Returns true if the value has a type property with value 'joinUserChannelResponse'. This is a fast check that does not check the format of the message + */ export function isJoinUserChannelResponse(value: any): value is JoinUserChannelResponse { + return value != null && value.type === 'joinUserChannelResponse'; +} + +/** + * Returns true if value is a valid JoinUserChannelResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidJoinUserChannelResponse(value: any): value is JoinUserChannelResponse { try { Convert.joinUserChannelResponseToJson(value); return true; @@ -6461,7 +6882,17 @@ export function isJoinUserChannelResponse(value: any): value is JoinUserChannelR export const JOIN_USER_CHANNEL_RESPONSE_TYPE = "JoinUserChannelResponse"; +/** + * Returns true if the value has a type property with value 'leaveCurrentChannelRequest'. This is a fast check that does not check the format of the message + */ export function isLeaveCurrentChannelRequest(value: any): value is LeaveCurrentChannelRequest { + return value != null && value.type === 'leaveCurrentChannelRequest'; +} + +/** + * Returns true if value is a valid LeaveCurrentChannelRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidLeaveCurrentChannelRequest(value: any): value is LeaveCurrentChannelRequest { try { Convert.leaveCurrentChannelRequestToJson(value); return true; @@ -6472,7 +6903,17 @@ export function isLeaveCurrentChannelRequest(value: any): value is LeaveCurrentC export const LEAVE_CURRENT_CHANNEL_REQUEST_TYPE = "LeaveCurrentChannelRequest"; +/** + * Returns true if the value has a type property with value 'leaveCurrentChannelResponse'. This is a fast check that does not check the format of the message + */ export function isLeaveCurrentChannelResponse(value: any): value is LeaveCurrentChannelResponse { + return value != null && value.type === 'leaveCurrentChannelResponse'; +} + +/** + * Returns true if value is a valid LeaveCurrentChannelResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidLeaveCurrentChannelResponse(value: any): value is LeaveCurrentChannelResponse { try { Convert.leaveCurrentChannelResponseToJson(value); return true; @@ -6483,7 +6924,17 @@ export function isLeaveCurrentChannelResponse(value: any): value is LeaveCurrent export const LEAVE_CURRENT_CHANNEL_RESPONSE_TYPE = "LeaveCurrentChannelResponse"; +/** + * Returns true if the value has a type property with value 'openRequest'. This is a fast check that does not check the format of the message + */ export function isOpenRequest(value: any): value is OpenRequest { + return value != null && value.type === 'openRequest'; +} + +/** + * Returns true if value is a valid OpenRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidOpenRequest(value: any): value is OpenRequest { try { Convert.openRequestToJson(value); return true; @@ -6494,7 +6945,17 @@ export function isOpenRequest(value: any): value is OpenRequest { export const OPEN_REQUEST_TYPE = "OpenRequest"; +/** + * Returns true if the value has a type property with value 'openResponse'. This is a fast check that does not check the format of the message + */ export function isOpenResponse(value: any): value is OpenResponse { + return value != null && value.type === 'openResponse'; +} + +/** + * Returns true if value is a valid OpenResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidOpenResponse(value: any): value is OpenResponse { try { Convert.openResponseToJson(value); return true; @@ -6505,7 +6966,17 @@ export function isOpenResponse(value: any): value is OpenResponse { export const OPEN_RESPONSE_TYPE = "OpenResponse"; +/** + * Returns true if the value has a type property with value 'privateChannelAddEventListenerRequest'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelAddEventListenerRequest(value: any): value is PrivateChannelAddEventListenerRequest { + return value != null && value.type === 'privateChannelAddEventListenerRequest'; +} + +/** + * Returns true if value is a valid PrivateChannelAddEventListenerRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelAddEventListenerRequest(value: any): value is PrivateChannelAddEventListenerRequest { try { Convert.privateChannelAddEventListenerRequestToJson(value); return true; @@ -6516,7 +6987,17 @@ export function isPrivateChannelAddEventListenerRequest(value: any): value is Pr export const PRIVATE_CHANNEL_ADD_EVENT_LISTENER_REQUEST_TYPE = "PrivateChannelAddEventListenerRequest"; +/** + * Returns true if the value has a type property with value 'privateChannelAddEventListenerResponse'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelAddEventListenerResponse(value: any): value is PrivateChannelAddEventListenerResponse { + return value != null && value.type === 'privateChannelAddEventListenerResponse'; +} + +/** + * Returns true if value is a valid PrivateChannelAddEventListenerResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelAddEventListenerResponse(value: any): value is PrivateChannelAddEventListenerResponse { try { Convert.privateChannelAddEventListenerResponseToJson(value); return true; @@ -6527,7 +7008,17 @@ export function isPrivateChannelAddEventListenerResponse(value: any): value is P export const PRIVATE_CHANNEL_ADD_EVENT_LISTENER_RESPONSE_TYPE = "PrivateChannelAddEventListenerResponse"; +/** + * Returns true if the value has a type property with value 'privateChannelDisconnectRequest'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelDisconnectRequest(value: any): value is PrivateChannelDisconnectRequest { + return value != null && value.type === 'privateChannelDisconnectRequest'; +} + +/** + * Returns true if value is a valid PrivateChannelDisconnectRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelDisconnectRequest(value: any): value is PrivateChannelDisconnectRequest { try { Convert.privateChannelDisconnectRequestToJson(value); return true; @@ -6538,7 +7029,17 @@ export function isPrivateChannelDisconnectRequest(value: any): value is PrivateC export const PRIVATE_CHANNEL_DISCONNECT_REQUEST_TYPE = "PrivateChannelDisconnectRequest"; +/** + * Returns true if the value has a type property with value 'privateChannelDisconnectResponse'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelDisconnectResponse(value: any): value is PrivateChannelDisconnectResponse { + return value != null && value.type === 'privateChannelDisconnectResponse'; +} + +/** + * Returns true if value is a valid PrivateChannelDisconnectResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelDisconnectResponse(value: any): value is PrivateChannelDisconnectResponse { try { Convert.privateChannelDisconnectResponseToJson(value); return true; @@ -6549,7 +7050,17 @@ export function isPrivateChannelDisconnectResponse(value: any): value is Private export const PRIVATE_CHANNEL_DISCONNECT_RESPONSE_TYPE = "PrivateChannelDisconnectResponse"; +/** + * Returns true if the value has a type property with value 'privateChannelOnAddContextListenerEvent'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelOnAddContextListenerEvent(value: any): value is PrivateChannelOnAddContextListenerEvent { + return value != null && value.type === 'privateChannelOnAddContextListenerEvent'; +} + +/** + * Returns true if value is a valid PrivateChannelOnAddContextListenerEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelOnAddContextListenerEvent(value: any): value is PrivateChannelOnAddContextListenerEvent { try { Convert.privateChannelOnAddContextListenerEventToJson(value); return true; @@ -6560,7 +7071,17 @@ export function isPrivateChannelOnAddContextListenerEvent(value: any): value is export const PRIVATE_CHANNEL_ON_ADD_CONTEXT_LISTENER_EVENT_TYPE = "PrivateChannelOnAddContextListenerEvent"; +/** + * Returns true if the value has a type property with value 'privateChannelOnDisconnectEvent'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelOnDisconnectEvent(value: any): value is PrivateChannelOnDisconnectEvent { + return value != null && value.type === 'privateChannelOnDisconnectEvent'; +} + +/** + * Returns true if value is a valid PrivateChannelOnDisconnectEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelOnDisconnectEvent(value: any): value is PrivateChannelOnDisconnectEvent { try { Convert.privateChannelOnDisconnectEventToJson(value); return true; @@ -6571,7 +7092,17 @@ export function isPrivateChannelOnDisconnectEvent(value: any): value is PrivateC export const PRIVATE_CHANNEL_ON_DISCONNECT_EVENT_TYPE = "PrivateChannelOnDisconnectEvent"; +/** + * Returns true if the value has a type property with value 'privateChannelOnUnsubscribeEvent'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelOnUnsubscribeEvent(value: any): value is PrivateChannelOnUnsubscribeEvent { + return value != null && value.type === 'privateChannelOnUnsubscribeEvent'; +} + +/** + * Returns true if value is a valid PrivateChannelOnUnsubscribeEvent. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelOnUnsubscribeEvent(value: any): value is PrivateChannelOnUnsubscribeEvent { try { Convert.privateChannelOnUnsubscribeEventToJson(value); return true; @@ -6582,7 +7113,17 @@ export function isPrivateChannelOnUnsubscribeEvent(value: any): value is Private export const PRIVATE_CHANNEL_ON_UNSUBSCRIBE_EVENT_TYPE = "PrivateChannelOnUnsubscribeEvent"; +/** + * Returns true if the value has a type property with value 'privateChannelUnsubscribeEventListenerRequest'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelUnsubscribeEventListenerRequest(value: any): value is PrivateChannelUnsubscribeEventListenerRequest { + return value != null && value.type === 'privateChannelUnsubscribeEventListenerRequest'; +} + +/** + * Returns true if value is a valid PrivateChannelUnsubscribeEventListenerRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelUnsubscribeEventListenerRequest(value: any): value is PrivateChannelUnsubscribeEventListenerRequest { try { Convert.privateChannelUnsubscribeEventListenerRequestToJson(value); return true; @@ -6593,7 +7134,17 @@ export function isPrivateChannelUnsubscribeEventListenerRequest(value: any): val export const PRIVATE_CHANNEL_UNSUBSCRIBE_EVENT_LISTENER_REQUEST_TYPE = "PrivateChannelUnsubscribeEventListenerRequest"; +/** + * Returns true if the value has a type property with value 'privateChannelUnsubscribeEventListenerResponse'. This is a fast check that does not check the format of the message + */ export function isPrivateChannelUnsubscribeEventListenerResponse(value: any): value is PrivateChannelUnsubscribeEventListenerResponse { + return value != null && value.type === 'privateChannelUnsubscribeEventListenerResponse'; +} + +/** + * Returns true if value is a valid PrivateChannelUnsubscribeEventListenerResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidPrivateChannelUnsubscribeEventListenerResponse(value: any): value is PrivateChannelUnsubscribeEventListenerResponse { try { Convert.privateChannelUnsubscribeEventListenerResponseToJson(value); return true; @@ -6604,7 +7155,17 @@ export function isPrivateChannelUnsubscribeEventListenerResponse(value: any): va export const PRIVATE_CHANNEL_UNSUBSCRIBE_EVENT_LISTENER_RESPONSE_TYPE = "PrivateChannelUnsubscribeEventListenerResponse"; +/** + * Returns true if the value has a type property with value 'raiseIntentForContextRequest'. This is a fast check that does not check the format of the message + */ export function isRaiseIntentForContextRequest(value: any): value is RaiseIntentForContextRequest { + return value != null && value.type === 'raiseIntentForContextRequest'; +} + +/** + * Returns true if value is a valid RaiseIntentForContextRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidRaiseIntentForContextRequest(value: any): value is RaiseIntentForContextRequest { try { Convert.raiseIntentForContextRequestToJson(value); return true; @@ -6615,7 +7176,17 @@ export function isRaiseIntentForContextRequest(value: any): value is RaiseIntent export const RAISE_INTENT_FOR_CONTEXT_REQUEST_TYPE = "RaiseIntentForContextRequest"; +/** + * Returns true if the value has a type property with value 'raiseIntentForContextResponse'. This is a fast check that does not check the format of the message + */ export function isRaiseIntentForContextResponse(value: any): value is RaiseIntentForContextResponse { + return value != null && value.type === 'raiseIntentForContextResponse'; +} + +/** + * Returns true if value is a valid RaiseIntentForContextResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidRaiseIntentForContextResponse(value: any): value is RaiseIntentForContextResponse { try { Convert.raiseIntentForContextResponseToJson(value); return true; @@ -6626,7 +7197,17 @@ export function isRaiseIntentForContextResponse(value: any): value is RaiseInten export const RAISE_INTENT_FOR_CONTEXT_RESPONSE_TYPE = "RaiseIntentForContextResponse"; +/** + * Returns true if the value has a type property with value 'raiseIntentRequest'. This is a fast check that does not check the format of the message + */ export function isRaiseIntentRequest(value: any): value is RaiseIntentRequest { + return value != null && value.type === 'raiseIntentRequest'; +} + +/** + * Returns true if value is a valid RaiseIntentRequest. This checks the type against the json schema for the message and will be slower + */ +export function isValidRaiseIntentRequest(value: any): value is RaiseIntentRequest { try { Convert.raiseIntentRequestToJson(value); return true; @@ -6637,7 +7218,17 @@ export function isRaiseIntentRequest(value: any): value is RaiseIntentRequest { export const RAISE_INTENT_REQUEST_TYPE = "RaiseIntentRequest"; +/** + * Returns true if the value has a type property with value 'raiseIntentResponse'. This is a fast check that does not check the format of the message + */ export function isRaiseIntentResponse(value: any): value is RaiseIntentResponse { + return value != null && value.type === 'raiseIntentResponse'; +} + +/** + * Returns true if value is a valid RaiseIntentResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidRaiseIntentResponse(value: any): value is RaiseIntentResponse { try { Convert.raiseIntentResponseToJson(value); return true; @@ -6648,7 +7239,17 @@ export function isRaiseIntentResponse(value: any): value is RaiseIntentResponse export const RAISE_INTENT_RESPONSE_TYPE = "RaiseIntentResponse"; +/** + * Returns true if the value has a type property with value 'raiseIntentResultResponse'. This is a fast check that does not check the format of the message + */ export function isRaiseIntentResultResponse(value: any): value is RaiseIntentResultResponse { + return value != null && value.type === 'raiseIntentResultResponse'; +} + +/** + * Returns true if value is a valid RaiseIntentResultResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidRaiseIntentResultResponse(value: any): value is RaiseIntentResultResponse { try { Convert.raiseIntentResultResponseToJson(value); return true; @@ -6659,7 +7260,17 @@ export function isRaiseIntentResultResponse(value: any): value is RaiseIntentRes export const RAISE_INTENT_RESULT_RESPONSE_TYPE = "RaiseIntentResultResponse"; +/** + * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + return value != null && value.type === 'WCP1Hello'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { try { Convert.webConnectionProtocol1HelloToJson(value); return true; @@ -6670,7 +7281,17 @@ export function isWebConnectionProtocol1Hello(value: any): value is WebConnectio export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = "WebConnectionProtocol1Hello"; +/** + * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + return value != null && value.type === 'WCP2LoadUrl'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { try { Convert.webConnectionProtocol2LoadURLToJson(value); return true; @@ -6681,7 +7302,17 @@ export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnect export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = "WebConnectionProtocol2LoadURL"; +/** + * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + return value != null && value.type === 'WCP3Handshake'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { try { Convert.webConnectionProtocol3HandshakeToJson(value); return true; @@ -6692,7 +7323,17 @@ export function isWebConnectionProtocol3Handshake(value: any): value is WebConne export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = "WebConnectionProtocol3Handshake"; +/** + * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { + return value != null && value.type === 'WCP4ValidateAppIdentity'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { try { Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); return true; @@ -6703,7 +7344,17 @@ export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value i export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = "WebConnectionProtocol4ValidateAppIdentity"; +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { try { Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); return true; @@ -6714,7 +7365,17 @@ export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentityFailedResponse"; +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { try { Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); return true; @@ -6725,7 +7386,17 @@ export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentitySuccessResponse"; +/** + * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message + */ export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + return value != null && value.type === 'WCP6Goodbye'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { try { Convert.webConnectionProtocol6GoodbyeToJson(value); return true; @@ -6736,7 +7407,10 @@ export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnect export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = "WebConnectionProtocol6Goodbye"; -export function isWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { +/** + * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { try { Convert.webConnectionProtocolMessageToJson(value); return true; @@ -6745,91 +7419,4 @@ export function isWebConnectionProtocolMessage(value: any): value is WebConnecti } } -export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; - -export type RequestMessage = AddContextListenerRequest | AddEventListenerRequest | AddIntentListenerRequest | BroadcastRequest | ContextListenerUnsubscribeRequest | CreatePrivateChannelRequest | EventListenerUnsubscribeRequest | FindInstancesRequest | FindIntentRequest | FindIntentsByContextRequest | GetAppMetadataRequest | GetCurrentChannelRequest | GetCurrentContextRequest | GetInfoRequest | GetOrCreateChannelRequest | GetUserChannelsRequest | HeartbeatAcknowledgementRequest | IntentListenerUnsubscribeRequest | IntentResultRequest | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest | PrivateChannelAddEventListenerRequest | PrivateChannelDisconnectRequest | PrivateChannelUnsubscribeEventListenerRequest | RaiseIntentForContextRequest | RaiseIntentRequest; - -export type ResponseMessage = AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse | WebConnectionProtocol5ValidateAppIdentityFailedResponse | WebConnectionProtocol5ValidateAppIdentitySuccessResponse; - -export type EventMessage = BroadcastEvent | ChannelChangedEvent | HeartbeatEvent | IntentEvent | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnDisconnectEvent | PrivateChannelOnUnsubscribeEvent; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; diff --git a/packages/fdc3-schema/schemas/api/api.schema.json b/packages/fdc3-schema/schemas/api/api.schema.json index 7f1fcf0ad..3aea24fac 100644 --- a/packages/fdc3-schema/schemas/api/api.schema.json +++ b/packages/fdc3-schema/schemas/api/api.schema.json @@ -529,6 +529,33 @@ }, "required":["type","details"], "additionalProperties": false + }, + "PrivateChannelEventType": { + "title": "PrivateChannel Event Type", + "description": "Type defining valid type strings for Private Channel events.", + "type": "string", + "enum": [ + "addContextListener", + "unsubscribe", + "disconnect" + ] + }, + "PrivateChannelEvent": { + "description": "Type defining the format of event objects that may be received via a PrivateChannel's addEventListener function.", + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/PrivateChannelEventType" + }, + "details": { + "title": "Event details", + "description": "Additional details of the event, such as the `currentChannelId` for a CHANNEL_CHANGED event.", + "type": "object", + "additionalProperties": true + } + }, + "required":["type","details"], + "additionalProperties": false } } } \ No newline at end of file diff --git a/packages/fdc3-schema/schemas/api/common.schema.json b/packages/fdc3-schema/schemas/api/common.schema.json index 50c6c274a..6c35a4704 100644 --- a/packages/fdc3-schema/schemas/api/common.schema.json +++ b/packages/fdc3-schema/schemas/api/common.schema.json @@ -54,16 +54,6 @@ "$ref": "api.schema.json#/definitions/BridgingError" } ] - }, - "PrivateChannelEventListenerTypes": { - "title": "Private Channel Event Listener Types", - "description": "Event listener type names for Private Channel events.", - "type": "string", - "enum": [ - "onAddContextListener", - "onUnsubscribe", - "onDisconnect" - ] } } } \ No newline at end of file diff --git a/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json b/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json index 72057d724..7cc8a3b37 100644 --- a/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json +++ b/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerRequest.schema.json @@ -28,7 +28,7 @@ "const": "privateChannelAddEventListenerRequest" }, "PrivateChannelAddEventListenerRequestPayload": { - "title": "privateChannelAddEventListener Event Payload", + "title": "PrivateChannelAddEventListener Request Payload", "type": "object", "properties": { "privateChannelId": { @@ -40,12 +40,11 @@ "title": "Event listener type", "description": "The type of PrivateChannel event that the listener should be applied to, or null for all event types.", "oneOf" : [ - { "$ref": "common.schema.json#/$defs/PrivateChannelEventListenerTypes" }, + { "$ref": "api.schema.json#/definitions/PrivateChannelEventType" }, { "type": "null" } ] - } }, "additionalProperties": false, diff --git a/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerResponse.schema.json b/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerResponse.schema.json index 45564b339..a02fc50bd 100644 --- a/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerResponse.schema.json +++ b/packages/fdc3-schema/schemas/api/privateChannelAddEventListenerResponse.schema.json @@ -44,7 +44,8 @@ }, "required": [ "listenerUUID" - ] + ], + "additionalProperties": false }, "PrivateChannelAddEventListenerErrorResponsePayload": { "title": "PrivateChannelAddEventListener Error Response Payload", diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index b74774099..5a398bf5c 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -4,8 +4,9 @@ import { Context } from "@kite9/fdc3-context"; import { AppIdentifier, ChannelError, DisplayMetadata } from "@kite9/fdc3-standard"; import { successResponse, errorResponse, onlyUnique } from "./support"; import { BrowserTypes } from "@kite9/fdc3-schema"; +import { PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -type PrivateChannelEventListenerTypes = BrowserTypes.PrivateChannelEventListenerTypes +type PrivateChannelEventType = BrowserTypes.PrivateChannelEventType type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest type BroadcastRequest = BrowserTypes.BroadcastRequest type ContextListenerUnsubscribeRequest = BrowserTypes.ContextListenerUnsubscribeRequest @@ -21,6 +22,8 @@ type GetCurrentChannelRequest = BrowserTypes.GetCurrentChannelRequest type AgentEventMessage = BrowserTypes.AgentEventMessage type CreatePrivateChannelRequest = BrowserTypes.CreatePrivateChannelRequest +type PrivateChannelEvents = PrivateChannelOnAddContextListenerEvent | PrivateChannelOnUnsubscribeEvent | PrivateChannelOnDisconnectEvent; + type ContextListenerRegistration = { appId: string, instanceId: string, @@ -30,13 +33,11 @@ type ContextListenerRegistration = { userChannelListener: boolean } -type NotificationAgentEventMessage = 'privateChannelOnAddContextListenerEvent' | 'privateChannelOnDisconnectEvent' | 'privateChannelOnUnsubscribeEvent' - type PrivateChannelEventListener = { appId: string, instanceId: string, channelId: string, - eventType: PrivateChannelEventListenerTypes, + eventType: PrivateChannelEventType, listenerUuid: string } @@ -137,7 +138,7 @@ export class BroadcastHandler implements MessageHandler { case 'privateChannelAddEventListenerRequest': return this.handlePrivateChannelAddEventListenerRequest(msg as PrivateChannelAddEventListenerRequest, from, sc) case 'privateChannelUnsubscribeEventListenerRequest': return this.handlePrivateChannelUnsubscribeEventListenerRequest(msg as PrivateChannelUnsubscribeEventListenerRequest, sc, from) - // handling state synchronisation of channels + // handling state synchronization of channels case 'getCurrentContextRequest': return this.handleGetCurrentContextRequest(msg as GetCurrentContextRequest, sc, from) } } catch (e: any) { @@ -187,11 +188,11 @@ export class BroadcastHandler implements MessageHandler { .filter(r => r.channelId == arg0.payload.channelId) toUnsubscribe.forEach(u => { - this.invokeEventListeners(arg0.payload.channelId, "onUnsubscribe", 'privateChannelOnUnsubscribeEvent', sc, u.contextType ?? undefined) + this.invokePrivateChannelEventListeners(arg0.payload.channelId, "unsubscribe", 'privateChannelOnUnsubscribeEvent', sc, u.contextType ?? undefined) }) this.contextListeners = this.contextListeners.filter(r => !toUnsubscribe.includes(r)) - this.invokeEventListeners(arg0.payload.channelId, "onDisconnect", 'privateChannelOnDisconnectEvent', sc) + this.invokePrivateChannelEventListeners(arg0.payload.channelId, "disconnect", 'privateChannelOnDisconnectEvent', sc) successResponse(sc, arg0, from, {}, 'privateChannelDisconnectResponse') } @@ -202,7 +203,7 @@ export class BroadcastHandler implements MessageHandler { if (i > -1) { const rl = this.contextListeners[i] const channel = this.getChannelById(rl.channelId) - this.invokeEventListeners(channel?.id ?? null, "onUnsubscribe", 'privateChannelOnUnsubscribeEvent', sc, rl.contextType ?? undefined) + this.invokePrivateChannelEventListeners(channel?.id ?? null, "unsubscribe", 'privateChannelOnUnsubscribeEvent', sc, rl.contextType ?? undefined) this.contextListeners.splice(i, 1) successResponse(sc, arg0, from, {}, 'contextListenerUnsubscribeResponse') } else { @@ -236,7 +237,7 @@ export class BroadcastHandler implements MessageHandler { } this.contextListeners.push(lr) - this.invokeEventListeners(channelId, "onAddContextListener", "privateChannelOnAddContextListenerEvent", sc, arg0.payload.contextType ?? undefined) + this.invokePrivateChannelEventListeners(channelId, "addContextListener", "privateChannelOnAddContextListenerEvent", sc, arg0.payload.contextType ?? undefined) successResponse(sc, arg0, from, { listenerUUID: lr.listenerUuid }, 'addContextListenerResponse') } @@ -351,7 +352,7 @@ export class BroadcastHandler implements MessageHandler { } } - invokeEventListeners(privateChannelId: string | null, eventType: PrivateChannelEventListenerTypes, messageType: NotificationAgentEventMessage, sc: ServerContext, contextType?: string) { + invokePrivateChannelEventListeners(privateChannelId: string | null, eventType: PrivateChannelEventType, messageType: PrivateChannelEvents["type"], sc: ServerContext, contextType?: string) { if (privateChannelId) { const msg = { type: messageType, From 59ad838cc6239e225c0a95f972f845e93d449834 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 28 Nov 2024 16:34:48 +0000 Subject: [PATCH 14/90] Better logging in getAgent --- packages/fdc3-get-agent/src/index.ts | 1 - .../src/messaging/MessagePortMessaging.ts | 1 - .../src/messaging/message-port.ts | 6 ++++ .../src/sessionStorage/DesktopAgentDetails.ts | 8 +++-- .../strategies/DesktopAgentPreloadLoader.ts | 21 ++++++++++++- .../src/strategies/FailoverHandler.ts | 5 ++-- .../src/strategies/HelloHandler.ts | 17 ++++++++--- .../strategies/IdentityValidationHandler.ts | 23 +++++++++----- .../src/strategies/PostMessageLoader.ts | 30 +++++++++++++++---- .../fdc3-get-agent/src/strategies/getAgent.ts | 28 ++++++++++++----- packages/fdc3-get-agent/src/util/Logger.ts | 21 +++++++++++++ 11 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 packages/fdc3-get-agent/src/util/Logger.ts diff --git a/packages/fdc3-get-agent/src/index.ts b/packages/fdc3-get-agent/src/index.ts index 78a7831b9..865ba0d9b 100644 --- a/packages/fdc3-get-agent/src/index.ts +++ b/packages/fdc3-get-agent/src/index.ts @@ -2,7 +2,6 @@ import { DesktopAgent } from '@kite9/fdc3-standard' import { getAgent } from './strategies/getAgent'; const DEFAULT_WAIT_FOR_MS = 20000; - export { getAgent } /** diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 2443c1409..c072e3ffc 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -67,7 +67,6 @@ export class MessagePortMessaging extends AbstractMessaging { } async disconnect(): Promise { - await this.disconnect() this.cd.messagePort.close() } } diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 68b4b7f3c..173ae9893 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -6,6 +6,7 @@ import { DefaultDesktopAgentChannelSelector } from "../ui/DefaultDesktopAgentCha import { NullIntentResolver } from "../ui/NullIntentResolver"; import { NullChannelSelector } from "../ui/NullChannelSelector"; import { ChannelSelector } from "@kite9/fdc3-standard"; +import { Logger } from "../util/Logger"; /** * Given a message port, constructs a desktop agent to communicate via that. @@ -57,8 +58,13 @@ async function populateChannelSelector(cs: ChannelSupport, channelSelector: Chan function handleDisconnectOnPageHide(da: DesktopAgent) { globalThis.window.addEventListener("pagehide", (event) => { + Logger.log(`Received pagehide event with persisted ${event.persisted}`); + //the page is being destroyed, disconnect from the DA if (!event.persisted) { + //TODO: send WCP6Goodbye + + //TODO: change this to more directly close the MessagePort if ((da as any).disconnect) { (da as any).disconnect(); } diff --git a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts index 74856979b..5b865e499 100644 --- a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts +++ b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts @@ -3,6 +3,7 @@ import { DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX, } from '@kite9/fdc3-standard'; import { v4 as uuidv4 } from 'uuid'; +import { Logger } from '../util/Logger'; export function createUUID(): string { return uuidv4(); @@ -25,6 +26,7 @@ export function sessionKey(): string { * reconnection to the same Desktop Agent and to request the same instanceId. */ export function storeDesktopAgentDetails(details: DesktopAgentDetails){ + Logger.debug(`DesktopAgentDetails: Storing Desktop Agent details:`, details); //check if there are existing details in storage to update let detailsToStore = retrieveAllDesktopAgentDetails(); if (!detailsToStore) { @@ -44,7 +46,7 @@ export function retrieveAllDesktopAgentDetails(): Record; } catch (e) { - console.error(`FDC3 connection data couldn't be parsed\nstorage key: ${sessionKey()}\nvalue: ${detailsStr}`); + Logger.error(`DesktopAgentDetails: FDC3 connection data couldn't be parsed\nstorage key: ${sessionKey()}\nvalue: ${detailsStr}`); return null; } } else { @@ -57,7 +59,9 @@ export function retrieveAllDesktopAgentDetails(): Record void) | null = null; /** Overall timeout */ timeout: NodeJS.Timeout | null = null; + + /** Reference to the get fn's Promise's reject call - used when cancelling. */ + rejectFn: ((reason?: any) => void) | null = null; async poll(resolve: (value: DesktopAgentSelection) => void) { if (globalThis.window.fdc3) { + Logger.debug(`DesktopAgentPreloadLoader.get(): Discovered DA through polling...`); this.prepareSelection(globalThis.window.fdc3, resolve); } else { if (!this.done) { @@ -26,6 +31,9 @@ export class DesktopAgentPreloadLoader implements Loader { } async prepareSelection(fdc3: DesktopAgent, resolve: (value: DesktopAgentSelection) => void) { + //note that we've found an agent and will be settling our get promise + this.rejectFn = null; + //stop polling and listening for fdc3Ready this.cancel(); @@ -44,25 +52,31 @@ export class DesktopAgentPreloadLoader implements Loader { }; if (selection.details.instanceId === "unknown"){ - console.warn("The DesktopAgent did not return an instanceId in the app's metadata", implMetadata); + Logger.warn("The DesktopAgent did not return an instanceId in the app's metadata", implMetadata); } resolve(selection); } get(options: GetAgentParams): Promise { + Logger.debug(`DesktopAgentPreloadLoader.get(): Initiating search for Desktop Agent Preload`); return new Promise((resolve, reject) => { + //save reject fn in case we get cancelled + this.rejectFn = reject; + //do an initial check if (globalThis.window.fdc3) { this.prepareSelection(globalThis.window.fdc3, resolve); } else { //setup a timeout so that we can reject if don't find anything this.timeout = setTimeout(() => { + Logger.debug(`DesktopAgentPreloadLoader.get(): timeout`); reject(new Error(AgentError.AgentNotFound)); }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); //listen for the fdc3Ready event this.readyEventHandler = () => { + Logger.debug(`DesktopAgentPreloadLoader.get(): discovered DA through fdc3Ready event`); if (globalThis.window.fdc3) { this.prepareSelection(globalThis.window.fdc3, resolve); } @@ -76,7 +90,12 @@ export class DesktopAgentPreloadLoader implements Loader { } cancel(): void { + Logger.debug("Cleaning up DesktopAgentPreloadLoader"); this.done = true; + if (this.rejectFn){ + this.rejectFn(new Error(AgentError.AgentNotFound)); + this.rejectFn = null; + } if (this.timeout) { clearTimeout(this.timeout); } diff --git a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts index 939441420..a9c145ccc 100644 --- a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts @@ -4,6 +4,7 @@ import { DesktopAgentSelection } from './Loader'; import { v4 as uuidv4 } from 'uuid'; import { HelloHandler } from './HelloHandler'; import { IdentityValidationHandler } from './IdentityValidationHandler'; +import { Logger } from '../util/Logger'; /** TypeGuard for a Desktop Agent */ function isDesktopAgent(da: WindowProxy | DesktopAgent): da is DesktopAgent { @@ -73,7 +74,7 @@ export class FailoverHandler { //send a hello message this.helloHandler.sendWCP1Hello(failoverResult, '*'); } else { - console.error('Failover function returned an invalid result', failoverResult); + Logger.error('Failover function returned an invalid result', failoverResult); throw new Error(AgentError.InvalidFailover); } } else { @@ -107,7 +108,7 @@ export class FailoverHandler { return desktopAgentSelection; } catch (e) { //identity validation may have failed - console.error("Error during identity validation of Failover", e); + Logger.error("Error during identity validation of Failover", e); throw e; } } diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index dddb7d702..bd858c601 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -7,6 +7,7 @@ import { import { GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; import { ConnectionDetails } from '../messaging/MessagePortMessaging'; import { FDC3_VERSION } from './getAgent'; +import { Logger } from '../util/Logger'; export class HelloHandler { constructor(options: GetAgentParams, connectionAttemptUuid: string, agentType: WebDesktopAgentType = WebDesktopAgentType.ProxyParent) { @@ -63,6 +64,8 @@ export class HelloHandler { * into an iframe instead of working with the parent window. */ openFrame(url: string) { + Logger.debug(`HelloHandler Opening iframe for: ${url}`); + const IFRAME_ID = 'fdc3-communications-embedded-iframe'; // remove an old one if it's there @@ -86,7 +89,7 @@ export class HelloHandler { if (ifrm.contentWindow) { this.sendWCP1Hello(ifrm.contentWindow, '*'); } else { - console.error('iframe does not have a contentWindow, despite firing its load event!'); + Logger.error('iframe does not have a contentWindow, despite firing its load event!'); } }; document.body.appendChild(ifrm); @@ -94,10 +97,14 @@ export class HelloHandler { /** Listen for WCP responses from 'parent' windows and frames and handle them */ listenForHelloResponses(): Promise { + Logger.debug(`HelloHandler: listening for hello responses`); + return new Promise((resolve, _reject) => { // setup listener for message and retrieve JS URL from it this.helloResponseListener = (event: MessageEvent) => { const data = event.data; + Logger.debug(`HelloHandler: received message: ${JSON.stringify(data)}`); + if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { if (isWebConnectionProtocol2LoadURL(data)) { // in this case, we need to load the URL with the embedded Iframe @@ -110,6 +117,8 @@ export class HelloHandler { //n.b event listener remains in place to receive messages from the iframe } else if (isWebConnectionProtocol3Handshake(data)) { + Logger.debug(`HelloHandler: successful handshake`); + resolve({ connectionAttemptUuid: this.connectionAttemptUuid, handshake: data, @@ -123,13 +132,13 @@ export class HelloHandler { //remove the event listener as we've received a messagePort to use this.cancel(); } else { - console.debug( - `Ignoring message unexpected message in HelloHandler (because its not WCP2LoadUrl or WCP3Handshake).`, + Logger.debug( + `Ignoring unexpected message in HelloHandler (because its not WCP2LoadUrl or WCP3Handshake).`, data ); } } else { - console.warn( + Logger.warn( `Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, data ); diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts index 80a4c6f86..2036a7182 100644 --- a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -7,6 +7,7 @@ import { } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { GetAgentParams, AgentError } from '@kite9/fdc3-standard'; import { retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; +import { Logger } from '../util/Logger'; /** Timeout allowed for id validation to occur and for the DA to respond with details. * This is additional to the app's specified timeout for discovery - we have already @@ -54,6 +55,8 @@ export class IdentityValidationHandler { actualUrl, }, }; + Logger.log(`IdentityValidationHandler: sending validation message`, requestMessage); + const persistedDetails = retrieveDesktopAgentDetails(identityUrl); if (persistedDetails) { @@ -69,11 +72,13 @@ export class IdentityValidationHandler { return new Promise((resolve, reject) => { //timeout for id validation only const timeout = setTimeout(() => { + Logger.log(`IdentityValidationHandler: timeout`); + if (this.idValidationResponseListener) { //remove the event listener as we won't proceed further this.messagePort.removeEventListener('message', this.idValidationResponseListener); } - console.error( + Logger.error( `The Desktop Agent didn't respond to ID validation within ${ID_VALIDATION_TIMEOUT / 1000} seconds` ); reject(AgentError.ErrorOnConnect); @@ -82,6 +87,8 @@ export class IdentityValidationHandler { // setup listener for message and retrieve JS URL from it this.idValidationResponseListener = (event: MessageEvent) => { const data = event.data; + Logger.debug(`IdentityValidationHandler: received message`, data); + if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { if (isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(data)) { //passed validation @@ -90,8 +97,8 @@ export class IdentityValidationHandler { //remove the event listener as we've received a messagePort to use this.messagePort.removeEventListener('message', this.idValidationResponseListener); } - console.debug( - `Validated app identity, appId: ${data.payload.appId}, instanceId: ${data.payload.instanceId}` + Logger.debug( + `IdentityValidationHandler: Validated app identity, appId: ${data.payload.appId}, instanceId: ${data.payload.instanceId}` ); resolve(data); @@ -102,19 +109,19 @@ export class IdentityValidationHandler { //remove the event listener as we've received a messagePort to use this.messagePort.removeEventListener('message', this.idValidationResponseListener); } - console.error(`App identity validation failed: ${data.payload.message ?? 'No reason given'}`); + Logger.error(`IdentityValidationHandler: App identity validation failed: ${data.payload.message ?? 'No reason given'}`); reject(AgentError.AccessDenied); } else { - console.debug( - `Ignoring message unexpected message in PostMessageLoader (because its not a WCP5 message).`, + Logger.debug( + `IdentityValidationHandler: Ignoring message unexpected message in PostMessageLoader (because its not a WCP5 message).`, data ); } } else { - console.debug( - `Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, + Logger.debug( + `IdentityValidationHandler: Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, data ); } diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index bcf7a3a20..33ce4f5ae 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -4,6 +4,7 @@ import { v4 as uuidv4 } from 'uuid'; import { DesktopAgentSelection, Loader } from './Loader'; import { HelloHandler } from './HelloHandler'; import { IdentityValidationHandler } from './IdentityValidationHandler'; +import { Logger } from '../util/Logger'; /** * Recursive search for all possible parent frames (windows) that we may @@ -13,6 +14,7 @@ import { IdentityValidationHandler } from './IdentityValidationHandler'; */ function collectPossibleTargets(startWindow: Window, found: Window[]) { _recursePossibleTargets(startWindow, startWindow, found); + Logger.debug(`Possible parent windows/frames found: ${found.length}`); } function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[]) { @@ -21,11 +23,11 @@ function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[] found.push(w); } - if (found.indexOf(w.opener) == -1 && w != startWindow) { + if (found.indexOf(w.opener) == -1 && w.opener != startWindow) { _recursePossibleTargets(startWindow, w.opener, found); } - if (found.indexOf(w.parent) == -1 && w != startWindow) { + if (found.indexOf(w.parent) == -1 && w.parent != startWindow) { _recursePossibleTargets(startWindow, w.parent, found); } } @@ -52,23 +54,29 @@ export class PostMessageLoader implements Loader { /** Initial timeout (released once a MessagePort is received - additional steps are outside timeout) */ timeout: NodeJS.Timeout | null = null; + /** Reference to the get fn's Promise's reject call - used when cancelling. */ + rejectFn: ((reason?: any) => void) | null = null; + get(options: GetAgentParams): Promise { + Logger.debug(`PostMessageLoader.get(): Initiating search for Desktop Agent Proxy`); return new Promise(async (resolve, reject) => { - + //save reject fn in case we get cancelled + this.rejectFn = reject; + //setup a timeout so we can reject if it runs out this.timeout = setTimeout(() => { + Logger.debug(`PostMessageLoader.get(): timeout`); this.cancel(); reject(new Error(AgentError.AgentNotFound)); }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); - this.helloHandler = new HelloHandler(options, this.connectionAttemptUuid); // ok, begin the process const handshakePromise = this.helloHandler.listenForHelloResponses(); if (this.previousUrl) { - console.debug(`Loading previously used adaptor URL: ${this.previousUrl}`); + Logger.debug(`PostMessageLoader.get(): Loading previously used adaptor URL: ${this.previousUrl}`); //skip looking for target parent windows and open an iframe immediately this.helloHandler.openFrame(this.previousUrl); @@ -91,6 +99,9 @@ export class PostMessageLoader implements Loader { // If no WCP3Handshake is ever received this will not resolve const connectionDetails = await handshakePromise; + //prevent us being cancelled + this.rejectFn = null; + //cancel the initial timeout as we got a handshake response if (this.timeout) { clearTimeout(this.timeout); @@ -129,6 +140,14 @@ export class PostMessageLoader implements Loader { } cancel(): void { + Logger.debug("Cleaning up PostMessageLoader"); + + //if we're being cancelled while still running, reject the promise + if (this.rejectFn){ + this.rejectFn(new Error(AgentError.AgentNotFound)); + this.rejectFn = null; + } + //cancel the timeout if (this.timeout) { clearTimeout(this.timeout); @@ -139,6 +158,7 @@ export class PostMessageLoader implements Loader { this.helloHandler.cancel(); } + //TODO Decide if we should NOT do this - there may be a race on timeout cancellations if (this.identityValidationHandler){ this.identityValidationHandler.cancel(); } diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 04f63dfe8..6514315d1 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -4,6 +4,7 @@ import { PostMessageLoader } from './PostMessageLoader'; import { retrieveDesktopAgentDetails, storeDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; import { FailoverHandler } from './FailoverHandler'; import { Loader } from './Loader'; +import { Logger } from '../util/Logger'; export const FDC3_VERSION = "2.2" @@ -30,7 +31,7 @@ export function getAgentPromise(): Promise | null { } function initAgentPromise(options: GetAgentParams): Promise { - + Logger.log("Initiating Desktop Agent discovery..."); let strategies: Loader[]; //Retrieve persisted connection data limit to a previous strategy if one exists @@ -63,14 +64,21 @@ function initAgentPromise(options: GetAgentParams): Promise { ]; } - const promises = strategies.map(s => s.get(options)); - + const promises = strategies.map(s => s.get(options).then((selection) => { + //cancel other strategies if we selected a DA + strategies.forEach(s => s.cancel()); + return selection; + })); + + Logger.debug("Waiting for discovery promises to settle...") return Promise.allSettled(promises) .then(async results => { //review results const daResult = results.find(isFulfilled); + Logger.debug(`Discovery results: ${JSON.stringify(results)}`); if (daResult) { + const selection = daResult.value; const desktopAgentDetails: DesktopAgentDetails = { agentType: selection.details.agentType, @@ -82,11 +90,13 @@ function initAgentPromise(options: GetAgentParams): Promise { instanceUuid: selection.details.instanceUuid }; storeDesktopAgentDetails(desktopAgentDetails); - + Logger.log(`Desktop Agent located via discovery, appId: ${desktopAgentDetails.appId}, instanceId: ${desktopAgentDetails.instanceId}`); return selection.agent; } else { //if we received any error other than AgentError.AgentNotFound, throw it const errors = results.filter(isRejected); + + Logger.debug(`Discovery errors: ${JSON.stringify(errors)}`); const error = errors.find((aRejection) => { aRejection.reason?.message !== AgentError.AgentNotFound; }); @@ -94,6 +104,7 @@ function initAgentPromise(options: GetAgentParams): Promise { throw error; } else if (options.failover != undefined) { + Logger.debug(`Calling failover fn...`); //Proceed with the failover try { //TODO: consider adding a timeout for the failover, to avoid getting stuck here @@ -114,15 +125,16 @@ function initAgentPromise(options: GetAgentParams): Promise { instanceUuid: selection.details.instanceUuid }; storeDesktopAgentDetails(desktopAgentDetails); - + Logger.log(`Desktop Agent located via failover, appId: ${desktopAgentDetails.appId}, instanceId: ${desktopAgentDetails.instanceId}`); + return selection.agent; } catch (e) { - console.error("Desktop agent not found. Error reported during failover", e); + Logger.error("Desktop agent not found. Error reported during failover", e); throw e; } } else { //We didn't manage to find an agent. - console.log("Desktop agent not found. Error reported during discovery", error); + Logger.error("Desktop agent not found. Error reported during discovery", error); throw new Error(AgentError.AgentNotFound); } } @@ -184,6 +196,8 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { return da; }; + Logger.debug(`Got options: ${JSON.stringify(options)}`); + if (!theAgentPromise) { theAgentPromise = initAgentPromise(options).then(handleSetWindowFdc3); } diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts new file mode 100644 index 000000000..9988a7b9e --- /dev/null +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -0,0 +1,21 @@ +const GET_AGENT_LOG_PREFIX = "FDC3 getAgent: "; + +export class Logger { + constructor() {} + + static debug(message?: any, ...optionalParams: any[]) { + console.debug(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + } + + static log(message?: any, ...optionalParams: any[]) { + console.log(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + } + + static warn(message?: any, ...optionalParams: any[]) { + console.warn(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + } + + static error(message?: any, ...optionalParams: any[]) { + console.error(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + } +} From a54b2f75d67a683ddcfd4aba3faf5e96550c65f3 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 28 Nov 2024 18:02:24 +0000 Subject: [PATCH 15/90] Send WCP6Goodbye on disconnects - inside MessagePortMessaging --- .../src/heartbeat/DefaultHeartbeatSupport.ts | 7 ------ .../src/messaging/MessagePortMessaging.ts | 9 ++++++- .../src/messaging/message-port.ts | 25 +++++++++++++------ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts index 22eee5db2..80206258c 100644 --- a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts +++ b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts @@ -22,13 +22,6 @@ export class DefaultHeartbeatSupport implements HeartbeatSupport { async disconnect(): Promise { await this.heartbeatListener?.unsubscribe(); - await this.messaging.post({ - type: 'WCP6Goodbye', - meta: { - timestamp: new Date(), - } - } as WebConnectionProtocol6Goodbye); return this.messaging.disconnect(); } - } \ No newline at end of file diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index c072e3ffc..2856e06b0 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -2,7 +2,7 @@ import { AbstractMessaging, RegisterableListener } from "@kite9/fdc3-agent-proxy import { AppIdentifier, GetAgentParams, WebDesktopAgentType } from "@kite9/fdc3-standard" import { v4 as uuidv4 } from "uuid" import { BrowserTypes } from "@kite9/fdc3-schema"; -import { AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AppRequestMessage, WebConnectionProtocol6Goodbye } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake /** @@ -67,6 +67,13 @@ export class MessagePortMessaging extends AbstractMessaging { } async disconnect(): Promise { + await this.post({ + type: 'WCP6Goodbye', + meta: { + timestamp: new Date(), + } + } as WebConnectionProtocol6Goodbye); + this.cd.messagePort.close() } } diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 173ae9893..8035cd3f4 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -7,6 +7,7 @@ import { NullIntentResolver } from "../ui/NullIntentResolver"; import { NullChannelSelector } from "../ui/NullChannelSelector"; import { ChannelSelector } from "@kite9/fdc3-standard"; import { Logger } from "../util/Logger"; +import { WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; /** * Given a message port, constructs a desktop agent to communicate via that. @@ -45,7 +46,7 @@ export async function createDesktopAgentAPI(cd: ConnectionDetails, appIdentifier await populateChannelSelector(cs, channelSelector); - handleDisconnectOnPageHide(da); + handleDisconnectOnPageHide(da, messaging); return da; } @@ -56,18 +57,26 @@ async function populateChannelSelector(cs: ChannelSupport, channelSelector: Chan channelSelector.updateChannel(channel?.id ?? null, userChannels) } -function handleDisconnectOnPageHide(da: DesktopAgent) { - globalThis.window.addEventListener("pagehide", (event) => { +function handleDisconnectOnPageHide(da: DesktopAgent, messaging: MessagePortMessaging) { + globalThis.window.addEventListener("pagehide", async (event) => { Logger.log(`Received pagehide event with persisted ${event.persisted}`); - //the page is being destroyed, disconnect from the DA - if (!event.persisted) { - //TODO: send WCP6Goodbye - - //TODO: change this to more directly close the MessagePort + //If persisted == true then the page is stored and might come back if the user hits back + // In that case don't disconnect and let heartbeat handle that instead + + //TODO: implement disconnect on any hide and reconnect if the page is shown again + // Will have to happen inside the BasicDesktopAgent as the reference to the DA needs to remain the same + // and any listeners need to be re-registered automatically etc. + if (!event.persisted) { + //the page is being destroyed, disconnect from the DA + + //Notify the Desktop Agent implementation to disconnect if ((da as any).disconnect) { (da as any).disconnect(); } + + //disconnect the MessagePort - which should send WCP6Goodbye first + messaging.disconnect(); } }); } From 832349f3678a1d716dbf955cb9c7e0d275d389b9 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 13:03:21 +0000 Subject: [PATCH 16/90] minor tweaks to heartbeats --- .../src/heartbeat/DefaultHeartbeatSupport.ts | 1 - .../src/listeners/HeartbeatListener.ts | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts index 80206258c..18b4546eb 100644 --- a/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts +++ b/packages/fdc3-agent-proxy/src/heartbeat/DefaultHeartbeatSupport.ts @@ -1,4 +1,3 @@ -import { WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { HeartbeatListener } from "../listeners/HeartbeatListener"; import { Messaging } from "../Messaging"; import { HeartbeatSupport } from "./HeartbeatSupport"; diff --git a/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts b/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts index 6ff5b4836..000552c84 100644 --- a/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts @@ -4,16 +4,16 @@ import { RegisterableListener } from "./RegisterableListener"; export class HeartbeatListener implements RegisterableListener { - readonly id: string - readonly messaging: Messaging + readonly id: string; + readonly messaging: Messaging; constructor(messaging: Messaging) { - this.id = "heartbeat-" + messaging.createUUID() - this.messaging = messaging + this.id = "heartbeat-" + messaging.createUUID(); + this.messaging = messaging; } filter(m: any): boolean { - return m.type === "heartbeatEvent" + return m.type === "heartbeatEvent"; } action(_m: any): void { @@ -26,16 +26,16 @@ export class HeartbeatListener implements RegisterableListener { payload: { heartbeatEventUuid: (_m as HeartbeatEvent).meta.eventUuid } - } as HeartbeatAcknowledgementRequest) + } as HeartbeatAcknowledgementRequest); //console.log("Heartbeat acknowledged") } async register(): Promise { - this.messaging.register(this) + this.messaging.register(this); } async unsubscribe(): Promise { - this.messaging.unregister(this.id) + this.messaging.unregister(this.id); } } \ No newline at end of file From f066ffb489d902a5978aa33d251a01b90e0cb1d7 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 13:03:51 +0000 Subject: [PATCH 17/90] typing in UI component handling --- .../src/ui/AbstractUIComponent.ts | 115 ++++++++++-------- .../ui/DefaultDesktopAgentChannelSelector.ts | 18 ++- .../ui/DefaultDesktopAgentIntentResolver.ts | 30 ++--- 3 files changed, 84 insertions(+), 79 deletions(-) diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index 91708b09e..fac2a1d69 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -1,14 +1,14 @@ -import { FDC3_USER_INTERFACE_HANDSHAKE_TYPE, FDC3_USER_INTERFACE_HELLO_TYPE, FDC3_USER_INTERFACE_RESTYLE_TYPE, Fdc3UserInterfaceHello, InitialCSS, UpdatedCSS } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -import { Connectable } from "@kite9/fdc3-standard"; +import { Fdc3UserInterfaceHandshake, InitialCSS, isFdc3UserInterfaceHello, isFdc3UserInterfaceRestyle, UpdatedCSS } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; +import { Connectable, FDC3_VERSION } from "@kite9/fdc3-standard"; +import { Logger } from "../util/Logger"; -export interface CSSPositioning { [key: string]: string } +export interface CSSPositioning { [key: string]: string }; export const INITIAL_CONTAINER_CSS = { width: "0", height: "0", position: "fixed" -} - +}; export const ALLOWED_CSS_ELEMENTS = [ "width", @@ -23,32 +23,30 @@ export const ALLOWED_CSS_ELEMENTS = [ "maxHeight", "maxWidth", "display" -] +]; export abstract class AbstractUIComponent implements Connectable { - - private container: HTMLDivElement | undefined = undefined - private iframe: HTMLIFrameElement | undefined = undefined - private url: string - private name: string - port: MessagePort | null = null + private container: HTMLDivElement | undefined = undefined; + private iframe: HTMLIFrameElement | undefined = undefined; + private url: string; + private name: string; + port: MessagePort | null = null; constructor(url: string, name: string) { - this.url = url - this.name = name + this.url = url; + this.name = name; } async connect() { - const portPromise = this.awaitHello() - this.openFrame() - this.port = await portPromise - await this.setupMessagePort(this.port) - await this.messagePortReady(this.port) - + const portPromise = this.awaitHello(); + this.openFrame(); + this.port = await portPromise; + await this.setupMessagePort(this.port); + await this.messagePortReady(this.port); } async disconnect() { - this.port?.close() + this.port?.close(); } /** @@ -56,51 +54,64 @@ export abstract class AbstractUIComponent implements Connectable { */ async setupMessagePort(port: MessagePort): Promise { port.addEventListener("message", (e) => { - const data = e.data - if (data.type == FDC3_USER_INTERFACE_RESTYLE_TYPE) { + const data = e.data; + + if (isFdc3UserInterfaceRestyle(data)) { // console.log(`Restyling ${JSON.stringify(data.payload)}`) - const css = data.payload.updatedCSS - this.themeContainer(css) + const css = data.payload.updatedCSS; + this.themeContainer(css); } - }) + }); } async messagePortReady(port: MessagePort) { // tells the iframe it can start posting - port.postMessage({ type: FDC3_USER_INTERFACE_HANDSHAKE_TYPE, payload: {} }) + const message: Fdc3UserInterfaceHandshake = { + type: "Fdc3UserInterfaceHandshake", + payload: { + fdc3Version: FDC3_VERSION + } + }; + port.postMessage(message); } private awaitHello(): Promise { return new Promise((resolve, _reject) => { const ml = (e: MessageEvent) => { - // console.log("Received UI Message: " + JSON.stringify(e.data)) - if ((e.source == this.iframe?.contentWindow) && (e.data.type == FDC3_USER_INTERFACE_HELLO_TYPE)) { - const helloData = e.data as Fdc3UserInterfaceHello - if (helloData.payload.initialCSS) { - this.themeContainer(helloData.payload.initialCSS) + if (e.source == this.iframe?.contentWindow) { + if (isFdc3UserInterfaceHello(e.data)){ + Logger.debug("AbstractUIComponent: Received Hello Message from UI iframe: ",e.data) + const helloData = e.data; + if (helloData.payload.initialCSS) { + this.themeContainer(helloData.payload.initialCSS); + } + const port = e.ports[0]; + port.start(); + globalThis.window.removeEventListener("message", ml); + resolve(port); + } else { + Logger.debug("AbstractUIComponent: ignored UI Message from UI iframe while awaiting hello: ",e.data) } - const port = e.ports[0] - port.start() - globalThis.window.removeEventListener("message", ml) - resolve(port) + } else { + Logger.debug("AbstractUIComponent: ignored Message that didn't come from expected UI frame", e.data); } } - globalThis.window.addEventListener("message", ml) + globalThis.window.addEventListener("message", ml); }); } private openFrame(): void { - this.container = globalThis.document.createElement("div") - this.iframe = globalThis.document.createElement("iframe") + this.container = globalThis.document.createElement("div"); + this.iframe = globalThis.document.createElement("iframe"); - this.themeContainer(INITIAL_CONTAINER_CSS) - this.themeFrame(this.iframe) + this.themeContainer(INITIAL_CONTAINER_CSS); + this.themeFrame(this.iframe); - this.iframe.setAttribute("src", this.url) - this.container.appendChild(this.iframe) - document.body.appendChild(this.container) + this.iframe.setAttribute("src", this.url); + this.container.appendChild(this.iframe); + document.body.appendChild(this.container); } private toKebabCase(str: String) { @@ -110,22 +121,22 @@ export abstract class AbstractUIComponent implements Connectable { themeContainer(css: UpdatedCSS | InitialCSS) { if (css) { for (let i = 0; i < ALLOWED_CSS_ELEMENTS.length; i++) { - const k = ALLOWED_CSS_ELEMENTS[i] - const value: string | undefined = css[(k as string)] + const k = ALLOWED_CSS_ELEMENTS[i]; + const value: string | undefined = css[(k as string)]; if (value != null) { - this.container!.style.setProperty(this.toKebabCase(k), value) + this.container!.style.setProperty(this.toKebabCase(k), value); } else { - this.container!.style.removeProperty(this.toKebabCase(k)) + this.container!.style.removeProperty(this.toKebabCase(k)); } } } } themeFrame(ifrm: HTMLIFrameElement) { - ifrm.setAttribute("name", this.name) - ifrm.style.width = "100%" - ifrm.style.height = "100%" - ifrm.style.border = "0" + ifrm.setAttribute("name", this.name); + ifrm.style.width = "100%"; + ifrm.style.height = "100%"; + ifrm.style.border = "0"; } } \ No newline at end of file diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts index 89593adee..82cdde160 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts @@ -1,11 +1,8 @@ import { Channel } from "@kite9/fdc3-standard"; import { ChannelSelector } from "@kite9/fdc3-standard" import { AbstractUIComponent } from "./AbstractUIComponent"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE, FDC3_USER_INTERFACE_CHANNELS_TYPE } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; +import { Fdc3UserInterfaceChannels, isFdc3UserInterfaceChannelSelected } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -type Fdc3UserInterfaceChannels = BrowserTypes.Fdc3UserInterfaceChannels -type Fdc3UserInterfaceChannelSelected = BrowserTypes.Fdc3UserInterfaceChannelSelected /** * Works with the desktop agent to provide a simple channel selector. @@ -26,8 +23,8 @@ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent impl this.port = port port.addEventListener("message", (e) => { - if (e.data.type == FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE) { - const choice = e.data as Fdc3UserInterfaceChannelSelected + if (isFdc3UserInterfaceChannelSelected(e.data)) { + const choice = e.data; if (this.callback) { this.callback(choice.payload.selected) } @@ -36,20 +33,21 @@ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent impl } updateChannel(channelId: string | null, availableChannels: Channel[]): void { - // also send to the iframe - this.port!!.postMessage({ - type: FDC3_USER_INTERFACE_CHANNELS_TYPE, + const message: Fdc3UserInterfaceChannels = { + type: "Fdc3UserInterfaceChannels", payload: { selected: channelId, userChannels: availableChannels.map(ch => { return { id: ch.id, + type: "user", displayMetadata: ch.displayMetadata } }) } - } as Fdc3UserInterfaceChannels) + }; + this.port!.postMessage( message ) } setChannelChangeCallback(callback: (channelId: string | null) => void): void { diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts index d8f5272ee..a4f130642 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts @@ -1,12 +1,9 @@ import { AppIntent } from "@kite9/fdc3-standard"; import { IntentResolver, IntentResolutionChoice } from '@kite9/fdc3-standard' import { AbstractUIComponent } from "./AbstractUIComponent"; -import { BrowserTypes } from "@kite9/fdc3-schema"; import { Context } from "@kite9/fdc3-context"; -import { FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, FDC3_USER_INTERFACE_RESOLVE_TYPE } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; - -type Fdc3UserInterfaceResolveAction = BrowserTypes.Fdc3UserInterfaceResolveAction -type Fdc3UserInterfaceResolve = BrowserTypes.Fdc3UserInterfaceResolve +import { Fdc3UserInterfaceResolve, isFdc3UserInterfaceResolveAction } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; +import { Logger } from "../util/Logger"; /** * Works with the desktop agent to provide a resolution to the intent choices. @@ -26,13 +23,14 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple this.port = port this.port.addEventListener("message", (e) => { - console.log("Got resolve action") - if (e.data.type == FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE) { - const choice = e.data as Fdc3UserInterfaceResolveAction + if (isFdc3UserInterfaceResolveAction(e.data)) { + Logger.debug("DefaultDesktopAgentIntentResolver: Received resolveAction message: ", e.data); + + const choice = e.data; if ((choice.payload.action == 'click') && (this.pendingResolve)) { this.pendingResolve({ - appId: choice.payload.appIdentifier!!, - intent: choice.payload.intent!! + appId: choice.payload.appIdentifier!, + intent: choice.payload.intent! }) } else if ((choice.payload.action == 'cancel') && (this.pendingResolve)) { this.pendingResolve() @@ -47,16 +45,14 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple const out = new Promise((resolve, _reject) => { this.pendingResolve = resolve }) - - - this.port?.postMessage({ - type: FDC3_USER_INTERFACE_RESOLVE_TYPE, + const message: Fdc3UserInterfaceResolve = { + type: "Fdc3UserInterfaceResolve", payload: { appIntents, context } - } as Fdc3UserInterfaceResolve) - - return out + }; + this.port?.postMessage(message); + return out; } } \ No newline at end of file From 9b236ea86b97a67c9cdbf16e4b56c9258ef25c19 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 13:07:49 +0000 Subject: [PATCH 18/90] Add fdc3 version to standard package --- packages/fdc3-standard/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/fdc3-standard/src/index.ts b/packages/fdc3-standard/src/index.ts index f784c1108..349743814 100644 --- a/packages/fdc3-standard/src/index.ts +++ b/packages/fdc3-standard/src/index.ts @@ -34,6 +34,8 @@ export * from './ui/IntentResolver'; export * from './ui/ChannelSelector'; export * from './ui/Connectable' +export const FDC3_VERSION = "2.2"; + declare global { interface Window { fdc3?: DesktopAgent; From 721ba3e7ba23c0cd2c7fcc78df8de89e624ea337 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 13:08:50 +0000 Subject: [PATCH 19/90] Additional logging in getAgent --- .../src/messaging/message-port.ts | 15 +++++++++++-- .../strategies/DesktopAgentPreloadLoader.ts | 11 ++++++---- .../src/strategies/HelloHandler.ts | 6 +++--- .../fdc3-get-agent/src/strategies/Loader.ts | 2 ++ .../src/strategies/PostMessageLoader.ts | 21 ++++++++++++++----- .../fdc3-get-agent/src/strategies/getAgent.ts | 18 +++++++++------- 6 files changed, 51 insertions(+), 22 deletions(-) diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 8035cd3f4..198606d1f 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -7,13 +7,13 @@ import { NullIntentResolver } from "../ui/NullIntentResolver"; import { NullChannelSelector } from "../ui/NullChannelSelector"; import { ChannelSelector } from "@kite9/fdc3-standard"; import { Logger } from "../util/Logger"; -import { WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; /** * Given a message port, constructs a desktop agent to communicate via that. */ export async function createDesktopAgentAPI(cd: ConnectionDetails, appIdentifier: AppIdentifier): Promise { + Logger.debug("message-port: Creating Desktop Agent..."); cd.messagePort.start(); function string(o: string | boolean): string | null { @@ -37,17 +37,28 @@ export async function createDesktopAgentAPI(cd: ConnectionDetails, appIdentifier new DefaultDesktopAgentChannelSelector(string(cd.handshake.payload.channelSelectorUrl)) : new NullChannelSelector(); + Logger.debug("message-port: Setting up support components..."); + const hs = new DefaultHeartbeatSupport(messaging); const cs = new DefaultChannelSupport(messaging, channelSelector); const is = new DefaultIntentSupport(messaging, intentResolver); const as = new DefaultAppSupport(messaging); const da = new BasicDesktopAgent(hs, cs, is, as, [hs, intentResolver, channelSelector]); + + Logger.debug("message-port: Connecting components ..."); + await da.connect(); - + + Logger.debug("message-port: Populating channel selector..."); + await populateChannelSelector(cs, channelSelector); + Logger.debug("message-port: Setting up disconnect handling..."); + handleDisconnectOnPageHide(da, messaging); + Logger.debug("message-port: Returning..."); + return da; } diff --git a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts index 64ff1d339..93c2846f2 100644 --- a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts @@ -9,6 +9,8 @@ import { Logger } from "../util/Logger"; */ export class DesktopAgentPreloadLoader implements Loader { + name = "DesktopAgentPreloadLoader"; + /** Variable used to end polling */ done: boolean = false; /** Reference to the handler for the fdc3Ready event (used to remove it) */ @@ -69,10 +71,11 @@ export class DesktopAgentPreloadLoader implements Loader { this.prepareSelection(globalThis.window.fdc3, resolve); } else { //setup a timeout so that we can reject if don't find anything + const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS; this.timeout = setTimeout(() => { - Logger.debug(`DesktopAgentPreloadLoader.get(): timeout`); - reject(new Error(AgentError.AgentNotFound)); - }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); + Logger.debug(`DesktopAgentPreloadLoader.get(): timeout (${timeoutMs} ms) at ${new Date().toISOString()}`); + reject(AgentError.AgentNotFound); + }, timeoutMs); //listen for the fdc3Ready event this.readyEventHandler = () => { @@ -90,7 +93,7 @@ export class DesktopAgentPreloadLoader implements Loader { } cancel(): void { - Logger.debug("Cleaning up DesktopAgentPreloadLoader"); + Logger.debug("DesktopAgentPreloadLoader: Cleaning up"); this.done = true; if (this.rejectFn){ this.rejectFn(new Error(AgentError.AgentNotFound)); diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index bd858c601..390061a47 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -4,9 +4,8 @@ import { isWebConnectionProtocol2LoadURL, isWebConnectionProtocol3Handshake, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -import { GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; +import { FDC3_VERSION, GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; import { ConnectionDetails } from '../messaging/MessagePortMessaging'; -import { FDC3_VERSION } from './getAgent'; import { Logger } from '../util/Logger'; export class HelloHandler { @@ -56,6 +55,7 @@ export class HelloHandler { }, }; + Logger.debug(`HelloHandler: sending hello message: `, requestMessage); w.postMessage(requestMessage, { targetOrigin: origin }); } @@ -103,7 +103,7 @@ export class HelloHandler { // setup listener for message and retrieve JS URL from it this.helloResponseListener = (event: MessageEvent) => { const data = event.data; - Logger.debug(`HelloHandler: received message: ${JSON.stringify(data)}`); + Logger.debug(`HelloHandler: received message: `, data); if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { if (isWebConnectionProtocol2LoadURL(data)) { diff --git a/packages/fdc3-get-agent/src/strategies/Loader.ts b/packages/fdc3-get-agent/src/strategies/Loader.ts index 135955190..731d34ea7 100644 --- a/packages/fdc3-get-agent/src/strategies/Loader.ts +++ b/packages/fdc3-get-agent/src/strategies/Loader.ts @@ -11,6 +11,8 @@ export interface Loader { get(options: GetAgentParams): Promise; cancel(): void; + + name: string; } /** Specific partial of DesktopAgentDetails defining the details that Loaders diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 33ce4f5ae..8df3cfea6 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -41,6 +41,8 @@ function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[] */ export class PostMessageLoader implements Loader { + name = "PostMessageLoader"; + constructor(previousUrl?: string) { this.previousUrl = previousUrl ?? null; } @@ -64,11 +66,12 @@ export class PostMessageLoader implements Loader { this.rejectFn = reject; //setup a timeout so we can reject if it runs out + const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS; this.timeout = setTimeout(() => { - Logger.debug(`PostMessageLoader.get(): timeout`); + Logger.debug(`PostMessageLoader.get(): timeout (${timeoutMs} ms) at ${new Date().toISOString()}`); this.cancel(); - reject(new Error(AgentError.AgentNotFound)); - }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS); + reject(AgentError.AgentNotFound); + }, timeoutMs); this.helloHandler = new HelloHandler(options, this.connectionAttemptUuid); @@ -114,10 +117,13 @@ export class PostMessageLoader implements Loader { try { const idDetails = await idValidationPromise; + + //resolve const appIdentifier: AppIdentifier = { appId: idDetails.payload.appId, instanceId: idDetails.payload.instanceId }; + const desktopAgentSelection: DesktopAgentSelection = { agent: await createDesktopAgentAPI(connectionDetails, appIdentifier), details: { @@ -131,20 +137,25 @@ export class PostMessageLoader implements Loader { }, }; + //clean up + this.cancel(); + + Logger.debug("PostMessageLoader.get(): Resolving with Desktop Agent selection..."); resolve(desktopAgentSelection); } catch (e) { //id validation may have failed + Logger.error("PostMessageLoader.get(): Id validation failed!",e); reject(e); } }); } cancel(): void { - Logger.debug("Cleaning up PostMessageLoader"); + Logger.debug("PostMessageLoader: Cleaning up"); //if we're being cancelled while still running, reject the promise if (this.rejectFn){ - this.rejectFn(new Error(AgentError.AgentNotFound)); + this.rejectFn(AgentError.AgentNotFound); this.rejectFn = null; } diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 6514315d1..ac2d1a534 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -6,8 +6,6 @@ import { FailoverHandler } from './FailoverHandler'; import { Loader } from './Loader'; import { Logger } from '../util/Logger'; -export const FDC3_VERSION = "2.2" - // TypeGuards used to examine results of Loaders const isRejected = (input: PromiseSettledResult): input is PromiseRejectedResult => input.status === 'rejected' @@ -15,7 +13,6 @@ const isRejected = (input: PromiseSettledResult): input is PromiseRejec const isFulfilled = (input: PromiseSettledResult): input is PromiseFulfilledResult => input.status === 'fulfilled' - /** * For now, we only allow a single call to getAgent per application, so * we keep track of the promise we use here. @@ -31,7 +28,7 @@ export function getAgentPromise(): Promise | null { } function initAgentPromise(options: GetAgentParams): Promise { - Logger.log("Initiating Desktop Agent discovery..."); + Logger.log(`Initiating Desktop Agent discovery at ${new Date().toISOString()}`); let strategies: Loader[]; //Retrieve persisted connection data limit to a previous strategy if one exists @@ -66,7 +63,12 @@ function initAgentPromise(options: GetAgentParams): Promise { const promises = strategies.map(s => s.get(options).then((selection) => { //cancel other strategies if we selected a DA - strategies.forEach(s => s.cancel()); + Logger.log(`Strategy ${s.name} resolved - cleaning up other strategies`); + strategies.forEach(s2 => { + if(s2 !== s) { + s2.cancel(); + } + }); return selection; })); @@ -75,7 +77,7 @@ function initAgentPromise(options: GetAgentParams): Promise { .then(async results => { //review results const daResult = results.find(isFulfilled); - Logger.debug(`Discovery results: ${JSON.stringify(results)}`); + Logger.debug(`Discovery results: `, results); if (daResult) { @@ -98,7 +100,7 @@ function initAgentPromise(options: GetAgentParams): Promise { Logger.debug(`Discovery errors: ${JSON.stringify(errors)}`); const error = errors.find((aRejection) => { - aRejection.reason?.message !== AgentError.AgentNotFound; + aRejection.reason?.message ?? aRejection.reason !== AgentError.AgentNotFound; }); if (error){ throw error; @@ -134,7 +136,7 @@ function initAgentPromise(options: GetAgentParams): Promise { } } else { //We didn't manage to find an agent. - Logger.error("Desktop agent not found. Error reported during discovery", error); + Logger.error("Desktop agent not found. No error reported during discovery."); throw new Error(AgentError.AgentNotFound); } } From 1ea6f9e51342c733087ec21012a44341ef037450 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 19:31:39 +0000 Subject: [PATCH 20/90] minor logging tweaks --- packages/fdc3-get-agent/src/strategies/HelloHandler.ts | 10 ++++++++-- packages/fdc3-get-agent/src/strategies/getAgent.ts | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index 390061a47..d1fbed15a 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -28,6 +28,8 @@ export class HelloHandler { /** If we're asked to load a URL into an iframe, it is stored here to be saved in Session Storage */ agentUrl: string | null = null; + + /** Reference to event listener used for responses from Desktop Agents - * Used to remove them when no longer needed. * Initialized when @@ -64,7 +66,7 @@ export class HelloHandler { * into an iframe instead of working with the parent window. */ openFrame(url: string) { - Logger.debug(`HelloHandler Opening iframe for: ${url}`); + Logger.debug(`HelloHandler Opening iframe for: ${url} on window with name: ${window.name}`); const IFRAME_ID = 'fdc3-communications-embedded-iframe'; @@ -95,11 +97,15 @@ export class HelloHandler { document.body.appendChild(ifrm); } - /** Listen for WCP responses from 'parent' windows and frames and handle them */ + /** Listen for WCP responses from 'parent' windows and frames and handle them. + * Resolves when a response is received. + * @returns A Promise resolving to a set of connectiondetails + */ listenForHelloResponses(): Promise { Logger.debug(`HelloHandler: listening for hello responses`); return new Promise((resolve, _reject) => { + // setup listener for message and retrieve JS URL from it this.helloResponseListener = (event: MessageEvent) => { const data = event.data; diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index ac2d1a534..1be25a916 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -198,7 +198,7 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { return da; }; - Logger.debug(`Got options: ${JSON.stringify(options)}`); + Logger.debug(`GetAgentParams: ${JSON.stringify(options)}`); if (!theAgentPromise) { theAgentPromise = initAgentPromise(options).then(handleSetWindowFdc3); From 5c37064967d97b348c16ce1014a9f684f85db36c Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 19:32:18 +0000 Subject: [PATCH 21/90] minor schema correction in fdc3UserInterfaceResolveAction --- .../schemas/api/fdc3UserInterfaceResolveAction.schema.json | 2 +- packages/fdc3-schema/schemas/api/getInfoResponse.schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fdc3-schema/schemas/api/fdc3UserInterfaceResolveAction.schema.json b/packages/fdc3-schema/schemas/api/fdc3UserInterfaceResolveAction.schema.json index e543e959f..781690976 100644 --- a/packages/fdc3-schema/schemas/api/fdc3UserInterfaceResolveAction.schema.json +++ b/packages/fdc3-schema/schemas/api/fdc3UserInterfaceResolveAction.schema.json @@ -48,7 +48,7 @@ "$ref": "api.schema.json#/definitions/AppIdentifier" }, "action": { - "anyOf": [ + "oneOf": [ { "type": "string", "const": "hover" diff --git a/packages/fdc3-schema/schemas/api/getInfoResponse.schema.json b/packages/fdc3-schema/schemas/api/getInfoResponse.schema.json index a10a7749d..8c7ecc4f5 100644 --- a/packages/fdc3-schema/schemas/api/getInfoResponse.schema.json +++ b/packages/fdc3-schema/schemas/api/getInfoResponse.schema.json @@ -35,7 +35,7 @@ "const": "getInfoResponse" }, "GetInfoSuccessResponsePayload": { - "title": "GetInfo Response Payload", + "title": "GetInfo Success Response Payload", "type": "object", "properties": { "implementationMetadata": { From b95cc6055fd5ea8b48719a18af8ffa32c58499c7 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 19:33:39 +0000 Subject: [PATCH 22/90] iframe adaptor responds to hello message --- .../fdc3-for-web/demo/src/client/da/embed.ts | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index 2b25c4976..02ca58880 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -1,6 +1,7 @@ import { io } from "socket.io-client" import { link, UI, UI_URLS } from "./util"; import { APP_HELLO } from "../../message-types"; +import { isWebConnectionProtocol1Hello, WebConnectionProtocol3Handshake } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; const appWindow = window.parent; @@ -28,7 +29,7 @@ function getSource(): string { return source } -function getDeskopAgentId(): string { +function getDesktopAgentId(): string { const id = getQueryVariable("desktopAgentId") return id } @@ -38,35 +39,43 @@ function getUIKey(): UI { return parseInt(ui) as UI } +//set-up a listener for the WCP1Hello message +const helloHandler = (e) => { + const event = e as MessageEvent + const data = event.data; + // const source = event.source as Window + // const origin = event.origin; + + console.log("Received postMessage: " + JSON.stringify(event.data)); + if (isWebConnectionProtocol1Hello(data)) { + const socket = io(); + const channel = new MessageChannel(); + const source = getSource(); + const desktopAgentUUID = getDesktopAgentId(); + + socket.on("connect", () => { + link(socket, channel, source); + socket.emit(APP_HELLO, desktopAgentUUID, source); + const ui = UI_URLS[getUIKey()]; + + // send the other end of the channel to the app + const message: WebConnectionProtocol3Handshake = { + type: 'WCP3Handshake', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date() + }, + payload: { + fdc3Version: "2.2", + channelSelectorUrl: data?.payload.channelSelector === false ? false : ui.channelSelectorUrl, + intentResolverUrl: data?.payload.intentResolver === false ? false : ui.intentResolverUrl, + } + }; + appWindow.postMessage(message, "*", [channel.port1]) + }); + + window.removeEventListener("message", helloHandler); + } +}; -window.addEventListener("load", () => { - - const socket = io() - const channel = new MessageChannel() - const source = getSource() - const desktopAgentUUID = getDeskopAgentId() - - socket.on("connect", () => { - - link(socket, channel, source) - - socket.emit(APP_HELLO, desktopAgentUUID, source) - - const ui = UI_URLS[getUIKey()] - - // sned the other end of the channel to the app - appWindow.postMessage({ - type: 'WCP3Handshake', - meta: { - connectionAttemptUuid: getConnectionAttemptUuid(), - timestamp: new Date() - }, - payload: { - fdc3Version: "2.2", - ...ui - } - }, "*", [channel.port1]) - - - }) -}) +window.addEventListener("message", helloHandler); From fd2870c8bf9cb00ffbc9798810dc5c2aa71b2d78 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 29 Nov 2024 19:34:01 +0000 Subject: [PATCH 23/90] Refactoring fdc3-get-agent tests --- .../test/step-definitions/generic.steps.ts | 4 +- .../test/support/TestMessaging.ts | 16 +- .../features/default-channel-selector.feature | 8 +- .../features/default-intent-resolver.feature | 8 +- .../features/desktop-agent-disconnect.feature | 15 +- .../features/desktop-agent-strategy.feature | 94 +++--- .../channel-selector.steps.ts | 55 +-- .../step-definitions/desktop-agent.steps.ts | 313 +++++++++++------- .../step-definitions/intent-resolver.steps.ts | 165 ++++----- .../step-definitions/port-creation.steps.ts | 95 +++--- .../test/support/MockDocument.ts | 33 +- .../test/support/MockFDC3Server.ts | 23 +- .../fdc3-get-agent/test/support/MockIFrame.ts | 1 + .../fdc3-get-agent/test/support/MockWindow.ts | 15 +- .../test/support/responses/CurrentChannel.ts | 5 +- .../test/support/responses/FindIntent.ts | 11 +- .../test/support/responses/GetInfo.ts | 41 +++ .../test/support/responses/Handshake.ts | 16 +- .../test/support/responses/RaiseIntent.ts | 8 +- .../test/support/responses/UserChannels.ts | 10 +- packages/testing/src/steps/generic.steps.ts | 5 +- 21 files changed, 549 insertions(+), 392 deletions(-) create mode 100644 packages/fdc3-get-agent/test/support/responses/GetInfo.ts diff --git a/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts index d6a81f28a..87a1bca19 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts @@ -1,7 +1,7 @@ import { TestMessaging } from '../support/TestMessaging'; import { Given, When } from '@cucumber/cucumber' import { CustomWorld } from '../world/index'; -import { BasicDesktopAgent, DefaultAppSupport, DefaultChannelSupport, DefaultIntentSupport, DefaultHandshakeSupport } from '../../src'; +import { BasicDesktopAgent, DefaultAppSupport, DefaultChannelSupport, DefaultIntentSupport, DefaultHeartbeatSupport } from '../../src'; import { SimpleIntentResolver, setupGenericSteps } from '@kite9/testing'; import { CHANNEL_STATE, SimpleChannelSelector } from '@kite9/testing/dist/src/agent'; import { BrowserTypes } from '@kite9/fdc3-schema'; @@ -14,7 +14,7 @@ Given('A Desktop Agent in {string}', async function (this: CustomWorld, field: s } const cs = new DefaultChannelSupport(this.messaging, new SimpleChannelSelector(this)) - const hs = new DefaultHandshakeSupport(this.messaging) + const hs = new DefaultHeartbeatSupport(this.messaging) const is = new DefaultIntentSupport(this.messaging, new SimpleIntentResolver(this)) const as = new DefaultAppSupport(this.messaging) diff --git a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts index 576aaccf1..751483406 100644 --- a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts +++ b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts @@ -104,12 +104,7 @@ export class TestMessaging extends AbstractMessaging { readonly automaticResponses: AutomaticResponse[] constructor(channelState: { [key: string]: Context[] }) { - super({ - timeoutMs: 0, - channelSelector: false, - intentResolver: false, - dontSetWindowFdc3: false - }, "test", "myActualUrl", 200) + super({ appId: "TestMessaging", instanceId: "TestMessaging"}); this.channelState = channelState this.automaticResponses = [ @@ -136,6 +131,13 @@ export class TestMessaging extends AbstractMessaging { return uuidv4() } + getTimeoutMs(): number { + return 1000; + } + + async disconnect(): Promise { + console.log("TestMessaging: disconnect called"); + } post(message: AppRequestMessage): Promise { this.allPosts.push(message) @@ -170,7 +172,7 @@ export class TestMessaging extends AbstractMessaging { return { "requestUuid": this.createUUID(), "timestamp": new Date(), - "source": this.getSource() + "source": this.getAppIdentifier() } } diff --git a/packages/fdc3-get-agent/test/features/default-channel-selector.feature b/packages/fdc3-get-agent/test/features/default-channel-selector.feature index b1993868a..d0fe6b84c 100644 --- a/packages/fdc3-get-agent/test/features/default-channel-selector.feature +++ b/packages/fdc3-get-agent/test/features/default-channel-selector.feature @@ -1,7 +1,7 @@ Feature: Default Channel Selector Background: Desktop Agent API - Given a browser document in "document" and window in "window" + Given a parent window document in "parentDoc", window in "parentWin", child window document in "childDoc" and window in "childWin" And A Channel Selector in "channel-selector" with callback piping to "cb" Given User Channels one, two and three in "channel-list" @@ -9,7 +9,8 @@ Feature: Default Channel Selector Given The channel selector sends a channel change message for channel "one" And we wait for a period of "200" ms Then "{cb}" is "one" - And I call "{document}" with "shutdown" + And I call "{childDoc}" with "shutdown" + And I call "{parentDoc}" with "shutdown" Scenario: Updating channel information in the channel selector Given I call "{channel-selector}" with "updateChannel" with parameters "one" and "{channel-list}" @@ -17,4 +18,5 @@ Feature: Default Channel Selector Then "{lastChannelSelectorMessage}" is an object with the following contents | type | payload.selected | payload.userChannels[0].id | payload.userChannels[1].id | payload.userChannels[2].id | | Fdc3UserInterfaceChannels | one | one | two | three | - And I call "{document}" with "shutdown" + And I call "{childDoc}" with "shutdown" + And I call "{parentDoc}" with "shutdown" diff --git a/packages/fdc3-get-agent/test/features/default-intent-resolver.feature b/packages/fdc3-get-agent/test/features/default-intent-resolver.feature index 98047b309..b2735e620 100644 --- a/packages/fdc3-get-agent/test/features/default-intent-resolver.feature +++ b/packages/fdc3-get-agent/test/features/default-intent-resolver.feature @@ -1,7 +1,7 @@ Feature: Default Intent Resolver Background: Desktop Agent API - Given a browser document in "document" and window in "window" + Given a parent window document in "parentDoc", window in "parentWin", child window document in "childDoc" and window in "childWin" And An Intent Resolver in "intent-resolver" And "instrumentContext" is a "fdc3.instrument" context And "appIntents" is an AppIntents array with a ViewNews intent and two apps @@ -15,7 +15,8 @@ Feature: Default Intent Resolver And "{result}" is an object with the following contents | intent | appId.appId | | ViewNews | app1 | - And I call "{document}" with "shutdown" + And I call "{childDoc}" with "shutdown" + And I call "{parentDoc}" with "shutdown" And I call "{intent-resolver}" with "disconnect" Scenario: Intent Resolution Cancelled @@ -25,5 +26,6 @@ Feature: Default Intent Resolver Given The intent resolver cancels the intent selection message Then the promise "{theIntentPromise}" should resolve And "{result}" is undefined - And I call "{document}" with "shutdown" + And I call "{childDoc}" with "shutdown" + And I call "{parentDoc}" with "shutdown" And I call "{intent-resolver}" with "disconnect" diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature b/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature index 8e57edb30..95f36fb6a 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature @@ -1,11 +1,12 @@ Feature: Death of the Desktop Agent Background: Desktop Agent API - Given a browser document in "document" and window in "window" - # And Testing ends after "8000" ms + # Given a browser document in "document" and window in "window" + Given a parent window document in "parentDoc", window in "parentWin", child window document in "childDoc" and window in "childWin" + #And Testing ends after "8000" ms Scenario: Loaded in the browser, but the user navigates away - Given Parent Window desktop "da" listens for postMessage events in "{window}", returns direct message response + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And we wait for a period of "200" ms And I call getAgent for a promise result with the following options | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | @@ -13,6 +14,8 @@ Feature: Death of the Desktop Agent And I refer to "{result}" as "theAPIPromise" And the promise "{theAPIPromise}" should resolve And I refer to "{result}" as "desktopAgent" - When "{window}" pagehide occurs - Then theAgentPromise is cleared - And I call "{document}" with "shutdown" + When "{childWin}" pagehide occurs with persisted = "{false}" + And we wait for a period of "200" ms + Then The Desktop Agent receives a WCP6Goodbye message + And I call "{childDoc}" with "shutdown" + And I call "{parentDoc}" with "shutdown" diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index 61b5886a5..1dff69b2b 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -1,14 +1,14 @@ Feature: Different Strategies for Accessing the Desktop Agent Background: Desktop Agent API - Given a browser document in "document" and window in "window" + Given a parent window document in "parentDoc", window in "parentWin", child window document in "childDoc" and window in "childWin" # And Testing ends after "8000" ms Scenario: Running inside a Browser and using post message with direct message ports - Given Parent Window desktop "da" listens for postMessage events in "{window}", returns direct message response + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And we wait for a period of "200" ms And I call getAgent for a promise result with the following options - | dontSetWindowFdc3 | timeout | intentResolver | channelSelector | + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | | true | 8000 | false | false | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve @@ -19,19 +19,22 @@ Feature: Different Strategies for Accessing the Desktop Agent | 2.0 | cucumber-app | cucumber-provider | And I refer to "{document.body.children[0]}" as "channel-selector" And I refer to "{channel-selector.children[0]}" as "iframe" - And "{window.fdc3}" is undefined - And "{window.events}" is an array of objects with the following contents + And "{childWin.fdc3}" is undefined + And "{childWin.events}" is an array of objects with the following contents | type | data.type | - | message | WCP1Hello | | message | WCP3Handshake | - Then I call "{document}" with "shutdown" + And "{parentWin.events}" is an array of objects with the following contents + | type | data.type | + | message | WCP1Hello | + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" Scenario: Running inside a Browser using the embedded iframe strategy - Given Parent Window desktop "da" listens for postMessage events in "{window}", returns iframe response + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns iframe response And we wait for a period of "200" ms And I call getAgent for a promise result with the following options - | dontSetWindowFdc3 | timeout | + | dontSetWindowFdc3 | timeoutMs | | false | 8000 | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve @@ -40,28 +43,28 @@ Feature: Different Strategies for Accessing the Desktop Agent Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | - And I refer to "{document.iframes[0]}" as "embedded-iframe" + And I refer to "{childDoc.iframes[0]}" as "embedded-iframe" Then "{embedded-iframe}" is an object with the following contents | tag | atts.name | style.width | style.height | | iframe | FDC3 Communications | 0px | 0px | - And I refer to "{document.iframes[1]}" as "intent-resolver-iframe" - And I refer to "{document.iframes[2]}" as "channel-selector-iframe" + And I refer to "{childDoc.iframes[1]}" as "intent-resolver-iframe" + And I refer to "{childDoc.iframes[2]}" as "channel-selector-iframe" Then "{channel-selector-iframe}" is an object with the following contents | tag | atts.name | atts.src | style.width | style.height | | iframe | FDC3 Channel Selector | https://mock.fdc3.com/channelSelector | 100% | 100% | Then "{intent-resolver-iframe}" is an object with the following contents | tag | atts.name | atts.src | style.width | style.height | | iframe | FDC3 Intent Resolver | https://mock.fdc3.com/resolver | 100% | 100% | - And "{window.fdc3}" is not null - And "{window.events}" is an array of objects with the following contents + And "{childWin.fdc3}" is not null + And "{childWin.events}" is an array of objects with the following contents | type | data.type | - | message | WCP1Hello | | message | WCP2LoadUrl | | message | WCP3Handshake | | message | Fdc3UserInterfaceHello | | message | Fdc3UserInterfaceHello | | fdc3Ready | {null} | - Then I call "{document}" with "shutdown" + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" Scenario: Running inside an Electron Container. @@ -77,7 +80,8 @@ Feature: Different Strategies for Accessing the Desktop Agent Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | - Then I call "{document}" with "shutdown" + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" Scenario: Failover Strategy returning desktop agent Given A Dummy Desktop Agent in "dummy-api" @@ -91,10 +95,11 @@ Feature: Different Strategies for Accessing the Desktop Agent Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | - Then I call "{document}" with "shutdown" + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" Scenario: Failover Strategy returning a proxy - Given "dummyFailover2" is a function which opens an iframe for communications on "{document}" + Given "dummyFailover2" is a function which opens an iframe for communications on "{childDoc}" And I call getAgent for a promise result with the following options | failover | timeoutMs | | {dummyFailover2} | 1000 | @@ -104,37 +109,49 @@ Feature: Different Strategies for Accessing the Desktop Agent Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | - Then I call "{document}" with "shutdown" + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" Scenario: Recovery from SessionState Here, we recover the details of the session from the session state, obviating the need to make a request to the parent iframe. - Given Parent Window desktop "da" listens for postMessage events in "{window}", returns direct message response + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And an existing app instance in "instanceID" - And the session identity is set to "{instanceID}" + And the session identity is set to "{instanceID}" with identityUrl "https://dummyOrigin.test/path" And we wait for a period of "200" ms And I call getAgent for a promise result with the following options - | dontSetWindowFdc3 | timeout | intentResolver | channelSelector | + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | | true | 8000 | false | false | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve - Then I call "{document}" with "shutdown" + And I call "{result}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | cucumber-provider | + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" - Scenario: Failed Recovery from SessionState - App tries to recover with an ID that doesn't exist. - Given Parent Window desktop "da" listens for postMessage events in "{window}", returns direct message response - And we wait for a period of "200" ms - And the session identity is set to "BAD_INSTANCE" - And I call getAgent for a promise result with the following options - | dontSetWindowFdc3 | timeout | intentResolver | channelSelector | - | true | 8000 | false | false | - And I refer to "{result}" as "theAPIPromise" - Then the promise "{theAPIPromise}" should resolve - And "{result}" is an error with message "Invalid instance" - Then I call "{document}" with "shutdown" + # Scenario: Failed Recovery from SessionState + # App tries to recover with an ID that doesn't exist. + # It should be allowed to connect but issued a different instanceId + # needs more thought to complete... + # Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + # And we wait for a period of "200" ms + # And the session identity is set to "BAD_INSTANCE" with identityUrl "https://dummyOrigin.test/path" + # And I call getAgent for a promise result with the following options + # | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | + # | true | 8000 | false | false | + # And I refer to "{result}" as "theAPIPromise" + # Then the promise "{theAPIPromise}" should resolve + # And I call "{result}" with "getInfo" + # Then "{result}" is an object with the following contents + # | fdc3Version | appMetadata.appId | provider | + # | 2.0 | cucumber-app | cucumber-provider | + # Then I call "{parentDoc}" with "shutdown" + # Then I call "{childDoc}" with "shutdown" Scenario: Nothing works and we timeout When I call getAgent for a promise result with the following options @@ -145,7 +162,7 @@ Feature: Different Strategies for Accessing the Desktop Agent And "{result}" is an error with message "AgentNotFound" Scenario: Someone calls getAgent twice - Given Parent Window desktop "da" listens for postMessage events in "{window}", returns direct message response + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And we wait for a period of "200" ms And I call getAgent for a promise result with the following options | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | @@ -160,5 +177,6 @@ Feature: Different Strategies for Accessing the Desktop Agent And the promise "{theAPIPromise2}" should resolve And I refer to "{result}" as "desktopAgent2" And "{desktopAgent1}" is "{desktopAgent2}" - Then I call "{document}" with "shutdown" + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" diff --git a/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts b/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts index 72564ec68..a32248bd2 100644 --- a/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts @@ -1,32 +1,39 @@ -import { Given } from "@cucumber/cucumber"; -import { handleResolve } from "@kite9/testing"; -import { DefaultDesktopAgentChannelSelector } from "../../src/ui/DefaultDesktopAgentChannelSelector"; -import { CHANNEL_SELECTOR_URL } from "../support/MockFDC3Server"; -import { USER_CHANNELS } from "../support/responses/UserChannels"; -import { CustomWorld } from "../world"; +import { Given } from '@cucumber/cucumber'; +import { handleResolve } from '@kite9/testing'; +import { DefaultDesktopAgentChannelSelector } from '../../src/ui/DefaultDesktopAgentChannelSelector'; +import { CHANNEL_SELECTOR_URL } from '../support/MockFDC3Server'; +import { USER_CHANNELS } from '../support/responses/UserChannels'; +import { CustomWorld } from '../world'; +import { Fdc3UserInterfaceChannelSelected } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -Given('A Channel Selector in {string} with callback piping to {string}', async function (this: CustomWorld, field: string, cb: string) { +Given( + 'A Channel Selector in {string} with callback piping to {string}', + async function (this: CustomWorld, field: string, cb: string) { const cs = new DefaultDesktopAgentChannelSelector(CHANNEL_SELECTOR_URL); cs.setChannelChangeCallback((channelId: string | null) => { - this.props[cb] = channelId - }) + this.props[cb] = channelId; + }); - this.props[field] = cs - await cs.connect() -}) + this.props[field] = cs; + await cs.connect(); + } +); Given('User Channels one, two and three in {string}', function (this: CustomWorld, field: string) { - this.props[field] = USER_CHANNELS -}) + this.props[field] = USER_CHANNELS; +}); -Given('The channel selector sends a channel change message for channel {string}', async function (this: CustomWorld, channel: string) { - const port = handleResolve("{document.iframes[0].messageChannels[0].port2}", this) - - port.postMessage({ - type: 'Fdc3UserInterfaceChannelSelected', - payload: { - selected: channel - } - }) -}) \ No newline at end of file +Given( + 'The channel selector sends a channel change message for channel {string}', + async function (this: CustomWorld, channel: string) { + const port = handleResolve('{document.iframes[0].messageChannels[0].port2}', this); + const msg: Fdc3UserInterfaceChannelSelected = { + type: 'Fdc3UserInterfaceChannelSelected', + payload: { + selected: channel, + }, + }; + port.postMessage(msg); + } +); diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index 4c2ac6447..c92d250e9 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -1,152 +1,215 @@ -import { After, DataTable, Given, When } from '@cucumber/cucumber' +import { After, DataTable, Given, When } from '@cucumber/cucumber'; import { CustomWorld } from '../world'; import { handleResolve, setupGenericSteps } from '@kite9/testing'; import { MockDocument } from '../support/MockDocument'; -import { MockWindow } from "../support/MockWindow"; +import { MockWindow } from '../support/MockWindow'; import { fdc3Ready, getAgent } from '../../src'; -import { DesktopAgentDetails, GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; +import { + DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX, + DesktopAgentDetails, + GetAgentParams, + WebDesktopAgentType, +} from '@kite9/fdc3-standard'; import { dummyInstanceId, EMBED_URL, MockFDC3Server } from '../support/MockFDC3Server'; import { MockStorage } from '../support/MockStorage'; import { DesktopAgent, ImplementationMetadata } from '@kite9/fdc3-standard'; -import { DESKTOP_AGENT_SESSION_STORAGE_DETAILS_KEY } from '../../src/messaging/AbstractWebMessaging'; -import { clearAgentPromise, getAgentPromise } from '../../src/strategies/getAgent'; +import { clearAgentPromise } from '../../src/strategies/getAgent'; import expect from 'expect'; //var wtf = require('wtfnode') -setupGenericSteps() -Given('Parent Window desktop {string} listens for postMessage events in {string}, returns direct message response', async function (this: CustomWorld, field: string, w: string) { - const mockWindow = handleResolve(w, this) - this.mockFDC3Server = new MockFDC3Server(mockWindow as any, false, this.mockContext) - this.props[field] = this.mockFDC3Server - this.mockContext.open(dummyInstanceId.appId) -}) - -Given('Parent Window desktop {string} listens for postMessage events in {string}, returns iframe response', async function (this: CustomWorld, field: string, w: string) { - const mockWindow = handleResolve(w, this) - this.mockFDC3Server = new MockFDC3Server(mockWindow as any, true, this.mockContext) - this.props[field] = this.mockFDC3Server - this.mockContext.open(dummyInstanceId.appId) -}) - -Given('{string} is a function which opens an iframe for communications on {string}', function (this: CustomWorld, fn: string, doc: string) { +interface MockPageTransitionEvent extends Event { + persisted?: boolean; +} + +setupGenericSteps(); +Given( + 'Parent Window desktop {string} listens for postMessage events in {string}, returns direct message response', + async function (this: CustomWorld, field: string, w: string) { + const mockWindow = handleResolve(w, this); + this.mockFDC3Server = new MockFDC3Server(mockWindow as any, false, this.mockContext); + this.props[field] = this.mockFDC3Server; + this.mockContext.open(dummyInstanceId.appId); + } +); + +Given( + 'Parent Window desktop {string} listens for postMessage events in {string}, returns iframe response', + async function (this: CustomWorld, field: string, w: string) { + const mockWindow = handleResolve(w, this); + this.mockFDC3Server = new MockFDC3Server(mockWindow as any, true, this.mockContext); + this.props[field] = this.mockFDC3Server; + this.mockContext.open(dummyInstanceId.appId); + } +); + +Given( + '{string} is a function which opens an iframe for communications on {string}', + function (this: CustomWorld, fn: string, doc: string) { this.props[fn] = () => { - this.mockContext.open(dummyInstanceId.appId) - const document = handleResolve(doc, this) as MockDocument - var ifrm = document.createElement("iframe") - this.mockFDC3Server = new MockFDC3Server(ifrm as any, false, this.mockContext) - ifrm.setAttribute("src", EMBED_URL + "?connectionAttemptUuid=123") - document.body.appendChild(ifrm) - return ifrm - } -}); + this.mockContext.open(dummyInstanceId.appId); + const document = handleResolve(doc, this) as MockDocument; + let ifrm = document.createElement('iframe'); + this.mockFDC3Server = new MockFDC3Server(ifrm as any, false, this.mockContext); + ifrm.setAttribute('src', EMBED_URL + '?connectionAttemptUuid=124'); + document.body.appendChild(ifrm); + return ifrm; + }; + } +); Given('an existing app instance in {string}', async function (this: CustomWorld, field: string) { - const uuid = this.mockContext.open(dummyInstanceId.appId) - this.props[field] = uuid -}) - + const uuid = this.mockContext.open(dummyInstanceId.appId); + this.props[field] = uuid; +}); Given('A Dummy Desktop Agent in {string}', async function (this: CustomWorld, field: string) { - - const da: DesktopAgent = { - async getInfo(): Promise { - return { - fdc3Version: "2.0", - appMetadata: { - appId: "cucumber-app" - }, - provider: "cucumber-provider" - } as any - } - } as any - - this.props[field] = da - this.props['result'] = null -}) - -Given('`window.fdc3` is injected into the runtime with the value in {string}', async function (this: CustomWorld, field: string) { - const object = handleResolve(field, this) - window.fdc3 = object - window.dispatchEvent(new Event('fdc3.ready')) + const da: DesktopAgent = { + async getInfo(): Promise { + return { + fdc3Version: '2.0', + appMetadata: { + appId: 'cucumber-app', + }, + provider: 'cucumber-provider', + } as any; + }, + } as any; + + this.props[field] = da; + this.props['result'] = null; }); +Given( + '`window.fdc3` is injected into the runtime with the value in {string}', + async function (this: CustomWorld, field: string) { + const object = handleResolve(field, this); + window.fdc3 = object; + window.dispatchEvent(new Event('fdc3.ready')); + } +); + When('I call getAgent for a promise result', function (this: CustomWorld) { - try { - this.props['result'] = getAgent() - } catch (error) { - this.props['result'] = error - } -}) + try { + this.props['result'] = getAgent(); + } catch (error) { + this.props['result'] = error; + } +}); When('I call fdc3Ready for a promise result', function (this: CustomWorld) { - try { - this.props['result'] = fdc3Ready() - } catch (error) { - this.props['result'] = error - } -}) + try { + this.props['result'] = fdc3Ready(); + } catch (error) { + this.props['result'] = error; + } +}); After(function (this: CustomWorld) { - console.log("Cleaning up") - clearAgentPromise() - // setTimeout(() => { - // //console.log((process as any)._getActiveHandles()) - // wtf.dump() - // }, 10000) - -}) + console.log('Cleaning up'); + clearAgentPromise(); + // setTimeout(() => { + // //console.log((process as any)._getActiveHandles()) + // wtf.dump() + // }, 10000) +}); When('I call getAgent for a promise result with the following options', function (this: CustomWorld, dt: DataTable) { - try { - const first = dt.hashes()[0] - const toArgs = Object.fromEntries(Object.entries(first) - .map(([k, v]) => { - const val = handleResolve(v, this) - const val2 = isNaN(val) ? val : Number(val) - const val3 = val2 === "true" ? true : val2 === "false" ? false : val2 - return [k, val3] - }) - ) - this.props['result'] = getAgent(toArgs as GetAgentParams) - } catch (error) { - this.props['result'] = error - } -}) - -Given('a browser document in {string} and window in {string}', async function (this: CustomWorld, d: string, w: string) { - // creates the mock app window - const mw = new MockWindow("mockWindow", this, "mocky") - globalThis.window = mw as any - this.props[w] = globalThis.window; - - // to keep it simple, mock app window parent is set to itself, to avoid excess routing - mw.parent = mw; - - // mock document exists in the window - globalThis.document = new MockDocument("mockDocument", mw) as any - this.props[d] = globalThis.document as any; - - // browser storage - globalThis.sessionStorage = new MockStorage() as any - -}) - -Given("the session identity is set to {string}", async function (this: CustomWorld, id: string) { - const details: DesktopAgentDetails = { - agentType: WebDesktopAgentType.ProxyParent, - instanceUuid: handleResolve(id, this), - appId: 'cucumber-app', - instanceId: 'uuid-0' - } + try { + const first = dt.hashes()[0]; + const toArgs = Object.fromEntries( + Object.entries(first).map(([k, v]) => { + const val = handleResolve(v, this); + const val2 = isNaN(val) ? val : Number(val); + const val3 = val2 === 'true' ? true : val2 === 'false' ? false : val2; + return [k, val3]; + }) + ); + this.props['result'] = getAgent(toArgs as GetAgentParams); + } catch (error) { + this.props['result'] = error; + } +}); - globalThis.sessionStorage.setItem(DESKTOP_AGENT_SESSION_STORAGE_DETAILS_KEY + "-mocky", JSON.stringify(details)) -}) +Given( + 'a parent window document in {string}, window in {string}, child window document in {string} and window in {string}', + async function (this: CustomWorld, pd: string, pw: string, cd: string, cw: string) { + //create the parent window + const mpw = new MockWindow('mockParentWindow', this, 'parentWin'); + this.props[pw] = mpw as any; -When("{string} pagehide occurs", async function (this: CustomWorld, field: string) { - const window: MockWindow = handleResolve(field, this) - window.dispatchEvent(new Event('pagehide')) -}) + // mock parent window document + this.props[pd] = new MockDocument('parentDoc', mpw) as any; -When("theAgentPromise is cleared", async function (this: CustomWorld) { - expect(getAgentPromise()).toBeNull() -}) \ No newline at end of file + // creates the mock app window + const mcw = new MockWindow('mockWindow', this, 'mocky'); + this.props[cw] = mcw; + + // mock app document + this.props[cd] = new MockDocument('childDoc', mcw); + + //run tests from the perspective of the child window + globalThis.window = this.props[cw]; + globalThis.document = this.props[cd]; + + // create parent relationship + mcw.parent = mpw; + + //create child relationship (for attributing postMessage calls) + mpw.child = mcw; + + // session storage (will be common between windows, which is ok as DA doesn't use this) + globalThis.sessionStorage = new MockStorage() as any; + } +); + +// Given('a browser document in {string} and window in {string}', async function (this: CustomWorld, d: string, w: string) { +// // creates the mock app window +// const mw = new MockWindow("mockWindow", this, "mocky") +// globalThis.window = mw as any +// this.props[w] = globalThis.window; + +// // to keep it simple, mock app window parent is set to itself, to avoid excess routing +// mw.parent = mw; + +// // mock document exists in the window +// globalThis.document = new MockDocument("mockDocument", mw) as any +// this.props[d] = globalThis.document as any; + +// // browser storage +// globalThis.sessionStorage = new MockStorage() as any + +// }) + +Given( + 'the session identity is set to {string} with identityUrl {string}', + async function (this: CustomWorld, uuid: string, identityUrl: string) { + const theUuid = handleResolve(uuid, this); + const theIdentityUrl = handleResolve(identityUrl, this); + const details: Record = {}; + details[theIdentityUrl] = { + agentType: WebDesktopAgentType.ProxyParent, + instanceUuid: theUuid, + appId: 'cucumber-app', + instanceId: 'uuid-0', + identityUrl: theIdentityUrl, + actualUrl: theIdentityUrl, + }; + + globalThis.sessionStorage.setItem(DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-mocky', JSON.stringify(details)); + } +); + +When( + '{string} pagehide occurs with persisted = {string}', + async function (this: CustomWorld, field: string, persisted: string) { + const window: MockWindow = handleResolve(field, this); + const isPersisted = handleResolve(persisted, this); + const transitionEvent: MockPageTransitionEvent = new Event('pagehide'); + transitionEvent.persisted = isPersisted; + window.dispatchEvent(transitionEvent); + } +); + +When('The Desktop Agent receives a WCP6Goodbye message', async function (this: CustomWorld) { + expect(this.mockFDC3Server?.hasReceivedGoodbye).toBeTruthy(); +}); diff --git a/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts b/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts index cb5963dce..88b4da7a3 100644 --- a/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts @@ -1,103 +1,104 @@ -import { Given, When } from "@cucumber/cucumber"; -import { CustomWorld } from "../world"; -import { handleResolve } from "@kite9/testing"; -import { DefaultDesktopAgentIntentResolver } from "../../src/ui/DefaultDesktopAgentIntentResolver"; -import { INTENT_RESPOLVER_URL } from "../support/MockFDC3Server"; -import { FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE } from "@kite9/fdc3-schema/dist/generated/api/BrowserTypes"; - +import { Given, When } from '@cucumber/cucumber'; +import { CustomWorld } from '../world'; +import { handleResolve } from '@kite9/testing'; +import { DefaultDesktopAgentIntentResolver } from '../../src/ui/DefaultDesktopAgentIntentResolver'; +import { INTENT_RESPOLVER_URL } from '../support/MockFDC3Server'; +import { FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE } from '@kite9/fdc3-schema/dist/generated/api/BrowserTypes'; const contextMap: Record = { - "fdc3.instrument": { - "type": "fdc3.instrument", - "name": "Apple", - "id": { - "ticker": "AAPL" - } + 'fdc3.instrument': { + type: 'fdc3.instrument', + name: 'Apple', + id: { + ticker: 'AAPL', }, - "fdc3.country": { - "type": "fdc3.country", - "name": "Sweden", - "id": { - "COUNTRY_ISOALPHA2": "SE", - "COUNTRY_ISOALPHA3": "SWE", - } + }, + 'fdc3.country': { + type: 'fdc3.country', + name: 'Sweden', + id: { + COUNTRY_ISOALPHA2: 'SE', + COUNTRY_ISOALPHA3: 'SWE', }, - "fdc3.unsupported": { - "type": "fdc3.unsupported", - "bogus": true - } -} + }, + 'fdc3.unsupported': { + type: 'fdc3.unsupported', + bogus: true, + }, +}; Given('{string} is a {string} context', function (this: CustomWorld, field: string, type: string) { - this.props[field] = contextMap[type]; -}) - + this.props[field] = contextMap[type]; +}); Given('An Intent Resolver in {string}', async function (this: CustomWorld, field: string) { - const cs = new DefaultDesktopAgentIntentResolver(INTENT_RESPOLVER_URL); - this.props[field] = cs - await cs.connect() -}) + const cs = new DefaultDesktopAgentIntentResolver(INTENT_RESPOLVER_URL); + this.props[field] = cs; + await cs.connect(); +}); -Given('{string} is an AppIntents array with a ViewNews intent and two apps', function (this: CustomWorld, field: string) { +Given( + '{string} is an AppIntents array with a ViewNews intent and two apps', + function (this: CustomWorld, field: string) { this.props[field] = [ - { - intent: { - name: 'ViewNews' - }, - apps: [ - { - appId: 'app1' - }, - { - appId: 'app2' - } - ] - } - - - ] -}) - - -When('I call {string} with {string} with parameters {string} and {string} for a promise', function (this: CustomWorld, field: string, fnName: string, param1: string, param2: string) { + { + intent: { + name: 'ViewNews', + }, + apps: [ + { + appId: 'app1', + }, + { + appId: 'app2', + }, + ], + }, + ]; + } +); + +When( + 'I call {string} with {string} with parameters {string} and {string} for a promise', + function (this: CustomWorld, field: string, fnName: string, param1: string, param2: string) { try { - const object = handleResolve(field, this) - const fn = object[fnName]; - const arg0 = handleResolve(param1, this) - const arg1 = handleResolve(param2, this) - const result = fn.call(object, arg0, arg1) - this.props['result'] = result; + const object = handleResolve(field, this); + const fn = object[fnName]; + const arg0 = handleResolve(param1, this); + const arg1 = handleResolve(param2, this); + const result = fn.call(object, arg0, arg1); + this.props['result'] = result; } catch (error) { - this.props['result'] = error + this.props['result'] = error; } -}); + } +); Given('The intent resolver sends an intent selection message', async function (this: CustomWorld) { - const port = handleResolve("{document.iframes[0].messageChannels[0].port2}", this) - - port.postMessage({ - type: FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, - payload: { - action: 'click', - appIdentifier: { - appId: 'app1' - }, - intent: 'ViewNews' - } - }) -}) + const port = handleResolve('{document.iframes[0].messageChannels[0].port2}', this); + + port.postMessage({ + type: FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, + payload: { + action: 'click', + appIdentifier: { + appId: 'app1', + }, + intent: 'ViewNews', + }, + }); +}); Given('The intent resolver cancels the intent selection message', async function (this: CustomWorld) { - const port = handleResolve("{document.iframes[0].messageChannels[0].port2}", this) + const port = handleResolve('{document.iframes[0].messageChannels[0].port2}', this); - port.postMessage({ - type: FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, - payload: { - action: 'cancel' - } - }) -}) + port.postMessage({ + type: FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, + payload: { + action: 'cancel', + }, + }); +}); // Given('{string} receives a {string} message for the intent resolver and pipes comms to {string}', async function (this: CustomWorld, frame: string, type: string, output: string) { // const channelSelectorIframe = handleResolve(frame, this) diff --git a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts index 3e0ece420..a3fbf1659 100644 --- a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts @@ -1,65 +1,66 @@ -import { Given, Then } from "@cucumber/cucumber"; -import { CustomWorld } from "../world"; -import { handleResolve } from "@kite9/testing"; -var wtf = require('wtfnode') +import { Given, Then } from '@cucumber/cucumber'; +import { CustomWorld } from '../world'; +import { handleResolve } from '@kite9/testing'; +var wtf = require('wtfnode'); - -Given('{string} receives a {string} message for the {string} and creates port {string}', async function (this: CustomWorld, frame: string, type: string, _item: string, port: string) { - const channelSelectorIframe = handleResolve(frame, this) +Given( + '{string} receives a {string} message for the {string} and creates port {string}', + async function (this: CustomWorld, frame: string, type: string, _item: string, port: string) { + const channelSelectorIframe = handleResolve(frame, this); const mc = new MessageChannel(); const internalPort = mc.port1; const externalPort = mc.port2; - if (type == "SelectorMessageInitialize") { - globalThis.window.dispatchEvent({ - type: 'message', - data: { - type: 'SelectorMessageInitialize' - }, - origin: globalThis.window.location.origin, - ports: [externalPort], - source: channelSelectorIframe - } as any) + if (type == 'SelectorMessageInitialize') { + globalThis.window.dispatchEvent({ + type: 'message', + data: { + type: 'SelectorMessageInitialize', + }, + origin: globalThis.window.location.origin, + ports: [externalPort], + source: channelSelectorIframe, + } as any); } + internalPort.start(); + this.props[port] = internalPort; + } +); - internalPort.start() - this.props[port] = internalPort -}); - -Given("{string} pipes messages to {string}", async function (this: CustomWorld, port: string, output: string) { - const out: any[] = [] - this.props[output] = out +Given('{string} pipes messages to {string}', async function (this: CustomWorld, port: string, output: string) { + const out: any[] = []; + this.props[output] = out; - const internalPort = handleResolve(port, this) - internalPort.onmessage = (e: any) => { - out.push({ type: e.type, data: e.data }) - } -}) + const internalPort = handleResolve(port, this); + internalPort.onmessage = (e: any) => { + out.push({ type: e.type, data: e.data }); + }; +}); /** * Avoid checking this in as a line in .features - just used for debugging */ Given('Testing ends after {string} ms', function (string) { - setTimeout(() => { - wtf.dump() + setTimeout(() => { + wtf.dump(); - process.exit(); - }, parseInt(string)) -}) + process.exit(); + }, parseInt(string)); +}); Then('{string} receives a {string} message', function (this: CustomWorld, port: string, type: string) { - const internalPort = handleResolve(port, this) + const internalPort = handleResolve(port, this); - if (type == 'ResolverMessageChoice') { - (internalPort as MessagePort).postMessage({ - type, - payload: { - intent: "viewNews", - target: { - appId: "test-app-1" - } - } - }) - } -}) \ No newline at end of file + if (type == 'ResolverMessageChoice') { + (internalPort as MessagePort).postMessage({ + type, + payload: { + intent: 'viewNews', + target: { + appId: 'test-app-1', + }, + }, + }); + } +}); diff --git a/packages/fdc3-get-agent/test/support/MockDocument.ts b/packages/fdc3-get-agent/test/support/MockDocument.ts index 94cff4fde..0500e5a7d 100644 --- a/packages/fdc3-get-agent/test/support/MockDocument.ts +++ b/packages/fdc3-get-agent/test/support/MockDocument.ts @@ -3,34 +3,39 @@ import { MockIFrame } from "./MockIFrame" import { MockElement } from "./MockElement" export class MockDocument { - - name: string - window: MockWindow - iframes: MockIFrame[] = [] + name: string; + window: MockWindow; + iframes: MockIFrame[] = []; constructor(name: string, window: MockWindow) { - this.name = name - this.window = window + this.name = name; + this.window = window; + console.log(`MockDocument created with name: ${name} in window.name: ${this.window.name}`); } createElement(tag: string): HTMLElement { if (tag == 'iframe') { - const mw = new MockIFrame("iframe", this.window.cw, this.window, "embedded-iframe") - this.iframes.push(mw) - return mw as any + console.log(`MockDocument ${this.name} creating iframe in window.name ${this.window.name}`); + const mw = new MockIFrame("iframe", this.window.cw, this.window, "embedded-iframe"); + //make sure the parent doc is aware of the iframe for attributing postMessage + //TODO: set a different variable for UI iframes + this.window.commsIframe = mw; + + this.iframes.push(mw); + return mw as any; } else { - return new MockElement(tag) as any + return new MockElement(tag) as any; } } getElementById(_id: string): HTMLElement | null { - return new MockElement("div") as any + return new MockElement("div") as any; } - body = new MockElement("body") + body = new MockElement("body"); shutdown() { - this.window.shutdown() - this.iframes.forEach(i => i.shutdown()) + this.window.shutdown(); + this.iframes.forEach(i => i.shutdown()); } } \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index b6c65224b..dda124dc4 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -8,6 +8,7 @@ import { Handshake } from "./responses/Handshake" import { UserChannels } from "./responses/UserChannels" import { CurrentChannel } from "./responses/CurrentChannel" import { BrowserTypes } from "@kite9/fdc3-schema" +import { GetInfo } from "./responses/GetInfo" type AppRequestMessage = BrowserTypes.AppRequestMessage type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL @@ -26,13 +27,15 @@ export class MockFDC3Server implements FDC3Server { private useIframe: boolean private window: MockWindow private tsc: TestServerContext + private receivedGoodbye = false; readonly automaticResponses: AutomaticResponse[] = [ new FindIntent(), new RaiseIntent(), new Handshake(), new UserChannels(), - new CurrentChannel() + new CurrentChannel(), + new GetInfo() ] constructor(window: MockWindow, useIframe: boolean, ctx: TestServerContext) { @@ -54,6 +57,10 @@ export class MockFDC3Server implements FDC3Server { this.tsc.shutdown() } + hasReceivedGoodbye(): boolean { + return this.receivedGoodbye; + } + init() { this.window.addEventListener( "message", @@ -63,10 +70,10 @@ export class MockFDC3Server implements FDC3Server { const source = event.source as Window const origin = event.origin; - console.log("Received: " + JSON.stringify(event.data)); + console.log("MockFDC3Server received: ", event.data); if (data.type == "WCP1Hello") { if (this.useIframe) { - source.postMessage({ + const message: WebConnectionProtocol2LoadURL = { type: "WCP2LoadUrl", meta: { connectionAttemptUuid: data.meta.connectionAttemptUuid, @@ -75,10 +82,11 @@ export class MockFDC3Server implements FDC3Server { payload: { iframeUrl: EMBED_URL + "?connectionAttemptUuid=" + data.meta.connectionAttemptUuid } - } as WebConnectionProtocol2LoadURL, origin) + }; + source.postMessage(message, origin); } else { const details = this.tsc.getMatchingInstance(data.payload.identityUrl) - source.postMessage({ + const message: WebConnectionProtocol3Handshake = { type: "WCP3Handshake", meta: { connectionAttemptUuid: data.meta.connectionAttemptUuid, @@ -89,8 +97,11 @@ export class MockFDC3Server implements FDC3Server { intentResolverUrl: INTENT_RESPOLVER_URL, channelSelectorUrl: CHANNEL_SELECTOR_URL, } - } as WebConnectionProtocol3Handshake, origin, [details!!.externalPort]) + }; + source.postMessage(message , origin, [details!.externalPort]) } + } else if (data.type == "WCP6Goodbye") { + this.receivedGoodbye = true; } }); } diff --git a/packages/fdc3-get-agent/test/support/MockIFrame.ts b/packages/fdc3-get-agent/test/support/MockIFrame.ts index 0c1ee728d..96c9e3a0c 100644 --- a/packages/fdc3-get-agent/test/support/MockIFrame.ts +++ b/packages/fdc3-get-agent/test/support/MockIFrame.ts @@ -12,6 +12,7 @@ export class MockIFrame extends MockWindow { super(tag, cw, name); this.parent = parent; this.contentWindow = this as any; + console.log(`MockIFrame created with tag ${tag}, name: ${name} and parent.name ${parent.name}`); } setAttribute(name: string, value: string): void { diff --git a/packages/fdc3-get-agent/test/support/MockWindow.ts b/packages/fdc3-get-agent/test/support/MockWindow.ts index aa88db684..ec607ec48 100644 --- a/packages/fdc3-get-agent/test/support/MockWindow.ts +++ b/packages/fdc3-get-agent/test/support/MockWindow.ts @@ -17,12 +17,15 @@ export class MockWindow extends MockElement { super(tag); this.cw = cw; this.name = name; + console.log(`MockWindow created with name: ${this.name} / tag: ${this.tag}`); } eventHandlers: EventHandler[] = []; events: any[] = []; parent: MockWindow | null = null; + child: MockWindow | null = null; + commsIframe: MockWindow | null = null; location = { origin: "https://dummyOrigin.test", @@ -31,13 +34,14 @@ export class MockWindow extends MockElement { addEventListener(type: string, callback: (e: Event) => void): void { this.eventHandlers.push({ type, callback }); - console.log("Added event handler " + this.tag); + console.log(`MockWindow ${this.name} / ${this.tag}: added event handler: ${type}`); } removeEventListener(type: string, el: EventListener): void { const removeIndex = this.eventHandlers.findIndex(e => e.type === type && e.callback === el); if (removeIndex !== -1) { this.eventHandlers.splice(removeIndex, 1); + console.log(`MockWindow ${this.name} / ${this.tag}: removed event handler: ${type}`); } } @@ -51,13 +55,16 @@ export class MockWindow extends MockElement { } postMessage(msg: object, targetOrigin: string, transfer: MessagePort[] | undefined): void { - this.dispatchEvent({ + const event = { type: 'message', data: msg, origin: targetOrigin, ports: transfer, - source: this.parent ?? this // when posting from client, set source to self - } as any); + //TODO: set source for UI iframes, comms iframe, parent DA or child app depending on message type + source: this.commsIframe ?? this.child ?? this.parent ?? this + } as any; + console.log(`MockWindow ${this.name} / ${this.tag}: postMessage with source: ${event.source.name}`); + this.dispatchEvent(event); } shutdown() { diff --git a/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts b/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts index 7b75c361a..1db0f9773 100644 --- a/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts +++ b/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts @@ -17,7 +17,7 @@ export class CurrentChannel implements AutomaticResponse { } private createResponse(i: GetCurrentChannelRequest, m: TestServerContext): GetCurrentChannelResponse { - return { + const response: GetCurrentChannelResponse = { meta: { ...i.meta, responseUuid: m.createUUID(), @@ -26,6 +26,7 @@ export class CurrentChannel implements AutomaticResponse { payload: { } - } + }; + return response; } } \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/support/responses/FindIntent.ts b/packages/fdc3-get-agent/test/support/responses/FindIntent.ts index add45bc04..c36ee2439 100644 --- a/packages/fdc3-get-agent/test/support/responses/FindIntent.ts +++ b/packages/fdc3-get-agent/test/support/responses/FindIntent.ts @@ -1,10 +1,8 @@ import { TestServerContext } from "../TestServerContext"; import { InstanceID } from "@kite9/fdc3-web-impl"; import { AutomaticResponse } from "./AutomaticResponses"; -import { BrowserTypes } from "@kite9/fdc3-schema"; +import { FindIntentRequest, FindIntentResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; -type FindIntentRequest = BrowserTypes.FindIntentRequest -type FindIntentResponse = BrowserTypes.FindIntentResponse export class FindIntent implements AutomaticResponse { @@ -20,12 +18,12 @@ export class FindIntent implements AutomaticResponse { } private createFindIntentResponseMessage(m: FindIntentRequest): FindIntentResponse { - return { + const response: FindIntentResponse = { meta: m.meta as any, type: "findIntentResponse", payload: { appIntent: { - intent: m.payload.intent, + intent: { name: m.payload.intent }, apps: [ { appId: 'test-app-1', @@ -38,6 +36,7 @@ export class FindIntent implements AutomaticResponse { ] } } - } as any + }; + return response; } } \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/support/responses/GetInfo.ts b/packages/fdc3-get-agent/test/support/responses/GetInfo.ts new file mode 100644 index 000000000..810dd2c5a --- /dev/null +++ b/packages/fdc3-get-agent/test/support/responses/GetInfo.ts @@ -0,0 +1,41 @@ +import { TestServerContext } from "../TestServerContext"; +import { InstanceID } from "@kite9/fdc3-web-impl"; +import { AutomaticResponse } from "./AutomaticResponses"; +import { GetInfoRequest, GetInfoResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; + +export class GetInfo implements AutomaticResponse { + + filter(t: string) { + return t == 'getInfoRequest' + } + + action(input: object, m: TestServerContext, from: InstanceID) { + const out = this.createResponse(input as GetInfoRequest, m) + setTimeout(() => { m.post(out, from) }, 100) + return Promise.resolve() + } + + private createResponse(i: GetInfoRequest, m: TestServerContext): GetInfoResponse { + const response: GetInfoResponse = { + meta: { + ...i.meta, + responseUuid: m.createUUID(), + }, + type: "getInfoResponse", + payload: { + implementationMetadata: { + appMetadata: {appId: "cucumber-app", instanceId: "cucumber-instance"}, + provider: "cucumber-provider", + providerVersion: "test", + fdc3Version: "2.0", + optionalFeatures: { + DesktopAgentBridging: false, + OriginatingAppMetadata: false, + UserChannelMembershipAPIs: false + } + } + } + }; + return response; + } +} \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/support/responses/Handshake.ts b/packages/fdc3-get-agent/test/support/responses/Handshake.ts index c65517839..e2550fe73 100644 --- a/packages/fdc3-get-agent/test/support/responses/Handshake.ts +++ b/packages/fdc3-get-agent/test/support/responses/Handshake.ts @@ -1,11 +1,7 @@ import { TestServerContext } from "../TestServerContext"; import { InstanceID } from "@kite9/fdc3-web-impl"; import { AutomaticResponse } from "./AutomaticResponses"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity -type WebConnectionProtocol5ValidateAppIdentityFailedResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentityFailedResponse -type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse +import { WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export const BAD_INSTANCE_ID = "BAD_INSTANCE" @@ -26,7 +22,7 @@ export class Handshake implements AutomaticResponse { WebConnectionProtocol5ValidateAppIdentitySuccessResponse | WebConnectionProtocol5ValidateAppIdentityFailedResponse { if (i.payload.instanceUuid == BAD_INSTANCE_ID) { - return { + const msg: WebConnectionProtocol5ValidateAppIdentityFailedResponse = { meta: { connectionAttemptUuid: i.meta.connectionAttemptUuid, timestamp: new Date(), @@ -35,9 +31,10 @@ export class Handshake implements AutomaticResponse { payload: { message: "Invalid instance" } - } + }; + return msg; } else { - return { + const msg: WebConnectionProtocol5ValidateAppIdentitySuccessResponse = { meta: { connectionAttemptUuid: i.meta.connectionAttemptUuid, timestamp: new Date(), @@ -62,7 +59,8 @@ export class Handshake implements AutomaticResponse { instanceId: 'cucumber-instance', instanceUuid: 'some-instance-uuid', } - } + }; + return msg; } } } \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/support/responses/RaiseIntent.ts b/packages/fdc3-get-agent/test/support/responses/RaiseIntent.ts index 30e4a09f4..ceefd1525 100644 --- a/packages/fdc3-get-agent/test/support/responses/RaiseIntent.ts +++ b/packages/fdc3-get-agent/test/support/responses/RaiseIntent.ts @@ -1,11 +1,7 @@ import { TestServerContext } from "../TestServerContext"; import { InstanceID } from "@kite9/fdc3-web-impl"; import { AutomaticResponse } from "./AutomaticResponses"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type RaiseIntentRequest = BrowserTypes.RaiseIntentRequest -type RaiseIntentResponse = BrowserTypes.RaiseIntentResponse - +import { RaiseIntentRequest, RaiseIntentResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export class RaiseIntent implements AutomaticResponse { @@ -28,7 +24,7 @@ export class RaiseIntent implements AutomaticResponse { type: "raiseIntentResponse" } - return out + return out; } action(input: object, m: TestServerContext, from: InstanceID) { diff --git a/packages/fdc3-get-agent/test/support/responses/UserChannels.ts b/packages/fdc3-get-agent/test/support/responses/UserChannels.ts index 0d4c0fffa..399953614 100644 --- a/packages/fdc3-get-agent/test/support/responses/UserChannels.ts +++ b/packages/fdc3-get-agent/test/support/responses/UserChannels.ts @@ -1,10 +1,7 @@ import { TestServerContext } from "../TestServerContext"; import { InstanceID } from "@kite9/fdc3-web-impl"; import { AutomaticResponse } from "./AutomaticResponses"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type GetUserChannelsRequest = BrowserTypes.GetUserChannelsRequest -type GetUserChannelsResponse = BrowserTypes.GetUserChannelsResponse +import { GetUserChannelsRequest, GetUserChannelsResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export const USER_CHANNELS = [ { @@ -35,7 +32,7 @@ export class UserChannels implements AutomaticResponse { } private createResponse(i: GetUserChannelsRequest, m: TestServerContext): GetUserChannelsResponse { - return { + const response: GetUserChannelsResponse = { meta: { ...i.meta, responseUuid: m.createUUID(), @@ -44,6 +41,7 @@ export class UserChannels implements AutomaticResponse { payload: { userChannels: USER_CHANNELS } - } + }; + return response } } \ No newline at end of file diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index b8f07ef24..3a737e9a7 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -78,8 +78,9 @@ export function setupGenericSteps() { }); Then('{string} is an object with the following contents', function (this: PropsWorld, field: string, params: DataTable) { - const table = params.hashes() - expect(doesRowMatch(this, table[0], handleResolve(field, this))).toBeTruthy(); + const table = params.hashes(); + const object = handleResolve(field, this); + expect(doesRowMatch(this, table[0], object)).toBeTruthy(); }); Then('{string} is null', function (this: PropsWorld, field: string) { From 5b1b0b17f890bad1e009e673081462e04ea55066 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 2 Dec 2024 11:07:53 +0000 Subject: [PATCH 24/90] getAgent tests passing + reducing log messaging during tests --- .../src/strategies/HelloHandler.ts | 4 - .../strategies/IdentityValidationHandler.ts | 6 +- .../src/strategies/PostMessageLoader.ts | 1 - .../fdc3-get-agent/src/strategies/getAgent.ts | 4 +- .../src/ui/AbstractUIComponent.ts | 1 - .../channel-selector.steps.ts | 2 +- .../step-definitions/desktop-agent.steps.ts | 19 - .../step-definitions/intent-resolver.steps.ts | 4 +- .../test/support/MockDocument.ts | 4 +- .../test/support/MockFDC3Server.ts | 2 +- .../fdc3-get-agent/test/support/MockIFrame.ts | 2 +- .../fdc3-get-agent/test/support/MockWindow.ts | 8 +- .../test/support/TestServerContext.ts | 3 +- packages/fdc3-get-agent/test/world/index.ts | 2 + .../fdc3-schema/generated/api/BrowserTypes.ts | 4364 ++++++++--------- 15 files changed, 2199 insertions(+), 2227 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index d1fbed15a..4e1665a18 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -57,7 +57,6 @@ export class HelloHandler { }, }; - Logger.debug(`HelloHandler: sending hello message: `, requestMessage); w.postMessage(requestMessage, { targetOrigin: origin }); } @@ -66,7 +65,6 @@ export class HelloHandler { * into an iframe instead of working with the parent window. */ openFrame(url: string) { - Logger.debug(`HelloHandler Opening iframe for: ${url} on window with name: ${window.name}`); const IFRAME_ID = 'fdc3-communications-embedded-iframe'; @@ -102,14 +100,12 @@ export class HelloHandler { * @returns A Promise resolving to a set of connectiondetails */ listenForHelloResponses(): Promise { - Logger.debug(`HelloHandler: listening for hello responses`); return new Promise((resolve, _reject) => { // setup listener for message and retrieve JS URL from it this.helloResponseListener = (event: MessageEvent) => { const data = event.data; - Logger.debug(`HelloHandler: received message: `, data); if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { if (isWebConnectionProtocol2LoadURL(data)) { diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts index 2036a7182..d794ca08e 100644 --- a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -55,7 +55,6 @@ export class IdentityValidationHandler { actualUrl, }, }; - Logger.log(`IdentityValidationHandler: sending validation message`, requestMessage); const persistedDetails = retrieveDesktopAgentDetails(identityUrl); @@ -72,7 +71,7 @@ export class IdentityValidationHandler { return new Promise((resolve, reject) => { //timeout for id validation only const timeout = setTimeout(() => { - Logger.log(`IdentityValidationHandler: timeout`); + Logger.warn(`IdentityValidationHandler: Identity validation timed out`); if (this.idValidationResponseListener) { //remove the event listener as we won't proceed further @@ -87,7 +86,6 @@ export class IdentityValidationHandler { // setup listener for message and retrieve JS URL from it this.idValidationResponseListener = (event: MessageEvent) => { const data = event.data; - Logger.debug(`IdentityValidationHandler: received message`, data); if (data?.meta?.connectionAttemptUuid == this.connectionAttemptUuid) { if (isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(data)) { @@ -120,7 +118,7 @@ export class IdentityValidationHandler { } } else { - Logger.debug( + Logger.warn( `IdentityValidationHandler: Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, data ); diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 8df3cfea6..65d843efc 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -140,7 +140,6 @@ export class PostMessageLoader implements Loader { //clean up this.cancel(); - Logger.debug("PostMessageLoader.get(): Resolving with Desktop Agent selection..."); resolve(desktopAgentSelection); } catch (e) { //id validation may have failed diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 1be25a916..dbf5cf175 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -72,7 +72,7 @@ function initAgentPromise(options: GetAgentParams): Promise { return selection; })); - Logger.debug("Waiting for discovery promises to settle...") + Logger.debug("Waiting for discovery promises to settle..."); return Promise.allSettled(promises) .then(async results => { //review results @@ -198,8 +198,6 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { return da; }; - Logger.debug(`GetAgentParams: ${JSON.stringify(options)}`); - if (!theAgentPromise) { theAgentPromise = initAgentPromise(options).then(handleSetWindowFdc3); } diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index 2f7224224..771a42f61 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -88,7 +88,6 @@ export abstract class AbstractUIComponent implements Connectable { const ml = (e: MessageEvent) => { if (e.source == this.iframe?.contentWindow) { if (isFdc3UserInterfaceHello(e.data)) { - Logger.debug('AbstractUIComponent: Received Hello Message from UI iframe: ', e.data); const helloData = e.data; if (helloData.payload.initialCSS) { this.themeContainer(helloData.payload.initialCSS); diff --git a/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts b/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts index a32248bd2..2a77064ff 100644 --- a/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/channel-selector.steps.ts @@ -27,7 +27,7 @@ Given('User Channels one, two and three in {string}', function (this: CustomWorl Given( 'The channel selector sends a channel change message for channel {string}', async function (this: CustomWorld, channel: string) { - const port = handleResolve('{document.iframes[0].messageChannels[0].port2}', this); + const port = handleResolve('{childDoc.iframes[0].messageChannels[0].port2}', this); const msg: Fdc3UserInterfaceChannelSelected = { type: 'Fdc3UserInterfaceChannelSelected', payload: { diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index c92d250e9..c75868bdf 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -15,7 +15,6 @@ import { MockStorage } from '../support/MockStorage'; import { DesktopAgent, ImplementationMetadata } from '@kite9/fdc3-standard'; import { clearAgentPromise } from '../../src/strategies/getAgent'; import expect from 'expect'; -//var wtf = require('wtfnode') interface MockPageTransitionEvent extends Event { persisted?: boolean; @@ -162,24 +161,6 @@ Given( } ); -// Given('a browser document in {string} and window in {string}', async function (this: CustomWorld, d: string, w: string) { -// // creates the mock app window -// const mw = new MockWindow("mockWindow", this, "mocky") -// globalThis.window = mw as any -// this.props[w] = globalThis.window; - -// // to keep it simple, mock app window parent is set to itself, to avoid excess routing -// mw.parent = mw; - -// // mock document exists in the window -// globalThis.document = new MockDocument("mockDocument", mw) as any -// this.props[d] = globalThis.document as any; - -// // browser storage -// globalThis.sessionStorage = new MockStorage() as any - -// }) - Given( 'the session identity is set to {string} with identityUrl {string}', async function (this: CustomWorld, uuid: string, identityUrl: string) { diff --git a/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts b/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts index 88b4da7a3..9c1e63144 100644 --- a/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts @@ -75,7 +75,7 @@ When( ); Given('The intent resolver sends an intent selection message', async function (this: CustomWorld) { - const port = handleResolve('{document.iframes[0].messageChannels[0].port2}', this); + const port = handleResolve('{childDoc.iframes[0].messageChannels[0].port2}', this); port.postMessage({ type: FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, @@ -90,7 +90,7 @@ Given('The intent resolver sends an intent selection message', async function (t }); Given('The intent resolver cancels the intent selection message', async function (this: CustomWorld) { - const port = handleResolve('{document.iframes[0].messageChannels[0].port2}', this); + const port = handleResolve('{childDoc.iframes[0].messageChannels[0].port2}', this); port.postMessage({ type: FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE, diff --git a/packages/fdc3-get-agent/test/support/MockDocument.ts b/packages/fdc3-get-agent/test/support/MockDocument.ts index 0500e5a7d..2a8618238 100644 --- a/packages/fdc3-get-agent/test/support/MockDocument.ts +++ b/packages/fdc3-get-agent/test/support/MockDocument.ts @@ -10,12 +10,12 @@ export class MockDocument { constructor(name: string, window: MockWindow) { this.name = name; this.window = window; - console.log(`MockDocument created with name: ${name} in window.name: ${this.window.name}`); + if (this.window.cw.debugLogs) { console.log(`MockDocument created with name: ${name} in window.name: ${this.window.name}`); } } createElement(tag: string): HTMLElement { if (tag == 'iframe') { - console.log(`MockDocument ${this.name} creating iframe in window.name ${this.window.name}`); + if (this.window.cw.debugLogs) { console.log(`MockDocument ${this.name} creating iframe in window.name ${this.window.name}`); } const mw = new MockIFrame("iframe", this.window.cw, this.window, "embedded-iframe"); //make sure the parent doc is aware of the iframe for attributing postMessage //TODO: set a different variable for UI iframes diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index dda124dc4..5b4da0f3d 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -70,7 +70,7 @@ export class MockFDC3Server implements FDC3Server { const source = event.source as Window const origin = event.origin; - console.log("MockFDC3Server received: ", event.data); + if (this.tsc.cw.debugLogs) { console.log("MockFDC3Server received: ", event.data); } if (data.type == "WCP1Hello") { if (this.useIframe) { const message: WebConnectionProtocol2LoadURL = { diff --git a/packages/fdc3-get-agent/test/support/MockIFrame.ts b/packages/fdc3-get-agent/test/support/MockIFrame.ts index 96c9e3a0c..f16b4acbc 100644 --- a/packages/fdc3-get-agent/test/support/MockIFrame.ts +++ b/packages/fdc3-get-agent/test/support/MockIFrame.ts @@ -12,7 +12,7 @@ export class MockIFrame extends MockWindow { super(tag, cw, name); this.parent = parent; this.contentWindow = this as any; - console.log(`MockIFrame created with tag ${tag}, name: ${name} and parent.name ${parent.name}`); + if (this.cw.debugLogs) { console.log(`MockIFrame created with tag ${tag}, name: ${name} and parent.name ${parent.name}`); } } setAttribute(name: string, value: string): void { diff --git a/packages/fdc3-get-agent/test/support/MockWindow.ts b/packages/fdc3-get-agent/test/support/MockWindow.ts index ec607ec48..34cd2938c 100644 --- a/packages/fdc3-get-agent/test/support/MockWindow.ts +++ b/packages/fdc3-get-agent/test/support/MockWindow.ts @@ -17,7 +17,7 @@ export class MockWindow extends MockElement { super(tag); this.cw = cw; this.name = name; - console.log(`MockWindow created with name: ${this.name} / tag: ${this.tag}`); + if (cw.debugLogs) { console.debug(`MockWindow created with name: ${this.name} / tag: ${this.tag}`); } } eventHandlers: EventHandler[] = []; @@ -34,14 +34,14 @@ export class MockWindow extends MockElement { addEventListener(type: string, callback: (e: Event) => void): void { this.eventHandlers.push({ type, callback }); - console.log(`MockWindow ${this.name} / ${this.tag}: added event handler: ${type}`); + if (this.cw.debugLogs) { console.log(`MockWindow ${this.name} / ${this.tag}: added event handler: ${type}`); } } removeEventListener(type: string, el: EventListener): void { const removeIndex = this.eventHandlers.findIndex(e => e.type === type && e.callback === el); if (removeIndex !== -1) { this.eventHandlers.splice(removeIndex, 1); - console.log(`MockWindow ${this.name} / ${this.tag}: removed event handler: ${type}`); + if (this.cw.debugLogs) { console.debug(`MockWindow ${this.name} / ${this.tag}: removed event handler: ${type}`); } } } @@ -63,7 +63,7 @@ export class MockWindow extends MockElement { //TODO: set source for UI iframes, comms iframe, parent DA or child app depending on message type source: this.commsIframe ?? this.child ?? this.parent ?? this } as any; - console.log(`MockWindow ${this.name} / ${this.tag}: postMessage with source: ${event.source.name}`); + if (this.cw.debugLogs) { console.debug(`MockWindow ${this.name} / ${this.tag}: postMessage with source: ${event.source.name}`); } this.dispatchEvent(event); } diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index 3241441ba..9a3fe96c7 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -21,7 +21,7 @@ type MessageRecord = { export class TestServerContext implements ServerContext { public postedMessages: MessageRecord[] = [] - private readonly cw: CustomWorld + public readonly cw: CustomWorld private instances: ConnectionDetails[] = [] private nextInstanceId: number = 0 private nextUUID: number = 0 @@ -82,7 +82,6 @@ export class TestServerContext implements ServerContext { this.instances.push(connectionDetails) internalPort.onmessage = (msg) => { - console.log(`Received message on internalPort ${appId}: ${JSON.stringify(msg.data)}`) this.cw.mockFDC3Server?.receive(msg.data, connectionDetails.instanceId) } diff --git a/packages/fdc3-get-agent/test/world/index.ts b/packages/fdc3-get-agent/test/world/index.ts index e9daf8dfb..98a7f6f66 100644 --- a/packages/fdc3-get-agent/test/world/index.ts +++ b/packages/fdc3-get-agent/test/world/index.ts @@ -9,6 +9,8 @@ export class CustomWorld extends PropsWorld { mockContext: TestServerContext = new TestServerContext(this) + debugLogs: boolean = false; + } setWorldConstructor(CustomWorld) \ No newline at end of file diff --git a/packages/fdc3-schema/generated/api/BrowserTypes.ts b/packages/fdc3-schema/generated/api/BrowserTypes.ts index bb3936b9e..3b71a09d8 100644 --- a/packages/fdc3-schema/generated/api/BrowserTypes.ts +++ b/packages/fdc3-schema/generated/api/BrowserTypes.ts @@ -1,15 +1,7 @@ // To parse this data: // -// import { Convert, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceChannels, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse } from "./file"; +// import { Convert, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannels, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage } from "./file"; // -// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); -// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); -// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); -// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); -// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); -// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); -// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); -// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // const addContextListenerRequest = Convert.toAddContextListenerRequest(json); // const addContextListenerResponse = Convert.toAddContextListenerResponse(json); // const addEventListenerRequest = Convert.toAddEventListenerRequest(json); @@ -29,8 +21,8 @@ // const createPrivateChannelResponse = Convert.toCreatePrivateChannelResponse(json); // const eventListenerUnsubscribeRequest = Convert.toEventListenerUnsubscribeRequest(json); // const eventListenerUnsubscribeResponse = Convert.toEventListenerUnsubscribeResponse(json); -// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceChannels = Convert.toFdc3UserInterfaceChannels(json); +// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceDrag = Convert.toFdc3UserInterfaceDrag(json); // const fdc3UserInterfaceHandshake = Convert.toFdc3UserInterfaceHandshake(json); // const fdc3UserInterfaceHello = Convert.toFdc3UserInterfaceHello(json); @@ -83,761 +75,244 @@ // const raiseIntentRequest = Convert.toRaiseIntentRequest(json); // const raiseIntentResponse = Convert.toRaiseIntentResponse(json); // const raiseIntentResultResponse = Convert.toRaiseIntentResultResponse(json); +// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); +// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); +// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); +// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); +// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); +// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); +// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); +// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // // These functions will throw an error if the JSON doesn't // match the expected interface, even if the JSON is valid. /** - * Hello message sent by an application to a parent window or frame when attempting to - * establish connectivity to a Desktop Agent. + * A request to add a context listener to a specified Channel OR to the current user + * channel. Where the listener is added to the current user channel (channelId == null), and + * this app has already been added to a user channel, client code should make a subsequent + * request to get the current context of that channel for this listener and then call its + * handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1Hello { +export interface AddContextListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol1HelloPayload; + payload: AddContextListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "WCP1Hello"; + type: "addContextListenerRequest"; } /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1HelloMeta { - connectionAttemptUuid: string; +export interface AddContextListenerRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + */ + source?: AppIdentifier; timestamp: Date; } /** - * The message payload, containing data pertaining to this connection step. + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. + * + * Details of the application instance that broadcast the context. + * + * The App resolution option chosen. + * + * Details of the application instance that raised the intent. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. */ -export interface WebConnectionProtocol1HelloPayload { +export interface AppIdentifier { /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. */ - actualUrl: string; + appId: string; /** - * A flag that may be used to indicate that a channel selector user interface is or is not - * required. Set to `false` if the app includes its own interface for selecting channels or - * does not work with user channels. + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. */ - channelSelector?: boolean; + desktopAgent?: string; /** - * The version of FDC3 API that the app supports. + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. */ - fdc3Version: string; + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface AddContextListenerRequestPayload { /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. + * The id of the channel to add the listener to or `null` indicating that it should listen + * to the current user channel (at the time of broadcast). */ - identityUrl: string; + channelId: null | string; /** - * A flag that may be used to indicate that an intent resolver is or is not required. Set to - * `false` if no intents, or only targeted intents, are raised. + * The type of context to listen for OR `null` indicating that it should listen to all + * context types. */ - intentResolver?: boolean; - [property: string]: any; + contextType: null | string; } /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Response from a Desktop Agent to an application requesting access to it indicating that - * it should load a specified URL into a hidden iframe in order to establish connectivity to - * a Desktop Agent. + * A response to a addContextListener request. Where the listener was added to the current + * user channel (channelId == null), and this app has already been added to a user channel, + * client code should make a subsequent request to get the current context of that channel + * for this listener and then call its handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol2LoadURL { +export interface AddContextListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: WebConnectionProtocol2LoadURLPayload; + payload: AddContextListenerResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "WCP2LoadUrl"; + type: "addContextListenerResponse"; } /** - * The message payload, containing data pertaining to this connection step. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ -export interface WebConnectionProtocol2LoadURLPayload { +export interface AddContextListenerResponseMeta { + requestUuid: string; + responseUuid: string; /** - * A URL which can be used to establish communication with the Desktop Agent, via loading - * the URL into an iframe and restarting the Web Connection protocol with the iframe as the - * target. + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. */ - iframeUrl: string; - [property: string]: any; + source?: AppIdentifier; + timestamp: Date; } /** - * Identifies the type of the connection step message. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ +export interface AddContextListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; +} /** - * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that - * should be used for subsequent communication steps. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface WebConnectionProtocol3Handshake { +export type PurpleError = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to add an event listener for a specified event type to the Desktop Agent. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface AddEventListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol3HandshakePayload; + payload: AddEventListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "WCP3Handshake"; + type: "addEventListenerRequest"; } /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface WebConnectionProtocol3HandshakePayload { - /** - * Indicates whether a channel selector user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the channel selector (as the - * Desktop Agent will handle it another way). - */ - channelSelectorUrl: boolean | string; - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; +export interface AddEventListenerRequestPayload { /** - * Indicates whether an intent resolver user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the intent resolver (as the - * Desktop Agent will handle it another way). + * The type of the event to be listened to or `null` to listen to all event types. */ - intentResolverUrl: boolean | string; + type: "USER_CHANNEL_CHANGED" | null; } /** - * Identifies the type of the connection step message. + * The type of a (non-context and non-intent) event that may be received via the FDC3 API's + * addEventListener function. */ /** - * Identity Validation request from an app attempting to connect to a Desktop Agent. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to an addEventListener request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol4ValidateAppIdentity { +export interface AddEventListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol4ValidateAppIdentityPayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP4ValidateAppIdentity"; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol4ValidateAppIdentityPayload { - /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. - */ - actualUrl: string; - /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. - */ - identityUrl: string; - /** - * If an application has previously connected to the Desktop Agent, it may specify its prior - * instance id and associated instance UUID to request the same same instance Id be assigned. - */ - instanceId?: string; - /** - * Instance UUID associated with the requested instanceId. - */ - instanceUuid?: string; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Message sent by the Desktop Agent to an app if their identity validation fails. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP5ValidateAppIdentityFailedResponse"; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { - message?: string; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Message sent by the Desktop Agent to an app after successful identity validation. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP5ValidateAppIdentityResponse"; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { - /** - * The appId that the app's identity was validated against. - */ - appId: string; - /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - */ - implementationMetadata: ImplementationMetadata; - /** - * The instance Id granted to the application by the Desktop Agent. - */ - instanceId: string; - /** - * Instance UUID associated with the instanceId granted, which may be used to retrieve the - * same instanceId if the app is reloaded or navigates. - */ - instanceUuid: string; -} - -/** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - * - * Includes Metadata for the current application. - * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. - */ -export interface ImplementationMetadata { - /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - */ - appMetadata: AppMetadata; - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; -} - -/** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - * - * Extends an `AppIdentifier`, describing an application or instance of an application, with - * additional descriptive metadata that is usually provided by an FDC3 App Directory that - * the Desktop Agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such - * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon - * and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the - * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. - */ -export interface AppMetadata { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * A longer, multi-paragraph description for the application that could include markup. - */ - description?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * A list of icon URLs for the application that can be used to render UI elements. - */ - icons?: Icon[]; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - /** - * An optional set of, implementation specific, metadata fields that can be used to - * disambiguate instances, such as a window title or screen position. Must only be set if - * `instanceId` is set. - */ - instanceMetadata?: { [key: string]: any }; - /** - * The 'friendly' app name. - * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now - * require an `AppIdentifier` wth `appId` set. - * Note that for display purposes the `title` field should be used, if set, in preference to - * this field. - */ - name?: string; - /** - * The type of output returned for any intent specified during resolution. May express a - * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel - * that will receive a specified type (e.g. "channel"). - */ - resultType?: null | string; - /** - * Images representing the app in common usage scenarios that can be used to render UI - * elements. - */ - screenshots?: Image[]; - /** - * A more user-friendly application title that can be used to render UI elements. - */ - title?: string; - /** - * A tooltip for the application that can be used to render UI elements. - */ - tooltip?: string; - /** - * The Version of the application. - */ - version?: string; -} - -/** - * Describes an Icon image that may be used to represent the application. - */ -export interface Icon { - /** - * The icon dimension, formatted as `x`. - */ - size?: string; - /** - * The icon url. - */ - src: string; - /** - * Icon media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Describes an image file, typically a screenshot, that often represents the application in - * a common usage scenario. - */ -export interface Image { - /** - * Caption for the image. - */ - label?: string; - /** - * The image dimension, formatted as `x`. - */ - size?: string; - /** - * The image url. - */ - src: string; - /** - * Image media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ -export interface OptionalFeatures { - /** - * Used to indicate whether the experimental Desktop Agent Bridging - * feature is implemented by the Desktop Agent. - */ - DesktopAgentBridging: boolean; - /** - * Used to indicate whether the exposure of 'originating app metadata' for - * context and intent messages is supported by the Desktop Agent. - */ - OriginatingAppMetadata: boolean; - /** - * Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent. - */ - UserChannelMembershipAPIs: boolean; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the - * window or navigating). Desktop Agents should close the MessagePort after receiving this - * message, but retain instance details in case the application reconnects (e.g. after a - * navigation event). - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol6Goodbye { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol6GoodbyeMeta; - /** - * Identifies the type of the connection step message. - */ - type: "WCP6Goodbye"; -} - -/** - * Metadata for a Web Connection Protocol message. - */ -export interface WebConnectionProtocol6GoodbyeMeta { - timestamp: Date; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocolMessage { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: ConnectionStepMetadata; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload?: { [key: string]: any }; - /** - * Identifies the type of the connection step message. - */ - type: ConnectionStepMessageType; -} - -/** - * Metadata for a Web Connection Protocol message. - */ -export interface ConnectionStepMetadata { - timestamp: Date; - connectionAttemptUuid?: string; -} - -/** - * Identifies the type of the connection step message. - */ -export type ConnectionStepMessageType = "WCP1Hello" | "WCP2LoadUrl" | "WCP3Handshake" | "WCP4ValidateAppIdentity" | "WCP5ValidateAppIdentityFailedResponse" | "WCP5ValidateAppIdentityResponse" | "WCP6Goodbye"; - -/** - * A request to add a context listener to a specified Channel OR to the current user - * channel. Where the listener is added to the current user channel (channelId == null), and - * this app has already been added to a user channel, client code should make a subsequent - * request to get the current context of that channel for this listener and then call its - * handler with it. - * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AddContextListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddContextListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addContextListenerRequest"; -} - -/** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ -export interface AddContextListenerRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - * - * Details of the application instance that broadcast the context. - * - * The App resolution option chosen. - * - * Details of the application instance that raised the intent. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface AddContextListenerRequestPayload { - /** - * The id of the channel to add the listener to or `null` indicating that it should listen - * to the current user channel (at the time of broadcast). - */ - channelId: null | string; - /** - * The type of context to listen for OR `null` indicating that it should listen to all - * context types. - */ - contextType: null | string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a addContextListener request. Where the listener was added to the current - * user channel (channelId == null), and this app has already been added to a user channel, - * client code should make a subsequent request to get the current context of that channel - * for this listener and then call its handler with it. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. - */ -export interface AddContextListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: AddContextListenerResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "addContextListenerResponse"; -} - -/** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ -export interface AddContextListenerResponseMeta { - requestUuid: string; - responseUuid: string; - /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface AddContextListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; -} - -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type PurpleError = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound"; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to add an event listener for a specified event type to the Desktop Agent. - * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AddEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddEventListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addEventListenerRequest"; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface AddEventListenerRequestPayload { - /** - * The type of the event to be listened to or `null` to listen to all event types. - */ - type: "USER_CHANNEL_CHANGED" | null; -} - -/** - * The type of a (non-context and non-intent) event that may be received via the FDC3 API's - * addEventListener function. - */ - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to an addEventListener request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. - */ -export interface AddEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; + meta: AddContextListenerResponseMeta; /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was @@ -1250,20 +725,219 @@ export interface ChannelChangedEventPayload { * The Id of the channel that the app was added to or `null` if it was removed from a * channel. */ - newChannelId: null | string; + newChannelId: null | string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to unsubscribe a context listener. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface ContextListenerUnsubscribeRequest { + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: ContextListenerUnsubscribeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "contextListenerUnsubscribeRequest"; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface ContextListenerUnsubscribeRequestPayload { + listenerUUID: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a contextListenerUnsubscribe request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface ContextListenerUnsubscribeResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "contextListenerUnsubscribeResponse"; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface CreatePrivateChannelRequest { + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: CreatePrivateChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "createPrivateChannelRequest"; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface CreatePrivateChannelRequestPayload { +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a createPrivateChannel request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface CreatePrivateChannelResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: CreatePrivateChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "createPrivateChannelResponse"; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface CreatePrivateChannelResponsePayload { + error?: PurpleError; + privateChannel?: Channel; +} + +/** + * Represents a context channel that applications can use to send and receive + * context data. + * + * Please note that There are differences in behavior when you interact with a + * User channel via the `DesktopAgent` interface and the `Channel` interface. + * Specifically, when 'joining' a User channel or adding a context listener + * when already joined to a channel via the `DesktopAgent` interface, existing + * context (matching the type of the context listener) on the channel is + * received by the context listener immediately. Whereas, when a context + * listener is added via the Channel interface, context is not received + * automatically, but may be retrieved manually via the `getCurrentContext()` + * function. + */ +export interface Channel { + /** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + */ + displayMetadata?: DisplayMetadata; + /** + * Constant that uniquely identifies this channel. + */ + id: string; + /** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ + type: Type; +} + +/** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + * + * A system channel will be global enough to have a presence across many apps. This gives us + * some hints + * to render them in a standard way. It is assumed it may have other properties too, but if + * it has these, + * this is their meaning. + */ +export interface DisplayMetadata { + /** + * The color that should be associated within this channel when displaying this channel in a + * UI, e.g: `0xFF0000`. + */ + color?: string; + /** + * A URL of an image that can be used to display this channel. + */ + glyph?: string; + /** + * A user-readable name for this channel, e.g: `"Red"`. + */ + name?: string; } +/** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ +export type Type = "app" | "private" | "user"; + /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request to unsubscribe a context listener. + * A request to unsubscribe an event listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface ContextListenerUnsubscribeRequest { +export interface EventListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -1271,18 +945,18 @@ export interface ContextListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: ContextListenerUnsubscribeRequestPayload; + payload: EventListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "contextListenerUnsubscribeRequest"; + type: "eventListenerUnsubscribeRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface ContextListenerUnsubscribeRequestPayload { +export interface EventListenerUnsubscribeRequestPayload { listenerUUID: string; } @@ -1292,12 +966,12 @@ export interface ContextListenerUnsubscribeRequestPayload { */ /** - * A response to a contextListenerUnsubscribe request. + * A response to an eventListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface ContextListenerUnsubscribeResponse { +export interface EventListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -1312,7 +986,7 @@ export interface ContextListenerUnsubscribeResponse { * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "contextListenerUnsubscribeResponse"; + type: "eventListenerUnsubscribeResponse"; } /** @@ -1321,313 +995,442 @@ export interface ContextListenerUnsubscribeResponse { */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an + * iframe with the channel definitions and current channel selection. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface CreatePrivateChannelRequest { +export interface Fdc3UserInterfaceChannels { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * The message payload. */ - meta: AddContextListenerRequestMeta; + payload: Fdc3UserInterfaceChannelsPayload; /** - * The message payload typically contains the arguments to FDC3 API functions. + * Identifies the type of the message to or from the user interface frame. */ - payload: CreatePrivateChannelRequestPayload; + type: "Fdc3UserInterfaceChannels"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceChannelsPayload { /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * The id of the channel that should be currently selected, or `null` if none should be + * selected. */ - type: "createPrivateChannelRequest"; + selected: null | string; + /** + * User Channel definitions.```````s + */ + userChannels: Channel[]; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * Identifies the type of the message to or from the user interface frame. */ -export interface CreatePrivateChannelRequestPayload { + +/** + * Message from a channel selector UI to the DA proxy sent when the channel selection + * changes. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceChannelSelected { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelSelectedPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: "Fdc3UserInterfaceChannelSelected"; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * The message payload. + */ +export interface Fdc3UserInterfaceChannelSelectedPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; +} + +/** + * Identifies the type of the message to or from the user interface frame. */ /** - * A response to a createPrivateChannel request. + * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user + * is dragging the UI to a new location and providing the offset to apply to the location. + * The DA proxy implementation should limit the location to the current bounds of the + * window's viewport. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface CreatePrivateChannelResponse { +export interface Fdc3UserInterfaceDrag { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The message payload. */ - meta: AddContextListenerResponseMeta; + payload: Fdc3UserInterfaceDragPayload; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Identifies the type of the message to or from the user interface frame. */ - payload: CreatePrivateChannelResponsePayload; + type: "Fdc3UserInterfaceDrag"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceDragPayload { /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The offset to move the frame by. */ - type: "createPrivateChannelResponse"; + mouseOffsets: MouseOffsets; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The offset to move the frame by. */ -export interface CreatePrivateChannelResponsePayload { - error?: PurpleError; - privateChannel?: Channel; +export interface MouseOffsets { + x: number; + y: number; } /** - * Represents a context channel that applications can use to send and receive - * context data. + * Identifies the type of the message to or from the user interface frame. + */ + +/** + * Handshake message sent back to a user interface from the DA proxy code (setup by + * `getAgent()`) over the `MessagePort` provide in the preceding iFrameHello message, + * confirming that it is listening to the `MessagePort` for further communication. * - * Please note that There are differences in behavior when you interact with a - * User channel via the `DesktopAgent` interface and the `Channel` interface. - * Specifically, when 'joining' a User channel or adding a context listener - * when already joined to a channel via the `DesktopAgent` interface, existing - * context (matching the type of the context listener) on the channel is - * received by the context listener immediately. Whereas, when a context - * listener is added via the Channel interface, context is not received - * automatically, but may be retrieved manually via the `getCurrentContext()` - * function. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface Channel { +export interface Fdc3UserInterfaceHandshake { /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. + * The message payload. */ - displayMetadata?: DisplayMetadata; + payload: Fdc3UserInterfaceHandshakePayload; /** - * Constant that uniquely identifies this channel. + * Identifies the type of the message to or from the user interface frame. */ - id: string; + type: "Fdc3UserInterfaceHandshake"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceHandshakePayload { /** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". + * The version of FDC3 API that the Desktop Agent will provide support for. */ - type: Type; + fdc3Version: string; } /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. + * Identifies the type of the message to or from the user interface frame. + */ + +/** + * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate + * it is ready to communicate, containing initial CSS to set on the iframe, and including an + * appended `MessagePort` to be used for further communication. * - * A system channel will be global enough to have a presence across many apps. This gives us - * some hints - * to render them in a standard way. It is assumed it may have other properties too, but if - * it has these, - * this is their meaning. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface DisplayMetadata { +export interface Fdc3UserInterfaceHello { /** - * The color that should be associated within this channel when displaying this channel in a - * UI, e.g: `0xFF0000`. + * The message payload. */ - color?: string; + payload: Fdc3UserInterfaceHelloPayload; /** - * A URL of an image that can be used to display this channel. + * Identifies the type of the message to or from the user interface frame. */ - glyph?: string; + type: "Fdc3UserInterfaceHello"; +} + +/** + * The message payload. + */ +export interface Fdc3UserInterfaceHelloPayload { + /** + * Details about the UI implementation, such as vendor and version, for logging purposes. + */ + implementationDetails: string; + /** + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + */ + initialCSS: InitialCSS; +} + +/** + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + */ +export interface InitialCSS { + /** + * The initial bottom property to apply to the iframe. + */ + bottom?: string; + /** + * The initial height of the iframe. + */ + height?: string; + /** + * The initial left property to apply to the iframe. + */ + left?: string; + /** + * The maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; /** - * A user-readable name for this channel, e.g: `"Red"`. + * The initial top property to apply to the iframe. */ - name?: string; -} - -/** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". - */ -export type Type = "app" | "private" | "user"; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to unsubscribe an event listener. - * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface EventListenerUnsubscribeRequest { + top?: string; /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * The transition property to apply to the iframe. */ - meta: AddContextListenerRequestMeta; + transition?: string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The initial width of the iframe. */ - payload: EventListenerUnsubscribeRequestPayload; + width?: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * The initial zindex to apply to the iframe. */ - type: "eventListenerUnsubscribeRequest"; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface EventListenerUnsubscribeRequestPayload { - listenerUUID: string; + zIndex?: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A response to an eventListenerUnsubscribe request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface EventListenerUnsubscribeResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface Fdc3UserInterfaceMessage { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ - payload: BroadcastResponseResponsePayload; + payload?: { [key: string]: any }; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: "eventListenerUnsubscribeResponse"; + type: Fdc3UserInterfaceMessageType; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ +export type Fdc3UserInterfaceMessageType = "Fdc3UserInterfaceHello" | "Fdc3UserInterfaceHandshake" | "Fdc3UserInterfaceRestyle" | "Fdc3UserInterfaceDrag" | "Fdc3UserInterfaceResolve" | "Fdc3UserInterfaceResolveAction" | "Fdc3UserInterfaceChannels" | "Fdc3UserInterfaceChannelSelected"; /** - * Message from a channel selector UI to the DA proxy sent when the channel selection - * changes. + * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the + * resolver data to setup the UI. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceChannelSelected { +export interface Fdc3UserInterfaceResolve { /** * The message payload. */ - payload: Fdc3UserInterfaceChannelSelectedPayload; + payload: Fdc3UserInterfaceResolvePayload; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceChannelSelected"; + type: "Fdc3UserInterfaceResolve"; } /** * The message payload. */ -export interface Fdc3UserInterfaceChannelSelectedPayload { +export interface Fdc3UserInterfaceResolvePayload { /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. + * An array of AppIntent objects defining the resolution options. */ - selected: null | string; + appIntents: AppIntent[]; + context: Context; } /** - * Identifies the type of the message to or from the user interface frame. - */ - -/** - * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an - * iframe with the channel definitions and current channel selection. + * An interface that relates an intent to apps. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. */ -export interface Fdc3UserInterfaceChannels { +export interface AppIntent { /** - * The message payload. + * Details of applications that can resolve the intent. */ - payload: Fdc3UserInterfaceChannelsPayload; + apps: AppMetadata[]; /** - * Identifies the type of the message to or from the user interface frame. + * Details of the intent whose relationship to resolving applications is being described. */ - type: "Fdc3UserInterfaceChannels"; + intent: IntentMetadata; } /** - * The message payload. + * Extends an `AppIdentifier`, describing an application or instance of an application, with + * additional descriptive metadata that is usually provided by an FDC3 App Directory that + * the Desktop Agent connects to. + * + * The additional information from an app directory can aid in rendering UI elements, such + * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon + * and screenshot URLs. + * + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the + * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. + * + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). */ -export interface Fdc3UserInterfaceChannelsPayload { +export interface AppMetadata { /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. */ - selected: null | string; + appId: string; /** - * User Channel definitions.```````s + * A longer, multi-paragraph description for the application that could include markup. */ - userChannels: Channel[]; + description?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * A list of icon URLs for the application that can be used to render UI elements. + */ + icons?: Icon[]; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + /** + * An optional set of, implementation specific, metadata fields that can be used to + * disambiguate instances, such as a window title or screen position. Must only be set if + * `instanceId` is set. + */ + instanceMetadata?: { [key: string]: any }; + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now + * require an `AppIdentifier` wth `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to + * this field. + */ + name?: string; + /** + * The type of output returned for any intent specified during resolution. May express a + * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel + * that will receive a specified type (e.g. "channel"). + */ + resultType?: null | string; + /** + * Images representing the app in common usage scenarios that can be used to render UI + * elements. + */ + screenshots?: Image[]; + /** + * A more user-friendly application title that can be used to render UI elements. + */ + title?: string; + /** + * A tooltip for the application that can be used to render UI elements. + */ + tooltip?: string; + /** + * The Version of the application. + */ + version?: string; } /** - * Identifies the type of the message to or from the user interface frame. - */ - -/** - * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user - * is dragging the UI to a new location and providing the offset to apply to the location. - * The DA proxy implementation should limit the location to the current bounds of the - * window's viewport. - * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * Describes an Icon image that may be used to represent the application. */ -export interface Fdc3UserInterfaceDrag { +export interface Icon { /** - * The message payload. + * The icon dimension, formatted as `x`. */ - payload: Fdc3UserInterfaceDragPayload; + size?: string; /** - * Identifies the type of the message to or from the user interface frame. + * The icon url. */ - type: "Fdc3UserInterfaceDrag"; + src: string; + /** + * Icon media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; } /** - * The message payload. + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. */ -export interface Fdc3UserInterfaceDragPayload { +export interface Image { /** - * The offset to move the frame by. + * Caption for the image. */ - mouseOffsets: MouseOffsets; + label?: string; + /** + * The image dimension, formatted as `x`. + */ + size?: string; + /** + * The image url. + */ + src: string; + /** + * Image media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; } /** - * The offset to move the frame by. + * Details of the intent whose relationship to resolving applications is being described. + * + * Metadata describing an Intent. */ -export interface MouseOffsets { - x: number; - y: number; +export interface IntentMetadata { + /** + * Display name for the intent. + */ + displayName?: string; + /** + * The unique name of the intent that can be invoked by the raiseIntent call. + */ + name: string; } /** @@ -1635,85 +1438,87 @@ export interface MouseOffsets { */ /** - * Handshake message sent back to a user interface from the DA proxy code (setup by - * `getAgent()`) over the `MessagePort` provide in the preceding iFrameHello message, - * confirming that it is listening to the `MessagePort` for further communication. + * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user + * action. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceHandshake { +export interface Fdc3UserInterfaceResolveAction { /** * The message payload. */ - payload: Fdc3UserInterfaceHandshakePayload; + payload: Fdc3UserInterfaceResolveActionPayload; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceHandshake"; + type: "Fdc3UserInterfaceResolveAction"; } /** * The message payload. */ -export interface Fdc3UserInterfaceHandshakePayload { +export interface Fdc3UserInterfaceResolveActionPayload { + action: Action; /** - * The version of FDC3 API that the Desktop Agent will provide support for. + * The App resolution option chosen. */ - fdc3Version: string; + appIdentifier?: AppIdentifier; + /** + * The intent resolved. + */ + intent?: string; } +export type Action = "hover" | "click" | "cancel"; + /** * Identifies the type of the message to or from the user interface frame. */ /** - * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate - * it is ready to communicate, containing initial CSS to set on the iframe, and including an - * appended `MessagePort` to be used for further communication. + * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling + * information to apply to it. Can be used to implement a pop-open or close interaction or + * other transition needed by a UI implementation. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceHello { +export interface Fdc3UserInterfaceRestyle { /** * The message payload. */ - payload: Fdc3UserInterfaceHelloPayload; + payload: Fdc3UserInterfaceRestylePayload; /** * Identifies the type of the message to or from the user interface frame. */ - type: "Fdc3UserInterfaceHello"; + type: "Fdc3UserInterfaceRestyle"; } /** * The message payload. */ -export interface Fdc3UserInterfaceHelloPayload { - /** - * Details about the UI implementation, such as vendor and version, for logging purposes. - */ - implementationDetails: string; +export interface Fdc3UserInterfaceRestylePayload { /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. */ - initialCSS: InitialCSS; + updatedCSS: UpdatedCSS; } /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. */ -export interface InitialCSS { +export interface UpdatedCSS { /** * The initial bottom property to apply to the iframe. */ bottom?: string; /** - * The initial height of the iframe. + * The updated height of the iframe. */ height?: string; /** @@ -1721,11 +1526,11 @@ export interface InitialCSS { */ left?: string; /** - * The maximum height to apply to the iframe. + * The updated maximum height to apply to the iframe. */ maxHeight?: string; /** - * The maximum with to apply to the iframe. + * The updated maximum with to apply to the iframe. */ maxWidth?: string; /** @@ -1737,15 +1542,15 @@ export interface InitialCSS { */ top?: string; /** - * The transition property to apply to the iframe. + * The updated transition property to apply to the iframe. */ transition?: string; /** - * The initial width of the iframe. + * The updated width of the iframe. */ width?: string; /** - * The initial zindex to apply to the iframe. + * The updated zIndex to apply to the iframe. */ zIndex?: string; [property: string]: any; @@ -1756,222 +1561,335 @@ export interface InitialCSS { */ /** - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request for details of instances of a particular app. + * + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceMessage { +export interface FindInstancesRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload?: { [key: string]: any }; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: Fdc3UserInterfaceMessageType; + payload: FindInstancesRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findInstancesRequest"; } /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ -export type Fdc3UserInterfaceMessageType = "Fdc3UserInterfaceHello" | "Fdc3UserInterfaceHandshake" | "Fdc3UserInterfaceRestyle" | "Fdc3UserInterfaceDrag" | "Fdc3UserInterfaceResolve" | "Fdc3UserInterfaceResolveAction" | "Fdc3UserInterfaceChannels" | "Fdc3UserInterfaceChannelSelected"; +export interface FindInstancesRequestPayload { + app: AppIdentifier; +} /** - * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the - * resolver data to setup the UI. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a findInstances request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceResolve { +export interface FindInstancesResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceResolvePayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: "Fdc3UserInterfaceResolve"; + payload: FindInstancesResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findInstancesResponse"; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + * + * The message payload contains a flag indicating whether the API call was successful, plus + * any return values for the FDC3 API function called, or indicating that the request + * resulted in an error and including a standardized error message. */ -export interface Fdc3UserInterfaceResolvePayload { +export interface FindInstancesResponsePayload { + error?: FindInstancesErrors; + appIdentifiers?: AppMetadata[]; +} + +/** + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + * + * Unique identifier for a `listener` object returned by a Desktop Agent to an app in + * response to addContextListener, addIntentListener or one of the PrivateChannel event + * listeners and used to identify it in messages (e.g. when unsubscribing). + * + * Unique identifier for an event message sent from a Desktop Agent to an app. + * + * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID + * should be used in the first (WCP1Hello) message and should be quoted in all subsequent + * messages to link them to the same connection attempt. + * + * Should be set if the raiseIntent request returned an error. + */ +export type FindInstancesErrors = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request for details of apps available to resolve a particular intent and context pair. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface FindIntentRequest { /** - * An array of AppIntent objects defining the resolution options. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - appIntents: AppIntent[]; - context: Context; + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "findIntentRequest"; } /** - * An interface that relates an intent to apps. + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentRequestPayload { + context?: Context; + intent: string; + resultType?: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a findIntent request. * - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface AppIntent { +export interface FindIntentResponse { /** - * Details of applications that can resolve the intent. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: FindIntentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentResponse"; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface FindIntentResponsePayload { + error?: FindInstancesErrors; + appIntent?: AppIntent; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request for details of intents and apps available to resolve them for a particular + * context. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface FindIntentsByContextRequest { + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. */ - apps: AppMetadata[]; + payload: FindIntentsByContextRequestPayload; /** - * Details of the intent whose relationship to resolving applications is being described. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - intent: IntentMetadata; + type: "findIntentsByContextRequest"; } /** - * Details of the intent whose relationship to resolving applications is being described. - * - * Metadata describing an Intent. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentMetadata { - /** - * Display name for the intent. - */ - displayName?: string; - /** - * The unique name of the intent that can be invoked by the raiseIntent call. - */ - name: string; +export interface FindIntentsByContextRequestPayload { + context: Context; + resultType?: string; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user - * action. + * A response to a findIntentsByContext request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceResolveAction { +export interface FindIntentsByContextResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceResolveActionPayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: "Fdc3UserInterfaceResolveAction"; + payload: FindIntentsByContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "findIntentsByContextResponse"; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceResolveActionPayload { - action: Action; - /** - * The App resolution option chosen. - */ - appIdentifier?: AppIdentifier; - /** - * The intent resolved. - */ - intent?: string; +export interface FindIntentsByContextResponsePayload { + error?: FindInstancesErrors; + appIntents?: AppIntent[]; } -export type Action = "hover" | "click" | "cancel"; - /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling - * information to apply to it. Can be used to implement a pop-open or close interaction or - * other transition needed by a UI implementation. + * A request for metadata about an app. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceRestyle { +export interface GetAppMetadataRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceRestylePayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: "Fdc3UserInterfaceRestyle"; + payload: GetAppMetadataRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: "getAppMetadataRequest"; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceRestylePayload { - /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. - */ - updatedCSS: UpdatedCSS; +export interface GetAppMetadataRequestPayload { + app: AppIdentifier; } /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export interface UpdatedCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The updated height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The updated maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The updated maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; + +/** + * A response to a getAppMetadata request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface GetAppMetadataResponse { /** - * The updated transition property to apply to the iframe. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - transition?: string; + meta: AddContextListenerResponseMeta; /** - * The updated width of the iframe. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - width?: string; + payload: GetAppMetadataResponsePayload; /** - * The updated zIndex to apply to the iframe. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - zIndex?: string; - [property: string]: any; + type: "getAppMetadataResponse"; } /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ +export interface GetAppMetadataResponsePayload { + error?: FindInstancesErrors; + appMetadata?: AppMetadata; +} /** - * A request for details of instances of a particular app. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to return the Channel object for the current User channel membership. Returns + * `null` if the app is not joined to a channel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindInstancesRequest { +export interface GetCurrentChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -1979,19 +1897,18 @@ export interface FindInstancesRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindInstancesRequestPayload; + payload: GetCurrentChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "findInstancesRequest"; + type: "getCurrentChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindInstancesRequestPayload { - app: AppIdentifier; +export interface GetCurrentChannelRequestPayload { } /** @@ -2000,12 +1917,12 @@ export interface FindInstancesRequestPayload { */ /** - * A response to a findInstances request. + * A response to a getCurrentChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindInstancesResponse { +export interface GetCurrentChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2015,66 +1932,37 @@ export interface FindInstancesResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindInstancesResponsePayload; + payload: GetCurrentChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "findInstancesResponse"; + type: "getCurrentChannelResponse"; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - * - * The message payload contains a flag indicating whether the API call was successful, plus - * any return values for the FDC3 API function called, or indicating that the request - * resulted in an error and including a standardized error message. */ -export interface FindInstancesResponsePayload { - error?: FindInstancesErrors; - appIdentifiers?: AppMetadata[]; +export interface GetCurrentChannelResponsePayload { + error?: ResponsePayloadError; + channel?: Channel | null; } -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - * - * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID - * should be used in the first (WCP1Hello) message and should be quoted in all subsequent - * messages to link them to the same connection attempt. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - * - * Unique identifier for a `listener` object returned by a Desktop Agent to an app in - * response to addContextListener, addIntentListener or one of the PrivateChannel event - * listeners and used to identify it in messages (e.g. when unsubscribing). - * - * Unique identifier for an event message sent from a Desktop Agent to an app. - * - * Should be set if the raiseIntent request returned an error. - */ -export type FindInstancesErrors = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request for details of apps available to resolve a particular intent and context pair. + * A request to return the current context (either of a specified type or most recent + * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if + * one was specified) is available in the channel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentRequest { +export interface GetCurrentContextRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2082,21 +1970,27 @@ export interface FindIntentRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentRequestPayload; + payload: GetCurrentContextRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "findIntentRequest"; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindIntentRequestPayload { - context?: Context; - intent: string; - resultType?: string; + type: "getCurrentContextRequest"; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface GetCurrentContextRequestPayload { + /** + * The id of the channel to return the current context of. + */ + channelId: string; + /** + * The type of context to return for OR `null` indicating that the most recently broadcast + * context on the channel should be returned. + */ + contextType: null | string; } /** @@ -2105,12 +1999,12 @@ export interface FindIntentRequestPayload { */ /** - * A response to a findIntent request. + * A response to a getCurrentContext request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentResponse { +export interface GetCurrentContextResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2120,12 +2014,12 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentResponsePayload; + payload: GetCurrentContextResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "findIntentResponse"; + type: "getCurrentContextResponse"; } /** @@ -2133,9 +2027,13 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentResponsePayload { - error?: FindInstancesErrors; - appIntent?: AppIntent; +export interface GetCurrentContextResponsePayload { + error?: PurpleError; + /** + * The most recently broadcast context object (of the specified type, if one was specified), + * or `null` if none was available in the channel. + */ + context?: null | Context; } /** @@ -2144,12 +2042,12 @@ export interface FindIntentResponsePayload { */ /** - * A request for details of intents and apps available to resolve them for a particular - * context. + * Request to retrieve information about the FDC3 Desktop Agent implementation and the + * metadata of the calling application according to the Desktop Agent. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentsByContextRequest { +export interface GetInfoRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2157,20 +2055,18 @@ export interface FindIntentsByContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentsByContextRequestPayload; + payload: GetInfoRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "findIntentsByContextRequest"; + type: "getInfoRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentsByContextRequestPayload { - context: Context; - resultType?: string; +export interface GetInfoRequestPayload { } /** @@ -2179,12 +2075,12 @@ export interface FindIntentsByContextRequestPayload { */ /** - * A response to a findIntentsByContext request. + * A response to a getInfo request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentsByContextResponse { +export interface GetInfoResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2194,12 +2090,12 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentsByContextResponsePayload; + payload: GetInfoResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "findIntentsByContextResponse"; + type: "getInfoResponse"; } /** @@ -2207,9 +2103,67 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentsByContextResponsePayload { - error?: FindInstancesErrors; - appIntents?: AppIntent[]; +export interface GetInfoResponsePayload { + error?: ResponsePayloadError; + implementationMetadata?: ImplementationMetadata; +} + +/** + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. + * + * Includes Metadata for the current application. + * + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + */ +export interface ImplementationMetadata { + /** + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). + */ + appMetadata: AppMetadata; + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ +export interface OptionalFeatures { + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + DesktopAgentBridging: boolean; + /** + * Used to indicate whether the exposure of 'originating app metadata' for + * context and intent messages is supported by the Desktop Agent. + */ + OriginatingAppMetadata: boolean; + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + UserChannelMembershipAPIs: boolean; } /** @@ -2218,11 +2172,12 @@ export interface FindIntentsByContextResponsePayload { */ /** - * A request for metadata about an app. + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetAppMetadataRequest { +export interface GetOrCreateChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2230,19 +2185,22 @@ export interface GetAppMetadataRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetAppMetadataRequestPayload; + payload: GetOrCreateChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getAppMetadataRequest"; + type: "getOrCreateChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetAppMetadataRequestPayload { - app: AppIdentifier; +export interface GetOrCreateChannelRequestPayload { + /** + * The id of the channel to return + */ + channelId: string; } /** @@ -2251,12 +2209,12 @@ export interface GetAppMetadataRequestPayload { */ /** - * A response to a getAppMetadata request. + * A response to a getOrCreateChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetAppMetadataResponse { +export interface GetOrCreateChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2266,12 +2224,12 @@ export interface GetAppMetadataResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetAppMetadataResponsePayload; + payload: GetOrCreateChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getAppMetadataResponse"; + type: "getOrCreateChannelResponse"; } /** @@ -2279,9 +2237,9 @@ export interface GetAppMetadataResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetAppMetadataResponsePayload { - error?: FindInstancesErrors; - appMetadata?: AppMetadata; +export interface GetOrCreateChannelResponsePayload { + error?: PurpleError; + channel?: Channel; } /** @@ -2290,12 +2248,11 @@ export interface GetAppMetadataResponsePayload { */ /** - * A request to return the Channel object for the current User channel membership. Returns - * `null` if the app is not joined to a channel. + * Request to retrieve a list of the User Channels available for the app to join. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetCurrentChannelRequest { +export interface GetUserChannelsRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2303,18 +2260,18 @@ export interface GetCurrentChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetCurrentChannelRequestPayload; + payload: GetUserChannelsRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getCurrentChannelRequest"; + type: "getUserChannelsRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentChannelRequestPayload { +export interface GetUserChannelsRequestPayload { } /** @@ -2323,12 +2280,12 @@ export interface GetCurrentChannelRequestPayload { */ /** - * A response to a getCurrentChannel request. + * A response to a getUserChannels request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetCurrentChannelResponse { +export interface GetUserChannelsResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2338,12 +2295,12 @@ export interface GetCurrentChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetCurrentChannelResponsePayload; + payload: GetUserChannelsResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getCurrentChannelResponse"; + type: "getUserChannelsResponse"; } /** @@ -2351,9 +2308,9 @@ export interface GetCurrentChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetCurrentChannelResponsePayload { - error?: ResponsePayloadError; - channel?: Channel | null; +export interface GetUserChannelsResponsePayload { + error?: PurpleError; + userChannels?: Channel[]; } /** @@ -2362,13 +2319,12 @@ export interface GetCurrentChannelResponsePayload { */ /** - * A request to return the current context (either of a specified type or most recent - * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if - * one was specified) is available in the channel. + * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent + * and indicates that an application window or frame is still alive. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetCurrentContextRequest { +export interface HeartbeatAcknowledgementRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2376,70 +2332,106 @@ export interface GetCurrentContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetCurrentContextRequestPayload; + payload: HeartbeatAcknowledgementRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getCurrentContextRequest"; + type: "heartbeatAcknowledgementRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentContextRequestPayload { +export interface HeartbeatAcknowledgementRequestPayload { /** - * The id of the channel to return the current context of. + * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. */ - channelId: string; + heartbeatEventUuid: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is + * alive and that the application should send a heartbeatResponseRequest to the agent in + * response. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface HeartbeatEvent { /** - * The type of context to return for OR `null` indicating that the most recently broadcast - * context on the channel should be returned. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - contextType: null | string; + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: HeartbeatEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "heartbeatEvent"; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface HeartbeatEventPayload { } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a getCurrentContext request. + * An event message from the Desktop Agent to an app indicating that it has been selected to + * resolve a raised intent and context. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface GetCurrentContextResponse { +export interface IntentEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: GetCurrentContextResponsePayload; + payload: IntentEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getCurrentContextResponse"; + type: "intentEvent"; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface GetCurrentContextResponsePayload { - error?: PurpleError; +export interface IntentEventPayload { + /** + * The context object passed with the raised intent. + */ + context: Context; /** - * The most recently broadcast context object (of the specified type, if one was specified), - * or `null` if none was available in the channel. + * The intent that was raised. */ - context?: null | Context; + intent: string; + /** + * Details of the application instance that raised the intent. + */ + originatingApp?: AppIdentifier; + /** + * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates + * to. + */ + raiseIntentRequestUuid: string; } /** @@ -2448,12 +2440,11 @@ export interface GetCurrentContextResponsePayload { */ /** - * Request to retrieve information about the FDC3 Desktop Agent implementation and the - * metadata of the calling application according to the Desktop Agent. + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetInfoRequest { +export interface IntentListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2461,18 +2452,19 @@ export interface GetInfoRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetInfoRequestPayload; + payload: IntentListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getInfoRequest"; + type: "intentListenerUnsubscribeRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetInfoRequestPayload { +export interface IntentListenerUnsubscribeRequestPayload { + listenerUUID: string; } /** @@ -2481,12 +2473,12 @@ export interface GetInfoRequestPayload { */ /** - * A response to a getInfo request. + * A response to a intentListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetInfoResponse { +export interface IntentListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2496,22 +2488,12 @@ export interface GetInfoResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetInfoResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getInfoResponse"; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetInfoResponsePayload { - error?: ResponsePayloadError; - implementationMetadata?: ImplementationMetadata; + type: "intentListenerUnsubscribeResponse"; } /** @@ -2520,12 +2502,13 @@ export interface GetInfoResponsePayload { */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * A request to deliver a result for an intent (which may include a `void` result that just + * indicates that the handler has run, returning no result). The result is tied to the + * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetOrCreateChannelRequest { +export interface IntentResultRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2533,22 +2516,32 @@ export interface GetOrCreateChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetOrCreateChannelRequestPayload; + payload: IntentResultRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getOrCreateChannelRequest"; + type: "intentResultRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetOrCreateChannelRequestPayload { +export interface IntentResultRequestPayload { /** - * The id of the channel to return + * The eventUuid value of the intentEvent that the result being sent relates to. */ - channelId: string; + intentEventUuid: string; + intentResult: IntentResult; + /** + * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + */ + raiseIntentRequestUuid: string; +} + +export interface IntentResult { + context?: Context; + channel?: Channel; } /** @@ -2557,12 +2550,12 @@ export interface GetOrCreateChannelRequestPayload { */ /** - * A response to a getOrCreateChannel request. + * A response to a request to deliver an intent result. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetOrCreateChannelResponse { +export interface IntentResultResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2572,22 +2565,12 @@ export interface GetOrCreateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetOrCreateChannelResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getOrCreateChannelResponse"; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetOrCreateChannelResponsePayload { - error?: PurpleError; - channel?: Channel; + type: "intentResultResponse"; } /** @@ -2596,11 +2579,13 @@ export interface GetOrCreateChannelResponsePayload { */ /** - * Request to retrieve a list of the User Channels available for the app to join. + * Request to join the app to the specified User channel. On successfully joining a channel, + * client code should make subsequent requests to get the current context of that channel + * for all registered context listeners and then call their handlers with it. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetUserChannelsRequest { +export interface JoinUserChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2608,18 +2593,22 @@ export interface GetUserChannelsRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetUserChannelsRequestPayload; + payload: JoinUserChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "getUserChannelsRequest"; + type: "joinUserChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetUserChannelsRequestPayload { +export interface JoinUserChannelRequestPayload { + /** + * The id of the channel to join. + */ + channelId: string; } /** @@ -2628,12 +2617,14 @@ export interface GetUserChannelsRequestPayload { */ /** - * A response to a getUserChannels request. + * A response to a joinUserChannel request. On receipt of this response, client code should + * make subsequent requests to get the current context of that channel for all registered + * context listeners and then call their handlers with it. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetUserChannelsResponse { +export interface JoinUserChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2643,12 +2634,12 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetUserChannelsResponsePayload; + payload: JoinUserChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "getUserChannelsResponse"; + type: "joinUserChannelResponse"; } /** @@ -2656,9 +2647,8 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetUserChannelsResponsePayload { +export interface JoinUserChannelResponsePayload { error?: PurpleError; - userChannels?: Channel[]; } /** @@ -2667,12 +2657,11 @@ export interface GetUserChannelsResponsePayload { */ /** - * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent - * and indicates that an application window or frame is still alive. + * Request to remove the app from any User channel membership. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface HeartbeatAcknowledgementRequest { +export interface LeaveCurrentChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2680,22 +2669,18 @@ export interface HeartbeatAcknowledgementRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: HeartbeatAcknowledgementRequestPayload; + payload: LeaveCurrentChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "heartbeatAcknowledgementRequest"; + type: "leaveCurrentChannelRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface HeartbeatAcknowledgementRequestPayload { - /** - * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. - */ - heartbeatEventUuid: string; +export interface LeaveCurrentChannelRequestPayload { } /** @@ -2704,82 +2689,36 @@ export interface HeartbeatAcknowledgementRequestPayload { */ /** - * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is - * alive and that the application should send a heartbeatResponseRequest to the agent in - * response. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. - */ -export interface HeartbeatEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: HeartbeatEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "heartbeatEvent"; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface HeartbeatEventPayload { -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that it has been selected to - * resolve a raised intent and context. + * A response to a leaveCurrentChannel request. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentEvent { +export interface LeaveCurrentChannelResponse { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: BroadcastEventMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: IntentEventPayload; + payload: LeaveCurrentChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "intentEvent"; + type: "leaveCurrentChannelResponse"; } /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface IntentEventPayload { - /** - * The context object passed with the raised intent. - */ - context: Context; - /** - * The intent that was raised. - */ - intent: string; - /** - * Details of the application instance that raised the intent. - */ - originatingApp?: AppIdentifier; - /** - * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates - * to. - */ - raiseIntentRequestUuid: string; +export interface LeaveCurrentChannelResponsePayload { + error?: PurpleError; } /** @@ -2788,11 +2727,11 @@ export interface IntentEventPayload { */ /** - * A request to unsubscribe a context listener. + * A request to open an application. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentListenerUnsubscribeRequest { +export interface OpenRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2800,19 +2739,25 @@ export interface IntentListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentListenerUnsubscribeRequestPayload; + payload: OpenRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "intentListenerUnsubscribeRequest"; + type: "openRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface OpenRequestPayload { + app: AppIdentifier; + /** + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. + */ + context?: Context; } /** @@ -2821,12 +2766,12 @@ export interface IntentListenerUnsubscribeRequestPayload { */ /** - * A response to a intentListenerUnsubscribe request. + * A response to a open request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentListenerUnsubscribeResponse { +export interface OpenResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2836,27 +2781,45 @@ export interface IntentListenerUnsubscribeResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: OpenResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "intentListenerUnsubscribeResponse"; + type: "openResponse"; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface OpenResponsePayload { + error?: OpenErrorResponsePayload; + appIdentifier?: AppIdentifier; } +/** + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + */ +export type OpenErrorResponsePayload = "MalformedContext" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; + /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request to deliver a result for an intent (which may include a `void` result that just - * indicates that the handler has run, returning no result). The result is tied to the - * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. + * A request to add an event listener to a specific PrivateChannel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentResultRequest { +export interface PrivateChannelAddEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2864,33 +2827,33 @@ export interface IntentResultRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentResultRequestPayload; + payload: PrivateChannelAddEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "intentResultRequest"; + type: "privateChannelAddEventListenerRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentResultRequestPayload { +export interface PrivateChannelAddEventListenerRequestPayload { /** - * The eventUuid value of the intentEvent that the result being sent relates to. + * The type of PrivateChannel event that the listener should be applied to, or null for all + * event types. */ - intentEventUuid: string; - intentResult: IntentResult; + listenerType: PrivateChannelEventType | null; /** - * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + * The Id of the PrivateChannel that the listener should be added to. */ - raiseIntentRequestUuid: string; + privateChannelId: string; } -export interface IntentResult { - context?: Context; - channel?: Channel; -} +/** + * Type defining valid type strings for Private Channel events. + */ +export type PrivateChannelEventType = "addContextListener" | "unsubscribe" | "disconnect"; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2898,12 +2861,12 @@ export interface IntentResult { */ /** - * A response to a request to deliver an intent result. + * A response to a privateChannelAddEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentResultResponse { +export interface PrivateChannelAddEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2913,12 +2876,22 @@ export interface IntentResultResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: PrivateChannelAddEventListenerResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "intentResultResponse"; + type: "privateChannelAddEventListenerResponse"; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface PrivateChannelAddEventListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; } /** @@ -2927,13 +2900,12 @@ export interface IntentResultResponse { */ /** - * Request to join the app to the specified User channel. On successfully joining a channel, - * client code should make subsequent requests to get the current context of that channel - * for all registered context listeners and then call their handlers with it. + * Request that indicates that a participant will no longer interact with a specified + * `PrivateChannel`. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface JoinUserChannelRequest { +export interface PrivateChannelDisconnectRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2941,20 +2913,20 @@ export interface JoinUserChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: JoinUserChannelRequestPayload; + payload: PrivateChannelDisconnectRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "joinUserChannelRequest"; + type: "privateChannelDisconnectRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface JoinUserChannelRequestPayload { +export interface PrivateChannelDisconnectRequestPayload { /** - * The id of the channel to join. + * The Id of the Channel that should be disconnected from */ channelId: string; } @@ -2965,14 +2937,12 @@ export interface JoinUserChannelRequestPayload { */ /** - * A response to a joinUserChannel request. On receipt of this response, client code should - * make subsequent requests to get the current context of that channel for all registered - * context listeners and then call their handlers with it. + * A response to a privateChannelDisconnect request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface JoinUserChannelResponse { +export interface PrivateChannelDisconnectResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2982,12 +2952,12 @@ export interface JoinUserChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: JoinUserChannelResponsePayload; + payload: PrivateChannelDisconnectResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "joinUserChannelResponse"; + type: "privateChannelDisconnectResponse"; } /** @@ -2995,7 +2965,7 @@ export interface JoinUserChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface JoinUserChannelResponsePayload { +export interface PrivateChannelDisconnectResponsePayload { error?: PurpleError; } @@ -3005,68 +2975,77 @@ export interface JoinUserChannelResponsePayload { */ /** - * Request to remove the app from any User channel membership. + * An event message from the Desktop Agent to an app indicating that another app has added a + * context listener to a specific PrivateChannel. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface LeaveCurrentChannelRequest { +export interface PrivateChannelOnAddContextListenerEvent { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerRequestMeta; + meta: BroadcastEventMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ - payload: LeaveCurrentChannelRequestPayload; + payload: PrivateChannelOnAddContextListenerEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "leaveCurrentChannelRequest"; + type: "privateChannelOnAddContextListenerEvent"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ -export interface LeaveCurrentChannelRequestPayload { +export interface PrivateChannelOnAddContextListenerEventPayload { + /** + * The type of the context listener added to the channel by another app, or null if it will + * listen to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was added to. + */ + privateChannelId: string; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a leaveCurrentChannel request. + * An event message from the Desktop Agent to an app indicating that another app has + * disconnected from a specific PrivateChannel and will no longer interact with it. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface LeaveCurrentChannelResponse { +export interface PrivateChannelOnDisconnectEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: LeaveCurrentChannelResponsePayload; + payload: PrivateChannelOnDisconnectEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "leaveCurrentChannelResponse"; + type: "privateChannelOnDisconnectEvent"; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface LeaveCurrentChannelResponsePayload { - error?: PurpleError; +export interface PrivateChannelOnDisconnectEventPayload { + /** + * The Id of the PrivateChannel that the app has disconnected from. + */ + privateChannelId: string; } /** @@ -3075,11 +3054,53 @@ export interface LeaveCurrentChannelResponsePayload { */ /** - * A request to open an application. + * An event message from the Desktop Agent to an app indicating that another app has + * unsubscribed a context listener from a specific PrivateChannel. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface PrivateChannelOnUnsubscribeEvent { + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: PrivateChannelOnUnsubscribeEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: "privateChannelOnUnsubscribeEvent"; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface PrivateChannelOnUnsubscribeEventPayload { + /** + * The type of the context listener unsubscribed from the channel by another app, or null if + * it was listening to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was unsubscribed from. + */ + privateChannelId: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface OpenRequest { +export interface PrivateChannelUnsubscribeEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3087,25 +3108,19 @@ export interface OpenRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: OpenRequestPayload; + payload: PrivateChannelUnsubscribeEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "openRequest"; + type: "privateChannelUnsubscribeEventListenerRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface OpenRequestPayload { - app: AppIdentifier; - /** - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. - */ - context?: Context; +export interface PrivateChannelUnsubscribeEventListenerRequestPayload { + listenerUUID: string; } /** @@ -3114,12 +3129,12 @@ export interface OpenRequestPayload { */ /** - * A response to a open request. + * A response to a privateChannelUnsubscribeEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface OpenResponse { +export interface PrivateChannelUnsubscribeEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3129,45 +3144,25 @@ export interface OpenResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: OpenResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "openResponse"; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface OpenResponsePayload { - error?: OpenErrorResponsePayload; - appIdentifier?: AppIdentifier; + type: "privateChannelUnsubscribeEventListenerResponse"; } -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type OpenErrorResponsePayload = "MalformedContext" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request to add an event listener to a specific PrivateChannel. + * A request to raise an unspecified intent for a specified context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface PrivateChannelAddEventListenerRequest { +export interface RaiseIntentForContextRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3175,46 +3170,34 @@ export interface PrivateChannelAddEventListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: PrivateChannelAddEventListenerRequestPayload; + payload: RaiseIntentForContextRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "privateChannelAddEventListenerRequest"; + type: "raiseIntentForContextRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface PrivateChannelAddEventListenerRequestPayload { - /** - * The type of PrivateChannel event that the listener should be applied to, or null for all - * event types. - */ - listenerType: PrivateChannelEventType | null; - /** - * The Id of the PrivateChannel that the listener should be added to. - */ - privateChannelId: string; +export interface RaiseIntentForContextRequestPayload { + app?: AppIdentifier; + context: Context; } -/** - * Type defining valid type strings for Private Channel events. - */ -export type PrivateChannelEventType = "addContextListener" | "unsubscribe" | "disconnect"; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * A response to a privateChannelAddEventListener request. + * A response to a raiseIntentForContext request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelAddEventListenerResponse { +export interface RaiseIntentForContextResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3223,23 +3206,89 @@ export interface PrivateChannelAddEventListenerResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). */ - payload: PrivateChannelAddEventListenerResponsePayload; + payload: RaiseIntentForContextResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "privateChannelAddEventListenerResponse"; + type: "raiseIntentForContextResponse"; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). + * + * Response to a raiseIntentForContext request that needs additional resolution (i.e. show + * an intent resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface PrivateChannelAddEventListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; +export interface RaiseIntentForContextResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing + * an intent resolver) before it can be handled. + */ + appIntents?: AppIntent[]; +} + +/** + * Used if the raiseIntent request was successfully resolved. + * + * IntentResolution provides a standard format for data returned upon resolving an intent. + * + * ```javascript + * //resolve a "Chain" type intent + * let resolution = await agent.raiseIntent("intentName", context); + * + * //resolve a "Client-Service" type intent with a data response or a Channel + * let resolution = await agent.raiseIntent("intentName", context); + * try { + * const result = await resolution.getResult(); + * if (result && result.broadcast) { + * console.log(`${resolution.source} returned a channel with id ${result.id}`); + * } else if (result){ + * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); + * } else { + * console.error(`${resolution.source} didn't return data` + * } + * } catch(error) { + * console.error(`${resolution.source} returned an error: ${error}`); + * } + * + * // Use metadata about the resolving app instance to target a further intent + * await agent.raiseIntent("intentName", context, resolution.source); + * ``` + */ +export interface IntentResolution { + /** + * The intent that was raised. May be used to determine which intent the user + * chose in response to `fdc3.raiseIntentForContext()`. + */ + intent: string; + /** + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ + source: AppIdentifier; } /** @@ -3248,12 +3297,11 @@ export interface PrivateChannelAddEventListenerResponsePayload { */ /** - * Request that indicates that a participant will no longer interact with a specified - * `PrivateChannel`. + * A request to raise an intent for a context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface PrivateChannelDisconnectRequest { +export interface RaiseIntentRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3261,22 +3309,21 @@ export interface PrivateChannelDisconnectRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: PrivateChannelDisconnectRequestPayload; + payload: RaiseIntentRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: "privateChannelDisconnectRequest"; + type: "raiseIntentRequest"; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface PrivateChannelDisconnectRequestPayload { - /** - * The Id of the Channel that should be disconnected from - */ - channelId: string; +export interface RaiseIntentRequestPayload { + app?: AppIdentifier; + context: Context; + intent: string; } /** @@ -3285,12 +3332,12 @@ export interface PrivateChannelDisconnectRequestPayload { */ /** - * A response to a privateChannelDisconnect request. + * A response to a raiseIntent request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelDisconnectResponse { +export interface RaiseIntentResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3299,22 +3346,47 @@ export interface PrivateChannelDisconnectResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). */ - payload: PrivateChannelDisconnectResponsePayload; + payload: RaiseIntentResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "privateChannelDisconnectResponse"; + type: "raiseIntentResponse"; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). + * + * Response to a raiseIntent request that needs additional resolution (i.e. show an intent + * resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface PrivateChannelDisconnectResponsePayload { - error?: PurpleError; +export interface RaiseIntentResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. + */ + appIntent?: AppIntent; } /** @@ -3323,40 +3395,39 @@ export interface PrivateChannelDisconnectResponsePayload { */ /** - * An event message from the Desktop Agent to an app indicating that another app has added a - * context listener to a specific PrivateChannel. + * A secondary response to a request to raise an intent used to deliver the intent result. + * This message should quote the original requestUuid of the raiseIntentRequest message in + * its `meta.requestUuid` field. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelOnAddContextListenerEvent { +export interface RaiseIntentResultResponse { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: BroadcastEventMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: PrivateChannelOnAddContextListenerEventPayload; + payload: RaiseIntentResultResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: "privateChannelOnAddContextListenerEvent"; + type: "raiseIntentResultResponse"; } /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface PrivateChannelOnAddContextListenerEventPayload { - /** - * The type of the context listener added to the channel by another app, or null if it will - * listen to all types. - */ - contextType: null | string; - /** - * The Id of the PrivateChannel that the listener was added to. - */ - privateChannelId: string; +export interface RaiseIntentResultResponsePayload { + error?: ResponsePayloadError; + intentResult?: IntentResult; } /** @@ -3365,491 +3436,356 @@ export interface PrivateChannelOnAddContextListenerEventPayload { */ /** - * An event message from the Desktop Agent to an app indicating that another app has - * disconnected from a specific PrivateChannel and will no longer interact with it. + * Hello message sent by an application to a parent window or frame when attempting to + * establish connectivity to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelOnDisconnectEvent { +export interface WebConnectionProtocol1Hello { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for a Web Connection Protocol message. */ - meta: BroadcastEventMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload contains details of the event that the app is being notified about. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelOnDisconnectEventPayload; + payload: WebConnectionProtocol1HelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "privateChannelOnDisconnectEvent"; + type: "WCP1Hello"; } /** - * The message payload contains details of the event that the app is being notified about. + * Metadata for a Web Connection Protocol message. */ -export interface PrivateChannelOnDisconnectEventPayload { - /** - * The Id of the PrivateChannel that the app has disconnected from. - */ - privateChannelId: string; +export interface WebConnectionProtocol1HelloMeta { + connectionAttemptUuid: string; + timestamp: Date; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that another app has - * unsubscribed a context listener from a specific PrivateChannel. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelOnUnsubscribeEvent { +export interface WebConnectionProtocol1HelloPayload { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - meta: BroadcastEventMeta; + actualUrl: string; /** - * The message payload contains details of the event that the app is being notified about. + * A flag that may be used to indicate that a channel selector user interface is or is not + * required. Set to `false` if the app includes its own interface for selecting channels or + * does not work with user channels. */ - payload: PrivateChannelOnUnsubscribeEventPayload; + channelSelector?: boolean; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The version of FDC3 API that the app supports. */ - type: "privateChannelOnUnsubscribeEvent"; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface PrivateChannelOnUnsubscribeEventPayload { + fdc3Version: string; /** - * The type of the context listener unsubscribed from the channel by another app, or null if - * it was listening to all types. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - contextType: null | string; + identityUrl: string; /** - * The Id of the PrivateChannel that the listener was unsubscribed from. + * A flag that may be used to indicate that an intent resolver is or is not required. Set to + * `false` if no intents, or only targeted intents, are raised. */ - privateChannelId: string; + intentResolver?: boolean; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to unsubscribe a context listener. + * Response from a Desktop Agent to an application requesting access to it indicating that + * it should load a specified URL into a hidden iframe in order to establish connectivity to + * a Desktop Agent. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerRequest { +export interface WebConnectionProtocol2LoadURL { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelUnsubscribeEventListenerRequestPayload; + payload: WebConnectionProtocol2LoadURLPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: "privateChannelUnsubscribeEventListenerRequest"; + type: "WCP2LoadUrl"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelUnsubscribeEventListenerRequestPayload { - listenerUUID: string; +export interface WebConnectionProtocol2LoadURLPayload { + /** + * A URL which can be used to establish communication with the Desktop Agent, via loading + * the URL into an iframe and restarting the Web Connection protocol with the iframe as the + * target. + */ + iframeUrl: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a privateChannelUnsubscribeEventListener request. + * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that + * should be used for subsequent communication steps. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerResponse { +export interface WebConnectionProtocol3Handshake { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: BroadcastResponseResponsePayload; + payload: WebConnectionProtocol3HandshakePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "privateChannelUnsubscribeEventListenerResponse"; + type: "WCP3Handshake"; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to raise an unspecified intent for a specified context. - * - * A request message from an FDC3-enabled app to a Desktop Agent. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextRequest { +export interface WebConnectionProtocol3HandshakePayload { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Indicates whether a channel selector user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the channel selector (as the + * Desktop Agent will handle it another way). */ - meta: AddContextListenerRequestMeta; + channelSelectorUrl: boolean | string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The version of FDC3 API that the Desktop Agent will provide support for. */ - payload: RaiseIntentForContextRequestPayload; + fdc3Version: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Indicates whether an intent resolver user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the intent resolver (as the + * Desktop Agent will handle it another way). */ - type: "raiseIntentForContextRequest"; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface RaiseIntentForContextRequestPayload { - app?: AppIdentifier; - context: Context; + intentResolverUrl: boolean | string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntentForContext request. + * Identity Validation request from an app attempting to connect to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentForContextResponse { +export interface WebConnectionProtocol4ValidateAppIdentity { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentForContextResponsePayload; + payload: WebConnectionProtocol4ValidateAppIdentityPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "raiseIntentForContextResponse"; + type: "WCP4ValidateAppIdentity"; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). - * - * Response to a raiseIntentForContext request that needs additional resolution (i.e. show - * an intent resolver UI). - * - * Used if a raiseIntent request resulted in an error. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol4ValidateAppIdentityPayload { /** - * Used if the raiseIntent request was successfully resolved. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - intentResolution?: IntentResolution; + actualUrl: string; /** - * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing - * an intent resolver) before it can be handled. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - appIntents?: AppIntent[]; -} - -/** - * Used if the raiseIntent request was successfully resolved. - * - * IntentResolution provides a standard format for data returned upon resolving an intent. - * - * ```javascript - * //resolve a "Chain" type intent - * let resolution = await agent.raiseIntent("intentName", context); - * - * //resolve a "Client-Service" type intent with a data response or a Channel - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { - * console.log(`${resolution.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return data` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * - * // Use metadata about the resolving app instance to target a further intent - * await agent.raiseIntent("intentName", context, resolution.source); - * ``` - */ -export interface IntentResolution { + identityUrl: string; /** - * The intent that was raised. May be used to determine which intent the user - * chose in response to `fdc3.raiseIntentForContext()`. + * If an application has previously connected to the Desktop Agent, it may specify its prior + * instance id and associated instance UUID to request the same same instance Id be assigned. */ - intent: string; + instanceId?: string; /** - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. + * Instance UUID associated with the requested instanceId. */ - source: AppIdentifier; + instanceUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to raise an intent for a context. + * Message sent by the Desktop Agent to an app if their identity validation fails. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentRequest { +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentRequestPayload; + payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: "raiseIntentRequest"; + type: "WCP5ValidateAppIdentityFailedResponse"; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentRequestPayload { - app?: AppIdentifier; - context: Context; - intent: string; +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { + message?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntent request. + * Message sent by the Desktop Agent to an app after successful identity validation. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; + /** + * Identifies the type of the connection step message. + */ + type: "WCP5ValidateAppIdentityResponse"; +} + +/** + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentResponse { +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The appId that the app's identity was validated against. */ - meta: AddContextListenerResponseMeta; + appId: string; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. */ - payload: RaiseIntentResponsePayload; + implementationMetadata: ImplementationMetadata; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The instance Id granted to the application by the Desktop Agent. */ - type: "raiseIntentResponse"; + instanceId: string; + /** + * Instance UUID associated with the instanceId granted, which may be used to retrieve the + * same instanceId if the app is reloaded or navigates. + */ + instanceUuid: string; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). - * - * Response to a raiseIntent request that needs additional resolution (i.e. show an intent - * resolver UI). + * Identifies the type of the connection step message. + */ + +/** + * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the + * window or navigating). Desktop Agents should close the MessagePort after receiving this + * message, but retain instance details in case the application reconnects (e.g. after a + * navigation event). * - * Used if a raiseIntent request resulted in an error. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol6Goodbye { /** - * Used if the raiseIntent request was successfully resolved. + * Metadata for a Web Connection Protocol message. */ - intentResolution?: IntentResolution; + meta: WebConnectionProtocol6GoodbyeMeta; /** - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * Identifies the type of the connection step message. */ - appIntent?: AppIntent; + type: "WCP6Goodbye"; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Metadata for a Web Connection Protocol message. */ +export interface WebConnectionProtocol6GoodbyeMeta { + timestamp: Date; +} /** - * A secondary response to a request to raise an intent used to deliver the intent result. - * This message should quote the original requestUuid of the raiseIntentRequest message in - * its `meta.requestUuid` field. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * Identifies the type of the connection step message. */ -export interface RaiseIntentResultResponse { + +/** + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocolMessage { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: ConnectionStepMetadata; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentResultResponsePayload; + payload?: { [key: string]: any }; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: "raiseIntentResultResponse"; + type: ConnectionStepMessageType; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Metadata for a Web Connection Protocol message. */ -export interface RaiseIntentResultResponsePayload { - error?: ResponsePayloadError; - intentResult?: IntentResult; +export interface ConnectionStepMetadata { + timestamp: Date; + connectionAttemptUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ +export type ConnectionStepMessageType = "WCP1Hello" | "WCP2LoadUrl" | "WCP3Handshake" | "WCP4ValidateAppIdentity" | "WCP5ValidateAppIdentityFailedResponse" | "WCP5ValidateAppIdentityResponse" | "WCP6Goodbye"; // Converts JSON strings to/from your types // and asserts the results of JSON.parse at runtime export class Convert { - public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { - return cast(JSON.parse(json), r("WebConnectionProtocol1Hello")); - } - - public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol1Hello")), null, 2); - } - - public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { - return cast(JSON.parse(json), r("WebConnectionProtocol2LoadURL")); - } - - public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol2LoadURL")), null, 2); - } - - public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { - return cast(JSON.parse(json), r("WebConnectionProtocol3Handshake")); - } - - public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol3Handshake")), null, 2); - } - - public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { - return cast(JSON.parse(json), r("WebConnectionProtocol4ValidateAppIdentity")); - } - - public static webConnectionProtocol4ValidateAppIdentityToJson(value: WebConnectionProtocol4ValidateAppIdentity): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol4ValidateAppIdentity")), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json: string): WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")); - } - - public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value: WebConnectionProtocol5ValidateAppIdentityFailedResponse): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json: string): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")); - } - - public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")), null, 2); - } - - public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { - return cast(JSON.parse(json), r("WebConnectionProtocol6Goodbye")); - } - - public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol6Goodbye")), null, 2); - } - - public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { - return cast(JSON.parse(json), r("WebConnectionProtocolMessage")); - } - - public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocolMessage")), null, 2); - } - public static toAddContextListenerRequest(json: string): AddContextListenerRequest { return cast(JSON.parse(json), r("AddContextListenerRequest")); } @@ -4002,14 +3938,6 @@ export class Convert { return JSON.stringify(uncast(value, r("EventListenerUnsubscribeResponse")), null, 2); } - public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { - return cast(JSON.parse(json), r("Fdc3UserInterfaceChannelSelected")); - } - - public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannelSelected")), null, 2); - } - public static toFdc3UserInterfaceChannels(json: string): Fdc3UserInterfaceChannels { return cast(JSON.parse(json), r("Fdc3UserInterfaceChannels")); } @@ -4018,6 +3946,14 @@ export class Convert { return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannels")), null, 2); } + public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { + return cast(JSON.parse(json), r("Fdc3UserInterfaceChannelSelected")); + } + + public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { + return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannelSelected")), null, 2); + } + public static toFdc3UserInterfaceDrag(json: string): Fdc3UserInterfaceDrag { return cast(JSON.parse(json), r("Fdc3UserInterfaceDrag")); } @@ -4426,12 +4362,76 @@ export class Convert { return JSON.stringify(uncast(value, r("RaiseIntentResponse")), null, 2); } - public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { - return cast(JSON.parse(json), r("RaiseIntentResultResponse")); + public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { + return cast(JSON.parse(json), r("RaiseIntentResultResponse")); + } + + public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { + return JSON.stringify(uncast(value, r("RaiseIntentResultResponse")), null, 2); + } + + public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { + return cast(JSON.parse(json), r("WebConnectionProtocol1Hello")); + } + + public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol1Hello")), null, 2); + } + + public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { + return cast(JSON.parse(json), r("WebConnectionProtocol2LoadURL")); + } + + public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol2LoadURL")), null, 2); + } + + public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { + return cast(JSON.parse(json), r("WebConnectionProtocol3Handshake")); + } + + public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol3Handshake")), null, 2); + } + + public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { + return cast(JSON.parse(json), r("WebConnectionProtocol4ValidateAppIdentity")); + } + + public static webConnectionProtocol4ValidateAppIdentityToJson(value: WebConnectionProtocol4ValidateAppIdentity): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol4ValidateAppIdentity")), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json: string): WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")); + } + + public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value: WebConnectionProtocol5ValidateAppIdentityFailedResponse): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json: string): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")); + } + + public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")), null, 2); + } + + public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { + return cast(JSON.parse(json), r("WebConnectionProtocol6Goodbye")); + } + + public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocol6Goodbye")), null, 2); + } + + public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { + return cast(JSON.parse(json), r("WebConnectionProtocolMessage")); } - public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { - return JSON.stringify(uncast(value, r("RaiseIntentResultResponse")), null, 2); + public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { + return JSON.stringify(uncast(value, r("WebConnectionProtocolMessage")), null, 2); } } @@ -4588,123 +4588,6 @@ function r(name: string) { } const typeMap: any = { - "WebConnectionProtocol1Hello": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol1HelloPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol1HelloType") }, - ], false), - "WebConnectionProtocol1HelloMeta": o([ - { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: "" }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "WebConnectionProtocol1HelloPayload": o([ - { json: "actualUrl", js: "actualUrl", typ: "" }, - { json: "channelSelector", js: "channelSelector", typ: u(undefined, true) }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "identityUrl", js: "identityUrl", typ: "" }, - { json: "intentResolver", js: "intentResolver", typ: u(undefined, true) }, - ], "any"), - "WebConnectionProtocol2LoadURL": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol2LoadURLPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol2LoadURLType") }, - ], false), - "WebConnectionProtocol2LoadURLPayload": o([ - { json: "iframeUrl", js: "iframeUrl", typ: "" }, - ], "any"), - "WebConnectionProtocol3Handshake": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol3HandshakePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol3HandshakeType") }, - ], false), - "WebConnectionProtocol3HandshakePayload": o([ - { json: "channelSelectorUrl", js: "channelSelectorUrl", typ: u(true, "") }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "intentResolverUrl", js: "intentResolverUrl", typ: u(true, "") }, - ], false), - "WebConnectionProtocol4ValidateAppIdentity": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol4ValidateAppIdentityPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol4ValidateAppIdentityType") }, - ], false), - "WebConnectionProtocol4ValidateAppIdentityPayload": o([ - { json: "actualUrl", js: "actualUrl", typ: "" }, - { json: "identityUrl", js: "identityUrl", typ: "" }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - { json: "instanceUuid", js: "instanceUuid", typ: u(undefined, "") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentityFailedResponse": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponseType") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload": o([ - { json: "message", js: "message", typ: u(undefined, "") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentitySuccessResponse": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponseType") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "implementationMetadata", js: "implementationMetadata", typ: r("ImplementationMetadata") }, - { json: "instanceId", js: "instanceId", typ: "" }, - { json: "instanceUuid", js: "instanceUuid", typ: "" }, - ], false), - "ImplementationMetadata": o([ - { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, - { json: "provider", js: "provider", typ: "" }, - { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, - ], false), - "AppMetadata": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "description", js: "description", typ: u(undefined, "") }, - { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, - { json: "icons", js: "icons", typ: u(undefined, a(r("Icon"))) }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - { json: "instanceMetadata", js: "instanceMetadata", typ: u(undefined, m("any")) }, - { json: "name", js: "name", typ: u(undefined, "") }, - { json: "resultType", js: "resultType", typ: u(undefined, u(null, "")) }, - { json: "screenshots", js: "screenshots", typ: u(undefined, a(r("Image"))) }, - { json: "title", js: "title", typ: u(undefined, "") }, - { json: "tooltip", js: "tooltip", typ: u(undefined, "") }, - { json: "version", js: "version", typ: u(undefined, "") }, - ], false), - "Icon": o([ - { json: "size", js: "size", typ: u(undefined, "") }, - { json: "src", js: "src", typ: "" }, - { json: "type", js: "type", typ: u(undefined, "") }, - ], false), - "Image": o([ - { json: "label", js: "label", typ: u(undefined, "") }, - { json: "size", js: "size", typ: u(undefined, "") }, - { json: "src", js: "src", typ: "" }, - { json: "type", js: "type", typ: u(undefined, "") }, - ], false), - "OptionalFeatures": o([ - { json: "DesktopAgentBridging", js: "DesktopAgentBridging", typ: true }, - { json: "OriginatingAppMetadata", js: "OriginatingAppMetadata", typ: true }, - { json: "UserChannelMembershipAPIs", js: "UserChannelMembershipAPIs", typ: true }, - ], false), - "WebConnectionProtocol6Goodbye": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol6GoodbyeMeta") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol6GoodbyeType") }, - ], false), - "WebConnectionProtocol6GoodbyeMeta": o([ - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "WebConnectionProtocolMessage": o([ - { json: "meta", js: "meta", typ: r("ConnectionStepMetadata") }, - { json: "payload", js: "payload", typ: u(undefined, m("any")) }, - { json: "type", js: "type", typ: r("ConnectionStepMessageType") }, - ], false), - "ConnectionStepMetadata": o([ - { json: "timestamp", js: "timestamp", typ: Date }, - { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: u(undefined, "") }, - ], false), "AddContextListenerRequest": o([ { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, { json: "payload", js: "payload", typ: r("AddContextListenerRequestPayload") }, @@ -4902,13 +4785,6 @@ const typeMap: any = { { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, { json: "type", js: "type", typ: r("EventListenerUnsubscribeResponseType") }, ], false), - "Fdc3UserInterfaceChannelSelected": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelSelectedPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelSelectedType") }, - ], false), - "Fdc3UserInterfaceChannelSelectedPayload": o([ - { json: "selected", js: "selected", typ: u(null, "") }, - ], false), "Fdc3UserInterfaceChannels": o([ { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelsPayload") }, { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelsType") }, @@ -4917,6 +4793,13 @@ const typeMap: any = { { json: "selected", js: "selected", typ: u(null, "") }, { json: "userChannels", js: "userChannels", typ: a(r("Channel")) }, ], false), + "Fdc3UserInterfaceChannelSelected": o([ + { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelSelectedPayload") }, + { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelSelectedType") }, + ], false), + "Fdc3UserInterfaceChannelSelectedPayload": o([ + { json: "selected", js: "selected", typ: u(null, "") }, + ], false), "Fdc3UserInterfaceDrag": o([ { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceDragPayload") }, { json: "type", js: "type", typ: r("Fdc3UserInterfaceDragType") }, @@ -4971,6 +4854,31 @@ const typeMap: any = { { json: "apps", js: "apps", typ: a(r("AppMetadata")) }, { json: "intent", js: "intent", typ: r("IntentMetadata") }, ], false), + "AppMetadata": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "description", js: "description", typ: u(undefined, "") }, + { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, + { json: "icons", js: "icons", typ: u(undefined, a(r("Icon"))) }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + { json: "instanceMetadata", js: "instanceMetadata", typ: u(undefined, m("any")) }, + { json: "name", js: "name", typ: u(undefined, "") }, + { json: "resultType", js: "resultType", typ: u(undefined, u(null, "")) }, + { json: "screenshots", js: "screenshots", typ: u(undefined, a(r("Image"))) }, + { json: "title", js: "title", typ: u(undefined, "") }, + { json: "tooltip", js: "tooltip", typ: u(undefined, "") }, + { json: "version", js: "version", typ: u(undefined, "") }, + ], false), + "Icon": o([ + { json: "size", js: "size", typ: u(undefined, "") }, + { json: "src", js: "src", typ: "" }, + { json: "type", js: "type", typ: u(undefined, "") }, + ], false), + "Image": o([ + { json: "label", js: "label", typ: u(undefined, "") }, + { json: "size", js: "size", typ: u(undefined, "") }, + { json: "src", js: "src", typ: "" }, + { json: "type", js: "type", typ: u(undefined, "") }, + ], false), "IntentMetadata": o([ { json: "displayName", js: "displayName", typ: u(undefined, "") }, { json: "name", js: "name", typ: "" }, @@ -5124,6 +5032,18 @@ const typeMap: any = { { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, { json: "implementationMetadata", js: "implementationMetadata", typ: u(undefined, r("ImplementationMetadata")) }, ], false), + "ImplementationMetadata": o([ + { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, + { json: "provider", js: "provider", typ: "" }, + { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, + ], false), + "OptionalFeatures": o([ + { json: "DesktopAgentBridging", js: "DesktopAgentBridging", typ: true }, + { json: "OriginatingAppMetadata", js: "OriginatingAppMetadata", typ: true }, + { json: "UserChannelMembershipAPIs", js: "UserChannelMembershipAPIs", typ: true }, + ], false), "GetOrCreateChannelRequest": o([ { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, { json: "payload", js: "payload", typ: r("GetOrCreateChannelRequestPayload") }, @@ -5360,65 +5280,115 @@ const typeMap: any = { { json: "intent", js: "intent", typ: "" }, { json: "source", js: "source", typ: r("AppIdentifier") }, ], false), - "RaiseIntentRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentRequestPayload") }, - { json: "type", js: "type", typ: r("RaiseIntentRequestType") }, + "RaiseIntentRequest": o([ + { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentRequestPayload") }, + { json: "type", js: "type", typ: r("RaiseIntentRequestType") }, + ], false), + "RaiseIntentRequestPayload": o([ + { json: "app", js: "app", typ: u(undefined, r("AppIdentifier")) }, + { json: "context", js: "context", typ: r("Context") }, + { json: "intent", js: "intent", typ: "" }, + ], false), + "RaiseIntentResponse": o([ + { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentResponseType") }, + ], false), + "RaiseIntentResponsePayload": o([ + { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, + { json: "intentResolution", js: "intentResolution", typ: u(undefined, r("IntentResolution")) }, + { json: "appIntent", js: "appIntent", typ: u(undefined, r("AppIntent")) }, + ], false), + "RaiseIntentResultResponse": o([ + { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, + { json: "payload", js: "payload", typ: r("RaiseIntentResultResponsePayload") }, + { json: "type", js: "type", typ: r("RaiseIntentResultResponseType") }, + ], false), + "RaiseIntentResultResponsePayload": o([ + { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, + { json: "intentResult", js: "intentResult", typ: u(undefined, r("IntentResult")) }, + ], false), + "WebConnectionProtocol1Hello": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol1HelloPayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol1HelloType") }, + ], false), + "WebConnectionProtocol1HelloMeta": o([ + { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: "" }, + { json: "timestamp", js: "timestamp", typ: Date }, + ], false), + "WebConnectionProtocol1HelloPayload": o([ + { json: "actualUrl", js: "actualUrl", typ: "" }, + { json: "channelSelector", js: "channelSelector", typ: u(undefined, true) }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "identityUrl", js: "identityUrl", typ: "" }, + { json: "intentResolver", js: "intentResolver", typ: u(undefined, true) }, + ], "any"), + "WebConnectionProtocol2LoadURL": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol2LoadURLPayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol2LoadURLType") }, + ], false), + "WebConnectionProtocol2LoadURLPayload": o([ + { json: "iframeUrl", js: "iframeUrl", typ: "" }, + ], "any"), + "WebConnectionProtocol3Handshake": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol3HandshakePayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol3HandshakeType") }, + ], false), + "WebConnectionProtocol3HandshakePayload": o([ + { json: "channelSelectorUrl", js: "channelSelectorUrl", typ: u(true, "") }, + { json: "fdc3Version", js: "fdc3Version", typ: "" }, + { json: "intentResolverUrl", js: "intentResolverUrl", typ: u(true, "") }, + ], false), + "WebConnectionProtocol4ValidateAppIdentity": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol4ValidateAppIdentityPayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol4ValidateAppIdentityType") }, + ], false), + "WebConnectionProtocol4ValidateAppIdentityPayload": o([ + { json: "actualUrl", js: "actualUrl", typ: "" }, + { json: "identityUrl", js: "identityUrl", typ: "" }, + { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, + { json: "instanceUuid", js: "instanceUuid", typ: u(undefined, "") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentityFailedResponse": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponseType") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload": o([ + { json: "message", js: "message", typ: u(undefined, "") }, + ], false), + "WebConnectionProtocol5ValidateAppIdentitySuccessResponse": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, + { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponseType") }, ], false), - "RaiseIntentRequestPayload": o([ - { json: "app", js: "app", typ: u(undefined, r("AppIdentifier")) }, - { json: "context", js: "context", typ: r("Context") }, - { json: "intent", js: "intent", typ: "" }, + "WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload": o([ + { json: "appId", js: "appId", typ: "" }, + { json: "implementationMetadata", js: "implementationMetadata", typ: r("ImplementationMetadata") }, + { json: "instanceId", js: "instanceId", typ: "" }, + { json: "instanceUuid", js: "instanceUuid", typ: "" }, ], false), - "RaiseIntentResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentResponsePayload") }, - { json: "type", js: "type", typ: r("RaiseIntentResponseType") }, + "WebConnectionProtocol6Goodbye": o([ + { json: "meta", js: "meta", typ: r("WebConnectionProtocol6GoodbyeMeta") }, + { json: "type", js: "type", typ: r("WebConnectionProtocol6GoodbyeType") }, ], false), - "RaiseIntentResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "intentResolution", js: "intentResolution", typ: u(undefined, r("IntentResolution")) }, - { json: "appIntent", js: "appIntent", typ: u(undefined, r("AppIntent")) }, + "WebConnectionProtocol6GoodbyeMeta": o([ + { json: "timestamp", js: "timestamp", typ: Date }, ], false), - "RaiseIntentResultResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentResultResponsePayload") }, - { json: "type", js: "type", typ: r("RaiseIntentResultResponseType") }, + "WebConnectionProtocolMessage": o([ + { json: "meta", js: "meta", typ: r("ConnectionStepMetadata") }, + { json: "payload", js: "payload", typ: u(undefined, m("any")) }, + { json: "type", js: "type", typ: r("ConnectionStepMessageType") }, ], false), - "RaiseIntentResultResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - { json: "intentResult", js: "intentResult", typ: u(undefined, r("IntentResult")) }, + "ConnectionStepMetadata": o([ + { json: "timestamp", js: "timestamp", typ: Date }, + { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: u(undefined, "") }, ], false), - "WebConnectionProtocol1HelloType": [ - "WCP1Hello", - ], - "WebConnectionProtocol2LoadURLType": [ - "WCP2LoadUrl", - ], - "WebConnectionProtocol3HandshakeType": [ - "WCP3Handshake", - ], - "WebConnectionProtocol4ValidateAppIdentityType": [ - "WCP4ValidateAppIdentity", - ], - "WebConnectionProtocol5ValidateAppIdentityFailedResponseType": [ - "WCP5ValidateAppIdentityFailedResponse", - ], - "WebConnectionProtocol5ValidateAppIdentitySuccessResponseType": [ - "WCP5ValidateAppIdentityResponse", - ], - "WebConnectionProtocol6GoodbyeType": [ - "WCP6Goodbye", - ], - "ConnectionStepMessageType": [ - "WCP1Hello", - "WCP2LoadUrl", - "WCP3Handshake", - "WCP4ValidateAppIdentity", - "WCP5ValidateAppIdentityFailedResponse", - "WCP5ValidateAppIdentityResponse", - "WCP6Goodbye", - ], "AddContextListenerRequestType": [ "addContextListenerRequest", ], @@ -5583,12 +5553,12 @@ const typeMap: any = { "EventListenerUnsubscribeResponseType": [ "eventListenerUnsubscribeResponse", ], - "Fdc3UserInterfaceChannelSelectedType": [ - "Fdc3UserInterfaceChannelSelected", - ], "Fdc3UserInterfaceChannelsType": [ "Fdc3UserInterfaceChannels", ], + "Fdc3UserInterfaceChannelSelectedType": [ + "Fdc3UserInterfaceChannelSelected", + ], "Fdc3UserInterfaceDragType": [ "Fdc3UserInterfaceDrag", ], @@ -5767,196 +5737,65 @@ const typeMap: any = { ], "PrivateChannelOnUnsubscribeEventType": [ "privateChannelOnUnsubscribeEvent", - ], - "PrivateChannelUnsubscribeEventListenerRequestType": [ - "privateChannelUnsubscribeEventListenerRequest", - ], - "PrivateChannelUnsubscribeEventListenerResponseType": [ - "privateChannelUnsubscribeEventListenerResponse", - ], - "RaiseIntentForContextRequestType": [ - "raiseIntentForContextRequest", - ], - "RaiseIntentForContextResponseType": [ - "raiseIntentForContextResponse", - ], - "RaiseIntentRequestType": [ - "raiseIntentRequest", - ], - "RaiseIntentResponseType": [ - "raiseIntentResponse", - ], - "RaiseIntentResultResponseType": [ - "raiseIntentResultResponse", - ], -}; - -export type AppRequestMessage = AddContextListenerRequest | AddEventListenerRequest | AddIntentListenerRequest | BroadcastRequest | ContextListenerUnsubscribeRequest | CreatePrivateChannelRequest | EventListenerUnsubscribeRequest | FindInstancesRequest | FindIntentRequest | FindIntentsByContextRequest | GetAppMetadataRequest | GetCurrentChannelRequest | GetCurrentContextRequest | GetInfoRequest | GetOrCreateChannelRequest | GetUserChannelsRequest | HeartbeatAcknowledgementRequest | IntentListenerUnsubscribeRequest | IntentResultRequest | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest | PrivateChannelAddEventListenerRequest | PrivateChannelDisconnectRequest | PrivateChannelUnsubscribeEventListenerRequest | RaiseIntentForContextRequest | RaiseIntentRequest; - -export type AgentResponseMessage = AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse; - -export type AgentEventMessage = BroadcastEvent | ChannelChangedEvent | HeartbeatEvent | IntentEvent | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnDisconnectEvent | PrivateChannelOnUnsubscribeEvent; - -/** - * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - return value != null && value.type === 'WCP1Hello'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - try { - Convert.webConnectionProtocol1HelloToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = "WebConnectionProtocol1Hello"; - -/** - * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - return value != null && value.type === 'WCP2LoadUrl'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - try { - Convert.webConnectionProtocol2LoadURLToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = "WebConnectionProtocol2LoadURL"; - -/** - * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - return value != null && value.type === 'WCP3Handshake'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - try { - Convert.webConnectionProtocol3HandshakeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = "WebConnectionProtocol3Handshake"; - -/** - * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { - return value != null && value.type === 'WCP4ValidateAppIdentity'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { - try { - Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = "WebConnectionProtocol4ValidateAppIdentity"; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentityFailedResponse"; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentitySuccessResponse"; - -/** - * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - return value != null && value.type === 'WCP6Goodbye'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - try { - Convert.webConnectionProtocol6GoodbyeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} + ], + "PrivateChannelUnsubscribeEventListenerRequestType": [ + "privateChannelUnsubscribeEventListenerRequest", + ], + "PrivateChannelUnsubscribeEventListenerResponseType": [ + "privateChannelUnsubscribeEventListenerResponse", + ], + "RaiseIntentForContextRequestType": [ + "raiseIntentForContextRequest", + ], + "RaiseIntentForContextResponseType": [ + "raiseIntentForContextResponse", + ], + "RaiseIntentRequestType": [ + "raiseIntentRequest", + ], + "RaiseIntentResponseType": [ + "raiseIntentResponse", + ], + "RaiseIntentResultResponseType": [ + "raiseIntentResultResponse", + ], + "WebConnectionProtocol1HelloType": [ + "WCP1Hello", + ], + "WebConnectionProtocol2LoadURLType": [ + "WCP2LoadUrl", + ], + "WebConnectionProtocol3HandshakeType": [ + "WCP3Handshake", + ], + "WebConnectionProtocol4ValidateAppIdentityType": [ + "WCP4ValidateAppIdentity", + ], + "WebConnectionProtocol5ValidateAppIdentityFailedResponseType": [ + "WCP5ValidateAppIdentityFailedResponse", + ], + "WebConnectionProtocol5ValidateAppIdentitySuccessResponseType": [ + "WCP5ValidateAppIdentityResponse", + ], + "WebConnectionProtocol6GoodbyeType": [ + "WCP6Goodbye", + ], + "ConnectionStepMessageType": [ + "WCP1Hello", + "WCP2LoadUrl", + "WCP3Handshake", + "WCP4ValidateAppIdentity", + "WCP5ValidateAppIdentityFailedResponse", + "WCP5ValidateAppIdentityResponse", + "WCP6Goodbye", + ], +}; -export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = "WebConnectionProtocol6Goodbye"; +export type AppRequestMessage = AddContextListenerRequest | AddEventListenerRequest | AddIntentListenerRequest | BroadcastRequest | ContextListenerUnsubscribeRequest | CreatePrivateChannelRequest | EventListenerUnsubscribeRequest | FindInstancesRequest | FindIntentRequest | FindIntentsByContextRequest | GetAppMetadataRequest | GetCurrentChannelRequest | GetCurrentContextRequest | GetInfoRequest | GetOrCreateChannelRequest | GetUserChannelsRequest | HeartbeatAcknowledgementRequest | IntentListenerUnsubscribeRequest | IntentResultRequest | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest | PrivateChannelAddEventListenerRequest | PrivateChannelDisconnectRequest | PrivateChannelUnsubscribeEventListenerRequest | RaiseIntentForContextRequest | RaiseIntentRequest; -/** - * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { - try { - Convert.webConnectionProtocolMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } -} +export type AgentResponseMessage = AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse; -export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; +export type AgentEventMessage = BroadcastEvent | ChannelChangedEvent | HeartbeatEvent | IntentEvent | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnDisconnectEvent | PrivateChannelOnUnsubscribeEvent; /** * Returns true if the value has a type property with value 'addContextListenerRequest'. This is a fast check that does not check the format of the message @@ -6295,46 +6134,46 @@ export function isValidEventListenerUnsubscribeResponse(value: any): value is Ev export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "EventListenerUnsubscribeResponse"; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { - return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; +export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { + return value != null && value.type === 'Fdc3UserInterfaceChannels'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { +export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { try { - Convert.fdc3UserInterfaceChannelSelectedToJson(value); + Convert.fdc3UserInterfaceChannelsToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = "Fdc3UserInterfaceChannelSelected"; +export const FDC3_USER_INTERFACE_CHANNELS_TYPE = "Fdc3UserInterfaceChannels"; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { - return value != null && value.type === 'Fdc3UserInterfaceChannels'; +export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { + return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { +export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { try { - Convert.fdc3UserInterfaceChannelsToJson(value); + Convert.fdc3UserInterfaceChannelSelectedToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNELS_TYPE = "Fdc3UserInterfaceChannels"; +export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = "Fdc3UserInterfaceChannelSelected"; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceDrag'. This is a fast check that does not check the format of the message @@ -7419,4 +7258,165 @@ export function isValidRaiseIntentResultResponse(value: any): value is RaiseInte } } -export const RAISE_INTENT_RESULT_RESPONSE_TYPE = "RaiseIntentResultResponse"; +export const RAISE_INTENT_RESULT_RESPONSE_TYPE = "RaiseIntentResultResponse"; + +/** + * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + return value != null && value.type === 'WCP1Hello'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + try { + Convert.webConnectionProtocol1HelloToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = "WebConnectionProtocol1Hello"; + +/** + * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + return value != null && value.type === 'WCP2LoadUrl'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + try { + Convert.webConnectionProtocol2LoadURLToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = "WebConnectionProtocol2LoadURL"; + +/** + * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + return value != null && value.type === 'WCP3Handshake'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + try { + Convert.webConnectionProtocol3HandshakeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = "WebConnectionProtocol3Handshake"; + +/** + * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { + return value != null && value.type === 'WCP4ValidateAppIdentity'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { + try { + Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = "WebConnectionProtocol4ValidateAppIdentity"; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentityFailedResponse"; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentitySuccessResponse"; + +/** + * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + return value != null && value.type === 'WCP6Goodbye'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + try { + Convert.webConnectionProtocol6GoodbyeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = "WebConnectionProtocol6Goodbye"; + +/** + * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { + try { + Convert.webConnectionProtocolMessageToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; From 314b3137710697eded379178b7a21495449ca8b0 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 2 Dec 2024 17:33:33 +0000 Subject: [PATCH 25/90] some minor logging additions for debug use --- packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts | 3 +-- packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts | 2 +- packages/testing/src/steps/generic.steps.ts | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts index d267b3944..e07a9f834 100644 --- a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts @@ -82,7 +82,7 @@ export class DefaultAppSupport implements AppSupport { meta: this.messaging.createMeta() } - const out = await this.messaging.exchange(request, "getInfoResponse", OpenError.AppTimeout); + const out = await this.messaging.exchange(request, "getInfoResponse", "timed out waiting for getInfo response!"); if (out.payload.implementationMetadata) { return out.payload.implementationMetadata; } else { @@ -99,7 +99,6 @@ export class DefaultAppSupport implements AppSupport { }; return unknownImpl; } - } } \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index 118896def..287bfd0de 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -47,7 +47,7 @@ export abstract class AbstractMessaging implements Messaging { setTimeout(() => { this.unregister(id); if (!done) { - console.error(`Rejecting after ${this.getTimeoutMs()}ms with ${timeoutErrorMessage}`); + console.error(`waitFor rejecting after ${this.getTimeoutMs()}ms with ${timeoutErrorMessage}`); reject(new Error(timeoutErrorMessage)); } }, this.getTimeoutMs()); diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index 3a737e9a7..884414449 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -26,8 +26,10 @@ export function setupGenericSteps() { const fn = object[fnName]; const result = await fn.call(object) this.props['result'] = result; + console.log("Result:", result); } catch (error) { this.props['result'] = error + console.log("Result was an error:", error); } }) From 7914ac2f92bd6656a4e1ff753a16e1f4a713da80 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 3 Dec 2024 23:38:25 +0000 Subject: [PATCH 26/90] improving typescript use in fdc3-agent-proxy --- packages/fdc3-agent-proxy/src/Messaging.ts | 6 +- .../src/channels/DefaultChannel.ts | 25 +- .../src/channels/DefaultChannelSupport.ts | 336 ++++++++++-------- .../src/listeners/DefaultContextListener.ts | 4 +- .../listeners/PrivateChannelEventListener.ts | 2 +- ...tener.ts => UserChannelContextListener.ts} | 6 +- .../src/messaging/message-port.ts | 6 +- 7 files changed, 217 insertions(+), 168 deletions(-) rename packages/fdc3-agent-proxy/src/listeners/{FollowingContextListener.ts => UserChannelContextListener.ts} (64%) diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index 5c8b66dab..1f3a9221e 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -40,10 +40,10 @@ export interface Messaging /*extends Connectable*/ { ): Promise; /** - * - * @param message Performs a request / response message pass + * Sends a request message and waits for a response. If the response contains a payload.error, it is thrown. + * @param message The request message to send. */ - exchange(message: object, expectedTypeName: string, timeoutErrorMessage?: string): Promise; + exchange(message: AppRequestMessage, expectedTypeName: string, timeoutErrorMessage?: string): Promise; /** * App identification used to provide source information used in diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index b3c7d866f..162a5a4bf 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -3,12 +3,8 @@ import { Context } from '@kite9/fdc3-context'; import { Messaging } from '../Messaging'; import { DefaultContextListener } from '../listeners/DefaultContextListener'; -import { BrowserTypes } from '@kite9/fdc3-schema'; +import { BroadcastRequest, BroadcastResponse, GetCurrentContextRequest, GetCurrentContextResponse } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -type BroadcastRequest = BrowserTypes.BroadcastRequest; -type BroadcastResponse = BrowserTypes.BroadcastResponse; -type GetCurrentContextResponse = BrowserTypes.GetCurrentContextResponse; -type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest; export class DefaultChannel implements Channel { readonly messaging: Messaging; @@ -55,20 +51,23 @@ export class DefaultChannel implements Channel { return response.payload.context ?? null; } - async addContextListener(contextType: any, handler?: ContextHandler): Promise { + async addContextListener(contextTypeOrHandler: string | null | ContextHandler, handler?: ContextHandler): Promise { let theContextType: string | null; let theHandler: ContextHandler; - if (contextType == null) { + if (contextTypeOrHandler == null && handler) { theContextType = null; - theHandler = handler as ContextHandler; - } else if (typeof contextType === 'string') { - theContextType = contextType; - theHandler = handler as ContextHandler; - } else { + theHandler = handler; + } else if (typeof contextTypeOrHandler === 'string' && handler) { + theContextType = contextTypeOrHandler; + theHandler = handler; + } else if (handler) { // deprecated one-arg version theContextType = null; - theHandler = contextType as ContextHandler; + theHandler = contextTypeOrHandler as ContextHandler; + } else { + //invalid call + throw new Error("Invalid arguments passed to addContextListener!"); } return await this.addContextListenerInner(theContextType, theHandler); diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index ce88e25e4..53ca1e573 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -1,154 +1,206 @@ -import { Channel, ContextHandler, Listener, PrivateChannel, ChannelSelector, EventHandler } from "@kite9/fdc3-standard"; -import { Messaging } from "../Messaging"; -import { ChannelSupport } from "./ChannelSupport"; -import { DefaultPrivateChannel } from "./DefaultPrivateChannel"; -import { DefaultChannel } from "./DefaultChannel"; -import { DefaultContextListener } from "../listeners/DefaultContextListener"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { FollowingContextListener } from "../listeners/FollowingContextListener"; -import { EventListener } from "../listeners/EventListener"; - -type ChannelDetail = BrowserTypes.Channel -type GetUserChannelsRequest = BrowserTypes.GetUserChannelsRequest -type GetUserChannelsResponse = BrowserTypes.GetUserChannelsResponse -type GetOrCreateChannelResponse = BrowserTypes.GetOrCreateChannelResponse -type GetOrCreateChannelRequest = BrowserTypes.GetOrCreateChannelRequest -type CreatePrivateChannelRequest = BrowserTypes.CreatePrivateChannelRequest -type CreatePrivateChannelResponse = BrowserTypes.CreatePrivateChannelResponse -type JoinUserChannelResponse = BrowserTypes.JoinUserChannelResponse -type JoinUserChannelRequest = BrowserTypes.JoinUserChannelRequest -type GetCurrentChannelResponse = BrowserTypes.GetCurrentChannelResponse -type GetCurrentChannelRequest = BrowserTypes.GetCurrentChannelRequest -type LeaveCurrentChannelRequest = BrowserTypes.LeaveCurrentChannelRequest -type LeaveCurrentChannelResponse = BrowserTypes.LeaveCurrentChannelResponse +import { + Channel, + ContextHandler, + Listener, + PrivateChannel, + ChannelSelector, + EventHandler, + ChannelError, +} from '@kite9/fdc3-standard'; +import { Messaging } from '../Messaging'; +import { ChannelSupport } from './ChannelSupport'; +import { DefaultPrivateChannel } from './DefaultPrivateChannel'; +import { DefaultChannel } from './DefaultChannel'; +import { DefaultContextListener } from '../listeners/DefaultContextListener'; +import { UserChannelContextListener } from '../listeners/UserChannelContextListener'; +import { EventListener } from '../listeners/EventListener'; +import { + GetCurrentChannelResponse, + GetCurrentChannelRequest, + GetUserChannelsResponse, + GetUserChannelsRequest, + GetOrCreateChannelResponse, + GetOrCreateChannelRequest, + CreatePrivateChannelResponse, + CreatePrivateChannelRequest, + LeaveCurrentChannelResponse, + LeaveCurrentChannelRequest, + JoinUserChannelResponse, + JoinUserChannelRequest, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class DefaultChannelSupport implements ChannelSupport { - - readonly messaging: Messaging - readonly channelSelector: ChannelSelector - protected userChannels: Channel[] | null = null - private followingListeners: FollowingContextListener[] = [] - - constructor(messaging: Messaging, channelSelector: ChannelSelector) { - this.messaging = messaging; - this.channelSelector = channelSelector - this.channelSelector.setChannelChangeCallback((channelId: string | null) => { - if (channelId == null) { - this.leaveUserChannel() - } else { - this.joinUserChannel(channelId) - } - }) - - this.addChannelChangedEventHandler((e) => { - this.channelSelector.updateChannel(e.details.newChannelId, this.userChannels ?? []) - }) - } - - async addChannelChangedEventHandler(handler: EventHandler): Promise { - const listener = new EventListener(this.messaging, "channelChangedEvent", handler) - await listener.register() - return listener + readonly messaging: Messaging; + readonly channelSelector: ChannelSelector; + protected userChannels: Channel[] = []; + protected userChannelListeners: UserChannelContextListener[] = []; + + constructor(messaging: Messaging, channelSelector: ChannelSelector) { + this.messaging = messaging; + this.channelSelector = channelSelector; + this.channelSelector.setChannelChangeCallback((channelId: string | null) => { + if (channelId == null) { + this.leaveUserChannel(); + } else { + this.joinUserChannel(channelId); + } + }); + + this.addChannelChangedEventHandler(e => { + this.channelSelector.updateChannel(e.details.newChannelId, this.userChannels ?? []); + }); + } + + async addChannelChangedEventHandler(handler: EventHandler): Promise { + const listener = new EventListener(this.messaging, 'channelChangedEvent', handler); + await listener.register(); + return listener; + } + + async getUserChannel(): Promise { + const request: GetCurrentChannelRequest = { + meta: this.messaging.createMeta(), + type: 'getCurrentChannelRequest', + payload: {}, + }; + const response = await this.messaging.exchange(request, 'getCurrentChannelResponse'); + //handle successful responses - errors will already have been thrown by exchange above + if (response.payload.channel) { + return new DefaultChannel( + this.messaging, + response.payload.channel.id, + 'user', + response.payload.channel.displayMetadata + ); + } else if (response.payload.channel === null) { + //this is a valid response if no channel is set + return null; + } else { + console.warn( + 'Invalid response from Desktop Agent to getCurrentChannel (channel should be explicitly null if no channel is set)!', + response.payload + ); + return null; } - - async getUserChannel(): Promise { - const response = await this.messaging.exchange({ - meta: this.messaging.createMeta(), - type: 'getCurrentChannelRequest', - payload: {} - } as GetCurrentChannelRequest, 'getCurrentChannelResponse') - - if (response.payload?.channel?.id) { - return new DefaultChannel(this.messaging, response.payload.channel.id, "user", response.payload.channel.displayMetadata) - } else { - return null - } + } + + async getUserChannels(): Promise { + const response = await this.messaging.exchange( + { + meta: this.messaging.createMeta(), + type: 'getUserChannelsRequest', + payload: {}, + } as GetUserChannelsRequest, + 'getUserChannelsResponse' + ); + //handle successful responses - errors will already have been thrown by exchange above + if (response.payload.userChannels) { + const channels = response.payload.userChannels; + this.userChannels = channels.map(c => new DefaultChannel(this.messaging, c.id, 'user', c.displayMetadata)); + } else { + console.error('Invalid response from Desktop Agent to getUserChannelsRequest!', response); + throw new Error(ChannelError.NoChannelFound); } - - async getUserChannels(): Promise { - if (!this.userChannels) { - const response = await this.messaging.exchange({ - meta: this.messaging.createMeta(), - type: 'getUserChannelsRequest', - payload: {} - } as GetUserChannelsRequest, 'getUserChannelsResponse') - - const channels: ChannelDetail[] = response.payload.userChannels ?? [] - this.userChannels = channels.map(c => new DefaultChannel(this.messaging, c.id, "user", c.displayMetadata)); - } - return this.userChannels + return this.userChannels; + } + + async getOrCreate(id: string): Promise { + const request: GetOrCreateChannelRequest = { + meta: this.messaging.createMeta(), + type: 'getOrCreateChannelRequest', + payload: { + channelId: id, + }, + }; + const response = await this.messaging.exchange(request, 'getOrCreateChannelResponse'); + //handle successful responses - errors will already have been thrown by exchange above + if (response.payload.channel) { + const out = new DefaultChannel(this.messaging, id, 'app', response.payload.channel.displayMetadata); + return out; + } else { + console.error('Invalid response from Desktop Agent to getUserChannelsRequest!', response); + throw new Error(ChannelError.CreationFailed); } - - async getOrCreate(id: string): Promise { - const response = await this.messaging.exchange({ - meta: this.messaging.createMeta(), - type: 'getOrCreateChannelRequest', - payload: { - channelId: id - } - } as GetOrCreateChannelRequest, - 'getOrCreateChannelResponse') - - const out = new DefaultChannel(this.messaging, id, "app", response.payload.channel?.displayMetadata!!) - return out + } + + async createPrivateChannel(): Promise { + const request: CreatePrivateChannelRequest = { + meta: this.messaging.createMeta(), + type: 'createPrivateChannelRequest', + payload: {}, + }; + const response = await this.messaging.exchange( + request, + 'createPrivateChannelResponse' + ); + if (response.payload.privateChannel) { + return new DefaultPrivateChannel(this.messaging, response.payload.privateChannel.id); + } else { + console.error('Invalid response from Desktop Agent to getUserChannelsRequest!', response); + throw new Error(ChannelError.CreationFailed); } - - async createPrivateChannel(): Promise { - const response = await this.messaging.exchange({ - meta: this.messaging.createMeta(), - type: 'createPrivateChannelRequest', - payload: {} - } as CreatePrivateChannelRequest, - 'createPrivateChannelResponse') - - return new DefaultPrivateChannel(this.messaging, response.payload?.privateChannel?.id!!) + } + + async leaveUserChannel(): Promise { + const request: LeaveCurrentChannelRequest = { + meta: this.messaging.createMeta(), + type: 'leaveCurrentChannelRequest', + payload: {}, + }; + await this.messaging.exchange(request, 'leaveCurrentChannelResponse'); + this.channelSelector.updateChannel(null, this.userChannels); + this.userChannelListeners.forEach(l => l.changeChannel(null)); + } + + async joinUserChannel(id: string) { + const request: JoinUserChannelRequest = { + meta: this.messaging.createMeta(), + type: 'joinUserChannelRequest', + payload: { + channelId: id, + }, + }; + await this.messaging.exchange(request, 'joinUserChannelResponse'); + this.channelSelector.updateChannel(id, this.userChannels); + for (const l of this.userChannelListeners) { + await l.changeChannel(new DefaultChannel(this.messaging, id, 'user')); } - - async leaveUserChannel(): Promise { - await this.messaging.exchange({ - meta: this.messaging.createMeta(), - type: 'leaveCurrentChannelRequest', - payload: {} - } as LeaveCurrentChannelRequest, - 'leaveCurrentChannelResponse') - - this.channelSelector.updateChannel(null, this.userChannels ?? []) - this.followingListeners.forEach(l => l.changeChannel(null)) + } + + async addContextListener(handler: ContextHandler, type: string | null): Promise { + //TODO: Figure out a better solution than inlining this class. + /** Utility class used to wrap the DefaultContextListener and ensure it gets removed + * when its unsubscribe function is called. + */ + class UnsubscribingDefaultContextListener extends DefaultContextListener { + container: DefaultChannelSupport; + + constructor( + container: DefaultChannelSupport, + messaging: Messaging, + channelId: string | null, + contextType: string | null, + handler: ContextHandler, + messageType: string = 'broadcastEvent' + ) { + super(messaging, channelId, contextType, handler, messageType); + this.container = container; + } + + async unsubscribe(): Promise { + super.unsubscribe(); + this.container.userChannelListeners = this.container.userChannelListeners.filter(l => l != this); + } } - async joinUserChannel(id: string) { - await this.messaging.exchange({ - meta: this.messaging.createMeta(), - type: 'joinUserChannelRequest', - payload: { - channelId: id - } - } as JoinUserChannelRequest, - 'joinUserChannelResponse') - - this.channelSelector.updateChannel(id, this.userChannels ?? []) - - for (const l of this.followingListeners) { - await l.changeChannel(new DefaultChannel(this.messaging, id, "user")) - } - } + const currentChannelId = (await this.getUserChannel())?.id ?? null; + const listener = new UnsubscribingDefaultContextListener(this, this.messaging, currentChannelId, type, handler); + this.userChannelListeners.push(listener); + await listener.register(); + return listener; + } - async addContextListener(handler: ContextHandler, type: string | null): Promise { - const _container = this - - class UnsubscribingDefaultContextListener extends DefaultContextListener { - async unsubscribe(): Promise { - super.unsubscribe() - _container.followingListeners = _container.followingListeners.filter(l => l != this) - } - } - - const currentChannelId = (await this.getUserChannel())?.id ?? null - const listener = new UnsubscribingDefaultContextListener(this.messaging, currentChannelId, type, handler) - this.followingListeners.push(listener) - await listener.register() - return listener - } + +} -} \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts index eb6747603..8d4c293ca 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultContextListener.ts @@ -1,10 +1,10 @@ import { ContextHandler, Channel } from '@kite9/fdc3-standard'; import { Messaging } from '../Messaging'; import { AbstractListener } from './AbstractListener'; -import { FollowingContextListener } from './FollowingContextListener'; +import { UserChannelContextListener } from './UserChannelContextListener'; import { AddContextListenerRequest, BroadcastEvent } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -export class DefaultContextListener extends AbstractListener implements FollowingContextListener { +export class DefaultContextListener extends AbstractListener implements UserChannelContextListener { private channelId: string | null; private readonly messageType: string; private readonly contextType: string | null; diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index 5a7e72e89..e0706a5c5 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -63,7 +63,7 @@ export class PrivateChannelNullEventListener extends AbstractPrivateChannelEvent break; case "privateChannelOnDisconnectEvent": type = "disconnect"; - details: null + details = null; break; } diff --git a/packages/fdc3-agent-proxy/src/listeners/FollowingContextListener.ts b/packages/fdc3-agent-proxy/src/listeners/UserChannelContextListener.ts similarity index 64% rename from packages/fdc3-agent-proxy/src/listeners/FollowingContextListener.ts rename to packages/fdc3-agent-proxy/src/listeners/UserChannelContextListener.ts index 1d46b8c00..fbd681098 100644 --- a/packages/fdc3-agent-proxy/src/listeners/FollowingContextListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/UserChannelContextListener.ts @@ -2,11 +2,11 @@ import { Channel, Listener } from '@kite9/fdc3-standard'; import { RegisterableListener } from './RegisterableListener'; /** - * This is a spercial version of a ContextListener created when the user calls the - * fdc3.addContextListener method. In this scenario, the listener will respond to broadcasts + * This is a special version of a ContextListener created when the user calls the + * fdc3.addContextListener method. In this scenario, the listener will respond to broadcasts * on whatever is the current user channel. */ -export interface FollowingContextListener extends Listener, RegisterableListener { +export interface UserChannelContextListener extends Listener, RegisterableListener { /** * This method is called when the user channel changes. The listener should then diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 198606d1f..397cbeac6 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -68,7 +68,7 @@ async function populateChannelSelector(cs: ChannelSupport, channelSelector: Chan channelSelector.updateChannel(channel?.id ?? null, userChannels) } -function handleDisconnectOnPageHide(da: DesktopAgent, messaging: MessagePortMessaging) { +function handleDisconnectOnPageHide(da: BasicDesktopAgent, messaging: MessagePortMessaging) { globalThis.window.addEventListener("pagehide", async (event) => { Logger.log(`Received pagehide event with persisted ${event.persisted}`); @@ -82,9 +82,7 @@ function handleDisconnectOnPageHide(da: DesktopAgent, messaging: MessagePortMess //the page is being destroyed, disconnect from the DA //Notify the Desktop Agent implementation to disconnect - if ((da as any).disconnect) { - (da as any).disconnect(); - } + da.disconnect(); //disconnect the MessagePort - which should send WCP6Goodbye first messaging.disconnect(); From f99e46b2d227405e5079dcfc2697baee359874b7 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 3 Dec 2024 23:38:49 +0000 Subject: [PATCH 27/90] adjusting privateChannel tests to match correct to private channel event types --- .../test/features/private-channels-deprecated.feature | 6 +++--- .../test/features/private-channels.feature | 8 ++++---- .../test/step-definitions/channels.steps.ts | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/fdc3-agent-proxy/test/features/private-channels-deprecated.feature b/packages/fdc3-agent-proxy/test/features/private-channels-deprecated.feature index e048cf6e1..d03f459dd 100644 --- a/packages/fdc3-agent-proxy/test/features/private-channels-deprecated.feature +++ b/packages/fdc3-agent-proxy/test/features/private-channels-deprecated.feature @@ -16,7 +16,7 @@ Feature: Basic Private Channels Support And I call "{theListener}" with "unsubscribe" Then messaging will have posts | type | payload.listenerType | payload.privateChannelId | payload.listenerUUID | matches_type | - | privateChannelAddEventListenerRequest | onAddContextListener | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | + | privateChannelAddEventListenerRequest | addContextListener | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | Scenario: Adding an "onAddContextListener" on a given Private Channel to receive a notification @@ -37,7 +37,7 @@ Feature: Basic Private Channels Support And I call "{theListener}" with "unsubscribe" Then messaging will have posts | type | payload.listenerType | payload.privateChannelId | payload.listenerUUID | matches_type | - | privateChannelAddEventListenerRequest | onUnsubscribe | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | + | privateChannelAddEventListenerRequest | unsubscribe | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | Scenario: Adding an "onUnsubscribe" on a given Private Channel to receive a notification @@ -58,7 +58,7 @@ Feature: Basic Private Channels Support And I call "{theListener}" with "unsubscribe" Then messaging will have posts | type | payload.listenerType | payload.privateChannelId | payload.listenerUUID | matches_type | - | privateChannelAddEventListenerRequest | onDisconnect | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | + | privateChannelAddEventListenerRequest | disconnect | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | Scenario: Adding an "onDisconnect" on a given Private Channel to receive a notification diff --git a/packages/fdc3-agent-proxy/test/features/private-channels.feature b/packages/fdc3-agent-proxy/test/features/private-channels.feature index 911615bf6..16dd3eb72 100644 --- a/packages/fdc3-agent-proxy/test/features/private-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/private-channels.feature @@ -34,7 +34,7 @@ Feature: Basic Private Channels Support And I call "{theListener}" with "unsubscribe" Then messaging will have posts | type | payload.listenerType | payload.privateChannelId | payload.listenerUUID | matches_type | - | privateChannelAddEventListenerRequest | onAddContextListener | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | + | privateChannelAddEventListenerRequest | addContextListener | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | Scenario: Adding an "onAddContextListener" on a given Private Channel to receive a notification @@ -55,7 +55,7 @@ Feature: Basic Private Channels Support And I call "{theListener}" with "unsubscribe" Then messaging will have posts | type | payload.listenerType | payload.privateChannelId | payload.listenerUUID | matches_type | - | privateChannelAddEventListenerRequest | onUnsubscribe | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | + | privateChannelAddEventListenerRequest | unsubscribe | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | Scenario: Adding an "onUnsubscribe" on a given Private Channel to receive a notification @@ -68,7 +68,7 @@ Feature: Basic Private Channels Support | value | | fdc3.instrument | - Scenario: Adding and then unsubscribing an "onDisconnect" listener will send a notification of each event to the agent + Scenario: Adding and then unsubscribing an "disconnect" listener will send a notification of each event to the agent Given "voidHandler" is a invocation counter into "count" When I call "{privateChannel}" with "addEventListener" with parameters "disconnect" and "{voidHandler}" And I refer to "{result}" as "theListener" @@ -76,7 +76,7 @@ Feature: Basic Private Channels Support And I call "{theListener}" with "unsubscribe" Then messaging will have posts | type | payload.listenerType | payload.privateChannelId | payload.listenerUUID | matches_type | - | privateChannelAddEventListenerRequest | onDisconnect | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | + | privateChannelAddEventListenerRequest | disconnect | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | Scenario: Adding an "onDisconnect" on a given Private Channel to receive a notification diff --git a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts index e31613db4..4b23fffa6 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts @@ -14,7 +14,7 @@ type BroadcastEvent = BrowserTypes.BroadcastEvent; type PrivateChannelOnUnsubscribeEvent = BrowserTypes.PrivateChannelOnUnsubscribeEvent; type PrivateChannelOnDisconnectEvent = BrowserTypes.PrivateChannelOnDisconnectEvent; -const contextMap: Record = { +const contextMap: Record = { 'fdc3.instrument': { type: 'fdc3.instrument', name: 'Apple', @@ -181,13 +181,13 @@ Given('{string} pipes context to {string}', function (this: CustomWorld, context When('messaging receives {string}', function (this: CustomWorld, field: string) { const message = handleResolve(field, this); this.log(`Sending: ${JSON.stringify(message)}`); - this.messaging!!.receive(message, this.log); + this.messaging!.receive(message, this.log); }); Then('messaging will have posts', function (this: CustomWorld, dt: DataTable) { // just take the last few posts and match those const matching = dt.rows().length; - var toUse = this.messaging?.allPosts!; + let toUse = this.messaging!.allPosts!; if (toUse.length > matching) { toUse = toUse.slice(toUse.length - matching, toUse.length); } From 7341ebe7c4aa2d4d911ef86d36c647fa7625459d Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 3 Dec 2024 23:39:35 +0000 Subject: [PATCH 28/90] code formating and minor improvements in toolbox/fdc3-for-web implementation --- .../fdc3-web-impl/src/BasicFDC3Server.ts | 13 +- .../fdc3-web-impl/src/ServerContext.ts | 2 +- .../src/handlers/BroadcastHandler.ts | 783 +++++++------ .../src/handlers/HeartbeatHandler.ts | 229 ++-- .../src/handlers/IntentHandler.ts | 1027 +++++++++-------- .../fdc3-web-impl/src/handlers/OpenHandler.ts | 593 ++++++---- .../fdc3-web-impl/src/handlers/support.ts | 30 +- 7 files changed, 1501 insertions(+), 1176 deletions(-) diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index db9ff7e5e..0e5846e2c 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -4,18 +4,17 @@ import { BroadcastHandler, ChannelState } from "./handlers/BroadcastHandler"; import { IntentHandler } from "./handlers/IntentHandler"; import { Directory } from "./directory/DirectoryInterface"; import { OpenHandler } from "./handlers/OpenHandler"; -import { BrowserTypes } from "@kite9/fdc3-schema"; import { HeartbeatHandler } from "./handlers/HeartbeatHandler"; - -type AppRequestMessage = BrowserTypes.AppRequestMessage -type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity +import { AppRequestMessage, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol6Goodbye } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export interface MessageHandler { /** - * Handles an AgentRequestMessage from the messaging source + * Handles an AgentRequestMessage from the messaging source. This function + * is called by BasicFDC3Server on every message received and should only + * process those it supports. */ - accept(msg: any, sc: ServerContext, from: InstanceID): void + accept(msg: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity | WebConnectionProtocol6Goodbye, sc: ServerContext, from: InstanceID): void shutdown(): void } @@ -33,7 +32,7 @@ export class BasicFDC3Server implements FDC3Server { this.sc = sc; } - receive(message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity, from: InstanceID): void { + receive(message: AppRequestMessage, from: InstanceID): void { // this.sc.log(`MessageReceived: \n ${JSON.stringify(message, null, 2)}`) this.handlers.forEach(h => h.accept(message, this.sc, from)) } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts index 3b9ac236e..5668c59e9 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts @@ -104,7 +104,7 @@ export interface ServerContext { /** * This is called prior to returning intents to the client. It is a * an opportunity for the server to either present an intent resolver - * or otherwise mess with the availble intents, or do nothing. + * or otherwise mess with the available intents, or do nothing. */ narrowIntents(raiser: AppIdentifier, IappIntents: AppIntent[], context: Context): Promise } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index 5a398bf5c..5b4bf1cde 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -1,377 +1,478 @@ -import { MessageHandler } from "../BasicFDC3Server"; -import { InstanceID, ServerContext } from "../ServerContext"; -import { Context } from "@kite9/fdc3-context"; -import { AppIdentifier, ChannelError, DisplayMetadata } from "@kite9/fdc3-standard"; -import { successResponse, errorResponse, onlyUnique } from "./support"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; - -type PrivateChannelEventType = BrowserTypes.PrivateChannelEventType -type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest -type BroadcastRequest = BrowserTypes.BroadcastRequest -type ContextListenerUnsubscribeRequest = BrowserTypes.ContextListenerUnsubscribeRequest -type AddContextListenerRequest = BrowserTypes.AddContextListenerRequest -type PrivateChannelDisconnectRequest = BrowserTypes.PrivateChannelDisconnectRequest -type PrivateChannelAddEventListenerRequest = BrowserTypes.PrivateChannelAddEventListenerRequest -type PrivateChannelUnsubscribeEventListenerRequest = BrowserTypes.PrivateChannelUnsubscribeEventListenerRequest -type GetOrCreateChannelRequest = BrowserTypes.GetOrCreateChannelRequest -type GetUserChannelsRequest = BrowserTypes.GetUserChannelsRequest -type LeaveCurrentChannelRequest = BrowserTypes.LeaveCurrentChannelRequest -type JoinUserChannelRequest = BrowserTypes.JoinUserChannelRequest -type GetCurrentChannelRequest = BrowserTypes.GetCurrentChannelRequest -type AgentEventMessage = BrowserTypes.AgentEventMessage -type CreatePrivateChannelRequest = BrowserTypes.CreatePrivateChannelRequest - -type PrivateChannelEvents = PrivateChannelOnAddContextListenerEvent | PrivateChannelOnUnsubscribeEvent | PrivateChannelOnDisconnectEvent; +import { MessageHandler } from '../BasicFDC3Server'; +import { InstanceID, ServerContext } from '../ServerContext'; +import { Context } from '@kite9/fdc3-context'; +import { AppIdentifier, ChannelError, DisplayMetadata, PrivateChannelEventTypes } from '@kite9/fdc3-standard'; +import { successResponse, errorResponse, onlyUnique, FullAppIdentifier } from './support'; +import { + AddContextListenerRequest, + AgentEventMessage, + AgentResponseMessage, + AppRequestMessage, + BroadcastRequest, + ContextListenerUnsubscribeRequest, + CreatePrivateChannelRequest, + GetCurrentChannelRequest, + GetCurrentContextRequest, + GetOrCreateChannelRequest, + GetUserChannelsRequest, + JoinUserChannelRequest, + LeaveCurrentChannelRequest, + PrivateChannelAddEventListenerRequest, + PrivateChannelDisconnectRequest, + PrivateChannelOnAddContextListenerEvent, + PrivateChannelOnDisconnectEvent, + PrivateChannelOnUnsubscribeEvent, + PrivateChannelUnsubscribeEventListenerRequest, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; + + +type PrivateChannelEvents = + | PrivateChannelOnAddContextListenerEvent + | PrivateChannelOnUnsubscribeEvent + | PrivateChannelOnDisconnectEvent; type ContextListenerRegistration = { - appId: string, - instanceId: string, - listenerUuid: string, - channelId: string | null, - contextType: string | null - userChannelListener: boolean -} + appId: string; + instanceId: string; + listenerUuid: string; + channelId: string | null; + contextType: string | null; + userChannelListener: boolean; +}; type PrivateChannelEventListener = { - appId: string, - instanceId: string, - channelId: string, - eventType: PrivateChannelEventType, - listenerUuid: string + appId: string; + instanceId: string; + channelId: string; + eventType: PrivateChannelEventTypes; + listenerUuid: string; +}; + +export enum ChannelType { + 'user', + 'app', + 'private', } -export enum ChannelType { 'user', 'app', 'private' } - export type ChannelState = { - id: string, - type: ChannelType, - context: Context[], - displayMetadata: DisplayMetadata -} + id: string; + type: ChannelType; + context: Context[]; + displayMetadata: DisplayMetadata; +}; export class BroadcastHandler implements MessageHandler { + private contextListeners: ContextListenerRegistration[] = []; + private readonly eventListeners: PrivateChannelEventListener[] = []; + private readonly state: ChannelState[] = []; + private readonly currentChannel: { [instanceId: string]: ChannelState } = {}; - private contextListeners: ContextListenerRegistration[] = [] - private readonly eventListeners: PrivateChannelEventListener[] = [] - private readonly state: ChannelState[] = [] - private readonly currentChannel: { [instanceId: string]: ChannelState } = {} + constructor(initialChannelState: ChannelState[]) { + this.state = initialChannelState; + } - constructor(initialChannelState: ChannelState[]) { - this.state = initialChannelState - } + shutdown(): void {} - shutdown(): void { - } + getCurrentChannel(from: FullAppIdentifier): ChannelState | null { + return this.currentChannel[from.instanceId]; + } - getCurrentChannel(from: AppIdentifier): ChannelState | null { - return this.currentChannel[from.instanceId!!] + getChannelById(id: string | null): ChannelState | null { + if (id == null) { + return null; } - - getChannelById(id: string | null): ChannelState | null { - if (id == null) { - return null - } - return this.state.find(c => c.id == id) ?? null + return this.state.find(c => c.id == id) ?? null; + } + + convertChannelTypeToString(type: ChannelType): string { + switch (type) { + case ChannelType.app: + return 'app'; + case ChannelType.user: + return 'user'; + case ChannelType.private: + return 'private'; } - - convertChannelTypeToString(type: ChannelType): string { - switch (type) { - case ChannelType.app: return 'app' - case ChannelType.user: return 'user' - case ChannelType.private: return 'private' - } + } + + getListeners(appId: AppIdentifier) { + return this.contextListeners.filter(r => r.instanceId == appId.instanceId); + } + + moveUserChannelListeners(app: AppIdentifier, channelId: string | null) { + this.getListeners(app) + .filter(l => l.userChannelListener) + .forEach(l => { + l.channelId = channelId; + }); + } + + updateChannelState(channelId: string, context: Context) { + const cs = this.getChannelById(channelId); + if (cs) { + cs.context = cs.context.filter(c => c.type != context.type); + cs.context.unshift(context); } + } - getListeners(appId: AppIdentifier) { - return this.contextListeners.filter(r => r.instanceId == appId.instanceId) - } + accept(msg: AppRequestMessage, sc: ServerContext, uuid: InstanceID) { + const from = sc.getInstanceDetails(uuid); - moveUserChannelListeners(app: AppIdentifier, channelId: string | null) { - this.getListeners(app) - .filter(l => l.userChannelListener) - .forEach(l => { - l.channelId = channelId - }) + if (from == null) { + // this handler only deals with connected apps + return; } - updateChannelState(channelId: string, context: Context) { - const cs = this.getChannelById(channelId) - if (cs) { - cs.context = cs.context.filter(c => c.type != context.type) - cs.context.unshift(context) - } + try { + switch (msg.type as string | null) { + // app channels registration + case 'getOrCreateChannelRequest': + return this.handleGetOrCreateRequest(msg as GetOrCreateChannelRequest, sc, from); + + // user channel management + case 'getUserChannelsRequest': + return this.handleGetUserChannelsRequest(msg as GetUserChannelsRequest, sc, from); + case 'leaveCurrentChannelRequest': + return this.handleLeaveCurrentChannelRequest(msg as LeaveCurrentChannelRequest, sc, from); + case 'joinUserChannelRequest': + return this.handleJoinUserChannelRequest(msg as JoinUserChannelRequest, sc, from); + case 'getCurrentChannelRequest': + return this.handleGetCurrentChannelRequest(msg as GetCurrentChannelRequest, sc, from); + + // general broadcast + case 'broadcastRequest': + return this.handleBroadcastRequest(msg as BroadcastRequest, sc, from); + + // context listeners + case 'addContextListenerRequest': + return this.handleAddContextListenerRequest(msg as AddContextListenerRequest, sc, from); + case 'contextListenerUnsubscribeRequest': + return this.handleContextListenerUnsubscribeRequest(msg as ContextListenerUnsubscribeRequest, sc, from); + + // private channels create/disconnect + case 'createPrivateChannelRequest': + return this.handleCreatePrivateChannelRequest(msg as CreatePrivateChannelRequest, sc, from); + case 'privateChannelDisconnectRequest': + return this.handlePrivateChannelDisconnectRequest(msg as PrivateChannelDisconnectRequest, sc, from); + + // private channel event listeners + case 'privateChannelAddEventListenerRequest': + return this.handlePrivateChannelAddEventListenerRequest( + msg as PrivateChannelAddEventListenerRequest, + from, + sc + ); + case 'privateChannelUnsubscribeEventListenerRequest': + return this.handlePrivateChannelUnsubscribeEventListenerRequest( + msg as PrivateChannelUnsubscribeEventListenerRequest, + sc, + from + ); + + // handling state synchronization of channels + case 'getCurrentContextRequest': + return this.handleGetCurrentContextRequest(msg as GetCurrentContextRequest, sc, from); + } + } catch (e: any) { + const responseType = msg.type.replace(new RegExp('Request$'), 'Response'); + errorResponse(sc, msg, from, e.message ?? e, responseType as AgentResponseMessage['type']); } - - accept(msg: any, sc: ServerContext, uuid: InstanceID) { - const from = sc.getInstanceDetails(uuid) - - if (from == null) { - // this handler only deals with connected apps - return - } - - try { - - switch (msg.type as string | null) { - // app channels registration - case 'getOrCreateChannelRequest': return this.handleGetOrCreateRequest(msg as GetOrCreateChannelRequest, sc, from) - - // user channel management - case 'getUserChannelsRequest': return this.handleGetUserChannelsRequest(msg as GetUserChannelsRequest, sc, from) - case 'leaveCurrentChannelRequest': return this.handleLeaveCurrentChannelRequest(msg as LeaveCurrentChannelRequest, sc, from) - case 'joinUserChannelRequest': return this.handleJoinUserChannelRequest(msg as JoinUserChannelRequest, sc, from) - case 'getCurrentChannelRequest': return this.handleGetCurrentChannelRequest(msg as GetCurrentChannelRequest, sc, from) - - // general broadcast - case 'broadcastRequest': return this.handleBroadcastRequest(msg as BroadcastRequest, sc, from) - - // context listeners - case 'addContextListenerRequest': return this.handleAddContextListenerRequest(msg as AddContextListenerRequest, sc, from) - case 'contextListenerUnsubscribeRequest': return this.handleContextListenerUnsubscribeRequest(msg as ContextListenerUnsubscribeRequest, sc, from) - - // private channels create/disconnect - case 'createPrivateChannelRequest': return this.handleCreatePrivateChannelRequest(msg as CreatePrivateChannelRequest, sc, from) - case 'privateChannelDisconnectRequest': return this.handlePrivateChannelDisconnectRequest(msg as PrivateChannelDisconnectRequest, sc, from) - - // private channel event listeners - case 'privateChannelAddEventListenerRequest': return this.handlePrivateChannelAddEventListenerRequest(msg as PrivateChannelAddEventListenerRequest, from, sc) - case 'privateChannelUnsubscribeEventListenerRequest': return this.handlePrivateChannelUnsubscribeEventListenerRequest(msg as PrivateChannelUnsubscribeEventListenerRequest, sc, from) - - // handling state synchronization of channels - case 'getCurrentContextRequest': return this.handleGetCurrentContextRequest(msg as GetCurrentContextRequest, sc, from) - } - } catch (e: any) { - const responseType = msg.type.replace(new RegExp("Request$"), 'Response') - errorResponse(sc, msg, from, e.message ?? e, responseType) - } + } + + handleCreatePrivateChannelRequest(arg0: CreatePrivateChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + const id = sc.createUUID(); + this.state.push({ + id, + type: ChannelType.private, + context: [], + displayMetadata: {}, + }); + + successResponse( + sc, + arg0, + from, + { privateChannel: { id, type: this.convertChannelTypeToString(ChannelType.private) } }, + 'createPrivateChannelResponse' + ); + } + + handleGetCurrentContextRequest(arg0: GetCurrentContextRequest, sc: ServerContext, from: FullAppIdentifier) { + const channel = this.getChannelById(arg0.payload.channelId); + const type = arg0.payload.contextType; + + if (channel) { + const context = type ? channel.context.find(c => c.type == type) ?? null : channel.context[0] ?? null; + successResponse(sc, arg0, from, { context: context }, 'getCurrentContextResponse'); + } else { + errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'getCurrentContextResponse'); } - - handleCreatePrivateChannelRequest(arg0: CreatePrivateChannelRequest, sc: ServerContext, from: AppIdentifier) { - const id = sc.createUUID() - this.state.push({ - id, - type: ChannelType.private, - context: [], - displayMetadata: { - } - }) - - successResponse(sc, arg0, from, { privateChannel: { id, type: this.convertChannelTypeToString(ChannelType.private) } }, 'createPrivateChannelResponse') + } + + handlePrivateChannelUnsubscribeEventListenerRequest( + arg0: PrivateChannelUnsubscribeEventListenerRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { + const i = this.eventListeners.findIndex(r => r.listenerUuid == arg0.payload.listenerUUID); + if (i > -1) { + this.eventListeners.splice(i, 1); + successResponse(sc, arg0, from, {}, 'privateChannelUnsubscribeEventListenerResponse'); + } else { + errorResponse(sc, arg0, from, 'ListenerNotFound', 'privateChannelUnsubscribeEventListenerResponse'); } - - handleGetCurrentContextRequest(arg0: GetCurrentContextRequest, sc: ServerContext, from: AppIdentifier) { - const channel = this.getChannelById(arg0.payload.channelId) - const type = arg0.payload.contextType - - if (channel) { - const context = type ? (channel.context.find(c => c.type == type) ?? null) : (channel.context[0] ?? null) - successResponse(sc, arg0, from, { context: context }, 'getCurrentContextResponse') - } else { - errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'getCurrentContextResponse') - } + } + + handlePrivateChannelDisconnectRequest( + arg0: PrivateChannelDisconnectRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { + const toUnsubscribe = this.contextListeners + .filter(r => r.appId == from.appId && r.instanceId == from.instanceId) + .filter(r => r.channelId == arg0.payload.channelId); + + toUnsubscribe.forEach(u => { + this.invokePrivateChannelEventListeners( + arg0.payload.channelId, + 'unsubscribe', + 'privateChannelOnUnsubscribeEvent', + sc, + u.contextType ?? undefined + ); + }); + + this.contextListeners = this.contextListeners.filter(r => !toUnsubscribe.includes(r)); + this.invokePrivateChannelEventListeners( + arg0.payload.channelId, + 'disconnect', + 'privateChannelOnDisconnectEvent', + sc + ); + successResponse(sc, arg0, from, {}, 'privateChannelDisconnectResponse'); + } + + handleContextListenerUnsubscribeRequest( + arg0: ContextListenerUnsubscribeRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { + const i = this.contextListeners.findIndex( + r => r.listenerUuid == arg0.payload.listenerUUID && r.instanceId == from.instanceId + ); + + if (i > -1) { + const rl = this.contextListeners[i]; + const channel = this.getChannelById(rl.channelId); + this.invokePrivateChannelEventListeners( + channel?.id ?? null, + 'unsubscribe', + 'privateChannelOnUnsubscribeEvent', + sc, + rl.contextType ?? undefined + ); + this.contextListeners.splice(i, 1); + successResponse(sc, arg0, from, {}, 'contextListenerUnsubscribeResponse'); + } else { + errorResponse(sc, arg0, from, 'ListenerNotFound', 'contextListenerUnsubscribeResponse'); } - - handlePrivateChannelUnsubscribeEventListenerRequest(arg0: PrivateChannelUnsubscribeEventListenerRequest, sc: ServerContext, from: AppIdentifier) { - const i = this.eventListeners.findIndex(r => r.listenerUuid == arg0.payload.listenerUUID) - if (i > -1) { - this.eventListeners.splice(i, 1) - successResponse(sc, arg0, from, {}, 'privateChannelUnsubscribeEventListenerResponse') - } else { - errorResponse(sc, arg0, from, "ListenerNotFound", 'privateChannelUnsubscribeEventListenerResponse') - } - } - - handlePrivateChannelDisconnectRequest(arg0: PrivateChannelDisconnectRequest, sc: ServerContext, from: AppIdentifier) { - const toUnsubscribe = this.contextListeners - .filter(r => (r.appId == from.appId) && (r.instanceId == from.instanceId)) - .filter(r => r.channelId == arg0.payload.channelId) - - toUnsubscribe.forEach(u => { - this.invokePrivateChannelEventListeners(arg0.payload.channelId, "unsubscribe", 'privateChannelOnUnsubscribeEvent', sc, u.contextType ?? undefined) - }) - - this.contextListeners = this.contextListeners.filter(r => !toUnsubscribe.includes(r)) - this.invokePrivateChannelEventListeners(arg0.payload.channelId, "disconnect", 'privateChannelOnDisconnectEvent', sc) - successResponse(sc, arg0, from, {}, 'privateChannelDisconnectResponse') - } - - handleContextListenerUnsubscribeRequest(arg0: ContextListenerUnsubscribeRequest, sc: ServerContext, from: AppIdentifier) { - const i = this.contextListeners - .findIndex(r => (r.listenerUuid == arg0.payload.listenerUUID) && (r.instanceId == from.instanceId)) - - if (i > -1) { - const rl = this.contextListeners[i] - const channel = this.getChannelById(rl.channelId) - this.invokePrivateChannelEventListeners(channel?.id ?? null, "unsubscribe", 'privateChannelOnUnsubscribeEvent', sc, rl.contextType ?? undefined) - this.contextListeners.splice(i, 1) - successResponse(sc, arg0, from, {}, 'contextListenerUnsubscribeResponse') - } else { - errorResponse(sc, arg0, from, "ListenerNotFound", 'contextListenerUnsubscribeResponse') - } - } - - handleAddContextListenerRequest(arg0: AddContextListenerRequest, sc: ServerContext, from: AppIdentifier) { - var channelId = null - var channelType = ChannelType.user - - if (arg0.payload?.channelId) { - const channel = this.getChannelById(arg0.payload?.channelId) - channelType = channel?.type ?? ChannelType.user - - if (channel == null) { - errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'addContextListenerResponse') - return - } else { - channelId = channel.id - } - } - - const lr: ContextListenerRegistration = { - appId: from.appId, - instanceId: from.instanceId ?? 'no-instance-id', - channelId: channelId, - listenerUuid: sc.createUUID(), - contextType: arg0.payload.contextType, - userChannelListener: channelType == ChannelType.user - } - - this.contextListeners.push(lr) - this.invokePrivateChannelEventListeners(channelId, "addContextListener", "privateChannelOnAddContextListenerEvent", sc, arg0.payload.contextType ?? undefined) - successResponse(sc, arg0, from, { listenerUUID: lr.listenerUuid }, 'addContextListenerResponse') - + } + + handleAddContextListenerRequest(arg0: AddContextListenerRequest, sc: ServerContext, from: FullAppIdentifier) { + var channelId = null; + var channelType = ChannelType.user; + + if (arg0.payload?.channelId) { + const channel = this.getChannelById(arg0.payload?.channelId); + channelType = channel?.type ?? ChannelType.user; + + if (channel == null) { + errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'addContextListenerResponse'); + return; + } else { + channelId = channel.id; + } } - handleBroadcastRequest(arg0: BroadcastRequest, sc: ServerContext, from: AppIdentifier) { - const matchingListeners = this.contextListeners - .filter(r => r.channelId == arg0.payload.channelId) - .filter(r => r.contextType == null || r.contextType == arg0.payload.context.type) - - const matchingApps = matchingListeners - .map(r => { return { appId: r.appId, instanceId: r.instanceId } }) - .filter(onlyUnique) - - matchingApps.forEach(app => { - sc.post({ - meta: { - eventUuid: sc.createUUID(), - timestamp: new Date() - }, - type: 'broadcastEvent', - payload: { - channelId: arg0.payload.channelId, - context: arg0.payload.context - } - }, app.instanceId) - }) - - this.updateChannelState(arg0.payload.channelId, arg0.payload.context) - successResponse(sc, arg0, from, {}, 'broadcastResponse') + const lr: ContextListenerRegistration = { + appId: from.appId, + instanceId: from.instanceId ?? 'no-instance-id', + channelId: channelId, + listenerUuid: sc.createUUID(), + contextType: arg0.payload.contextType, + userChannelListener: channelType == ChannelType.user, + }; + + this.contextListeners.push(lr); + this.invokePrivateChannelEventListeners( + channelId, + 'addContextListener', + 'privateChannelOnAddContextListenerEvent', + sc, + arg0.payload.contextType ?? undefined + ); + successResponse(sc, arg0, from, { listenerUUID: lr.listenerUuid }, 'addContextListenerResponse'); + } + + handleBroadcastRequest(arg0: BroadcastRequest, sc: ServerContext, from: FullAppIdentifier) { + const matchingListeners = this.contextListeners + .filter(r => r.channelId == arg0.payload.channelId) + .filter(r => r.contextType == null || r.contextType == arg0.payload.context.type); + + const matchingApps = matchingListeners + .map(r => { + return { appId: r.appId, instanceId: r.instanceId }; + }) + .filter(onlyUnique); + + matchingApps.forEach(app => { + sc.post( + { + meta: { + eventUuid: sc.createUUID(), + timestamp: new Date(), + }, + type: 'broadcastEvent', + payload: { + channelId: arg0.payload.channelId, + context: arg0.payload.context, + }, + }, + app.instanceId + ); + }); + + this.updateChannelState(arg0.payload.channelId, arg0.payload.context); + successResponse(sc, arg0, from, {}, 'broadcastResponse'); + } + + handleGetCurrentChannelRequest(arg0: GetCurrentChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + const currentChannel = this.getCurrentChannel(from); + if (currentChannel) { + successResponse( + sc, + arg0, + from, + { + channel: { + id: currentChannel.id, + type: this.convertChannelTypeToString(currentChannel.type), + displayMetadata: currentChannel.displayMetadata, + }, + }, + 'getCurrentChannelResponse' + ); + } else { + successResponse(sc, arg0, from, { channel: null }, 'getCurrentChannelResponse'); } + } - handleGetCurrentChannelRequest(arg0: GetCurrentChannelRequest, sc: ServerContext, from: AppIdentifier) { - const currentChannel = this.getCurrentChannel(from) - if (currentChannel) { - successResponse(sc, arg0, from, { - channel: { - id: currentChannel.id, - type: this.convertChannelTypeToString(currentChannel.type), - displayMetadata: currentChannel.displayMetadata - } - }, 'getCurrentChannelResponse') - } else { - successResponse(sc, arg0, from, { channel: null }, 'getCurrentChannelResponse') - } + handleJoinUserChannelRequest(arg0: JoinUserChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + // check it's a user channel + const newChannel = this.getChannelById(arg0.payload.channelId); + if (newChannel == null || newChannel.type != ChannelType.user) { + return errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'joinUserChannelResponse'); } - handleJoinUserChannelRequest(arg0: JoinUserChannelRequest, sc: ServerContext, from: AppIdentifier) { - // check it's a user channel - const newChannel = this.getChannelById(arg0.payload.channelId) - if ((newChannel == null) || (newChannel.type != ChannelType.user)) { - return errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'joinUserChannelResponse') - } - - // join it. - const instanceId = from.instanceId ?? 'no-instance-id' - this.currentChannel[instanceId] = newChannel - this.moveUserChannelListeners(from, newChannel.id) - successResponse(sc, arg0, from, {}, 'joinUserChannelResponse') + // join it. + const instanceId = from.instanceId ?? 'no-instance-id'; + this.currentChannel[instanceId] = newChannel; + this.moveUserChannelListeners(from, newChannel.id); + successResponse(sc, arg0, from, {}, 'joinUserChannelResponse'); + } + + handleLeaveCurrentChannelRequest(arg0: LeaveCurrentChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + const instanceId = from.instanceId ?? 'no-instance-id'; + const currentChannel = this.currentChannel[instanceId]; + if (currentChannel) { + delete this.currentChannel[instanceId]; + this.moveUserChannelListeners(from, null); } - - handleLeaveCurrentChannelRequest(arg0: LeaveCurrentChannelRequest, sc: ServerContext, from: AppIdentifier) { - const instanceId = from.instanceId ?? 'no-instance-id' - const currentChannel = this.currentChannel[instanceId] - if (currentChannel) { - delete this.currentChannel[instanceId] - this.moveUserChannelListeners(from, null) - } - successResponse(sc, arg0, from, {}, 'leaveCurrentChannelResponse') - } - - handleGetOrCreateRequest(arg0: GetOrCreateChannelRequest, sc: ServerContext, from: AppIdentifier) { - const id = arg0.payload.channelId - var channel = this.getChannelById(id) - if (channel) { - if (channel.type != ChannelType.app) { - errorResponse(sc, arg0, from, ChannelError.AccessDenied, 'getOrCreateChannelResponse') - return - } - } - - channel = { - id: id, - type: ChannelType.app, - context: [], - displayMetadata: {} - } - this.state.push(channel) - successResponse(sc, arg0, from, { channel: { id: channel.id, type: channel.type, } }, 'getOrCreateChannelResponse') - } - - - handleGetUserChannelsRequest(arg0: GetUserChannelsRequest, sc: ServerContext, from: AppIdentifier) { - const userChannels = this.state.filter(c => c.type == ChannelType.user) - successResponse(sc, arg0, from, { userChannels: userChannels.map(c => ({ id: c.id, type: this.convertChannelTypeToString(c.type), displayMetadata: c.displayMetadata })) }, 'getUserChannelsResponse') + successResponse(sc, arg0, from, {}, 'leaveCurrentChannelResponse'); + } + + handleGetOrCreateRequest(arg0: GetOrCreateChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + const id = arg0.payload.channelId; + var channel = this.getChannelById(id); + if (channel) { + if (channel.type != ChannelType.app) { + errorResponse(sc, arg0, from, ChannelError.AccessDenied, 'getOrCreateChannelResponse'); + return; + } } - handlePrivateChannelAddEventListenerRequest(arg0: PrivateChannelAddEventListenerRequest, from: AppIdentifier, sc: ServerContext) { - const channel = this.getChannelById(arg0.payload.privateChannelId) - - if ((channel == null) || (channel.type != ChannelType.private)) { - errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'privateChannelAddEventListenerResponse') - } else { - const el = { - appId: from.appId!!, - instanceId: from.instanceId!!, - channelId: arg0.payload.privateChannelId, - eventType: arg0.payload.listenerType, - listenerUuid: sc.createUUID(), - } as PrivateChannelEventListener - this.eventListeners.push(el) - successResponse(sc, arg0, from, { listenerUUID: el.listenerUuid }, 'privateChannelAddEventListenerResponse') - } + channel = { + id: id, + type: ChannelType.app, + context: [], + displayMetadata: {}, + }; + this.state.push(channel); + successResponse(sc, arg0, from, { channel: { id: channel.id, type: channel.type } }, 'getOrCreateChannelResponse'); + } + + handleGetUserChannelsRequest(arg0: GetUserChannelsRequest, sc: ServerContext, from: FullAppIdentifier) { + const userChannels = this.state.filter(c => c.type == ChannelType.user); + successResponse( + sc, + arg0, + from, + { + userChannels: userChannels.map(c => ({ + id: c.id, + type: this.convertChannelTypeToString(c.type), + displayMetadata: c.displayMetadata, + })), + }, + 'getUserChannelsResponse' + ); + } + + handlePrivateChannelAddEventListenerRequest( + arg0: PrivateChannelAddEventListenerRequest, + from: FullAppIdentifier, + sc: ServerContext + ) { + const channel = this.getChannelById(arg0.payload.privateChannelId); + + if (channel == null || channel.type != ChannelType.private) { + errorResponse(sc, arg0, from, ChannelError.NoChannelFound, 'privateChannelAddEventListenerResponse'); + } else { + const el = { + appId: from.appId, + instanceId: from.instanceId, + channelId: arg0.payload.privateChannelId, + eventType: arg0.payload.listenerType, + listenerUuid: sc.createUUID(), + } as PrivateChannelEventListener; + this.eventListeners.push(el); + successResponse(sc, arg0, from, { listenerUUID: el.listenerUuid }, 'privateChannelAddEventListenerResponse'); } - - invokePrivateChannelEventListeners(privateChannelId: string | null, eventType: PrivateChannelEventType, messageType: PrivateChannelEvents["type"], sc: ServerContext, contextType?: string) { - if (privateChannelId) { - const msg = { - type: messageType, - meta: { - eventUuid: sc.createUUID(), - timestamp: new Date() - }, - payload: { - privateChannelId, - contextType: contextType - } - } as AgentEventMessage - - this.eventListeners - .filter(e => (e.channelId == privateChannelId) && (e.eventType == eventType)) - .forEach(e => sc.post(msg, e.instanceId)) - } + } + + invokePrivateChannelEventListeners( + privateChannelId: string | null, + eventType: PrivateChannelEventTypes, + messageType: PrivateChannelEvents['type'], + sc: ServerContext, + contextType?: string + ) { + if (privateChannelId) { + const msg = { + type: messageType, + meta: { + eventUuid: sc.createUUID(), + timestamp: new Date(), + }, + payload: { + privateChannelId, + contextType: contextType, + }, + } as AgentEventMessage; + + this.eventListeners + .filter(e => e.channelId == privateChannelId && e.eventType == eventType) + .forEach(e => sc.post(msg, e.instanceId)); } - + } } - - diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts index eb877db4b..bfe150dbe 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts @@ -1,126 +1,137 @@ -import { AppIdentifier } from "@kite9/fdc3-standard"; -import { MessageHandler } from "../BasicFDC3Server"; -import { AppRegistration, InstanceID, ServerContext, State } from "../ServerContext"; -import { BrowserTypes } from "@kite9/fdc3-schema"; +import { MessageHandler } from '../BasicFDC3Server'; +import { AppRegistration, InstanceID, ServerContext, State } from '../ServerContext'; +import { AppRequestMessage, HeartbeatEvent, WebConnectionProtocol6Goodbye } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { FullAppIdentifier } from './support'; type HeartbeatDetails = { - instanceId: string, - time: number, - state: string -} + instanceId: string; + time: number; + state: string; +}; function convertToText(s?: State): string { - if (s == undefined) { - return "Unknown" - } else { - switch (s) { - case State.Pending: - return "Pending" - case State.Connected: - return "Connected" - case State.NotResponding: - return "Not Responding" - case State.Terminated: - return "Terminated" - } + if (s == undefined) { + return 'Unknown'; + } else { + switch (s) { + case State.Pending: + return 'Pending'; + case State.Connected: + return 'Connected'; + case State.NotResponding: + return 'Not Responding'; + case State.Terminated: + return 'Terminated'; } + } } /* * Handles heartbeat pings and responses */ export class HeartbeatHandler implements MessageHandler { - - private readonly contexts: ServerContext[] = [] - private readonly lastHeartbeats: Map = new Map() - private readonly timerFunction: NodeJS.Timeout - - constructor(pingInterval: number = 1000, disconnectedAfter: number = 5000, deadAfter: number = 20000) { - - this.timerFunction = setInterval(() => { - //console.log(`Contexts: ${this.contexts.length} Last Heartbeats: `, this.heartbeatTimes()) - - this.contexts.forEach(async (sc) => { - const apps = await sc.getAllApps() - apps - .filter(app => (app.state == State.Connected) || (app.state == State.NotResponding)) - .forEach(app => { - const now = new Date().getTime() - this.sendHeartbeat(sc, app) - - // check when the last heartbeat happened - const lastHeartbeat = this.lastHeartbeats.get(app.instanceId!!) - const currentState = app.state - - if (lastHeartbeat != undefined) { - const timeSinceLastHeartbeat = now - lastHeartbeat - - if ((timeSinceLastHeartbeat < disconnectedAfter) && (currentState != State.Connected)) { - console.error(`Heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered connected.`) - sc.setAppState(app.instanceId!!, State.Connected) - } else if ((timeSinceLastHeartbeat > disconnectedAfter) && (currentState == State.Connected)) { - console.error(`No heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered not responding.`) - sc.setAppState(app.instanceId!!, State.NotResponding) - } else if ((timeSinceLastHeartbeat > deadAfter) && (currentState == State.NotResponding)) { - console.error(`No heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered terminated.`) - sc.setAppState(app.instanceId!!, State.Terminated) - } else { - // no action - } - - } else { - // start the clock - this.lastHeartbeats.set(app.instanceId!!, now) - } - }) - }) - }, pingInterval) - } - - heartbeatTimes(): HeartbeatDetails[] { - const now = new Date().getTime() - return Array.from(this.lastHeartbeats).map(e => { - return { - instanceId: e[0], time: now - e[1], state: convertToText(this.contexts.map(sc => sc.getInstanceDetails(e[0])).reduce((a, b) => a || b)?.state) - } as HeartbeatDetails - }).filter(e => e.state != "Terminated") - } - - shutdown(): void { - clearInterval(this.timerFunction) - } - - accept(msg: any, sc: ServerContext, from: InstanceID): void { - if (!this.contexts.includes(sc)) { - this.contexts.push(sc) - } - - if (msg.type == 'heartbeatAcknowledgementRequest') { - const app = sc.getInstanceDetails(from) - if (app) { - this.lastHeartbeats.set(app.instanceId!!, new Date().getTime()) + private readonly contexts: ServerContext[] = []; + private readonly lastHeartbeats: Map = new Map(); + private readonly timerFunction: NodeJS.Timeout; + + constructor(pingInterval: number = 1000, disconnectedAfter: number = 5000, deadAfter: number = 20000) { + this.timerFunction = setInterval(() => { + //console.log(`Contexts: ${this.contexts.length} Last Heartbeats: `, this.heartbeatTimes()) + + this.contexts.forEach(async sc => { + const apps = await sc.getAllApps(); + apps + .filter(app => app.state == State.Connected || app.state == State.NotResponding) + .forEach(app => { + const now = new Date().getTime(); + this.sendHeartbeat(sc, app); + + // check when the last heartbeat happened + const lastHeartbeat = this.lastHeartbeats.get(app.instanceId!!); + const currentState = app.state; + + if (lastHeartbeat != undefined) { + const timeSinceLastHeartbeat = now - lastHeartbeat; + + if (timeSinceLastHeartbeat < disconnectedAfter && currentState != State.Connected) { + console.error( + `Heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered connected.` + ); + sc.setAppState(app.instanceId!!, State.Connected); + } else if (timeSinceLastHeartbeat > disconnectedAfter && currentState == State.Connected) { + console.error( + `No heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered not responding.` + ); + sc.setAppState(app.instanceId!!, State.NotResponding); + } else if (timeSinceLastHeartbeat > deadAfter && currentState == State.NotResponding) { + console.error( + `No heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered terminated.` + ); + sc.setAppState(app.instanceId!!, State.Terminated); + } else { + // no action + } + } else { + // start the clock + this.lastHeartbeats.set(app.instanceId!!, now); } - } - - if (msg.type == 'WCP5Shutdown') { - const app = sc.getInstanceDetails(from) - if (app) { - sc.setAppState(from, State.Terminated) - } - } + }); + }); + }, pingInterval); + } + + heartbeatTimes(): HeartbeatDetails[] { + const now = new Date().getTime(); + return Array.from(this.lastHeartbeats) + .map(e => { + return { + instanceId: e[0], + time: now - e[1], + state: convertToText(this.contexts.map(sc => sc.getInstanceDetails(e[0])).reduce((a, b) => a || b)?.state), + } as HeartbeatDetails; + }) + .filter(e => e.state != 'Terminated'); + } + + shutdown(): void { + clearInterval(this.timerFunction); + } + + accept( + msg: AppRequestMessage | WebConnectionProtocol6Goodbye, + sc: ServerContext, + from: InstanceID + ): void { + if (!this.contexts.includes(sc)) { + this.contexts.push(sc); } - - async sendHeartbeat(sc: ServerContext, app: AppIdentifier): Promise { - sc.post({ - type: 'heartbeatEvent', - meta: { - timestamp: new Date(), - eventUuid: sc.createUUID(), - }, - payload: { - } - } as BrowserTypes.HeartbeatEvent, app.instanceId!!) + if (msg.type == 'heartbeatAcknowledgementRequest') { + const app = sc.getInstanceDetails(from); + if (app) { + this.lastHeartbeats.set(app.instanceId!!, new Date().getTime()); + } } + if (msg.type == 'WCP6Goodbye') { + const app = sc.getInstanceDetails(from); + if (app) { + sc.setAppState(from, State.Terminated); + } + } + } + + async sendHeartbeat(sc: ServerContext, app: FullAppIdentifier): Promise { + sc.post( + { + type: 'heartbeatEvent', + meta: { + timestamp: new Date(), + eventUuid: sc.createUUID(), + }, + payload: {}, + } as HeartbeatEvent, + app.instanceId + ); + } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts index 17173e78a..fb4e20b8c 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts @@ -1,509 +1,626 @@ -import { MessageHandler } from "../BasicFDC3Server"; -import { AppRegistration, InstanceID, ServerContext } from "../ServerContext"; -import { Directory, DirectoryIntent } from "../directory/DirectoryInterface"; -import { Context } from "@kite9/fdc3-context"; -import { AppIntent, ResolveError, AppIdentifier, } from "@kite9/fdc3-standard"; -import { errorResponse, errorResponseId, successResponse, successResponseId } from "./support"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type AddIntentListenerRequest = BrowserTypes.AddIntentListenerRequest -type FindIntentRequest = BrowserTypes.FindIntentRequest -type FindIntentsByContextRequest = BrowserTypes.FindIntentsByContextRequest -type IntentEvent = BrowserTypes.IntentEvent -type IntentListenerUnsubscribeRequest = BrowserTypes.IntentListenerUnsubscribeRequest -type RaiseIntentRequest = BrowserTypes.RaiseIntentRequest -type RaiseIntentForContextRequest = BrowserTypes.RaiseIntentForContextRequest -type IntentResultRequest = BrowserTypes.IntentResultRequest +import { MessageHandler } from '../BasicFDC3Server'; +import { AppRegistration, InstanceID, ServerContext } from '../ServerContext'; +import { Directory, DirectoryIntent } from '../directory/DirectoryInterface'; +import { Context } from '@kite9/fdc3-context'; +import { AppIntent, ResolveError, AppIdentifier } from '@kite9/fdc3-standard'; +import { errorResponse, errorResponseId, FullAppIdentifier, isFullAppIdentifier, successResponse, successResponseId } from './support'; +import { IntentEvent, FindIntentsByContextRequest, FindIntentRequest, AddIntentListenerRequest, IntentListenerUnsubscribeRequest, RaiseIntentRequest, RaiseIntentForContextRequest, IntentResultRequest } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; type ListenerRegistration = { - appId: string | undefined, - instanceId: string | undefined, - intentName: string | undefined, - listenerUUID: string -} + appId: string; + instanceId: string; + intentName: string; + listenerUUID: string; +}; type IntentRequest = { - intent: string, - context: Context, - requestUuid: string, - from: AppIdentifier, - type: 'raiseIntentResponse' | 'raiseIntentForContextResponse' -} - + intent: string; + context: Context; + requestUuid: string; + from: FullAppIdentifier; + type: 'raiseIntentResponse' | 'raiseIntentForContextResponse'; +}; /** * Re-writes the request to forward it on to the target application */ -async function forwardRequest(arg0: IntentRequest, to: AppIdentifier, sc: ServerContext, ih: IntentHandler): Promise { - const out: IntentEvent = { - type: 'intentEvent', - payload: { - context: arg0.context, - intent: arg0.intent, - originatingApp: { - appId: arg0.from.appId, - instanceId: arg0.from.instanceId - }, - raiseIntentRequestUuid: arg0.requestUuid - }, - meta: { - eventUuid: sc.createUUID(), - timestamp: new Date() - } - } - - // register the resolution destination - ih.pendingResolutions.set(arg0.requestUuid, arg0.from) - await sc.post(out, to.instanceId!!) - successResponseId(sc, arg0.requestUuid, arg0.from, { - intentResolution: { - intent: arg0.intent, - source: to - } - }, arg0.type) +async function forwardRequest( + arg0: IntentRequest, + to: FullAppIdentifier, + sc: ServerContext, + ih: IntentHandler +): Promise { + const out: IntentEvent = { + type: 'intentEvent', + payload: { + context: arg0.context, + intent: arg0.intent, + originatingApp: { + appId: arg0.from.appId, + instanceId: arg0.from.instanceId, + }, + raiseIntentRequestUuid: arg0.requestUuid, + }, + meta: { + eventUuid: sc.createUUID(), + timestamp: new Date(), + }, + }; + + // register the resolution destination + ih.pendingResolutions.set(arg0.requestUuid, arg0.from); + await sc.post(out, to.instanceId); + successResponseId( + sc, + arg0.requestUuid, + arg0.from, + { + intentResolution: { + intent: arg0.intent, + source: to, + }, + }, + arg0.type + ); } /** * A pending intent is one for an app that hasn't registered it's intent listener yet. * (Possibly it is being opened) - * + * * Pending intents wait for that registration and then message the app. */ class PendingIntent { - - complete: boolean = false - r: IntentRequest - appId: AppIdentifier - sc: ServerContext - ih: IntentHandler - - constructor(r: IntentRequest, sc: ServerContext, ih: IntentHandler, appId: AppIdentifier) { - this.r = r - this.appId = appId - this.sc = sc - this.ih = ih - - // handle the timeout - setTimeout(() => { - if (!this.complete) { - errorResponseId(sc, r.requestUuid, r.from, ResolveError.IntentDeliveryFailed, r.type) - this.ih.pendingIntents.delete(this) - } - }, ih.timeoutMs) - } - - - async accept(arg0: ListenerRegistration): Promise { - if ((arg0.appId == this.appId.appId) && - (arg0.intentName == this.r.intent) && - ((arg0.instanceId == this.appId.instanceId) || (this.appId.instanceId == undefined))) { - this.complete = true - this.ih.pendingIntents.delete(this) - forwardRequest(this.r, { appId: arg0.appId, instanceId: arg0.instanceId }, this.sc, this.ih) - } + complete: boolean = false; + r: IntentRequest; + appId: AppIdentifier; + sc: ServerContext; + ih: IntentHandler; + + constructor(r: IntentRequest, sc: ServerContext, ih: IntentHandler, appId: AppIdentifier) { + this.r = r; + this.appId = appId; + this.sc = sc; + this.ih = ih; + + // handle the timeout + setTimeout(() => { + if (!this.complete) { + errorResponseId(sc, r.requestUuid, r.from, ResolveError.IntentDeliveryFailed, r.type); + this.ih.pendingIntents.delete(this); + } + }, ih.timeoutMs); + } + + async accept(arg0: ListenerRegistration): Promise { + if ( + arg0.appId == this.appId.appId && + arg0.intentName == this.r.intent && + (arg0.instanceId == this.appId.instanceId || this.appId.instanceId == undefined) + ) { + this.complete = true; + this.ih.pendingIntents.delete(this); + forwardRequest(this.r, { appId: arg0.appId, instanceId: arg0.instanceId! }, this.sc, this.ih); } + } } export class IntentHandler implements MessageHandler { + private readonly directory: Directory; + private readonly regs: ListenerRegistration[] = []; + readonly pendingIntents: Set = new Set(); + readonly pendingResolutions: Map = new Map(); + readonly timeoutMs: number; + + constructor(d: Directory, timeoutMs: number) { + this.directory = d; + this.timeoutMs = timeoutMs; + } + + shutdown(): void {} + + async narrowIntents( + raiser: AppIdentifier, + appIntents: AppIntent[], + context: Context, + sc: ServerContext + ): Promise { + const out = await sc.narrowIntents(raiser, appIntents, context); + return out; + } - private readonly directory: Directory - private readonly regs: ListenerRegistration[] = [] - readonly pendingIntents: Set = new Set() - readonly pendingResolutions: Map = new Map() - readonly timeoutMs: number - - constructor(d: Directory, timeoutMs: number) { - this.directory = d - this.timeoutMs = timeoutMs - } - - shutdown(): void { - } - - async narrowIntents(raiser: AppIdentifier, appIntents: AppIntent[], context: Context, sc: ServerContext): Promise { - const out = await sc.narrowIntents(raiser, appIntents, context) - return out - } - - async accept(msg: any, sc: ServerContext, uuid: InstanceID): Promise { - const from = sc.getInstanceDetails(uuid) - - if (from == null) { - // this handler only deals with connected apps - return - } - - try { - - - switch (msg.type as string) { - // finding intents - case 'findIntentsByContextRequest': return this.findIntentsByContextRequest(msg as FindIntentsByContextRequest, sc, from) - case 'findIntentRequest': return this.findIntentRequest(msg as FindIntentRequest, sc, from) - - // listeners - case 'addIntentListenerRequest': return this.onAddIntentListener(msg as AddIntentListenerRequest, sc, from) - case 'intentListenerUnsubscribeRequest': return this.onUnsubscribe(msg as IntentListenerUnsubscribeRequest, sc, from) - - // raising intents and returning results - case 'raiseIntentRequest': return this.raiseIntentRequest(msg as RaiseIntentRequest, sc, from) - case 'raiseIntentForContextRequest': return this.raiseIntentForContextRequest(msg as RaiseIntentForContextRequest, sc, from) - case 'intentResultRequest': return this.intentResultRequest(msg as IntentResultRequest, sc, from) - } + async accept(msg: any, sc: ServerContext, uuid: InstanceID): Promise { + const from = sc.getInstanceDetails(uuid); - } catch (e: any) { - const responseType = msg.type.replace(new RegExp("Request$"), 'Response') - errorResponse(sc, msg, from, e.message ?? e, responseType) - } + if (from == null) { + // this handler only deals with connected apps + return; } - /** - * Called when target app handles an intent - */ - intentResultRequest(arg0: IntentResultRequest, sc: ServerContext, from: AppIdentifier): void | PromiseLike { - const requestId = arg0.payload.raiseIntentRequestUuid - const to = this.pendingResolutions.get(requestId) - if (to) { - // post the result to the app that raised the intent - successResponseId(sc, requestId, to!!, { - intentResult: arg0.payload.intentResult - }, 'raiseIntentResultResponse') - - // respond to the app that handled the intent - successResponse(sc, arg0, from, {}, 'intentResultResponse') - this.pendingResolutions.delete(requestId) - } else { - // no-one waiting for this result - errorResponse(sc, arg0, from, "No-one waiting for this result", 'intentResultResponse') - } + try { + switch (msg.type as string) { + // finding intents + case 'findIntentsByContextRequest': + return this.findIntentsByContextRequest(msg as FindIntentsByContextRequest, sc, from); + case 'findIntentRequest': + return this.findIntentRequest(msg as FindIntentRequest, sc, from); + + // listeners + case 'addIntentListenerRequest': + return this.onAddIntentListener(msg as AddIntentListenerRequest, sc, from); + case 'intentListenerUnsubscribeRequest': + return this.onUnsubscribe(msg as IntentListenerUnsubscribeRequest, sc, from); + + // raising intents and returning results + case 'raiseIntentRequest': + return this.raiseIntentRequest(msg as RaiseIntentRequest, sc, from); + case 'raiseIntentForContextRequest': + return this.raiseIntentForContextRequest(msg as RaiseIntentForContextRequest, sc, from); + case 'intentResultRequest': + return this.intentResultRequest(msg as IntentResultRequest, sc, from); + } + } catch (e: any) { + const responseType = msg.type.replace(new RegExp('Request$'), 'Response'); + errorResponse(sc, msg, from, e.message ?? e, responseType); } - - onUnsubscribe(arg0: IntentListenerUnsubscribeRequest, sc: ServerContext, from: AppIdentifier): void { - const id = arg0.payload.listenerUUID - const fi = this.regs.findIndex((e) => e.listenerUUID == id) - if (fi > -1) { - this.regs.splice(fi, 1) - successResponse(sc, arg0, from, {}, 'intentListenerUnsubscribeResponse') - } else { - errorResponse(sc, arg0, from, "Non-Existent Listener", 'intentListenerUnsubscribeResponse') - } + } + + /** + * Called when target app handles an intent + */ + intentResultRequest( + arg0: IntentResultRequest, + sc: ServerContext, + from: FullAppIdentifier + ): void | PromiseLike { + const requestId = arg0.payload.raiseIntentRequestUuid; + const to = this.pendingResolutions.get(requestId); + if (to) { + // post the result to the app that raised the intent + successResponseId( + sc, + requestId, + to, + { + intentResult: arg0.payload.intentResult, + }, + 'raiseIntentResultResponse' + ); + + // respond to the app that handled the intent + successResponse(sc, arg0, from, {}, 'intentResultResponse'); + this.pendingResolutions.delete(requestId); + } else { + // no-one waiting for this result + errorResponse(sc, arg0, from, 'No-one waiting for this result', 'intentResultResponse'); } - - onAddIntentListener(arg0: AddIntentListenerRequest, sc: ServerContext, from: AppIdentifier): void { - const lr = { - appId: from.appId, - instanceId: from.instanceId, - intentName: arg0.payload.intent, - listenerUUID: sc.createUUID() - } as ListenerRegistration - - this.regs.push(lr) - successResponse(sc, arg0, from, { - listenerUUID: lr.listenerUUID - }, 'addIntentListenerResponse') - - // see if this intent listener is the destination for any pending intents - for (let x of this.pendingIntents) { - x.accept(lr) - if (x.complete) { - this.pendingIntents.delete(x) - } - } + } + + onUnsubscribe(arg0: IntentListenerUnsubscribeRequest, sc: ServerContext, from: FullAppIdentifier): void { + const id = arg0.payload.listenerUUID; + const fi = this.regs.findIndex(e => e.listenerUUID == id); + if (fi > -1) { + this.regs.splice(fi, 1); + successResponse(sc, arg0, from, {}, 'intentListenerUnsubscribeResponse'); + } else { + errorResponse(sc, arg0, from, 'Non-Existent Listener', 'intentListenerUnsubscribeResponse'); } - - hasListener(instanceId: string, intentName: string): boolean { - return this.regs.find(r => (r.instanceId == instanceId) && (r.intentName == intentName)) != null + } + + onAddIntentListener(arg0: AddIntentListenerRequest, sc: ServerContext, from: FullAppIdentifier): void { + const lr: ListenerRegistration = { + appId: from.appId, + instanceId: from.instanceId, + intentName: arg0.payload.intent, + listenerUUID: sc.createUUID(), + }; + + this.regs.push(lr); + successResponse( + sc, + arg0, + from, + { + listenerUUID: lr.listenerUUID, + }, + 'addIntentListenerResponse' + ); + + // see if this intent listener is the destination for any pending intents + for (let x of this.pendingIntents) { + x.accept(lr); + if (x.complete) { + this.pendingIntents.delete(x); + } } - - async getRunningApps(appId: string, sc: ServerContext): Promise { - return (await sc.getConnectedApps()).filter(a => a.appId == appId) + } + + hasListener(instanceId: string, intentName: string): boolean { + return this.regs.find(r => r.instanceId == instanceId && r.intentName == intentName) != null; + } + + async getRunningApps(appId: string, sc: ServerContext): Promise { + return (await sc.getConnectedApps()).filter(a => a.appId == appId); + } + + async startWithPendingIntent( + arg0: IntentRequest, + sc: ServerContext, + target: AppIdentifier + ): Promise { + // app exists but needs starting + const pi = new PendingIntent(arg0, sc, this, target); + this.pendingIntents.add(pi); + sc.open(target?.appId!!).then(() => { + return undefined; + }); + } + + createAppIntents(ir: IntentRequest[], target: AppIdentifier[]): AppIntent[] { + return ir.map(r => { + return { + intent: { + name: r.intent, + displayName: r.intent, + }, + apps: target, + }; + }); + } + + async raiseIntentRequestToSpecificInstance( + arg0: IntentRequest[], + sc: ServerContext, + target: FullAppIdentifier + ): Promise { + if (!(await sc.isAppConnected(target.instanceId))) { + // instance doesn't exist + return errorResponseId( + sc, + arg0[0].requestUuid, + arg0[0].from, + ResolveError.TargetInstanceUnavailable, + arg0[0].type + ); } - async startWithPendingIntent(arg0: IntentRequest, sc: ServerContext, target: AppIdentifier): Promise { - // app exists but needs starting - const pi = new PendingIntent(arg0, sc, this, target) - this.pendingIntents.add(pi) - sc.open(target?.appId!!).then(() => { return undefined }) - } + const requestsWithListeners = arg0.filter(r => this.hasListener(target.instanceId, r.intent)); - createAppIntents(ir: IntentRequest[], target: AppIdentifier[]): AppIntent[] { - return ir.map(r => { - return { - intent: { - name: r.intent, - displayName: r.intent - }, - apps: target - } - }) + if (requestsWithListeners.length == 0) { + this.createPendingIntentIfAllowed(arg0[0], sc, target); + } else { + // ok, deliver to the current running app. + return forwardRequest(requestsWithListeners[0], target, sc, this); } - - async raiseIntentRequestToSpecificInstance(arg0: IntentRequest[], sc: ServerContext, target: AppIdentifier): Promise { - if (!(await sc.isAppConnected(target.instanceId!!))) { - // instance doesn't exist - return errorResponseId(sc, arg0[0].requestUuid, arg0[0].from, ResolveError.TargetInstanceUnavailable, arg0[0].type) - } - - const requestsWithListeners = arg0.filter(r => this.hasListener(target.instanceId!!, r.intent)) - - if (requestsWithListeners.length == 0) { - this.createPendingIntentIfAllowed(arg0[0], sc, target) - } else { - // ok, deliver to the current running app. - return forwardRequest(requestsWithListeners[0], target, sc, this) - } + } + + async createPendingIntentIfAllowed(ir: IntentRequest, sc: ServerContext, target: AppIdentifier) { + // if this app declares that it supports the intent, we'll create a pending intent + const matchingIntents: DirectoryIntent[] = this.directory.retrieveIntents(ir.context.type, ir.intent, undefined); + const declared = matchingIntents.find(i => i.appId == target.appId); + + if (declared) { + // maybe listener hasn't been registered yet - create a pending intent + const pi = new PendingIntent(ir, sc, this, target); + this.pendingIntents.add(pi); + } else { + errorResponseId(sc, ir.requestUuid, ir.from, ResolveError.NoAppsFound, ir.type); } - - async createPendingIntentIfAllowed(ir: IntentRequest, sc: ServerContext, target: AppIdentifier) { - // if this app declares that it supports the intent, we'll create a pending intent - const matchingIntents: DirectoryIntent[] = this.directory.retrieveIntents(ir.context.type, ir.intent, undefined) - const declared = matchingIntents.find(i => i.appId == target.appId) - - if (declared) { - // maybe listener hasn't been registered yet - create a pending intent - const pi = new PendingIntent(ir, sc, this, target) - this.pendingIntents.add(pi) + } + + async raiseIntentRequestToSpecificAppId( + arg0: IntentRequest[], + sc: ServerContext, + target: AppIdentifier + ): Promise { + // dealing with a specific app, which may or may not be open + const runningApps = await this.getRunningApps(target.appId, sc); + + const appIntents = this.createAppIntents(arg0, [...runningApps, { appId: target.appId }]); + + const narrowedAppIntents = await this.narrowIntents(arg0[0].from, appIntents, arg0[0].context, sc); + + if (narrowedAppIntents.length == 1) { + if (narrowedAppIntents[0].apps.length == 2 && narrowedAppIntents[0].apps[0].instanceId) { + // single running instance + return this.raiseIntentRequestToSpecificInstance(arg0, sc, runningApps[0]); + } else if (narrowedAppIntents[0].apps.length == 1) { + // no running instance, single app + const appRecords = this.directory.retrieveAppsById(target.appId); + if (appRecords.length >= 1) { + const ir: IntentRequest = { + ...arg0[0], + intent: narrowedAppIntents[0].intent.name, + }; + return this.startWithPendingIntent(ir, sc, target); } else { - errorResponseId(sc, ir.requestUuid, ir.from, ResolveError.NoAppsFound, ir.type) + // app doesn't exist + return errorResponseId( + sc, + arg0[0].requestUuid, + arg0[0].from, + ResolveError.TargetAppUnavailable, + arg0[0].type + ); } + } } - async raiseIntentRequestToSpecificAppId(arg0: IntentRequest[], sc: ServerContext, target: AppIdentifier): Promise { - // dealing with a specific app, which may or may not be open - const runningApps = await this.getRunningApps(target.appId, sc) - - const appIntents = this.createAppIntents(arg0, [...runningApps, { appId: target.appId }]) - - const narrowedAppIntents = await this.narrowIntents(arg0[0].from, appIntents, arg0[0].context, sc) - - if (narrowedAppIntents.length == 1) { - if ((narrowedAppIntents[0].apps.length == 2) && (narrowedAppIntents[0].apps[0].instanceId)) { - // single running instance - return this.raiseIntentRequestToSpecificInstance(arg0, sc, runningApps[0]) - } else if (narrowedAppIntents[0].apps.length == 1) { - // no running instance, single app - const appRecords = this.directory.retrieveAppsById(target.appId) - if (appRecords.length >= 1) { - const ir: IntentRequest = { - ...arg0[0], - intent: narrowedAppIntents[0].intent.name - } - return this.startWithPendingIntent(ir, sc, target) - } else { - // app doesn't exist - return errorResponseId(sc, arg0[0].requestUuid, arg0[0].from, ResolveError.TargetAppUnavailable, arg0[0].type) - } - } - } - - // need to use the resolver to choose a running app instance + // need to use the resolver to choose a running app instance - if (arg0[0].type == 'raiseIntentResponse') { - return successResponseId(sc, arg0[0].requestUuid, arg0[0].from, { - appIntent: narrowedAppIntents[0] - }, arg0[0].type) - } else { - // raise intent for context - return successResponseId(sc, arg0[0].requestUuid, arg0[0].from, { - appIntents: narrowedAppIntents - }, arg0[0].type) - } + if (arg0[0].type == 'raiseIntentResponse') { + return successResponseId( + sc, + arg0[0].requestUuid, + arg0[0].from, + { + appIntent: narrowedAppIntents[0], + }, + arg0[0].type + ); + } else { + // raise intent for context + return successResponseId( + sc, + arg0[0].requestUuid, + arg0[0].from, + { + appIntents: narrowedAppIntents, + }, + arg0[0].type + ); } - - oneAppOnly(appIntent: AppIntent): boolean { - const apps = appIntent.apps.map(a => a.appId) - const uniqueApps = apps.filter((v, i, a) => a.indexOf(v) === i).length - return (uniqueApps == 1) + } + + oneAppOnly(appIntent: AppIntent): boolean { + const apps = appIntent.apps.map(a => a.appId); + const uniqueApps = apps.filter((v, i, a) => a.indexOf(v) === i).length; + return uniqueApps == 1; + } + + async raiseIntentToAnyApp(arg0: IntentRequest[], sc: ServerContext): Promise { + const connectedApps = await sc.getConnectedApps(); + const matchingIntents = arg0.flatMap(i => this.directory.retrieveIntents(i.context.type, i.intent, undefined)); + const uniqueIntentNames = matchingIntents.map(i => i.intentName).filter((v, i, a) => a.indexOf(v) === i); + + const appIntents: AppIntent[] = uniqueIntentNames.map(i => { + const directoryAppsWithIntent = matchingIntents.filter(mi => mi.intentName == i).map(mi => mi.appId); + const runningApps = connectedApps.filter(ca => directoryAppsWithIntent.includes(ca.appId)); + + return { + intent: { + name: i, + displayName: i, + }, + apps: [ + ...runningApps, + ...directoryAppsWithIntent.map(d => { + return { appId: d }; + }), + ], + }; + }); + + const narrowedAppIntents = await this.narrowIntents(arg0[0].from, appIntents, arg0[0].context, sc); + + if (narrowedAppIntents.length == 0) { + // nothing can resolve the intent, fail + return errorResponseId(sc, arg0[0].requestUuid, arg0[0].from, ResolveError.NoAppsFound, arg0[0].type); } - async raiseIntentToAnyApp(arg0: IntentRequest[], sc: ServerContext): Promise { - const connectedApps = await sc.getConnectedApps() - const matchingIntents = arg0.flatMap(i => this.directory.retrieveIntents(i.context.type, i.intent, undefined)) - const uniqueIntentNames = matchingIntents.map(i => i.intentName).filter((v, i, a) => a.indexOf(v) === i) - - const appIntents: AppIntent[] = uniqueIntentNames.map(i => { - const directoryAppsWithIntent = matchingIntents.filter(mi => mi.intentName == i).map(mi => mi.appId) - const runningApps = connectedApps.filter(ca => directoryAppsWithIntent.includes(ca.appId)) - - return { - intent: { - name: i, - displayName: i - }, - apps: [ - ...runningApps, - ...directoryAppsWithIntent.map(d => { return { appId: d } }) - ] - } - }) - - const narrowedAppIntents = await this.narrowIntents(arg0[0].from, appIntents, arg0[0].context, sc) - - if (narrowedAppIntents.length == 0) { - // nothing can resolve the intent, fail - return errorResponseId(sc, arg0[0].requestUuid, arg0[0].from, ResolveError.NoAppsFound, arg0[0].type) + if (narrowedAppIntents.length == 1) { + const theAppIntent = narrowedAppIntents[0]; + if (this.oneAppOnly(theAppIntent)) { + const instanceCount = theAppIntent.apps.filter(a => a.instanceId).length; + const ir: IntentRequest = { + ...arg0[0], + intent: narrowedAppIntents[0].intent.name, + }; + if (instanceCount == 1 && isFullAppIdentifier(theAppIntent.apps[0])) { + // app is running + return forwardRequest(ir, theAppIntent.apps[0], sc, this); + } else if (instanceCount == 0) { + return this.startWithPendingIntent(ir, sc, theAppIntent.apps[0]); } - - if (narrowedAppIntents.length == 1) { - const theAppIntent = narrowedAppIntents[0] - if (this.oneAppOnly(theAppIntent)) { - const instanceCount = theAppIntent.apps.filter(a => a.instanceId).length - const ir: IntentRequest = { - ...arg0[0], - intent: narrowedAppIntents[0].intent.name - } - if (instanceCount == 1) { - // app is running - return forwardRequest(ir, theAppIntent.apps[0], sc, this) - } else if (instanceCount == 0) { - return this.startWithPendingIntent(ir, sc, theAppIntent.apps[0]) - } - } - } - - if (arg0[0].type == 'raiseIntentResponse') { - // raise intent - return successResponseId(sc, arg0[0].requestUuid, arg0[0].from, { - appIntent: narrowedAppIntents[0] - }, arg0[0].type) - } else { - // raise intent for context - return successResponseId(sc, arg0[0].requestUuid, arg0[0].from, { appIntents: narrowedAppIntents }, arg0[0].type) - } - + } } - async raiseIntentRequest(arg0: RaiseIntentRequest, sc: ServerContext, from: AppIdentifier): Promise { - const intentRequest: IntentRequest = { - context: arg0.payload.context, - from, - intent: arg0.payload.intent, - requestUuid: arg0.meta.requestUuid, - type: 'raiseIntentResponse' - } - - const target = arg0.payload.app!! - if (target?.instanceId) { - return this.raiseIntentRequestToSpecificInstance([intentRequest], sc, target) - } else if (target?.appId) { - return this.raiseIntentRequestToSpecificAppId([intentRequest], sc, target) - } else { - return this.raiseIntentToAnyApp([intentRequest], sc) - } + if (arg0[0].type == 'raiseIntentResponse') { + // raise intent + return successResponseId( + sc, + arg0[0].requestUuid, + arg0[0].from, + { + appIntent: narrowedAppIntents[0], + }, + arg0[0].type + ); + } else { + // raise intent for context + return successResponseId(sc, arg0[0].requestUuid, arg0[0].from, { appIntents: narrowedAppIntents }, arg0[0].type); } - - async raiseIntentForContextRequest(arg0: RaiseIntentForContextRequest, sc: ServerContext, from: AppIdentifier): Promise { - // dealing with a specific instance of an app - const mappedIntents = this.directory.retrieveIntents(arg0.payload.context.type, undefined, undefined) - const uniqueIntentNames = mappedIntents.filter((v, i, a) => a.findIndex(v2 => v2.intentName == v.intentName) == i) - const possibleIntentRequests: IntentRequest[] = uniqueIntentNames.map(i => { - return { - context: arg0.payload.context, - from, - intent: i.intentName, - requestUuid: arg0.meta.requestUuid, - type: 'raiseIntentForContextResponse' - } - }) - - if (possibleIntentRequests.length == 0) { - return errorResponseId(sc, arg0.meta.requestUuid, from, ResolveError.NoAppsFound, 'raiseIntentForContextResponse') - } - - const target = arg0.payload.app!! - if (target?.instanceId) { - return this.raiseIntentRequestToSpecificInstance(possibleIntentRequests, sc, target) - } else if (target?.appId) { - return this.raiseIntentRequestToSpecificAppId(possibleIntentRequests, sc, target) - } else { - return this.raiseIntentToAnyApp(possibleIntentRequests, sc) - } + } + + async raiseIntentRequest( + arg0: RaiseIntentRequest, + sc: ServerContext, + from: FullAppIdentifier + ): Promise { + const intentRequest: IntentRequest = { + context: arg0.payload.context, + from, + intent: arg0.payload.intent, + requestUuid: arg0.meta.requestUuid, + type: 'raiseIntentResponse', + }; + + const target = arg0.payload.app; + if (target) { + if (isFullAppIdentifier(target)) { + return this.raiseIntentRequestToSpecificInstance([intentRequest], sc, target); + } else if (target.appId) { + return this.raiseIntentRequestToSpecificAppId([intentRequest], sc, target); + } else { + //invalid target + console.warn("Received an invalid target argument for raiseIntent", target, arg0); + return this.raiseIntentToAnyApp([intentRequest], sc); + } + } else { + //No target + return this.raiseIntentToAnyApp([intentRequest], sc); } - - async findIntentsByContextRequest(r: FindIntentsByContextRequest, sc: ServerContext, from: AppIdentifier): Promise { - - // TODO: Add result type - const { context } = r.payload - - const apps1 = this.directory.retrieveIntents(context?.type, undefined, undefined) - - // fold apps so same intents aren't duplicated - const apps2: AppIntent[] = [] - apps1.forEach(a1 => { - const existing = apps2.find(a2 => a2.intent.name == a1.intentName) - if (existing) { - existing.apps.push({ appId: a1.appId }) - } else { - apps2.push({ - intent: { - name: a1.intentName, - displayName: a1.displayName ?? a1.intentName - }, - apps: [ - { - appId: a1.appId - } - ] - }) - } - }) - - successResponse(sc, r, from, { - appIntents: apps2 - }, 'findIntentsByContextResponse') + } + + async raiseIntentForContextRequest( + arg0: RaiseIntentForContextRequest, + sc: ServerContext, + from: FullAppIdentifier + ): Promise { + // dealing with a specific instance of an app + const mappedIntents = this.directory.retrieveIntents(arg0.payload.context.type, undefined, undefined); + const uniqueIntentNames = mappedIntents.filter((v, i, a) => a.findIndex(v2 => v2.intentName == v.intentName) == i); + const possibleIntentRequests: IntentRequest[] = uniqueIntentNames.map(i => { + return { + context: arg0.payload.context, + from, + intent: i.intentName, + requestUuid: arg0.meta.requestUuid, + type: 'raiseIntentForContextResponse', + }; + }); + + if (possibleIntentRequests.length == 0) { + return errorResponseId( + sc, + arg0.meta.requestUuid, + from, + ResolveError.NoAppsFound, + 'raiseIntentForContextResponse' + ); } - - async findIntentRequest(r: FindIntentRequest, sc: ServerContext, from: AppIdentifier): Promise { - const { intent, context, resultType } = r.payload - - // listeners for connected applications - const apps2 = (await this.retrieveListeners(intent, sc)) - .map(lr => { - return { - appId: lr.appId, - instanceId: lr.instanceId - } - }) as AppIdentifier[] - - // directory entries - const apps1 = this.directory.retrieveApps(context?.type, intent, resultType) - .map(a => { - return { - appId: a.appId, - } - }) - .filter(i => { - // remove any directory entries that are already started - const running = apps2.find(i2 => i2.appId == i.appId) - return !running - }) as AppIdentifier[] - - // just need this for the (deprecated) display name - const allMatchingIntents = this.directory.retrieveIntents(context?.type, intent, resultType) - const displayName = (allMatchingIntents.length > 0) ? allMatchingIntents[0].displayName : undefined - - successResponse(sc, r, from, { - appIntent: { - intent: { - name: intent, - displayName - }, - apps: [...apps1, ...apps2] - } - }, 'findIntentResponse') + const target = arg0.payload.app; + if (target) { + if (isFullAppIdentifier(target)) { + return this.raiseIntentRequestToSpecificInstance(possibleIntentRequests, sc, target); + } else if (target.appId) { + return this.raiseIntentRequestToSpecificAppId(possibleIntentRequests, sc, target); + } else { + //invalid target + console.warn("Received an invalid target argument for raiseIntentForContext", target, arg0); + return this.raiseIntentToAnyApp(possibleIntentRequests, sc); + } + } else { + //No target + return this.raiseIntentToAnyApp(possibleIntentRequests, sc); } - async retrieveListeners(intentName: string | undefined, sc: ServerContext): Promise { - const activeApps = await sc.getConnectedApps() - const matching = this.regs.filter(r => r.intentName == intentName) - - //console.log(`Matched listeners returned ${matching.length}`) - const active = matching.filter(r => activeApps.find(a => a.instanceId == r.instanceId)) - //console.log(`Active listeners returned ${active.length}`) + } + + async findIntentsByContextRequest( + r: FindIntentsByContextRequest, + sc: ServerContext, + from: FullAppIdentifier + ): Promise { + // TODO: Add result type + const { context } = r.payload; + + const apps1 = this.directory.retrieveIntents(context?.type, undefined, undefined); + + // fold apps so same intents aren't duplicated + const apps2: AppIntent[] = []; + apps1.forEach(a1 => { + const existing = apps2.find(a2 => a2.intent.name == a1.intentName); + if (existing) { + existing.apps.push({ appId: a1.appId }); + } else { + apps2.push({ + intent: { + name: a1.intentName, + displayName: a1.displayName ?? a1.intentName, + }, + apps: [ + { + appId: a1.appId, + }, + ], + }); + } + }); + + successResponse( + sc, + r, + from, + { + appIntents: apps2, + }, + 'findIntentsByContextResponse' + ); + } + + async findIntentRequest( + r: FindIntentRequest, + sc: ServerContext, + from: FullAppIdentifier + ): Promise { + const { intent, context, resultType } = r.payload; + + // listeners for connected applications + const apps2 = (await this.retrieveListeners(intent, sc)).map(lr => { + return { + appId: lr.appId, + instanceId: lr.instanceId, + }; + }) as AppIdentifier[]; + + // directory entries + const apps1 = this.directory + .retrieveApps(context?.type, intent, resultType) + .map(a => { + return { + appId: a.appId, + }; + }) + .filter(i => { + // remove any directory entries that are already started + const running = apps2.find(i2 => i2.appId == i.appId); + return !running; + }) as AppIdentifier[]; + + // just need this for the (deprecated) display name + const allMatchingIntents = this.directory.retrieveIntents(context?.type, intent, resultType); + const displayName = allMatchingIntents.length > 0 ? allMatchingIntents[0].displayName : undefined; + + successResponse( + sc, + r, + from, + { + appIntent: { + intent: { + name: intent, + displayName, + }, + apps: [...apps1, ...apps2], + }, + }, + 'findIntentResponse' + ); + } - return active - } + async retrieveListeners( + intentName: string | undefined, + sc: ServerContext + ): Promise { + const activeApps = await sc.getConnectedApps(); + const matching = this.regs.filter(r => r.intentName == intentName); + //console.log(`Matched listeners returned ${matching.length}`) + const active = matching.filter(r => activeApps.find(a => a.instanceId == r.instanceId)); + //console.log(`Active listeners returned ${active.length}`) + return active; + } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts index 81c7c7b11..85e6c6c12 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts @@ -1,276 +1,363 @@ -import { MessageHandler } from "../BasicFDC3Server"; -import { AppRegistration, InstanceID, ServerContext, State } from "../ServerContext"; -import { Directory, DirectoryApp } from "../directory/DirectoryInterface"; -import { ContextElement } from "@kite9/fdc3-context"; +import { MessageHandler } from '../BasicFDC3Server'; +import { AppRegistration, InstanceID, ServerContext, State } from '../ServerContext'; +import { Directory, DirectoryApp } from '../directory/DirectoryInterface'; +import { ContextElement } from '@kite9/fdc3-context'; +import { OpenError, ResolveError, AppIdentifier, AppMetadata, ImplementationMetadata } from '@kite9/fdc3-standard'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +import { errorResponse, FullAppIdentifier, successResponse } from './support'; import { - OpenError, ResolveError, - AppIdentifier, AppMetadata, -} from "@kite9/fdc3-standard"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { errorResponse, successResponse } from './support' - - -type BroadcastEvent = BrowserTypes.BroadcastEvent -type AddContextListenerRequest = BrowserTypes.AddContextListenerRequest -type FindInstancesRequest = BrowserTypes.FindInstancesRequest -type GetAppMetadataRequest = BrowserTypes.GetAppMetadataRequest -type OpenRequest = BrowserTypes.OpenRequest -type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity -type WebConnectionProtocol5ValidateAppIdentityFailedResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentityFailedResponse -type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse + AgentResponseMessage, + AppRequestMessage, + GetInfoRequest, + isAddContextListenerRequest, + isFindInstancesRequest, + isGetAppMetadataRequest, + isGetInfoRequest, + isOpenRequest, + isWebConnectionProtocol4ValidateAppIdentity, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; + +type BroadcastEvent = BrowserTypes.BroadcastEvent; +type AddContextListenerRequest = BrowserTypes.AddContextListenerRequest; +type FindInstancesRequest = BrowserTypes.FindInstancesRequest; +type GetAppMetadataRequest = BrowserTypes.GetAppMetadataRequest; +type OpenRequest = BrowserTypes.OpenRequest; +type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity; +type WebConnectionProtocol5ValidateAppIdentityFailedResponse = + BrowserTypes.WebConnectionProtocol5ValidateAppIdentityFailedResponse; +type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = + BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse; + +enum AppState { + Opening, + DeliveringContext, + Done, +} -enum AppState { Opening, DeliveringContext, Done } +//TODO: Explain the naming of this file and clarify its purpose (what is it responsible for) - you can't intuit this from the name +//TODO document this class, its purpose and why it is in this file class PendingApp { - - private readonly sc: ServerContext - private readonly msg: OpenRequest - readonly context: ContextElement | undefined - readonly source: AppMetadata - state: AppState = AppState.Opening - private openedApp: AppIdentifier | undefined = undefined - - constructor(sc: ServerContext, msg: OpenRequest, context: ContextElement | undefined, source: AppIdentifier, timeoutMs: number) { - this.context = context - this.source = source - this.sc = sc - this.msg = msg - - setTimeout(() => { - if (this.state != AppState.Done) { - this.onError() - } - }, timeoutMs) - } - - private onSuccess() { - this.sc.setAppState(this.openedApp?.instanceId!!, State.Connected) - successResponse(this.sc, this.msg, this.source, { - appIdentifier: { - appId: this.openedApp!!.appId, - instanceId: this.openedApp!!.instanceId - } - }, 'openResponse') - } - - private onError() { - errorResponse(this.sc, this.msg, this.source, OpenError.AppTimeout, 'openResponse') - } - - setOpened(openedApp: AppIdentifier) { - this.openedApp = openedApp - if (this.context) { - this.state = AppState.DeliveringContext - } else { - this.setDone() - } + private readonly sc: ServerContext; + private readonly msg: OpenRequest; + readonly context: ContextElement | undefined; + readonly source: FullAppIdentifier; + state: AppState = AppState.Opening; + private openedApp: AppIdentifier | undefined = undefined; + + constructor( + sc: ServerContext, + msg: OpenRequest, + context: ContextElement | undefined, + source: FullAppIdentifier, + timeoutMs: number + ) { + this.context = context; + this.source = source; + this.sc = sc; + this.msg = msg; + + setTimeout(() => { + if (this.state != AppState.Done) { + this.onError(); + } + }, timeoutMs); + } + + private onSuccess() { + this.sc.setAppState(this.openedApp?.instanceId!!, State.Connected); + successResponse( + this.sc, + this.msg, + this.source, + { + appIdentifier: { + appId: this.openedApp!!.appId, + instanceId: this.openedApp!!.instanceId, + }, + }, + 'openResponse' + ); + } + + private onError() { + errorResponse(this.sc, this.msg, this.source, OpenError.AppTimeout, 'openResponse'); + } + + setOpened(openedApp: AppIdentifier) { + this.openedApp = openedApp; + if (this.context) { + this.state = AppState.DeliveringContext; + } else { + this.setDone(); } + } - setDone() { - this.state = AppState.Done - this.onSuccess() - } + setDone() { + this.state = AppState.Done; + this.onSuccess(); + } } export class OpenHandler implements MessageHandler { - - private readonly directory: Directory - readonly pending: Map = new Map() - readonly timeoutMs: number - - constructor(d: Directory, timeoutMs: number) { - this.directory = d - this.timeoutMs = timeoutMs - } - - shutdown(): void { - } - - async accept(msg: any, sc: ServerContext, uuid: InstanceID): Promise { - switch (msg.type as string) { - case 'addContextListenerRequest': return this.handleAddContextListener(msg as AddContextListenerRequest, sc, uuid) - case 'WCP4ValidateAppIdentity': return this.handleValidate(msg as WebConnectionProtocol4ValidateAppIdentity, sc, uuid) - } - - const from = sc.getInstanceDetails(uuid) - try { - if (from) { - switch (msg.type as string) { - case 'openRequest': return this.open(msg as OpenRequest, sc, from) - case 'findInstancesRequest': return this.findInstances(msg as FindInstancesRequest, sc, from) - case 'getAppMetadataRequest': return this.getAppMetadata(msg as GetAppMetadataRequest, sc, from) - } - } - } catch (e: any) { - const responseType = msg.type.replace(new RegExp("Request$"), 'Response') - errorResponse(sc, msg, from!!, e.message ?? e, responseType) + private readonly directory: Directory; + readonly pending: Map = new Map(); + readonly timeoutMs: number; + + constructor(d: Directory, timeoutMs: number) { + this.directory = d; + this.timeoutMs = timeoutMs; + } + + shutdown(): void {} + + async accept( + msg: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity, + sc: ServerContext, + uuid: InstanceID + ): Promise { + if (isWebConnectionProtocol4ValidateAppIdentity(msg)) { + return this.handleValidate(msg as WebConnectionProtocol4ValidateAppIdentity, sc, uuid); + } else if (isAddContextListenerRequest(msg)) { + //handle context listener adds for pending applications (i.e. opened but awaiting context listener addition to deliver context) + // additional handling is performed BroadcastHandler + return this.handleAddContextListener(msg as AddContextListenerRequest, sc, uuid); + } else { + const from = sc.getInstanceDetails(uuid); + try { + if (from) { + if (isOpenRequest(msg)) { + return this.open(msg, sc, from); + } else if (isFindInstancesRequest(msg)) { + return this.findInstances(msg, sc, from); + } else if (isGetAppMetadataRequest(msg)) { + return this.getAppMetadata(msg, sc, from); + } else if (isGetInfoRequest(msg)) { + return this.getInfo(msg, sc, from); + } + } else { + console.warn('Received message from unknown source, ignoring', msg, uuid); } - + } catch (e: any) { + const responseType = msg.type.replace(new RegExp('Request$'), 'Response'); + //TODO: create a typeguard for response message types and use it to replace the 'as' below + errorResponse(sc, msg, from!!, e.message ?? e, responseType as AgentResponseMessage['type']); + } } - - /** - * This deals with sending pending context to listeners of newly-opened apps. - */ - handleAddContextListener(arg0: AddContextListenerRequest, sc: ServerContext, from: InstanceID): void { - const pendingOpen = this.pending.get(from) - - if (pendingOpen) { - const channelId = arg0.payload.channelId!! - const contextType = arg0.payload.contextType - - if ((pendingOpen.context) && (pendingOpen.state == AppState.DeliveringContext)) { - if ((contextType == pendingOpen.context.type) || (contextType == undefined)) { - // ok, we can deliver to this listener - - const message: BroadcastEvent = { - meta: { - eventUuid: sc.createUUID(), - timestamp: new Date() - }, - type: "broadcastEvent", - payload: { - channelId, - context: pendingOpen.context, - originatingApp: { - appId: pendingOpen.source.appId, - instanceId: pendingOpen.source.instanceId - } - } - } - - pendingOpen.setDone() - this.pending.delete(from) - sc.post(message, arg0.meta.source?.instanceId!!) - } - } + } + + /** + * This deals with sending pending context to listeners of newly-opened apps. + */ + handleAddContextListener( + arg0: AddContextListenerRequest, + sc: ServerContext, + from: InstanceID + ): void { + const pendingOpen = this.pending.get(from); + + if (pendingOpen) { + const channelId = arg0.payload.channelId!!; + const contextType = arg0.payload.contextType; + + if (pendingOpen.context && pendingOpen.state == AppState.DeliveringContext) { + if (contextType == pendingOpen.context.type || contextType == undefined) { + // ok, we can deliver to this listener + + const message: BroadcastEvent = { + meta: { + eventUuid: sc.createUUID(), + timestamp: new Date(), + }, + type: 'broadcastEvent', + payload: { + channelId, + context: pendingOpen.context, + originatingApp: { + appId: pendingOpen.source.appId, + instanceId: pendingOpen.source.instanceId, + }, + }, + }; + + pendingOpen.setDone(); + this.pending.delete(from); + sc.post(message, arg0.meta.source?.instanceId!!); } + } } - - filterPublicDetails(appD: DirectoryApp, appID: AppIdentifier): AppMetadata { + } + + filterPublicDetails(appD: DirectoryApp, appID: AppIdentifier): AppMetadata { + return { + appId: appD.appId, + name: appD.name, + version: appD.version, + title: appD.title, + tooltip: appD.tooltip, + description: appD.description, + icons: appD.icons, + screenshots: appD.screenshots, + instanceId: appID.instanceId, + }; + } + + getAppMetadata(arg0: GetAppMetadataRequest, sc: ServerContext, from: FullAppIdentifier): void { + const appID = arg0.payload.app; + const details = this.directory.retrieveAppsById(appID.appId); + if (details.length > 0) { + successResponse( + sc, + arg0, + from, + { + appMetadata: this.filterPublicDetails(details[0], appID), + }, + 'getAppMetadataResponse' + ); + } else { + errorResponse(sc, arg0, from, ResolveError.TargetAppUnavailable, 'getAppMetadataResponse'); + } + } + + async findInstances( + arg0: FindInstancesRequest, + sc: ServerContext, + from: FullAppIdentifier + ): Promise { + const appId = arg0.payload.app.appId; + const openApps = await sc.getConnectedApps(); + const matching = openApps + .filter(a => a.appId == appId) + .map(a => { return { - appId: appD.appId, - name: appD.name, - version: appD.version, - title: appD.title, - tooltip: appD.tooltip, - description: appD.description, - icons: appD.icons, - screenshots: appD.screenshots, - instanceId: appID.instanceId - } + appId: a.appId, + instanceId: a.instanceId, + }; + }); + successResponse( + sc, + arg0, + from, + { + appIdentifiers: matching, + }, + 'findInstancesResponse' + ); + } + + async open(arg0: OpenRequest, sc: ServerContext, from: FullAppIdentifier): Promise { + const source = arg0.payload.app; + const context = arg0.payload.context; + + try { + const uuid = await sc.open(source.appId); + this.pending.set(uuid, new PendingApp(sc, arg0, context, from, this.timeoutMs)); + } catch (e: any) { + errorResponse(sc, arg0, from, e.message, 'openResponse'); } - - getAppMetadata(arg0: GetAppMetadataRequest, sc: ServerContext, from: AppIdentifier): void { - const appID = arg0.payload.app - const details = this.directory.retrieveAppsById(appID.appId) - if (details.length > 0) { - successResponse(sc, arg0, from, { - appMetadata: this.filterPublicDetails(details[0], appID) - }, 'getAppMetadataResponse') - } else { - errorResponse(sc, arg0, from, ResolveError.TargetAppUnavailable, 'getAppMetadataResponse') - } + } + + async getInfo(arg0: GetInfoRequest, sc: ServerContext, from: FullAppIdentifier): Promise { + const _this = this; + const implMetadata: ImplementationMetadata = _this.getImplementationMetadata(sc, { + appId: from.appId, + instanceId: from.instanceId, + }); + successResponse( + sc, + arg0, + from, + { + implementationMetadata: implMetadata, + }, + 'getInfoResponse' + ); + } + + getImplementationMetadata(sc: ServerContext, appIdentity: AppIdentifier) { + const appMetadata = this.filterPublicDetails(this.directory.retrieveAppsById(appIdentity.appId)[0], appIdentity); + return { + provider: sc.provider(), + providerVersion: sc.providerVersion(), + fdc3Version: sc.fdc3Version(), + optionalFeatures: { + DesktopAgentBridging: false, + OriginatingAppMetadata: true, + UserChannelMembershipAPIs: true, + }, + appMetadata: appMetadata, + }; + } + + async handleValidate( + arg0: WebConnectionProtocol4ValidateAppIdentity, + sc: ServerContext, + from: InstanceID + ): Promise { + const _this = this; + + const responseMeta = { + connectionAttemptUuid: arg0.meta.connectionAttemptUuid, + timestamp: new Date(), + }; + + function returnError() { + sc.post( + { + meta: responseMeta, + type: 'WCP5ValidateAppIdentityFailedResponse', + payload: { + message: 'App Instance not found', + }, + } as WebConnectionProtocol5ValidateAppIdentityFailedResponse, + from + ); } - - async findInstances(arg0: FindInstancesRequest, sc: ServerContext, from: AppIdentifier): Promise { - const appId = arg0.payload.app.appId - const openApps = await sc.getConnectedApps() - const matching = openApps.filter(a => a.appId == appId).map(a => { - return { - appId: a.appId, - instanceId: a.instanceId - } - }) - successResponse(sc, arg0, from, { - appIdentifiers: matching - }, 'findInstancesResponse') + function returnSuccess(appId: string, instanceId: string) { + const implMetadata: ImplementationMetadata = _this.getImplementationMetadata(sc, { appId, instanceId }); + const msg: WebConnectionProtocol5ValidateAppIdentitySuccessResponse = { + meta: responseMeta, + type: 'WCP5ValidateAppIdentityResponse', + payload: { + appId: appId, + instanceId: instanceId, + instanceUuid: from, + implementationMetadata: implMetadata, + }, + }; + sc.post(msg, instanceId); } - async open(arg0: OpenRequest, sc: ServerContext, from: AppIdentifier): Promise { - - const source = arg0.payload.app - const context = arg0.payload.context - - try { - const uuid = await sc.open(source.appId) - this.pending.set(uuid, new PendingApp(sc, arg0, context, from, this.timeoutMs)) - } catch (e: any) { - errorResponse(sc, arg0, from, e.message, 'openResponse') - } + if (arg0.payload.instanceUuid) { + // existing app reconnecting + const appIdentity = sc.getInstanceDetails(arg0.payload.instanceUuid); + + if (appIdentity) { + // in this case, the app is reconnecting, so let's just re-assign the + // identity + sc.setInstanceDetails(from, appIdentity); + sc.setAppState(from, State.Connected); + return returnSuccess(appIdentity.appId, appIdentity.instanceId); + } } - async handleValidate(arg0: WebConnectionProtocol4ValidateAppIdentity, sc: ServerContext, from: InstanceID): Promise { - const _this = this - - const responseMeta = { - connectionAttemptUuid: arg0.meta.connectionAttemptUuid, - timestamp: new Date() + // we need to assign an identity to this app + const appIdentity = sc.getInstanceDetails(from); + if (appIdentity) { + sc.setAppState(appIdentity.instanceId, State.Connected); + returnSuccess(appIdentity.appId, appIdentity.instanceId); + + // make sure if the opener is listening for this app to open gets informed + const pendingOpen = this.pending.get(from); + if (pendingOpen) { + if (pendingOpen.state == AppState.Opening) { + pendingOpen.setOpened(appIdentity); } - - function returnError() { - sc.post({ - meta: responseMeta, - type: 'WCP5ValidateAppIdentityFailedResponse', - payload: { - message: 'App Instance not found' - } - } as WebConnectionProtocol5ValidateAppIdentityFailedResponse, from) - } - - function returnSuccess(appIdentity: AppIdentifier) { - const aopMetadata = _this.filterPublicDetails(_this.directory.retrieveAppsById(appIdentity.appId)[0], appIdentity) - sc.post({ - meta: responseMeta, - type: 'WCP5ValidateAppIdentityResponse', - payload: { - appId: appIdentity.appId, - instanceId: appIdentity.instanceId, - instanceUuid: from, - implementationMetadata: { - provider: sc.provider(), - providerVersion: sc.providerVersion(), - fdc3Version: sc.fdc3Version(), - optionalFeatures: { - DesktopAgentBridging: false, - OriginatingAppMetadata: true, - UserChannelMembershipAPIs: true - }, - appMetadata: aopMetadata - } - } - } as WebConnectionProtocol5ValidateAppIdentitySuccessResponse, appIdentity.instanceId!!) - } - - if (arg0.payload.instanceUuid) { - // existing app reconnecting - const appIdentity = sc.getInstanceDetails(arg0.payload.instanceUuid) - - if (appIdentity) { - // in this case, the app is reconnecting, so let's just re-assign the - // identity - sc.setInstanceDetails(from, appIdentity) - sc.setAppState(from, State.Connected) - return returnSuccess(appIdentity) - } - } - - // we need to assign an identity to this app - const appIdentity = sc.getInstanceDetails(from) - if (appIdentity) { - sc.setAppState(appIdentity.instanceId, State.Connected) - returnSuccess(appIdentity) - - // make sure if the opener is listening for this app to open gets informed - const pendingOpen = this.pending.get(from) - if (pendingOpen) { - if (pendingOpen.state == AppState.Opening) { - pendingOpen.setOpened(appIdentity) - } - } - } else { - returnError() - } - + } + } else { + returnError(); } -} \ No newline at end of file + } +} diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts index f8fe3889c..700d0ad70 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts @@ -1,20 +1,29 @@ +import { AgentResponseMessage, AppRequestMessage } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { AppRegistration, ServerContext } from "../ServerContext"; -import { BrowserTypes } from "@kite9/fdc3-schema"; import { AppIdentifier } from "@kite9/fdc3-standard"; -type AppRequestMessage = BrowserTypes.AppRequestMessage -type AgentResponseMessage = BrowserTypes.AgentResponseMessage -export function successResponse(sc: ServerContext, request: AppRequestMessage, to: AppIdentifier, payload: any, type: string) { +/** Interface representing a full specified app identifier (instanceId is optional in the API type). */ +export interface FullAppIdentifier { + readonly appId: string; + readonly instanceId: string; +} + +export function isFullAppIdentifier(identifier: AppIdentifier | FullAppIdentifier): identifier is FullAppIdentifier { + const typedIdentifier = (identifier as FullAppIdentifier); + return typedIdentifier.instanceId !== undefined && typedIdentifier.appId !== undefined; + } + +export function successResponse(sc: ServerContext, request: AppRequestMessage, to: FullAppIdentifier, payload: any, type: AgentResponseMessage['type']) { return successResponseId(sc, request.meta.requestUuid, to, payload, type); } -export function errorResponse(sc: ServerContext, request: AppRequestMessage, to: AppIdentifier, error: string, type: string) { +export function errorResponse(sc: ServerContext, request: AppRequestMessage, to: FullAppIdentifier, error: string, type: AgentResponseMessage['type']) { return errorResponseId(sc, request.meta.requestUuid, to, error, type); } -export function successResponseId(sc: ServerContext, requestId: string, to: AppIdentifier, payload: any, type: string) { - sc.post({ +export function successResponseId(sc: ServerContext, requestId: string, to: FullAppIdentifier, payload: AgentResponseMessage['payload'], type: AgentResponseMessage['type']) { + const msg = { meta: { responseUuid: sc.createUUID(), requestUuid: requestId, @@ -22,10 +31,11 @@ export function successResponseId(sc: ServerContext, requestId: }, type, payload, - } as AgentResponseMessage, to.instanceId!!) + }; + sc.post(msg, to.instanceId!) } -export function errorResponseId(sc: ServerContext, requestId: string, to: AppIdentifier, error: string, type: string) { +export function errorResponseId(sc: ServerContext, requestId: string, to: FullAppIdentifier, error: string, type: AgentResponseMessage['type']) { sc.post({ meta: { responseUuid: sc.createUUID(), @@ -36,7 +46,7 @@ export function errorResponseId(sc: ServerContext, requestId: s payload: { error }, - } as AgentResponseMessage, to.instanceId!!) + } as AgentResponseMessage, to.instanceId!) } /* From 26dd3561285dccec74119fa478206d1576a2d876 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 4 Dec 2024 16:50:28 +0000 Subject: [PATCH 29/90] Improved typing and fixes to agent-proxy tests (6 still need fixing) --- .../src/channels/DefaultChannel.ts | 2 +- .../test/features/app-channels.feature | 2 +- .../test/step-definitions/channels.steps.ts | 7 +- .../test/step-definitions/intents.steps.ts | 9 +- .../test/support/TestMessaging.ts | 399 +++++++++--------- .../test/support/responses/ChannelState.ts | 9 +- .../responses/DisconnectPrivateChannel.ts | 5 +- .../test/support/responses/FindInstances.ts | 9 +- .../test/support/responses/FindIntent.ts | 98 +++-- .../support/responses/FindIntentByContext.ts | 101 +++-- .../test/support/responses/GetAppMetadata.ts | 3 +- .../test/support/responses/GetInfo.ts | 43 ++ .../support/responses/GetOrCreateChannel.ts | 8 +- .../test/support/responses/GetUserChannels.ts | 13 +- .../test/support/responses/Handshake.ts | 4 +- .../test/support/responses/IntentResult.ts | 9 +- .../test/support/responses/Open.ts | 15 +- .../test/support/responses/RaiseIntent.ts | 309 +++++++------- .../responses/RaiseIntentForContext.ts | 310 +++++++------- .../support/responses/RegisterListeners.ts | 76 ++-- .../support/responses/UnsubscribeListeners.ts | 15 +- packages/testing/src/steps/generic.steps.ts | 3 +- 22 files changed, 792 insertions(+), 657 deletions(-) create mode 100644 packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index 162a5a4bf..b6007eba2 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -61,7 +61,7 @@ export class DefaultChannel implements Channel { } else if (typeof contextTypeOrHandler === 'string' && handler) { theContextType = contextTypeOrHandler; theHandler = handler; - } else if (handler) { + } else if (contextTypeOrHandler) { // deprecated one-arg version theContextType = null; theHandler = contextTypeOrHandler as ContextHandler; diff --git a/packages/fdc3-agent-proxy/test/features/app-channels.feature b/packages/fdc3-agent-proxy/test/features/app-channels.feature index c3cbf8237..cd529ad47 100644 --- a/packages/fdc3-agent-proxy/test/features/app-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/app-channels.feature @@ -40,7 +40,7 @@ Feature: Channel Listeners Support | {null} | {null} | contextListenerUnsubscribeRequest | Scenario: I can create a listener which listens for any context type - In this version we are using the deprecated no-args approach + In this version we are using the deprecated 1-arg approach Given "resultHandler" pipes context to "contexts" When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name" diff --git a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts index 4b23fffa6..6f28009a0 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts @@ -180,8 +180,11 @@ Given('{string} pipes context to {string}', function (this: CustomWorld, context When('messaging receives {string}', function (this: CustomWorld, field: string) { const message = handleResolve(field, this); - this.log(`Sending: ${JSON.stringify(message)}`); - this.messaging!.receive(message, this.log); + //TODO: restore this + //this.log(`Sending: ${JSON.stringify(message)}`); + console.log(`Sending: `, message); + + this.messaging!.receive(message, console.log);//this.log); }); Then('messaging will have posts', function (this: CustomWorld, dt: DataTable) { diff --git a/packages/fdc3-agent-proxy/test/step-definitions/intents.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/intents.steps.ts index 7de42beef..5fdae2a41 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/intents.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/intents.steps.ts @@ -1,10 +1,9 @@ import { Given } from '@cucumber/cucumber' import { CustomWorld } from '../world/index'; import { handleResolve } from '@kite9/testing'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { Context } from '@kite9/fdc3-context'; -import { ContextMetadata } from '@kite9/fdc3-standard'; -type IntentEvent = BrowserTypes.IntentEvent +import { ContextMetadata, ResolveError } from '@kite9/fdc3-standard'; +import { IntentEvent } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; Given("app {string}", function (this: CustomWorld, appStr: string) { const [appId, instanceId] = appStr.split("/") @@ -75,7 +74,7 @@ Given("Raise Intent will return a context of {string}", function (this: CustomWo }) -Given("Raise Intent will throw a {string} error", function (this: CustomWorld, error: string) { +Given("Raise Intent will throw a {string} error", function (this: CustomWorld, error: ResolveError) { this.messaging?.setIntentResult({ error }) @@ -135,7 +134,7 @@ Given('{string} is a intentEvent message with intent {string} and context {strin const msg: IntentEvent = { type: 'intentEvent', meta: { - eventUuid: this.messaging?.createUUID()!!, + eventUuid: this.messaging!.createUUID(), timestamp: new Date(), }, payload: { diff --git a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts index 751483406..733282d00 100644 --- a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts +++ b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts @@ -1,227 +1,240 @@ -import { AppIdentifier, Channel } from "@kite9/fdc3-standard"; -import { Context } from "@kite9/fdc3-context"; -import { v4 as uuidv4 } from 'uuid' -import { AbstractMessaging } from "../../src/messaging/AbstractMessaging"; -import { RegisterableListener } from "../../src/listeners/RegisterableListener"; -import { FindIntent } from "./responses/FindIntent"; -import { FindIntentByContext } from "./responses/FindIntentByContext"; -import { RaiseIntent } from "./responses/RaiseIntent"; -import { GetAppMetadata } from "./responses/GetAppMetadata"; -import { FindInstances } from "./responses/FindInstances"; -import { Open } from "./responses/Open"; -import { Handshake } from "./responses/Handshake"; -import { GetOrCreateChannel } from "./responses/GetOrCreateChannel"; -import { ChannelState } from "./responses/ChannelState"; -import { GetUserChannels } from "./responses/GetUserChannels"; -import { RegisterListeners } from "./responses/RegisterListeners"; -import { UnsubscribeListeners } from "./responses/UnsubscribeListeners"; -import { CreatePrivateChannel } from "./responses/CreatePrivateChannel"; -import { DisconnectPrivateChannel } from "./responses/DisconnectPrivateChannel"; -import { IntentResult } from "./responses/IntentResult"; -import { RaiseIntentForContext } from "./responses/RaiseIntentForContext"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type AppRequestMessage = BrowserTypes.AppRequestMessage -type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse +import { AppIdentifier, ResolveError } from '@kite9/fdc3-standard'; +import { Context } from '@kite9/fdc3-context'; +import { v4 as uuidv4 } from 'uuid'; +import { AbstractMessaging } from '../../src/messaging/AbstractMessaging'; +import { RegisterableListener } from '../../src/listeners/RegisterableListener'; +import { FindIntent } from './responses/FindIntent'; +import { FindIntentByContext } from './responses/FindIntentByContext'; +import { RaiseIntent } from './responses/RaiseIntent'; +import { GetAppMetadata } from './responses/GetAppMetadata'; +import { FindInstances } from './responses/FindInstances'; +import { Open } from './responses/Open'; +import { Handshake } from './responses/Handshake'; +import { GetOrCreateChannel } from './responses/GetOrCreateChannel'; +import { ChannelState } from './responses/ChannelState'; +import { GetUserChannels } from './responses/GetUserChannels'; +import { RegisterListeners } from './responses/RegisterListeners'; +import { UnsubscribeListeners } from './responses/UnsubscribeListeners'; +import { CreatePrivateChannel } from './responses/CreatePrivateChannel'; +import { DisconnectPrivateChannel } from './responses/DisconnectPrivateChannel'; +import { IntentResult } from './responses/IntentResult'; +import { RaiseIntentForContext } from './responses/RaiseIntentForContext'; +import { + AgentEventMessage, + AgentResponseMessage, + AppRequestMessage, + WebConnectionProtocolMessage, + Channel +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { GetInfo } from './responses/GetInfo'; export interface IntentDetail { - app?: AppIdentifier, - intent?: string, - context?: string, - resultType?: string, + app?: AppIdentifier; + intent?: string; + context?: string; + resultType?: string; } export interface AutomaticResponse { - - filter: (t: string) => boolean, - action: (input: object, m: TestMessaging) => Promise - + filter: (t: string) => boolean; + action: (input: AppRequestMessage, m: TestMessaging) => Promise; } - export interface PossibleIntentResult { - context?: Context; - channel?: any; - error?: string; - timeout?: boolean + context?: Context; + channel?: Channel; + error?: ResolveError; + timeout?: boolean; } function matchStringOrUndefined(expected: string | undefined, actual: string | undefined) { - if ((expected) && (actual)) { - return expected == actual - } else { - return true - } + if (expected && actual) { + return expected == actual; + } else { + return true; + } } function matchString(expected: string | undefined, actual: string | undefined) { - return expected == actual + return expected == actual; } function removeGenericType(t: string) { - const startOfGeneric = t.indexOf("<") - if (startOfGeneric > -1) { - return t.substring(0, startOfGeneric - 1) - } else { - return t - } + const startOfGeneric = t.indexOf('<'); + if (startOfGeneric > -1) { + return t.substring(0, startOfGeneric - 1); + } else { + return t; + } } function matchResultTypes(expected: string | undefined, actual: string | undefined) { - if (expected) { - if (expected.indexOf("<") > -1) { - // looking for a complete match involving generics - return expected == actual - } else if (actual == undefined) { - // no actual, only expected - return false; - } else { - // expected doesn't have generics, match without - const actualType = removeGenericType(actual) - return expected == actualType - } + if (expected) { + if (expected.indexOf('<') > -1) { + // looking for a complete match involving generics + return expected == actual; + } else if (actual == undefined) { + // no actual, only expected + return false; } else { - return true; + // expected doesn't have generics, match without + const actualType = removeGenericType(actual); + return expected == actualType; } + } else { + return true; + } } -export function intentDetailMatches(instance: IntentDetail, template: IntentDetail, contextMustMatch: boolean): boolean { - return matchStringOrUndefined(template.app?.appId, instance.app?.appId) && - matchStringOrUndefined(template.app?.instanceId, instance.app?.instanceId) && - matchStringOrUndefined(template.intent, instance.intent) && - (contextMustMatch ? matchString(template.context, instance.context) : matchStringOrUndefined(template.context, instance.context)) && - matchResultTypes(template.resultType, instance.resultType) +export function intentDetailMatches( + instance: IntentDetail, + template: IntentDetail, + contextMustMatch: boolean +): boolean { + return ( + matchStringOrUndefined(template.app?.appId, instance.app?.appId) && + matchStringOrUndefined(template.app?.instanceId, instance.app?.instanceId) && + matchStringOrUndefined(template.intent, instance.intent) && + (contextMustMatch + ? matchString(template.context, instance.context) + : matchStringOrUndefined(template.context, instance.context)) && + matchResultTypes(template.resultType, instance.resultType) + ); } export class TestMessaging extends AbstractMessaging { - - readonly allPosts: AppRequestMessage[] = [] - readonly listeners: Map = new Map() - readonly intentDetails: IntentDetail[] = [] - readonly channelState: { [key: string]: Context[] } - currentChannel: Channel | null = null - - readonly automaticResponses: AutomaticResponse[] - - constructor(channelState: { [key: string]: Context[] }) { - super({ appId: "TestMessaging", instanceId: "TestMessaging"}); - - this.channelState = channelState - this.automaticResponses = [ - new FindIntent(), - new FindIntentByContext(), - new RaiseIntent(), - new RaiseIntentForContext(), - new IntentResult(), - new GetAppMetadata(), - new FindInstances(), - new Open(), - new Handshake(), - new GetOrCreateChannel(), - new ChannelState(this.channelState), - new GetUserChannels(), - new RegisterListeners(), - new UnsubscribeListeners(), - new CreatePrivateChannel(), - new DisconnectPrivateChannel() - ] - } - - createUUID(): string { - return uuidv4() - } - - getTimeoutMs(): number { - return 1000; - } - - async disconnect(): Promise { - console.log("TestMessaging: disconnect called"); - } - - post(message: AppRequestMessage): Promise { - this.allPosts.push(message) - - for (let i = 0; i < this.automaticResponses.length; i++) { - const ar = this.automaticResponses[i] - if (ar.filter(message.type)) { - return ar.action(message, this) - } - } - - return Promise.resolve(); - } - - addAppIntentDetail(id: IntentDetail) { - this.intentDetails.push(id) - } - - register(l: RegisterableListener) { - if (l.id == null) { - throw new Error("Listener must have ID set") - } else { - this.listeners.set(l.id, l) + readonly allPosts: AppRequestMessage[] = []; + readonly listeners: Map = new Map(); + readonly intentDetails: IntentDetail[] = []; + readonly channelState: { [key: string]: Context[] }; + currentChannel: Channel | null = null; + + readonly automaticResponses: AutomaticResponse[]; + + constructor(channelState: { [key: string]: Context[] }) { + super({ appId: 'TestMessaging', instanceId: 'TestMessaging' }); + + this.channelState = channelState; + this.automaticResponses = [ + new FindIntent(), + new FindIntentByContext(), + new RaiseIntent(), + new RaiseIntentForContext(), + new IntentResult(), + new GetAppMetadata(), + new GetInfo(), + new FindInstances(), + new Open(), + new Handshake(), + new GetOrCreateChannel(), + new ChannelState(this.channelState), + new GetUserChannels(), + new RegisterListeners(), + new UnsubscribeListeners(), + new CreatePrivateChannel(), + new DisconnectPrivateChannel(), + ]; + } + + createUUID(): string { + return uuidv4(); + } + + getTimeoutMs(): number { + return 1000; + } + + async disconnect(): Promise { + console.log('TestMessaging: disconnect called'); + } + + post(message: AppRequestMessage): Promise { + this.allPosts.push(message); + + for (let i = 0; i < this.automaticResponses.length; i++) { + const ar = this.automaticResponses[i]; + if (ar.filter(message.type)) { + return ar.action(message, this); + } + } + + return Promise.resolve(); + } + + addAppIntentDetail(id: IntentDetail) { + this.intentDetails.push(id); + } + + register(l: RegisterableListener) { + if (l.id == null) { + throw new Error('Listener must have ID set'); + } else { + this.listeners.set(l.id, l); + } + } + + unregister(id: string) { + this.listeners.delete(id); + } + + createMeta() { + return { + requestUuid: this.createUUID(), + timestamp: new Date(), + source: this.getAppIdentifier(), + }; + } + + /** + * Used in testing steps + */ + createResponseMeta() { + return { + ...this.createMeta(), + responseUuid: this.createUUID(), + }; + } + + /** + * Used in testing steps + */ + createEventMeta() { + return { + ...this.createMeta(), + eventUuid: this.createUUID(), + }; + } + + receive(m: AgentResponseMessage | AgentEventMessage | WebConnectionProtocolMessage, log?: (s: string) => void) { + this.listeners.forEach((v, k) => { + if (v.filter(m)) { + if (log) { + log('Processing in ' + k); } - } - - unregister(id: string) { - this.listeners.delete(id) - } - - createMeta() { - return { - "requestUuid": this.createUUID(), - "timestamp": new Date(), - "source": this.getAppIdentifier() + v.action(m); + } else { + if (log) { + log('Ignoring in ' + k); } - } + } + }); + } - /** - * Used in testing steps - */ - createResponseMeta() { - return { - ...this.createMeta(), - responseUuid: this.createUUID() - } - } + private ir: PossibleIntentResult | null = null; - /** - * Used in testing steps - */ - createEventMeta() { - return { - ...this.createMeta(), - eventUuid: this.createUUID() - } - } - - receive(m: any, log?: (s: string) => void) { - this.listeners.forEach((v, k) => { - if (v.filter(m)) { - log ? log("Processing in " + k) : "" - v.action(m) - } else { - log ? log("Ignoring in " + k) : "" - } - }) - } - - private ir: PossibleIntentResult | null = null - - getIntentResult() { - return this.ir - } + getIntentResult() { + return this.ir; + } - setIntentResult(o: PossibleIntentResult) { - this.ir = o - } + setIntentResult(o: PossibleIntentResult) { + this.ir = o; + } - retrieveInstanceUuid(): string | undefined { - return (globalThis as any).instanceUuid as string | undefined - } +// retrieveInstanceUuid(): string | undefined { +// return (globalThis as any).instanceUuid; +// } - storeInstanceUuid(validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): void { - (globalThis as any).instanceUuid = validationResponse.payload.instanceUuid - } -} \ No newline at end of file +// storeInstanceUuid(validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): void { +// (globalThis as any).instanceUuid = validationResponse.payload.instanceUuid; +// } +} diff --git a/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts b/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts index 032e5e602..394ccb734 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts @@ -21,6 +21,7 @@ type AgentResponseMessage = BrowserTypes.AgentResponseMessage import { createResponseMeta } from "./support"; import { v4 as uuidv4 } from 'uuid' +import { AppRequestMessage } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export class ChannelState implements AutomaticResponse { @@ -43,8 +44,8 @@ export class ChannelState implements AutomaticResponse { || (t == 'getCurrentContextRequest') } - action(input: any, m: TestMessaging) { - var out: AgentResponseMessage | null = null + action(input: AppRequestMessage, m: TestMessaging) { + let out: AgentResponseMessage | null = null switch (input.type) { case 'joinUserChannelRequest': out = this.createJoinResponse(input as JoinUserChannelRequest) @@ -75,7 +76,7 @@ export class ChannelState implements AutomaticResponse { } if (out) { - setTimeout(() => { m.receive(out!!) }, 100) + setTimeout(() => { m.receive(out!) }, 100) } return Promise.resolve() } @@ -117,7 +118,7 @@ export class ChannelState implements AutomaticResponse { private createGetContextResponse(input: GetCurrentContextRequest): GetCurrentContextResponse { const ch = input.payload.channelId - var last: Context | undefined = undefined + let last: Context | undefined; const contexts = this.contextHistory[ch] ?? [] if (input.payload.contextType) { last = contexts.find((c) => c.type == input.payload.contextType) diff --git a/packages/fdc3-agent-proxy/test/support/responses/DisconnectPrivateChannel.ts b/packages/fdc3-agent-proxy/test/support/responses/DisconnectPrivateChannel.ts index 677ad7723..0b2bf1dc1 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/DisconnectPrivateChannel.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/DisconnectPrivateChannel.ts @@ -1,9 +1,6 @@ import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; import { createResponseMeta } from "./support"; - -type PrivateChannelDisconnectRequest = BrowserTypes.PrivateChannelDisconnectRequest -type PrivateChannelDisconnectResponse = BrowserTypes.PrivateChannelDisconnectResponse +import { PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export class DisconnectPrivateChannel implements AutomaticResponse { diff --git a/packages/fdc3-agent-proxy/test/support/responses/FindInstances.ts b/packages/fdc3-agent-proxy/test/support/responses/FindInstances.ts index 9e3212610..78217a39e 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/FindInstances.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/FindInstances.ts @@ -1,9 +1,6 @@ +import { FindInstancesRequest, FindInstancesResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type FindInstancesRequest = BrowserTypes.FindInstancesRequest -type FindInstancesResponse = BrowserTypes.FindInstancesResponse - +import { createResponseMeta } from "./support"; export class FindInstances implements AutomaticResponse { @@ -20,7 +17,7 @@ export class FindInstances implements AutomaticResponse { private createFindInstancesResponse(m: FindInstancesRequest): FindInstancesResponse { return { - meta: m.meta as any, + meta: createResponseMeta(m.meta), type: "findInstancesResponse", payload: { appIdentifiers: [ diff --git a/packages/fdc3-agent-proxy/test/support/responses/FindIntent.ts b/packages/fdc3-agent-proxy/test/support/responses/FindIntent.ts index 847e9393f..58cf55bf2 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/FindIntent.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/FindIntent.ts @@ -1,51 +1,59 @@ -import { AutomaticResponse, IntentDetail, TestMessaging, intentDetailMatches } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type FindIntentRequest = BrowserTypes.FindIntentRequest -type FindIntentResponse = BrowserTypes.FindIntentResponse +import { AppMetadata } from '@kite9/fdc3-standard'; +import { AutomaticResponse, IntentDetail, TestMessaging, intentDetailMatches } from '../TestMessaging'; +import { + AppRequestMessage, + FindIntentRequest, + FindIntentResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { createResponseMeta } from './support'; export class FindIntent implements AutomaticResponse { + filter(t: string) { + return t == 'findIntentRequest'; + } - filter(t: string) { - return t == 'findIntentRequest' - } - - action(input: object, m: TestMessaging) { - const intentRequest = input as FindIntentRequest - const payload = intentRequest.payload - const intent = payload.intent - const context = payload?.context?.type - const resultType = payload?.resultType; - const template: IntentDetail = { - intent, - context, - resultType - } + action(input: AppRequestMessage, m: TestMessaging) { + const intentRequest = input as FindIntentRequest; + const payload = intentRequest.payload; + const intent = payload.intent; + const context = payload.context?.type; + const resultType = payload.resultType; + const template: IntentDetail = { + intent, + context, + resultType, + }; - const relevant = m.intentDetails.filter(id => intentDetailMatches(id, template, false)) - const request = this.createFindIntentResponseMessage(intentRequest, relevant) - setTimeout(() => { m.receive(request) }, 100) - return Promise.resolve() - } + const relevant = m.intentDetails.filter(id => intentDetailMatches(id, template, false)); + const response = this.createFindIntentResponseMessage(intentRequest, relevant); + //TODO: annotate why this timeout is needed + setTimeout(() => { + m.receive(response); + }, 100); + return Promise.resolve(); + } - private createFindIntentResponseMessage(m: FindIntentRequest, relevant: IntentDetail[]): FindIntentResponse { - return { - meta: m.meta as any, - type: "findIntentResponse", - payload: { - appIntent: { - apps: relevant.map(r => { - return { - appId: r?.app?.appId!!, - instanceId: r?.app?.instanceId - } - }), - intent: { - displayName: m.payload.intent, - name: m.payload.intent - } - } + private createFindIntentResponseMessage(m: FindIntentRequest, relevant: IntentDetail[]): FindIntentResponse { + return { + meta: createResponseMeta(m.meta), + type: 'findIntentResponse', + payload: { + appIntent: { + apps: relevant.reduce((filtered: AppMetadata[], r) => { + if (r?.app?.appId) { + filtered.push({ + appId: r.app?.appId, + instanceId: r.app?.instanceId, + }); } - } - } -} \ No newline at end of file + return filtered; + }, []), + intent: { + displayName: m.payload.intent, + name: m.payload.intent, + }, + }, + }, + }; + } +} diff --git a/packages/fdc3-agent-proxy/test/support/responses/FindIntentByContext.ts b/packages/fdc3-agent-proxy/test/support/responses/FindIntentByContext.ts index d1381d26d..53f228240 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/FindIntentByContext.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/FindIntentByContext.ts @@ -1,47 +1,58 @@ -import { AutomaticResponse, IntentDetail, TestMessaging, intentDetailMatches } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type FindIntentsByContextRequest = BrowserTypes.FindIntentsByContextRequest -type FindIntentsByContextResponse = BrowserTypes.FindIntentsByContextResponse +import { + FindIntentsByContextRequest, + FindIntentsByContextResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AutomaticResponse, IntentDetail, TestMessaging, intentDetailMatches } from '../TestMessaging'; +import { createResponseMeta } from './support'; export class FindIntentByContext implements AutomaticResponse { - - filter(t: string) { - return t == 'findIntentsByContextRequest' - } - - action(input: object, m: TestMessaging) { - const intentRequest = input as FindIntentsByContextRequest - const payload = intentRequest.payload - const context = payload?.context?.type - const template: IntentDetail = { - context - } - - const relevant = m.intentDetails.filter(id => intentDetailMatches(id, template, true)) - const request = this.createFindIntentsByContextResponseMessage(intentRequest, relevant) - setTimeout(() => { m.receive(request) }, 100) - return Promise.resolve() - } - - - private createFindIntentsByContextResponseMessage(m: FindIntentsByContextRequest, relevant: IntentDetail[]): FindIntentsByContextResponse { - const relevantIntents = [...new Set(relevant.map(r => r.intent!!))] - - return { - meta: m.meta as any, - type: "findIntentsByContextResponse", - payload: { - appIntents: - relevantIntents.map(i => { - return { - intent: { name: i, displayName: i }, - apps: relevant - .filter(r => r.intent == i) - .map(r => r.app!!)!! - } - }) - } - } - } -} \ No newline at end of file + filter(t: string) { + return t == 'findIntentsByContextRequest'; + } + + action(input: object, m: TestMessaging) { + const intentRequest = input as FindIntentsByContextRequest; + const payload = intentRequest.payload; + const context = payload?.context?.type; + const template: IntentDetail = { + context, + }; + + const relevant = m.intentDetails.filter(id => intentDetailMatches(id, template, true)); + const request = this.createFindIntentsByContextResponseMessage(intentRequest, relevant); + setTimeout(() => { + m.receive(request); + }, 100); + return Promise.resolve(); + } + + private createFindIntentsByContextResponseMessage( + m: FindIntentsByContextRequest, + relevant: IntentDetail[] + ): FindIntentsByContextResponse { + //get unique intent names + const relevantIntents = [ + ...new Set( + relevant.reduce((filtered: string[], r) => { + if (r.intent) { + filtered.push(r.intent); + } + return filtered; + }, []) + ), + ]; + + return { + meta: createResponseMeta(m.meta), + type: 'findIntentsByContextResponse', + payload: { + appIntents: relevantIntents.map(i => { + return { + intent: { name: i, displayName: i }, + apps: relevant.filter(r => r.intent === i && r.app).map(r => r.app!), + }; + }), + }, + }; + } +} diff --git a/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts b/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts index 5aa6cb72a..86d872f8f 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts @@ -1,5 +1,6 @@ import { AutomaticResponse, TestMessaging } from "../TestMessaging"; import { BrowserTypes } from "@kite9/fdc3-schema"; +import { createResponseMeta } from "./support"; type GetAppMetadataRequest = BrowserTypes.GetAppMetadataRequest type GetAppMetadataResponse = BrowserTypes.GetAppMetadataResponse @@ -20,7 +21,7 @@ export class GetAppMetadata implements AutomaticResponse { private createMetadataResponseMessage(m: GetAppMetadataRequest): GetAppMetadataResponse { return { - meta: m.meta as any, + meta: createResponseMeta(m.meta), type: "getAppMetadataResponse", payload: { appMetadata: { diff --git a/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts b/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts new file mode 100644 index 000000000..a917e9423 --- /dev/null +++ b/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts @@ -0,0 +1,43 @@ +import { AutomaticResponse, TestMessaging } from "../TestMessaging"; +import { createResponseMeta } from "./support"; +import { GetInfoRequest, GetInfoResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; + + +export class GetInfo implements AutomaticResponse { + + filter(t: string) { + return t == 'getInfoRequest' + } + + action(input: object, m: TestMessaging) { + const out = this.createInfoResponseMessage(input as GetInfoRequest) + + setTimeout(() => { m.receive(out) }, 100) + return Promise.resolve() + } + + private createInfoResponseMessage(m: GetInfoRequest): GetInfoResponse { + return { + meta: createResponseMeta(m.meta), + type: "getInfoResponse", + payload: { + implementationMetadata: { + appMetadata: { + appId: "cucumber-app", + instanceId: "cucumber-instance" + }, + fdc3Version: "2.0", + optionalFeatures: { + DesktopAgentBridging: false, + OriginatingAppMetadata: true, + UserChannelMembershipAPIs: true + }, + provider: "cucumber-provider", + providerVersion: "test" + + } + + } + } + } +} \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/test/support/responses/GetOrCreateChannel.ts b/packages/fdc3-agent-proxy/test/support/responses/GetOrCreateChannel.ts index d5a757494..cdee35523 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/GetOrCreateChannel.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/GetOrCreateChannel.ts @@ -1,11 +1,9 @@ import { AutomaticResponse, TestMessaging } from "../TestMessaging"; import { ChannelError } from "@kite9/fdc3-standard"; -import { BrowserTypes } from "@kite9/fdc3-schema"; import { createResponseMeta } from "./support"; +import { AppRequestMessage, GetOrCreateChannelRequest, GetOrCreateChannelResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; type ChannelType = { [channelId: string]: 'user' | 'app' | 'private' } -type GetOrCreateChannelRequest = BrowserTypes.GetOrCreateChannelRequest -type GetOrCreateChannelResponse = BrowserTypes.GetOrCreateChannelResponse export class GetOrCreateChannel implements AutomaticResponse { @@ -16,10 +14,10 @@ export class GetOrCreateChannel implements AutomaticResponse { return t == 'getOrCreateChannelRequest' } - action(input: object, m: TestMessaging) { + action(input: AppRequestMessage, m: TestMessaging) { const out = this.registerChannel(input as GetOrCreateChannelRequest) - setTimeout(() => { m.receive(out as any) }, 100) + setTimeout(() => { m.receive(out) }, 100) return Promise.resolve() } diff --git a/packages/fdc3-agent-proxy/test/support/responses/GetUserChannels.ts b/packages/fdc3-agent-proxy/test/support/responses/GetUserChannels.ts index 6f68a8c3e..78521fce2 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/GetUserChannels.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/GetUserChannels.ts @@ -1,10 +1,8 @@ +import { Channel, GetUserChannelsRequest, GetUserChannelsResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; import { createResponseMeta } from "./support"; -type GetUserChannelsRequest = BrowserTypes.GetUserChannelsRequest -type GetUserChannelsResponse = BrowserTypes.GetUserChannelsResponse -type Channel = BrowserTypes.Channel + export class GetUserChannels implements AutomaticResponse { @@ -22,7 +20,7 @@ export class GetUserChannels implements AutomaticResponse { private createResponse(i: GetUserChannelsRequest, m: TestMessaging): GetUserChannelsResponse { const userChannels: Channel[] = Object.keys(m.channelState).map((c) => { - return { + const aChannel: Channel = { id: c, type: 'user', displayMetadata: { @@ -30,8 +28,9 @@ export class GetUserChannels implements AutomaticResponse { color: "red", glyph: "triangle", } - } as any - }) + }; + return aChannel; + }); return { meta: createResponseMeta(i.meta), diff --git a/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts b/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts index f327f222f..1b8243522 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts @@ -1,8 +1,6 @@ +import { WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentitySuccessResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity -type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse export class Handshake implements AutomaticResponse { diff --git a/packages/fdc3-agent-proxy/test/support/responses/IntentResult.ts b/packages/fdc3-agent-proxy/test/support/responses/IntentResult.ts index eab1f1d9e..4adfa11ee 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/IntentResult.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/IntentResult.ts @@ -1,8 +1,5 @@ +import { IntentResultRequest, IntentResultResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; - -type IntentResultRequest = BrowserTypes.IntentResultRequest -type IntentResultResponse = BrowserTypes.IntentResultResponse export class IntentResult implements AutomaticResponse { @@ -10,8 +7,6 @@ export class IntentResult implements AutomaticResponse { return t == 'intentResultRequest' } - - createIntentResultResponseMessage(intentRequest: IntentResultRequest, m: TestMessaging): IntentResultResponse { const out: IntentResultResponse = { meta: { @@ -30,7 +25,7 @@ export class IntentResult implements AutomaticResponse { const intentRequest = input as IntentResultRequest const payload = intentRequest.payload - m.setIntentResult(payload.intentResult as any) + m.setIntentResult(payload.intentResult) // next, send the result response const out2 = this.createIntentResultResponseMessage(intentRequest, m) diff --git a/packages/fdc3-agent-proxy/test/support/responses/Open.ts b/packages/fdc3-agent-proxy/test/support/responses/Open.ts index fdd3e11d9..6f006ab3c 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/Open.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/Open.ts @@ -1,5 +1,6 @@ -import { AutomaticResponse, IntentDetail, TestMessaging } from "../TestMessaging"; +import { AutomaticResponse, TestMessaging } from "../TestMessaging"; import { BrowserTypes } from "@kite9/fdc3-schema"; +import { createResponseMeta } from "./support"; type OpenRequest = BrowserTypes.OpenRequest type OpenResponse = BrowserTypes.OpenResponse @@ -11,29 +12,29 @@ export class Open implements AutomaticResponse { } action(input: object, m: TestMessaging) { - const out = this.createOpenResponse(input as OpenRequest, m.intentDetails[0], m) + const out = this.createOpenResponse(input as OpenRequest, m) setTimeout(() => { m.receive(out) }, 100) return Promise.resolve() } - private createOpenResponse(m: OpenRequest, id: IntentDetail, tm: TestMessaging): OpenResponse { + private createOpenResponse(m: OpenRequest, tm: TestMessaging): OpenResponse { const found = tm.intentDetails.find(id => id.app?.appId == m.payload.app.appId) - if (found) { + if (found && found.app) { return { - meta: m.meta as any, + meta: createResponseMeta(m.meta), type: "openResponse", payload: { appIdentifier: { - appId: id.app?.appId!!, + appId: found.app.appId, instanceId: "abc123" } } } as OpenResponse } else { return { - meta: m.meta as any, + meta: createResponseMeta(m.meta), type: "openResponse", payload: { error: "AppNotFound" diff --git a/packages/fdc3-agent-proxy/test/support/responses/RaiseIntent.ts b/packages/fdc3-agent-proxy/test/support/responses/RaiseIntent.ts index efb426301..f291cf71f 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/RaiseIntent.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/RaiseIntent.ts @@ -1,158 +1,167 @@ -import { AutomaticResponse, IntentDetail, intentDetailMatches, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { ResolveError } from "@kite9/fdc3-standard" - -type RaiseIntentRequest = BrowserTypes.RaiseIntentRequest -type RaiseIntentResponse = BrowserTypes.RaiseIntentResponse -type RaiseIntentResultResponse = BrowserTypes.RaiseIntentResultResponse - - +import { RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AutomaticResponse, IntentDetail, intentDetailMatches, TestMessaging } from '../TestMessaging'; +import { AppMetadata, ResolveError } from '@kite9/fdc3-standard'; +import { createResponseMeta } from './support'; export class RaiseIntent implements AutomaticResponse { - - filter(t: string) { - return t == 'raiseIntentRequest' - } - - createCannedRaiseIntentResponseMessage(intentRequest: RaiseIntentRequest, m: TestMessaging): RaiseIntentResponse { - const result = m.getIntentResult()!! - if (result.error) { - const out: RaiseIntentResponse = { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - payload: { - error: result.error as any - }, - type: "raiseIntentResponse" - } - - return out - } else { - const out: RaiseIntentResponse = { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - payload: { - intentResolution: { - intent: intentRequest.payload.intent, - source: { - appId: "some-app", - instanceId: "abc123" - } - } - }, - type: "raiseIntentResponse" - } - - return out - } + filter(t: string) { + return t == 'raiseIntentRequest'; + } + + createCannedRaiseIntentResponseMessage(intentRequest: RaiseIntentRequest, m: TestMessaging): RaiseIntentResponse { + const result = m.getIntentResult(); + + if (result && result.error) { + const out: RaiseIntentResponse = { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + payload: { + error: result.error, + }, + type: 'raiseIntentResponse', + }; + + return out; + } else if (result) { + const out: RaiseIntentResponse = { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + payload: { + intentResolution: { + intent: intentRequest.payload.intent, + source: { + appId: 'some-app', + instanceId: 'abc123', + }, + }, + }, + type: 'raiseIntentResponse', + }; + + return out; + } else { + throw new Error("TestMessaging did not return an IntentResult") } - - private createRaiseIntentResponseMessage(intentRequest: RaiseIntentRequest, relevant: IntentDetail[], m: TestMessaging): RaiseIntentResponse { - if (relevant.length == 0) { - return { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - type: "raiseIntentResponse", - payload: { - error: ResolveError.NoAppsFound - } - } - } else if (relevant.length == 1) { - return { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - type: "raiseIntentResponse", - payload: { - intentResolution: { - intent: relevant[0].intent!!, - source: relevant[0].app!! - } + } + + private createRaiseIntentResponseMessage( + intentRequest: RaiseIntentRequest, + relevant: IntentDetail[], + m: TestMessaging + ): RaiseIntentResponse { + if (relevant.length == 0) { + return { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + type: 'raiseIntentResponse', + payload: { + error: ResolveError.NoAppsFound, + }, + }; + } else if (relevant.length == 1 && relevant[0].intent && relevant[0].app) { + return { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + type: 'raiseIntentResponse', + payload: { + intentResolution: { + intent: relevant[0].intent, + source: relevant[0].app, + }, + }, + }; + } else if (relevant.length > 0) { + return { + meta: createResponseMeta(intentRequest.meta), + type: 'raiseIntentResponse', + payload: { + appIntent: { + apps: relevant.reduce((filtered, r) => { + if (r.app?.appId){ + filtered.push({ + appId: r.app.appId, + instanceId: r.app.instanceId, + }); } - } - } else { - return { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - type: "raiseIntentResponse", - payload: { - appIntent: { - apps: relevant.map(r => { - return { - appId: r?.app?.appId!!, - instanceId: r?.app?.instanceId - } - }), - intent: { - displayName: intentRequest.payload.intent, - name: intentRequest.payload.intent - } - } - } - } - } + return filtered; + }, []), + intent: { + displayName: intentRequest.payload.intent, + name: intentRequest.payload.intent, + }, + }, + }, + }; + } else { + throw new Error("createRaiseIntentResponseMessage did not produce a valid result!") } - - createRaiseIntentResultResponseMesssage(intentRequest: RaiseIntentRequest, m: TestMessaging): RaiseIntentResultResponse | undefined { - const result = m.getIntentResult()!! - if (result.error) { - return undefined - } else { - const out: RaiseIntentResultResponse = { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - payload: { - intentResult: m.getIntentResult()!! - }, - type: "raiseIntentResultResponse" - } - - return out - } - + } + + createRaiseIntentResultResponseMessage( + intentRequest: RaiseIntentRequest, + m: TestMessaging + ): RaiseIntentResultResponse | undefined { + const result = m.getIntentResult(); + if (result?.error) { + return undefined; + } else if (result) { + const out: RaiseIntentResultResponse = { + meta: createResponseMeta(intentRequest.meta), + payload: { + intentResult: result, + }, + type: 'raiseIntentResultResponse', + }; + + return out; + } else { + return; } - - action(input: object, m: TestMessaging) { - const intentRequest = input as RaiseIntentRequest - const payload = intentRequest.payload - const intent = payload.intent - const context = payload?.context?.type - - - if (m.getIntentResult() == undefined) { - // we're going to figure out the right response based on the app details (a la FindIntent) - const app = payload?.app - const using: IntentDetail = { - intent, - context, - app - } - - const relevant = m.intentDetails.filter(id => intentDetailMatches(id, using, false)) - const request = this.createRaiseIntentResponseMessage(intentRequest, relevant, m) - setTimeout(() => { m.receive(request) }, 100) - } else if (!m.getIntentResult()?.timeout) { - // this sends out the pre-set intent resolution - const out1 = this.createCannedRaiseIntentResponseMessage(intentRequest, m) - setTimeout(() => { m.receive(out1) }, 100) - - // next, send the result response - const out2 = this.createRaiseIntentResultResponseMesssage(intentRequest, m) - if (out2) { - setTimeout(() => { m.receive(out2) }, 300) - } - } - return Promise.resolve() + } + + action(input: object, m: TestMessaging) { + const intentRequest = input as RaiseIntentRequest; + const payload = intentRequest.payload; + const intent = payload.intent; + const context = payload?.context?.type; + + if (m.getIntentResult() == undefined) { + // we're going to figure out the right response based on the app details (a la FindIntent) + const app = payload?.app; + const using: IntentDetail = { + intent, + context, + app, + }; + + const relevant = m.intentDetails.filter(id => intentDetailMatches(id, using, false)); + const request = this.createRaiseIntentResponseMessage(intentRequest, relevant, m); + setTimeout(() => { + m.receive(request); + }, 100); + } else if (!m.getIntentResult()?.timeout) { + // this sends out the pre-set intent resolution + const out1 = this.createCannedRaiseIntentResponseMessage(intentRequest, m); + setTimeout(() => { + m.receive(out1); + }, 100); + + // next, send the result response + const out2 = this.createRaiseIntentResultResponseMessage(intentRequest, m); + if (out2) { + setTimeout(() => { + m.receive(out2); + }, 300); + } } + return Promise.resolve(); + } } diff --git a/packages/fdc3-agent-proxy/test/support/responses/RaiseIntentForContext.ts b/packages/fdc3-agent-proxy/test/support/responses/RaiseIntentForContext.ts index 44a130700..1691564ab 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/RaiseIntentForContext.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/RaiseIntentForContext.ts @@ -1,151 +1,179 @@ -import { AutomaticResponse, IntentDetail, intentDetailMatches, TestMessaging } from "../TestMessaging"; -import { BrowserTypes } from "@kite9/fdc3-schema"; -import { ResolveError } from "@kite9/fdc3-standard" - -type RaiseIntentForContextRequest = BrowserTypes.RaiseIntentForContextRequest -type RaiseIntentForContextResponse = BrowserTypes.RaiseIntentForContextResponse -type RaiseIntentResultResponse = BrowserTypes.RaiseIntentResultResponse +import { + RaiseIntentForContextRequest, + RaiseIntentForContextResponse, + RaiseIntentResultResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AutomaticResponse, IntentDetail, intentDetailMatches, TestMessaging } from '../TestMessaging'; +import { AppIdentifier, AppIntent, ResolveError } from '@kite9/fdc3-standard'; +import { createResponseMeta } from './support'; export class RaiseIntentForContext implements AutomaticResponse { - - filter(t: string) { - return t == 'raiseIntentForContextRequest' + filter(t: string) { + return t == 'raiseIntentForContextRequest'; + } + + createCannedRaiseIntentForContextResponseMessage( + intentRequest: RaiseIntentForContextRequest, + m: TestMessaging + ): RaiseIntentForContextResponse { + const result = m.getIntentResult(); + if (result && result.error) { + const out: RaiseIntentForContextResponse = { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + payload: { + error: result.error, + }, + type: 'raiseIntentForContextResponse', + }; + + return out; + } else { + const out: RaiseIntentForContextResponse = { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + payload: { + intentResolution: { + intent: 'some-canned-intent', + source: { + appId: 'some-app', + instanceId: 'abc123', + }, + }, + }, + type: 'raiseIntentForContextResponse', + }; + + return out; } - - createCannedRaiseIntentForContextResponseMessage(intentRequest: RaiseIntentForContextRequest, m: TestMessaging): RaiseIntentForContextResponse { - const result = m.getIntentResult()!! - if (result.error) { - const out: RaiseIntentForContextResponse = { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - payload: { - error: result.error as any - }, - type: "raiseIntentForContextResponse" - } - - return out - } else { - const out: RaiseIntentForContextResponse = { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - payload: { - intentResolution: { - intent: "some-canned-intent", - source: { - appId: "some-app", - instanceId: "abc123" - } - } - }, - type: "raiseIntentForContextResponse" - } - - return out - } - } - - private createRaiseIntentForContextResponseMessage(intentRequest: RaiseIntentForContextRequest, relevant: IntentDetail[], m: TestMessaging): RaiseIntentForContextResponse { - if (relevant.length == 0) { - return { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - type: "raiseIntentForContextResponse", - payload: { - error: ResolveError.NoAppsFound - } - } - } else if (relevant.length == 1) { - return { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - type: "raiseIntentForContextResponse", - payload: { - intentResolution: { - intent: relevant[0].intent!!, - source: relevant[0].app!! + } + + private createRaiseIntentForContextResponseMessage( + intentRequest: RaiseIntentForContextRequest, + relevant: IntentDetail[], + m: TestMessaging + ): RaiseIntentForContextResponse { + if (relevant.length == 0) { + return { + meta: createResponseMeta(intentRequest.meta), + type: 'raiseIntentForContextResponse', + payload: { + error: ResolveError.NoAppsFound, + }, + }; + } else if (relevant.length == 1 && relevant[0].intent && relevant[0].app) { + return { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + type: 'raiseIntentForContextResponse', + payload: { + intentResolution: { + intent: relevant[0].intent, + source: relevant[0].app, + }, + }, + }; + } else if (relevant.length > 0) { + //get unique intent names + const relevantIntents = [ + ...new Set( + relevant.reduce((filtered: string[], r) => { + if (r.intent) { + filtered.push(r.intent); } - } - } - } else { + return filtered; + }, []) + ), + ]; + const appIntents = relevantIntents.map(i => { return { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - type: "raiseIntentForContextResponse", - payload: { - appIntents: relevant.map(r => { - return { - apps: [r.app!!], - intent: { - name: r.intent!! - } - } - }) + intent: { name: i, displayName: i }, + apps: relevant.reduce((filtered: AppIdentifier[], r) => { + if (r.intent === i && r.app) { + filtered.push(r.app); } - } - } + return filtered; + }, []) + }; + }); + + return { + meta: createResponseMeta(intentRequest.meta), + type: 'raiseIntentForContextResponse', + payload: { + appIntents: appIntents + }, + }; + } else { + throw new Error("createRaiseIntentForContextResponseMessage did not produce a valid result!") } - - createRaiseIntentResultResponseMesssage(intentRequest: RaiseIntentForContextRequest, m: TestMessaging): RaiseIntentResultResponse | undefined { - const result = m.getIntentResult()!! - if (result.error) { - return undefined - } else { - const out: RaiseIntentResultResponse = { - meta: { - ...intentRequest.meta, - responseUuid: m.createUUID() - }, - payload: { - intentResult: m.getIntentResult()!! - }, - type: "raiseIntentResultResponse" - } - - return out - } - + } + + createRaiseIntentResultResponseMessage( + intentRequest: RaiseIntentForContextRequest, + m: TestMessaging + ): RaiseIntentResultResponse | undefined { + const result = m.getIntentResult(); + if (result && result.error) { + return undefined; + } else if (result) { + const out: RaiseIntentResultResponse = { + meta: { + ...intentRequest.meta, + responseUuid: m.createUUID(), + }, + payload: { + intentResult: result, + }, + type: 'raiseIntentResultResponse', + }; + + return out; + } else { + throw new Error("") } - - - action(input: object, m: TestMessaging) { - const intentRequest = input as RaiseIntentForContextRequest - const payload = intentRequest.payload - const context = payload?.context?.type - - if (m.getIntentResult() == undefined) { - // we're going to figure out the right response based on the app details (a la FindIntent) - const app = payload?.app - const using: IntentDetail = { - context, - app - } - - const relevant = m.intentDetails.filter(id => intentDetailMatches(id, using, false)) - const request = this.createRaiseIntentForContextResponseMessage(intentRequest, relevant, m) - setTimeout(() => { m.receive(request) }, 100) - } else if (!m.getIntentResult()?.timeout) { - // this sends out the pre-set intent resolution - const out1 = this.createCannedRaiseIntentForContextResponseMessage(intentRequest, m) - setTimeout(() => { m.receive(out1) }, 100) - - // next, send the result response - const out2 = this.createRaiseIntentResultResponseMesssage(intentRequest, m) - if (out2) { - setTimeout(() => { m.receive(out2) }, 300) - } - } - - return Promise.resolve() + } + + action(input: object, m: TestMessaging) { + const intentRequest = input as RaiseIntentForContextRequest; + const payload = intentRequest.payload; + const context = payload?.context?.type; + + if (m.getIntentResult() == undefined) { + // we're going to figure out the right response based on the app details (a la FindIntent) + const app = payload?.app; + const using: IntentDetail = { + context, + app, + }; + + const relevant = m.intentDetails.filter(id => intentDetailMatches(id, using, false)); + const request = this.createRaiseIntentForContextResponseMessage(intentRequest, relevant, m); + setTimeout(() => { + m.receive(request); + }, 100); + } else if (!m.getIntentResult()?.timeout) { + // this sends out the pre-set intent resolution + const out1 = this.createCannedRaiseIntentForContextResponseMessage(intentRequest, m); + setTimeout(() => { + m.receive(out1); + }, 100); + + // next, send the result response + const out2 = this.createRaiseIntentResultResponseMessage(intentRequest, m); + if (out2) { + setTimeout(() => { + m.receive(out2); + }, 300); + } } + + return Promise.resolve(); + } } diff --git a/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts b/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts index 9a1136e8e..14f38412f 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts @@ -1,30 +1,56 @@ -import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { createResponseMeta } from "./support"; -import { v4 as uuidv4 } from 'uuid' +import { + AddContextListenerRequest, + AddContextListenerResponse, + AddEventListenerRequest, + AddEventListenerResponse, + AddIntentListenerRequest, + AddIntentListenerResponse, + AppRequestMessage, + PrivateChannelAddEventListenerRequest, + PrivateChannelAddEventListenerResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AutomaticResponse, TestMessaging } from '../TestMessaging'; +import { createResponseMeta } from './support'; +import { v4 as uuidv4 } from 'uuid'; -export class RegisterListeners implements AutomaticResponse { +type requests = + | AddContextListenerRequest + | AddIntentListenerRequest + | AddEventListenerRequest + | PrivateChannelAddEventListenerRequest; +type responses = + | AddContextListenerResponse + | AddIntentListenerResponse + | AddEventListenerResponse + | PrivateChannelAddEventListenerResponse; - filter(t: string) { - return (t == 'addContextListenerRequest') || - (t == 'addIntentListenerRequest') || - (t == 'privateChannelAddContextListenerRequest') || - (t == 'privateChannelAddEventListenerRequest') - } +export class RegisterListeners implements AutomaticResponse { + filter(t: string) { + return ( + t == 'addContextListenerRequest' || + t == 'addIntentListenerRequest' || + t == 'addEventListenerRequest' || + t == 'privateChannelAddEventListenerRequest' + ); + } - action(input: object, m: TestMessaging) { - const out = this.createResponse(input) + action(input: AppRequestMessage, m: TestMessaging) { + const out = this.createResponse(input as requests); - setTimeout(() => { m.receive(out) }, 100) - return Promise.resolve() - } + setTimeout(() => { + m.receive(out); + }, 100); + return Promise.resolve(); + } - private createResponse(i: any): any { - return { - meta: createResponseMeta(i.meta), - type: i.type.replace('Request', 'Response'), - payload: { - listenerUUID: uuidv4() - } - } - } -} \ No newline at end of file + private createResponse(i: requests): responses { + return { + meta: createResponseMeta(i.meta), + //TODO: use a typesafe method of creating response messages + type: i.type.replace('Request', 'Response') as responses['type'], + payload: { + listenerUUID: uuidv4(), + }, + }; + } +} diff --git a/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts b/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts index ef12678cc..f7a278cb5 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts @@ -1,24 +1,31 @@ +import { ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, EventListenerUnsubscribeRequest, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; import { AutomaticResponse, TestMessaging } from "../TestMessaging"; import { createResponseMeta } from "./support"; +import { EventListenerUnsubscribeResponse } from "@kite9/fdc3-schema/dist/generated/api/BrowserTypes"; +type requests = IntentListenerUnsubscribeRequest | PrivateChannelUnsubscribeEventListenerRequest | ContextListenerUnsubscribeRequest | EventListenerUnsubscribeRequest; +type responses = IntentListenerUnsubscribeResponse | PrivateChannelUnsubscribeEventListenerResponse | ContextListenerUnsubscribeResponse | EventListenerUnsubscribeResponse; export class UnsubscribeListeners implements AutomaticResponse { filter(t: string) { return (t == 'intentListenerUnsubscribeRequest') || - (t == 'privateChannelUnsubscribeEventListenerRequest') + (t == 'privateChannelUnsubscribeEventListenerRequest') || + (t == 'contextListenerUnsubscribeRequest') || + (t == 'eventListenerUnsubscribeRequest') } action(input: object, m: TestMessaging) { - const out = this.createResponse(input) + const out = this.createResponse(input as requests) setTimeout(() => { m.receive(out) }, 100) return Promise.resolve() } - private createResponse(i: any): any { + private createResponse(i: requests): responses { return { meta: createResponseMeta(i.meta), - type: i.type.replace('Request', 'Response'), + type: i.type.replace('Request', 'Response') as responses['type'], + payload: {} } } } \ No newline at end of file diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index 884414449..a21f13af6 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -71,7 +71,8 @@ export function setupGenericSteps() { }) Then('{string} is an array of objects with the following contents', function (this: PropsWorld, field: string, dt: DataTable) { - matchData(this, handleResolve(field, this), dt) + const arr = handleResolve(field, this); + matchData(this, arr, dt) }); Then('{string} is an array of strings with the following values', function (this: PropsWorld, field: string, dt: DataTable) { From 25314d2a6daadb84d97bb911b3ec946215ded2b8 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 4 Dec 2024 18:49:00 +0000 Subject: [PATCH 30/90] agent-proxy tests passing, fix PrivateChannel event and getInfo handling --- .../src/channels/DefaultPrivateChannel.ts | 2 +- .../listeners/PrivateChannelEventListener.ts | 6 +- .../test/features/private-channels.feature | 12 +-- .../test/support/TestMessaging.ts | 32 +++++--- .../test/support/responses/GetInfo.ts | 74 +++++++++---------- .../src/messaging/MessagePortMessaging.ts | 5 +- packages/testing/src/steps/generic.steps.ts | 11 ++- 7 files changed, 79 insertions(+), 63 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts index 96bf7b5d5..c57467e08 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts @@ -71,7 +71,7 @@ export class DefaultPrivateChannel extends DefaultChannel implements PrivateChan onDisconnect(handler: () => void): Listener { //Adapt handler type for differences between addEventListener and onDisconnectListener handler types - const adapterHandler: EventHandler = (_event: ApiEvent) => { + const adapterHandler: EventHandler = () => { handler(); }; const l = new PrivateChannelDisconnectEventListener(this.messaging, this.id, adapterHandler); diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index e0706a5c5..88e44b2da 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -6,7 +6,7 @@ import { } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Messaging } from '../Messaging'; import { AbstractListener } from './AbstractListener'; -import { EventHandler, PrivateChannelAddContextListenerEvent, PrivateChannelDisconnectEvent, PrivateChannelEvent, PrivateChannelEventTypes, PrivateChannelUnsubscribeEvent } from '@kite9/fdc3-standard'; +import { ApiEvent, EventHandler, PrivateChannelAddContextListenerEvent, PrivateChannelDisconnectEvent, PrivateChannelEvent, PrivateChannelEventTypes, PrivateChannelUnsubscribeEvent } from '@kite9/fdc3-standard'; type PrivateChannelEventMessages = | PrivateChannelOnAddContextListenerEvent @@ -111,7 +111,7 @@ export class PrivateChannelAddContextEventListener extends AbstractPrivateChanne constructor(messaging: Messaging, channelId: string, handler: EventHandler) { const wrappedHandler = (msg: PrivateChannelEventMessages) => { if (msg.type === "privateChannelOnAddContextListenerEvent") { - const event: PrivateChannelAddContextListenerEvent = { + const event: ApiEvent = { type: "addContextListener", details: { contextType: msg.payload.contextType } }; @@ -129,7 +129,7 @@ export class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChann constructor(messaging: Messaging, channelId: string, handler: EventHandler) { const wrappedHandler = (msg: PrivateChannelEventMessages) => { if (msg.type === "privateChannelOnUnsubscribeEvent") { - const event: PrivateChannelUnsubscribeEvent = { + const event: ApiEvent = { type: "unsubscribe", details: { contextType: msg.payload.contextType } }; diff --git a/packages/fdc3-agent-proxy/test/features/private-channels.feature b/packages/fdc3-agent-proxy/test/features/private-channels.feature index 16dd3eb72..9d1ba3736 100644 --- a/packages/fdc3-agent-proxy/test/features/private-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/private-channels.feature @@ -37,14 +37,14 @@ Feature: Basic Private Channels Support | privateChannelAddEventListenerRequest | addContextListener | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | - Scenario: Adding an "onAddContextListener" on a given Private Channel to receive a notification + Scenario: Adding an "addContextListener" event handler on a given Private Channel to receive a notification Given "onAddContextListenerMessage" is a PrivateChannelOnAddContextListenerEvent message on channel "{privateChannel.id}" with contextType as "fdc3.instrument" And "typesHandler" pipes events to "types" When I call "{privateChannel}" with "addEventListener" with parameters "addContextListener" and "{typesHandler}" And we wait for a period of "100" ms And messaging receives "{onAddContextListenerMessage}" - Then "{types}" is an array of strings with the following values - | value | + Then "{types}" is an array of objects with the following contents + | contextType | | fdc3.instrument | Scenario: Adding and then unsubscribing an "onUnsubscribe" listener will send a notification of each event to the agent @@ -58,14 +58,14 @@ Feature: Basic Private Channels Support | privateChannelAddEventListenerRequest | unsubscribe | {privateChannel.id} | {null} | privateChannelAddEventListenerRequest | | privateChannelUnsubscribeEventListenerRequest | {null} | {null} | {theListener.id} | privateChannelUnsubscribeEventListenerRequest | - Scenario: Adding an "onUnsubscribe" on a given Private Channel to receive a notification + Scenario: Adding an "unsubscribe" event handler on a given Private Channel to receive a notification Given "onUnsubscribeListenerMessage" is a PrivateChannelOnUnsubscribeEvent message on channel "{privateChannel.id}" with contextType as "fdc3.instrument" And "typesHandler" pipes events to "types" When I call "{privateChannel}" with "addEventListener" with parameters "unsubscribe" and "{typesHandler}" And we wait for a period of "100" ms And messaging receives "{onUnsubscribeListenerMessage}" - Then "{types}" is an array of strings with the following values - | value | + Then "{types}" is an array of objects with the following contents + | contextType | | fdc3.instrument | Scenario: Adding and then unsubscribing an "disconnect" listener will send a notification of each event to the agent diff --git a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts index 733282d00..3861905bf 100644 --- a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts +++ b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts @@ -24,7 +24,8 @@ import { AgentResponseMessage, AppRequestMessage, WebConnectionProtocolMessage, - Channel + Channel, + WebConnectionProtocol6Goodbye } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { GetInfo } from './responses/GetInfo'; @@ -103,7 +104,7 @@ export function intentDetailMatches( } export class TestMessaging extends AbstractMessaging { - readonly allPosts: AppRequestMessage[] = []; + readonly allPosts: (AppRequestMessage | WebConnectionProtocol6Goodbye)[] = []; readonly listeners: Map = new Map(); readonly intentDetails: IntentDetail[] = []; readonly channelState: { [key: string]: Context[] }; @@ -112,7 +113,7 @@ export class TestMessaging extends AbstractMessaging { readonly automaticResponses: AutomaticResponse[]; constructor(channelState: { [key: string]: Context[] }) { - super({ appId: 'TestMessaging', instanceId: 'TestMessaging' }); + super({ appId: 'cucumber-app', instanceId: 'cucumber-instance' }); this.channelState = channelState; this.automaticResponses = [ @@ -145,19 +146,28 @@ export class TestMessaging extends AbstractMessaging { } async disconnect(): Promise { - console.log('TestMessaging: disconnect called'); + //Theres no explicit disconnect call for the DA in FDC3, but the BasicDesktopAgent implementation includes one that is called to pagehide + const bye: WebConnectionProtocol6Goodbye = { + type: 'WCP6Goodbye', + meta: { + timestamp: new Date(), + } + }; + await this.post(bye); } - post(message: AppRequestMessage): Promise { + post(message: AppRequestMessage | WebConnectionProtocol6Goodbye): Promise { this.allPosts.push(message); - for (let i = 0; i < this.automaticResponses.length; i++) { - const ar = this.automaticResponses[i]; - if (ar.filter(message.type)) { - return ar.action(message, this); - } + if (message.type != "WCP6Goodbye") { + for (let i = 0; i < this.automaticResponses.length; i++) { + const ar = this.automaticResponses[i]; + if (ar.filter(message.type)) { + return ar.action(message, this); + } + } } - + return Promise.resolve(); } diff --git a/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts b/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts index a917e9423..0a9726de0 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/GetInfo.ts @@ -1,43 +1,41 @@ -import { AutomaticResponse, TestMessaging } from "../TestMessaging"; -import { createResponseMeta } from "./support"; -import { GetInfoRequest, GetInfoResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; - +import { AutomaticResponse, TestMessaging } from '../TestMessaging'; +import { createResponseMeta } from './support'; +import { GetInfoRequest, GetInfoResponse } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class GetInfo implements AutomaticResponse { + filter(t: string) { + return t == 'getInfoRequest'; + } - filter(t: string) { - return t == 'getInfoRequest' - } - - action(input: object, m: TestMessaging) { - const out = this.createInfoResponseMessage(input as GetInfoRequest) + action(input: object, m: TestMessaging) { + const out = this.createInfoResponseMessage(input as GetInfoRequest); - setTimeout(() => { m.receive(out) }, 100) - return Promise.resolve() - } + setTimeout(() => { + m.receive(out); + }, 100); + return Promise.resolve(); + } - private createInfoResponseMessage(m: GetInfoRequest): GetInfoResponse { - return { - meta: createResponseMeta(m.meta), - type: "getInfoResponse", - payload: { - implementationMetadata: { - appMetadata: { - appId: "cucumber-app", - instanceId: "cucumber-instance" - }, - fdc3Version: "2.0", - optionalFeatures: { - DesktopAgentBridging: false, - OriginatingAppMetadata: true, - UserChannelMembershipAPIs: true - }, - provider: "cucumber-provider", - providerVersion: "test" - - } - - } - } - } -} \ No newline at end of file + private createInfoResponseMessage(m: GetInfoRequest): GetInfoResponse { + return { + meta: createResponseMeta(m.meta), + type: 'getInfoResponse', + payload: { + implementationMetadata: { + appMetadata: { + appId: 'cucumber-app', + instanceId: 'cucumber-instance', + }, + fdc3Version: '2.0', + optionalFeatures: { + DesktopAgentBridging: false, + OriginatingAppMetadata: true, + UserChannelMembershipAPIs: true, + }, + provider: 'cucumber-provider', + providerVersion: 'test', + }, + }, + }; + } +} diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 2856e06b0..8702bb182 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -67,12 +67,13 @@ export class MessagePortMessaging extends AbstractMessaging { } async disconnect(): Promise { - await this.post({ + const bye: WebConnectionProtocol6Goodbye = { type: 'WCP6Goodbye', meta: { timestamp: new Date(), } - } as WebConnectionProtocol6Goodbye); + }; + await this.post(bye); this.cd.messagePort.close() } diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index a21f13af6..a6b6845ed 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -72,12 +72,19 @@ export function setupGenericSteps() { Then('{string} is an array of objects with the following contents', function (this: PropsWorld, field: string, dt: DataTable) { const arr = handleResolve(field, this); + console.log(`values: `, arr); matchData(this, arr, dt) }); Then('{string} is an array of strings with the following values', function (this: PropsWorld, field: string, dt: DataTable) { - const values = handleResolve(field, this).map((s: string) => { return { "value": s } }) - matchData(this, values, dt) + const values = handleResolve(field, this) + const processedValues = values.map((s: string) => { return { "value": s } }); + console.log(`values: `, values); + console.log(`processed values: `, processedValues); + console.log("dt raw", dt.raw()); + console.log("dt rows", dt.rows()); + + matchData(this, processedValues, dt) }); Then('{string} is an object with the following contents', function (this: PropsWorld, field: string, params: DataTable) { From fc3438d47ec5acbf4e47de42e5bc66365688eac2 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 4 Dec 2024 23:27:13 +0000 Subject: [PATCH 31/90] dealing private channel event listener changes in fdc3-web-impl --- README.md | 4 ++- packages/testing/src/steps/generic.steps.ts | 5 ---- .../fdc3-web-impl/src/BasicFDC3Server.ts | 2 +- .../src/handlers/BroadcastHandler.ts | 26 +++++++++++++------ .../test/features/private-channel.feature | 12 +++++---- .../test/step-definitions/messaging.steps.ts | 2 +- .../step-definitions/private-channel.steps.ts | 4 +-- 7 files changed, 32 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e517718de..c0310389d 100755 --- a/README.md +++ b/README.md @@ -204,4 +204,6 @@ THIS STANDARD IS BEING OFFERED WITHOUT ANY WARRANTY WHATSOEVER, AND IN PARTICULA ## FDC3 Archive -An archive of FDC3 documentation and meeting notes is available at . The mailing list archive for [fdc3@finos.org](mailto:fdc3@finos.org) is available at +An archive of FDC3 documentation and meeting notes from the early days of FDC3 is available at . Later meeting minutes cam be found in closed Github issues. + +The mailing list archive for [fdc3@finos.org](mailto:fdc3@finos.org) is available at diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index a6b6845ed..30beecc0f 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -72,17 +72,12 @@ export function setupGenericSteps() { Then('{string} is an array of objects with the following contents', function (this: PropsWorld, field: string, dt: DataTable) { const arr = handleResolve(field, this); - console.log(`values: `, arr); matchData(this, arr, dt) }); Then('{string} is an array of strings with the following values', function (this: PropsWorld, field: string, dt: DataTable) { const values = handleResolve(field, this) const processedValues = values.map((s: string) => { return { "value": s } }); - console.log(`values: `, values); - console.log(`processed values: `, processedValues); - console.log("dt raw", dt.raw()); - console.log("dt rows", dt.rows()); matchData(this, processedValues, dt) }); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index 0e5846e2c..fd24badf0 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -32,7 +32,7 @@ export class BasicFDC3Server implements FDC3Server { this.sc = sc; } - receive(message: AppRequestMessage, from: InstanceID): void { + receive(message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity, from: InstanceID): void { // this.sc.log(`MessageReceived: \n ${JSON.stringify(message, null, 2)}`) this.handlers.forEach(h => h.accept(message, this.sc, from)) } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index 5b4bf1cde..abfd86823 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -4,8 +4,7 @@ import { Context } from '@kite9/fdc3-context'; import { AppIdentifier, ChannelError, DisplayMetadata, PrivateChannelEventTypes } from '@kite9/fdc3-standard'; import { successResponse, errorResponse, onlyUnique, FullAppIdentifier } from './support'; import { - AddContextListenerRequest, - AgentEventMessage, + AddContextListenerRequest, AgentResponseMessage, AppRequestMessage, BroadcastRequest, @@ -25,7 +24,6 @@ import { PrivateChannelUnsubscribeEventListenerRequest, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; - type PrivateChannelEvents = | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnUnsubscribeEvent @@ -179,7 +177,11 @@ export class BroadcastHandler implements MessageHandler { } } - handleCreatePrivateChannelRequest(arg0: CreatePrivateChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + handleCreatePrivateChannelRequest( + arg0: CreatePrivateChannelRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { const id = sc.createUUID(); this.state.push({ id, @@ -453,12 +455,16 @@ export class BroadcastHandler implements MessageHandler { invokePrivateChannelEventListeners( privateChannelId: string | null, eventType: PrivateChannelEventTypes, - messageType: PrivateChannelEvents['type'], + messageType: + | 'privateChannelOnAddContextListenerEvent' + | 'privateChannelOnUnsubscribeEvent' + | 'privateChannelOnDisconnectEvent', sc: ServerContext, contextType?: string ) { + console.log('invokePrivateChannelEventListeners', arguments); if (privateChannelId) { - const msg = { + const msg: PrivateChannelEvents = { type: messageType, meta: { eventUuid: sc.createUUID(), @@ -468,11 +474,15 @@ export class BroadcastHandler implements MessageHandler { privateChannelId, contextType: contextType, }, - } as AgentEventMessage; + } as PrivateChannelEvents; //Typescript doesn't like comparing an object with a union property (messageType) with a union of object types + console.log('invokePrivateChannelEventListeners msg: ', msg); this.eventListeners .filter(e => e.channelId == privateChannelId && e.eventType == eventType) - .forEach(e => sc.post(msg, e.instanceId)); + .forEach(e => { + console.log(`invokePrivateChannelEventListeners: posting to instance ${e.instanceId}`); + sc.post(msg, e.instanceId); + }); } } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/private-channel.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/private-channel.feature index efd9dbb74..779c6cf5d 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/private-channel.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/private-channel.feature @@ -6,6 +6,7 @@ Feature: Relaying Private Channel Broadcast messages And "App1/a1" is opened with connection id "a1" And "App2/a2" is opened with connection id "a2" And "App2/a1" creates a private channel + #TODO: have a2 retrieve the private channel by raising an intent - its currently using a1 reference to the channel And I refer to "uuid3" as "channel1Id" Scenario: Creating a new private channel @@ -30,9 +31,10 @@ Feature: Relaying Private Channel Broadcast messages | broadcastResponse | {null} | {null} | {null} | App1 | a1 | Scenario: Event Listener created for addContextListener and unsubscribe - When "App2/a2" adds an "onAddContextListener" on "{channel1Id}" - And "App2/a2" adds an "onUnsubscribe" on "{channel1Id}" + When "App2/a2" adds an "addContextListener" event listener on "{channel1Id}" + And "App2/a2" adds an "unsubscribe" event listener on "{channel1Id}" And "App1/a1" adds a context listener on "{channel1Id}" with type "fdc3.instrument" + And we wait for a period of "10" ms Then messaging will have outgoing posts | msg.matches_type | to.appId | to.instanceId | msg.payload.privateChannelId | msg.payload.contextType | msg.payload.listenerUUID | | privateChannelAddEventListenerResponse | App2 | a2 | {null} | {null} | uuid6 | @@ -46,9 +48,9 @@ Feature: Relaying Private Channel Broadcast messages | contextListenerUnsubscribeResponse | {null} | {null} | App1 | a1 | Scenario: Disconnecting from a channel sends unsubscribe and disconnect messages - When "App2/a2" adds an "onDisconnect" on "{channel1Id}" + When "App2/a2" adds an "disconnect" event listener on "{channel1Id}" And "App1/a1" adds a context listener on "{channel1Id}" with type "fdc3.instrument" - And "App2/a2" adds an "onUnsubscribe" on "{channel1Id}" + And "App2/a2" adds an "unsubscribe" event listener on "{channel1Id}" And "App1/a1" disconnects from private channel "{channel1Id}" Then messaging will have outgoing posts | msg.matches_type | msg.payload.privateChannelId | msg.payload.contextType | to.appId | to.instanceId | @@ -57,7 +59,7 @@ Feature: Relaying Private Channel Broadcast messages | privateChannelDisconnectResponse | {null} | {null} | App1 | a1 | Scenario: addContextListener Event Listener add and removed, shouldn't fire when addContextListener called. - When "App2/a2" adds an "onAddContextListener" on "{channel1Id}" + When "App2/a2" adds an "addContextListener" event listener on "{channel1Id}" And "App2/a2" removes event listener "uuid6" And "App1/a1" adds a context listener on "{channel1Id}" with type "fdc3.instrument" Then messaging will have outgoing posts diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/messaging.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/messaging.steps.ts index 7bfc287a7..917ac9546 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/messaging.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/messaging.steps.ts @@ -7,7 +7,7 @@ import { setupGenericSteps, matchData } from '@kite9/testing'; Then('messaging will have outgoing posts', function (this: CustomWorld, dt: DataTable) { // just take the last few posts and match those const matching = dt.rows().length - var toUse = this.sc?.postedMessages + let toUse = this.sc?.postedMessages if (toUse.length > matching) { toUse = toUse.slice(toUse.length - matching, toUse.length) } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts index 1e2978fc9..a4686a330 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts @@ -35,9 +35,9 @@ When('{string} removes event listener {string}', function (this: CustomWorld, ap this.server.receive(message, uuid) }) -When('{string} adds an {string} on {string}', function (this: CustomWorld, app: string, listenerType: string, channelId: string) { +When('{string} adds an {string} event listener on {string}', function (this: CustomWorld, app: string, listenerType: string, channelId: string) { const meta = createMeta(this, app) - const uuid = this.sc.getInstanceUUID(meta.source)!! + const uuid = this.sc.getInstanceUUID(meta.source)! const message = { meta, payload: { From e5676782a17d957219c0a0bc03f6b16aee50b839 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 6 Dec 2024 14:36:27 +0000 Subject: [PATCH 32/90] more typing and formatting in fdc3-get-agent --- .../strategies/DesktopAgentPreloadLoader.ts | 4 +- .../fdc3-get-agent/src/strategies/getAgent.ts | 21 +- packages/fdc3-get-agent/src/util/Logger.ts | 1 + .../fdc3-get-agent/test/support/FrameTypes.ts | 6 +- .../test/support/MockFDC3Server.ts | 30 +- .../fdc3-get-agent/test/support/MockIFrame.ts | 4 +- .../test/support/TestServerContext.ts | 303 +++++++++--------- 7 files changed, 190 insertions(+), 179 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts index 93c2846f2..512f5382c 100644 --- a/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/DesktopAgentPreloadLoader.ts @@ -19,7 +19,7 @@ export class DesktopAgentPreloadLoader implements Loader { timeout: NodeJS.Timeout | null = null; /** Reference to the get fn's Promise's reject call - used when cancelling. */ - rejectFn: ((reason?: any) => void) | null = null; + rejectFn: ((reason?: string) => void) | null = null; async poll(resolve: (value: DesktopAgentSelection) => void) { if (globalThis.window.fdc3) { @@ -96,7 +96,7 @@ export class DesktopAgentPreloadLoader implements Loader { Logger.debug("DesktopAgentPreloadLoader: Cleaning up"); this.done = true; if (this.rejectFn){ - this.rejectFn(new Error(AgentError.AgentNotFound)); + this.rejectFn(AgentError.AgentNotFound); this.rejectFn = null; } if (this.timeout) { diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index dbf5cf175..4227a88bb 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -17,7 +17,7 @@ const isFulfilled = (input: PromiseSettledResult): input is PromiseFulfill * For now, we only allow a single call to getAgent per application, so * we keep track of the promise we use here. */ -var theAgentPromise: Promise | null = null; +let theAgentPromise: Promise | null = null; export function clearAgentPromise() { theAgentPromise = null; @@ -31,8 +31,13 @@ function initAgentPromise(options: GetAgentParams): Promise { Logger.log(`Initiating Desktop Agent discovery at ${new Date().toISOString()}`); let strategies: Loader[]; + //if options doesn't contain an identityURL, use the actualUrl + if (!options.identityUrl){ + options.identityUrl = globalThis.window.location.href; + } + //Retrieve persisted connection data limit to a previous strategy if one exists - const persistedData = retrieveDesktopAgentDetails(options.identityUrl ?? globalThis.window.location.href); + const persistedData = retrieveDesktopAgentDetails(options.identityUrl); if (persistedData) { switch (persistedData.agentType) { case WebDesktopAgentType.Preload: @@ -98,13 +103,11 @@ function initAgentPromise(options: GetAgentParams): Promise { //if we received any error other than AgentError.AgentNotFound, throw it const errors = results.filter(isRejected); + //n.b. the Loaders throw string error messages, rather than Error objects Logger.debug(`Discovery errors: ${JSON.stringify(errors)}`); - const error = errors.find((aRejection) => { - aRejection.reason?.message ?? aRejection.reason !== AgentError.AgentNotFound; - }); + const error = errors.find((aRejection) => aRejection.reason !== AgentError.AgentNotFound); if (error){ - throw error; - + throw new Error(error.reason); } else if (options.failover != undefined) { Logger.debug(`Calling failover fn...`); //Proceed with the failover @@ -131,6 +134,7 @@ function initAgentPromise(options: GetAgentParams): Promise { return selection.agent; } catch (e) { + //n.b. FailoverHandler throws Error Objects so we can return this directly Logger.error("Desktop agent not found. Error reported during failover", e); throw e; } @@ -181,8 +185,7 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { dontSetWindowFdc3: true, channelSelector: true, intentResolver: true, - timeoutMs: DEFAULT_TIMEOUT_MS, - identityUrl: globalThis.window.location.href + timeoutMs: DEFAULT_TIMEOUT_MS }; const options: GetAgentParams = { diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 9988a7b9e..54957d29c 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ const GET_AGENT_LOG_PREFIX = "FDC3 getAgent: "; export class Logger { diff --git a/packages/fdc3-get-agent/test/support/FrameTypes.ts b/packages/fdc3-get-agent/test/support/FrameTypes.ts index 443998425..708dd4dce 100644 --- a/packages/fdc3-get-agent/test/support/FrameTypes.ts +++ b/packages/fdc3-get-agent/test/support/FrameTypes.ts @@ -1,6 +1,6 @@ import { CustomWorld } from "../world" import { MockWindow } from "./MockWindow" -import { CHANNEL_SELECTOR_URL, EMBED_URL, INTENT_RESPOLVER_URL } from "./MockFDC3Server" +import { CHANNEL_SELECTOR_URL, EMBED_URL, INTENT_RESOLVER_URL } from "./MockFDC3Server" import { BrowserTypes } from "@kite9/fdc3-schema" import { FDC3_USER_INTERFACE_HANDSHAKE_TYPE, FDC3_USER_INTERFACE_HELLO_TYPE, FDC3_USER_INTERFACE_RESTYLE_TYPE } from "@kite9/fdc3-schema/dist/generated/api/BrowserTypes" @@ -24,7 +24,7 @@ export function handleEmbeddedIframeComms(value: string, parent: MockWindow, cw: }, payload: { fdc3Version: "2.2", - intentResolverUrl: INTENT_RESPOLVER_URL, + intentResolverUrl: INTENT_RESOLVER_URL, channelSelectorUrl: CHANNEL_SELECTOR_URL, } } as WebConnectionProtocol3Handshake, EMBED_URL, [connection!!.externalPort]) @@ -87,7 +87,7 @@ export function handleIntentResolverComms(_value: string, parent: MockWindow, so } } } as Fdc3UserInterfaceHello, - origin: INTENT_RESPOLVER_URL, + origin: INTENT_RESOLVER_URL, source, ports: [connection.port1] } as any as Event) diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index 5b4da0f3d..343d82b3e 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -20,7 +20,7 @@ export const EMBED_URL = "http://localhost:8080/static/da/embed.html" export const CHANNEL_SELECTOR_URL = "https://mock.fdc3.com/channelSelector" -export const INTENT_RESPOLVER_URL = "https://mock.fdc3.com/resolver" +export const INTENT_RESOLVER_URL = "https://mock.fdc3.com/resolver" export class MockFDC3Server implements FDC3Server { @@ -86,19 +86,21 @@ export class MockFDC3Server implements FDC3Server { source.postMessage(message, origin); } else { const details = this.tsc.getMatchingInstance(data.payload.identityUrl) - const message: WebConnectionProtocol3Handshake = { - type: "WCP3Handshake", - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date() - }, - payload: { - fdc3Version: "2.2", - intentResolverUrl: INTENT_RESPOLVER_URL, - channelSelectorUrl: CHANNEL_SELECTOR_URL, - } - }; - source.postMessage(message , origin, [details!.externalPort]) + if (details) { + const message: WebConnectionProtocol3Handshake = { + type: "WCP3Handshake", + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date() + }, + payload: { + fdc3Version: "2.2", + intentResolverUrl: INTENT_RESOLVER_URL, + channelSelectorUrl: CHANNEL_SELECTOR_URL, + } + }; + source.postMessage(message , origin, [details.externalPort]); + } //getMatchingInstance will log if it didn't find anything } } else if (data.type == "WCP6Goodbye") { this.receivedGoodbye = true; diff --git a/packages/fdc3-get-agent/test/support/MockIFrame.ts b/packages/fdc3-get-agent/test/support/MockIFrame.ts index f16b4acbc..5334def42 100644 --- a/packages/fdc3-get-agent/test/support/MockIFrame.ts +++ b/packages/fdc3-get-agent/test/support/MockIFrame.ts @@ -1,6 +1,6 @@ import { CustomWorld } from "../world"; import { handleEmbeddedIframeComms, handleChannelSelectorComms, handleIntentResolverComms } from "./FrameTypes"; -import { EMBED_URL, CHANNEL_SELECTOR_URL, INTENT_RESPOLVER_URL } from "./MockFDC3Server"; +import { EMBED_URL, CHANNEL_SELECTOR_URL, INTENT_RESOLVER_URL } from "./MockFDC3Server"; import { MockWindow } from "./MockWindow"; export class MockIFrame extends MockWindow { @@ -26,7 +26,7 @@ export class MockIFrame extends MockWindow { } else if (value.startsWith(CHANNEL_SELECTOR_URL)) { this.name = "channel-selector"; this.messageChannels.push(handleChannelSelectorComms(value, parent, this.contentWindow, this.cw)); - } else if (value.startsWith(INTENT_RESPOLVER_URL)) { + } else if (value.startsWith(INTENT_RESOLVER_URL)) { this.name = "intent-resolver"; this.messageChannels.push(handleIntentResolverComms(value, parent, this.contentWindow, this.cw)); } diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index 9a3fe96c7..ed8f96f59 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -1,155 +1,160 @@ -import { ServerContext, InstanceID } from '@kite9/fdc3-web-impl' -import { CustomWorld } from '../world' -import { Context } from '@kite9/fdc3-context' -import { OpenError, AppIdentifier, AppIntent } from '@kite9/fdc3-standard' -import { AppRegistration, State } from '@kite9/fdc3-web-impl' +import { ServerContext, InstanceID } from '@kite9/fdc3-web-impl'; +import { CustomWorld } from '../world'; +import { OpenError, AppIdentifier, AppIntent } from '@kite9/fdc3-standard'; +import { AppRegistration, State } from '@kite9/fdc3-web-impl'; type ConnectionDetails = AppRegistration & { - msg?: object - connectionId: string, - externalPort: MessagePort, - internalPort: MessagePort, - url: string -} + msg?: object; + connectionId: string; + externalPort: MessagePort; + internalPort: MessagePort; + url: string; +}; type MessageRecord = { - to?: AppIdentifier, - uuid?: InstanceID, - msg: object -} + to?: AppIdentifier; + uuid?: InstanceID; + msg: object; +}; export class TestServerContext implements ServerContext { - - public postedMessages: MessageRecord[] = [] - public readonly cw: CustomWorld - private instances: ConnectionDetails[] = [] - private nextInstanceId: number = 0 - private nextUUID: number = 0 - - constructor(cw: CustomWorld) { - this.cw = cw - } - - async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[], _context: Context): Promise { - return appIntents - } - - getInstanceDetails(uuid: string) { - return this.instances.find(ca => ca.instanceId === uuid) - } - - setInstanceDetails(uuid: InstanceID, appId: ConnectionDetails) { - this.instances = this.instances.filter(ca => ca.connectionId !== uuid) - this.instances.push({ - ...appId, - connectionId: uuid - }) - } - - getMatchingInstance(url: string): ConnectionDetails | undefined { - return this.instances.find(ca => ca.url === url) - } - - async shutdown(): Promise { - await Promise.all(this.instances.map(i => i.internalPort.close())) - await Promise.all(this.instances.map(i => i.externalPort.close())) - } - - async open(appId: string): Promise { - const ni = this.nextInstanceId++ - if (appId.includes("missing")) { - throw new Error(OpenError.AppNotFound) - } else { - const mc = new MessageChannel() - const internalPort = mc.port1 - const externalPort = mc.port2; - - (internalPort as any).name = "internalPort-" + ni; - (externalPort as any).name = "externalPort-" + ni; - - internalPort.start() - - const connectionDetails = { - appId, - instanceId: "uuid-" + ni, - connected: false, - connectionId: "uuid-" + ni, - externalPort, - internalPort, - url: "https://dummyOrigin.test/path", - state: State.Pending - } - - this.instances.push(connectionDetails) - internalPort.onmessage = (msg) => { - this.cw.mockFDC3Server?.receive(msg.data, connectionDetails.instanceId) - } - - return connectionDetails.connectionId - } - } - - async getConnectedApps(): Promise { - return (await this.getAllApps()).filter(ca => ca.state == State.Connected) - } - - async isAppConnected(app: InstanceID): Promise { - const found = this.instances.find(a => (a.instanceId == app) && (a.state == State.Connected)) - return found != null - } - - async setAppState(app: InstanceID, state: State): Promise { - const found = this.instances.find(a => (a.instanceId == app)) - if (found) { - found.state = state - } - } - async getAllApps(): Promise { - return this.instances.map(x => { - return { - appId: x.appId, - instanceId: x.instanceId, - state: x.state - } - }) - } - - provider(): string { - return "cucumber-provider" - } - providerVersion(): string { - return "1.2.3.TEST" - } - fdc3Version(): string { - return "2.0" - } - - createUUID(): string { - return "uuid" + this.nextUUID++ - } - - /** - * USED FOR TESTING - */ - getInstanceUUID(appId: AppIdentifier): InstanceID | undefined { - return this.instances.find(ca => (ca.appId == appId.appId) && (ca.instanceId == appId.instanceId) && (ca.state == State.Connected))?.instanceId - } - - /** - * USED FOR TESTING - */ - getFirstInstance() { - return this.instances[0] - } - - post(msg: object, to: InstanceID): Promise { - const details = this.getInstanceDetails(to) - details?.internalPort.postMessage(msg) - return Promise.resolve(); - } - - log(message: string): void { - this.cw.log(message) - } - -} \ No newline at end of file + public postedMessages: MessageRecord[] = []; + public readonly cw: CustomWorld; + private instances: ConnectionDetails[] = []; + private nextInstanceId: number = 0; + private nextUUID: number = 0; + + constructor(cw: CustomWorld) { + this.cw = cw; + } + + async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[]/*, _context: Context*/): Promise { + return appIntents; + } + + getInstanceDetails(uuid: string) { + return this.instances.find(ca => ca.instanceId === uuid); + } + + setInstanceDetails(uuid: InstanceID, appId: ConnectionDetails) { + this.instances = this.instances.filter(ca => ca.connectionId !== uuid); + this.instances.push({ + ...appId, + connectionId: uuid, + }); + } + + getMatchingInstance(url: string): ConnectionDetails | undefined { + const details = this.instances.find(ca => ca.url === url); + + if (!details) { + console.error(`No connection instance found for ${url}, known instances: `, this.instances); + } + + return; + } + + async shutdown(): Promise { + await Promise.all(this.instances.map(i => i.internalPort.close())); + await Promise.all(this.instances.map(i => i.externalPort.close())); + } + + async open(appId: string): Promise { + const ni = this.nextInstanceId++; + if (appId.includes('missing')) { + throw new Error(OpenError.AppNotFound); + } else { + const mc = new MessageChannel(); + const internalPort = mc.port1; + const externalPort = mc.port2; + + // internalPort.name = 'internalPort-' + ni; + // externalPort.name = 'externalPort-' + ni; + + internalPort.start(); + + const connectionDetails = { + appId, + instanceId: 'uuid-' + ni, + connected: false, + connectionId: 'uuid-' + ni, + externalPort, + internalPort, + url: 'https://dummyOrigin.test/path', + state: State.Pending, + }; + + this.instances.push(connectionDetails); + internalPort.onmessage = msg => { + this.cw.mockFDC3Server?.receive(msg.data, connectionDetails.instanceId); + }; + + return connectionDetails.connectionId; + } + } + + async getConnectedApps(): Promise { + return (await this.getAllApps()).filter(ca => ca.state == State.Connected); + } + + async isAppConnected(app: InstanceID): Promise { + const found = this.instances.find(a => a.instanceId == app && a.state == State.Connected); + return found != null; + } + + async setAppState(app: InstanceID, state: State): Promise { + const found = this.instances.find(a => a.instanceId == app); + if (found) { + found.state = state; + } + } + async getAllApps(): Promise { + return this.instances.map(x => { + return { + appId: x.appId, + instanceId: x.instanceId, + state: x.state, + }; + }); + } + + provider(): string { + return 'cucumber-provider'; + } + providerVersion(): string { + return '1.2.3.TEST'; + } + fdc3Version(): string { + return '2.0'; + } + + createUUID(): string { + return 'uuid' + this.nextUUID++; + } + + /** + * USED FOR TESTING + */ + getInstanceUUID(appId: AppIdentifier): InstanceID | undefined { + return this.instances.find( + ca => ca.appId == appId.appId && ca.instanceId == appId.instanceId && ca.state == State.Connected + )?.instanceId; + } + + /** + * USED FOR TESTING + */ + getFirstInstance() { + return this.instances[0]; + } + + post(msg: object, to: InstanceID): Promise { + const details = this.getInstanceDetails(to); + details?.internalPort.postMessage(msg); + return Promise.resolve(); + } + + log(message: string): void { + this.cw.log(message); + } +} From 89a8ae250bbc99abff2f3ca1661a0a47ed3dffa5 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 6 Dec 2024 15:59:49 +0000 Subject: [PATCH 33/90] more test cleanup and adding a test for failed validation --- .../src/strategies/PostMessageLoader.ts | 89 ++++++++++--------- .../features/desktop-agent-strategy.feature | 38 +++++++- .../step-definitions/desktop-agent.steps.ts | 54 ++++++++--- .../step-definitions/intent-resolver.steps.ts | 7 +- .../test/support/MockFDC3Server.ts | 2 - .../test/support/TestServerContext.ts | 78 +++++++++------- .../test/support/responses/GetInfo.ts | 2 +- .../test/support/responses/Handshake.ts | 40 +++++++-- 8 files changed, 204 insertions(+), 106 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 65d843efc..11fa702da 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -57,11 +57,11 @@ export class PostMessageLoader implements Loader { timeout: NodeJS.Timeout | null = null; /** Reference to the get fn's Promise's reject call - used when cancelling. */ - rejectFn: ((reason?: any) => void) | null = null; + rejectFn: ((reason?: string) => void) | null = null; get(options: GetAgentParams): Promise { Logger.debug(`PostMessageLoader.get(): Initiating search for Desktop Agent Proxy`); - return new Promise(async (resolve, reject) => { + return new Promise((resolve, reject) => { //save reject fn in case we get cancelled this.rejectFn = reject; @@ -100,52 +100,53 @@ export class PostMessageLoader implements Loader { // and an adaptor iframe setup to load it, resolves on // WCP3Handshake response. // If no WCP3Handshake is ever received this will not resolve - const connectionDetails = await handshakePromise; + handshakePromise.then((connectionDetails) => { + //prevent us being cancelled + this.rejectFn = null; - //prevent us being cancelled - this.rejectFn = null; + //cancel the initial timeout as we got a handshake response + if (this.timeout) { + clearTimeout(this.timeout); + } - //cancel the initial timeout as we got a handshake response - if (this.timeout) { - clearTimeout(this.timeout); - } + //perform id validation + this.identityValidationHandler = new IdentityValidationHandler(connectionDetails.messagePort, options, this.connectionAttemptUuid) + const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + this.identityValidationHandler.sendIdValidationMessage(); + + idValidationPromise.then((idDetails) => { - //perform id validation - this.identityValidationHandler = new IdentityValidationHandler(connectionDetails.messagePort, options, this.connectionAttemptUuid) - const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); - this.identityValidationHandler.sendIdValidationMessage(); - - try { - const idDetails = await idValidationPromise; - - //resolve - const appIdentifier: AppIdentifier = { - appId: idDetails.payload.appId, - instanceId: idDetails.payload.instanceId - }; - - const desktopAgentSelection: DesktopAgentSelection = { - agent: await createDesktopAgentAPI(connectionDetails, appIdentifier), - details: { - agentType: connectionDetails.agentType, - agentUrl: connectionDetails.agentUrl ?? undefined, - identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, - actualUrl: connectionDetails.actualUrl, + //resolve + const appIdentifier: AppIdentifier = { appId: idDetails.payload.appId, - instanceId: idDetails.payload.instanceId, - instanceUuid: idDetails.payload.instanceUuid - }, - }; - - //clean up - this.cancel(); - - resolve(desktopAgentSelection); - } catch (e) { - //id validation may have failed - Logger.error("PostMessageLoader.get(): Id validation failed!",e); - reject(e); - } + instanceId: idDetails.payload.instanceId + }; + + createDesktopAgentAPI(connectionDetails, appIdentifier).then((da) => { + const desktopAgentSelection: DesktopAgentSelection = { + agent: da, + details: { + agentType: connectionDetails.agentType, + agentUrl: connectionDetails.agentUrl ?? undefined, + identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, + actualUrl: connectionDetails.actualUrl, + appId: idDetails.payload.appId, + instanceId: idDetails.payload.instanceId, + instanceUuid: idDetails.payload.instanceUuid + }, + }; + + //clean up + this.cancel(); + + resolve(desktopAgentSelection); + }); + }).catch((e) => { + //id validation may have failed + Logger.error("PostMessageLoader.get(): Id validation failed!",e); + reject(e); + }); + }); }); } diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index 1dff69b2b..fcad6d427 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -4,7 +4,7 @@ Feature: Different Strategies for Accessing the Desktop Agent Given a parent window document in "parentDoc", window in "parentWin", child window document in "childDoc" and window in "childWin" # And Testing ends after "8000" ms - Scenario: Running inside a Browser and using post message with direct message ports + Scenario: Running inside a Browser and using post message with direct message ports and no identityUrl Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And we wait for a period of "200" ms And I call getAgent for a promise result with the following options @@ -30,6 +30,39 @@ Feature: Different Strategies for Accessing the Desktop Agent Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" + Scenario: Connecting with a specified identityUrl + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And we wait for a period of "200" ms + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | identityUrl | timeoutMs | intentResolver | channelSelector | + | true | https://dummyOrigin.test/alternativePath | 8000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | appMetadata.instanceId | provider | + | 2.0 | cucumber-alternative-app | cucumber-alternative-instance | cucumber-provider | + And "{childWin.events}" is an array of objects with the following contents + | type | data.type | + | message | WCP3Handshake | + And "{parentWin.events}" is an array of objects with the following contents + | type | data.type | + | message | WCP1Hello | + Then I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" + And I call "{desktopAgent}" with "disconnect" + + Scenario: Connecting with a unknown identityUrl fails + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And we wait for a period of "200" ms + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | identityUrl | timeoutMs | intentResolver | channelSelector | + | true | "https://bad.identity.com/path" | 4000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And "{result}" is an error with message "AccessDenied" + Scenario: Running inside a Browser using the embedded iframe strategy Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns iframe response And we wait for a period of "200" ms @@ -131,7 +164,6 @@ Feature: Different Strategies for Accessing the Desktop Agent | 2.0 | cucumber-app | cucumber-provider | Then I call "{parentDoc}" with "shutdown" Then I call "{childDoc}" with "shutdown" - And I call "{desktopAgent}" with "disconnect" # Scenario: Failed Recovery from SessionState @@ -179,4 +211,4 @@ Feature: Different Strategies for Accessing the Desktop Agent And "{desktopAgent1}" is "{desktopAgent2}" Then I call "{parentDoc}" with "shutdown" Then I call "{childDoc}" with "shutdown" - And I call "{desktopAgent}" with "disconnect" + And I call "{desktopAgent1}" with "disconnect" diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index c75868bdf..e5d98143d 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -10,11 +10,12 @@ import { GetAgentParams, WebDesktopAgentType, } from '@kite9/fdc3-standard'; -import { dummyInstanceId, EMBED_URL, MockFDC3Server } from '../support/MockFDC3Server'; +import { EMBED_URL, MockFDC3Server } from '../support/MockFDC3Server'; import { MockStorage } from '../support/MockStorage'; import { DesktopAgent, ImplementationMetadata } from '@kite9/fdc3-standard'; import { clearAgentPromise } from '../../src/strategies/getAgent'; import expect from 'expect'; +import { dummyInstanceDetails } from '../support/TestServerContext'; interface MockPageTransitionEvent extends Event { persisted?: boolean; @@ -25,9 +26,10 @@ Given( 'Parent Window desktop {string} listens for postMessage events in {string}, returns direct message response', async function (this: CustomWorld, field: string, w: string) { const mockWindow = handleResolve(w, this); - this.mockFDC3Server = new MockFDC3Server(mockWindow as any, false, this.mockContext); + this.mockFDC3Server = new MockFDC3Server(mockWindow, false, this.mockContext); this.props[field] = this.mockFDC3Server; - this.mockContext.open(dummyInstanceId.appId); + this.mockContext.open(dummyInstanceDetails[0].appId); + this.mockContext.open(dummyInstanceDetails[1].appId); } ); @@ -35,9 +37,10 @@ Given( 'Parent Window desktop {string} listens for postMessage events in {string}, returns iframe response', async function (this: CustomWorld, field: string, w: string) { const mockWindow = handleResolve(w, this); - this.mockFDC3Server = new MockFDC3Server(mockWindow as any, true, this.mockContext); + this.mockFDC3Server = new MockFDC3Server(mockWindow, true, this.mockContext); this.props[field] = this.mockFDC3Server; - this.mockContext.open(dummyInstanceId.appId); + this.mockContext.open(dummyInstanceDetails[0].appId); + this.mockContext.open(dummyInstanceDetails[1].appId); } ); @@ -45,9 +48,9 @@ Given( '{string} is a function which opens an iframe for communications on {string}', function (this: CustomWorld, fn: string, doc: string) { this.props[fn] = () => { - this.mockContext.open(dummyInstanceId.appId); + this.mockContext.open(dummyInstanceDetails[0].appId); const document = handleResolve(doc, this) as MockDocument; - let ifrm = document.createElement('iframe'); + const ifrm = document.createElement('iframe'); this.mockFDC3Server = new MockFDC3Server(ifrm as any, false, this.mockContext); ifrm.setAttribute('src', EMBED_URL + '?connectionAttemptUuid=124'); document.body.appendChild(ifrm); @@ -57,22 +60,47 @@ Given( ); Given('an existing app instance in {string}', async function (this: CustomWorld, field: string) { - const uuid = this.mockContext.open(dummyInstanceId.appId); + const uuid = this.mockContext.open(dummyInstanceDetails[0].appId); this.props[field] = uuid; }); Given('A Dummy Desktop Agent in {string}', async function (this: CustomWorld, field: string) { + const notImplemented = () => { throw new Error('Function not implemented.'); }; const da: DesktopAgent = { async getInfo(): Promise { return { fdc3Version: '2.0', + optionalFeatures: { + "DesktopAgentBridging": false, + "OriginatingAppMetadata": false, + "UserChannelMembershipAPIs": false + }, appMetadata: { appId: 'cucumber-app', }, provider: 'cucumber-provider', - } as any; + }; }, - } as any; + open: notImplemented, + findIntent: notImplemented, + findIntentsByContext: notImplemented, + findInstances: notImplemented, + broadcast: notImplemented, + raiseIntent: notImplemented, + raiseIntentForContext: notImplemented, + addIntentListener: notImplemented, + addContextListener: notImplemented, + addEventListener: notImplemented, + getUserChannels: notImplemented, + joinUserChannel: notImplemented, + getOrCreateChannel: notImplemented, + createPrivateChannel: notImplemented, + getCurrentChannel: notImplemented, + leaveCurrentChannel: notImplemented, + getAppMetadata: notImplemented, + getSystemChannels: notImplemented, + joinChannel: notImplemented + }; this.props[field] = da; this.props['result'] = null; @@ -134,10 +162,10 @@ Given( async function (this: CustomWorld, pd: string, pw: string, cd: string, cw: string) { //create the parent window const mpw = new MockWindow('mockParentWindow', this, 'parentWin'); - this.props[pw] = mpw as any; + this.props[pw] = mpw; // mock parent window document - this.props[pd] = new MockDocument('parentDoc', mpw) as any; + this.props[pd] = new MockDocument('parentDoc', mpw); // creates the mock app window const mcw = new MockWindow('mockWindow', this, 'mocky'); @@ -157,7 +185,7 @@ Given( mpw.child = mcw; // session storage (will be common between windows, which is ok as DA doesn't use this) - globalThis.sessionStorage = new MockStorage() as any; + globalThis.sessionStorage = new MockStorage(); } ); diff --git a/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts b/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts index 9c1e63144..368fa5f53 100644 --- a/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/intent-resolver.steps.ts @@ -2,10 +2,11 @@ import { Given, When } from '@cucumber/cucumber'; import { CustomWorld } from '../world'; import { handleResolve } from '@kite9/testing'; import { DefaultDesktopAgentIntentResolver } from '../../src/ui/DefaultDesktopAgentIntentResolver'; -import { INTENT_RESPOLVER_URL } from '../support/MockFDC3Server'; +import { INTENT_RESOLVER_URL } from '../support/MockFDC3Server'; import { FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE } from '@kite9/fdc3-schema/dist/generated/api/BrowserTypes'; +import { Context } from '@kite9/fdc3-context'; -const contextMap: Record = { +const contextMap: Record = { 'fdc3.instrument': { type: 'fdc3.instrument', name: 'Apple', @@ -32,7 +33,7 @@ Given('{string} is a {string} context', function (this: CustomWorld, field: stri }); Given('An Intent Resolver in {string}', async function (this: CustomWorld, field: string) { - const cs = new DefaultDesktopAgentIntentResolver(INTENT_RESPOLVER_URL); + const cs = new DefaultDesktopAgentIntentResolver(INTENT_RESOLVER_URL); this.props[field] = cs; await cs.connect(); }); diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index 343d82b3e..7a108cba3 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -14,8 +14,6 @@ type AppRequestMessage = BrowserTypes.AppRequestMessage type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake -export const dummyInstanceId = { appId: "Test App Id", instanceId: "1" } - export const EMBED_URL = "http://localhost:8080/static/da/embed.html" export const CHANNEL_SELECTOR_URL = "https://mock.fdc3.com/channelSelector" diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index ed8f96f59..33fbd2d95 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -17,6 +17,11 @@ type MessageRecord = { msg: object; }; +export const dummyInstanceDetails = [ + { appId: 'Test App Id', url: 'https://dummyOrigin.test/path' }, + { appId: 'Test App Id 2', url: 'https://dummyOrigin.test/alternativePath' }, +]; + export class TestServerContext implements ServerContext { public postedMessages: MessageRecord[] = []; public readonly cw: CustomWorld; @@ -28,7 +33,7 @@ export class TestServerContext implements ServerContext { this.cw = cw; } - async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[]/*, _context: Context*/): Promise { + async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[] /*, _context: Context*/): Promise { return appIntents; } @@ -46,12 +51,12 @@ export class TestServerContext implements ServerContext { getMatchingInstance(url: string): ConnectionDetails | undefined { const details = this.instances.find(ca => ca.url === url); - if (!details) { - console.error(`No connection instance found for ${url}, known instances: `, this.instances); + const knownInstances = this.instances.map(inst => { return {appId: inst.appId, url: inst.url} }); + console.error(`No connection instance found for ${url} - will return a mismatched instance, known instances: `, knownInstances); + return this.instances[0]; } - - return; + return details; } async shutdown(): Promise { @@ -59,37 +64,44 @@ export class TestServerContext implements ServerContext { await Promise.all(this.instances.map(i => i.externalPort.close())); } + /** Used to mock connections to the server from apps. Must be called before the app attempts to connect for that connection to succeed. */ async open(appId: string): Promise { - const ni = this.nextInstanceId++; - if (appId.includes('missing')) { + const url = dummyInstanceDetails.find(value => value.appId === appId)?.url; + if (!url) { + console.error('TestServerContext Tried to open an unknown appId'); throw new Error(OpenError.AppNotFound); } else { - const mc = new MessageChannel(); - const internalPort = mc.port1; - const externalPort = mc.port2; - - // internalPort.name = 'internalPort-' + ni; - // externalPort.name = 'externalPort-' + ni; - - internalPort.start(); - - const connectionDetails = { - appId, - instanceId: 'uuid-' + ni, - connected: false, - connectionId: 'uuid-' + ni, - externalPort, - internalPort, - url: 'https://dummyOrigin.test/path', - state: State.Pending, - }; - - this.instances.push(connectionDetails); - internalPort.onmessage = msg => { - this.cw.mockFDC3Server?.receive(msg.data, connectionDetails.instanceId); - }; - - return connectionDetails.connectionId; + const ni = this.nextInstanceId++; + if (appId.includes('missing')) { + throw new Error(OpenError.AppNotFound); + } else { + const mc = new MessageChannel(); + const internalPort = mc.port1; + const externalPort = mc.port2; + + // internalPort.name = 'internalPort-' + ni; + // externalPort.name = 'externalPort-' + ni; + + internalPort.start(); + + const connectionDetails = { + appId, + instanceId: 'uuid-' + ni, + connected: false, + connectionId: 'uuid-' + ni, + externalPort, + internalPort, + url: url, + state: State.Pending, + }; + + this.instances.push(connectionDetails); + internalPort.onmessage = msg => { + this.cw.mockFDC3Server?.receive(msg.data, connectionDetails.instanceId); + }; + + return connectionDetails.connectionId; + } } } diff --git a/packages/fdc3-get-agent/test/support/responses/GetInfo.ts b/packages/fdc3-get-agent/test/support/responses/GetInfo.ts index 810dd2c5a..37b3b61db 100644 --- a/packages/fdc3-get-agent/test/support/responses/GetInfo.ts +++ b/packages/fdc3-get-agent/test/support/responses/GetInfo.ts @@ -24,7 +24,7 @@ export class GetInfo implements AutomaticResponse { type: "getInfoResponse", payload: { implementationMetadata: { - appMetadata: {appId: "cucumber-app", instanceId: "cucumber-instance"}, + appMetadata: i.meta.source!,//{appId: "cucumber-app", instanceId: "cucumber-instance"}, provider: "cucumber-provider", providerVersion: "test", fdc3Version: "2.0", diff --git a/packages/fdc3-get-agent/test/support/responses/Handshake.ts b/packages/fdc3-get-agent/test/support/responses/Handshake.ts index e2550fe73..799e4baa8 100644 --- a/packages/fdc3-get-agent/test/support/responses/Handshake.ts +++ b/packages/fdc3-get-agent/test/support/responses/Handshake.ts @@ -4,6 +4,8 @@ import { AutomaticResponse } from "./AutomaticResponses"; import { WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse } from "@kite9/fdc3-schema/generated/api/BrowserTypes"; export const BAD_INSTANCE_ID = "BAD_INSTANCE" +export const EXPECTED_IDENTITY_URL = "https://dummyOrigin.test/path"; +export const ALTERNATIVE_IDENTITY_URL = "https://dummyOrigin.test/alternativePath"; export class Handshake implements AutomaticResponse { @@ -21,6 +23,8 @@ export class Handshake implements AutomaticResponse { private createResponse(i: WebConnectionProtocol4ValidateAppIdentity): WebConnectionProtocol5ValidateAppIdentitySuccessResponse | WebConnectionProtocol5ValidateAppIdentityFailedResponse { + + const identityURL = i.payload.identityUrl ?? i.payload.actualUrl; if (i.payload.instanceUuid == BAD_INSTANCE_ID) { const msg: WebConnectionProtocol5ValidateAppIdentityFailedResponse = { meta: { @@ -33,7 +37,17 @@ export class Handshake implements AutomaticResponse { } }; return msg; - } else { + } else if (identityURL == EXPECTED_IDENTITY_URL || identityURL == ALTERNATIVE_IDENTITY_URL) { + let appId = "cucumber-app"; + let instanceId = "cucumber-instance"; + let instanceUuid = "some-instance-uuid"; + + if (identityURL == ALTERNATIVE_IDENTITY_URL) { + appId = "cucumber-alternative-app"; + instanceId = "cucumber-alternative-instance"; + instanceUuid = "some-alternative-instance-uuid"; + } + const msg: WebConnectionProtocol5ValidateAppIdentitySuccessResponse = { meta: { connectionAttemptUuid: i.meta.connectionAttemptUuid, @@ -43,8 +57,8 @@ export class Handshake implements AutomaticResponse { payload: { implementationMetadata: { appMetadata: { - appId: "cucumber-app", - instanceId: "cucumber-instance", + appId: appId, + instanceId: instanceId, }, fdc3Version: "2.0", optionalFeatures: { @@ -55,12 +69,24 @@ export class Handshake implements AutomaticResponse { provider: "cucumber-provider", providerVersion: "test" }, - appId: 'cucumber-app', - instanceId: 'cucumber-instance', - instanceUuid: 'some-instance-uuid', + appId: appId, + instanceId: instanceId, + instanceUuid: instanceUuid, + } + }; + return msg; + } else { + const msg: WebConnectionProtocol5ValidateAppIdentityFailedResponse = { + meta: { + connectionAttemptUuid: i.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + type: "WCP5ValidateAppIdentityFailedResponse", + payload: { + message: "Unknown identity URL" } }; return msg; - } + } } } \ No newline at end of file From de836923fa8eda9eaf690039058b2f3398f07f19 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 9 Dec 2024 14:50:40 +0000 Subject: [PATCH 34/90] fdc3-get-agent tests coverage --- package-lock.json | 41 +++- .../src/messaging/AbstractMessaging.ts | 2 +- packages/fdc3-get-agent/package.json | 1 + .../src/messaging/MessagePortMessaging.ts | 11 +- .../src/sessionStorage/DesktopAgentDetails.ts | 69 +++--- .../strategies/DesktopAgentPreloadLoader.ts | 39 +-- .../src/strategies/HelloHandler.ts | 10 +- .../strategies/IdentityValidationHandler.ts | 3 +- .../fdc3-get-agent/src/strategies/Loader.ts | 2 +- .../src/strategies/PostMessageLoader.ts | 2 +- .../fdc3-get-agent/src/strategies/getAgent.ts | 12 +- .../ui/DefaultDesktopAgentChannelSelector.ts | 1 + .../ui/DefaultDesktopAgentIntentResolver.ts | 3 +- packages/fdc3-get-agent/src/util/Logger.ts | 35 ++- packages/fdc3-get-agent/src/util/Uuid.ts | 5 + .../features/desktop-agent-strategy.feature | 178 +++++++++++--- .../test/features/utils.feature | 8 + .../step-definitions/desktop-agent.steps.ts | 87 ++++++- .../step-definitions/port-creation.steps.ts | 4 +- .../test/step-definitions/util.steps.ts | 22 ++ .../test/support/MockDocument.ts | 16 +- .../test/support/MockFDC3Server.ts | 223 +++++++++--------- .../fdc3-get-agent/test/support/MockWindow.ts | 8 +- .../test/support/responses/CurrentChannel.ts | 2 +- .../test/support/responses/Handshake.ts | 19 +- .../fdc3-for-web/demo/src/client/da/embed.ts | 6 +- 26 files changed, 568 insertions(+), 241 deletions(-) create mode 100644 packages/fdc3-get-agent/src/util/Uuid.ts create mode 100644 packages/fdc3-get-agent/test/features/utils.feature create mode 100644 packages/fdc3-get-agent/test/step-definitions/util.steps.ts diff --git a/package-lock.json b/package-lock.json index 08986ebd8..b4e4681e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7748,8 +7748,8 @@ } }, "node_modules/express": { - "version": "4.21.1", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -7770,7 +7770,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -7785,6 +7785,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -12005,8 +12009,8 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/path-type": { "version": "5.0.0", @@ -16713,6 +16717,7 @@ "@kite9/fdc3-schema": "2.2.0-beta.29", "@kite9/fdc3-standard": "2.2.0-beta.29", "@types/uuid": "^10.0.0", + "picocolors": "^1.1.1", "uuid": "^9.0.1" }, "devDependencies": { @@ -16854,6 +16859,21 @@ "url": "https://opencollective.com/eslint" } }, + "packages/fdc3-get-agent/node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "packages/fdc3-get-agent/node_modules/file-entry-cache": { "version": "8.0.0", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", @@ -16950,6 +16970,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/fdc3-get-agent/node_modules/supports-color": { + "version": "7.2.0", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "packages/fdc3-schema": { "name": "@kite9/fdc3-schema", "version": "2.2.0-beta.29", diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index 287bfd0de..a9e5cd628 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -47,7 +47,7 @@ export abstract class AbstractMessaging implements Messaging { setTimeout(() => { this.unregister(id); if (!done) { - console.error(`waitFor rejecting after ${this.getTimeoutMs()}ms with ${timeoutErrorMessage}`); + console.error(`waitFor rejecting after ${this.getTimeoutMs()}ms at ${new Date().toISOString()} with ${timeoutErrorMessage}`); reject(new Error(timeoutErrorMessage)); } }, this.getTimeoutMs()); diff --git a/packages/fdc3-get-agent/package.json b/packages/fdc3-get-agent/package.json index 495b5c65c..8e574ce5f 100644 --- a/packages/fdc3-get-agent/package.json +++ b/packages/fdc3-get-agent/package.json @@ -28,6 +28,7 @@ "@kite9/fdc3-schema": "2.2.0-beta.29", "@kite9/fdc3-standard": "2.2.0-beta.29", "@types/uuid": "^10.0.0", + "picocolors": "^1.1.1", "uuid": "^9.0.1" }, "devDependencies": { diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 8702bb182..6fc1f29d4 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -18,16 +18,23 @@ export type ConnectionDetails = { agentUrl?: string, } -const DEFAULT_TIMEOUT = 10016; +const MESSAGE_EXCHANGE_TIMEOUT = 10016; export class MessagePortMessaging extends AbstractMessaging { private readonly cd: ConnectionDetails private readonly listeners: Map = new Map() + private messageExchangeTimeout: number; + constructor(cd: ConnectionDetails, appIdentifier: AppIdentifier) { super(appIdentifier); this.cd = cd; + /** We do not use the timeout specified as an argument to getAgent as + * that is for connection messaging, rather than message exchanges + * post-connection. */ + this.messageExchangeTimeout = MESSAGE_EXCHANGE_TIMEOUT; + this.cd.messagePort.onmessage = (m) => { this.listeners.forEach((v) => { if (v.filter(m.data)) { @@ -63,7 +70,7 @@ export class MessagePortMessaging extends AbstractMessaging { } getTimeoutMs(): number { - return this.cd.options.timeoutMs ?? DEFAULT_TIMEOUT; + return this.messageExchangeTimeout; } async disconnect(): Promise { diff --git a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts index 5b865e499..b8b1f056c 100644 --- a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts +++ b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts @@ -1,13 +1,6 @@ -import { - DesktopAgentDetails, - DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX, -} from '@kite9/fdc3-standard'; -import { v4 as uuidv4 } from 'uuid'; +import { DesktopAgentDetails, DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX } from '@kite9/fdc3-standard'; import { Logger } from '../util/Logger'; - -export function createUUID(): string { - return uuidv4(); -} +import { createUUID } from '../util/Uuid'; /** * Note that we also key by the window name as well, in case multiple iframes are using the same session storage. @@ -25,15 +18,15 @@ export function sessionKey(): string { /** Used to persist data on the connection, which can later be used to ensure * reconnection to the same Desktop Agent and to request the same instanceId. */ -export function storeDesktopAgentDetails(details: DesktopAgentDetails){ +export function storeDesktopAgentDetails(details: DesktopAgentDetails) { Logger.debug(`DesktopAgentDetails: Storing Desktop Agent details:`, details); - //check if there are existing details in storage to update - let detailsToStore = retrieveAllDesktopAgentDetails(); - if (!detailsToStore) { - detailsToStore = {}; - } - detailsToStore[details.identityUrl] = details; - globalThis.sessionStorage.setItem(sessionKey(), JSON.stringify(detailsToStore)); + //check if there are existing details in storage to update + let detailsToStore = retrieveAllDesktopAgentDetails(); + if (!detailsToStore) { + detailsToStore = {}; + } + detailsToStore[details.identityUrl] = details; + globalThis.sessionStorage.setItem(sessionKey(), JSON.stringify(detailsToStore)); } /** Retrieves persisted data about previous connections. Used to ensure reconnection @@ -44,9 +37,19 @@ export function retrieveAllDesktopAgentDetails(): Record; + const theData: Record = JSON.parse(detailsStr) as Record< + string, + DesktopAgentDetails + >; + if (typeof theData !== 'object' || Array.isArray(theData)) { + throw new Error('Stored DesktopAgentDetails is not in the expected format!'); + } + return theData; } catch (e) { - Logger.error(`DesktopAgentDetails: FDC3 connection data couldn't be parsed\nstorage key: ${sessionKey()}\nvalue: ${detailsStr}`); + Logger.error( + `DesktopAgentDetails: FDC3 connection data couldn't be parsed\nstorage key: ${sessionKey()}\nvalue: ${detailsStr}`, + e + ); return null; } } else { @@ -55,16 +58,28 @@ export function retrieveAllDesktopAgentDetails(): Record void) | null = null; + /** Variable used to end polling */ + done: boolean = false; /** Overall timeout */ timeout: NodeJS.Timeout | null = null; + /** Timeout used in polling */ + pollingTimeout: NodeJS.Timeout | null = null; /** Reference to the get fn's Promise's reject call - used when cancelling. */ rejectFn: ((reason?: string) => void) | null = null; async poll(resolve: (value: DesktopAgentSelection) => void) { - if (globalThis.window.fdc3) { - Logger.debug(`DesktopAgentPreloadLoader.get(): Discovered DA through polling...`); - this.prepareSelection(globalThis.window.fdc3, resolve); - } else { - if (!this.done) { - setTimeout(() => this.poll(resolve), 100); + if (!this.done) { + if (globalThis.window.fdc3) { + Logger.debug(`DesktopAgentPreloadLoader.get(): Discovered DA through polling...`); + this.prepareSelection(globalThis.window.fdc3, resolve); + } else { + this.pollingTimeout = setTimeout(() => this.poll(resolve), 100); } } } async prepareSelection(fdc3: DesktopAgent, resolve: (value: DesktopAgentSelection) => void) { + Logger.debug("DesktopAgentPreloadLoader: Preparing selection") + //note that we've found an agent and will be settling our get promise this.rejectFn = null; - //stop polling and listening for fdc3Ready this.cancel(); @@ -53,10 +56,6 @@ export class DesktopAgentPreloadLoader implements Loader { } }; - if (selection.details.instanceId === "unknown"){ - Logger.warn("The DesktopAgent did not return an instanceId in the app's metadata", implMetadata); - } - resolve(selection); } @@ -75,6 +74,7 @@ export class DesktopAgentPreloadLoader implements Loader { this.timeout = setTimeout(() => { Logger.debug(`DesktopAgentPreloadLoader.get(): timeout (${timeoutMs} ms) at ${new Date().toISOString()}`); reject(AgentError.AgentNotFound); + this.cancel(); }, timeoutMs); //listen for the fdc3Ready event @@ -92,19 +92,22 @@ export class DesktopAgentPreloadLoader implements Loader { }); } - cancel(): void { + async cancel(): Promise { Logger.debug("DesktopAgentPreloadLoader: Cleaning up"); this.done = true; - if (this.rejectFn){ - this.rejectFn(AgentError.AgentNotFound); - this.rejectFn = null; - } if (this.timeout) { clearTimeout(this.timeout); } + if(this.pollingTimeout){ + clearTimeout(this.pollingTimeout); + } if (this.readyEventHandler) { globalThis.window.removeEventListener('fdc3Ready', this.readyEventHandler); } + if (this.rejectFn){ + this.rejectFn(AgentError.AgentNotFound); + this.rejectFn = null; + } } } diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index 4e1665a18..b9d6c8e61 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -52,7 +52,7 @@ export class HelloHandler { channelSelector: this.options.channelSelector, fdc3Version: FDC3_VERSION, resolver: this.options.intentResolver, - identityUrl: this.options.identityUrl!!, + identityUrl: this.options.identityUrl!, actualUrl: globalThis.window.location.href, }, }; @@ -75,7 +75,7 @@ export class HelloHandler { } // create a new one - var ifrm = document.createElement('iframe'); + const ifrm = document.createElement('iframe'); ifrm.setAttribute('src', url); ifrm.setAttribute('id', IFRAME_ID); ifrm.setAttribute('name', 'FDC3 Communications'); @@ -85,7 +85,7 @@ export class HelloHandler { ifrm.style.position = 'fixed'; //Wait for the iframe to load... then send it a hello message - ifrm.onload = _event => { + ifrm.onload = () => { if (ifrm.contentWindow) { this.sendWCP1Hello(ifrm.contentWindow, '*'); } else { @@ -101,7 +101,7 @@ export class HelloHandler { */ listenForHelloResponses(): Promise { - return new Promise((resolve, _reject) => { + return new Promise((resolve, ) => { // setup listener for message and retrieve JS URL from it this.helloResponseListener = (event: MessageEvent) => { @@ -141,7 +141,7 @@ export class HelloHandler { } } else { Logger.warn( - `Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, + `HelloHandler: Ignoring message with invalid connectionAttemptUuid. Expected ${this.connectionAttemptUuid}, received: ${data?.meta?.connectionAttemptUuid}`, data ); } diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts index d794ca08e..531ded48a 100644 --- a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -12,7 +12,7 @@ import { Logger } from '../util/Logger'; /** Timeout allowed for id validation to occur and for the DA to respond with details. * This is additional to the app's specified timeout for discovery - we have already * found an agent at that point we are just finishing setting up the connection. */ -const ID_VALIDATION_TIMEOUT = 3000; +const ID_VALIDATION_TIMEOUT = 5000; export class IdentityValidationHandler { constructor(mp: MessagePort, options: GetAgentParams, connectionAttemptUuid: string) { @@ -134,5 +134,6 @@ export class IdentityValidationHandler { if (this.idValidationResponseListener) { this.messagePort.removeEventListener('message', this.idValidationResponseListener); } + //TODO: cancel any timeouts and reject any returned promises } } diff --git a/packages/fdc3-get-agent/src/strategies/Loader.ts b/packages/fdc3-get-agent/src/strategies/Loader.ts index 731d34ea7..51dd81e77 100644 --- a/packages/fdc3-get-agent/src/strategies/Loader.ts +++ b/packages/fdc3-get-agent/src/strategies/Loader.ts @@ -10,7 +10,7 @@ export interface Loader { */ get(options: GetAgentParams): Promise; - cancel(): void; + cancel(): Promise; name: string; } diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 11fa702da..d7072c2b5 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -150,7 +150,7 @@ export class PostMessageLoader implements Loader { }); } - cancel(): void { + async cancel(): Promise { Logger.debug("PostMessageLoader: Cleaning up"); //if we're being cancelled while still running, reject the promise diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 4227a88bb..cd831f8cb 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -66,12 +66,18 @@ function initAgentPromise(options: GetAgentParams): Promise { ]; } - const promises = strategies.map(s => s.get(options).then((selection) => { + const promises = strategies.map(s => s.get(options).then(async (selection) => { //cancel other strategies if we selected a DA Logger.log(`Strategy ${s.name} resolved - cleaning up other strategies`); - strategies.forEach(s2 => { + for (let s2 = 0; s2 < strategies.length; s2++) { + if(strategies[s2] !== s) { + Logger.debug(` cleaning up ${strategies[s2].name}`); + await strategies[s2].cancel(); + } + } + strategies.forEach(async s2 => { if(s2 !== s) { - s2.cancel(); + await s2.cancel(); } }); return selection; diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts index 82cdde160..a1555ad37 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts @@ -15,6 +15,7 @@ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent impl private callback: ((channelId: string | null) => void) | null = null constructor(url: string | null) { + //TODO: check default UI URL is correct on release super(url ?? "https://fdc3.finos.org/webui/channel_selector.html", "FDC3 Channel Selector") } diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts index a4f130642..393a6ed9f 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts @@ -15,6 +15,7 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple private pendingResolve: ((x: IntentResolutionChoice | void) => void) | null = null constructor(url: string | null) { + //TODO: check default UI URL is correct on release super(url ?? "https://fdc3.finos.org/webui/intent_resolver.html", "FDC3 Intent Resolver") } @@ -42,7 +43,7 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple } async chooseIntent(appIntents: AppIntent[], context: Context): Promise { - const out = new Promise((resolve, _reject) => { + const out = new Promise((resolve/*, _reject*/) => { this.pendingResolve = resolve }) const message: Fdc3UserInterfaceResolve = { diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 54957d29c..19f019b5f 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -1,22 +1,39 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import pc from 'picocolors'; + const GET_AGENT_LOG_PREFIX = "FDC3 getAgent: "; export class Logger { - constructor() {} - static debug(message?: any, ...optionalParams: any[]) { - console.debug(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + static debug(...params: any[]) { + if (typeof params[0] === "string") { + console.debug(pc.black(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + } else { + console.debug(pc.black(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + } } - static log(message?: any, ...optionalParams: any[]) { - console.log(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + static log(...params: any[]) { + if (typeof params[0] === "string") { + console.log(pc.green(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + } else { + console.log(pc.green(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + } } - static warn(message?: any, ...optionalParams: any[]) { - console.warn(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + static warn(...params: any[]) { + if (typeof params[0] === "string") { + console.warn(pc.yellow(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + } else { + console.warn(pc.yellow(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + } } - static error(message?: any, ...optionalParams: any[]) { - console.error(GET_AGENT_LOG_PREFIX + (message ?? ""), ...optionalParams); + static error(...params: any[]) { + if (typeof params[0] === "string") { + console.error(pc.red(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + } else { + console.error(pc.red(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + } } } diff --git a/packages/fdc3-get-agent/src/util/Uuid.ts b/packages/fdc3-get-agent/src/util/Uuid.ts new file mode 100644 index 000000000..5349d5748 --- /dev/null +++ b/packages/fdc3-get-agent/src/util/Uuid.ts @@ -0,0 +1,5 @@ +import { v4 as uuidv4 } from 'uuid'; + +export function createUUID(): string { + return uuidv4(); +} \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index fcad6d427..b15f915c6 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -2,7 +2,7 @@ Feature: Different Strategies for Accessing the Desktop Agent Background: Desktop Agent API Given a parent window document in "parentDoc", window in "parentWin", child window document in "childDoc" and window in "childWin" - # And Testing ends after "8000" ms + And SessionStorage is clear Scenario: Running inside a Browser and using post message with direct message ports and no identityUrl Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response @@ -26,8 +26,30 @@ Feature: Different Strategies for Accessing the Desktop Agent And "{parentWin.events}" is an array of objects with the following contents | type | data.type | | message | WCP1Hello | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" + And I call "{desktopAgent}" with "disconnect" + + Scenario: Running inside a Browser and using post message, direct message ports, no identityUrl and default UI URLs + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response and uses default UI URLs + And we wait for a period of "200" ms + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | + | true | 8000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | cucumber-provider | + And I refer to "{document.body.children[0]}" as "channel-selector" + And I refer to "{channel-selector.children[0]}" as "iframe" + And "{childWin.fdc3}" is undefined + And "{childWin.events}" is an array of objects with the following contents + | type | data.type | + | message | WCP3Handshake | + And "{parentWin.events}" is an array of objects with the following contents + | type | data.type | + | message | WCP1Hello | And I call "{desktopAgent}" with "disconnect" Scenario: Connecting with a specified identityUrl @@ -35,7 +57,7 @@ Feature: Different Strategies for Accessing the Desktop Agent And we wait for a period of "200" ms And I call getAgent for a promise result with the following options | dontSetWindowFdc3 | identityUrl | timeoutMs | intentResolver | channelSelector | - | true | https://dummyOrigin.test/alternativePath | 8000 | false | false | + | true | https://dummyOrigin.test/alternativePath | 8000 | false | false | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve And I refer to "{result}" as "desktopAgent" @@ -49,11 +71,9 @@ Feature: Different Strategies for Accessing the Desktop Agent And "{parentWin.events}" is an array of objects with the following contents | type | data.type | | message | WCP1Hello | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" - Scenario: Connecting with a unknown identityUrl fails + Scenario: Connecting with an unknown identityUrl fails Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And we wait for a period of "200" ms And I call getAgent for a promise result with the following options @@ -63,6 +83,16 @@ Feature: Different Strategies for Accessing the Desktop Agent Then the promise "{theAPIPromise}" should resolve And "{result}" is an error with message "AccessDenied" +Scenario: Connecting but identity validation times out + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response, but times out identity validation + And we wait for a period of "200" ms + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | + | true | 2000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And "{result}" is an error with message "ErrorOnConnect" + Scenario: Running inside a Browser using the embedded iframe strategy Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns iframe response And we wait for a period of "200" ms @@ -96,11 +126,9 @@ Feature: Different Strategies for Accessing the Desktop Agent | message | Fdc3UserInterfaceHello | | message | Fdc3UserInterfaceHello | | fdc3Ready | {null} | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent}" with "disconnect" - Scenario: Running inside an Electron Container. + Scenario: Desktop Agent Preload (injected after the getAgent call with no event) In this scenario, window.fdc3 is set by the electron container and returned by getAgent Given A Dummy Desktop Agent in "dummy-api" @@ -112,9 +140,34 @@ Feature: Different Strategies for Accessing the Desktop Agent And I call "{result}" with "getInfo" Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | - | 2.0 | cucumber-app | cucumber-provider | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" + | 2.0 | cucumber-app | preload-provider | + + Scenario: Desktop Agent Preload (arrived after getAgent call with fdc3Ready event) + In this scenario, window.fdc3 is set by the electron container and returned by getAgent + + Given A Dummy Desktop Agent in "dummy-api" + And I call fdc3Ready for a promise result + And I refer to "{result}" as "theAPIPromise" + And we wait for a period of "100" ms + And `window.fdc3` is injected into the runtime with the value in "{dummy-api}" and fdc3Ready is fired + Then the promise "{theAPIPromise}" should resolve + And I call "{result}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | preload-provider | + + Scenario: Desktop Agent preload (present before getAgent call) + In this scenario, window.fdc3 is set by the electron container and returned by getAgent + + Given A Dummy Desktop Agent in "dummy-api" + And `window.fdc3` is injected into the runtime with the value in "{dummy-api}" + And I call fdc3Ready for a promise result + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I call "{result}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | preload-provider | Scenario: Failover Strategy returning desktop agent Given A Dummy Desktop Agent in "dummy-api" @@ -127,9 +180,7 @@ Feature: Different Strategies for Accessing the Desktop Agent And I call "{result}" with "getInfo" Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | - | 2.0 | cucumber-app | cucumber-provider | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" + | 2.0 | cucumber-app | preload-provider | Scenario: Failover Strategy returning a proxy Given "dummyFailover2" is a function which opens an iframe for communications on "{childDoc}" @@ -138,33 +189,101 @@ Feature: Different Strategies for Accessing the Desktop Agent | {dummyFailover2} | 1000 | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve - And I call "{result}" with "getInfo" + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" + And I call "{desktopAgent}" with "disconnect" - Scenario: Recovery from SessionState + Scenario: Recover adaptor URL from SessionStorage Here, we recover the details of the session from the session state, obviating the need to make a request to the parent iframe. Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response And an existing app instance in "instanceID" - And the session identity is set to "{instanceID}" with identityUrl "https://dummyOrigin.test/path" + And SessionStorage contains instanceUuid "{instanceID}", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path" and agentType "PROXY_PARENT" And we wait for a period of "200" ms And I call getAgent for a promise result with the following options | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | - | true | 8000 | false | false | + | true | 8000 | false | false | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve - And I call "{result}" with "getInfo" + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" + And I call "{desktopAgent}" with "disconnect" + Scenario: Handle corrupted data in SessionStorage + Here we deal with data in SessionStorage that is not in the proper format. + + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And an existing app instance in "instanceID" + And SessionStorage contains corrupted data + And we wait for a period of "200" ms + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | + | true | 8000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | cucumber-provider | + And I call "{desktopAgent}" with "disconnect" + + Scenario: Handle truncated data in SessionStorage + Here we deal with data in SessionStorage that is only partially complete. + + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And an existing app instance in "instanceID" + And SessionStorage contains partial data with with identityUrl "https://dummyOrigin.test/path", appId "cucumber-app" and agentType "PROXY_PARENT" + And we wait for a period of "200" ms + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | + | true | 8000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | cucumber-provider | + And I call "{desktopAgent}" with "disconnect" + + Scenario: Latch to Desktop Agent Preload via SessionStorage + Here, we recover the details of the session from session storage, and latch to the + same Desktop Agent type (preload) - the connection should succeed. + + Given A Dummy Desktop Agent in "dummy-api" + And Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And SessionStorage contains instanceUuid "{instanceID}", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path" and agentType "PRELOAD" + And I call fdc3Ready for a promise result + And I refer to "{result}" as "theAPIPromise" + And we wait for a period of "500" ms + And `window.fdc3` is injected into the runtime with the value in "{dummy-api}" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | preload-provider | + +Scenario: Latch to Desktop Agent Preload via SessionStorage which has gone away + Here, we recover the details of the session from session storage, and latch to the + same Desktop Agent type (preload) - the connection should fail. + Given SessionStorage contains instanceUuid "{instanceID}", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path" and agentType "PRELOAD" + And Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And I call getAgent for a promise result with the following options + | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | + | true | 3000 | false | false | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And "{result}" is an error with message "AgentNotFound" + # Scenario: Failed Recovery from SessionState # App tries to recover with an ID that doesn't exist. @@ -188,7 +307,7 @@ Feature: Different Strategies for Accessing the Desktop Agent Scenario: Nothing works and we timeout When I call getAgent for a promise result with the following options | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | - | true | 1000 | false | false | + | true | 4000 | false | false | And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve And "{result}" is an error with message "AgentNotFound" @@ -209,6 +328,9 @@ Feature: Different Strategies for Accessing the Desktop Agent And the promise "{theAPIPromise2}" should resolve And I refer to "{result}" as "desktopAgent2" And "{desktopAgent1}" is "{desktopAgent2}" - Then I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" And I call "{desktopAgent1}" with "disconnect" + + Scenario: We dump any open handles + Given I call "{parentDoc}" with "shutdown" + Then I call "{childDoc}" with "shutdown" + Then Testing ends after "8000" ms diff --git a/packages/fdc3-get-agent/test/features/utils.feature b/packages/fdc3-get-agent/test/features/utils.feature new file mode 100644 index 000000000..e65525541 --- /dev/null +++ b/packages/fdc3-get-agent/test/features/utils.feature @@ -0,0 +1,8 @@ +Feature: Utility functions + +Scenario: Logger utility + When All log functions are used with a message + Then All log functions are used without a message + +Scenario: UUID generator + When A uuid is generated diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index e5d98143d..18ad84111 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -8,7 +8,6 @@ import { DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX, DesktopAgentDetails, GetAgentParams, - WebDesktopAgentType, } from '@kite9/fdc3-standard'; import { EMBED_URL, MockFDC3Server } from '../support/MockFDC3Server'; import { MockStorage } from '../support/MockStorage'; @@ -33,6 +32,28 @@ Given( } ); +Given( + 'Parent Window desktop {string} listens for postMessage events in {string}, returns direct message response, but times out identity validation', + async function (this: CustomWorld, field: string, w: string) { + const mockWindow = handleResolve(w, this); + this.mockFDC3Server = new MockFDC3Server(mockWindow, false, this.mockContext, true, true); + this.props[field] = this.mockFDC3Server; + this.mockContext.open(dummyInstanceDetails[0].appId); + this.mockContext.open(dummyInstanceDetails[1].appId); + } +); + +Given( + 'Parent Window desktop {string} listens for postMessage events in {string}, returns direct message response and uses default UI URLs', + async function (this: CustomWorld, field: string, w: string) { + const mockWindow = handleResolve(w, this); + this.mockFDC3Server = new MockFDC3Server(mockWindow, false, this.mockContext, true); + this.props[field] = this.mockFDC3Server; + this.mockContext.open(dummyInstanceDetails[0].appId); + this.mockContext.open(dummyInstanceDetails[1].appId); + } +); + Given( 'Parent Window desktop {string} listens for postMessage events in {string}, returns iframe response', async function (this: CustomWorld, field: string, w: string) { @@ -52,7 +73,7 @@ Given( const document = handleResolve(doc, this) as MockDocument; const ifrm = document.createElement('iframe'); this.mockFDC3Server = new MockFDC3Server(ifrm as any, false, this.mockContext); - ifrm.setAttribute('src', EMBED_URL + '?connectionAttemptUuid=124'); + ifrm.setAttribute('src', EMBED_URL); document.body.appendChild(ifrm); return ifrm; }; @@ -77,8 +98,9 @@ Given('A Dummy Desktop Agent in {string}', async function (this: CustomWorld, fi }, appMetadata: { appId: 'cucumber-app', + instanceId: 'uuid-0' }, - provider: 'cucumber-provider', + provider: 'preload-provider', }; }, open: notImplemented, @@ -111,7 +133,15 @@ Given( async function (this: CustomWorld, field: string) { const object = handleResolve(field, this); window.fdc3 = object; - window.dispatchEvent(new Event('fdc3.ready')); + } +); + +Given( + '`window.fdc3` is injected into the runtime with the value in {string} and fdc3Ready is fired', + async function (this: CustomWorld, field: string) { + const object = handleResolve(field, this); + window.fdc3 = object; + window.dispatchEvent(new Event('fdc3Ready')); } ); @@ -134,10 +164,7 @@ When('I call fdc3Ready for a promise result', function (this: CustomWorld) { After(function (this: CustomWorld) { console.log('Cleaning up'); clearAgentPromise(); - // setTimeout(() => { - // //console.log((process as any)._getActiveHandles()) - // wtf.dump() - // }, 10000) + MockDocument.shutdownAllDocuments(); }); When('I call getAgent for a promise result with the following options', function (this: CustomWorld, dt: DataTable) { @@ -190,15 +217,17 @@ Given( ); Given( - 'the session identity is set to {string} with identityUrl {string}', - async function (this: CustomWorld, uuid: string, identityUrl: string) { + 'SessionStorage contains instanceUuid {string}, appId {string} with identityUrl {string} and agentType {string}', + async function (this: CustomWorld, uuid: string, appId: string, identityUrl: string, agentType: string) { const theUuid = handleResolve(uuid, this); + const theAppId = handleResolve(appId, this); const theIdentityUrl = handleResolve(identityUrl, this); + const theAgentType = handleResolve(agentType, this); const details: Record = {}; details[theIdentityUrl] = { - agentType: WebDesktopAgentType.ProxyParent, + agentType: theAgentType, instanceUuid: theUuid, - appId: 'cucumber-app', + appId: theAppId, instanceId: 'uuid-0', identityUrl: theIdentityUrl, actualUrl: theIdentityUrl, @@ -208,6 +237,40 @@ Given( } ); +Given( + 'SessionStorage contains partial data with with identityUrl {string}, appId {string} and agentType {string}', + async function (this: CustomWorld, identityUrl: string, agentType: string, appId: string) { + const theIdentityUrl = handleResolve(identityUrl, this); + const theAgentType = handleResolve(agentType, this); + const theAppId = handleResolve(appId, this); + + const partialDetails: Record> = {}; + partialDetails[theIdentityUrl] = { + agentType: theAgentType, + appId: theAppId, + identityUrl: identityUrl + }; + + globalThis.sessionStorage.setItem(DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-mocky', JSON.stringify(partialDetails)); + } +); + +Given( + 'SessionStorage contains corrupted data', + async function (this: CustomWorld) { + const corruptedData = ["All your base are belong to us"]; + + globalThis.sessionStorage.setItem(DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-mocky', JSON.stringify(corruptedData)); + } +); + +Given( + 'SessionStorage is clear', + async function () { + globalThis.sessionStorage.clear(); + } +); + When( '{string} pagehide occurs with persisted = {string}', async function (this: CustomWorld, field: string, persisted: string) { diff --git a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts index a3fbf1659..64fbd5d6e 100644 --- a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts @@ -1,7 +1,7 @@ import { Given, Then } from '@cucumber/cucumber'; import { CustomWorld } from '../world'; import { handleResolve } from '@kite9/testing'; -var wtf = require('wtfnode'); +const wtf = require('wtfnode'); Given( '{string} receives a {string} message for the {string} and creates port {string}', @@ -20,7 +20,7 @@ Given( origin: globalThis.window.location.origin, ports: [externalPort], source: channelSelectorIframe, - } as any); + } as unknown as Event); } internalPort.start(); diff --git a/packages/fdc3-get-agent/test/step-definitions/util.steps.ts b/packages/fdc3-get-agent/test/step-definitions/util.steps.ts new file mode 100644 index 000000000..f631316bc --- /dev/null +++ b/packages/fdc3-get-agent/test/step-definitions/util.steps.ts @@ -0,0 +1,22 @@ +import { Given } from '@cucumber/cucumber'; +import { CustomWorld } from '../world'; +import { Logger } from '../../src/util/Logger'; +import { createUUID } from '../../src/util/Uuid'; + +Given('All log functions are used with a message', async function (this: CustomWorld) { + Logger.debug('Debug msg'); + Logger.log('Log msg'); + Logger.warn('Warning msg'); + Logger.error('Error msg'); + }); + + Given('All log functions are used without a message', async function (this: CustomWorld) { + Logger.debug(new Error("Test error")); + Logger.log(new Error("Test error")); + Logger.warn(new Error("Test error")); + Logger.error(new Error("Test error")); + }); + +Given('A uuid is generated', async function (this: CustomWorld) { + return createUUID(); +}); diff --git a/packages/fdc3-get-agent/test/support/MockDocument.ts b/packages/fdc3-get-agent/test/support/MockDocument.ts index 2a8618238..649ddc541 100644 --- a/packages/fdc3-get-agent/test/support/MockDocument.ts +++ b/packages/fdc3-get-agent/test/support/MockDocument.ts @@ -6,11 +6,13 @@ export class MockDocument { name: string; window: MockWindow; iframes: MockIFrame[] = []; + static allDocuments: MockDocument[] = []; constructor(name: string, window: MockWindow) { this.name = name; this.window = window; if (this.window.cw.debugLogs) { console.log(`MockDocument created with name: ${name} in window.name: ${this.window.name}`); } + MockDocument.allDocuments.push(this); } createElement(tag: string): HTMLElement { @@ -22,14 +24,14 @@ export class MockDocument { this.window.commsIframe = mw; this.iframes.push(mw); - return mw as any; + return mw as unknown as HTMLElement; } else { - return new MockElement(tag) as any; + return new MockElement(tag) as unknown as HTMLElement; } } - getElementById(_id: string): HTMLElement | null { - return new MockElement("div") as any; + getElementById(/*_id: string*/): HTMLElement | null { + return new MockElement("div") as unknown as HTMLElement; } body = new MockElement("body"); @@ -38,4 +40,10 @@ export class MockDocument { this.window.shutdown(); this.iframes.forEach(i => i.shutdown()); } + + static shutdownAllDocuments() { + MockDocument.allDocuments.forEach((doc: MockDocument) => { + doc.shutdown(); + }) + } } \ No newline at end of file diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index 7a108cba3..77dd504b5 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -1,111 +1,118 @@ -import { FDC3Server } from "@kite9/fdc3-web-impl" -import { TestServerContext } from "./TestServerContext" -import { MockWindow } from "./MockWindow" -import { AutomaticResponse } from "./responses/AutomaticResponses" -import { FindIntent } from "./responses/FindIntent" -import { RaiseIntent } from "./responses/RaiseIntent" -import { Handshake } from "./responses/Handshake" -import { UserChannels } from "./responses/UserChannels" -import { CurrentChannel } from "./responses/CurrentChannel" -import { BrowserTypes } from "@kite9/fdc3-schema" -import { GetInfo } from "./responses/GetInfo" - -type AppRequestMessage = BrowserTypes.AppRequestMessage -type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL -type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake - -export const EMBED_URL = "http://localhost:8080/static/da/embed.html" - -export const CHANNEL_SELECTOR_URL = "https://mock.fdc3.com/channelSelector" - -export const INTENT_RESOLVER_URL = "https://mock.fdc3.com/resolver" +import { FDC3Server } from '@kite9/fdc3-web-impl'; +import { TestServerContext } from './TestServerContext'; +import { MockWindow } from './MockWindow'; +import { AutomaticResponse } from './responses/AutomaticResponses'; +import { FindIntent } from './responses/FindIntent'; +import { RaiseIntent } from './responses/RaiseIntent'; +import { Handshake } from './responses/Handshake'; +import { UserChannels } from './responses/UserChannels'; +import { CurrentChannel } from './responses/CurrentChannel'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +import { GetInfo } from './responses/GetInfo'; + +type AppRequestMessage = BrowserTypes.AppRequestMessage; +type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL; +type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake; + +export const EMBED_URL = 'http://localhost:8080/static/da/embed.html'; + +export const CHANNEL_SELECTOR_URL = 'https://mock.fdc3.com/channelSelector'; +export const INTENT_RESOLVER_URL = 'https://mock.fdc3.com/resolver'; export class MockFDC3Server implements FDC3Server { - - private useIframe: boolean - private window: MockWindow - private tsc: TestServerContext - private receivedGoodbye = false; - - readonly automaticResponses: AutomaticResponse[] = [ - new FindIntent(), - new RaiseIntent(), - new Handshake(), - new UserChannels(), - new CurrentChannel(), - new GetInfo() - ] - - constructor(window: MockWindow, useIframe: boolean, ctx: TestServerContext) { - this.useIframe = useIframe - this.window = window - this.tsc = ctx - this.init() - } - - receive(message: AppRequestMessage, from: string): void { - this.automaticResponses.forEach((r) => { - if (r.filter(message.type)) { - r.action(message, this.tsc, from) - } - }) - } - - shutdown() { - this.tsc.shutdown() - } - - hasReceivedGoodbye(): boolean { - return this.receivedGoodbye; - } - - init() { - this.window.addEventListener( - "message", - (e) => { - const event = e as MessageEvent - const data = event.data; - const source = event.source as Window - const origin = event.origin; - - if (this.tsc.cw.debugLogs) { console.log("MockFDC3Server received: ", event.data); } - if (data.type == "WCP1Hello") { - if (this.useIframe) { - const message: WebConnectionProtocol2LoadURL = { - type: "WCP2LoadUrl", - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date() - }, - payload: { - iframeUrl: EMBED_URL + "?connectionAttemptUuid=" + data.meta.connectionAttemptUuid - } - }; - source.postMessage(message, origin); - } else { - const details = this.tsc.getMatchingInstance(data.payload.identityUrl) - if (details) { - const message: WebConnectionProtocol3Handshake = { - type: "WCP3Handshake", - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date() - }, - payload: { - fdc3Version: "2.2", - intentResolverUrl: INTENT_RESOLVER_URL, - channelSelectorUrl: CHANNEL_SELECTOR_URL, - } - }; - source.postMessage(message , origin, [details.externalPort]); - } //getMatchingInstance will log if it didn't find anything - } - } else if (data.type == "WCP6Goodbye") { - this.receivedGoodbye = true; - } - }); - } + private useIframe: boolean; + private useDefaultUIUrls: boolean; + private timeOutIdValidation: boolean; + private window: MockWindow; + private tsc: TestServerContext; + private receivedGoodbye = false; + + readonly automaticResponses: AutomaticResponse[]; + + constructor( + window: MockWindow, + useIframe: boolean, + ctx: TestServerContext, + useDefaultUIUrls: boolean = false, + timeOutIdValidation: boolean = false + ) { + this.useIframe = useIframe; + this.useDefaultUIUrls = useDefaultUIUrls; + this.timeOutIdValidation = timeOutIdValidation; + this.window = window; + this.tsc = ctx; + + this.automaticResponses = [ + new FindIntent(), + new RaiseIntent(), + new Handshake(this.timeOutIdValidation), + new UserChannels(), + new CurrentChannel(), + new GetInfo(), + ]; + this.init(); + } + + receive(message: AppRequestMessage, from: string): void { + this.automaticResponses.forEach(r => { + if (r.filter(message.type)) { + r.action(message, this.tsc, from); + } + }); + } + + shutdown() { + this.tsc.shutdown(); + } + + hasReceivedGoodbye(): boolean { + return this.receivedGoodbye; + } + + init() { + this.window.addEventListener('message', e => { + const event = e as MessageEvent; + const data = event.data; + const source = event.source as Window; + const origin = event.origin; + + if (this.tsc.cw.debugLogs) { + console.log('MockFDC3Server received: ', event.data); + } + if (data.type == 'WCP1Hello') { + if (this.useIframe) { + const message: WebConnectionProtocol2LoadURL = { + type: 'WCP2LoadUrl', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + iframeUrl: EMBED_URL + '?connectionAttemptUuid=' + data.meta.connectionAttemptUuid, + }, + }; + source.postMessage(message, origin); + } else { + const details = this.tsc.getMatchingInstance(data.payload.identityUrl); + if (details) { + const message: WebConnectionProtocol3Handshake = { + type: 'WCP3Handshake', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + fdc3Version: '2.2', + intentResolverUrl: this.useDefaultUIUrls ? true : INTENT_RESOLVER_URL, + channelSelectorUrl: this.useDefaultUIUrls ? true : CHANNEL_SELECTOR_URL, + }, + }; + source.postMessage(message, origin, [details.externalPort]); + } //getMatchingInstance will log if it didn't find anything + } + } else if (data.type == 'WCP6Goodbye') { + this.receivedGoodbye = true; + } + }); + } } - - - diff --git a/packages/fdc3-get-agent/test/support/MockWindow.ts b/packages/fdc3-get-agent/test/support/MockWindow.ts index 34cd2938c..158f6126b 100644 --- a/packages/fdc3-get-agent/test/support/MockWindow.ts +++ b/packages/fdc3-get-agent/test/support/MockWindow.ts @@ -21,7 +21,7 @@ export class MockWindow extends MockElement { } eventHandlers: EventHandler[] = []; - events: any[] = []; + events: {type: string, data: MessageEvent}[] = []; parent: MockWindow | null = null; child: MockWindow | null = null; @@ -46,7 +46,7 @@ export class MockWindow extends MockElement { } dispatchEvent(event: Event): void { - this.events.push({ type: event.type, data: (event as any).data }); + this.events.push({ type: event.type, data: (event as unknown as MessageEvent).data }); this.eventHandlers.forEach((e) => { if (e.type === event.type) { e.callback(event); @@ -62,8 +62,8 @@ export class MockWindow extends MockElement { ports: transfer, //TODO: set source for UI iframes, comms iframe, parent DA or child app depending on message type source: this.commsIframe ?? this.child ?? this.parent ?? this - } as any; - if (this.cw.debugLogs) { console.debug(`MockWindow ${this.name} / ${this.tag}: postMessage with source: ${event.source.name}`); } + } as unknown as MessageEvent; + if (this.cw.debugLogs) { console.debug(`MockWindow ${this.name} / ${this.tag}: postMessage with source: ${(event.source as WindowProxy)?.name ?? "UNKNOWN"}`); } this.dispatchEvent(event); } diff --git a/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts b/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts index 1db0f9773..6039f45fe 100644 --- a/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts +++ b/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts @@ -24,7 +24,7 @@ export class CurrentChannel implements AutomaticResponse { }, type: "getCurrentChannelResponse", payload: { - + channel: null } }; return response; diff --git a/packages/fdc3-get-agent/test/support/responses/Handshake.ts b/packages/fdc3-get-agent/test/support/responses/Handshake.ts index 799e4baa8..4aacbdac9 100644 --- a/packages/fdc3-get-agent/test/support/responses/Handshake.ts +++ b/packages/fdc3-get-agent/test/support/responses/Handshake.ts @@ -9,22 +9,31 @@ export const ALTERNATIVE_IDENTITY_URL = "https://dummyOrigin.test/alternativePat export class Handshake implements AutomaticResponse { + timeOut: boolean; + + constructor(timeOut: boolean = false) { + this.timeOut = timeOut; + } + filter(t: string) { return t == 'WCP4ValidateAppIdentity' } action(input: object, m: TestServerContext, from: InstanceID) { - const out = this.createResponse(input as WebConnectionProtocol4ValidateAppIdentity) - - setTimeout(() => { m.post(out, from) }, 100) - return Promise.resolve() + if (!this.timeOut) { + const out = this.createResponse(input as WebConnectionProtocol4ValidateAppIdentity) + setTimeout(() => { m.post(out, from) }, 100) + } else { + console.debug("Forcing timeout of identity validation"); + } + return Promise.resolve(); } private createResponse(i: WebConnectionProtocol4ValidateAppIdentity): WebConnectionProtocol5ValidateAppIdentitySuccessResponse | WebConnectionProtocol5ValidateAppIdentityFailedResponse { - const identityURL = i.payload.identityUrl ?? i.payload.actualUrl; + const identityURL = i.payload.identityUrl; if (i.payload.instanceUuid == BAD_INSTANCE_ID) { const msg: WebConnectionProtocol5ValidateAppIdentityFailedResponse = { meta: { diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index 02ca58880..a55f704a7 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -40,13 +40,13 @@ function getUIKey(): UI { } //set-up a listener for the WCP1Hello message -const helloHandler = (e) => { - const event = e as MessageEvent +const helloHandler = (e: MessageEvent) => { + const event = e; const data = event.data; // const source = event.source as Window // const origin = event.origin; - console.log("Received postMessage: " + JSON.stringify(event.data)); + console.debug("Received postMessage: " + JSON.stringify(event.data)); if (isWebConnectionProtocol1Hello(data)) { const socket = io(); const channel = new MessageChannel(); From 8a981c84d952834f00ab5b11365f1e9953a62425 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 15:08:57 +0000 Subject: [PATCH 35/90] Further refactor of fdc3-get-agent tests and improving coverage --- .../src/strategies/HelloHandler.ts | 29 ++- .../src/ui/AbstractUIComponent.ts | 29 ++- packages/fdc3-get-agent/test/README.md | 5 + .../features/desktop-agent-strategy.feature | 85 +++++-- .../step-definitions/desktop-agent.steps.ts | 64 ++++- .../step-definitions/port-creation.steps.ts | 4 +- .../fdc3-get-agent/test/support/FrameTypes.ts | 238 ++++++++++-------- .../test/support/MockDocument.ts | 12 +- .../test/support/MockElement.ts | 12 +- .../fdc3-get-agent/test/support/MockIFrame.ts | 49 +++- .../fdc3-get-agent/test/support/MockWindow.ts | 153 ++++++----- packages/fdc3-get-agent/test/world/index.ts | 2 +- packages/testing/src/support/matching.ts | 2 + .../fdc3-for-web/demo/src/client/da/embed.ts | 2 +- 14 files changed, 460 insertions(+), 226 deletions(-) create mode 100644 packages/fdc3-get-agent/test/README.md diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index b9d6c8e61..3977bcbc3 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -57,6 +57,8 @@ export class HelloHandler { }, }; + Logger.debug("HelloHandler: Sending hello msg: ", requestMessage); + w.postMessage(requestMessage, { targetOrigin: origin }); } @@ -74,8 +76,23 @@ export class HelloHandler { existing.remove(); } + //note the iframe URL and desktop agent type have changed + this.agentType = WebDesktopAgentType.ProxyUrl; + this.agentUrl = url; + // create a new one const ifrm = document.createElement('iframe'); + + //Wait for the iframe to load... then send it a hello message + ifrm.addEventListener("load", () => { + if (ifrm.contentWindow) { + Logger.debug("Sending hello message to communication iframe"); + this.sendWCP1Hello(ifrm.contentWindow, '*'); + } else { + Logger.error('iframe does not have a contentWindow, despite firing its load event!'); + } + }); + ifrm.setAttribute('src', url); ifrm.setAttribute('id', IFRAME_ID); ifrm.setAttribute('name', 'FDC3 Communications'); @@ -84,14 +101,6 @@ export class HelloHandler { ifrm.style.border = '0'; ifrm.style.position = 'fixed'; - //Wait for the iframe to load... then send it a hello message - ifrm.onload = () => { - if (ifrm.contentWindow) { - this.sendWCP1Hello(ifrm.contentWindow, '*'); - } else { - Logger.error('iframe does not have a contentWindow, despite firing its load event!'); - } - }; document.body.appendChild(ifrm); } @@ -113,10 +122,6 @@ export class HelloHandler { const url = data.payload.iframeUrl; this.openFrame(url); - //note the iframe URL and desktop agent type have changed - this.agentType = WebDesktopAgentType.ProxyUrl; - this.agentUrl = url; - //n.b event listener remains in place to receive messages from the iframe } else if (isWebConnectionProtocol3Handshake(data)) { Logger.debug(`HelloHandler: successful handshake`); diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index 771a42f61..534597b57 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -45,12 +45,24 @@ export abstract class AbstractUIComponent implements Connectable { this.name = name; } - async connect() { + /** + * Connect the UI component by creating the UI iframe, then wait on + * a Fdc3UserInterfaceHello message. + * + * This function is NOT properly async as we don't want to block the + * Desktop Agent connection on the UI frames as they may be blocked by + * security policies. I.e. awaiting this will not block. + */ + connect(): Promise { const portPromise = this.awaitHello(); this.openFrame(); - this.port = await portPromise; - await this.setupMessagePort(this.port); - await this.messagePortReady(this.port); + portPromise.then((port) => { + this.port = port; + this.setupMessagePort(port).then(() => { + this.messagePortReady(port); + }); + }); + return Promise.resolve(); } async disconnect() { @@ -84,7 +96,7 @@ export abstract class AbstractUIComponent implements Connectable { } private awaitHello(): Promise { - return new Promise((resolve, _reject) => { + return new Promise((resolve /*, _reject*/) => { const ml = (e: MessageEvent) => { if (e.source == this.iframe?.contentWindow) { if (isFdc3UserInterfaceHello(e.data)) { @@ -100,7 +112,7 @@ export abstract class AbstractUIComponent implements Connectable { Logger.debug('AbstractUIComponent: ignored UI Message from UI iframe while awaiting hello: ', e.data); } } else { - Logger.debug("AbstractUIComponent: ignored Message that didn't come from expected UI frame", e.data); + Logger.debug("AbstractUIComponent: ignored Message that didn't come from expected UI frame\n", e.data, "\nexpected window name: ", this.iframe?.contentWindow?.name, "\ngot window name: ", (e.source as Window).name); } }; @@ -116,11 +128,13 @@ export abstract class AbstractUIComponent implements Connectable { this.themeFrame(this.iframe); this.iframe.setAttribute('src', this.url); + this.iframe.setAttribute('name', this.name); + this.container.appendChild(this.iframe); document.body.appendChild(this.container); } - private toKebabCase(str: String) { + private toKebabCase(str: string) { return str.replace(/[A-Z]/g, match => '-' + match.toLowerCase()); } @@ -139,7 +153,6 @@ export abstract class AbstractUIComponent implements Connectable { } themeFrame(ifrm: HTMLIFrameElement) { - ifrm.setAttribute('name', this.name); ifrm.style.width = '100%'; ifrm.style.height = '100%'; ifrm.style.border = '0'; diff --git a/packages/fdc3-get-agent/test/README.md b/packages/fdc3-get-agent/test/README.md new file mode 100644 index 000000000..048576376 --- /dev/null +++ b/packages/fdc3-get-agent/test/README.md @@ -0,0 +1,5 @@ +# FDC3 GetAgent Test Infrastructure + +The test infrastructure for fdc3-get-agent is complex as it has to mock a collection of windows, documents and iframes to simulate a Wed-based Desktop Agent. Additional tests in the /toolbox/fdc3-for-web/fdc3-web-impl package test against the reference implementation of web-based Desktop Agent, while the tests here work against a simulated one. + +To enable debug logs for the test infrastructure, set the `debugLogs` flag in packages\fdc3-get-agent\test\world\index.ts to true. diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index b15f915c6..fa08cb586 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -200,9 +200,9 @@ Scenario: Connecting but identity validation times out Here, we recover the details of the session from the session state, obviating the need to make a request to the parent iframe. - Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns iframe response And an existing app instance in "instanceID" - And SessionStorage contains instanceUuid "{instanceID}", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path" and agentType "PROXY_PARENT" + And SessionStorage contains instanceUuid "some-instance-uuid", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path", agentType "PROXY_URL" and agentUrl "http://localhost:8080/static/da/embed.html" And we wait for a period of "200" ms And I call getAgent for a promise result with the following options | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | @@ -214,8 +214,52 @@ Scenario: Connecting but identity validation times out Then "{result}" is an object with the following contents | fdc3Version | appMetadata.appId | provider | | 2.0 | cucumber-app | cucumber-provider | + Then SessionStorage should contain instanceUuid "some-instance-uuid", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path", agentType "PROXY_URL" and agentUrl "http://localhost:8080/static/da/embed.html" And I call "{desktopAgent}" with "disconnect" +Scenario: Go straight to (preload) failover as directed by SessionStorage + Here, we recover the details of the session from the session state, obviating the need to + to do discovery and going straight to failover. + + Given A Dummy Desktop Agent in "dummy-api" + And "dummyFailover" is a function which returns a promise of "{dummy-api}" + And SessionStorage contains instanceUuid "uuid-0", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path", agentType "FAILOVER" and agentUrl "{undefined}" + And I call getAgent for a promise result with the following options + | failover | timeoutMs | + | {dummyFailover} | 1000 | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I call "{result}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | preload-provider | + Then SessionStorage for identityUrl "https://dummyOrigin.test/path" should contain the following values + | appId | agentType | identityUrl | + | cucumber-app | FAILOVER | https://dummyOrigin.test/path | + + Scenario: Go straight to (proxy) failover as directed by SessionStorage + Here, we recover the details of the session from the session state, obviating the need to + to do discovery and going straight to failover. + + Given "dummyFailover2" is a function which opens an iframe for communications on "{childDoc}" + And I call getAgent for a promise result with the following options + | failover | timeoutMs | + | {dummyFailover2} | 1000 | + And SessionStorage contains instanceUuid "uuid-0", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path", agentType "FAILOVER" and agentUrl "{undefined}" + And I call getAgent for a promise result with the following options + | failover | timeoutMs | + | {dummyFailover} | 1000 | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I call "{result}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | cucumber-provider | + Then SessionStorage for identityUrl "https://dummyOrigin.test/path" should contain the following values + | appId | agentType | identityUrl | + | cucumber-app | FAILOVER | https://dummyOrigin.test/path | + + Scenario: Handle corrupted data in SessionStorage Here we deal with data in SessionStorage that is not in the proper format. @@ -254,6 +298,23 @@ Scenario: Connecting but identity validation times out | 2.0 | cucumber-app | cucumber-provider | And I call "{desktopAgent}" with "disconnect" + Scenario: Latch to Desktop Agent Proxy parent via SessionStorage + Here, we recover the details of the session from session storage, and latch to the + same Desktop Agent type (preload) - the connection should succeed. + + Given A Dummy Desktop Agent in "dummy-api" + And Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response + And SessionStorage contains instanceUuid "{instanceID}", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path" and agentType "PROXY_PARENT" + And `window.fdc3` is injected into the runtime with the value in "{dummy-api}" + And I call fdc3Ready for a promise result + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | cucumber-provider | + Scenario: Latch to Desktop Agent Preload via SessionStorage Here, we recover the details of the session from session storage, and latch to the same Desktop Agent type (preload) - the connection should succeed. @@ -283,26 +344,6 @@ Scenario: Latch to Desktop Agent Preload via SessionStorage which has gone away And I refer to "{result}" as "theAPIPromise" Then the promise "{theAPIPromise}" should resolve And "{result}" is an error with message "AgentNotFound" - - - # Scenario: Failed Recovery from SessionState - # App tries to recover with an ID that doesn't exist. - # It should be allowed to connect but issued a different instanceId - # needs more thought to complete... - # Given Parent Window desktop "da" listens for postMessage events in "{parentWin}", returns direct message response - # And we wait for a period of "200" ms - # And the session identity is set to "BAD_INSTANCE" with identityUrl "https://dummyOrigin.test/path" - # And I call getAgent for a promise result with the following options - # | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | - # | true | 8000 | false | false | - # And I refer to "{result}" as "theAPIPromise" - # Then the promise "{theAPIPromise}" should resolve - # And I call "{result}" with "getInfo" - # Then "{result}" is an object with the following contents - # | fdc3Version | appMetadata.appId | provider | - # | 2.0 | cucumber-app | cucumber-provider | - # Then I call "{parentDoc}" with "shutdown" - # Then I call "{childDoc}" with "shutdown" Scenario: Nothing works and we timeout When I call getAgent for a promise result with the following options diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index 18ad84111..2198692de 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -1,6 +1,6 @@ -import { After, DataTable, Given, When } from '@cucumber/cucumber'; +import { After, DataTable, Given, Then, When } from '@cucumber/cucumber'; import { CustomWorld } from '../world'; -import { handleResolve, setupGenericSteps } from '@kite9/testing'; +import { doesRowMatch, handleResolve, setupGenericSteps } from '@kite9/testing'; import { MockDocument } from '../support/MockDocument'; import { MockWindow } from '../support/MockWindow'; import { fdc3Ready, getAgent } from '../../src'; @@ -15,6 +15,7 @@ import { DesktopAgent, ImplementationMetadata } from '@kite9/fdc3-standard'; import { clearAgentPromise } from '../../src/strategies/getAgent'; import expect from 'expect'; import { dummyInstanceDetails } from '../support/TestServerContext'; +import { MockIFrame } from '../support/MockIFrame'; interface MockPageTransitionEvent extends Event { persisted?: boolean; @@ -72,7 +73,8 @@ Given( this.mockContext.open(dummyInstanceDetails[0].appId); const document = handleResolve(doc, this) as MockDocument; const ifrm = document.createElement('iframe'); - this.mockFDC3Server = new MockFDC3Server(ifrm as any, false, this.mockContext); + + this.mockFDC3Server = new MockFDC3Server(ifrm as unknown as MockIFrame, false, this.mockContext); ifrm.setAttribute('src', EMBED_URL); document.body.appendChild(ifrm); return ifrm; @@ -237,6 +239,29 @@ Given( } ); +Given( + 'SessionStorage contains instanceUuid {string}, appId {string} with identityUrl {string}, agentType {string} and agentUrl {string}', + async function (this: CustomWorld, uuid: string, appId: string, identityUrl: string, agentType: string, agentUrl: string) { + const theUuid = handleResolve(uuid, this); + const theAppId = handleResolve(appId, this); + const theIdentityUrl = handleResolve(identityUrl, this); + const theAgentType = handleResolve(agentType, this); + const theAgentUrl = handleResolve(agentUrl, this); + const details: Record = {}; + details[theIdentityUrl] = { + agentType: theAgentType, + instanceUuid: theUuid, + appId: theAppId, + instanceId: 'uuid-0', + identityUrl: theIdentityUrl, + actualUrl: theIdentityUrl, + agentUrl: theAgentUrl + }; + + globalThis.sessionStorage.setItem(DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-mocky', JSON.stringify(details)); + } +); + Given( 'SessionStorage contains partial data with with identityUrl {string}, appId {string} and agentType {string}', async function (this: CustomWorld, identityUrl: string, agentType: string, appId: string) { @@ -271,6 +296,39 @@ Given( } ); +Then( + 'SessionStorage should contain instanceUuid {string}, appId {string} with identityUrl {string}, agentType {string} and agentUrl {string}', + async function (this: CustomWorld, uuid: string, appId: string, identityUrl: string, agentType: string, agentUrl: string) { + const theUuid = handleResolve(uuid, this); + const theAppId = handleResolve(appId, this); + const theIdentityUrl = handleResolve(identityUrl, this); + const theAgentType = handleResolve(agentType, this); + const theAgentUrl = handleResolve(agentUrl, this); + + const value = globalThis.sessionStorage.getItem(DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-mocky'); + expect(value).toBeTruthy(); + const theObject = JSON.parse(value!); + const details = theObject[theIdentityUrl]; + expect(details).toBeTruthy(); + expect(details.agentType).toEqual(theAgentType); + expect(details.agentUrl).toEqual(theAgentUrl); + expect(details.appId).toEqual(theAppId); + expect(details.instanceUuid).toEqual(theUuid); + } +); + +Then('SessionStorage for identityUrl {string} should contain the following values', + function (this: CustomWorld, identityUrl: string, dt: DataTable) { + const theIdentityUrl = handleResolve(identityUrl, this); + const value = globalThis.sessionStorage.getItem(DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX + '-mocky'); + expect(value).toBeTruthy(); + const theObject = JSON.parse(value!); + const details = theObject[theIdentityUrl]; + const table = dt.hashes(); + expect(doesRowMatch(this, table[0], details)).toBeTruthy(); + } +); + When( '{string} pagehide occurs with persisted = {string}', async function (this: CustomWorld, field: string, persisted: string) { diff --git a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts index 64fbd5d6e..eb8263b60 100644 --- a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts @@ -29,11 +29,11 @@ Given( ); Given('{string} pipes messages to {string}', async function (this: CustomWorld, port: string, output: string) { - const out: any[] = []; + const out: {type: string, data: any}[] = []; this.props[output] = out; const internalPort = handleResolve(port, this); - internalPort.onmessage = (e: any) => { + internalPort.onmessage = (e: MessageEvent) => { out.push({ type: e.type, data: e.data }); }; }); diff --git a/packages/fdc3-get-agent/test/support/FrameTypes.ts b/packages/fdc3-get-agent/test/support/FrameTypes.ts index 708dd4dce..95c275ec7 100644 --- a/packages/fdc3-get-agent/test/support/FrameTypes.ts +++ b/packages/fdc3-get-agent/test/support/FrameTypes.ts @@ -1,116 +1,150 @@ -import { CustomWorld } from "../world" -import { MockWindow } from "./MockWindow" -import { CHANNEL_SELECTOR_URL, EMBED_URL, INTENT_RESOLVER_URL } from "./MockFDC3Server" -import { BrowserTypes } from "@kite9/fdc3-schema" -import { FDC3_USER_INTERFACE_HANDSHAKE_TYPE, FDC3_USER_INTERFACE_HELLO_TYPE, FDC3_USER_INTERFACE_RESTYLE_TYPE } from "@kite9/fdc3-schema/dist/generated/api/BrowserTypes" - -type Fdc3UserInterfaceHello = BrowserTypes.Fdc3UserInterfaceHello -type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake +import { CustomWorld } from '../world'; +import { MockWindow } from './MockWindow'; +import { CHANNEL_SELECTOR_URL, INTENT_RESOLVER_URL } from './MockFDC3Server'; +import { + isWebConnectionProtocol1Hello, +} from '@kite9/fdc3-schema/dist/generated/api/BrowserTypes'; +import { + Fdc3UserInterfaceHello, + Fdc3UserInterfaceRestyle, + isFdc3UserInterfaceHandshake, + WebConnectionProtocol3Handshake, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; /** * This handles the frame communications when we're using the embedded iframe approach */ -export function handleEmbeddedIframeComms(value: string, parent: MockWindow, cw: CustomWorld) { - const paramStr = value.substring(EMBED_URL.length + 1) - const params = new URLSearchParams(paramStr) - const connectionAttemptUuid = params.get("connectionAttemptUuid")!! - const connection = cw.mockContext.getFirstInstance() - try { - parent.postMessage({ - type: "WCP3Handshake", - meta: { - connectionAttemptUuid: connectionAttemptUuid, - timestamp: new Date() - }, - payload: { - fdc3Version: "2.2", - intentResolverUrl: INTENT_RESOLVER_URL, - channelSelectorUrl: CHANNEL_SELECTOR_URL, - } - } as WebConnectionProtocol3Handshake, EMBED_URL, [connection!!.externalPort]) - } catch (e) { - console.error(e) - } -} +export function handleEmbeddedIframeComms(_value: string, parent: MockWindow, source: MockWindow, cw: CustomWorld) { + const helloHandler = (e: Event) => { + const event = e as MessageEvent; + const eventSource = event.source as unknown as MockWindow; + const data = event.data; -export function handleChannelSelectorComms(_value: string, parent: MockWindow, source: Window, cw: CustomWorld): MessageChannel { - const connection = new MessageChannel(); - try { - parent.dispatchEvent({ - type: "message", - data: { - type: FDC3_USER_INTERFACE_HELLO_TYPE, - payload: { - initialCSS: { - "width": "100px" - } - } - } as Fdc3UserInterfaceHello, - origin: CHANNEL_SELECTOR_URL, - source, - ports: [connection.port1] - } as any as Event) + if (isWebConnectionProtocol1Hello(data)) { + console.debug( + `Received hello message from ${eventSource.name} ${eventSource == parent ? '(parent window)' : 'NOT parent win)'}: `, + event.data + ); + const connection = cw.mockContext.getFirstInstance(); + // send the other end of the channel to the app + const message: WebConnectionProtocol3Handshake = { + type: 'WCP3Handshake', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + fdc3Version: '2.2', + channelSelectorUrl: CHANNEL_SELECTOR_URL, + intentResolverUrl: INTENT_RESOLVER_URL, + }, + }; + eventSource.postMessage(message, '*', [connection!.externalPort]); - connection.port2.onmessage = (e) => { - if (e.data.type == FDC3_USER_INTERFACE_HANDSHAKE_TYPE) { - setTimeout(() => { - connection.port2.postMessage({ - type: FDC3_USER_INTERFACE_RESTYLE_TYPE, - payload: { - css: { - "width": "100px" - } - } - }) - }, 100) - } - cw.props['lastChannelSelectorMessage'] = e.data - } - } catch (e) { - console.error(e) + window.removeEventListener('message', helloHandler); + } else { + console.warn(`Unexpected message received by MockIframe - ignored`, e); } + }; - return connection + //listen for hello message events from parent to respond to + source.addEventListener('message', helloHandler); } -export function handleIntentResolverComms(_value: string, parent: MockWindow, source: Window, cw: CustomWorld): MessageChannel { - const connection = new MessageChannel(); - try { - parent.dispatchEvent({ - type: "message", - data: { - type: FDC3_USER_INTERFACE_HELLO_TYPE, - payload: { - initialCSS: { - "width": "100px" - } - } - } as Fdc3UserInterfaceHello, - origin: INTENT_RESOLVER_URL, - source, - ports: [connection.port1] - } as any as Event) +export function handleChannelSelectorComms( + _value: string, + parent: MockWindow, + source: MockWindow, + cw: CustomWorld +): MessageChannel { + const connection = new MessageChannel(); + try { + const msg: Fdc3UserInterfaceHello = { + type: 'Fdc3UserInterfaceHello', + payload: { + implementationDetails: 'mock channel selector', + initialCSS: { + width: '100px', + }, + }, + }; + parent.dispatchEvent({ + type: 'message', + data: msg, + origin: CHANNEL_SELECTOR_URL, + source, + ports: [connection.port1], + } as unknown as Event); - connection.port2.onmessage = (e) => { - if (e.type == FDC3_USER_INTERFACE_HANDSHAKE_TYPE) { - setTimeout(() => { - connection.port2.postMessage({ - type: FDC3_USER_INTERFACE_RESTYLE_TYPE, - payload: { - css: { - "width": "100px" - } - } - }) - }, 100) - } + connection.port2.onmessage = e => { + if (isFdc3UserInterfaceHandshake(e)) { + setTimeout(() => { + const msg: Fdc3UserInterfaceRestyle = { + type: "Fdc3UserInterfaceRestyle", + payload: { + updatedCSS: { + width: '100px', + }, + }, + }; + connection.port2.postMessage(msg); + }, 100); + } + cw.props['lastChannelSelectorMessage'] = e.data; + }; + } catch (e) { + console.error(e); + } - cw.props['lastIntentResolverMessage'] = e - } - } catch (e) { - console.error(e) - } + return connection; +} + +export function handleIntentResolverComms( + _value: string, + parent: MockWindow, + source: MockWindow, + cw: CustomWorld +): MessageChannel { + const connection = new MessageChannel(); + try { + const msg: Fdc3UserInterfaceHello = { + type: "Fdc3UserInterfaceHello", + payload: { + implementationDetails: 'mock intent resolver', + initialCSS: { + width: '100px', + }, + }, + }; + parent.dispatchEvent({ + type: 'message', + data: msg, + origin: INTENT_RESOLVER_URL, + source, + ports: [connection.port1], + } as unknown as Event); - return connection -} \ No newline at end of file + connection.port2.onmessage = e => { + if (isFdc3UserInterfaceHandshake(e)) { + setTimeout(() => { + const msg: Fdc3UserInterfaceRestyle = { + type: "Fdc3UserInterfaceRestyle", + payload: { + updatedCSS: { + width: '100px', + }, + }, + }; + connection.port2.postMessage(msg); + }, 100); + } + + cw.props['lastIntentResolverMessage'] = e; + }; + } catch (e) { + console.error(e); + } + + return connection; +} diff --git a/packages/fdc3-get-agent/test/support/MockDocument.ts b/packages/fdc3-get-agent/test/support/MockDocument.ts index 649ddc541..0771c906f 100644 --- a/packages/fdc3-get-agent/test/support/MockDocument.ts +++ b/packages/fdc3-get-agent/test/support/MockDocument.ts @@ -11,19 +11,19 @@ export class MockDocument { constructor(name: string, window: MockWindow) { this.name = name; this.window = window; - if (this.window.cw.debugLogs) { console.log(`MockDocument created with name: ${name} in window.name: ${this.window.name}`); } + if (this.window.cw.debugLogs) { console.log(`MockDocument (name: ${name} / window.name: ${this.window.name}): Created`); } MockDocument.allDocuments.push(this); } createElement(tag: string): HTMLElement { if (tag == 'iframe') { - if (this.window.cw.debugLogs) { console.log(`MockDocument ${this.name} creating iframe in window.name ${this.window.name}`); } - const mw = new MockIFrame("iframe", this.window.cw, this.window, "embedded-iframe"); - //make sure the parent doc is aware of the iframe for attributing postMessage - //TODO: set a different variable for UI iframes - this.window.commsIframe = mw; + if (this.window.cw.debugLogs) { console.log(`MockDocument (name: ${this.name} / window.name: ${this.window.name}): creating iframe`); } + const mw = new MockIFrame("iframe", this.window.cw, this.window, "pending-iframe"); + //n.b. variables are set on the parent window to link each iframe in order to allow use as source in + // postMessages from them - these are set in the MockIframe.setAttribute function this.iframes.push(mw); + return mw as unknown as HTMLElement; } else { return new MockElement(tag) as unknown as HTMLElement; diff --git a/packages/fdc3-get-agent/test/support/MockElement.ts b/packages/fdc3-get-agent/test/support/MockElement.ts index c8a81b276..dea32d8f4 100644 --- a/packages/fdc3-get-agent/test/support/MockElement.ts +++ b/packages/fdc3-get-agent/test/support/MockElement.ts @@ -1,11 +1,12 @@ import { MockCSSStyleDeclaration } from "./MockCSSStyleDeclaration"; +import { MockIFrame } from "./MockIFrame"; export class MockElement { - tag: string; - atts: { [name: string]: any; } = {}; - children: HTMLElement[] = []; + public tag: string; + public atts: { [name: string]: any; } = {}; + public children: HTMLElement[] = []; constructor(tag: string) { this.tag = tag; @@ -23,6 +24,11 @@ export class MockElement { appendChild(child: HTMLElement) { this.children.push(child); + + //if its an iframe make it load here + if ((child as unknown as MockIFrame).load) { + (child as unknown as MockIFrame).load(); + } } removeChild(child: HTMLElement) { diff --git a/packages/fdc3-get-agent/test/support/MockIFrame.ts b/packages/fdc3-get-agent/test/support/MockIFrame.ts index 5334def42..35b33c1e0 100644 --- a/packages/fdc3-get-agent/test/support/MockIFrame.ts +++ b/packages/fdc3-get-agent/test/support/MockIFrame.ts @@ -1,35 +1,68 @@ import { CustomWorld } from "../world"; -import { handleEmbeddedIframeComms, handleChannelSelectorComms, handleIntentResolverComms } from "./FrameTypes"; +import { handleChannelSelectorComms, handleEmbeddedIframeComms, handleIntentResolverComms } from "./FrameTypes"; import { EMBED_URL, CHANNEL_SELECTOR_URL, INTENT_RESOLVER_URL } from "./MockFDC3Server"; import { MockWindow } from "./MockWindow"; export class MockIFrame extends MockWindow { - contentWindow: Window; + contentWindow: MockWindow; messageChannels: MessageChannel[] = []; + parent: MockWindow; + initFn: (() => void) | null = null; constructor(tag: string, cw: CustomWorld, parent: MockWindow, name: string) { super(tag, cw, name); this.parent = parent; - this.contentWindow = this as any; - if (this.cw.debugLogs) { console.log(`MockIFrame created with tag ${tag}, name: ${name} and parent.name ${parent.name}`); } + this.contentWindow = this; + if (this.cw.debugLogs) { console.log(`MockIFrame (name: ${name} / parent.name: ${parent.name}): Created`); } + + } + + /** Used to simulate the iframe loading. */ + load(): void { + if (this.cw.debugLogs) { console.log(`MockIFrame (name: ${this.name}): Dispatching load event`); } + + //if we've got an init fn *to simulate comms) call it before we dispatch the load event + if (this.initFn) { + this.initFn(); + } + + this.dispatchEvent(new Event("load")); } setAttribute(name: string, value: string): void { this.atts[name] = value; const parent = this.parent as MockWindow; - if (name == 'src') { + if (name === 'src') { + //set the frame up properly along wih a function to initialize comms when it loads if (value.startsWith(EMBED_URL)) { this.name = "embedded-iframe"; - handleEmbeddedIframeComms(value, parent, this.cw); + this.parent.commsIframe = this; + this.initFn = () => { + handleEmbeddedIframeComms(value, parent, this.contentWindow, this.cw); + }; + if (this.cw.debugLogs) { console.debug(`MockIframe (name: ${this.name}): Created comms iframe with url: ${value}`); } } else if (value.startsWith(CHANNEL_SELECTOR_URL)) { this.name = "channel-selector"; - this.messageChannels.push(handleChannelSelectorComms(value, parent, this.contentWindow, this.cw)); + this.parent.channelSelectorIframe = this; + this.initFn = () => { + this.messageChannels.push(handleChannelSelectorComms(value, parent, this.contentWindow, this.cw)); + } + if (this.cw.debugLogs) { console.debug(`MockIframe (name: ${this.name}): Created channel selector iframe with url: ${value}`); } } else if (value.startsWith(INTENT_RESOLVER_URL)) { this.name = "intent-resolver"; - this.messageChannels.push(handleIntentResolverComms(value, parent, this.contentWindow, this.cw)); + this.parent.intentResolverIframe = this; + this.initFn = () => { + this.messageChannels.push(handleIntentResolverComms(value, parent, this.contentWindow, this.cw)); + } + if (this.cw.debugLogs) { console.debug(`MockIframe (name: ${this.name}): Created intent resolver iframe with url: ${value}`); } + } else { + if (this.cw.debugLogs) { console.warn(`MockIframe (name: ${this.name}): Set an unrecognized URL: ${value}`); } } + } else if (name === 'name') { + if (this.cw.debugLogs) { console.debug(`MockIframe (name: ${this.name}): setAttribute() changing iframe name to: ${value}`); } + this.name = value; } } diff --git a/packages/fdc3-get-agent/test/support/MockWindow.ts b/packages/fdc3-get-agent/test/support/MockWindow.ts index 158f6126b..937b923c9 100644 --- a/packages/fdc3-get-agent/test/support/MockWindow.ts +++ b/packages/fdc3-get-agent/test/support/MockWindow.ts @@ -1,77 +1,114 @@ -import { DesktopAgent } from "@kite9/fdc3-standard"; -import { CustomWorld } from "../world"; -import { EventHandler } from "./EventHandler"; -import { MockElement } from "./MockElement"; +import { DesktopAgent } from '@kite9/fdc3-standard'; +import { CustomWorld } from '../world'; +import { EventHandler } from './EventHandler'; +import { MockElement } from './MockElement'; +import { + AgentEventMessage, + AgentResponseMessage, + AppRequestMessage, + Fdc3UserInterfaceMessage, + isFdc3UserInterfaceHello, + WebConnectionProtocolMessage, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -/** - * Used for routing of post-message events while running tests - */ +type STANDARD_MESSAGES = + | AppRequestMessage + | AgentResponseMessage + | AgentEventMessage + | WebConnectionProtocolMessage + | Fdc3UserInterfaceMessage; export class MockWindow extends MockElement { + fdc3: DesktopAgent | undefined; + cw: CustomWorld; + name: string; - fdc3: DesktopAgent | undefined; - cw: CustomWorld; - name: string; - - constructor(tag: string, cw: CustomWorld, name: string) { - super(tag); - this.cw = cw; - this.name = name; - if (cw.debugLogs) { console.debug(`MockWindow created with name: ${this.name} / tag: ${this.tag}`); } + constructor(tag: string, cw: CustomWorld, name: string) { + super(tag); + this.cw = cw; + this.name = name; + if (cw.debugLogs) { + console.debug(`MockWindow (name: ${this.name} / tag: ${this.tag}): Created`); } + } - eventHandlers: EventHandler[] = []; - events: {type: string, data: MessageEvent}[] = []; + eventHandlers: EventHandler[] = []; + events: { type: string; data: MessageEvent }[] = []; - parent: MockWindow | null = null; - child: MockWindow | null = null; - commsIframe: MockWindow | null = null; + //references used to attribute postMessages to sources + parent: MockWindow | null = null; + child: MockWindow | null = null; + commsIframe: MockWindow | null = null; + channelSelectorIframe: MockWindow | null = null; + intentResolverIframe: MockWindow | null = null; - location = { - origin: "https://dummyOrigin.test", - href: "https://dummyOrigin.test/path" - }; + location = { + origin: 'https://dummyOrigin.test', + href: 'https://dummyOrigin.test/path', + }; - addEventListener(type: string, callback: (e: Event) => void): void { - this.eventHandlers.push({ type, callback }); - if (this.cw.debugLogs) { console.log(`MockWindow ${this.name} / ${this.tag}: added event handler: ${type}`); } + addEventListener(type: string, callback: (e: Event) => void): void { + this.eventHandlers.push({ type, callback }); + if (this.cw.debugLogs) { + console.log(`MockWindow (name: ${this.name} / tag: ${this.tag}): added event handler: ${type}`); } + } - removeEventListener(type: string, el: EventListener): void { - const removeIndex = this.eventHandlers.findIndex(e => e.type === type && e.callback === el); - if (removeIndex !== -1) { - this.eventHandlers.splice(removeIndex, 1); - if (this.cw.debugLogs) { console.debug(`MockWindow ${this.name} / ${this.tag}: removed event handler: ${type}`); } - } + removeEventListener(type: string, el: EventListener): void { + const removeIndex = this.eventHandlers.findIndex(e => e.type === type && e.callback === el); + if (removeIndex !== -1) { + this.eventHandlers.splice(removeIndex, 1); + if (this.cw.debugLogs) { + console.debug(`MockWindow (name: ${this.name} / tag: ${this.tag}): removed event handler: ${type}`); + } } + } + + dispatchEvent(event: Event): void { + this.events.push({ type: event.type, data: (event as unknown as MessageEvent).data }); + this.eventHandlers.forEach(e => { + if (e.type === event.type) { + e.callback(event); + } + }); + } - dispatchEvent(event: Event): void { - this.events.push({ type: event.type, data: (event as unknown as MessageEvent).data }); - this.eventHandlers.forEach((e) => { - if (e.type === event.type) { - e.callback(event); - } - }); + postMessage(msg: STANDARD_MESSAGES, targetOrigin: string, transfer: MessagePort[] | undefined): void { + //usually only one of these will be set - however parent might be set initially, + // but later overridden by commsIframe wafter a WCP2LoadUrl + let source = this.commsIframe ?? this.child ?? this.parent ?? this; + + //adjust source for mock UI iframes - these variables are set in MockDocument.setAttribute + if (isFdc3UserInterfaceHello(msg)) { + if (msg.payload.implementationDetails == 'mock channel selector') { + source = this.channelSelectorIframe!; + } else if (msg.payload.implementationDetails == 'mock intent resolver') { + source = this.intentResolverIframe!; + } } - postMessage(msg: object, targetOrigin: string, transfer: MessagePort[] | undefined): void { - const event = { - type: 'message', - data: msg, - origin: targetOrigin, - ports: transfer, - //TODO: set source for UI iframes, comms iframe, parent DA or child app depending on message type - source: this.commsIframe ?? this.child ?? this.parent ?? this - } as unknown as MessageEvent; - if (this.cw.debugLogs) { console.debug(`MockWindow ${this.name} / ${this.tag}: postMessage with source: ${(event.source as WindowProxy)?.name ?? "UNKNOWN"}`); } - this.dispatchEvent(event); + const event = { + type: 'message', + data: msg, + origin: targetOrigin, + ports: transfer, + //TODO: set source for UI iframes, comms iframe, parent DA or child app depending on message type + source, + } as unknown as MessageEvent; + + if (this.cw.debugLogs) { + console.debug( + `MockWindow (name: ${this.name} / tag: ${this.tag}): postMessage called with source: ${(event.source as WindowProxy)?.name ?? 'UNKNOWN'}` + ); } + this.dispatchEvent(event); + } - shutdown() { - this.eventHandlers = []; - this.fdc3 = undefined; - if (this.cw.mockFDC3Server) { - this.cw.mockFDC3Server.shutdown(); - } + shutdown() { + this.eventHandlers = []; + this.fdc3 = undefined; + if (this.cw.mockFDC3Server) { + this.cw.mockFDC3Server.shutdown(); } + } } diff --git a/packages/fdc3-get-agent/test/world/index.ts b/packages/fdc3-get-agent/test/world/index.ts index 98a7f6f66..4ef0164f5 100644 --- a/packages/fdc3-get-agent/test/world/index.ts +++ b/packages/fdc3-get-agent/test/world/index.ts @@ -9,7 +9,7 @@ export class CustomWorld extends PropsWorld { mockContext: TestServerContext = new TestServerContext(this) - debugLogs: boolean = false; + debugLogs: boolean = true; } diff --git a/packages/testing/src/support/matching.ts b/packages/testing/src/support/matching.ts index f4c75df7d..8e7a9790a 100644 --- a/packages/testing/src/support/matching.ts +++ b/packages/testing/src/support/matching.ts @@ -68,6 +68,8 @@ export function handleResolve(name: string, on: PropsWorld): any { return true } else if (stripped == 'false') { return false + } else if (stripped == 'undefined') { + return undefined } else { const out = JSONPath({ path: stripped, json: on.props })[0]; return out diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index a55f704a7..dac5b13ff 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -46,8 +46,8 @@ const helloHandler = (e: MessageEvent) => { // const source = event.source as Window // const origin = event.origin; - console.debug("Received postMessage: " + JSON.stringify(event.data)); if (isWebConnectionProtocol1Hello(data)) { + console.debug("Received hello message: ", event.data); const socket = io(); const channel = new MessageChannel(); const source = getSource(); From 74daa90a9a73a03d127e4f48e2f7be2f807ba542 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 19:10:36 +0000 Subject: [PATCH 36/90] Attempting to deal with SemGrep issues with log messages --- .semgrepignore | 3 ++- packages/fdc3-get-agent/src/util/Logger.ts | 16 ++++++++-------- .../fdc3-get-agent/test/support/FrameTypes.ts | 5 ++++- .../test/support/TestServerContext.ts | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.semgrepignore b/.semgrepignore index fee340922..9509aecef 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -2,9 +2,10 @@ website/** # Just used for build so ignoring s2tQuicktypeUtil.js +t2sQuicktypeUtil.js # API schema set for localhost gets picked up by semgrep rule -schemas/bridgingAsyncAPI/bridgingAsyncAPI.json +schemas/bridgingAsyncAPI/bridgingAsyncAPI.json # demo apps get picked up for not having integrity headers toolbox/fdc3-for-web/demo/src/client/apps/** diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 8fb762e47..55448675e 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -6,33 +6,33 @@ const GET_AGENT_LOG_PREFIX = 'FDC3 getAgent: '; export class Logger { static debug(...params: any[]) { if (typeof params[0] === 'string') { - console.debug(pc.black(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + console.debug(pc.black(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); } else { - console.debug(pc.black(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + console.debug(pc.black(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } } static log(...params: any[]) { if (typeof params[0] === 'string') { - console.log(pc.green(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + console.log(pc.green(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); } else { - console.log(pc.green(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + console.log(pc.green(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } } static warn(...params: any[]) { if (typeof params[0] === 'string') { - console.warn(pc.yellow(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + console.warn(pc.yellow(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); } else { - console.warn(pc.yellow(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + console.warn(pc.yellow(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } } static error(...params: any[]) { if (typeof params[0] === 'string') { - console.error(pc.red(pc.dim(`${GET_AGENT_LOG_PREFIX}${params[0]}`)), ...params.slice(1)); + console.error(pc.red(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); } else { - console.error(pc.red(pc.dim(`${GET_AGENT_LOG_PREFIX}`)), ...params); + console.error(pc.red(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } } } diff --git a/packages/fdc3-get-agent/test/support/FrameTypes.ts b/packages/fdc3-get-agent/test/support/FrameTypes.ts index 1c29e5a01..e74a57d96 100644 --- a/packages/fdc3-get-agent/test/support/FrameTypes.ts +++ b/packages/fdc3-get-agent/test/support/FrameTypes.ts @@ -20,7 +20,10 @@ export function handleEmbeddedIframeComms(_value: string, parent: MockWindow, so if (isWebConnectionProtocol1Hello(data)) { console.debug( - `Received hello message from ${eventSource.name} ${eventSource == parent ? '(parent window)' : 'NOT parent win)'}: `, + 'Received hello message from' + + eventSource.name + + ' ' + + (eventSource == parent ? '(parent window): ' : 'NOT parent win): '), event.data ); const connection = cw.mockContext.getFirstInstance(); diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index 225a77f4d..fd9a92894 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -56,7 +56,7 @@ export class TestServerContext implements ServerContext { return { appId: inst.appId, url: inst.url }; }); console.error( - `No connection instance found for ${url} - will return a mismatched instance, known instances: `, + 'No connection instance found for ' + url + ' - will return a mismatched instance, known instances: ', knownInstances ); return this.instances[0]; From b650a63d7c6668e6a60053af3048e40065f0e38b Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 19:14:56 +0000 Subject: [PATCH 37/90] Fixing remaining BrowserTypes imports --- .../src/channels/DefaultPrivateChannel.ts | 26 ++++++------- .../test/step-definitions/channels.steps.ts | 8 ++-- .../test/step-definitions/generic.steps.ts | 4 +- .../test/support/responses/ChannelState.ts | 38 +++++++++---------- .../support/responses/CreatePrivateChannel.ts | 8 ++-- .../test/support/responses/GetAppMetadata.ts | 5 +-- .../test/support/responses/Open.ts | 5 +-- .../test/support/responses/support.ts | 5 +-- .../src/messaging/MessagePortMessaging.ts | 8 ++-- .../test/support/MockFDC3Server.ts | 11 +++--- .../test/support/responses/CurrentChannel.ts | 5 +-- 11 files changed, 54 insertions(+), 69 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts index 438c6bef8..50738f200 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts @@ -6,7 +6,6 @@ import { PrivateChannel, PrivateChannelEventTypes, } from '@kite9/fdc3-standard'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { DefaultChannel } from './DefaultChannel'; import { Messaging } from '../Messaging'; import { @@ -17,9 +16,10 @@ import { } from '../listeners/PrivateChannelEventListener'; import { DefaultContextListener } from '../listeners/DefaultContextListener'; import { RegisterableListener } from '../listeners/RegisterableListener'; - -type PrivateChannelDisconnectRequest = BrowserTypes.PrivateChannelDisconnectRequest; -type PrivateChannelDisconnectResponse = BrowserTypes.PrivateChannelDisconnectResponse; +import { + PrivateChannelDisconnectRequest, + PrivateChannelDisconnectResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class DefaultPrivateChannel extends DefaultChannel implements PrivateChannel { constructor(messaging: Messaging, id: string) { @@ -80,16 +80,14 @@ export class DefaultPrivateChannel extends DefaultChannel implements PrivateChan } async disconnect(): Promise { - await this.messaging.exchange( - { - meta: this.messaging.createMeta(), - payload: { - channelId: this.id, - }, - type: 'privateChannelDisconnectRequest', - } as PrivateChannelDisconnectRequest, - 'privateChannelDisconnectResponse' - ); + const msg: PrivateChannelDisconnectRequest = { + meta: this.messaging.createMeta(), + payload: { + channelId: this.id, + }, + type: 'privateChannelDisconnectRequest', + }; + await this.messaging.exchange(msg, 'privateChannelDisconnectResponse'); } async addContextListenerInner(contextType: string | null, theHandler: ContextHandler): Promise { diff --git a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts index df76c6971..b297d3803 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts @@ -2,18 +2,16 @@ import { DataTable, Given, Then, When } from '@cucumber/cucumber'; import { Context } from '@kite9/fdc3-context'; import { handleResolve, matchData } from '@kite9/testing'; import { CustomWorld } from '../world/index'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { CHANNEL_STATE } from '@kite9/testing'; import { ApiEvent } from '@kite9/fdc3-standard'; import { + BroadcastEvent, ChannelChangedEvent, PrivateChannelOnAddContextListenerEvent, + PrivateChannelOnDisconnectEvent, + PrivateChannelOnUnsubscribeEvent, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -type BroadcastEvent = BrowserTypes.BroadcastEvent; -type PrivateChannelOnUnsubscribeEvent = BrowserTypes.PrivateChannelOnUnsubscribeEvent; -type PrivateChannelOnDisconnectEvent = BrowserTypes.PrivateChannelOnDisconnectEvent; - const contextMap: Record = { 'fdc3.instrument': { type: 'fdc3.instrument', diff --git a/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts index 8e4581d23..52ff5fd1c 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts @@ -10,7 +10,7 @@ import { } from '../../src'; import { SimpleIntentResolver, setupGenericSteps } from '@kite9/testing'; import { CHANNEL_STATE, SimpleChannelSelector } from '@kite9/testing/dist/src/agent'; -import { BrowserTypes } from '@kite9/fdc3-schema'; +import { HeartbeatEvent } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; Given('A Desktop Agent in {string}', async function (this: CustomWorld, field: string) { if (!this.messaging) { @@ -36,7 +36,7 @@ When('messaging receives a heartbeat event', function (this: CustomWorld) { payload: { timestamp: new Date(), }, - } as BrowserTypes.HeartbeatEvent); + } as HeartbeatEvent); }); setupGenericSteps(); diff --git a/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts b/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts index 3f6b36964..fb84afaa5 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts @@ -1,27 +1,25 @@ import { AutomaticResponse, TestMessaging } from '../TestMessaging'; import { Context } from '@kite9/fdc3-context'; - -import { BrowserTypes } from '@kite9/fdc3-schema'; - -type JoinUserChannelRequest = BrowserTypes.JoinUserChannelRequest; -type JoinUserChannelResponse = BrowserTypes.JoinUserChannelResponse; -type LeaveCurrentChannelResponse = BrowserTypes.LeaveCurrentChannelResponse; -type LeaveCurrentChannelRequest = BrowserTypes.LeaveCurrentChannelRequest; -type GetCurrentChannelRequest = BrowserTypes.GetCurrentChannelRequest; -type GetCurrentChannelResponse = BrowserTypes.GetCurrentChannelResponse; -type AddContextListenerRequest = BrowserTypes.AddContextListenerRequest; -type AddContextListenerResponse = BrowserTypes.AddContextListenerResponse; -type ContextListenerUnsubscribeRequest = BrowserTypes.ContextListenerUnsubscribeRequest; -type ContextListenerUnsubscribeResponse = BrowserTypes.ContextListenerUnsubscribeResponse; -type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest; -type GetCurrentContextResponse = BrowserTypes.GetCurrentContextResponse; -type BroadcastRequest = BrowserTypes.BroadcastRequest; -type BroadcastResponse = BrowserTypes.BroadcastResponse; -type AgentResponseMessage = BrowserTypes.AgentResponseMessage; - import { createResponseMeta } from './support'; import { v4 as uuidv4 } from 'uuid'; -import { AppRequestMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { + AddContextListenerRequest, + AddContextListenerResponse, + AgentResponseMessage, + AppRequestMessage, + BroadcastRequest, + BroadcastResponse, + ContextListenerUnsubscribeRequest, + ContextListenerUnsubscribeResponse, + GetCurrentChannelRequest, + GetCurrentChannelResponse, + GetCurrentContextRequest, + GetCurrentContextResponse, + JoinUserChannelRequest, + JoinUserChannelResponse, + LeaveCurrentChannelRequest, + LeaveCurrentChannelResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class ChannelState implements AutomaticResponse { private channelId: string | null = null; diff --git a/packages/fdc3-agent-proxy/test/support/responses/CreatePrivateChannel.ts b/packages/fdc3-agent-proxy/test/support/responses/CreatePrivateChannel.ts index 0ca94fb70..e91496c9d 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/CreatePrivateChannel.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/CreatePrivateChannel.ts @@ -1,11 +1,11 @@ +import { + CreatePrivateChannelRequest, + CreatePrivateChannelResponse, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { AutomaticResponse, TestMessaging } from '../TestMessaging'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { createResponseMeta } from './support'; import { v4 as uuidv4 } from 'uuid'; -type CreatePrivateChannelRequest = BrowserTypes.CreatePrivateChannelRequest; -type CreatePrivateChannelResponse = BrowserTypes.CreatePrivateChannelResponse; - export class CreatePrivateChannel implements AutomaticResponse { count: number = 0; diff --git a/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts b/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts index 917ac12e5..044dc6834 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/GetAppMetadata.ts @@ -1,10 +1,7 @@ +import { GetAppMetadataRequest, GetAppMetadataResponse } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { AutomaticResponse, TestMessaging } from '../TestMessaging'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { createResponseMeta } from './support'; -type GetAppMetadataRequest = BrowserTypes.GetAppMetadataRequest; -type GetAppMetadataResponse = BrowserTypes.GetAppMetadataResponse; - export class GetAppMetadata implements AutomaticResponse { filter(t: string) { return t == 'getAppMetadataRequest'; diff --git a/packages/fdc3-agent-proxy/test/support/responses/Open.ts b/packages/fdc3-agent-proxy/test/support/responses/Open.ts index 8fb4b7a7d..cfc7f012b 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/Open.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/Open.ts @@ -1,10 +1,7 @@ +import { OpenRequest, OpenResponse } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { AutomaticResponse, TestMessaging } from '../TestMessaging'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { createResponseMeta } from './support'; -type OpenRequest = BrowserTypes.OpenRequest; -type OpenResponse = BrowserTypes.OpenResponse; - export class Open implements AutomaticResponse { filter(t: string) { return t == 'openRequest'; diff --git a/packages/fdc3-agent-proxy/test/support/responses/support.ts b/packages/fdc3-agent-proxy/test/support/responses/support.ts index 26fdc3e60..a563bc393 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/support.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/support.ts @@ -1,9 +1,6 @@ -import { BrowserTypes } from '@kite9/fdc3-schema'; +import { AppRequestMessageMeta, AgentResponseMessageMeta } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { v4 as uuidv4 } from 'uuid'; -type AppRequestMessageMeta = BrowserTypes.AppRequestMessageMeta; -type AgentResponseMessageMeta = BrowserTypes.AgentResponseMessageMeta; - export function createResponseMeta(m: AppRequestMessageMeta): AgentResponseMessageMeta { return { requestUuid: m.requestUuid, diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index e78205b00..4ba98c43e 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -1,9 +1,11 @@ import { AbstractMessaging, RegisterableListener } from '@kite9/fdc3-agent-proxy'; import { AppIdentifier, GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; import { v4 as uuidv4 } from 'uuid'; -import { BrowserTypes } from '@kite9/fdc3-schema'; -import { AppRequestMessage, WebConnectionProtocol6Goodbye } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake; +import { + AppRequestMessage, + WebConnectionProtocol3Handshake, + WebConnectionProtocol6Goodbye, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; /** * Details needed to set up the Messaging instance and Desktop AgentDetails record diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index 77dd504b5..7940bbeb3 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -7,15 +7,14 @@ import { RaiseIntent } from './responses/RaiseIntent'; import { Handshake } from './responses/Handshake'; import { UserChannels } from './responses/UserChannels'; import { CurrentChannel } from './responses/CurrentChannel'; -import { BrowserTypes } from '@kite9/fdc3-schema'; import { GetInfo } from './responses/GetInfo'; - -type AppRequestMessage = BrowserTypes.AppRequestMessage; -type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL; -type WebConnectionProtocol3Handshake = BrowserTypes.WebConnectionProtocol3Handshake; +import { + AppRequestMessage, + WebConnectionProtocol2LoadURL, + WebConnectionProtocol3Handshake, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export const EMBED_URL = 'http://localhost:8080/static/da/embed.html'; - export const CHANNEL_SELECTOR_URL = 'https://mock.fdc3.com/channelSelector'; export const INTENT_RESOLVER_URL = 'https://mock.fdc3.com/resolver'; diff --git a/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts b/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts index e139f02e4..c1a5bea55 100644 --- a/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts +++ b/packages/fdc3-get-agent/test/support/responses/CurrentChannel.ts @@ -1,9 +1,8 @@ import { TestServerContext } from '../TestServerContext'; import { InstanceID } from '@kite9/fdc3-web-impl'; import { AutomaticResponse } from './AutomaticResponses'; -import { BrowserTypes } from '@kite9/fdc3-schema'; -type GetCurrentChannelRequest = BrowserTypes.GetCurrentChannelRequest; -type GetCurrentChannelResponse = BrowserTypes.GetCurrentChannelResponse; +import { GetCurrentChannelRequest, GetCurrentChannelResponse } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; + export class CurrentChannel implements AutomaticResponse { filter(t: string) { return t == 'getCurrentChannelRequest'; From 1ddc9d9543503bf8b65e1f229d2cdfa64d31483e Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 19:24:11 +0000 Subject: [PATCH 38/90] Further work on resolving logging semgrep complaints --- .../src/sessionStorage/DesktopAgentDetails.ts | 2 +- .../fdc3-get-agent/src/strategies/HelloHandler.ts | 2 +- packages/fdc3-get-agent/src/strategies/getAgent.ts | 3 +-- .../fdc3-get-agent/src/ui/AbstractUIComponent.ts | 2 +- packages/fdc3-get-agent/src/util/Logger.ts | 12 ++++++++---- packages/fdc3-get-agent/test/support/FrameTypes.ts | 7 +++---- .../fdc3-get-agent/test/support/TestServerContext.ts | 4 +++- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts index 8c2b892c5..06708fb9e 100644 --- a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts +++ b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts @@ -77,7 +77,7 @@ export function retrieveDesktopAgentDetails(identityUrl: string): DesktopAgentDe } else { //ignore it and post a warning Logger.warn( - `DesktopAgentDetails: Stored details do not meet minimum requirements and will be ignored:\n${JSON.stringify(theData)}` + `DesktopAgentDetails: Stored details do not meet minimum requirements and will be ignored:\n${JSON.stringify(theData, null, 2)}` ); return null; } diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index d732b0737..3f1d4069f 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -59,7 +59,7 @@ export class HelloHandler { }, }; - Logger.debug(`HelloHandler: Sending hello msg:\n${JSON.stringify(requestMessage)}`); + Logger.debug(`HelloHandler: Sending hello msg:\n${JSON.stringify(requestMessage, null, 2)}`); w.postMessage(requestMessage, { targetOrigin: origin }); } diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 1596cd108..9945d48c0 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -91,7 +91,7 @@ function initAgentPromise(options: GetAgentParams): Promise { return Promise.allSettled(promises).then(async results => { //review results const daResult = results.find(isFulfilled); - Logger.debug(`Discovery results: `, results); + Logger.debug(`Discovery results: ${JSON.stringify(results, null, 2)}`); if (daResult) { const selection = daResult.value; @@ -114,7 +114,6 @@ function initAgentPromise(options: GetAgentParams): Promise { const errors = results.filter(isRejected); //n.b. the Loaders throw string error messages, rather than Error objects - Logger.debug(`Discovery errors: ${JSON.stringify(errors)}`); const error = errors.find(aRejection => aRejection.reason !== AgentError.AgentNotFound); if (error) { throw new Error(error.reason); diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index 59edb032e..f4a720625 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -77,7 +77,7 @@ export abstract class AbstractUIComponent implements Connectable { const data = e.data; if (isFdc3UserInterfaceRestyle(data)) { - // console.log(`Restyling ${JSON.stringify(data.payload)}`) + Logger.debug(`Restyling ${JSON.stringify(data.payload, null, 2)}`); const css = data.payload.updatedCSS; this.themeContainer(css); } diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 55448675e..ce05766ef 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -6,7 +6,8 @@ const GET_AGENT_LOG_PREFIX = 'FDC3 getAgent: '; export class Logger { static debug(...params: any[]) { if (typeof params[0] === 'string') { - console.debug(pc.black(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); + const msg = GET_AGENT_LOG_PREFIX + params[0]; + console.debug(pc.black(pc.dim(msg)), ...params.slice(1)); } else { console.debug(pc.black(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } @@ -14,7 +15,8 @@ export class Logger { static log(...params: any[]) { if (typeof params[0] === 'string') { - console.log(pc.green(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); + const msg = GET_AGENT_LOG_PREFIX + params[0]; + console.log(pc.green(pc.dim(msg)), ...params.slice(1)); } else { console.log(pc.green(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } @@ -22,7 +24,8 @@ export class Logger { static warn(...params: any[]) { if (typeof params[0] === 'string') { - console.warn(pc.yellow(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); + const msg = GET_AGENT_LOG_PREFIX + params[0]; + console.warn(pc.yellow(pc.dim(msg)), ...params.slice(1)); } else { console.warn(pc.yellow(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } @@ -30,7 +33,8 @@ export class Logger { static error(...params: any[]) { if (typeof params[0] === 'string') { - console.error(pc.red(pc.dim(GET_AGENT_LOG_PREFIX + params[0])), ...params.slice(1)); + const msg = GET_AGENT_LOG_PREFIX + params[0]; + console.error(pc.red(pc.dim(msg)), ...params.slice(1)); } else { console.error(pc.red(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } diff --git a/packages/fdc3-get-agent/test/support/FrameTypes.ts b/packages/fdc3-get-agent/test/support/FrameTypes.ts index e74a57d96..03430f393 100644 --- a/packages/fdc3-get-agent/test/support/FrameTypes.ts +++ b/packages/fdc3-get-agent/test/support/FrameTypes.ts @@ -20,10 +20,9 @@ export function handleEmbeddedIframeComms(_value: string, parent: MockWindow, so if (isWebConnectionProtocol1Hello(data)) { console.debug( - 'Received hello message from' + - eventSource.name + - ' ' + - (eventSource == parent ? '(parent window): ' : 'NOT parent win): '), + 'Received hello message from: ', + eventSource.name, + eventSource == parent ? '(parent window): ' : '(NOT parent win): ', event.data ); const connection = cw.mockContext.getFirstInstance(); diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index fd9a92894..342b03dba 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -56,7 +56,9 @@ export class TestServerContext implements ServerContext { return { appId: inst.appId, url: inst.url }; }); console.error( - 'No connection instance found for ' + url + ' - will return a mismatched instance, known instances: ', + 'No connection instance found - will return a mismatched instance, url: ', + url, + '\nknown instances: ', knownInstances ); return this.instances[0]; From 0565704ff79a4bd0269e6d54d7455b3a47af4545 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 19:36:29 +0000 Subject: [PATCH 39/90] Further attempt to resolve SemGrep logging issues --- packages/fdc3-get-agent/src/strategies/getAgent.ts | 10 +++++++++- packages/fdc3-get-agent/src/util/Logger.ts | 12 ++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 9945d48c0..0656a48f6 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -91,7 +91,15 @@ function initAgentPromise(options: GetAgentParams): Promise { return Promise.allSettled(promises).then(async results => { //review results const daResult = results.find(isFulfilled); - Logger.debug(`Discovery results: ${JSON.stringify(results, null, 2)}`); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const replacer = (key: string, value: any) => { + if (key == 'value') { + return ''; + } else { + return value; + } + }; + Logger.debug(`Discovery results: ${JSON.stringify(results, replacer, 2)}`); if (daResult) { const selection = daResult.value; diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index ce05766ef..53a267b72 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -7,7 +7,8 @@ export class Logger { static debug(...params: any[]) { if (typeof params[0] === 'string') { const msg = GET_AGENT_LOG_PREFIX + params[0]; - console.debug(pc.black(pc.dim(msg)), ...params.slice(1)); + const furtherArgs = params.slice(1); + console.debug(pc.black(pc.dim(msg)), ...furtherArgs); } else { console.debug(pc.black(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } @@ -16,7 +17,8 @@ export class Logger { static log(...params: any[]) { if (typeof params[0] === 'string') { const msg = GET_AGENT_LOG_PREFIX + params[0]; - console.log(pc.green(pc.dim(msg)), ...params.slice(1)); + const furtherArgs = params.slice(1); + console.log(pc.green(pc.dim(msg)), ...furtherArgs); } else { console.log(pc.green(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } @@ -25,7 +27,8 @@ export class Logger { static warn(...params: any[]) { if (typeof params[0] === 'string') { const msg = GET_AGENT_LOG_PREFIX + params[0]; - console.warn(pc.yellow(pc.dim(msg)), ...params.slice(1)); + const furtherArgs = params.slice(1); + console.warn(pc.yellow(pc.dim(msg)), ...furtherArgs); } else { console.warn(pc.yellow(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } @@ -34,7 +37,8 @@ export class Logger { static error(...params: any[]) { if (typeof params[0] === 'string') { const msg = GET_AGENT_LOG_PREFIX + params[0]; - console.error(pc.red(pc.dim(msg)), ...params.slice(1)); + const furtherArgs = params.slice(1); + console.error(pc.red(pc.dim(msg)), ...furtherArgs); } else { console.error(pc.red(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); } From d1ced2374d4374c80f3fba2ed6d19fc766661aab Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 21:21:29 +0000 Subject: [PATCH 40/90] reworking Logger again to appease semgrep --- packages/fdc3-get-agent/src/util/Logger.ts | 42 ++++++++-------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 53a267b72..57f5168df 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -3,44 +3,30 @@ import pc from 'picocolors'; const GET_AGENT_LOG_PREFIX = 'FDC3 getAgent: '; +type ColorFn = (aString: string) => string; +const debugColor: ColorFn = value => pc.black(pc.dim(value)); +const logColor: ColorFn = value => pc.green(pc.dim(value)); +const warnColor: ColorFn = value => pc.yellow(value); +const errorColor: ColorFn = value => pc.red(value); + +const prefixAndColorize = (params: any[], colorFn: ColorFn): string[] => { + const prefixed = [GET_AGENT_LOG_PREFIX, ...params]; + return prefixed.map(value => colorFn(typeof value === 'string' ? value : JSON.stringify(value, null, 2))); +}; export class Logger { static debug(...params: any[]) { - if (typeof params[0] === 'string') { - const msg = GET_AGENT_LOG_PREFIX + params[0]; - const furtherArgs = params.slice(1); - console.debug(pc.black(pc.dim(msg)), ...furtherArgs); - } else { - console.debug(pc.black(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); - } + console.debug(...prefixAndColorize(params, debugColor)); } static log(...params: any[]) { - if (typeof params[0] === 'string') { - const msg = GET_AGENT_LOG_PREFIX + params[0]; - const furtherArgs = params.slice(1); - console.log(pc.green(pc.dim(msg)), ...furtherArgs); - } else { - console.log(pc.green(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); - } + console.log(...prefixAndColorize(params, logColor)); } static warn(...params: any[]) { - if (typeof params[0] === 'string') { - const msg = GET_AGENT_LOG_PREFIX + params[0]; - const furtherArgs = params.slice(1); - console.warn(pc.yellow(pc.dim(msg)), ...furtherArgs); - } else { - console.warn(pc.yellow(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); - } + console.warn(...prefixAndColorize(params, warnColor)); } static error(...params: any[]) { - if (typeof params[0] === 'string') { - const msg = GET_AGENT_LOG_PREFIX + params[0]; - const furtherArgs = params.slice(1); - console.error(pc.red(pc.dim(msg)), ...furtherArgs); - } else { - console.error(pc.red(pc.dim(GET_AGENT_LOG_PREFIX)), ...params); - } + console.error(...prefixAndColorize(params, errorColor)); } } From e39185b6a990398af487a8dba14852c4bb53c24a Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 10 Dec 2024 21:34:02 +0000 Subject: [PATCH 41/90] Output error stack traces in Logger --- packages/fdc3-get-agent/src/util/Logger.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 57f5168df..761d99425 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -11,8 +11,20 @@ const errorColor: ColorFn = value => pc.red(value); const prefixAndColorize = (params: any[], colorFn: ColorFn): string[] => { const prefixed = [GET_AGENT_LOG_PREFIX, ...params]; - return prefixed.map(value => colorFn(typeof value === 'string' ? value : JSON.stringify(value, null, 2))); + return prefixed.map(value => { + if (typeof value === 'string') { + //just color strings + return colorFn(value); + } else if (value && value.stack && value.message) { + //probably an error + return colorFn(value.stack); + } else { + //something else... lets hope it stringifies + return colorFn(JSON.stringify(value, null, 2)); + } + }); }; + export class Logger { static debug(...params: any[]) { console.debug(...prefixAndColorize(params, debugColor)); From b83b099367c0b9c92a496dfc552af002961cb726 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 11 Dec 2024 10:12:23 +0000 Subject: [PATCH 42/90] failoverhandler test coverage --- .../src/strategies/FailoverHandler.ts | 7 ++--- .../fdc3-get-agent/src/strategies/getAgent.ts | 10 +++++-- .../features/desktop-agent-strategy.feature | 26 +++++++++++++++++++ .../step-definitions/desktop-agent.steps.ts | 16 ++++++++++++ packages/testing/src/steps/generic.steps.ts | 16 +++++++++++- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts index 6b185f183..931dce7a4 100644 --- a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts @@ -73,11 +73,12 @@ export class FailoverHandler { //send a hello message this.helloHandler.sendWCP1Hello(failoverResult, '*'); } else { - Logger.error('Failover function returned an invalid result', failoverResult); - throw new Error(AgentError.InvalidFailover); + Logger.error('Failover function returned an invalid result: ', failoverResult); + throw AgentError.InvalidFailover; } } else { - throw new Error(AgentError.InvalidFailover); + Logger.error('Failover was not a function, actual type: ', typeof this.options.failover); + throw AgentError.InvalidFailover; } //if we received a WindowProxy from failover, and it sent us a handshake, try to validate its identity diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index 0656a48f6..dee756ca6 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -27,6 +27,8 @@ const isFulfilled = (input: PromiseSettledResult): input is PromiseFulfill */ let theAgentPromise: Promise | null = null; +const CLEAR_PROMISE_DELAY = 500; + export function clearAgentPromise() { theAgentPromise = null; } @@ -124,6 +126,8 @@ function initAgentPromise(options: GetAgentParams): Promise { //n.b. the Loaders throw string error messages, rather than Error objects const error = errors.find(aRejection => aRejection.reason !== AgentError.AgentNotFound); if (error) { + //Clear the promise so a fresh call could be made later + setTimeout(() => clearAgentPromise(), CLEAR_PROMISE_DELAY); throw new Error(error.reason); } else if (options.failover != undefined) { Logger.debug(`Calling failover fn...`); @@ -154,12 +158,14 @@ function initAgentPromise(options: GetAgentParams): Promise { return selection.agent; } catch (e) { //n.b. FailoverHandler throws Error Objects so we can return this directly - Logger.error('Desktop agent not found. Error reported during failover', e); - throw e; + Logger.error('Desktop agent not found. Error reported during failover: ', e); + throw new Error(e as string); } } else { //We didn't manage to find an agent. Logger.error('Desktop agent not found. No error reported during discovery.'); + //Clear the promise so a fresh call could be made later + setTimeout(() => clearAgentPromise(), CLEAR_PROMISE_DELAY); throw new Error(AgentError.AgentNotFound); } } diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index fa08cb586..00fe9e4ea 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -196,6 +196,32 @@ Scenario: Connecting but identity validation times out | 2.0 | cucumber-app | cucumber-provider | And I call "{desktopAgent}" with "disconnect" + Scenario: Failover Strategy returning an invalid result + Given "invalidFailover" is a function which returns a promise of "some string" + And I call getAgent for a promise result with the following options + | failover | timeoutMs | + | {invalidFailover} | 1000 | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And "{result}" is an error with message "InvalidFailover" + + Scenario: Failover that is not a function + Given I call getAgent for a promise result with the following options + | failover | timeoutMs | + | "some string" | 1000 | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And "{result}" is an error with message "InvalidFailover" + + Scenario: Failover with identity validation timeout + Given "dummyFailover2" is a function which opens an iframe for communications on "{childDoc}" but times out identity validation + And I call getAgent for a promise result with the following options + | failover | timeoutMs | + | {dummyFailover2} | 1000 | + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve within 10 seconds + And "{result}" is an error with message "ErrorOnConnect" + Scenario: Recover adaptor URL from SessionStorage Here, we recover the details of the session from the session state, obviating the need to make a request to the parent iframe. diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index 2f6fa1dce..ab181b93c 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -78,6 +78,22 @@ Given( } ); +Given( + '{string} is a function which opens an iframe for communications on {string} but times out identity validation', + function (this: CustomWorld, fn: string, doc: string) { + this.props[fn] = () => { + this.mockContext.open(dummyInstanceDetails[0].appId); + const document = handleResolve(doc, this) as MockDocument; + const ifrm = document.createElement('iframe'); + + this.mockFDC3Server = new MockFDC3Server(ifrm as unknown as MockIFrame, false, this.mockContext, true, true); + ifrm.setAttribute('src', EMBED_URL); + document.body.appendChild(ifrm); + return ifrm; + }; + } +); + Given('an existing app instance in {string}', async function (this: CustomWorld, field: string) { const uuid = this.mockContext.open(dummyInstanceDetails[0].appId); this.props[field] = uuid; diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index 3b9dc8d2b..842cc9707 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -9,7 +9,7 @@ import fs from 'fs'; import path from 'path'; export function setupGenericSteps() { - When('the promise {string} should resolve', async function (this: PropsWorld, field: string) { + Then('the promise {string} should resolve', async function (this: PropsWorld, field: string) { try { const promise = handleResolve(field, this); const object = await promise; @@ -19,6 +19,20 @@ export function setupGenericSteps() { } }); + Then( + 'the promise {string} should resolve within 10 seconds', + { timeout: 10 * 1000 }, + async function (this: PropsWorld, field: string) { + try { + const promise = handleResolve(field, this); + const object = await promise; + this.props['result'] = object; + } catch (error) { + this.props['result'] = error; + } + } + ); + When('I call {string} with {string}', async function (this: PropsWorld, field: string, fnName: string) { try { const object = handleResolve(field, this); From 0ea5b95a3d76dd4c5b8baa8f5fa974dec2e2bc56 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 11 Dec 2024 10:20:24 +0000 Subject: [PATCH 43/90] lint free fdc3-get-agent --- packages/fdc3-get-agent/src/ui/NullChannelSelector.ts | 8 ++------ packages/fdc3-get-agent/src/ui/NullIntentResolver.ts | 6 +----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts b/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts index 2caefa4b9..4303a32c6 100644 --- a/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts @@ -1,13 +1,9 @@ -import { Channel } from '@kite9/fdc3-standard'; import { Connectable } from '@kite9/fdc3-standard'; import { ChannelSelector } from '@kite9/fdc3-standard'; export class NullChannelSelector implements ChannelSelector, Connectable { async disconnect(): Promise {} - async connect(): Promise {} - - updateChannel(_channelId: string | null, _availableChannels: Channel[]): void {} - - setChannelChangeCallback(_callback: (channelId: string | null) => void): void {} + updateChannel(): void {} + setChannelChangeCallback(): void {} } diff --git a/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts b/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts index b2d52af16..3ea918ca8 100644 --- a/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts @@ -1,11 +1,7 @@ -import { AppIntent } from '@kite9/fdc3-standard'; import { IntentResolver, IntentResolutionChoice } from '@kite9/fdc3-standard'; -import { Context } from '@kite9/fdc3-context'; export class NullIntentResolver implements IntentResolver { async disconnect(): Promise {} - async connect(): Promise {} - - async chooseIntent(_appIntents: AppIntent[], _ctx: Context): Promise {} + async chooseIntent(): Promise {} } From 731b2ec40874eabb481264e78b65053a00fdc8ec Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 11 Dec 2024 12:05:20 +0000 Subject: [PATCH 44/90] lint in fdc3-web-impl --- .../src/heartbeat/HeartbeatSupport.ts | 1 + .../specification/appd.schema.json | 8 +- .../demo/src/client/da/DemoServerContext.ts | 103 ++++++++++++------ .../fdc3-web-impl/src/ServerContext.ts | 6 +- .../src/directory/BasicDirectory.ts | 4 +- .../src/handlers/BroadcastHandler.ts | 7 +- .../src/handlers/HeartbeatHandler.ts | 12 +- .../src/handlers/IntentHandler.ts | 32 +++--- .../fdc3-web-impl/src/handlers/OpenHandler.ts | 39 ++++--- .../fdc3-web-impl/src/handlers/support.ts | 4 +- 10 files changed, 126 insertions(+), 90 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts b/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts index de3f01131..b8bc221d3 100644 --- a/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts +++ b/packages/fdc3-agent-proxy/src/heartbeat/HeartbeatSupport.ts @@ -1,3 +1,4 @@ import { Connectable } from '@kite9/fdc3-standard'; +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface HeartbeatSupport extends Connectable {} diff --git a/packages/fdc3-standard/src/app-directory/specification/appd.schema.json b/packages/fdc3-standard/src/app-directory/specification/appd.schema.json index cd8987624..b4348c4be 100644 --- a/packages/fdc3-standard/src/app-directory/specification/appd.schema.json +++ b/packages/fdc3-standard/src/app-directory/specification/appd.schema.json @@ -656,7 +656,7 @@ }, "LaunchDetails": { "description": "The type specific launch details of the application. These details are intended to be vendor-agnostic and MAY be duplicated or overridden by details provided in the hostManifests object for a specific host.", - "anyOf": [ + "oneOf": [ { "$ref": "#/components/schemas/WebAppDetails" }, @@ -675,6 +675,7 @@ ] }, "WebAppDetails": { + "type": "object", "description": "Properties used to launch apps with `type: web`.", "required": [ "url" @@ -689,6 +690,7 @@ "additionalProperties": false }, "NativeAppDetails": { + "type": "object", "description": "Properties used to launch apps with `type: native` that are already installed on the device.", "required": [ "path" @@ -706,6 +708,7 @@ "additionalProperties": false }, "CitrixAppDetails": { + "type": "object", "description": "Properties used to launch apps virtualized apps with `type: citrix`.", "required": [ "alias" @@ -723,6 +726,7 @@ "additionalProperties": false }, "OnlineNativeAppDetails": { + "type": "object", "description": "Properties used to launch a native apps with `type: onlineNative` that have an online launcher, e.g. online ClickOnce app deployments.", "required": [ "url" @@ -737,7 +741,9 @@ "additionalProperties": false }, "OtherAppDetails": { + "type": "object", "description": "Apps with `type: other` are defined by a hostManifest and do not require other details.", + "properties": {}, "additionalProperties": false }, "HostManifests": { diff --git a/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts b/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts index 1167b739f..453159283 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts @@ -2,7 +2,7 @@ import { AppRegistration, Directory, DirectoryApp, InstanceID, ServerContext, St import { Socket } from 'socket.io-client'; import { v4 as uuid } from 'uuid'; import { FDC3_DA_EVENT } from '../../message-types'; -import { AppIdentifier, AppIntent, Context, OpenError } from '@kite9/fdc3'; +import { AppIdentifier, AppIntent, OpenError } from '@kite9/fdc3'; enum Opener { Tab, @@ -15,6 +15,11 @@ type DemoRegistration = AppRegistration & { url: string; }; +//Typeguard used to check if application launch details have a URL +function isWebAppLaunchDetails(details: object): details is { url: string } { + return (details as { url: string }).url !== undefined; +} + export class DemoServerContext implements ServerContext { private readonly socket: Socket; private readonly directory: Directory; @@ -25,7 +30,7 @@ export class DemoServerContext implements ServerContext { this.directory = directory; } - async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[], _context: Context): Promise { + async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[] /*, _context: Context*/): Promise { return appIntents; } @@ -48,7 +53,7 @@ export class DemoServerContext implements ServerContext { getOpener(): Opener { const cb = document.getElementById('opener') as HTMLInputElement; const val = cb.value; - var out: Opener = Opener[val as keyof typeof Opener]; //Works with --noImplicitAny + const out: Opener = Opener[val as keyof typeof Opener]; //Works with --noImplicitAny return out; } @@ -64,15 +69,6 @@ export class DemoServerContext implements ServerContext { this.socket.emit(FDC3_DA_EVENT, message, to); } - openFrame(url: string): Window { - var ifrm = document.createElement('iframe'); - ifrm.setAttribute('src', url); - ifrm.style.width = '640px'; - ifrm.style.height = '480px'; - document.body.appendChild(ifrm); - return ifrm.contentWindow!!; - } - goodbye(id: string) { this.connections = this.connections.filter(i => i.instanceId !== id); console.debug(`Closed instance`, id); @@ -82,20 +78,42 @@ export class DemoServerContext implements ServerContext { ); } - openTab(url: string): Window { - return window.open(url, '_blank')!!; + openFrame(url: string): Promise { + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', url); + iframe.style.width = '640px'; + iframe.style.height = '480px'; + document.body.appendChild(iframe); + + //wait for load event, after which contentWindow should not be null + const loadPromise = new Promise(resolve => { + iframe.onload = () => resolve(iframe.contentWindow); + }); + return loadPromise; + } + + openTab(url: string): Promise { + //n.b. There are cases where the window reference returned is null + // That can happen if the Cross-Origin-Opener-Policy opener policy is set (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) + // or a browser pop-up blocker gets in the way... + return Promise.resolve(window.open(url, '_blank')); } - openNested(url: string): Window { - var ifrm = document.createElement('iframe'); - ifrm.setAttribute('src', 'nested.html?url=' + url); - ifrm.style.width = '640px'; - ifrm.style.height = '480px'; - document.body.appendChild(ifrm); - return ifrm.contentWindow!!; + openNested(url: string): Promise { + const iframe = document.createElement('iframe'); + iframe.setAttribute('src', 'nested.html?url=' + url); + iframe.style.width = '640px'; + iframe.style.height = '480px'; + document.body.appendChild(iframe); + + //wait for load event, after which contentWindow should not be null + const loadPromise = new Promise(resolve => { + iframe.onload = () => resolve(iframe.contentWindow); + }); + return loadPromise; } - openUrl(url: string): Window { + async openUrl(url: string): Promise { const opener = this.getOpener(); switch (opener) { case Opener.Tab: @@ -110,19 +128,34 @@ export class DemoServerContext implements ServerContext { async open(appId: string): Promise { const details: DirectoryApp[] = this.directory.retrieveAppsById(appId) as DirectoryApp[]; if (details.length > 0) { - const url = (details[0].details as any)?.url ?? undefined; - const window = this.openUrl(url); - const instanceId: InstanceID = this.createUUID(); - const metadata = { - appId, - instanceId, - window, - url, - state: State.Pending, - }; - - this.setInstanceDetails(instanceId, metadata); - return instanceId; + const launchDetails = details[0].details; + if (isWebAppLaunchDetails(launchDetails)) { + const url = launchDetails.url ?? undefined; + const window = await this.openUrl(url); + if (window) { + const instanceId: InstanceID = this.createUUID(); + const metadata = { + appId, + instanceId, + window, + url, + state: State.Pending, + }; + + this.setInstanceDetails(instanceId, metadata); + return instanceId; + } else { + console.error( + 'We did not receive a window reference after launching app: ', + details[0], + '\nn.b. this may occur if a popup blocker prevented launch or the Cross-Origin-Opener-Policy opener policy is set' + ); + throw new Error(OpenError.ErrorOnLaunch); + } + } else { + console.error('Unable to launch app without a URL, app: ', details[0]); + throw new Error(OpenError.ErrorOnLaunch); + } } throw new Error(OpenError.AppNotFound); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts index 11eb74430..29de2f6fe 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts @@ -17,8 +17,8 @@ export type AppRegistration = { /** * This is a unique, long, unguessable string that identifies a particular instance of an app. * All messages arriving at the desktop agent will have this UUID attached to them. - * It is important that this is unguessable as it is a "password" of sorts used to - * identify the app between reconnections. + * It is important that this is unguessable as it is a shared secret used to identify the app + * when reconnecting after navigation or refresh. */ export type InstanceID = string; @@ -71,7 +71,7 @@ export interface ServerContext { getConnectedApps(): Promise; /** - * Return the list of all apps that have ever been registed with the ServerContext. + * Return the list of all apps that have ever been registered with the ServerContext. */ getAllApps(): Promise; diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts index df7efaedc..80053626c 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts @@ -43,11 +43,11 @@ export class BasicDirectory implements Directory { const lfAugmented = lfa.map(([key, value]) => { return { intentName: key, - ...(value as any), + ...value, appId: a.appId, }; }); - return lfAugmented as DirectoryIntent[]; + return lfAugmented; } retrieveAllIntents(): DirectoryIntent[] { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index 8d4ffd759..74fef4259 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -281,8 +281,8 @@ export class BroadcastHandler implements MessageHandler { } handleAddContextListenerRequest(arg0: AddContextListenerRequest, sc: ServerContext, from: FullAppIdentifier) { - var channelId = null; - var channelType = ChannelType.user; + let channelId = null; + let channelType = ChannelType.user; if (arg0.payload?.channelId) { const channel = this.getChannelById(arg0.payload?.channelId); @@ -395,7 +395,7 @@ export class BroadcastHandler implements MessageHandler { handleGetOrCreateRequest(arg0: GetOrCreateChannelRequest, sc: ServerContext, from: FullAppIdentifier) { const id = arg0.payload.channelId; - var channel = this.getChannelById(id); + let channel = this.getChannelById(id); if (channel) { if (channel.type != ChannelType.app) { errorResponse(sc, arg0, from, ChannelError.AccessDenied, 'getOrCreateChannelResponse'); @@ -462,7 +462,6 @@ export class BroadcastHandler implements MessageHandler { sc: ServerContext, contextType?: string ) { - console.log('invokePrivateChannelEventListeners', arguments); if (privateChannelId) { const msg: PrivateChannelEvents = { type: messageType, diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts index 490cba6fb..e2f660f52 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts @@ -51,7 +51,7 @@ export class HeartbeatHandler implements MessageHandler { this.sendHeartbeat(sc, app); // check when the last heartbeat happened - const lastHeartbeat = this.lastHeartbeats.get(app.instanceId!!); + const lastHeartbeat = this.lastHeartbeats.get(app.instanceId); const currentState = app.state; if (lastHeartbeat != undefined) { @@ -61,23 +61,23 @@ export class HeartbeatHandler implements MessageHandler { console.error( `Heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered connected.` ); - sc.setAppState(app.instanceId!!, State.Connected); + sc.setAppState(app.instanceId, State.Connected); } else if (timeSinceLastHeartbeat > disconnectedAfter && currentState == State.Connected) { console.error( `No heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered not responding.` ); - sc.setAppState(app.instanceId!!, State.NotResponding); + sc.setAppState(app.instanceId, State.NotResponding); } else if (timeSinceLastHeartbeat > deadAfter && currentState == State.NotResponding) { console.error( `No heartbeat from ${app.instanceId} for ${timeSinceLastHeartbeat}ms. App is considered terminated.` ); - sc.setAppState(app.instanceId!!, State.Terminated); + sc.setAppState(app.instanceId, State.Terminated); } else { // no action } } else { // start the clock - this.lastHeartbeats.set(app.instanceId!!, now); + this.lastHeartbeats.set(app.instanceId, now); } }); }); @@ -113,7 +113,7 @@ export class HeartbeatHandler implements MessageHandler { if (msg.type == 'heartbeatAcknowledgementRequest') { const app = sc.getInstanceDetails(from); if (app) { - this.lastHeartbeats.set(app.instanceId!!, new Date().getTime()); + this.lastHeartbeats.set(app.instanceId, new Date().getTime()); } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts index 9bfe3c622..1eb38e388 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts @@ -20,6 +20,8 @@ import { RaiseIntentRequest, RaiseIntentForContextRequest, IntentResultRequest, + AppRequestMessage, + AgentResponseMessage, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; type ListenerRegistration = { @@ -116,14 +118,14 @@ class PendingIntent { ) { this.complete = true; this.ih.pendingIntents.delete(this); - forwardRequest(this.r, { appId: arg0.appId, instanceId: arg0.instanceId! }, this.sc, this.ih); + forwardRequest(this.r, { appId: arg0.appId, instanceId: arg0.instanceId }, this.sc, this.ih); } } } export class IntentHandler implements MessageHandler { private readonly directory: Directory; - private readonly regs: ListenerRegistration[] = []; + private readonly registrations: ListenerRegistration[] = []; readonly pendingIntents: Set = new Set(); readonly pendingResolutions: Map = new Map(); readonly timeoutMs: number; @@ -145,7 +147,7 @@ export class IntentHandler implements MessageHandler { return out; } - async accept(msg: any, sc: ServerContext, uuid: InstanceID): Promise { + async accept(msg: AppRequestMessage, sc: ServerContext, uuid: InstanceID): Promise { const from = sc.getInstanceDetails(uuid); if (from == null) { @@ -175,9 +177,9 @@ export class IntentHandler implements MessageHandler { case 'intentResultRequest': return this.intentResultRequest(msg as IntentResultRequest, sc, from); } - } catch (e: any) { - const responseType = msg.type.replace(new RegExp('Request$'), 'Response'); - errorResponse(sc, msg, from, e.message ?? e, responseType); + } catch (e) { + const responseType = msg.type.replace(new RegExp('Request$'), 'Response') as AgentResponseMessage['type']; + errorResponse(sc, msg, from, (e as Error).message ?? e, responseType); } } @@ -218,9 +220,9 @@ export class IntentHandler implements MessageHandler { from: FullAppIdentifier ): void { const id = arg0.payload.listenerUUID; - const fi = this.regs.findIndex(e => e.listenerUUID == id); + const fi = this.registrations.findIndex(e => e.listenerUUID == id); if (fi > -1) { - this.regs.splice(fi, 1); + this.registrations.splice(fi, 1); successResponse(sc, arg0, from, {}, 'intentListenerUnsubscribeResponse'); } else { errorResponse(sc, arg0, from, 'Non-Existent Listener', 'intentListenerUnsubscribeResponse'); @@ -239,7 +241,7 @@ export class IntentHandler implements MessageHandler { listenerUUID: sc.createUUID(), }; - this.regs.push(lr); + this.registrations.push(lr); successResponse( sc, arg0, @@ -251,7 +253,7 @@ export class IntentHandler implements MessageHandler { ); // see if this intent listener is the destination for any pending intents - for (let x of this.pendingIntents) { + for (const x of this.pendingIntents) { x.accept(lr); if (x.complete) { this.pendingIntents.delete(x); @@ -260,7 +262,7 @@ export class IntentHandler implements MessageHandler { } hasListener(instanceId: string, intentName: string): boolean { - return this.regs.find(r => r.instanceId == instanceId && r.intentName == intentName) != null; + return this.registrations.find(r => r.instanceId == instanceId && r.intentName == intentName) != null; } async getRunningApps(appId: string, sc: ServerContext): Promise { @@ -275,7 +277,7 @@ export class IntentHandler implements MessageHandler { // app exists but needs starting const pi = new PendingIntent(arg0, sc, this, target); this.pendingIntents.add(pi); - sc.open(target?.appId!!).then(() => { + sc.open(target.appId).then(() => { return undefined; }); } @@ -638,12 +640,8 @@ export class IntentHandler implements MessageHandler { sc: ServerContext ): Promise { const activeApps = await sc.getConnectedApps(); - const matching = this.regs.filter(r => r.intentName == intentName); - - //console.log(`Matched listeners returned ${matching.length}`) + const matching = this.registrations.filter(r => r.intentName == intentName); const active = matching.filter(r => activeApps.find(a => a.instanceId == r.instanceId)); - //console.log(`Active listeners returned ${active.length}`) - return active; } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts index 85e6c6c12..549e6da61 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts @@ -120,12 +120,12 @@ export class OpenHandler implements MessageHandler { return this.handleValidate(msg as WebConnectionProtocol4ValidateAppIdentity, sc, uuid); } else if (isAddContextListenerRequest(msg)) { //handle context listener adds for pending applications (i.e. opened but awaiting context listener addition to deliver context) - // additional handling is performed BroadcastHandler + // additional handling is performed in BroadcastHandler return this.handleAddContextListener(msg as AddContextListenerRequest, sc, uuid); } else { const from = sc.getInstanceDetails(uuid); - try { - if (from) { + if (from) { + try { if (isOpenRequest(msg)) { return this.open(msg, sc, from); } else if (isFindInstancesRequest(msg)) { @@ -135,13 +135,13 @@ export class OpenHandler implements MessageHandler { } else if (isGetInfoRequest(msg)) { return this.getInfo(msg, sc, from); } - } else { - console.warn('Received message from unknown source, ignoring', msg, uuid); + } catch (e) { + const responseType = msg.type.replace(new RegExp('Request$'), 'Response') as AgentResponseMessage['type']; + //TODO: create a typeguard for response message types and use it to replace the 'as' below + errorResponse(sc, msg, from, (e as Error).message ?? e, responseType); } - } catch (e: any) { - const responseType = msg.type.replace(new RegExp('Request$'), 'Response'); - //TODO: create a typeguard for response message types and use it to replace the 'as' below - errorResponse(sc, msg, from!!, e.message ?? e, responseType as AgentResponseMessage['type']); + } else { + console.warn('Received message from unknown source, ignoring', msg, uuid); } } } @@ -157,6 +157,7 @@ export class OpenHandler implements MessageHandler { const pendingOpen = this.pending.get(from); if (pendingOpen) { + //TODO: Find out why this is asserted non-null - context is only sent to the user channel listener const channelId = arg0.payload.channelId!!; const contextType = arg0.payload.contextType; @@ -182,6 +183,7 @@ export class OpenHandler implements MessageHandler { pendingOpen.setDone(); this.pending.delete(from); + //TODO: find a better/more certain way to get teh destination for this message sc.post(message, arg0.meta.source?.instanceId!!); } } @@ -253,14 +255,13 @@ export class OpenHandler implements MessageHandler { try { const uuid = await sc.open(source.appId); this.pending.set(uuid, new PendingApp(sc, arg0, context, from, this.timeoutMs)); - } catch (e: any) { - errorResponse(sc, arg0, from, e.message, 'openResponse'); + } catch (e) { + errorResponse(sc, arg0, from, (e as Error).message ?? e, 'openResponse'); } } async getInfo(arg0: GetInfoRequest, sc: ServerContext, from: FullAppIdentifier): Promise { - const _this = this; - const implMetadata: ImplementationMetadata = _this.getImplementationMetadata(sc, { + const implMetadata: ImplementationMetadata = this.getImplementationMetadata(sc, { appId: from.appId, instanceId: from.instanceId, }); @@ -295,14 +296,12 @@ export class OpenHandler implements MessageHandler { sc: ServerContext, from: InstanceID ): Promise { - const _this = this; - const responseMeta = { connectionAttemptUuid: arg0.meta.connectionAttemptUuid, timestamp: new Date(), }; - function returnError() { + const returnError = () => { sc.post( { meta: responseMeta, @@ -313,10 +312,10 @@ export class OpenHandler implements MessageHandler { } as WebConnectionProtocol5ValidateAppIdentityFailedResponse, from ); - } + }; - function returnSuccess(appId: string, instanceId: string) { - const implMetadata: ImplementationMetadata = _this.getImplementationMetadata(sc, { appId, instanceId }); + const returnSuccess = (appId: string, instanceId: string) => { + const implMetadata: ImplementationMetadata = this.getImplementationMetadata(sc, { appId, instanceId }); const msg: WebConnectionProtocol5ValidateAppIdentitySuccessResponse = { meta: responseMeta, type: 'WCP5ValidateAppIdentityResponse', @@ -328,7 +327,7 @@ export class OpenHandler implements MessageHandler { }, }; sc.post(msg, instanceId); - } + }; if (arg0.payload.instanceUuid) { // existing app reconnecting diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts index a6def02e9..e745e8beb 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/support.ts @@ -17,7 +17,7 @@ export function successResponse( sc: ServerContext, request: AppRequestMessage, to: FullAppIdentifier, - payload: any, + payload: AgentResponseMessage['payload'], type: AgentResponseMessage['type'] ) { return successResponseId(sc, request.meta.requestUuid, to, payload, type); @@ -78,6 +78,6 @@ export function errorResponseId( /* * from: https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates#14438954 */ -export function onlyUnique(value: any, index: any, self: any) { +export function onlyUnique(value: X, index: number, self: X[]) { return self.indexOf(value) === index; } From 7304989366c8679eefebd004e47703207dde9934 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 11 Dec 2024 12:15:24 +0000 Subject: [PATCH 45/90] lint in fdc3-web-impl and reference-ui --- .../fdc3-web-impl/src/handlers/BroadcastHandler.ts | 4 ++-- toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts | 2 +- toolbox/fdc3-for-web/reference-ui/src/main.ts | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index 74fef4259..041e93dca 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -2,7 +2,7 @@ import { MessageHandler } from '../BasicFDC3Server'; import { InstanceID, ServerContext } from '../ServerContext'; import { Context } from '@kite9/fdc3-context'; import { AppIdentifier, ChannelError, DisplayMetadata, PrivateChannelEventTypes } from '@kite9/fdc3-standard'; -import { successResponse, errorResponse, onlyUnique, FullAppIdentifier } from './support'; +import { successResponse, errorResponse, FullAppIdentifier, onlyUnique } from './support'; import { AddContextListenerRequest, AgentResponseMessage, @@ -321,7 +321,7 @@ export class BroadcastHandler implements MessageHandler { .filter(r => r.channelId == arg0.payload.channelId) .filter(r => r.contextType == null || r.contextType == arg0.payload.context.type); - const matchingApps = matchingListeners + const matchingApps: FullAppIdentifier[] = matchingListeners .map(r => { return { appId: r.appId, instanceId: r.instanceId }; }) diff --git a/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts b/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts index a6627da29..329f34c57 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts @@ -31,7 +31,7 @@ const setup = ( intentSelect.appendChild(option); }); - intentSelect.addEventListener('change', (e: any) => + intentSelect.addEventListener('change', e => fillList( data.appIntents.filter(ai => ai.intent.name == e?.target?.value), e?.target?.value, diff --git a/toolbox/fdc3-for-web/reference-ui/src/main.ts b/toolbox/fdc3-for-web/reference-ui/src/main.ts index 7b167c608..75343bcdc 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/main.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/main.ts @@ -131,10 +131,16 @@ const openChannelIframe = (e: MouseEvent) => { channel.port1.onmessage = ({ data }) => { switch (data.type) { // User clicked on one of the channels in the channel selector - // @ts-ignore: Explicit fall-through to Fdc3UserInterfaceHandshake case FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE: { // STEP 4B: Receive user selection information from iframe selected = data.channel; + //Make sure UI receives message back about selection + channel.port1.postMessage({ + type: FDC3_USER_INTERFACE_CHANNELS_TYPE, + channels: recommendedChannels, + selected, + }); + break; } // Handshake completed. Send channel data to iframe From 4000f3d314d43044b9f7f796807a0e63f7328a46 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 11 Dec 2024 12:35:12 +0000 Subject: [PATCH 46/90] lint in demo --- .../fdc3-for-web/demo/src/client/apps/app6.ts | 10 ++- .../fdc3-for-web/demo/src/client/apps/app7.ts | 10 ++- .../demo/src/client/da/dummy-desktop-agent.ts | 87 ++++++++++--------- .../fdc3-for-web/demo/src/client/ui/drag.ts | 6 +- toolbox/fdc3-for-web/demo/src/server/main.ts | 14 +-- 5 files changed, 68 insertions(+), 59 deletions(-) diff --git a/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts b/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts index 632d92f7e..d98b2da4d 100644 --- a/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts +++ b/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts @@ -13,7 +13,11 @@ getAgent().then(async fdc3 => { }, }); - log!!.textContent = `Got resolution: ${JSON.stringify(reso)}`; - const result = await reso.getResult(); - log!!.textContent += `Got result: ${JSON.stringify(result)}`; + if (log) { + log.textContent = `Got resolution: ${JSON.stringify(reso)}`; + const result = await reso.getResult(); + log.textContent += `Got result: ${JSON.stringify(result)}`; + } else { + console.error("Unable to load resolution as the log element didn't exist!"); + } }); diff --git a/toolbox/fdc3-for-web/demo/src/client/apps/app7.ts b/toolbox/fdc3-for-web/demo/src/client/apps/app7.ts index 979c8b07a..643d3757a 100644 --- a/toolbox/fdc3-for-web/demo/src/client/apps/app7.ts +++ b/toolbox/fdc3-for-web/demo/src/client/apps/app7.ts @@ -13,7 +13,11 @@ getAgent().then(async fdc3 => { }, }); - log!!.textContent = `Got resolution: ${JSON.stringify(reso)}`; - const result = await reso.getResult(); - log!!.textContent += `Got result: ${JSON.stringify(result)}`; + if (log) { + log.textContent = `Got resolution: ${JSON.stringify(reso)}`; + const result = await reso.getResult(); + log.textContent += `Got result: ${JSON.stringify(result)}`; + } else { + console.error("Unable to load resolution as the log element didn't exist!"); + } }); diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index 7b9d19f46..52f08442d 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -34,19 +34,19 @@ enum Approach { function getApproach(): Approach { const cb = document.getElementById('approach') as HTMLInputElement; const val = cb.value; - var out: Approach = Approach[val as keyof typeof Approach]; //Works with --noImplicitAny + const out: Approach = Approach[val as keyof typeof Approach]; //Works with --noImplicitAny return out; } function getUIKey(): UI { const cb = document.getElementById('ui') as HTMLInputElement; const val = cb.value; - var out: UI = UI[val as keyof typeof UI]; //Works with --noImplicitAny + const out: UI = UI[val as keyof typeof UI]; //Works with --noImplicitAny return out; } window.addEventListener('load', () => { - let desktopAgentUUID = uuid(); + const desktopAgentUUID = uuid(); const socket = io(); @@ -94,48 +94,49 @@ window.addEventListener('load', () => { console.log('Received: ' + JSON.stringify(event.data)); if (data.type == 'WCP1Hello') { - if (getApproach() == Approach.IFRAME) { - const instance = sc.getInstanceForWindow(source); - source.postMessage( - { - type: 'WCP2LoadUrl', - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - iframeUrl: - window.location.origin + - `/static/da/embed.html?connectionAttemptUuid=${data.meta.connectionAttemptUuid}&desktopAgentId=${desktopAgentUUID}&instanceId=${instance?.instanceId}&UI=${getUIKey()}`, + const instance = sc.getInstanceForWindow(source); + if (instance) { + if (getApproach() == Approach.IFRAME) { + source.postMessage( + { + type: 'WCP2LoadUrl', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + iframeUrl: + window.location.origin + + `/static/da/embed.html?connectionAttemptUuid=${data.meta.connectionAttemptUuid}&desktopAgentId=${desktopAgentUUID}&instanceId=${instance.instanceId}&UI=${getUIKey()}`, + }, + } as WebConnectionProtocol2LoadURL, + origin + ); + } else { + const channel = new MessageChannel(); + link(socket, channel, instance.instanceId); + socket.emit(APP_HELLO, desktopAgentUUID, instance.instanceId); + const ui = UI_URLS[getUIKey()]; + + // send the other end of the channel to the app + source.postMessage( + { + type: 'WCP3Handshake', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + fdc3Version: '2.2', + ...ui, + }, }, - } as WebConnectionProtocol2LoadURL, - origin - ); + origin, + [channel.port1] + ); + } } else { - const instance = sc.getInstanceForWindow(source)!!; - const channel = new MessageChannel(); - link(socket, channel, instance.instanceId!!); - - socket.emit(APP_HELLO, desktopAgentUUID, instance.instanceId); - - const ui = UI_URLS[getUIKey()]; - - // send the other end of the channel to the app - source.postMessage( - { - type: 'WCP3Handshake', - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - fdc3Version: '2.2', - ...ui, - }, - }, - origin, - [channel.port1] - ); + console.error(`Couldn't locate an instance for Window.name: ${source.name}`); } } diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts b/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts index 579fe28dc..3d9bb5fc8 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts @@ -1,11 +1,11 @@ import { Position } from './channel-selector'; export function dragElement(drag: HTMLElement, selector: HTMLElement, position: Position) { - var posXDrag = 0, + let posXDrag = 0, posYDrag = 0, posXStart = 0, posYStart = 0; - var top = 0, + let top = 0, left = 0, screenX = 0, screenY = 0; @@ -25,7 +25,7 @@ export function dragElement(drag: HTMLElement, selector: HTMLElement, position: } function dragMouseDown(e: MouseEvent) { - console.log('astarting'); + console.log('starting'); e.preventDefault(); // get the mouse cursor position at startup: posXStart = e.clientX; diff --git a/toolbox/fdc3-for-web/demo/src/server/main.ts b/toolbox/fdc3-for-web/demo/src/server/main.ts index ddaa420f9..ee66dba2d 100644 --- a/toolbox/fdc3-for-web/demo/src/server/main.ts +++ b/toolbox/fdc3-for-web/demo/src/server/main.ts @@ -28,9 +28,9 @@ enum ConnectionType { const instances: Map = new Map(); io.on('connection', (socket: Socket) => { - var myInstance: ConnectedWorld | undefined; - var myId: string | undefined; - var connectionType: ConnectionType | undefined; + let myInstance: ConnectedWorld | undefined; + let myId: string | undefined; + let connectionType: ConnectionType | undefined; socket.on(DA_HELLO, function (id) { myId = id; @@ -76,7 +76,7 @@ io.on('connection', (socket: Socket) => { } if (myInstance != undefined) { - myInstance!!.server.emit(FDC3_APP_EVENT, data, from); + myInstance.server.emit(FDC3_APP_EVENT, data, from); } }); @@ -95,11 +95,11 @@ io.on('connection', (socket: Socket) => { if (myInstance) { if (connectionType == ConnectionType.DA) { console.log('DA disconnected: ' + myId); - instances.delete(myId!!); + instances.delete(myId!); } else { - myInstance.apps.delete(myId!!); + myInstance.apps.delete(myId!); console.log(`App Disconnected: ${myId} ( ${myInstance.apps.size} remaining )`); - myInstance.server.emit(APP_GOODBYE, myId!!); + myInstance.server.emit(APP_GOODBYE, myId!); } } }); From 29935c1a46c8d5aaa5e052983299325c999cfea5 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 12 Dec 2024 17:06:00 +0000 Subject: [PATCH 47/90] Addressing review feedback --- .../fdc3-agent-proxy/src/BasicDesktopAgent.ts | 3 +- .../src/apps/DefaultAppSupport.ts | 4 +- .../src/channels/DefaultChannel.ts | 43 +- .../src/channels/DefaultChannelSupport.ts | 18 +- .../src/intents/DefaultIntentSupport.ts | 29 +- .../src/listeners/HeartbeatListener.ts | 1 - .../src/messaging/AbstractMessaging.ts | 8 +- .../test/step-definitions/channels.steps.ts | 5 +- .../test/support/TestMessaging.ts | 8 - .../test/support/responses/ChannelState.ts | 14 +- .../support/responses/RegisterListeners.ts | 10 +- .../support/responses/UnsubscribeListeners.ts | 14 +- .../test/support/responses/support.ts | 7 +- .../src/sessionStorage/DesktopAgentDetails.ts | 5 +- .../src/strategies/PostMessageLoader.ts | 6 +- .../fdc3-get-agent/src/strategies/getAgent.ts | 18 +- src/bridging/BridgingTypes.ts | 6583 ----------------- 17 files changed, 84 insertions(+), 6692 deletions(-) delete mode 100644 src/bridging/BridgingTypes.ts diff --git a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts index e4f307103..662168d7c 100644 --- a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts +++ b/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts @@ -47,7 +47,8 @@ export class BasicDesktopAgent implements DesktopAgent, Connectable { case 'userChannelChanged': return this.channels.addChannelChangedEventHandler(handler); default: - throw new Error('UnknownEventType'); + console.warn(`Tried to add a listener for an unknown event type: ${type}`); + return Promise.reject(new Error('UnknownEventType')); } } diff --git a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts index 3f04d9b4b..8611a8bc8 100644 --- a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts @@ -45,7 +45,7 @@ export class DefaultAppSupport implements AppSupport { if (out.payload.appMetadata) { return out.payload.appMetadata; } else { - //should never happen as an error returned will be thrown + //defensive: unlikely to happen as an error returned should already have been thrown by exchange throw new Error(ResolveError.TargetAppUnavailable); } } @@ -67,7 +67,7 @@ export class DefaultAppSupport implements AppSupport { if (out.payload.appIdentifier) { return out.payload.appIdentifier; } else { - //should never happen as an error returned will be thrown + //defensive: unlikely to happen as an error returned should already have been thrown by exchange throw new Error(OpenError.AppNotFound); } } diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index 5891e2766..a256ea491 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -23,33 +23,28 @@ export class DefaultChannel implements Channel { } async broadcast(context: Context): Promise { - const done = await this.messaging.exchange( - { - meta: this.messaging.createMeta(), - payload: { - channelId: this.id, - context, - }, - type: 'broadcastRequest', - } as BroadcastRequest, - 'broadcastResponse' - ); - console.log('broadcast done', done); + const request: BroadcastRequest = { + meta: this.messaging.createMeta(), + payload: { + channelId: this.id, + context, + }, + type: 'broadcastRequest', + }; + await this.messaging.exchange(request, 'broadcastResponse'); } async getCurrentContext(contextType?: string | undefined): Promise { // first, ensure channel state is up-to-date - const response = await this.messaging.exchange( - { - meta: this.messaging.createMeta(), - payload: { - channelId: this.id, - contextType: contextType ?? null, - }, - type: 'getCurrentContextRequest', - } as GetCurrentContextRequest, - 'getCurrentContextResponse' - ); + const request: GetCurrentContextRequest = { + meta: this.messaging.createMeta(), + payload: { + channelId: this.id, + contextType: contextType ?? null, + }, + type: 'getCurrentContextRequest', + }; + const response = await this.messaging.exchange(request, 'getCurrentContextResponse'); return response.payload.context ?? null; } @@ -67,7 +62,7 @@ export class DefaultChannel implements Channel { } else if (typeof contextTypeOrHandler === 'string' && handler) { theContextType = contextTypeOrHandler; theHandler = handler; - } else if (contextTypeOrHandler) { + } else if (typeof contextTypeOrHandler === 'function') { // deprecated one-arg version theContextType = null; theHandler = contextTypeOrHandler as ContextHandler; diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index fd4fb6bb9..519ffaea0 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -85,14 +85,12 @@ export class DefaultChannelSupport implements ChannelSupport { } async getUserChannels(): Promise { - const response = await this.messaging.exchange( - { - meta: this.messaging.createMeta(), - type: 'getUserChannelsRequest', - payload: {}, - } as GetUserChannelsRequest, - 'getUserChannelsResponse' - ); + const request: GetUserChannelsRequest = { + meta: this.messaging.createMeta(), + type: 'getUserChannelsRequest', + payload: {}, + }; + const response = await this.messaging.exchange(request, 'getUserChannelsResponse'); //handle successful responses - errors will already have been thrown by exchange above if (response.payload.userChannels) { const channels = response.payload.userChannels; @@ -149,7 +147,9 @@ export class DefaultChannelSupport implements ChannelSupport { }; await this.messaging.exchange(request, 'leaveCurrentChannelResponse'); this.channelSelector.updateChannel(null, this.userChannels); - this.userChannelListeners.forEach(l => l.changeChannel(null)); + for (const l of this.userChannelListeners) { + await l.changeChannel(null); + } } async joinUserChannel(id: string) { diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index 1933d90f3..c78cd04ee 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -62,7 +62,7 @@ export class DefaultIntentSupport implements IntentSupport { } async findIntent(intent: string, context: Context, resultType: string | undefined): Promise { - const messageOut: FindIntentRequest = { + const request: FindIntentRequest = { type: 'findIntentRequest', payload: { intent, @@ -72,7 +72,7 @@ export class DefaultIntentSupport implements IntentSupport { meta: this.messaging.createMeta(), }; - const result = await this.messaging.exchange(messageOut, 'findIntentResponse'); + const result = await this.messaging.exchange(request, 'findIntentResponse'); const appIntent = result.payload.appIntent!; if (appIntent.apps.length == 0) { throw new Error(ResolveError.NoAppsFound); @@ -85,7 +85,7 @@ export class DefaultIntentSupport implements IntentSupport { } async findIntentsByContext(context: Context): Promise { - const messageOut: FindIntentsByContextRequest = { + const request: FindIntentsByContextRequest = { type: 'findIntentsByContextRequest', payload: { context, @@ -93,10 +93,7 @@ export class DefaultIntentSupport implements IntentSupport { meta: this.messaging.createMeta(), }; - const result: FindIntentsByContextResponse = await this.messaging.exchange( - messageOut, - 'findIntentsByContextResponse' - ); + const result: FindIntentsByContextResponse = await this.messaging.exchange(request, 'findIntentsByContextResponse'); const appIntents = result.payload.appIntents; if (!appIntents || appIntents.length == 0) { throw new Error(ResolveError.NoAppsFound); @@ -105,11 +102,9 @@ export class DefaultIntentSupport implements IntentSupport { } } - private async createResultPromise( - messageOut: RaiseIntentRequest | RaiseIntentForContextRequest - ): Promise { + private async createResultPromise(request: RaiseIntentRequest | RaiseIntentForContextRequest): Promise { const rp = await this.messaging.waitFor( - m => m.type == 'raiseIntentResultResponse' && m.meta.requestUuid == messageOut.meta.requestUuid + m => m.type == 'raiseIntentResultResponse' && m.meta.requestUuid == request.meta.requestUuid ); const ir = await convertIntentResult(rp, this.messaging); @@ -118,7 +113,7 @@ export class DefaultIntentSupport implements IntentSupport { async raiseIntent(intent: string, context: Context, app: AppIdentifier): Promise { const meta = this.messaging.createMeta(); - const messageOut: RaiseIntentRequest = { + const request: RaiseIntentRequest = { type: 'raiseIntentRequest', payload: { intent, @@ -128,9 +123,9 @@ export class DefaultIntentSupport implements IntentSupport { meta: meta, }; - const resultPromise = this.createResultPromise(messageOut); + const resultPromise = this.createResultPromise(request); const response = await this.messaging.exchange( - messageOut, + request, 'raiseIntentResponse', ResolveError.IntentDeliveryFailed ); @@ -157,7 +152,7 @@ export class DefaultIntentSupport implements IntentSupport { } async raiseIntentForContext(context: Context, app?: AppIdentifier | undefined): Promise { - const messageOut: RaiseIntentForContextRequest = { + const request: RaiseIntentForContextRequest = { type: 'raiseIntentForContextRequest', payload: { context, @@ -166,9 +161,9 @@ export class DefaultIntentSupport implements IntentSupport { meta: this.messaging.createMeta(), }; - const resultPromise = this.createResultPromise(messageOut); + const resultPromise = this.createResultPromise(request); const response = await this.messaging.exchange( - messageOut, + request, 'raiseIntentForContextResponse', ResolveError.IntentDeliveryFailed ); diff --git a/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts b/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts index 972159be9..a3e07be10 100644 --- a/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts @@ -30,7 +30,6 @@ export class HeartbeatListener implements RegisterableListener { heartbeatEventUuid: (_m as HeartbeatEvent).meta.eventUuid, }, } as HeartbeatAcknowledgementRequest); - //console.log("Heartbeat acknowledged") } async register(): Promise { diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index be51d4921..44fa51d6a 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -36,7 +36,13 @@ export abstract class AbstractMessaging implements Messaging { this.unregister(id); resolve(m); }, - } as RegisterableListener; + register: async () => { + this.register(l); + }, + unsubscribe: async () => { + this.unregister(id); + }, + }; this.register(l); diff --git a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts index b297d3803..7eb5bca35 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/channels.steps.ts @@ -178,11 +178,8 @@ Given('{string} pipes context to {string}', function (this: CustomWorld, context When('messaging receives {string}', function (this: CustomWorld, field: string) { const message = handleResolve(field, this); - //TODO: restore this - //this.log(`Sending: ${JSON.stringify(message)}`); console.log(`Sending: `, message); - - this.messaging!.receive(message, console.log); //this.log); + this.messaging!.receive(message, console.log); }); Then('messaging will have posts', function (this: CustomWorld, dt: DataTable) { diff --git a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts index 9e2ade74c..0fddc5711 100644 --- a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts +++ b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts @@ -239,12 +239,4 @@ export class TestMessaging extends AbstractMessaging { setIntentResult(o: PossibleIntentResult) { this.ir = o; } - - // retrieveInstanceUuid(): string | undefined { - // return (globalThis as any).instanceUuid; - // } - - // storeInstanceUuid(validationResponse: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): void { - // (globalThis as any).instanceUuid = validationResponse.payload.instanceUuid; - // } } diff --git a/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts b/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts index fb84afaa5..38ca98ff6 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/ChannelState.ts @@ -46,30 +46,30 @@ export class ChannelState implements AutomaticResponse { let out: AgentResponseMessage | null = null; switch (input.type) { case 'joinUserChannelRequest': - out = this.createJoinResponse(input as JoinUserChannelRequest); + out = this.createJoinResponse(input); break; case 'leaveCurrentChannelRequest': - out = this.createLeaveResponse(input as LeaveCurrentChannelRequest); + out = this.createLeaveResponse(input); break; case 'getCurrentChannelRequest': - out = this.createGetChannelResponse(input as GetCurrentChannelRequest); + out = this.createGetChannelResponse(input); break; case 'addContextListenerRequest': - out = this.createAddListenerResponse(input as AddContextListenerRequest); + out = this.createAddListenerResponse(input); break; case 'contextListenerUnsubscribeRequest': - out = this.createUnsubscribeResponse(input as ContextListenerUnsubscribeRequest); + out = this.createUnsubscribeResponse(input); break; case 'getCurrentContextRequest': - out = this.createGetContextResponse(input as GetCurrentContextRequest); + out = this.createGetContextResponse(input); break; case 'broadcastRequest': - out = this.createBroadcastResponse(input as BroadcastRequest); + out = this.createBroadcastResponse(input); break; } diff --git a/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts b/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts index 14f38412f..5fd5b4ff9 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/RegisterListeners.ts @@ -13,12 +13,12 @@ import { AutomaticResponse, TestMessaging } from '../TestMessaging'; import { createResponseMeta } from './support'; import { v4 as uuidv4 } from 'uuid'; -type requests = +type Requests = | AddContextListenerRequest | AddIntentListenerRequest | AddEventListenerRequest | PrivateChannelAddEventListenerRequest; -type responses = +type Responses = | AddContextListenerResponse | AddIntentListenerResponse | AddEventListenerResponse @@ -35,7 +35,7 @@ export class RegisterListeners implements AutomaticResponse { } action(input: AppRequestMessage, m: TestMessaging) { - const out = this.createResponse(input as requests); + const out = this.createResponse(input as Requests); setTimeout(() => { m.receive(out); @@ -43,11 +43,11 @@ export class RegisterListeners implements AutomaticResponse { return Promise.resolve(); } - private createResponse(i: requests): responses { + private createResponse(i: Requests): Responses { return { meta: createResponseMeta(i.meta), //TODO: use a typesafe method of creating response messages - type: i.type.replace('Request', 'Response') as responses['type'], + type: i.type.replace('Request', 'Response') as Responses['type'], payload: { listenerUUID: uuidv4(), }, diff --git a/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts b/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts index 2b4bbd0d2..7926d3669 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/UnsubscribeListeners.ts @@ -1,4 +1,5 @@ import { + AppRequestMessage, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, EventListenerUnsubscribeRequest, @@ -11,16 +12,17 @@ import { AutomaticResponse, TestMessaging } from '../TestMessaging'; import { createResponseMeta } from './support'; import { EventListenerUnsubscribeResponse } from '@kite9/fdc3-schema/dist/generated/api/BrowserTypes'; -type requests = +type Requests = | IntentListenerUnsubscribeRequest | PrivateChannelUnsubscribeEventListenerRequest | ContextListenerUnsubscribeRequest | EventListenerUnsubscribeRequest; -type responses = +type Responses = | IntentListenerUnsubscribeResponse | PrivateChannelUnsubscribeEventListenerResponse | ContextListenerUnsubscribeResponse | EventListenerUnsubscribeResponse; + export class UnsubscribeListeners implements AutomaticResponse { filter(t: string) { return ( @@ -31,8 +33,8 @@ export class UnsubscribeListeners implements AutomaticResponse { ); } - action(input: object, m: TestMessaging) { - const out = this.createResponse(input as requests); + action(input: AppRequestMessage, m: TestMessaging) { + const out = this.createResponse(input as Requests); setTimeout(() => { m.receive(out); @@ -40,10 +42,10 @@ export class UnsubscribeListeners implements AutomaticResponse { return Promise.resolve(); } - private createResponse(i: requests): responses { + private createResponse(i: Requests): Responses { return { meta: createResponseMeta(i.meta), - type: i.type.replace('Request', 'Response') as responses['type'], + type: i.type.replace('Request', 'Response') as Responses['type'], payload: {}, }; } diff --git a/packages/fdc3-agent-proxy/test/support/responses/support.ts b/packages/fdc3-agent-proxy/test/support/responses/support.ts index a563bc393..b62c9a3c5 100644 --- a/packages/fdc3-agent-proxy/test/support/responses/support.ts +++ b/packages/fdc3-agent-proxy/test/support/responses/support.ts @@ -1,11 +1,12 @@ -import { AppRequestMessageMeta, AgentResponseMessageMeta } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { AppRequestMessageMeta, AgentResponseMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { v4 as uuidv4 } from 'uuid'; -export function createResponseMeta(m: AppRequestMessageMeta): AgentResponseMessageMeta { - return { +export function createResponseMeta(m: AppRequestMessageMeta): AgentResponseMessage['meta'] { + const meta: AgentResponseMessage['meta'] = { requestUuid: m.requestUuid, responseUuid: uuidv4(), source: m.source, timestamp: new Date(), }; + return meta; } diff --git a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts index 06708fb9e..4c76c7e25 100644 --- a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts +++ b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts @@ -70,8 +70,11 @@ export function retrieveDesktopAgentDetails(identityUrl: string): DesktopAgentDe //check we got the minimum properties if ( typeof theData.agentType === 'string' && + theData.agentType && //TODO: check this is one of the enum values typeof theData.appId === 'string' && - typeof theData.instanceId === 'string' + theData.appId && + typeof theData.instanceId === 'string' && + theData.instanceId ) { return theData; } else { diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 5baf9e254..07b1591c4 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -9,7 +9,7 @@ import { Logger } from '../util/Logger'; /** * Recursive search for all possible parent frames (windows) that we may * target with the WCP. - * @param w window object to search + * @param startWindow window object to search * @param found window objects found so far */ function collectPossibleTargets(startWindow: Window, found: Window[]) { @@ -23,11 +23,11 @@ function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[] found.push(w); } - if (found.indexOf(w.opener) == -1 && w.opener != startWindow) { + if (w.opener) { _recursePossibleTargets(startWindow, w.opener, found); } - if (found.indexOf(w.parent) == -1 && w.parent != startWindow) { + if (w.parent != w) { _recursePossibleTargets(startWindow, w.parent, found); } } diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index dee756ca6..b9bb9773a 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -218,7 +218,7 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { }; async function handleSetWindowFdc3(da: DesktopAgent) { - if (!options.dontSetWindowFdc3 && globalThis.window.fdc3 == null) { + if (!options.dontSetWindowFdc3 && !globalThis.window.fdc3) { globalThis.window.fdc3 = da; globalThis.window.dispatchEvent(new Event('fdc3Ready')); } @@ -231,19 +231,3 @@ export const getAgent: GetAgentType = (params?: GetAgentParams) => { return theAgentPromise; }; - -/** - * Replaces the original fdc3Ready function from FDC3 2.0 with a new one that uses the - * new getAgent function. - * - * @param waitForMs Amount of time to wait before failing the promise (20 seconds is the default). - * @returns A DesktopAgent promise. - */ -export function fdc3Ready(waitForMs = DEFAULT_TIMEOUT_MS): Promise { - return getAgent({ - timeoutMs: waitForMs, - dontSetWindowFdc3: false, - channelSelector: true, - intentResolver: true, - }); -} diff --git a/src/bridging/BridgingTypes.ts b/src/bridging/BridgingTypes.ts deleted file mode 100644 index 9a15a3887..000000000 --- a/src/bridging/BridgingTypes.ts +++ /dev/null @@ -1,6583 +0,0 @@ -// To parse this data: -// -// import { Convert, AgentErrorResponseMessage, AgentRequestMessage, AgentResponseMessage, BridgeErrorResponseMessage, BridgeRequestMessage, BridgeResponseMessage, BroadcastAgentRequest, BroadcastBridgeRequest, ConnectionStepMessage, ConnectionStep2Hello, ConnectionStep3Handshake, ConnectionStep4AuthenticationFailed, ConnectionStep6ConnectedAgentsUpdate, FindInstancesAgentErrorResponse, FindInstancesAgentRequest, FindInstancesAgentResponse, FindInstancesBridgeErrorResponse, FindInstancesBridgeRequest, FindInstancesBridgeResponse, FindIntentAgentErrorResponse, FindIntentAgentRequest, FindIntentAgentResponse, FindIntentBridgeErrorResponse, FindIntentBridgeRequest, FindIntentBridgeResponse, FindIntentsByContextAgentErrorResponse, FindIntentsByContextAgentRequest, FindIntentsByContextAgentResponse, FindIntentsByContextBridgeErrorResponse, FindIntentsByContextBridgeRequest, FindIntentsByContextBridgeResponse, GetAppMetadataAgentErrorResponse, GetAppMetadataAgentRequest, GetAppMetadataAgentResponse, GetAppMetadataBridgeErrorResponse, GetAppMetadataBridgeRequest, GetAppMetadataBridgeResponse, OpenAgentErrorResponse, OpenAgentRequest, OpenAgentResponse, OpenBridgeErrorResponse, OpenBridgeRequest, OpenBridgeResponse, PrivateChannelBroadcastAgentRequest, PrivateChannelBroadcastBridgeRequest, PrivateChannelEventListenerAddedAgentRequest, PrivateChannelEventListenerAddedBridgeRequest, PrivateChannelEventListenerRemovedAgentRequest, PrivateChannelEventListenerRemovedBridgeRequest, PrivateChannelOnAddContextListenerAgentRequest, PrivateChannelOnAddContextListenerBridgeRequest, PrivateChannelOnDisconnectAgentRequest, PrivateChannelOnDisconnectBridgeRequest, PrivateChannelOnUnsubscribeAgentRequest, PrivateChannelOnUnsubscribeBridgeRequest, RaiseIntentAgentErrorResponse, RaiseIntentAgentRequest, RaiseIntentAgentResponse, RaiseIntentBridgeErrorResponse, RaiseIntentBridgeRequest, RaiseIntentBridgeResponse, RaiseIntentResultAgentErrorResponse, RaiseIntentResultAgentResponse, RaiseIntentResultBridgeErrorResponse, RaiseIntentResultBridgeResponse } from "./file"; -// -// const agentErrorResponseMessage = Convert.toAgentErrorResponseMessage(json); -// const agentRequestMessage = Convert.toAgentRequestMessage(json); -// const agentResponseMessage = Convert.toAgentResponseMessage(json); -// const bridgeErrorResponseMessage = Convert.toBridgeErrorResponseMessage(json); -// const bridgeRequestMessage = Convert.toBridgeRequestMessage(json); -// const bridgeResponseMessage = Convert.toBridgeResponseMessage(json); -// const broadcastAgentRequest = Convert.toBroadcastAgentRequest(json); -// const broadcastBridgeRequest = Convert.toBroadcastBridgeRequest(json); -// const bridgeCommonDefinitions = Convert.toBridgeCommonDefinitions(json); -// const connectionStepMessage = Convert.toConnectionStepMessage(json); -// const connectionStep2Hello = Convert.toConnectionStep2Hello(json); -// const connectionStep3Handshake = Convert.toConnectionStep3Handshake(json); -// const connectionStep4AuthenticationFailed = Convert.toConnectionStep4AuthenticationFailed(json); -// const connectionStep6ConnectedAgentsUpdate = Convert.toConnectionStep6ConnectedAgentsUpdate(json); -// const findInstancesAgentErrorResponse = Convert.toFindInstancesAgentErrorResponse(json); -// const findInstancesAgentRequest = Convert.toFindInstancesAgentRequest(json); -// const findInstancesAgentResponse = Convert.toFindInstancesAgentResponse(json); -// const findInstancesBridgeErrorResponse = Convert.toFindInstancesBridgeErrorResponse(json); -// const findInstancesBridgeRequest = Convert.toFindInstancesBridgeRequest(json); -// const findInstancesBridgeResponse = Convert.toFindInstancesBridgeResponse(json); -// const findIntentAgentErrorResponse = Convert.toFindIntentAgentErrorResponse(json); -// const findIntentAgentRequest = Convert.toFindIntentAgentRequest(json); -// const findIntentAgentResponse = Convert.toFindIntentAgentResponse(json); -// const findIntentBridgeErrorResponse = Convert.toFindIntentBridgeErrorResponse(json); -// const findIntentBridgeRequest = Convert.toFindIntentBridgeRequest(json); -// const findIntentBridgeResponse = Convert.toFindIntentBridgeResponse(json); -// const findIntentsByContextAgentErrorResponse = Convert.toFindIntentsByContextAgentErrorResponse(json); -// const findIntentsByContextAgentRequest = Convert.toFindIntentsByContextAgentRequest(json); -// const findIntentsByContextAgentResponse = Convert.toFindIntentsByContextAgentResponse(json); -// const findIntentsByContextBridgeErrorResponse = Convert.toFindIntentsByContextBridgeErrorResponse(json); -// const findIntentsByContextBridgeRequest = Convert.toFindIntentsByContextBridgeRequest(json); -// const findIntentsByContextBridgeResponse = Convert.toFindIntentsByContextBridgeResponse(json); -// const getAppMetadataAgentErrorResponse = Convert.toGetAppMetadataAgentErrorResponse(json); -// const getAppMetadataAgentRequest = Convert.toGetAppMetadataAgentRequest(json); -// const getAppMetadataAgentResponse = Convert.toGetAppMetadataAgentResponse(json); -// const getAppMetadataBridgeErrorResponse = Convert.toGetAppMetadataBridgeErrorResponse(json); -// const getAppMetadataBridgeRequest = Convert.toGetAppMetadataBridgeRequest(json); -// const getAppMetadataBridgeResponse = Convert.toGetAppMetadataBridgeResponse(json); -// const openAgentErrorResponse = Convert.toOpenAgentErrorResponse(json); -// const openAgentRequest = Convert.toOpenAgentRequest(json); -// const openAgentResponse = Convert.toOpenAgentResponse(json); -// const openBridgeErrorResponse = Convert.toOpenBridgeErrorResponse(json); -// const openBridgeRequest = Convert.toOpenBridgeRequest(json); -// const openBridgeResponse = Convert.toOpenBridgeResponse(json); -// const privateChannelBroadcastAgentRequest = Convert.toPrivateChannelBroadcastAgentRequest(json); -// const privateChannelBroadcastBridgeRequest = Convert.toPrivateChannelBroadcastBridgeRequest(json); -// const privateChannelEventListenerAddedAgentRequest = Convert.toPrivateChannelEventListenerAddedAgentRequest(json); -// const privateChannelEventListenerAddedBridgeRequest = Convert.toPrivateChannelEventListenerAddedBridgeRequest(json); -// const privateChannelEventListenerRemovedAgentRequest = Convert.toPrivateChannelEventListenerRemovedAgentRequest(json); -// const privateChannelEventListenerRemovedBridgeRequest = Convert.toPrivateChannelEventListenerRemovedBridgeRequest(json); -// const privateChannelOnAddContextListenerAgentRequest = Convert.toPrivateChannelOnAddContextListenerAgentRequest(json); -// const privateChannelOnAddContextListenerBridgeRequest = Convert.toPrivateChannelOnAddContextListenerBridgeRequest(json); -// const privateChannelOnDisconnectAgentRequest = Convert.toPrivateChannelOnDisconnectAgentRequest(json); -// const privateChannelOnDisconnectBridgeRequest = Convert.toPrivateChannelOnDisconnectBridgeRequest(json); -// const privateChannelOnUnsubscribeAgentRequest = Convert.toPrivateChannelOnUnsubscribeAgentRequest(json); -// const privateChannelOnUnsubscribeBridgeRequest = Convert.toPrivateChannelOnUnsubscribeBridgeRequest(json); -// const raiseIntentAgentErrorResponse = Convert.toRaiseIntentAgentErrorResponse(json); -// const raiseIntentAgentRequest = Convert.toRaiseIntentAgentRequest(json); -// const raiseIntentAgentResponse = Convert.toRaiseIntentAgentResponse(json); -// const raiseIntentBridgeErrorResponse = Convert.toRaiseIntentBridgeErrorResponse(json); -// const raiseIntentBridgeRequest = Convert.toRaiseIntentBridgeRequest(json); -// const raiseIntentBridgeResponse = Convert.toRaiseIntentBridgeResponse(json); -// const raiseIntentResultAgentErrorResponse = Convert.toRaiseIntentResultAgentErrorResponse(json); -// const raiseIntentResultAgentResponse = Convert.toRaiseIntentResultAgentResponse(json); -// const raiseIntentResultBridgeErrorResponse = Convert.toRaiseIntentResultBridgeErrorResponse(json); -// const raiseIntentResultBridgeResponse = Convert.toRaiseIntentResultBridgeResponse(json); -// -// These functions will throw an error if the JSON doesn't -// match the expected interface, even if the JSON is valid. - -/** - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface AgentErrorResponseMessage { - meta: AgentResponseMetadata; - /** - * Error message payload containing an standardized error string. - */ - payload: ErrorResponseMessagePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: ResponseMessageType; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface AgentResponseMetadata { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface ErrorResponseMessagePayload { - error: ResponseErrorDetail; - [property: string]: any; -} - -/** - * Array of error message strings for responses that were not returned to the bridge before - * the timeout or because an error occurred. Should be the same length as the `errorSources` - * array and ordered the same. May be omitted if all sources responded without errors. - * - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type ResponseErrorDetail = - | 'AccessDenied' - | 'CreationFailed' - | 'MalformedContext' - | 'NoChannelFound' - | 'AppNotFound' - | 'AppTimeout' - | 'DesktopAgentNotFound' - | 'ErrorOnLaunch' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution' - | 'IntentHandlerRejected' - | 'NoResultReturned' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ -export type ResponseMessageType = - | 'findInstancesResponse' - | 'findIntentResponse' - | 'findIntentsByContextResponse' - | 'getAppMetadataResponse' - | 'openResponse' - | 'raiseIntentResponse' - | 'raiseIntentResultResponse'; - -/** - * A request message from a Desktop Agent to the Bridge. - */ -export interface AgentRequestMessage { - meta: AgentRequestMetadata; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: RequestMessageType; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface AgentRequestMetadata { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: BridgeParticipantIdentifier; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceIdentifier; - timestamp: Date; -} - -/** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - * - * Represents identifiers that MUST include the Desktop Agent name and MAY identify a - * specific app or instance. - * - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface BridgeParticipantIdentifier { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - * - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent: string; - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - * - * Field that represents the source application that a request or response was received - * from, or the source Desktop Agent if it issued the request or response itself. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - */ -export interface SourceIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - * - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ -export type RequestMessageType = - | 'broadcastRequest' - | 'findInstancesRequest' - | 'findIntentRequest' - | 'findIntentsByContextRequest' - | 'getAppMetadataRequest' - | 'openRequest' - | 'PrivateChannel.broadcast' - | 'PrivateChannel.eventListenerAdded' - | 'PrivateChannel.eventListenerRemoved' - | 'PrivateChannel.onAddContextListener' - | 'PrivateChannel.onDisconnect' - | 'PrivateChannel.onUnsubscribe' - | 'raiseIntentRequest'; - -/** - * A response message from a Desktop Agent to the Bridge. - */ -export interface AgentResponseMessage { - meta: AgentResponseMetadata; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: ResponseMessageType; -} - -/** - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface BridgeErrorResponseMessage { - meta: BridgeErrorResponseMessageMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: ResponseErrorMessagePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: string; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface BridgeErrorResponseMessageMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - */ -export interface DesktopAgentIdentifier { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - */ - desktopAgent: string; - [property: string]: any; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface ResponseErrorMessagePayload { - error?: ResponseErrorDetail; - [property: string]: any; -} - -/** - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface BridgeRequestMessage { - meta: BridgeRequestMetadata; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: string; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface BridgeRequestMetadata { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: BridgeParticipantIdentifier; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: BridgeParticipantIdentifier; - timestamp: Date; -} - -/** - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface BridgeResponseMessage { - meta: BridgeResponseMessageMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: string; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface BridgeResponseMessageMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * A request to broadcast context on a channel. - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface BroadcastAgentRequest { - meta: BroadcastAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: BroadcastAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'broadcastRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface BroadcastAgentRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source: SourceObject; - timestamp: Date; -} - -/** - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - * - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - * - * Field that represents the source application that a request or response was received - * from, or the source Desktop Agent if it issued the request or response itself. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - */ -export interface SourceObject { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - * - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface BroadcastAgentRequestPayload { - /** - * The Id of the Channel that the broadcast was sent on. - */ - channelId: string; - /** - * The context object that is to be broadcast. - */ - context: Context; -} - -/** - * The context object that is to be broadcast. - * - * The context object that was the payload of a broadcast message. - * - * The `fdc3.context` type defines the basic contract or "shape" for all data exchanged by - * FDC3 operations. As such, it is not really meant to be used on its own, but is imported - * by more specific type definitions (standardized or custom) to provide the structure and - * properties shared by all FDC3 context data types. - * - * The key element of FDC3 context types is their mandatory `type` property, which is used - * to identify what type of data the object represents, and what shape it has. - * - * The FDC3 context type, and all derived types, define the minimum set of fields a context - * data object of a particular type can be expected to have, but this can always be extended - * with custom fields as appropriate. - */ -export interface Context { - /** - * Context data objects may include a set of equivalent key-value pairs that can be used to - * help applications identify and look up the context type they receive in their own domain. - * The idea behind this design is that applications can provide as many equivalent - * identifiers to a target application as possible, e.g. an instrument may be represented by - * an ISIN, CUSIP or Bloomberg identifier. - * - * Identifiers do not make sense for all types of data, so the `id` property is therefore - * optional, but some derived types may choose to require at least one identifier. - * Identifier values SHOULD always be of type string. - */ - id?: { [key: string]: any }; - /** - * Context data objects may include a name property that can be used for more information, - * or display purposes. Some derived types may require the name object as mandatory, - * depending on use case. - */ - name?: string; - /** - * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 - * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present - * to route shared context data appropriately. - * - * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data - * types they support in an FDC3 [App - * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery - * and routing. - * - * Standardized FDC3 context types have well-known `type` properties prefixed with the - * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and - * used by a particular organization, the convention is to prefix them with an - * organization-specific namespace, e.g. `blackrock.fund`. - * - * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more - * information about context data types. - */ - type: string; - [property: string]: any; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to broadcast context on a channel. - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface BroadcastBridgeRequest { - meta: BroadcastBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: BroadcastBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'broadcastRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface BroadcastBridgeRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - * - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - * - * Represents identifiers that MUST include the Desktop Agent name and MAY identify a - * specific app or instance. - * - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - */ -export interface MetaSource { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - * - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - */ - desktopAgent: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface BroadcastBridgeRequestPayload { - /** - * The Id of the Channel that the broadcast was sent on. - */ - channelId: string; - /** - * The context object that is to be broadcast. - */ - context: Context; -} - -/** - * A message used during the connection flow for a Desktop Agent to the Bridge. Used for - * messages sent in either direction. - */ -export interface ConnectionStepMessage { - meta: ConnectionStepMetadata; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: { [key: string]: any }; - /** - * Identifies the type of the connection step message. - */ - type: ConnectionStepMessageType; -} - -/** - * Metadata for this connection step message. - */ -export interface ConnectionStepMetadata { - requestUuid?: string; - responseUuid?: string; - timestamp: Date; -} - -/** - * Identifies the type of the connection step message. - */ -export type ConnectionStepMessageType = 'hello' | 'handshake' | 'authenticationFailed' | 'connectedAgentsUpdate'; - -/** - * Hello message sent by the Bridge to anyone connecting to the Bridge (enables - * identification as a bridge and confirmation of whether authentication is required) - * - * A message used during the connection flow for a Desktop Agent to the Bridge. Used for - * messages sent in either direction. - */ -export interface ConnectionStep2Hello { - meta: ConnectionStep2HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: ConnectionStep2HelloPayload; - /** - * Identifies the type of the connection step message. - */ - type: 'hello'; -} - -/** - * Metadata for this connection step message. - */ -export interface ConnectionStep2HelloMeta { - timestamp: Date; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface ConnectionStep2HelloPayload { - /** - * A flag indicating whether the Desktop Agent Bridge requires authentication or not. - */ - authRequired: boolean; - /** - * An optional Desktop Agent Bridge JWT authentication token if the Desktop Agent want to - * authenticate a bridge. - */ - authToken?: string; - /** - * The version of the Bridge - */ - desktopAgentBridgeVersion: string; - /** - * The FDC3 versions supported by the Bridge - */ - supportedFDC3Versions: string[]; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Handshake message sent by the Desktop Agent to the Bridge (including requested name, - * channel state and authentication data) - * - * A message used during the connection flow for a Desktop Agent to the Bridge. Used for - * messages sent in either direction. - */ -export interface ConnectionStep3Handshake { - meta: ConnectionStep3HandshakeMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: ConnectionStep3HandshakePayload; - /** - * Identifies the type of the connection step message. - */ - type: 'handshake'; -} - -/** - * Metadata for this connection step message. - */ -export interface ConnectionStep3HandshakeMeta { - requestUuid: string; - timestamp: Date; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface ConnectionStep3HandshakePayload { - authToken?: string; - /** - * The current state of the Desktop Agent's App and User channels (exclude any Private - * channels), as a mapping of channel id to an array of Context objects, one per type found - * in the channel, most recent first. - */ - channelsState: { [key: string]: Context[] }; - /** - * Desktop Agent ImplementationMetadata trying to connect to the bridge. - */ - implementationMetadata: ConnectingAgentImplementationMetadata; - /** - * The requested Desktop Agent name - */ - requestedName: string; -} - -/** - * Desktop Agent ImplementationMetadata trying to connect to the bridge. - * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. - */ -export interface ConnectingAgentImplementationMetadata { - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; -} - -/** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ -export interface OptionalFeatures { - /** - * Used to indicate whether the experimental Desktop Agent Bridging - * feature is implemented by the Desktop Agent. - */ - DesktopAgentBridging: boolean; - /** - * Used to indicate whether the exposure of 'originating app metadata' for - * context and intent messages is supported by the Desktop Agent. - */ - OriginatingAppMetadata: boolean; - /** - * Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent. - */ - UserChannelMembershipAPIs: boolean; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Message sent by Bridge to Desktop Agent if their authentication fails. - * - * A message used during the connection flow for a Desktop Agent to the Bridge. Used for - * messages sent in either direction. - */ -export interface ConnectionStep4AuthenticationFailed { - meta: ConnectionStep4AuthenticationFailedMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: ConnectionStep4AuthenticationFailedPayload; - /** - * Identifies the type of the connection step message. - */ - type: 'authenticationFailed'; -} - -/** - * Metadata for this connection step message. - */ -export interface ConnectionStep4AuthenticationFailedMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface ConnectionStep4AuthenticationFailedPayload { - message?: string; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * Message sent by Bridge to all Desktop Agent when an agent joins or leaves the bridge, - * includes the details of all agents, the change made and the expected channel state for - * all agents. - * - * A message used during the connection flow for a Desktop Agent to the Bridge. Used for - * messages sent in either direction. - */ -export interface ConnectionStep6ConnectedAgentsUpdate { - meta: ConnectionStep6ConnectedAgentsUpdateMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: ConnectionStep6ConnectedAgentsUpdatePayload; - /** - * Identifies the type of the connection step message. - */ - type: 'connectedAgentsUpdate'; -} - -/** - * Metadata for this connection step message. - */ -export interface ConnectionStep6ConnectedAgentsUpdateMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface ConnectionStep6ConnectedAgentsUpdatePayload { - /** - * Should be set when an agent first connects to the bridge and provide its assigned name. - */ - addAgent?: string; - /** - * Desktop Agent Bridge implementation metadata of all connected agents. - */ - allAgents: DesktopAgentImplementationMetadata[]; - /** - * The updated state of channels that should be adopted by the agents. Should only be set - * when an agent is connecting to the bridge. - */ - channelsState?: { [key: string]: Context[] }; - /** - * Should be set when an agent disconnects from the bridge and provide the name that no - * longer is assigned. - */ - removeAgent?: string; -} - -/** - * Includes the name assigned to the Desktop Agent by the Bridge. - * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. - */ -export interface DesktopAgentImplementationMetadata { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a particular Desktop - * Agent. - */ - desktopAgent: string; - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; -} - -/** - * Identifies the type of the connection step message. - */ - -/** - * A response to a findInstances request that contains an error. - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface FindInstancesAgentErrorResponse { - meta: FindInstancesAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: PayloadClass; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findInstancesResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface FindInstancesAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface PayloadClass { - error: FindInstancesErrors; -} - -/** - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - * - * Should be set if the raiseIntent request returned an error. - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - * - * Array of error message strings for responses that were not returned to the bridge before - * the timeout or because an error occurred. Should be the same length as the `errorSources` - * array and ordered the same. May be omitted if all sources responded without errors. - * - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - */ -export type FindInstancesErrors = - | 'DesktopAgentNotFound' - | 'IntentDeliveryFailed' - | 'MalformedContext' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'ResolverUnavailable' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request for details of instances of a particular app - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface FindInstancesAgentRequest { - meta: FindInstancesAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindInstancesAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'findInstancesRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface FindInstancesAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: DestinationObject; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceIdentifier; - timestamp: Date; -} - -/** - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - * - * Represents identifiers that MUST include the Desktop Agent name and MAY identify a - * specific app or instance. - * - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - * - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface DestinationObject { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - * - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent: string; - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindInstancesAgentRequestPayload { - app: AppIdentifier; -} - -/** - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A response to a findInstances request. - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface FindInstancesAgentResponse { - meta: AgentResponseMetadata; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: FindInstancesAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findInstancesResponse'; -} - -/** - * The message payload contains a flag indicating whether the API call was successful, plus - * any return values for the FDC3 API function called, or indicating that the request - * resulted in an error and including a standardized error message. - * - * The message payload typically contains return values for FDC3 API functions. - */ -export interface FindInstancesAgentResponsePayload { - appIdentifiers: AppMetadata[]; -} - -/** - * Extends an `AppIdentifier`, describing an application or instance of an application, with - * additional descriptive metadata that is usually provided by an FDC3 App Directory that - * the Desktop Agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such - * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon - * and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the - * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. - */ -export interface AppMetadata { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * A longer, multi-paragraph description for the application that could include markup. - */ - description?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * A list of icon URLs for the application that can be used to render UI elements. - */ - icons?: Icon[]; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - /** - * An optional set of, implementation specific, metadata fields that can be used to - * disambiguate instances, such as a window title or screen position. Must only be set if - * `instanceId` is set. - */ - instanceMetadata?: { [key: string]: any }; - /** - * The 'friendly' app name. - * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now - * require an `AppIdentifier` wth `appId` set. - * Note that for display purposes the `title` field should be used, if set, in preference to - * this field. - */ - name?: string; - /** - * The type of output returned for any intent specified during resolution. May express a - * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel - * that will receive a specified type (e.g. "channel"). - */ - resultType?: null | string; - /** - * Images representing the app in common usage scenarios that can be used to render UI - * elements. - */ - screenshots?: Image[]; - /** - * A more user-friendly application title that can be used to render UI elements. - */ - title?: string; - /** - * A tooltip for the application that can be used to render UI elements. - */ - tooltip?: string; - /** - * The Version of the application. - */ - version?: string; -} - -/** - * Describes an Icon image that may be used to represent the application. - */ -export interface Icon { - /** - * The icon dimension, formatted as `x`. - */ - size?: string; - /** - * The icon url. - */ - src: string; - /** - * Icon media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Describes an image file, typically a screenshot, that often represents the application in - * a common usage scenario. - */ -export interface Image { - /** - * Caption for the image. - */ - label?: string; - /** - * The image dimension, formatted as `x`. - */ - size?: string; - /** - * The image url. - */ - src: string; - /** - * Image media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * A response to a findInstances request that contains an error. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface FindInstancesBridgeErrorResponse { - meta: FindInstancesBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: MessagePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findInstancesResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface FindInstancesBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface MessagePayload { - error: FindInstancesErrors; -} - -/** - * A request for details of instances of a particular app - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface FindInstancesBridgeRequest { - meta: FindInstancesBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindInstancesBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'findInstancesRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface FindInstancesBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: DestinationObject; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSourceObject; - timestamp: Date; -} - -/** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - * - * Field that represents the source application that a request or response was received - * from, or the source Desktop Agent if it issued the request or response itself. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - * - * Represents identifiers that MUST include the Desktop Agent name and MAY identify a - * specific app or instance. - * - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - * - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - */ -export interface MetaSourceObject { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - * - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - */ - desktopAgent: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindInstancesBridgeRequestPayload { - app: AppIdentifier; -} - -/** - * A response to a findInstances request. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface FindInstancesBridgeResponse { - meta: BridgeResponseMessageMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: FindInstancesBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findInstancesResponse'; -} - -/** - * The message payload contains a flag indicating whether the API call was successful, plus - * any return values for the FDC3 API function called, or indicating that the request - * resulted in an error and including a standardized error message. - * - * The message payload typically contains return values for FDC3 API functions. - */ -export interface FindInstancesBridgeResponsePayload { - appIdentifiers: AppMetadata[]; -} - -/** - * A response to a findIntent request that contains an error. - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface FindIntentAgentErrorResponse { - meta: FindIntentAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: FindIntentAgentErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface FindIntentAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface FindIntentAgentErrorResponsePayload { - error: FindInstancesErrors; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request for details of apps available to resolve a particular intent and context pair. - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface FindIntentAgentRequest { - meta: FindIntentAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindIntentAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'findIntentRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface FindIntentAgentRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceIdentifier; - timestamp: Date; - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: BridgeParticipantIdentifier; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindIntentAgentRequestPayload { - context?: Context; - intent: string; - resultType?: string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A response to a findIntent request. - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface FindIntentAgentResponse { - meta: FindIntentAgentResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: FindIntentAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface FindIntentAgentResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface FindIntentAgentResponsePayload { - appIntent: AppIntent; -} - -/** - * An interface that relates an intent to apps. - */ -export interface AppIntent { - /** - * Details of applications that can resolve the intent. - */ - apps: AppMetadata[]; - /** - * Details of the intent whose relationship to resolving applications is being described. - */ - intent: IntentMetadata; -} - -/** - * Details of the intent whose relationship to resolving applications is being described. - * - * Metadata describing an Intent. - */ -export interface IntentMetadata { - /** - * Display name for the intent. - */ - displayName?: string; - /** - * The unique name of the intent that can be invoked by the raiseIntent call. - */ - name: string; -} - -/** - * A response to a findIntent request that contains an error. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface FindIntentBridgeErrorResponse { - meta: FindIntentBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: FindIntentBridgeErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface FindIntentBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface FindIntentBridgeErrorResponsePayload { - error: FindInstancesErrors; -} - -/** - * A request for details of apps available to resolve a particular intent and context pair. - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface FindIntentBridgeRequest { - meta: FindIntentBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindIntentBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'findIntentRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface FindIntentBridgeRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: BridgeParticipantIdentifier; - timestamp: Date; - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: BridgeParticipantIdentifier; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindIntentBridgeRequestPayload { - context?: Context; - intent: string; - resultType?: string; -} - -/** - * A response to a findIntent request. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface FindIntentBridgeResponse { - meta: FindIntentBridgeResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: FindIntentBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface FindIntentBridgeResponseMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface FindIntentBridgeResponsePayload { - appIntent: AppIntent; -} - -/** - * A response to a findIntentsByContext request that contains an error. - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface FindIntentsByContextAgentErrorResponse { - meta: FindIntentsByContextAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: FindIntentsByContextAgentErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentsByContextResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface FindIntentsByContextAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface FindIntentsByContextAgentErrorResponsePayload { - error: FindInstancesErrors; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request for details of intents and apps available to resolve them for a particular - * context. - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface FindIntentsByContextAgentRequest { - meta: FindIntentsByContextAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindIntentsByContextAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'findIntentsByContextRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface FindIntentsByContextAgentRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: BridgeParticipantIdentifier; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindIntentsByContextAgentRequestPayload { - context: Context; - resultType?: string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A response to a findIntentsByContext request. - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface FindIntentsByContextAgentResponse { - meta: FindIntentsByContextAgentResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: FindIntentsByContextAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentsByContextResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface FindIntentsByContextAgentResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface FindIntentsByContextAgentResponsePayload { - appIntents: AppIntent[]; -} - -/** - * A response to a findIntentsByContext request that contains an error. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface FindIntentsByContextBridgeErrorResponse { - meta: FindIntentsByContextBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: FindIntentsByContextBridgeErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentsByContextResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface FindIntentsByContextBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface FindIntentsByContextBridgeErrorResponsePayload { - error: FindInstancesErrors; -} - -/** - * A request for details of intents and apps available to resolve them for a particular - * context. - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface FindIntentsByContextBridgeRequest { - meta: FindIntentsByContextBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindIntentsByContextBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'findIntentsByContextRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface FindIntentsByContextBridgeRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: BridgeParticipantIdentifier; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface FindIntentsByContextBridgeRequestPayload { - context: Context; - resultType?: string; -} - -/** - * A response to a findIntentsByContext request. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface FindIntentsByContextBridgeResponse { - meta: FindIntentsByContextBridgeResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: FindIntentsByContextBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'findIntentsByContextResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface FindIntentsByContextBridgeResponseMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface FindIntentsByContextBridgeResponsePayload { - appIntents: AppIntent[]; -} - -/** - * A response to a getAppMetadata request that contains an error. - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface GetAppMetadataAgentErrorResponse { - meta: GetAppMetadataAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: GetAppMetadataAgentErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'getAppMetadataResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface GetAppMetadataAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface GetAppMetadataAgentErrorResponsePayload { - error: FindInstancesErrors; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request for metadata about an app - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface GetAppMetadataAgentRequest { - meta: GetAppMetadataAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetAppMetadataAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'getAppMetadataRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface GetAppMetadataAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: DestinationObject; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceIdentifier; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface GetAppMetadataAgentRequestPayload { - app: AppObject; -} - -/** - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppObject { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - * - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent: string; - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A response to a getAppMetadata request. - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface GetAppMetadataAgentResponse { - meta: GetAppMetadataAgentResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: GetAppMetadataAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'getAppMetadataResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface GetAppMetadataAgentResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface GetAppMetadataAgentResponsePayload { - appMetadata: AppMetadata; -} - -/** - * A response to a getAppMetadata request that contains an error. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface GetAppMetadataBridgeErrorResponse { - meta: GetAppMetadataBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: GetAppMetadataBridgeErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'getAppMetadataResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface GetAppMetadataBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface GetAppMetadataBridgeErrorResponsePayload { - error: FindInstancesErrors; -} - -/** - * A request for metadata about an app - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface GetAppMetadataBridgeRequest { - meta: GetAppMetadataBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetAppMetadataBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'getAppMetadataRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface GetAppMetadataBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: DestinationObject; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface GetAppMetadataBridgeRequestPayload { - app: AppObject; -} - -/** - * A response to a getAppMetadata request. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface GetAppMetadataBridgeResponse { - meta: GetAppMetadataBridgeResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: GetAppMetadataBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'getAppMetadataResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface GetAppMetadataBridgeResponseMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface GetAppMetadataBridgeResponsePayload { - appMetadata: AppMetadata; -} - -/** - * A response to an open request that contains an error - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface OpenAgentErrorResponse { - meta: OpenAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: OpenAgentErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'openResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface OpenAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface OpenAgentErrorResponsePayload { - error: OpenErrorResponsePayload; -} - -/** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Array of error message strings for responses that were not returned to the bridge before - * the timeout or because an error occurred. Should be the same length as the `errorSources` - * array and ordered the same. May be omitted if all sources responded without errors. - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type OpenErrorResponsePayload = - | 'AppNotFound' - | 'AppTimeout' - | 'DesktopAgentNotFound' - | 'ErrorOnLaunch' - | 'MalformedContext' - | 'ResolverUnavailable' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to open an application - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface OpenAgentRequest { - meta: OpenAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: OpenAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'openRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface OpenAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: DestinationObject; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface OpenAgentRequestPayload { - /** - * The application to open on the specified Desktop Agent - */ - app: AppToOpen; - context?: Context; -} - -/** - * The application to open on the specified Desktop Agent - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppToOpen { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - * - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent: string; - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A response to an open request - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface OpenAgentResponse { - meta: OpenAgentResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: OpenAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'openResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface OpenAgentResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface OpenAgentResponsePayload { - appIdentifier: AppIdentifier; -} - -/** - * A response to an open request that contains an error - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface OpenBridgeErrorResponse { - meta: OpenBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: OpenBridgeErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'openResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface OpenBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface OpenBridgeErrorResponsePayload { - error: OpenErrorResponsePayload; -} - -/** - * A request to open an application - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface OpenBridgeRequest { - meta: OpenBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: OpenBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'openRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface OpenBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: DestinationObject; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface OpenBridgeRequestPayload { - /** - * The application to open on the specified Desktop Agent - */ - app: AppToOpen; - context?: Context; -} - -/** - * A response to an open request - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface OpenBridgeResponse { - meta: OpenBridgeResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: OpenBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'openResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface OpenBridgeResponseMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface OpenBridgeResponsePayload { - appIdentifier: AppIdentifier; -} - -/** - * A request to broadcast on a PrivateChannel. - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface PrivateChannelBroadcastAgentRequest { - meta: PrivateChannelBroadcastAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelBroadcastAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.broadcast'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface PrivateChannelBroadcastAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; -} - -/** - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - * - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - * - * Represents identifiers that MUST include the Desktop Agent name and MAY identify a - * specific app or instance. - * - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ -export interface MetaDestination { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - * - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent: string; - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelBroadcastAgentRequestPayload { - /** - * The Id of the PrivateChannel that the broadcast was sent on - */ - channelId: string; - /** - * The context object that was the payload of a broadcast message. - */ - context: Context; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to broadcast on a PrivateChannel. - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface PrivateChannelBroadcastBridgeRequest { - meta: PrivateChannelBroadcastBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelBroadcastBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.broadcast'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface PrivateChannelBroadcastBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelBroadcastBridgeRequestPayload { - /** - * The Id of the PrivateChannel that the broadcast was sent on - */ - channelId: string; - /** - * The context object that was the payload of a broadcast message. - */ - context: Context; -} - -/** - * A request to forward on an EventListenerAdded event, relating to a PrivateChannel - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface PrivateChannelEventListenerAddedAgentRequest { - meta: PrivateChannelEventListenerAddedAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelEventListenerAddedAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.eventListenerAdded'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface PrivateChannelEventListenerAddedAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelEventListenerAddedAgentRequestPayload { - /** - * The id of the PrivateChannel that the event listener was added to. - */ - channelId: string; - listenerType: PrivateChannelEventListenerTypes; -} - -/** - * Event listener type names for Private Channel events. - */ -export type PrivateChannelEventListenerTypes = 'onAddContextListener' | 'onUnsubscribe' | 'onDisconnect'; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to forward on an EventListenerAdded event, relating to a PrivateChannel - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface PrivateChannelEventListenerAddedBridgeRequest { - meta: PrivateChannelEventListenerAddedBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelEventListenerAddedBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.eventListenerAdded'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface PrivateChannelEventListenerAddedBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelEventListenerAddedBridgeRequestPayload { - /** - * The id of the PrivateChannel that the event listener was added to. - */ - channelId: string; - listenerType: PrivateChannelEventListenerTypes; -} - -/** - * A request to forward on an EventListenerRemoved event, relating to a PrivateChannel - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface PrivateChannelEventListenerRemovedAgentRequest { - meta: PrivateChannelEventListenerRemovedAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelEventListenerRemovedAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.eventListenerRemoved'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface PrivateChannelEventListenerRemovedAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelEventListenerRemovedAgentRequestPayload { - /** - * The id of the PrivateChannel that the event listener was removed from. - */ - channelId: string; - listenerType: PrivateChannelEventListenerTypes; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to forward on an EventListenerRemoved event, relating to a PrivateChannel - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface PrivateChannelEventListenerRemovedBridgeRequest { - meta: PrivateChannelEventListenerRemovedBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelEventListenerRemovedBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.eventListenerRemoved'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface PrivateChannelEventListenerRemovedBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelEventListenerRemovedBridgeRequestPayload { - /** - * The id of the PrivateChannel that the event listener was removed from. - */ - channelId: string; - listenerType: PrivateChannelEventListenerTypes; -} - -/** - * A request to forward on an AddContextListener event, relating to a PrivateChannel - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface PrivateChannelOnAddContextListenerAgentRequest { - meta: PrivateChannelOnAddContextListenerAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelOnAddContextListenerAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.onAddContextListener'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface PrivateChannelOnAddContextListenerAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelOnAddContextListenerAgentRequestPayload { - /** - * The id of the PrivateChannel that the context listener was added to. - */ - channelId: string; - /** - * The type of the context listener added. Should be null for an untyped listener. - */ - contextType: null | string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to forward on an AddContextListener event, relating to a PrivateChannel - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface PrivateChannelOnAddContextListenerBridgeRequest { - meta: PrivateChannelOnAddContextListenerBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelOnAddContextListenerBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.onAddContextListener'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface PrivateChannelOnAddContextListenerBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelOnAddContextListenerBridgeRequestPayload { - /** - * The id of the PrivateChannel that the context listener was added to. - */ - channelId: string; - /** - * The type of the context listener added. Should be null for an untyped listener. - */ - contextType: null | string; -} - -/** - * A request to forward on a Disconnect event, relating to a PrivateChannel - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface PrivateChannelOnDisconnectAgentRequest { - meta: PrivateChannelOnDisconnectAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelOnDisconnectAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.onDisconnect'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface PrivateChannelOnDisconnectAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelOnDisconnectAgentRequestPayload { - /** - * The id of the PrivateChannel that the agent discconnected from. - */ - channelId: string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to forward on a Disconnect event, relating to a PrivateChannel - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface PrivateChannelOnDisconnectBridgeRequest { - meta: PrivateChannelOnDisconnectBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelOnDisconnectBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.onDisconnect'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface PrivateChannelOnDisconnectBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelOnDisconnectBridgeRequestPayload { - /** - * The id of the PrivateChannel that the agent discconnected from. - */ - channelId: string; -} - -/** - * A request to forward on an Unsubscribe event, relating to a PrivateChannel - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface PrivateChannelOnUnsubscribeAgentRequest { - meta: PrivateChannelOnUnsubscribeAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelOnUnsubscribeAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.onUnsubscribe'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface PrivateChannelOnUnsubscribeAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source?: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelOnUnsubscribeAgentRequestPayload { - /** - * The id of the PrivateChannel that the context listener was unsubscribed from. - */ - channelId: string; - /** - * The type of the context listener that was unsubscribed. Should be null for an untyped - * listener. - */ - contextType: null | string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to forward on an Unsubscribe event, relating to a PrivateChannel - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface PrivateChannelOnUnsubscribeBridgeRequest { - meta: ERequestMetadata; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelOnUnsubscribeBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'PrivateChannel.onUnsubscribe'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface ERequestMetadata { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination?: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelOnUnsubscribeBridgeRequestPayload { - /** - * The id of the PrivateChannel that the context listener was unsubscribed from. - */ - channelId: string; - /** - * The type of the context listener that was unsubscribed. Should be null for an untyped - * listener. - */ - contextType: null | string; -} - -/** - * A response to a request to raise an intent that contains an error. - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface RaiseIntentAgentErrorResponse { - meta: RaiseIntentAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: RaiseIntentAgentErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface RaiseIntentAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Used if a raiseIntent request resulted in an error. - * - * Error message payload containing an standardized error string. - */ -export interface RaiseIntentAgentErrorResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error: FindInstancesErrors; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A request to raise an intent. - * - * A request message from a Desktop Agent to the Bridge. - */ -export interface RaiseIntentAgentRequest { - meta: RaiseIntentAgentRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: RaiseIntentAgentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'raiseIntentRequest'; -} - -/** - * Metadata for a request message sent by Desktop Agents to the Bridge. - */ -export interface RaiseIntentAgentRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. - */ - source: SourceObject; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface RaiseIntentAgentRequestPayload { - app: AppDestinationIdentifier; - context: Context; - intent: string; -} - -/** - * Field that represents a destination App on a remote Desktop Agent that a request is to be - * sent to. - * - * Identifies a particular Desktop Agent in Desktop Agent Bridging scenarios - * where a request needs to be directed to a Desktop Agent rather than a specific app, or a - * response message is returned by the Desktop Agent (or more specifically its resolver) - * rather than a specific app. Used as a substitute for `AppIdentifier` in cases where no - * app details are available or are appropriate. - * - * Array of DesktopAgentIdentifiers for responses that were not returned to the bridge - * before the timeout or because an error occurred. May be omitted if all sources responded - * without errors. MUST include the `desktopAgent` field when returned by the bridge. - * - * Array of DesktopAgentIdentifiers for the sources that generated responses to the request. - * Will contain a single value for individual responses and multiple values for responses - * that were collated by the bridge. May be omitted if all sources errored. MUST include the - * `desktopAgent` field when returned by the bridge. - * - * Field that represents a destination Desktop Agent that a request is to be sent to. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that a request or response was received - * from. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppDestinationIdentifier { - /** - * Used in Desktop Agent Bridging to attribute or target a message to a - * particular Desktop Agent. - * - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent: string; - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A response to a request to raise an intent. - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface RaiseIntentAgentResponse { - meta: RaiseIntentAgentResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: RaiseIntentAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface RaiseIntentAgentResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface RaiseIntentAgentResponsePayload { - /** - * Used if the raiseIntent request was successfully resolved. - */ - intentResolution: IntentResolution; -} - -/** - * Used if the raiseIntent request was successfully resolved. - * - * IntentResolution provides a standard format for data returned upon resolving an intent. - * - * ```javascript - * //resolve a "Chain" type intent - * let resolution = await agent.raiseIntent("intentName", context); - * - * //resolve a "Client-Service" type intent with a data response or a Channel - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { - * console.log(`${resolution.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return data` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * - * // Use metadata about the resolving app instance to target a further intent - * await agent.raiseIntent("intentName", context, resolution.source); - * ``` - */ -export interface IntentResolution { - /** - * The intent that was raised. May be used to determine which intent the user - * chose in response to `fdc3.raiseIntentForContext()`. - */ - intent: string; - /** - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ - source: AppIdentifier; -} - -/** - * A response to a request to raise an intent that contains an error. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface RaiseIntentBridgeErrorResponse { - meta: RaiseIntentBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: RaiseIntentBridgeErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface RaiseIntentBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Used if a raiseIntent request resulted in an error. - * - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface RaiseIntentBridgeErrorResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error: FindInstancesErrors; -} - -/** - * A request to raise an intent. - * - * A request message forwarded from the Bridge onto a Desktop Agent connected to it. - */ -export interface RaiseIntentBridgeRequest { - meta: RaiseIntentBridgeRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: RaiseIntentBridgeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: 'raiseIntentRequest'; -} - -/** - * Metadata required in a request message forwarded on by the Bridge - */ -export interface RaiseIntentBridgeRequestMeta { - /** - * Optional field that represents the destination that the request should be routed to. Must - * be set by the Desktop Agent for API calls that include a target app parameter and must - * include the name of the Desktop Agent hosting the target application. - */ - destination: MetaDestination; - requestUuid: string; - /** - * Field that represents the source application that the request was received from, or the - * source Desktop Agent if it issued the request itself. The Desktop Agent identifier MUST - * be set by the bridge. - */ - source: MetaSource; - timestamp: Date; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface RaiseIntentBridgeRequestPayload { - app: AppDestinationIdentifier; - context: Context; - intent: string; -} - -/** - * A response to a request to raise an intent. - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface RaiseIntentBridgeResponse { - meta: RaiseIntentBridgeResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: RaiseIntentBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface RaiseIntentBridgeResponseMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface RaiseIntentBridgeResponsePayload { - /** - * Used if the raiseIntent request was successfully resolved. - */ - intentResolution: IntentResolution; -} - -/** - * A secondary response to a request to raise an intent used to deliver the intent result, - * which contains an error - * - * A response message from a Desktop Agent to the Bridge containing an error, to be used in - * preference to the standard response when an error needs to be returned. - */ -export interface RaiseIntentResultAgentErrorResponse { - meta: RaiseIntentResultAgentErrorResponseMeta; - /** - * Error message payload containing an standardized error string. - */ - payload: RaiseIntentResultAgentErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResultResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface RaiseIntentResultAgentErrorResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * Error message payload containing an standardized error string. - */ -export interface RaiseIntentResultAgentErrorResponsePayload { - error: RaiseIntentResultErrorMessage; -} - -/** - * Array of error message strings for responses that were not returned to the bridge before - * the timeout or because an error occurred. Should be the same length as the `errorSources` - * array and ordered the same. May be omitted if all sources responded without errors. - * - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type RaiseIntentResultErrorMessage = - | 'IntentHandlerRejected' - | 'NoResultReturned' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - */ - -/** - * A secondary response to a request to raise an intent used to deliver the intent result - * - * A response message from a Desktop Agent to the Bridge. - */ -export interface RaiseIntentResultAgentResponse { - meta: RaiseIntentResultAgentResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: RaiseIntentResultAgentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResultResponse'; -} - -/** - * Metadata for a response messages sent by a Desktop Agent to the Bridge - */ -export interface RaiseIntentResultAgentResponseMeta { - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface RaiseIntentResultAgentResponsePayload { - intentResult: IntentResult; -} - -export interface IntentResult { - context?: Context; - channel?: Channel; -} - -/** - * Represents a context channel that applications can use to send and receive - * context data. - * - * Please note that There are differences in behavior when you interact with a - * User channel via the `DesktopAgent` interface and the `Channel` interface. - * Specifically, when 'joining' a User channel or adding a context listener - * when already joined to a channel via the `DesktopAgent` interface, existing - * context (matching the type of the context listener) on the channel is - * received by the context listener immediately. Whereas, when a context - * listener is added via the Channel interface, context is not received - * automatically, but may be retrieved manually via the `getCurrentContext()` - * function. - */ -export interface Channel { - /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. - */ - displayMetadata?: DisplayMetadata; - /** - * Constant that uniquely identifies this channel. - */ - id: string; - /** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". - */ - type: Type; -} - -/** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. - * - * A system channel will be global enough to have a presence across many apps. This gives us - * some hints - * to render them in a standard way. It is assumed it may have other properties too, but if - * it has these, - * this is their meaning. - */ -export interface DisplayMetadata { - /** - * The color that should be associated within this channel when displaying this channel in a - * UI, e.g: `0xFF0000`. - */ - color?: string; - /** - * A URL of an image that can be used to display this channel. - */ - glyph?: string; - /** - * A user-readable name for this channel, e.g: `"Red"`. - */ - name?: string; -} - -/** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". - */ -export type Type = 'app' | 'private' | 'user'; - -/** - * A secondary response to a request to raise an intent used to deliver the intent result, - * which contains an error - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request, used where all connected agents returned errors. - */ -export interface RaiseIntentResultBridgeErrorResponse { - meta: RaiseIntentResultBridgeErrorResponseMeta; - /** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ - payload: RaiseIntentResultBridgeErrorResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResultResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface RaiseIntentResultBridgeErrorResponseMeta { - errorDetails: ResponseErrorDetail[]; - errorSources: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - timestamp: Date; -} - -/** - * The error message payload contains details of an error return to the app or agent that - * raised the original request. - */ -export interface RaiseIntentResultBridgeErrorResponsePayload { - error: RaiseIntentResultErrorMessage; -} - -/** - * A secondary response to a request to raise an intent used to deliver the intent result - * - * A response message from the Bridge back to the original Desktop Agent that raised the - * request. - */ -export interface RaiseIntentResultBridgeResponse { - meta: RaiseIntentResultBridgeResponseMeta; - /** - * The message payload typically contains return values for FDC3 API functions. - */ - payload: RaiseIntentResultBridgeResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'raiseIntentResultResponse'; -} - -/** - * Metadata required in a response message collated and/or forwarded on by the Bridge - */ -export interface RaiseIntentResultBridgeResponseMeta { - errorDetails?: ResponseErrorDetail[]; - errorSources?: DesktopAgentIdentifier[]; - requestUuid: string; - responseUuid: string; - sources?: DesktopAgentIdentifier[]; - timestamp: Date; -} - -/** - * The message payload typically contains return values for FDC3 API functions. - */ -export interface RaiseIntentResultBridgeResponsePayload { - intentResult: IntentResult; -} - -// Converts JSON strings to/from your types -// and asserts the results of JSON.parse at runtime -export class Convert { - public static toAgentErrorResponseMessage(json: string): AgentErrorResponseMessage { - return cast(JSON.parse(json), r('AgentErrorResponseMessage')); - } - - public static agentErrorResponseMessageToJson(value: AgentErrorResponseMessage): string { - return JSON.stringify(uncast(value, r('AgentErrorResponseMessage')), null, 2); - } - - public static toAgentRequestMessage(json: string): AgentRequestMessage { - return cast(JSON.parse(json), r('AgentRequestMessage')); - } - - public static agentRequestMessageToJson(value: AgentRequestMessage): string { - return JSON.stringify(uncast(value, r('AgentRequestMessage')), null, 2); - } - - public static toAgentResponseMessage(json: string): AgentResponseMessage { - return cast(JSON.parse(json), r('AgentResponseMessage')); - } - - public static agentResponseMessageToJson(value: AgentResponseMessage): string { - return JSON.stringify(uncast(value, r('AgentResponseMessage')), null, 2); - } - - public static toBridgeErrorResponseMessage(json: string): BridgeErrorResponseMessage { - return cast(JSON.parse(json), r('BridgeErrorResponseMessage')); - } - - public static bridgeErrorResponseMessageToJson(value: BridgeErrorResponseMessage): string { - return JSON.stringify(uncast(value, r('BridgeErrorResponseMessage')), null, 2); - } - - public static toBridgeRequestMessage(json: string): BridgeRequestMessage { - return cast(JSON.parse(json), r('BridgeRequestMessage')); - } - - public static bridgeRequestMessageToJson(value: BridgeRequestMessage): string { - return JSON.stringify(uncast(value, r('BridgeRequestMessage')), null, 2); - } - - public static toBridgeResponseMessage(json: string): BridgeResponseMessage { - return cast(JSON.parse(json), r('BridgeResponseMessage')); - } - - public static bridgeResponseMessageToJson(value: BridgeResponseMessage): string { - return JSON.stringify(uncast(value, r('BridgeResponseMessage')), null, 2); - } - - public static toBroadcastAgentRequest(json: string): BroadcastAgentRequest { - return cast(JSON.parse(json), r('BroadcastAgentRequest')); - } - - public static broadcastAgentRequestToJson(value: BroadcastAgentRequest): string { - return JSON.stringify(uncast(value, r('BroadcastAgentRequest')), null, 2); - } - - public static toBroadcastBridgeRequest(json: string): BroadcastBridgeRequest { - return cast(JSON.parse(json), r('BroadcastBridgeRequest')); - } - - public static broadcastBridgeRequestToJson(value: BroadcastBridgeRequest): string { - return JSON.stringify(uncast(value, r('BroadcastBridgeRequest')), null, 2); - } - - public static toBridgeCommonDefinitions(json: string): { [key: string]: any } { - return cast(JSON.parse(json), m('any')); - } - - public static bridgeCommonDefinitionsToJson(value: { [key: string]: any }): string { - return JSON.stringify(uncast(value, m('any')), null, 2); - } - - public static toConnectionStepMessage(json: string): ConnectionStepMessage { - return cast(JSON.parse(json), r('ConnectionStepMessage')); - } - - public static connectionStepMessageToJson(value: ConnectionStepMessage): string { - return JSON.stringify(uncast(value, r('ConnectionStepMessage')), null, 2); - } - - public static toConnectionStep2Hello(json: string): ConnectionStep2Hello { - return cast(JSON.parse(json), r('ConnectionStep2Hello')); - } - - public static connectionStep2HelloToJson(value: ConnectionStep2Hello): string { - return JSON.stringify(uncast(value, r('ConnectionStep2Hello')), null, 2); - } - - public static toConnectionStep3Handshake(json: string): ConnectionStep3Handshake { - return cast(JSON.parse(json), r('ConnectionStep3Handshake')); - } - - public static connectionStep3HandshakeToJson(value: ConnectionStep3Handshake): string { - return JSON.stringify(uncast(value, r('ConnectionStep3Handshake')), null, 2); - } - - public static toConnectionStep4AuthenticationFailed(json: string): ConnectionStep4AuthenticationFailed { - return cast(JSON.parse(json), r('ConnectionStep4AuthenticationFailed')); - } - - public static connectionStep4AuthenticationFailedToJson(value: ConnectionStep4AuthenticationFailed): string { - return JSON.stringify(uncast(value, r('ConnectionStep4AuthenticationFailed')), null, 2); - } - - public static toConnectionStep6ConnectedAgentsUpdate(json: string): ConnectionStep6ConnectedAgentsUpdate { - return cast(JSON.parse(json), r('ConnectionStep6ConnectedAgentsUpdate')); - } - - public static connectionStep6ConnectedAgentsUpdateToJson(value: ConnectionStep6ConnectedAgentsUpdate): string { - return JSON.stringify(uncast(value, r('ConnectionStep6ConnectedAgentsUpdate')), null, 2); - } - - public static toFindInstancesAgentErrorResponse(json: string): FindInstancesAgentErrorResponse { - return cast(JSON.parse(json), r('FindInstancesAgentErrorResponse')); - } - - public static findInstancesAgentErrorResponseToJson(value: FindInstancesAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('FindInstancesAgentErrorResponse')), null, 2); - } - - public static toFindInstancesAgentRequest(json: string): FindInstancesAgentRequest { - return cast(JSON.parse(json), r('FindInstancesAgentRequest')); - } - - public static findInstancesAgentRequestToJson(value: FindInstancesAgentRequest): string { - return JSON.stringify(uncast(value, r('FindInstancesAgentRequest')), null, 2); - } - - public static toFindInstancesAgentResponse(json: string): FindInstancesAgentResponse { - return cast(JSON.parse(json), r('FindInstancesAgentResponse')); - } - - public static findInstancesAgentResponseToJson(value: FindInstancesAgentResponse): string { - return JSON.stringify(uncast(value, r('FindInstancesAgentResponse')), null, 2); - } - - public static toFindInstancesBridgeErrorResponse(json: string): FindInstancesBridgeErrorResponse { - return cast(JSON.parse(json), r('FindInstancesBridgeErrorResponse')); - } - - public static findInstancesBridgeErrorResponseToJson(value: FindInstancesBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('FindInstancesBridgeErrorResponse')), null, 2); - } - - public static toFindInstancesBridgeRequest(json: string): FindInstancesBridgeRequest { - return cast(JSON.parse(json), r('FindInstancesBridgeRequest')); - } - - public static findInstancesBridgeRequestToJson(value: FindInstancesBridgeRequest): string { - return JSON.stringify(uncast(value, r('FindInstancesBridgeRequest')), null, 2); - } - - public static toFindInstancesBridgeResponse(json: string): FindInstancesBridgeResponse { - return cast(JSON.parse(json), r('FindInstancesBridgeResponse')); - } - - public static findInstancesBridgeResponseToJson(value: FindInstancesBridgeResponse): string { - return JSON.stringify(uncast(value, r('FindInstancesBridgeResponse')), null, 2); - } - - public static toFindIntentAgentErrorResponse(json: string): FindIntentAgentErrorResponse { - return cast(JSON.parse(json), r('FindIntentAgentErrorResponse')); - } - - public static findIntentAgentErrorResponseToJson(value: FindIntentAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('FindIntentAgentErrorResponse')), null, 2); - } - - public static toFindIntentAgentRequest(json: string): FindIntentAgentRequest { - return cast(JSON.parse(json), r('FindIntentAgentRequest')); - } - - public static findIntentAgentRequestToJson(value: FindIntentAgentRequest): string { - return JSON.stringify(uncast(value, r('FindIntentAgentRequest')), null, 2); - } - - public static toFindIntentAgentResponse(json: string): FindIntentAgentResponse { - return cast(JSON.parse(json), r('FindIntentAgentResponse')); - } - - public static findIntentAgentResponseToJson(value: FindIntentAgentResponse): string { - return JSON.stringify(uncast(value, r('FindIntentAgentResponse')), null, 2); - } - - public static toFindIntentBridgeErrorResponse(json: string): FindIntentBridgeErrorResponse { - return cast(JSON.parse(json), r('FindIntentBridgeErrorResponse')); - } - - public static findIntentBridgeErrorResponseToJson(value: FindIntentBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('FindIntentBridgeErrorResponse')), null, 2); - } - - public static toFindIntentBridgeRequest(json: string): FindIntentBridgeRequest { - return cast(JSON.parse(json), r('FindIntentBridgeRequest')); - } - - public static findIntentBridgeRequestToJson(value: FindIntentBridgeRequest): string { - return JSON.stringify(uncast(value, r('FindIntentBridgeRequest')), null, 2); - } - - public static toFindIntentBridgeResponse(json: string): FindIntentBridgeResponse { - return cast(JSON.parse(json), r('FindIntentBridgeResponse')); - } - - public static findIntentBridgeResponseToJson(value: FindIntentBridgeResponse): string { - return JSON.stringify(uncast(value, r('FindIntentBridgeResponse')), null, 2); - } - - public static toFindIntentsByContextAgentErrorResponse(json: string): FindIntentsByContextAgentErrorResponse { - return cast(JSON.parse(json), r('FindIntentsByContextAgentErrorResponse')); - } - - public static findIntentsByContextAgentErrorResponseToJson(value: FindIntentsByContextAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('FindIntentsByContextAgentErrorResponse')), null, 2); - } - - public static toFindIntentsByContextAgentRequest(json: string): FindIntentsByContextAgentRequest { - return cast(JSON.parse(json), r('FindIntentsByContextAgentRequest')); - } - - public static findIntentsByContextAgentRequestToJson(value: FindIntentsByContextAgentRequest): string { - return JSON.stringify(uncast(value, r('FindIntentsByContextAgentRequest')), null, 2); - } - - public static toFindIntentsByContextAgentResponse(json: string): FindIntentsByContextAgentResponse { - return cast(JSON.parse(json), r('FindIntentsByContextAgentResponse')); - } - - public static findIntentsByContextAgentResponseToJson(value: FindIntentsByContextAgentResponse): string { - return JSON.stringify(uncast(value, r('FindIntentsByContextAgentResponse')), null, 2); - } - - public static toFindIntentsByContextBridgeErrorResponse(json: string): FindIntentsByContextBridgeErrorResponse { - return cast(JSON.parse(json), r('FindIntentsByContextBridgeErrorResponse')); - } - - public static findIntentsByContextBridgeErrorResponseToJson(value: FindIntentsByContextBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('FindIntentsByContextBridgeErrorResponse')), null, 2); - } - - public static toFindIntentsByContextBridgeRequest(json: string): FindIntentsByContextBridgeRequest { - return cast(JSON.parse(json), r('FindIntentsByContextBridgeRequest')); - } - - public static findIntentsByContextBridgeRequestToJson(value: FindIntentsByContextBridgeRequest): string { - return JSON.stringify(uncast(value, r('FindIntentsByContextBridgeRequest')), null, 2); - } - - public static toFindIntentsByContextBridgeResponse(json: string): FindIntentsByContextBridgeResponse { - return cast(JSON.parse(json), r('FindIntentsByContextBridgeResponse')); - } - - public static findIntentsByContextBridgeResponseToJson(value: FindIntentsByContextBridgeResponse): string { - return JSON.stringify(uncast(value, r('FindIntentsByContextBridgeResponse')), null, 2); - } - - public static toGetAppMetadataAgentErrorResponse(json: string): GetAppMetadataAgentErrorResponse { - return cast(JSON.parse(json), r('GetAppMetadataAgentErrorResponse')); - } - - public static getAppMetadataAgentErrorResponseToJson(value: GetAppMetadataAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('GetAppMetadataAgentErrorResponse')), null, 2); - } - - public static toGetAppMetadataAgentRequest(json: string): GetAppMetadataAgentRequest { - return cast(JSON.parse(json), r('GetAppMetadataAgentRequest')); - } - - public static getAppMetadataAgentRequestToJson(value: GetAppMetadataAgentRequest): string { - return JSON.stringify(uncast(value, r('GetAppMetadataAgentRequest')), null, 2); - } - - public static toGetAppMetadataAgentResponse(json: string): GetAppMetadataAgentResponse { - return cast(JSON.parse(json), r('GetAppMetadataAgentResponse')); - } - - public static getAppMetadataAgentResponseToJson(value: GetAppMetadataAgentResponse): string { - return JSON.stringify(uncast(value, r('GetAppMetadataAgentResponse')), null, 2); - } - - public static toGetAppMetadataBridgeErrorResponse(json: string): GetAppMetadataBridgeErrorResponse { - return cast(JSON.parse(json), r('GetAppMetadataBridgeErrorResponse')); - } - - public static getAppMetadataBridgeErrorResponseToJson(value: GetAppMetadataBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('GetAppMetadataBridgeErrorResponse')), null, 2); - } - - public static toGetAppMetadataBridgeRequest(json: string): GetAppMetadataBridgeRequest { - return cast(JSON.parse(json), r('GetAppMetadataBridgeRequest')); - } - - public static getAppMetadataBridgeRequestToJson(value: GetAppMetadataBridgeRequest): string { - return JSON.stringify(uncast(value, r('GetAppMetadataBridgeRequest')), null, 2); - } - - public static toGetAppMetadataBridgeResponse(json: string): GetAppMetadataBridgeResponse { - return cast(JSON.parse(json), r('GetAppMetadataBridgeResponse')); - } - - public static getAppMetadataBridgeResponseToJson(value: GetAppMetadataBridgeResponse): string { - return JSON.stringify(uncast(value, r('GetAppMetadataBridgeResponse')), null, 2); - } - - public static toOpenAgentErrorResponse(json: string): OpenAgentErrorResponse { - return cast(JSON.parse(json), r('OpenAgentErrorResponse')); - } - - public static openAgentErrorResponseToJson(value: OpenAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('OpenAgentErrorResponse')), null, 2); - } - - public static toOpenAgentRequest(json: string): OpenAgentRequest { - return cast(JSON.parse(json), r('OpenAgentRequest')); - } - - public static openAgentRequestToJson(value: OpenAgentRequest): string { - return JSON.stringify(uncast(value, r('OpenAgentRequest')), null, 2); - } - - public static toOpenAgentResponse(json: string): OpenAgentResponse { - return cast(JSON.parse(json), r('OpenAgentResponse')); - } - - public static openAgentResponseToJson(value: OpenAgentResponse): string { - return JSON.stringify(uncast(value, r('OpenAgentResponse')), null, 2); - } - - public static toOpenBridgeErrorResponse(json: string): OpenBridgeErrorResponse { - return cast(JSON.parse(json), r('OpenBridgeErrorResponse')); - } - - public static openBridgeErrorResponseToJson(value: OpenBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('OpenBridgeErrorResponse')), null, 2); - } - - public static toOpenBridgeRequest(json: string): OpenBridgeRequest { - return cast(JSON.parse(json), r('OpenBridgeRequest')); - } - - public static openBridgeRequestToJson(value: OpenBridgeRequest): string { - return JSON.stringify(uncast(value, r('OpenBridgeRequest')), null, 2); - } - - public static toOpenBridgeResponse(json: string): OpenBridgeResponse { - return cast(JSON.parse(json), r('OpenBridgeResponse')); - } - - public static openBridgeResponseToJson(value: OpenBridgeResponse): string { - return JSON.stringify(uncast(value, r('OpenBridgeResponse')), null, 2); - } - - public static toPrivateChannelBroadcastAgentRequest(json: string): PrivateChannelBroadcastAgentRequest { - return cast(JSON.parse(json), r('PrivateChannelBroadcastAgentRequest')); - } - - public static privateChannelBroadcastAgentRequestToJson(value: PrivateChannelBroadcastAgentRequest): string { - return JSON.stringify(uncast(value, r('PrivateChannelBroadcastAgentRequest')), null, 2); - } - - public static toPrivateChannelBroadcastBridgeRequest(json: string): PrivateChannelBroadcastBridgeRequest { - return cast(JSON.parse(json), r('PrivateChannelBroadcastBridgeRequest')); - } - - public static privateChannelBroadcastBridgeRequestToJson(value: PrivateChannelBroadcastBridgeRequest): string { - return JSON.stringify(uncast(value, r('PrivateChannelBroadcastBridgeRequest')), null, 2); - } - - public static toPrivateChannelEventListenerAddedAgentRequest( - json: string - ): PrivateChannelEventListenerAddedAgentRequest { - return cast(JSON.parse(json), r('PrivateChannelEventListenerAddedAgentRequest')); - } - - public static privateChannelEventListenerAddedAgentRequestToJson( - value: PrivateChannelEventListenerAddedAgentRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelEventListenerAddedAgentRequest')), null, 2); - } - - public static toPrivateChannelEventListenerAddedBridgeRequest( - json: string - ): PrivateChannelEventListenerAddedBridgeRequest { - return cast(JSON.parse(json), r('PrivateChannelEventListenerAddedBridgeRequest')); - } - - public static privateChannelEventListenerAddedBridgeRequestToJson( - value: PrivateChannelEventListenerAddedBridgeRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelEventListenerAddedBridgeRequest')), null, 2); - } - - public static toPrivateChannelEventListenerRemovedAgentRequest( - json: string - ): PrivateChannelEventListenerRemovedAgentRequest { - return cast(JSON.parse(json), r('PrivateChannelEventListenerRemovedAgentRequest')); - } - - public static privateChannelEventListenerRemovedAgentRequestToJson( - value: PrivateChannelEventListenerRemovedAgentRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelEventListenerRemovedAgentRequest')), null, 2); - } - - public static toPrivateChannelEventListenerRemovedBridgeRequest( - json: string - ): PrivateChannelEventListenerRemovedBridgeRequest { - return cast(JSON.parse(json), r('PrivateChannelEventListenerRemovedBridgeRequest')); - } - - public static privateChannelEventListenerRemovedBridgeRequestToJson( - value: PrivateChannelEventListenerRemovedBridgeRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelEventListenerRemovedBridgeRequest')), null, 2); - } - - public static toPrivateChannelOnAddContextListenerAgentRequest( - json: string - ): PrivateChannelOnAddContextListenerAgentRequest { - return cast(JSON.parse(json), r('PrivateChannelOnAddContextListenerAgentRequest')); - } - - public static privateChannelOnAddContextListenerAgentRequestToJson( - value: PrivateChannelOnAddContextListenerAgentRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelOnAddContextListenerAgentRequest')), null, 2); - } - - public static toPrivateChannelOnAddContextListenerBridgeRequest( - json: string - ): PrivateChannelOnAddContextListenerBridgeRequest { - return cast(JSON.parse(json), r('PrivateChannelOnAddContextListenerBridgeRequest')); - } - - public static privateChannelOnAddContextListenerBridgeRequestToJson( - value: PrivateChannelOnAddContextListenerBridgeRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelOnAddContextListenerBridgeRequest')), null, 2); - } - - public static toPrivateChannelOnDisconnectAgentRequest(json: string): PrivateChannelOnDisconnectAgentRequest { - return cast(JSON.parse(json), r('PrivateChannelOnDisconnectAgentRequest')); - } - - public static privateChannelOnDisconnectAgentRequestToJson(value: PrivateChannelOnDisconnectAgentRequest): string { - return JSON.stringify(uncast(value, r('PrivateChannelOnDisconnectAgentRequest')), null, 2); - } - - public static toPrivateChannelOnDisconnectBridgeRequest(json: string): PrivateChannelOnDisconnectBridgeRequest { - return cast(JSON.parse(json), r('PrivateChannelOnDisconnectBridgeRequest')); - } - - public static privateChannelOnDisconnectBridgeRequestToJson(value: PrivateChannelOnDisconnectBridgeRequest): string { - return JSON.stringify(uncast(value, r('PrivateChannelOnDisconnectBridgeRequest')), null, 2); - } - - public static toPrivateChannelOnUnsubscribeAgentRequest(json: string): PrivateChannelOnUnsubscribeAgentRequest { - return cast(JSON.parse(json), r('PrivateChannelOnUnsubscribeAgentRequest')); - } - - public static privateChannelOnUnsubscribeAgentRequestToJson(value: PrivateChannelOnUnsubscribeAgentRequest): string { - return JSON.stringify(uncast(value, r('PrivateChannelOnUnsubscribeAgentRequest')), null, 2); - } - - public static toPrivateChannelOnUnsubscribeBridgeRequest(json: string): PrivateChannelOnUnsubscribeBridgeRequest { - return cast(JSON.parse(json), r('PrivateChannelOnUnsubscribeBridgeRequest')); - } - - public static privateChannelOnUnsubscribeBridgeRequestToJson( - value: PrivateChannelOnUnsubscribeBridgeRequest - ): string { - return JSON.stringify(uncast(value, r('PrivateChannelOnUnsubscribeBridgeRequest')), null, 2); - } - - public static toRaiseIntentAgentErrorResponse(json: string): RaiseIntentAgentErrorResponse { - return cast(JSON.parse(json), r('RaiseIntentAgentErrorResponse')); - } - - public static raiseIntentAgentErrorResponseToJson(value: RaiseIntentAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentAgentErrorResponse')), null, 2); - } - - public static toRaiseIntentAgentRequest(json: string): RaiseIntentAgentRequest { - return cast(JSON.parse(json), r('RaiseIntentAgentRequest')); - } - - public static raiseIntentAgentRequestToJson(value: RaiseIntentAgentRequest): string { - return JSON.stringify(uncast(value, r('RaiseIntentAgentRequest')), null, 2); - } - - public static toRaiseIntentAgentResponse(json: string): RaiseIntentAgentResponse { - return cast(JSON.parse(json), r('RaiseIntentAgentResponse')); - } - - public static raiseIntentAgentResponseToJson(value: RaiseIntentAgentResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentAgentResponse')), null, 2); - } - - public static toRaiseIntentBridgeErrorResponse(json: string): RaiseIntentBridgeErrorResponse { - return cast(JSON.parse(json), r('RaiseIntentBridgeErrorResponse')); - } - - public static raiseIntentBridgeErrorResponseToJson(value: RaiseIntentBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentBridgeErrorResponse')), null, 2); - } - - public static toRaiseIntentBridgeRequest(json: string): RaiseIntentBridgeRequest { - return cast(JSON.parse(json), r('RaiseIntentBridgeRequest')); - } - - public static raiseIntentBridgeRequestToJson(value: RaiseIntentBridgeRequest): string { - return JSON.stringify(uncast(value, r('RaiseIntentBridgeRequest')), null, 2); - } - - public static toRaiseIntentBridgeResponse(json: string): RaiseIntentBridgeResponse { - return cast(JSON.parse(json), r('RaiseIntentBridgeResponse')); - } - - public static raiseIntentBridgeResponseToJson(value: RaiseIntentBridgeResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentBridgeResponse')), null, 2); - } - - public static toRaiseIntentResultAgentErrorResponse(json: string): RaiseIntentResultAgentErrorResponse { - return cast(JSON.parse(json), r('RaiseIntentResultAgentErrorResponse')); - } - - public static raiseIntentResultAgentErrorResponseToJson(value: RaiseIntentResultAgentErrorResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResultAgentErrorResponse')), null, 2); - } - - public static toRaiseIntentResultAgentResponse(json: string): RaiseIntentResultAgentResponse { - return cast(JSON.parse(json), r('RaiseIntentResultAgentResponse')); - } - - public static raiseIntentResultAgentResponseToJson(value: RaiseIntentResultAgentResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResultAgentResponse')), null, 2); - } - - public static toRaiseIntentResultBridgeErrorResponse(json: string): RaiseIntentResultBridgeErrorResponse { - return cast(JSON.parse(json), r('RaiseIntentResultBridgeErrorResponse')); - } - - public static raiseIntentResultBridgeErrorResponseToJson(value: RaiseIntentResultBridgeErrorResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResultBridgeErrorResponse')), null, 2); - } - - public static toRaiseIntentResultBridgeResponse(json: string): RaiseIntentResultBridgeResponse { - return cast(JSON.parse(json), r('RaiseIntentResultBridgeResponse')); - } - - public static raiseIntentResultBridgeResponseToJson(value: RaiseIntentResultBridgeResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResultBridgeResponse')), null, 2); - } -} - -function invalidValue(typ: any, val: any, key: any, parent: any = ''): never { - const prettyTyp = prettyTypeName(typ); - const parentText = parent ? ` on ${parent}` : ''; - const keyText = key ? ` for key "${key}"` : ''; - throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`); -} - -function prettyTypeName(typ: any): string { - if (Array.isArray(typ)) { - if (typ.length === 2 && typ[0] === undefined) { - return `an optional ${prettyTypeName(typ[1])}`; - } else { - return `one of [${typ - .map(a => { - return prettyTypeName(a); - }) - .join(', ')}]`; - } - } else if (typeof typ === 'object' && typ.literal !== undefined) { - return typ.literal; - } else { - return typeof typ; - } -} - -function jsonToJSProps(typ: any): any { - if (typ.jsonToJS === undefined) { - const map: any = {}; - typ.props.forEach((p: any) => (map[p.json] = { key: p.js, typ: p.typ })); - typ.jsonToJS = map; - } - return typ.jsonToJS; -} - -function jsToJSONProps(typ: any): any { - if (typ.jsToJSON === undefined) { - const map: any = {}; - typ.props.forEach((p: any) => (map[p.js] = { key: p.json, typ: p.typ })); - typ.jsToJSON = map; - } - return typ.jsToJSON; -} - -function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any { - function transformPrimitive(typ: string, val: any): any { - if (typeof typ === typeof val) return val; - return invalidValue(typ, val, key, parent); - } - - function transformUnion(typs: any[], val: any): any { - // val must validate against one typ in typs - const l = typs.length; - for (let i = 0; i < l; i++) { - const typ = typs[i]; - try { - return transform(val, typ, getProps); - } catch (_) {} - } - return invalidValue(typs, val, key, parent); - } - - function transformEnum(cases: string[], val: any): any { - if (cases.indexOf(val) !== -1) return val; - return invalidValue( - cases.map(a => { - return l(a); - }), - val, - key, - parent - ); - } - - function transformArray(typ: any, val: any): any { - // val must be an array with no invalid elements - if (!Array.isArray(val)) return invalidValue(l('array'), val, key, parent); - return val.map(el => transform(el, typ, getProps)); - } - - function transformDate(val: any): any { - if (val === null) { - return null; - } - const d = new Date(val); - if (isNaN(d.valueOf())) { - return invalidValue(l('Date'), val, key, parent); - } - return d; - } - - function transformObject(props: { [k: string]: any }, additional: any, val: any): any { - if (val === null || typeof val !== 'object' || Array.isArray(val)) { - return invalidValue(l(ref || 'object'), val, key, parent); - } - const result: any = {}; - Object.getOwnPropertyNames(props).forEach(key => { - const prop = props[key]; - const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; - result[prop.key] = transform(v, prop.typ, getProps, key, ref); - }); - Object.getOwnPropertyNames(val).forEach(key => { - if (!Object.prototype.hasOwnProperty.call(props, key)) { - result[key] = transform(val[key], additional, getProps, key, ref); - } - }); - return result; - } - - if (typ === 'any') return val; - if (typ === null) { - if (val === null) return val; - return invalidValue(typ, val, key, parent); - } - if (typ === false) return invalidValue(typ, val, key, parent); - let ref: any = undefined; - while (typeof typ === 'object' && typ.ref !== undefined) { - ref = typ.ref; - typ = typeMap[typ.ref]; - } - if (Array.isArray(typ)) return transformEnum(typ, val); - if (typeof typ === 'object') { - return typ.hasOwnProperty('unionMembers') - ? transformUnion(typ.unionMembers, val) - : typ.hasOwnProperty('arrayItems') - ? transformArray(typ.arrayItems, val) - : typ.hasOwnProperty('props') - ? transformObject(getProps(typ), typ.additional, val) - : invalidValue(typ, val, key, parent); - } - // Numbers can be parsed by Date but shouldn't be. - if (typ === Date && typeof val !== 'number') return transformDate(val); - return transformPrimitive(typ, val); -} - -function cast(val: any, typ: any): T { - return transform(val, typ, jsonToJSProps); -} - -function uncast(val: T, typ: any): any { - return transform(val, typ, jsToJSONProps); -} - -function l(typ: any) { - return { literal: typ }; -} - -function a(typ: any) { - return { arrayItems: typ }; -} - -function u(...typs: any[]) { - return { unionMembers: typs }; -} - -function o(props: any[], additional: any) { - return { props, additional }; -} - -function m(additional: any) { - return { props: [], additional }; -} - -function r(name: string) { - return { ref: name }; -} - -const typeMap: any = { - AgentErrorResponseMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('AgentResponseMetadata') }, - { json: 'payload', js: 'payload', typ: r('ErrorResponseMessagePayload') }, - { json: 'type', js: 'type', typ: r('ResponseMessageType') }, - ], - false - ), - AgentResponseMetadata: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - ErrorResponseMessagePayload: o([{ json: 'error', js: 'error', typ: r('ResponseErrorDetail') }], 'any'), - AgentRequestMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('AgentRequestMetadata') }, - { json: 'payload', js: 'payload', typ: m('any') }, - { json: 'type', js: 'type', typ: r('RequestMessageType') }, - ], - false - ), - AgentRequestMetadata: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('BridgeParticipantIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceIdentifier')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - BridgeParticipantIdentifier: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'appId', js: 'appId', typ: u(undefined, '') }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - SourceIdentifier: o( - [ - { json: 'appId', js: 'appId', typ: u(undefined, '') }, - { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - AgentResponseMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('AgentResponseMetadata') }, - { json: 'payload', js: 'payload', typ: m('any') }, - { json: 'type', js: 'type', typ: r('ResponseMessageType') }, - ], - false - ), - BridgeErrorResponseMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('BridgeErrorResponseMessageMeta') }, - { json: 'payload', js: 'payload', typ: r('ResponseErrorMessagePayload') }, - { json: 'type', js: 'type', typ: '' }, - ], - false - ), - BridgeErrorResponseMessageMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - DesktopAgentIdentifier: o([{ json: 'desktopAgent', js: 'desktopAgent', typ: '' }], 'any'), - ResponseErrorMessagePayload: o([{ json: 'error', js: 'error', typ: u(undefined, r('ResponseErrorDetail')) }], 'any'), - BridgeRequestMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('BridgeRequestMetadata') }, - { json: 'payload', js: 'payload', typ: m('any') }, - { json: 'type', js: 'type', typ: '' }, - ], - false - ), - BridgeRequestMetadata: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('BridgeParticipantIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('BridgeParticipantIdentifier') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - BridgeResponseMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('BridgeResponseMessageMeta') }, - { json: 'payload', js: 'payload', typ: m('any') }, - { json: 'type', js: 'type', typ: '' }, - ], - false - ), - BridgeResponseMessageMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - BroadcastAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('BroadcastAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('BroadcastAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('BroadcastAgentRequestType') }, - ], - false - ), - BroadcastAgentRequestMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('SourceObject') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - SourceObject: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - BroadcastAgentRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'context', js: 'context', typ: r('Context') }, - ], - false - ), - Context: o( - [ - { json: 'id', js: 'id', typ: u(undefined, m('any')) }, - { json: 'name', js: 'name', typ: u(undefined, '') }, - { json: 'type', js: 'type', typ: '' }, - ], - 'any' - ), - BroadcastBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('BroadcastBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('BroadcastBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('BroadcastAgentRequestType') }, - ], - false - ), - BroadcastBridgeRequestMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - MetaSource: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - BroadcastBridgeRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'context', js: 'context', typ: r('Context') }, - ], - false - ), - ConnectionStepMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStepMetadata') }, - { json: 'payload', js: 'payload', typ: m('any') }, - { json: 'type', js: 'type', typ: r('ConnectionStepMessageType') }, - ], - false - ), - ConnectionStepMetadata: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: u(undefined, '') }, - { json: 'responseUuid', js: 'responseUuid', typ: u(undefined, '') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - ConnectionStep2Hello: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStep2HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('ConnectionStep2HelloPayload') }, - { json: 'type', js: 'type', typ: r('ConnectionStep2HelloType') }, - ], - false - ), - ConnectionStep2HelloMeta: o([{ json: 'timestamp', js: 'timestamp', typ: Date }], false), - ConnectionStep2HelloPayload: o( - [ - { json: 'authRequired', js: 'authRequired', typ: true }, - { json: 'authToken', js: 'authToken', typ: u(undefined, '') }, - { json: 'desktopAgentBridgeVersion', js: 'desktopAgentBridgeVersion', typ: '' }, - { json: 'supportedFDC3Versions', js: 'supportedFDC3Versions', typ: a('') }, - ], - false - ), - ConnectionStep3Handshake: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStep3HandshakeMeta') }, - { json: 'payload', js: 'payload', typ: r('ConnectionStep3HandshakePayload') }, - { json: 'type', js: 'type', typ: r('ConnectionStep3HandshakeType') }, - ], - false - ), - ConnectionStep3HandshakeMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - ConnectionStep3HandshakePayload: o( - [ - { json: 'authToken', js: 'authToken', typ: u(undefined, '') }, - { json: 'channelsState', js: 'channelsState', typ: m(a(r('Context'))) }, - { json: 'implementationMetadata', js: 'implementationMetadata', typ: r('ConnectingAgentImplementationMetadata') }, - { json: 'requestedName', js: 'requestedName', typ: '' }, - ], - false - ), - ConnectingAgentImplementationMetadata: o( - [ - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, - { json: 'provider', js: 'provider', typ: '' }, - { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, - ], - false - ), - OptionalFeatures: o( - [ - { json: 'DesktopAgentBridging', js: 'DesktopAgentBridging', typ: true }, - { json: 'OriginatingAppMetadata', js: 'OriginatingAppMetadata', typ: true }, - { json: 'UserChannelMembershipAPIs', js: 'UserChannelMembershipAPIs', typ: true }, - ], - false - ), - ConnectionStep4AuthenticationFailed: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStep4AuthenticationFailedMeta') }, - { json: 'payload', js: 'payload', typ: r('ConnectionStep4AuthenticationFailedPayload') }, - { json: 'type', js: 'type', typ: r('ConnectionStep4AuthenticationFailedType') }, - ], - false - ), - ConnectionStep4AuthenticationFailedMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - ConnectionStep4AuthenticationFailedPayload: o([{ json: 'message', js: 'message', typ: u(undefined, '') }], false), - ConnectionStep6ConnectedAgentsUpdate: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStep6ConnectedAgentsUpdateMeta') }, - { json: 'payload', js: 'payload', typ: r('ConnectionStep6ConnectedAgentsUpdatePayload') }, - { json: 'type', js: 'type', typ: r('ConnectionStep6ConnectedAgentsUpdateType') }, - ], - false - ), - ConnectionStep6ConnectedAgentsUpdateMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - ConnectionStep6ConnectedAgentsUpdatePayload: o( - [ - { json: 'addAgent', js: 'addAgent', typ: u(undefined, '') }, - { json: 'allAgents', js: 'allAgents', typ: a(r('DesktopAgentImplementationMetadata')) }, - { json: 'channelsState', js: 'channelsState', typ: u(undefined, m(a(r('Context')))) }, - { json: 'removeAgent', js: 'removeAgent', typ: u(undefined, '') }, - ], - false - ), - DesktopAgentImplementationMetadata: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, - { json: 'provider', js: 'provider', typ: '' }, - { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, - ], - false - ), - FindInstancesAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindInstancesAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('PayloadClass') }, - { json: 'type', js: 'type', typ: r('FindInstancesAgentErrorResponseType') }, - ], - false - ), - FindInstancesAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PayloadClass: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - FindInstancesAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('FindInstancesAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('FindInstancesAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('FindInstancesAgentRequestType') }, - ], - false - ), - FindInstancesAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceIdentifier')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - DestinationObject: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'appId', js: 'appId', typ: u(undefined, '') }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - FindInstancesAgentRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppIdentifier') }], false), - AppIdentifier: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - FindInstancesAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('AgentResponseMetadata') }, - { json: 'payload', js: 'payload', typ: r('FindInstancesAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindInstancesAgentErrorResponseType') }, - ], - false - ), - FindInstancesAgentResponsePayload: o( - [{ json: 'appIdentifiers', js: 'appIdentifiers', typ: a(r('AppMetadata')) }], - false - ), - AppMetadata: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'description', js: 'description', typ: u(undefined, '') }, - { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, - { json: 'icons', js: 'icons', typ: u(undefined, a(r('Icon'))) }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - { json: 'instanceMetadata', js: 'instanceMetadata', typ: u(undefined, m('any')) }, - { json: 'name', js: 'name', typ: u(undefined, '') }, - { json: 'resultType', js: 'resultType', typ: u(undefined, u(null, '')) }, - { json: 'screenshots', js: 'screenshots', typ: u(undefined, a(r('Image'))) }, - { json: 'title', js: 'title', typ: u(undefined, '') }, - { json: 'tooltip', js: 'tooltip', typ: u(undefined, '') }, - { json: 'version', js: 'version', typ: u(undefined, '') }, - ], - false - ), - Icon: o( - [ - { json: 'size', js: 'size', typ: u(undefined, '') }, - { json: 'src', js: 'src', typ: '' }, - { json: 'type', js: 'type', typ: u(undefined, '') }, - ], - false - ), - Image: o( - [ - { json: 'label', js: 'label', typ: u(undefined, '') }, - { json: 'size', js: 'size', typ: u(undefined, '') }, - { json: 'src', js: 'src', typ: '' }, - { json: 'type', js: 'type', typ: u(undefined, '') }, - ], - false - ), - FindInstancesBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindInstancesBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('MessagePayload') }, - { json: 'type', js: 'type', typ: r('FindInstancesAgentErrorResponseType') }, - ], - false - ), - FindInstancesBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - MessagePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - FindInstancesBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('FindInstancesBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('FindInstancesBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('FindInstancesAgentRequestType') }, - ], - false - ), - FindInstancesBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSourceObject') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - MetaSourceObject: o( - [ - { json: 'appId', js: 'appId', typ: u(undefined, '') }, - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - FindInstancesBridgeRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppIdentifier') }], false), - FindInstancesBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('BridgeResponseMessageMeta') }, - { json: 'payload', js: 'payload', typ: r('FindInstancesBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindInstancesAgentErrorResponseType') }, - ], - false - ), - FindInstancesBridgeResponsePayload: o( - [{ json: 'appIdentifiers', js: 'appIdentifiers', typ: a(r('AppMetadata')) }], - false - ), - FindIntentAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentAgentErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentAgentErrorResponseType') }, - ], - false - ), - FindIntentAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentAgentErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - FindIntentAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('FindIntentAgentRequestType') }, - ], - false - ), - FindIntentAgentRequestMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceIdentifier')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - { json: 'destination', js: 'destination', typ: u(undefined, r('BridgeParticipantIdentifier')) }, - ], - false - ), - FindIntentAgentRequestPayload: o( - [ - { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, - { json: 'intent', js: 'intent', typ: '' }, - { json: 'resultType', js: 'resultType', typ: u(undefined, '') }, - ], - false - ), - FindIntentAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentAgentResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentAgentErrorResponseType') }, - ], - false - ), - FindIntentAgentResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentAgentResponsePayload: o([{ json: 'appIntent', js: 'appIntent', typ: r('AppIntent') }], false), - AppIntent: o( - [ - { json: 'apps', js: 'apps', typ: a(r('AppMetadata')) }, - { json: 'intent', js: 'intent', typ: r('IntentMetadata') }, - ], - false - ), - IntentMetadata: o( - [ - { json: 'displayName', js: 'displayName', typ: u(undefined, '') }, - { json: 'name', js: 'name', typ: '' }, - ], - false - ), - FindIntentBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentBridgeErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentAgentErrorResponseType') }, - ], - false - ), - FindIntentBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentBridgeErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - FindIntentBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('FindIntentAgentRequestType') }, - ], - false - ), - FindIntentBridgeRequestMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('BridgeParticipantIdentifier') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - { json: 'destination', js: 'destination', typ: u(undefined, r('BridgeParticipantIdentifier')) }, - ], - false - ), - FindIntentBridgeRequestPayload: o( - [ - { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, - { json: 'intent', js: 'intent', typ: '' }, - { json: 'resultType', js: 'resultType', typ: u(undefined, '') }, - ], - false - ), - FindIntentBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentBridgeResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentAgentErrorResponseType') }, - ], - false - ), - FindIntentBridgeResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentBridgeResponsePayload: o([{ json: 'appIntent', js: 'appIntent', typ: r('AppIntent') }], false), - FindIntentsByContextAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentsByContextAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentsByContextAgentErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentsByContextAgentErrorResponseType') }, - ], - false - ), - FindIntentsByContextAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentsByContextAgentErrorResponsePayload: o( - [{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], - false - ), - FindIntentsByContextAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentsByContextAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentsByContextAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('FindIntentsByContextAgentRequestType') }, - ], - false - ), - FindIntentsByContextAgentRequestMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - { json: 'destination', js: 'destination', typ: u(undefined, r('BridgeParticipantIdentifier')) }, - ], - false - ), - FindIntentsByContextAgentRequestPayload: o( - [ - { json: 'context', js: 'context', typ: r('Context') }, - { json: 'resultType', js: 'resultType', typ: u(undefined, '') }, - ], - false - ), - FindIntentsByContextAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentsByContextAgentResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentsByContextAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentsByContextAgentErrorResponseType') }, - ], - false - ), - FindIntentsByContextAgentResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentsByContextAgentResponsePayload: o( - [{ json: 'appIntents', js: 'appIntents', typ: a(r('AppIntent')) }], - false - ), - FindIntentsByContextBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentsByContextBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentsByContextBridgeErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentsByContextAgentErrorResponseType') }, - ], - false - ), - FindIntentsByContextBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentsByContextBridgeErrorResponsePayload: o( - [{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], - false - ), - FindIntentsByContextBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentsByContextBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentsByContextBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('FindIntentsByContextAgentRequestType') }, - ], - false - ), - FindIntentsByContextBridgeRequestMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - { json: 'destination', js: 'destination', typ: u(undefined, r('BridgeParticipantIdentifier')) }, - ], - false - ), - FindIntentsByContextBridgeRequestPayload: o( - [ - { json: 'context', js: 'context', typ: r('Context') }, - { json: 'resultType', js: 'resultType', typ: u(undefined, '') }, - ], - false - ), - FindIntentsByContextBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('FindIntentsByContextBridgeResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('FindIntentsByContextBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('FindIntentsByContextAgentErrorResponseType') }, - ], - false - ), - FindIntentsByContextBridgeResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - FindIntentsByContextBridgeResponsePayload: o( - [{ json: 'appIntents', js: 'appIntents', typ: a(r('AppIntent')) }], - false - ), - GetAppMetadataAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('GetAppMetadataAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('GetAppMetadataAgentErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('GetAppMetadataAgentErrorResponseType') }, - ], - false - ), - GetAppMetadataAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - GetAppMetadataAgentErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - GetAppMetadataAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('GetAppMetadataAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('GetAppMetadataAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('GetAppMetadataAgentRequestType') }, - ], - false - ), - GetAppMetadataAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceIdentifier')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - GetAppMetadataAgentRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppObject') }], false), - AppObject: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'appId', js: 'appId', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - GetAppMetadataAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('GetAppMetadataAgentResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('GetAppMetadataAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('GetAppMetadataAgentErrorResponseType') }, - ], - false - ), - GetAppMetadataAgentResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - GetAppMetadataAgentResponsePayload: o([{ json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }], false), - GetAppMetadataBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('GetAppMetadataBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('GetAppMetadataBridgeErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('GetAppMetadataAgentErrorResponseType') }, - ], - false - ), - GetAppMetadataBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - GetAppMetadataBridgeErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - GetAppMetadataBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('GetAppMetadataBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('GetAppMetadataBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('GetAppMetadataAgentRequestType') }, - ], - false - ), - GetAppMetadataBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSourceObject') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - GetAppMetadataBridgeRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppObject') }], false), - GetAppMetadataBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('GetAppMetadataBridgeResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('GetAppMetadataBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('GetAppMetadataAgentErrorResponseType') }, - ], - false - ), - GetAppMetadataBridgeResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - GetAppMetadataBridgeResponsePayload: o([{ json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }], false), - OpenAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('OpenAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('OpenAgentErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('OpenAgentErrorResponseType') }, - ], - false - ), - OpenAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - OpenAgentErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('OpenErrorResponsePayload') }], false), - OpenAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('OpenAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('OpenAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('OpenAgentRequestType') }, - ], - false - ), - OpenAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('SourceObject') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - OpenAgentRequestPayload: o( - [ - { json: 'app', js: 'app', typ: r('AppToOpen') }, - { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, - ], - false - ), - AppToOpen: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'appId', js: 'appId', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - OpenAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('OpenAgentResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('OpenAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('OpenAgentErrorResponseType') }, - ], - false - ), - OpenAgentResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - OpenAgentResponsePayload: o([{ json: 'appIdentifier', js: 'appIdentifier', typ: r('AppIdentifier') }], false), - OpenBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('OpenBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('OpenBridgeErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('OpenAgentErrorResponseType') }, - ], - false - ), - OpenBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - OpenBridgeErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('OpenErrorResponsePayload') }], false), - OpenBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('OpenBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('OpenBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('OpenAgentRequestType') }, - ], - false - ), - OpenBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('DestinationObject')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - OpenBridgeRequestPayload: o( - [ - { json: 'app', js: 'app', typ: r('AppToOpen') }, - { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, - ], - false - ), - OpenBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('OpenBridgeResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('OpenBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('OpenAgentErrorResponseType') }, - ], - false - ), - OpenBridgeResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - OpenBridgeResponsePayload: o([{ json: 'appIdentifier', js: 'appIdentifier', typ: r('AppIdentifier') }], false), - PrivateChannelBroadcastAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelBroadcastAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelBroadcastAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelBroadcastAgentRequestType') }, - ], - false - ), - PrivateChannelBroadcastAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - MetaDestination: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'appId', js: 'appId', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - PrivateChannelBroadcastAgentRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'context', js: 'context', typ: r('Context') }, - ], - false - ), - PrivateChannelBroadcastBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelBroadcastBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelBroadcastBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelBroadcastAgentRequestType') }, - ], - false - ), - PrivateChannelBroadcastBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelBroadcastBridgeRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'context', js: 'context', typ: r('Context') }, - ], - false - ), - PrivateChannelEventListenerAddedAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelEventListenerAddedAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelEventListenerAddedAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelEventListenerAddedAgentRequestType') }, - ], - false - ), - PrivateChannelEventListenerAddedAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelEventListenerAddedAgentRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'listenerType', js: 'listenerType', typ: r('PrivateChannelEventListenerTypes') }, - ], - false - ), - PrivateChannelEventListenerAddedBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelEventListenerAddedBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelEventListenerAddedBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelEventListenerAddedAgentRequestType') }, - ], - false - ), - PrivateChannelEventListenerAddedBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelEventListenerAddedBridgeRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'listenerType', js: 'listenerType', typ: r('PrivateChannelEventListenerTypes') }, - ], - false - ), - PrivateChannelEventListenerRemovedAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelEventListenerRemovedAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelEventListenerRemovedAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelEventListenerRemovedAgentRequestType') }, - ], - false - ), - PrivateChannelEventListenerRemovedAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelEventListenerRemovedAgentRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'listenerType', js: 'listenerType', typ: r('PrivateChannelEventListenerTypes') }, - ], - false - ), - PrivateChannelEventListenerRemovedBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelEventListenerRemovedBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelEventListenerRemovedBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelEventListenerRemovedAgentRequestType') }, - ], - false - ), - PrivateChannelEventListenerRemovedBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelEventListenerRemovedBridgeRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'listenerType', js: 'listenerType', typ: r('PrivateChannelEventListenerTypes') }, - ], - false - ), - PrivateChannelOnAddContextListenerAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelOnAddContextListenerAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelOnAddContextListenerAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelOnAddContextListenerAgentRequestType') }, - ], - false - ), - PrivateChannelOnAddContextListenerAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelOnAddContextListenerAgentRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'contextType', js: 'contextType', typ: u(null, '') }, - ], - false - ), - PrivateChannelOnAddContextListenerBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelOnAddContextListenerBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelOnAddContextListenerBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelOnAddContextListenerAgentRequestType') }, - ], - false - ), - PrivateChannelOnAddContextListenerBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelOnAddContextListenerBridgeRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'contextType', js: 'contextType', typ: u(null, '') }, - ], - false - ), - PrivateChannelOnDisconnectAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelOnDisconnectAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelOnDisconnectAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelOnDisconnectAgentRequestType') }, - ], - false - ), - PrivateChannelOnDisconnectAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelOnDisconnectAgentRequestPayload: o([{ json: 'channelId', js: 'channelId', typ: '' }], false), - PrivateChannelOnDisconnectBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelOnDisconnectBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelOnDisconnectBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelOnDisconnectAgentRequestType') }, - ], - false - ), - PrivateChannelOnDisconnectBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelOnDisconnectBridgeRequestPayload: o([{ json: 'channelId', js: 'channelId', typ: '' }], false), - PrivateChannelOnUnsubscribeAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('PrivateChannelOnUnsubscribeAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelOnUnsubscribeAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelOnUnsubscribeAgentRequestType') }, - ], - false - ), - PrivateChannelOnUnsubscribeAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: u(undefined, r('SourceObject')) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelOnUnsubscribeAgentRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'contextType', js: 'contextType', typ: u(null, '') }, - ], - false - ), - PrivateChannelOnUnsubscribeBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('ERequestMetadata') }, - { json: 'payload', js: 'payload', typ: r('PrivateChannelOnUnsubscribeBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('PrivateChannelOnUnsubscribeAgentRequestType') }, - ], - false - ), - ERequestMetadata: o( - [ - { json: 'destination', js: 'destination', typ: u(undefined, r('MetaDestination')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - PrivateChannelOnUnsubscribeBridgeRequestPayload: o( - [ - { json: 'channelId', js: 'channelId', typ: '' }, - { json: 'contextType', js: 'contextType', typ: u(null, '') }, - ], - false - ), - RaiseIntentAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentAgentErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentAgentErrorResponseType') }, - ], - false - ), - RaiseIntentAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentAgentErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - RaiseIntentAgentRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentAgentRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentAgentRequestPayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentAgentRequestType') }, - ], - false - ), - RaiseIntentAgentRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: r('MetaDestination') }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('SourceObject') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentAgentRequestPayload: o( - [ - { json: 'app', js: 'app', typ: r('AppDestinationIdentifier') }, - { json: 'context', js: 'context', typ: r('Context') }, - { json: 'intent', js: 'intent', typ: '' }, - ], - false - ), - AppDestinationIdentifier: o( - [ - { json: 'desktopAgent', js: 'desktopAgent', typ: '' }, - { json: 'appId', js: 'appId', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - ], - 'any' - ), - RaiseIntentAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentAgentResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentAgentErrorResponseType') }, - ], - false - ), - RaiseIntentAgentResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentAgentResponsePayload: o( - [{ json: 'intentResolution', js: 'intentResolution', typ: r('IntentResolution') }], - false - ), - IntentResolution: o( - [ - { json: 'intent', js: 'intent', typ: '' }, - { json: 'source', js: 'source', typ: r('AppIdentifier') }, - ], - false - ), - RaiseIntentBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentBridgeErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentAgentErrorResponseType') }, - ], - false - ), - RaiseIntentBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentBridgeErrorResponsePayload: o([{ json: 'error', js: 'error', typ: r('FindInstancesErrors') }], false), - RaiseIntentBridgeRequest: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentBridgeRequestMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentBridgeRequestPayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentAgentRequestType') }, - ], - false - ), - RaiseIntentBridgeRequestMeta: o( - [ - { json: 'destination', js: 'destination', typ: r('MetaDestination') }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'source', js: 'source', typ: r('MetaSource') }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentBridgeRequestPayload: o( - [ - { json: 'app', js: 'app', typ: r('AppDestinationIdentifier') }, - { json: 'context', js: 'context', typ: r('Context') }, - { json: 'intent', js: 'intent', typ: '' }, - ], - false - ), - RaiseIntentBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentBridgeResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentAgentErrorResponseType') }, - ], - false - ), - RaiseIntentBridgeResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentBridgeResponsePayload: o( - [{ json: 'intentResolution', js: 'intentResolution', typ: r('IntentResolution') }], - false - ), - RaiseIntentResultAgentErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentResultAgentErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentResultAgentErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentResultAgentErrorResponseType') }, - ], - false - ), - RaiseIntentResultAgentErrorResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentResultAgentErrorResponsePayload: o( - [{ json: 'error', js: 'error', typ: r('RaiseIntentResultErrorMessage') }], - false - ), - RaiseIntentResultAgentResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentResultAgentResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentResultAgentResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentResultAgentErrorResponseType') }, - ], - false - ), - RaiseIntentResultAgentResponseMeta: o( - [ - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentResultAgentResponsePayload: o( - [{ json: 'intentResult', js: 'intentResult', typ: r('IntentResult') }], - false - ), - IntentResult: o( - [ - { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, - { json: 'channel', js: 'channel', typ: u(undefined, r('Channel')) }, - ], - false - ), - Channel: o( - [ - { json: 'displayMetadata', js: 'displayMetadata', typ: u(undefined, r('DisplayMetadata')) }, - { json: 'id', js: 'id', typ: '' }, - { json: 'type', js: 'type', typ: r('Type') }, - ], - false - ), - DisplayMetadata: o( - [ - { json: 'color', js: 'color', typ: u(undefined, '') }, - { json: 'glyph', js: 'glyph', typ: u(undefined, '') }, - { json: 'name', js: 'name', typ: u(undefined, '') }, - ], - false - ), - RaiseIntentResultBridgeErrorResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentResultBridgeErrorResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentResultBridgeErrorResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentResultAgentErrorResponseType') }, - ], - false - ), - RaiseIntentResultBridgeErrorResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: a(r('ResponseErrorDetail')) }, - { json: 'errorSources', js: 'errorSources', typ: a(r('DesktopAgentIdentifier')) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentResultBridgeErrorResponsePayload: o( - [{ json: 'error', js: 'error', typ: r('RaiseIntentResultErrorMessage') }], - false - ), - RaiseIntentResultBridgeResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('RaiseIntentResultBridgeResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentResultBridgeResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentResultAgentErrorResponseType') }, - ], - false - ), - RaiseIntentResultBridgeResponseMeta: o( - [ - { json: 'errorDetails', js: 'errorDetails', typ: u(undefined, a(r('ResponseErrorDetail'))) }, - { json: 'errorSources', js: 'errorSources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'requestUuid', js: 'requestUuid', typ: '' }, - { json: 'responseUuid', js: 'responseUuid', typ: '' }, - { json: 'sources', js: 'sources', typ: u(undefined, a(r('DesktopAgentIdentifier'))) }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - RaiseIntentResultBridgeResponsePayload: o( - [{ json: 'intentResult', js: 'intentResult', typ: r('IntentResult') }], - false - ), - ResponseErrorDetail: [ - 'AccessDenied', - 'AgentDisconnected', - 'AppNotFound', - 'AppTimeout', - 'CreationFailed', - 'DesktopAgentNotFound', - 'ErrorOnLaunch', - 'IntentDeliveryFailed', - 'IntentHandlerRejected', - 'MalformedContext', - 'MalformedMessage', - 'NoAppsFound', - 'NoChannelFound', - 'NoResultReturned', - 'NotConnectedToBridge', - 'ResolverTimeout', - 'ResolverUnavailable', - 'ResponseToBridgeTimedOut', - 'TargetAppUnavailable', - 'TargetInstanceUnavailable', - 'UserCancelledResolution', - ], - ResponseMessageType: [ - 'findInstancesResponse', - 'findIntentResponse', - 'findIntentsByContextResponse', - 'getAppMetadataResponse', - 'openResponse', - 'raiseIntentResponse', - 'raiseIntentResultResponse', - ], - RequestMessageType: [ - 'broadcastRequest', - 'findInstancesRequest', - 'findIntentRequest', - 'findIntentsByContextRequest', - 'getAppMetadataRequest', - 'openRequest', - 'PrivateChannel.broadcast', - 'PrivateChannel.eventListenerAdded', - 'PrivateChannel.eventListenerRemoved', - 'PrivateChannel.onAddContextListener', - 'PrivateChannel.onDisconnect', - 'PrivateChannel.onUnsubscribe', - 'raiseIntentRequest', - ], - BroadcastAgentRequestType: ['broadcastRequest'], - ConnectionStepMessageType: ['authenticationFailed', 'connectedAgentsUpdate', 'handshake', 'hello'], - ConnectionStep2HelloType: ['hello'], - ConnectionStep3HandshakeType: ['handshake'], - ConnectionStep4AuthenticationFailedType: ['authenticationFailed'], - ConnectionStep6ConnectedAgentsUpdateType: ['connectedAgentsUpdate'], - FindInstancesErrors: [ - 'AgentDisconnected', - 'DesktopAgentNotFound', - 'IntentDeliveryFailed', - 'MalformedContext', - 'MalformedMessage', - 'NoAppsFound', - 'NotConnectedToBridge', - 'ResolverTimeout', - 'ResolverUnavailable', - 'ResponseToBridgeTimedOut', - 'TargetAppUnavailable', - 'TargetInstanceUnavailable', - 'UserCancelledResolution', - ], - FindInstancesAgentErrorResponseType: ['findInstancesResponse'], - FindInstancesAgentRequestType: ['findInstancesRequest'], - FindIntentAgentErrorResponseType: ['findIntentResponse'], - FindIntentAgentRequestType: ['findIntentRequest'], - FindIntentsByContextAgentErrorResponseType: ['findIntentsByContextResponse'], - FindIntentsByContextAgentRequestType: ['findIntentsByContextRequest'], - GetAppMetadataAgentErrorResponseType: ['getAppMetadataResponse'], - GetAppMetadataAgentRequestType: ['getAppMetadataRequest'], - OpenErrorResponsePayload: [ - 'AgentDisconnected', - 'AppNotFound', - 'AppTimeout', - 'DesktopAgentNotFound', - 'ErrorOnLaunch', - 'MalformedContext', - 'MalformedMessage', - 'NotConnectedToBridge', - 'ResolverUnavailable', - 'ResponseToBridgeTimedOut', - ], - OpenAgentErrorResponseType: ['openResponse'], - OpenAgentRequestType: ['openRequest'], - PrivateChannelBroadcastAgentRequestType: ['PrivateChannel.broadcast'], - PrivateChannelEventListenerTypes: ['onAddContextListener', 'onDisconnect', 'onUnsubscribe'], - PrivateChannelEventListenerAddedAgentRequestType: ['PrivateChannel.eventListenerAdded'], - PrivateChannelEventListenerRemovedAgentRequestType: ['PrivateChannel.eventListenerRemoved'], - PrivateChannelOnAddContextListenerAgentRequestType: ['PrivateChannel.onAddContextListener'], - PrivateChannelOnDisconnectAgentRequestType: ['PrivateChannel.onDisconnect'], - PrivateChannelOnUnsubscribeAgentRequestType: ['PrivateChannel.onUnsubscribe'], - RaiseIntentAgentErrorResponseType: ['raiseIntentResponse'], - RaiseIntentAgentRequestType: ['raiseIntentRequest'], - RaiseIntentResultErrorMessage: [ - 'AgentDisconnected', - 'IntentHandlerRejected', - 'MalformedMessage', - 'NoResultReturned', - 'NotConnectedToBridge', - 'ResponseToBridgeTimedOut', - ], - RaiseIntentResultAgentErrorResponseType: ['raiseIntentResultResponse'], - Type: ['app', 'private', 'user'], -}; From db6b48138a65e3aacb32a89ef3468b382d655f67 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 12 Dec 2024 17:24:19 +0000 Subject: [PATCH 48/90] Removing redundant cleanup steps --- .../test/features/default-channel-selector.feature | 4 ---- .../test/features/default-intent-resolver.feature | 4 ---- .../test/features/desktop-agent-disconnect.feature | 2 -- .../test/step-definitions/desktop-agent.steps.ts | 2 +- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/fdc3-get-agent/test/features/default-channel-selector.feature b/packages/fdc3-get-agent/test/features/default-channel-selector.feature index d0fe6b84c..992643481 100644 --- a/packages/fdc3-get-agent/test/features/default-channel-selector.feature +++ b/packages/fdc3-get-agent/test/features/default-channel-selector.feature @@ -9,8 +9,6 @@ Feature: Default Channel Selector Given The channel selector sends a channel change message for channel "one" And we wait for a period of "200" ms Then "{cb}" is "one" - And I call "{childDoc}" with "shutdown" - And I call "{parentDoc}" with "shutdown" Scenario: Updating channel information in the channel selector Given I call "{channel-selector}" with "updateChannel" with parameters "one" and "{channel-list}" @@ -18,5 +16,3 @@ Feature: Default Channel Selector Then "{lastChannelSelectorMessage}" is an object with the following contents | type | payload.selected | payload.userChannels[0].id | payload.userChannels[1].id | payload.userChannels[2].id | | Fdc3UserInterfaceChannels | one | one | two | three | - And I call "{childDoc}" with "shutdown" - And I call "{parentDoc}" with "shutdown" diff --git a/packages/fdc3-get-agent/test/features/default-intent-resolver.feature b/packages/fdc3-get-agent/test/features/default-intent-resolver.feature index b2735e620..f736a914b 100644 --- a/packages/fdc3-get-agent/test/features/default-intent-resolver.feature +++ b/packages/fdc3-get-agent/test/features/default-intent-resolver.feature @@ -15,8 +15,6 @@ Feature: Default Intent Resolver And "{result}" is an object with the following contents | intent | appId.appId | | ViewNews | app1 | - And I call "{childDoc}" with "shutdown" - And I call "{parentDoc}" with "shutdown" And I call "{intent-resolver}" with "disconnect" Scenario: Intent Resolution Cancelled @@ -26,6 +24,4 @@ Feature: Default Intent Resolver Given The intent resolver cancels the intent selection message Then the promise "{theIntentPromise}" should resolve And "{result}" is undefined - And I call "{childDoc}" with "shutdown" - And I call "{parentDoc}" with "shutdown" And I call "{intent-resolver}" with "disconnect" diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature b/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature index 95f36fb6a..09b377700 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-disconnect.feature @@ -17,5 +17,3 @@ Feature: Death of the Desktop Agent When "{childWin}" pagehide occurs with persisted = "{false}" And we wait for a period of "200" ms Then The Desktop Agent receives a WCP6Goodbye message - And I call "{childDoc}" with "shutdown" - And I call "{parentDoc}" with "shutdown" diff --git a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts index ab181b93c..86ec22c8b 100644 --- a/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/desktop-agent.steps.ts @@ -178,7 +178,7 @@ When('I call fdc3Ready for a promise result', function (this: CustomWorld) { }); After(function (this: CustomWorld) { - console.log('Cleaning up'); + console.log(' Cleaning up test infrastructure'); clearAgentPromise(); MockDocument.shutdownAllDocuments(); }); From fec54c8ff3b458561a0b8f1f4fab82e0a6067d3e Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 12 Dec 2024 17:24:42 +0000 Subject: [PATCH 49/90] Clear timers when no longer needed in AbstractMessaging --- .../fdc3-agent-proxy/src/messaging/AbstractMessaging.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index 44fa51d6a..fba9a8077 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -28,12 +28,16 @@ export abstract class AbstractMessaging implements Messaging { const id = this.createUUID(); return new Promise((resolve, reject) => { let done = false; + let timeout: NodeJS.Timeout | null = null; const l: RegisterableListener = { id, filter: filter, action: m => { done = true; this.unregister(id); + if (timeout) { + clearTimeout(timeout); + } resolve(m); }, register: async () => { @@ -47,7 +51,7 @@ export abstract class AbstractMessaging implements Messaging { this.register(l); if (timeoutErrorMessage) { - setTimeout(() => { + timeout = setTimeout(() => { this.unregister(id); if (!done) { console.error( From 69d0bbcdf376f20a38a78410ac378454ee3463cb Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 16 Dec 2024 14:01:52 +0000 Subject: [PATCH 50/90] Update function in docs that searches for parent frames --- .../docs/api/specs/webConnectionProtocol.md | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/website/docs/api/specs/webConnectionProtocol.md b/website/docs/api/specs/webConnectionProtocol.md index 7b4dc2221..c04345a5f 100644 --- a/website/docs/api/specs/webConnectionProtocol.md +++ b/website/docs/api/specs/webConnectionProtocol.md @@ -148,23 +148,34 @@ const discoverPreloadDA = async (timeoutMs: number): Promise => { To discover a Desktop Agent Proxy interface, locate all candidates for a `parent` window or frame by first checking the values of `window.opener` and `window.parent`. If `window.opener !== null` or `window.parent !== window` then they are candidates for a parent window or frame. As iframes can be nested we can also search for candidates that are parents of a parent frame, e.g.: ```ts -const discoverProxyCandidates = (): WindowProxy[] => { - const candidates: WindowProxy[] = []; - //parent window - if (!!window.opener) { candidates.push(window.opener); } - - //parent frames - let currentWin = window; - while (currentWin.parent !== currentWin) { - candidates.push(currentWin.parent); - currentWin = currentWin.parent; - } +/** + * Recursive search for all possible parent frames (windows) that we may + * target with the WCP. + * @param startWindow window object to search + * @param found window objects found so far + * @return An array of Window Objects representing 'parent' frames of the + * specified window. + */ +function discoverProxyCandidates(startWindow: Window, found: Window[]) { + _recursePossibleTargets(startWindow, startWindow, found); + Logger.debug(`Possible parent windows/frames found: ${found.length}`); + return found; +} + +function _recursePossibleTargets(startWindow: Window, w: Window, found: Window[]) { + if (w) { + if (found.indexOf(w) == -1 && w != startWindow) { + found.push(w); + } - //parent window of top-level parent frame - if (window !== currentWin && !!currentWin.opener) { - candidates.push(currentWin.opener); + if (!!w.opener) { + _recursePossibleTargets(startWindow, w.opener, found); + } + + if (w.parent != w) { + _recursePossibleTargets(startWindow, w.parent, found); + } } - return candidates; } ``` From 2f7d1311a6e7d5da40eabc8db0f8d31b5a5bd491 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 16 Dec 2024 14:24:43 +0000 Subject: [PATCH 51/90] Renaming BasicDesktopAgent to DesktopAgentProxy (as that better represents what it does) --- .../src/{BasicDesktopAgent.ts => DesktopAgentProxy.ts} | 2 +- packages/fdc3-agent-proxy/src/index.ts | 4 ++-- .../test/step-definitions/generic.steps.ts | 4 ++-- packages/fdc3-agent-proxy/test/support/TestMessaging.ts | 2 +- packages/fdc3-get-agent/src/messaging/message-port.ts | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) rename packages/fdc3-agent-proxy/src/{BasicDesktopAgent.ts => DesktopAgentProxy.ts} (98%) diff --git a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts b/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts similarity index 98% rename from packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts rename to packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts index 662168d7c..3ea7aae71 100644 --- a/packages/fdc3-agent-proxy/src/BasicDesktopAgent.ts +++ b/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts @@ -21,7 +21,7 @@ import { HeartbeatSupport } from './heartbeat/HeartbeatSupport'; * This splits out the functionality of the desktop agent into * app, channels and intents concerns. */ -export class BasicDesktopAgent implements DesktopAgent, Connectable { +export class DesktopAgentProxy implements DesktopAgent, Connectable { readonly heartbeat: HeartbeatSupport; readonly channels: ChannelSupport; readonly intents: IntentSupport; diff --git a/packages/fdc3-agent-proxy/src/index.ts b/packages/fdc3-agent-proxy/src/index.ts index f5c67b023..c9ef5f85c 100644 --- a/packages/fdc3-agent-proxy/src/index.ts +++ b/packages/fdc3-agent-proxy/src/index.ts @@ -1,4 +1,4 @@ -import { BasicDesktopAgent } from './BasicDesktopAgent'; +import { DesktopAgentProxy } from './DesktopAgentProxy'; import { Messaging } from './Messaging'; import { AbstractMessaging } from './messaging/AbstractMessaging'; import { DefaultChannel } from './channels/DefaultChannel'; @@ -15,7 +15,7 @@ import { Connectable } from '@kite9/fdc3-standard'; export { type Messaging, AbstractMessaging, - BasicDesktopAgent, + DesktopAgentProxy, DefaultChannel, type AppSupport, type IntentSupport, diff --git a/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts index 52ff5fd1c..1ac7c4fb5 100644 --- a/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts +++ b/packages/fdc3-agent-proxy/test/step-definitions/generic.steps.ts @@ -2,7 +2,7 @@ import { TestMessaging } from '../support/TestMessaging'; import { Given, When } from '@cucumber/cucumber'; import { CustomWorld } from '../world/index'; import { - BasicDesktopAgent, + DesktopAgentProxy, DefaultAppSupport, DefaultChannelSupport, DefaultIntentSupport, @@ -22,7 +22,7 @@ Given('A Desktop Agent in {string}', async function (this: CustomWorld, field: s const is = new DefaultIntentSupport(this.messaging, new SimpleIntentResolver(this)); const as = new DefaultAppSupport(this.messaging); - const da = new BasicDesktopAgent(hs, cs, is, as, [hs]); + const da = new DesktopAgentProxy(hs, cs, is, as, [hs]); await da.connect(); this.props[field] = da; diff --git a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts index 0fddc5711..3a05591b6 100644 --- a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts +++ b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts @@ -146,7 +146,7 @@ export class TestMessaging extends AbstractMessaging { } async disconnect(): Promise { - //Theres no explicit disconnect call for the DA in FDC3, but the BasicDesktopAgent implementation includes one that is called to pagehide + //Theres no explicit disconnect call for the DA in FDC3, but the DesktopAgentProxy implementation includes one that is called to pagehide const bye: WebConnectionProtocol6Goodbye = { type: 'WCP6Goodbye', meta: { diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index 10e92d161..ba1dc56f4 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -1,6 +1,6 @@ import { AppIdentifier, DesktopAgent } from '@kite9/fdc3-standard'; import { - BasicDesktopAgent, + DesktopAgentProxy, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, @@ -52,7 +52,7 @@ export async function createDesktopAgentAPI( const cs = new DefaultChannelSupport(messaging, channelSelector); const is = new DefaultIntentSupport(messaging, intentResolver); const as = new DefaultAppSupport(messaging); - const da = new BasicDesktopAgent(hs, cs, is, as, [hs, intentResolver, channelSelector]); + const da = new DesktopAgentProxy(hs, cs, is, as, [hs, intentResolver, channelSelector]); Logger.debug('message-port: Connecting components ...'); @@ -77,7 +77,7 @@ async function populateChannelSelector(cs: ChannelSupport, channelSelector: Chan channelSelector.updateChannel(channel?.id ?? null, userChannels); } -function handleDisconnectOnPageHide(da: BasicDesktopAgent, messaging: MessagePortMessaging) { +function handleDisconnectOnPageHide(da: DesktopAgentProxy, messaging: MessagePortMessaging) { globalThis.window.addEventListener('pagehide', async event => { Logger.log(`Received pagehide event with persisted ${event.persisted}`); @@ -85,7 +85,7 @@ function handleDisconnectOnPageHide(da: BasicDesktopAgent, messaging: MessagePor // In that case don't disconnect and let heartbeat handle that instead //TODO: implement disconnect on any hide and reconnect if the page is shown again - // Will have to happen inside the BasicDesktopAgent as the reference to the DA needs to remain the same + // Will have to happen inside the DesktopAgentProxy as the reference to the DA needs to remain the same // and any listeners need to be re-registered automatically etc. if (!event.persisted) { //the page is being destroyed, disconnect from the DA From b69afaac31b3fe7d5a0447eafd9454e4c6a7c139 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 16 Dec 2024 14:25:20 +0000 Subject: [PATCH 52/90] minor formatting spelling and typing fixes in fdc3-agent-proxy --- packages/fdc3-agent-proxy/src/apps/AppSupport.ts | 4 ---- .../fdc3-agent-proxy/src/channels/ChannelSupport.ts | 8 -------- .../src/channels/DefaultPrivateChannel.ts | 12 ++++++------ .../fdc3-agent-proxy/src/intents/IntentSupport.ts | 4 ---- .../src/listeners/AbstractListener.ts | 6 +++--- .../src/listeners/HeartbeatListener.ts | 5 +++-- .../src/listeners/PrivateChannelEventListener.ts | 9 ++++++--- .../src/listeners/RegisterableListener.ts | 3 --- .../src/messaging/AbstractMessaging.ts | 3 --- 9 files changed, 18 insertions(+), 36 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/apps/AppSupport.ts b/packages/fdc3-agent-proxy/src/apps/AppSupport.ts index 048f4d452..bf7553c8f 100644 --- a/packages/fdc3-agent-proxy/src/apps/AppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/AppSupport.ts @@ -3,12 +3,8 @@ import { Context } from '@kite9/fdc3-context'; export interface AppSupport { findInstances(app: AppIdentifier): Promise>; - findInstances(app: AppIdentifier): Promise>; - getAppMetadata(app: AppIdentifier): Promise; - open(app: AppIdentifier, context?: Context): Promise; - getImplementationMetadata(): Promise; } diff --git a/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts index 5cba2b148..de47ab607 100644 --- a/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts @@ -2,20 +2,12 @@ import { Channel, ContextHandler, EventHandler, Listener, PrivateChannel } from export interface ChannelSupport { getUserChannel(): Promise; - getUserChannel(): Promise; - getUserChannels(): Promise; - getOrCreate(id: string): Promise; - createPrivateChannel(): Promise; - leaveUserChannel(): Promise; - joinUserChannel(id: string): Promise; - addContextListener(handler: ContextHandler, type: string | null): Promise; - addChannelChangedEventHandler(handler: EventHandler): Promise; } diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts index 50738f200..e4ac80489 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultPrivateChannel.ts @@ -51,30 +51,30 @@ export class DefaultPrivateChannel extends DefaultChannel implements PrivateChan //implementations of the deprecated listener functions onAddContextListener(handler: (contextType?: string) => void): Listener { //Adapt handler type for differences between addEventListener and onAddContextListener handler types - const adapterHandler: EventHandler = (event: ApiEvent) => { + const adaptorHandler: EventHandler = (event: ApiEvent) => { handler(event.details.contextType ?? undefined); }; - const l = new PrivateChannelAddContextEventListener(this.messaging, this.id, adapterHandler); + const l = new PrivateChannelAddContextEventListener(this.messaging, this.id, adaptorHandler); l.register(); return l; } onUnsubscribe(handler: (contextType?: string) => void): Listener { //Adapt handler type for differences between addEventListener and onUnsubscribeListener handler types - const adapterHandler: EventHandler = (event: ApiEvent) => { + const adaptorHandler: EventHandler = (event: ApiEvent) => { handler(event.details.contextType ?? undefined); }; - const l = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, adapterHandler); + const l = new PrivateChannelUnsubscribeEventListener(this.messaging, this.id, adaptorHandler); l.register(); return l; } onDisconnect(handler: () => void): Listener { //Adapt handler type for differences between addEventListener and onDisconnectListener handler types - const adapterHandler: EventHandler = () => { + const adaptorHandler: EventHandler = () => { handler(); }; - const l = new PrivateChannelDisconnectEventListener(this.messaging, this.id, adapterHandler); + const l = new PrivateChannelDisconnectEventListener(this.messaging, this.id, adaptorHandler); l.register(); return l; } diff --git a/packages/fdc3-agent-proxy/src/intents/IntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/IntentSupport.ts index a9ab46a11..b7afeb8de 100644 --- a/packages/fdc3-agent-proxy/src/intents/IntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/IntentSupport.ts @@ -3,12 +3,8 @@ import { Context } from '@kite9/fdc3-context'; export interface IntentSupport { findIntent(intent: string, context: Context, resultType: string | undefined): Promise; - findIntentsByContext(context: Context): Promise; - raiseIntent(intent: string, context: Context, app?: AppIdentifier): Promise; - raiseIntentForContext(context: Context, app?: AppIdentifier): Promise; - addIntentListener(intent: string, handler: IntentHandler): Promise; } diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 2d041cfbe..17a8dec51 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -96,9 +96,9 @@ export abstract class AbstractListener impleme async register(): Promise { const subscribeMessage: Y = { - meta: this.messaging.createMeta(), - payload: this.subscriptionPayload, - type: this.subscribeRequestType, + meta: this.messaging.createMeta() as Y['meta'], + payload: this.subscriptionPayload as Y['payload'], + type: this.subscribeRequestType as Y['type'], } as Y; const response = await this.messaging.exchange(subscribeMessage, this.subscribeResponseType); diff --git a/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts b/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts index a3e07be10..32bd723b1 100644 --- a/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/HeartbeatListener.ts @@ -20,7 +20,7 @@ export class HeartbeatListener implements RegisterableListener { } action(_m: AgentEventMessage): void { - this.messaging.post({ + const request: HeartbeatAcknowledgementRequest = { type: 'heartbeatAcknowledgementRequest', meta: { requestUuid: this.messaging.createUUID(), @@ -29,7 +29,8 @@ export class HeartbeatListener implements RegisterableListener { payload: { heartbeatEventUuid: (_m as HeartbeatEvent).meta.eventUuid, }, - } as HeartbeatAcknowledgementRequest); + }; + this.messaging.post(request); } async register(): Promise { diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index 98b6ded56..7b65cc93e 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -1,4 +1,7 @@ import { + isPrivateChannelOnAddContextListenerEvent, + isPrivateChannelOnDisconnectEvent, + isPrivateChannelOnUnsubscribeEvent, PrivateChannelAddEventListenerRequest, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, @@ -105,7 +108,7 @@ export class PrivateChannelNullEventListener extends AbstractPrivateChannelEvent export class PrivateChannelDisconnectEventListener extends AbstractPrivateChannelEventListener { constructor(messaging: Messaging, channelId: string, handler: EventHandler) { const wrappedHandler = (msg: PrivateChannelEventMessages) => { - if (msg.type === 'privateChannelOnDisconnectEvent') { + if (isPrivateChannelOnDisconnectEvent(msg)) { const event: PrivateChannelDisconnectEvent = { type: 'disconnect', details: null, @@ -123,7 +126,7 @@ export class PrivateChannelDisconnectEventListener extends AbstractPrivateChanne export class PrivateChannelAddContextEventListener extends AbstractPrivateChannelEventListener { constructor(messaging: Messaging, channelId: string, handler: EventHandler) { const wrappedHandler = (msg: PrivateChannelEventMessages) => { - if (msg.type === 'privateChannelOnAddContextListenerEvent') { + if (isPrivateChannelOnAddContextListenerEvent(msg)) { const event: ApiEvent = { type: 'addContextListener', details: { contextType: msg.payload.contextType }, @@ -140,7 +143,7 @@ export class PrivateChannelAddContextEventListener extends AbstractPrivateChanne export class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChannelEventListener { constructor(messaging: Messaging, channelId: string, handler: EventHandler) { const wrappedHandler = (msg: PrivateChannelEventMessages) => { - if (msg.type === 'privateChannelOnUnsubscribeEvent') { + if (isPrivateChannelOnUnsubscribeEvent(msg)) { const event: ApiEvent = { type: 'unsubscribe', details: { contextType: msg.payload.contextType }, diff --git a/packages/fdc3-agent-proxy/src/listeners/RegisterableListener.ts b/packages/fdc3-agent-proxy/src/listeners/RegisterableListener.ts index 573b645e0..013260a3b 100644 --- a/packages/fdc3-agent-proxy/src/listeners/RegisterableListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/RegisterableListener.ts @@ -7,11 +7,8 @@ import { Listener } from '@kite9/fdc3-standard'; */ export interface RegisterableListener extends Listener { id: string | null; - filter(m: any): boolean; - action(m: any): void; - /** * Listeners need to be registered in order to set their IDs. */ diff --git a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts index fba9a8077..d05d0cbb9 100644 --- a/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts +++ b/packages/fdc3-agent-proxy/src/messaging/AbstractMessaging.ts @@ -9,12 +9,9 @@ export abstract class AbstractMessaging implements Messaging { abstract createUUID(): string; abstract post(message: object): Promise; - abstract register(l: RegisterableListener): void; abstract unregister(id: string): void; - abstract createMeta(): AppRequestMessage['meta']; - abstract getTimeoutMs(): number; constructor(appIdentifier: AppIdentifier) { From 47308875d21927b112d552fedc3a52a85a819735 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 16 Dec 2024 17:54:17 +0000 Subject: [PATCH 53/90] Address review comments --- packages/fdc3-agent-proxy/src/Messaging.ts | 13 ++--- .../src/listeners/DefaultIntentListener.ts | 38 +++++++------- .../src/listeners/RegisterableListener.ts | 5 +- .../src/messaging/AbstractMessaging.ts | 16 +++--- .../test/features/intent-listener.feature | 1 - .../test/support/TestMessaging.ts | 5 +- .../test/support/responses/Handshake.ts | 51 ------------------- .../src/messaging/MessagePortMessaging.ts | 2 +- .../src/strategies/HelloHandler.ts | 5 +- .../src/ui/AbstractUIComponent.ts | 2 +- .../ui/DefaultDesktopAgentChannelSelector.ts | 2 +- .../ui/DefaultDesktopAgentIntentResolver.ts | 2 +- .../fdc3-get-agent/test/support/FrameTypes.ts | 13 +++-- .../test/support/MockElement.ts | 2 +- .../test/support/TestServerContext.ts | 3 -- 15 files changed, 52 insertions(+), 108 deletions(-) delete mode 100644 packages/fdc3-agent-proxy/test/support/responses/Handshake.ts diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index d66775e67..358497473 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -1,6 +1,10 @@ import { AppIdentifier } from '@kite9/fdc3-standard'; import { RegisterableListener } from './listeners/RegisterableListener'; -import { AppRequestMessage, AgentResponseMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { + AppRequestMessage, + AgentResponseMessage, + WebConnectionProtocol6Goodbye, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export interface Messaging /*extends Connectable*/ { /** @@ -11,7 +15,7 @@ export interface Messaging /*extends Connectable*/ { /** * Post an outgoing message */ - post(message: object): Promise; + post(message: AppRequestMessage | WebConnectionProtocol6Goodbye): Promise; /** * Registers a listener for incoming messages. @@ -30,10 +34,7 @@ export interface Messaging /*extends Connectable*/ { /** * Waits for a specific matching message */ - waitFor( - filter: (m: AgentResponseMessage) => boolean, - timeoutErrorMessage?: string - ): Promise; + waitFor(filter: (m: X) => boolean, timeoutErrorMessage?: string): Promise; /** * Sends a request message and waits for a response. If the response contains a payload.error, it is thrown. diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts index 33ce57c3b..9090919ad 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts @@ -7,7 +7,7 @@ import { IntentEvent, IntentResultRequest, IntentResultResponse, - RaiseIntentResponse, + //RaiseIntentResponse, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class DefaultIntentListener extends AbstractListener { @@ -31,7 +31,7 @@ export class DefaultIntentListener extends AbstractListener; + abstract post(message: AppRequestMessage | WebConnectionProtocol6Goodbye): Promise; abstract register(l: RegisterableListener): void; abstract unregister(id: string): void; abstract createMeta(): AppRequestMessage['meta']; @@ -18,10 +21,7 @@ export abstract class AbstractMessaging implements Messaging { this.appIdentifier = appIdentifier; } - waitFor( - filter: (m: AgentResponseMessage) => boolean, - timeoutErrorMessage?: string - ): Promise { + waitFor(filter: (m: X) => boolean, timeoutErrorMessage?: string): Promise { const id = this.createUUID(); return new Promise((resolve, reject) => { let done = false; @@ -35,7 +35,7 @@ export abstract class AbstractMessaging implements Messaging { if (timeout) { clearTimeout(timeout); } - resolve(m); + resolve(m as X); }, register: async () => { this.register(l); diff --git a/packages/fdc3-agent-proxy/test/features/intent-listener.feature b/packages/fdc3-agent-proxy/test/features/intent-listener.feature index 3c923dd31..bcaa3bba1 100644 --- a/packages/fdc3-agent-proxy/test/features/intent-listener.feature +++ b/packages/fdc3-agent-proxy/test/features/intent-listener.feature @@ -23,7 +23,6 @@ Feature: Intent Listeners And messaging receives "{intentMessageOne}" Then messaging will have posts | type | payload.intentResult.context.type | payload.intentResolution.intent | - | raiseIntentResponse | {empty} | BuyStock | | intentResultRequest | fdc3.returned-intent | {empty} | Scenario: Intent Listeners Can Return Results (Channel) diff --git a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts index 3a05591b6..1578ccd89 100644 --- a/packages/fdc3-agent-proxy/test/support/TestMessaging.ts +++ b/packages/fdc3-agent-proxy/test/support/TestMessaging.ts @@ -9,7 +9,6 @@ import { RaiseIntent } from './responses/RaiseIntent'; import { GetAppMetadata } from './responses/GetAppMetadata'; import { FindInstances } from './responses/FindInstances'; import { Open } from './responses/Open'; -import { Handshake } from './responses/Handshake'; import { GetOrCreateChannel } from './responses/GetOrCreateChannel'; import { ChannelState } from './responses/ChannelState'; import { GetUserChannels } from './responses/GetUserChannels'; @@ -23,7 +22,6 @@ import { AgentEventMessage, AgentResponseMessage, AppRequestMessage, - WebConnectionProtocolMessage, Channel, WebConnectionProtocol6Goodbye, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; @@ -126,7 +124,6 @@ export class TestMessaging extends AbstractMessaging { new GetInfo(), new FindInstances(), new Open(), - new Handshake(), new GetOrCreateChannel(), new ChannelState(this.channelState), new GetUserChannels(), @@ -215,7 +212,7 @@ export class TestMessaging extends AbstractMessaging { }; } - receive(m: AgentResponseMessage | AgentEventMessage | WebConnectionProtocolMessage, log?: (s: string) => void) { + receive(m: AgentResponseMessage | AgentEventMessage, log?: (s: string) => void) { this.listeners.forEach((v, k) => { if (v.filter(m)) { if (log) { diff --git a/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts b/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts deleted file mode 100644 index bdf072e29..000000000 --- a/packages/fdc3-agent-proxy/test/support/responses/Handshake.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - WebConnectionProtocol4ValidateAppIdentity, - WebConnectionProtocol5ValidateAppIdentitySuccessResponse, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -import { AutomaticResponse, TestMessaging } from '../TestMessaging'; - -export class Handshake implements AutomaticResponse { - filter(t: string) { - return t == 'WCP4ValidateAppIdentity'; - } - - action(input: object, m: TestMessaging) { - const out = this.createResponse(input as WebConnectionProtocol4ValidateAppIdentity); - - setTimeout(() => { - m.receive(out); - }, 100); - return Promise.resolve(); - } - - private createResponse( - i: WebConnectionProtocol4ValidateAppIdentity - ): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return { - meta: { - connectionAttemptUuid: i.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - type: 'WCP5ValidateAppIdentityResponse', - payload: { - implementationMetadata: { - appMetadata: { - appId: 'cucumber-app', - instanceId: 'cucumber-instance', - }, - fdc3Version: '2.0', - optionalFeatures: { - DesktopAgentBridging: false, - OriginatingAppMetadata: true, - UserChannelMembershipAPIs: true, - }, - provider: 'cucumber-provider', - providerVersion: 'test', - }, - appId: 'cucumber-app', - instanceId: 'cucumber-instance', - instanceUuid: 'some-instance-uuid', - }, - }; - } -} diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 4ba98c43e..6cb4d55c5 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -48,7 +48,7 @@ export class MessagePortMessaging extends AbstractMessaging { return uuidv4(); } - post(message: object): Promise { + async post(message: AppRequestMessage | WebConnectionProtocol6Goodbye): Promise { this.cd.messagePort.postMessage(message); return Promise.resolve(); } diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index 3f1d4069f..69273baeb 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -72,10 +72,7 @@ export class HelloHandler { const IFRAME_ID = 'fdc3-communications-embedded-iframe'; // remove an old one if it's there - const existing = document.getElementById(IFRAME_ID); - if (existing) { - existing.remove(); - } + document.getElementById(IFRAME_ID)?.remove(); //note the iframe URL and desktop agent type have changed this.agentType = WebDesktopAgentType.ProxyUrl; diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index f4a720625..5ff3ca93c 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -96,7 +96,7 @@ export abstract class AbstractUIComponent implements Connectable { } private awaitHello(): Promise { - return new Promise((resolve /*, _reject*/) => { + return new Promise(resolve => { const ml = (e: MessageEvent) => { if (e.source == this.iframe?.contentWindow) { if (isFdc3UserInterfaceHello(e.data)) { diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts index ed3e7b75b..2a2f729aa 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts @@ -48,7 +48,7 @@ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent impl }), }, }; - this.port!.postMessage(message); + this.port?.postMessage(message); } setChannelChangeCallback(callback: (channelId: string | null) => void): void { diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts index d8eeb77ef..8d3c3b35a 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts @@ -45,7 +45,7 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple } async chooseIntent(appIntents: AppIntent[], context: Context): Promise { - const out = new Promise((resolve /*, _reject*/) => { + const out = new Promise(resolve => { this.pendingResolve = resolve; }); const message: Fdc3UserInterfaceResolve = { diff --git a/packages/fdc3-get-agent/test/support/FrameTypes.ts b/packages/fdc3-get-agent/test/support/FrameTypes.ts index 03430f393..22bba0288 100644 --- a/packages/fdc3-get-agent/test/support/FrameTypes.ts +++ b/packages/fdc3-get-agent/test/support/FrameTypes.ts @@ -69,13 +69,15 @@ export function handleChannelSelectorComms( }, }, }; - parent.dispatchEvent({ + + const event: Event = { type: 'message', data: msg, origin: CHANNEL_SELECTOR_URL, - source, + source: source, ports: [connection.port1], - } as unknown as Event); + } as unknown as Event; + parent.dispatchEvent(event); connection.port2.onmessage = e => { if (isFdc3UserInterfaceHandshake(e)) { @@ -117,13 +119,14 @@ export function handleIntentResolverComms( }, }, }; - parent.dispatchEvent({ + const event: Event = { type: 'message', data: msg, origin: INTENT_RESOLVER_URL, source, ports: [connection.port1], - } as unknown as Event); + } as unknown as Event; + parent.dispatchEvent(event); connection.port2.onmessage = e => { if (isFdc3UserInterfaceHandshake(e)) { diff --git a/packages/fdc3-get-agent/test/support/MockElement.ts b/packages/fdc3-get-agent/test/support/MockElement.ts index cd46f658f..586526a77 100644 --- a/packages/fdc3-get-agent/test/support/MockElement.ts +++ b/packages/fdc3-get-agent/test/support/MockElement.ts @@ -3,7 +3,7 @@ import { MockIFrame } from './MockIFrame'; export class MockElement { public tag: string; - public atts: { [name: string]: any } = {}; + public atts: { [name: string]: unknown } = {}; public children: HTMLElement[] = []; constructor(tag: string) { diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index 342b03dba..026d8882a 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -86,9 +86,6 @@ export class TestServerContext implements ServerContext { const internalPort = mc.port1; const externalPort = mc.port2; - // internalPort.name = 'internalPort-' + ni; - // externalPort.name = 'externalPort-' + ni; - internalPort.start(); const connectionDetails = { From d5c4e202f75c9a5b0c8a242e24ada0f49514680f Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 17 Dec 2024 16:15:03 +0000 Subject: [PATCH 54/90] Resolving comments from Rob's review --- .../src/apps/DefaultAppSupport.ts | 45 +++++++++------- .../src/channels/DefaultChannelSupport.ts | 46 ++++++++-------- .../src/intents/DefaultIntentSupport.ts | 24 +++++++-- .../src/listeners/AbstractListener.ts | 2 +- packages/fdc3-agent-proxy/src/util.ts | 20 +++++++ .../test/features/private-channels.feature | 12 +++++ .../test/features/user-channels.feature | 6 ++- .../src/ui/AbstractUIComponent.ts | 20 +++---- packages/testing/src/steps/generic.steps.ts | 7 +++ .../fdc3-for-web/demo/src/client/apps/app6.ts | 10 ++-- .../fdc3-web-impl/src/BasicFDC3Server.ts | 5 +- .../fdc3-web-impl/test/features/apps.feature | 6 +++ .../test/features/heartbeat.feature | 11 +++- .../test/step-definitions/heartbeat.steps.ts | 19 ++++++- .../test/step-definitions/start-app.steps.ts | 52 ++++++++++++------- 15 files changed, 198 insertions(+), 87 deletions(-) create mode 100644 packages/fdc3-agent-proxy/src/util.ts diff --git a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts index 8611a8bc8..dd0c33ad2 100644 --- a/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/DefaultAppSupport.ts @@ -12,6 +12,7 @@ import { OpenRequest, OpenResponse, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { throwIfUndefined } from '../util'; export class DefaultAppSupport implements AppSupport { readonly messaging: Messaging; @@ -41,13 +42,16 @@ export class DefaultAppSupport implements AppSupport { meta: this.messaging.createMeta(), }; - const out = await this.messaging.exchange(request, 'getAppMetadataResponse'); - if (out.payload.appMetadata) { - return out.payload.appMetadata; - } else { - //defensive: unlikely to happen as an error returned should already have been thrown by exchange - throw new Error(ResolveError.TargetAppUnavailable); - } + const response = await this.messaging.exchange(request, 'getAppMetadataResponse'); + + throwIfUndefined( + response.payload.appMetadata, + 'Invalid response from Desktop Agent to getAppMetadata!', + response, + ResolveError.TargetAppUnavailable + ); + + return response.payload.appMetadata!; } async open(app: AppIdentifier, context?: Context | undefined): Promise { @@ -63,13 +67,16 @@ export class DefaultAppSupport implements AppSupport { meta: this.messaging.createMeta(), }; - const out = await this.messaging.exchange(request, 'openResponse', OpenError.AppTimeout); - if (out.payload.appIdentifier) { - return out.payload.appIdentifier; - } else { - //defensive: unlikely to happen as an error returned should already have been thrown by exchange - throw new Error(OpenError.AppNotFound); - } + const response = await this.messaging.exchange(request, 'openResponse', OpenError.AppTimeout); + + throwIfUndefined( + response.payload.appIdentifier, + 'Invalid response from Desktop Agent to open!', + response, + OpenError.AppNotFound + ); + + return response.payload.appIdentifier!; } async getImplementationMetadata(): Promise { @@ -79,15 +86,17 @@ export class DefaultAppSupport implements AppSupport { meta: this.messaging.createMeta(), }; - const out = await this.messaging.exchange( + const response = await this.messaging.exchange( request, 'getInfoResponse', 'timed out waiting for getInfo response!' ); - if (out.payload.implementationMetadata) { - return out.payload.implementationMetadata; + + if (response.payload.implementationMetadata) { + return response.payload.implementationMetadata; } else { - //should never happen as an error returned will be thrown + //This will only happen if the DA implementation returns an invalid message with a missing implementationMetadata property + console.error('Invalid response from Desktop Agent to open!', response); const unknownImpl: ImplementationMetadata = { fdc3Version: 'unknown', provider: 'unknown', diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index 519ffaea0..4bd240500 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -28,6 +28,7 @@ import { JoinUserChannelResponse, JoinUserChannelRequest, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { throwIfUndefined } from '../util'; export class DefaultChannelSupport implements ChannelSupport { readonly messaging: Messaging; @@ -91,14 +92,10 @@ export class DefaultChannelSupport implements ChannelSupport { payload: {}, }; const response = await this.messaging.exchange(request, 'getUserChannelsResponse'); - //handle successful responses - errors will already have been thrown by exchange above - if (response.payload.userChannels) { - const channels = response.payload.userChannels; - this.userChannels = channels.map(c => new DefaultChannel(this.messaging, c.id, 'user', c.displayMetadata)); - } else { - console.error('Invalid response from Desktop Agent to getUserChannelsRequest!', response); - throw new Error(ChannelError.NoChannelFound); - } + + //handle successful responses + const channels = response.payload.userChannels!; + this.userChannels = channels.map(c => new DefaultChannel(this.messaging, c.id, 'user', c.displayMetadata)); return this.userChannels; } @@ -111,14 +108,16 @@ export class DefaultChannelSupport implements ChannelSupport { }, }; const response = await this.messaging.exchange(request, 'getOrCreateChannelResponse'); - //handle successful responses - errors will already have been thrown by exchange above - if (response.payload.channel) { - const out = new DefaultChannel(this.messaging, id, 'app', response.payload.channel.displayMetadata); - return out; - } else { - console.error('Invalid response from Desktop Agent to getUserChannelsRequest!', response); - throw new Error(ChannelError.CreationFailed); - } + + throwIfUndefined( + response.payload.channel, + 'Invalid response from Desktop Agent to getOrCreate!', + response, + ChannelError.CreationFailed + ); + + const out = new DefaultChannel(this.messaging, id, 'app', response.payload.channel!.displayMetadata); + return out; } async createPrivateChannel(): Promise { @@ -131,12 +130,15 @@ export class DefaultChannelSupport implements ChannelSupport { request, 'createPrivateChannelResponse' ); - if (response.payload.privateChannel) { - return new DefaultPrivateChannel(this.messaging, response.payload.privateChannel.id); - } else { - console.error('Invalid response from Desktop Agent to getUserChannelsRequest!', response); - throw new Error(ChannelError.CreationFailed); - } + + throwIfUndefined( + response.payload.privateChannel, + 'Invalid response from Desktop Agent to createPrivateChannel!', + response, + ChannelError.CreationFailed + ); + + return new DefaultPrivateChannel(this.messaging, response.payload.privateChannel!.id); } async leaveUserChannel(): Promise { diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index c78cd04ee..b4c52220f 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -27,6 +27,7 @@ import { RaiseIntentResponse, RaiseIntentResultResponse, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { throwIfUndefined } from '../util'; const convertIntentResult = async ( { payload }: RaiseIntentResultResponse, @@ -130,6 +131,13 @@ export class DefaultIntentSupport implements IntentSupport { ResolveError.IntentDeliveryFailed ); + throwIfUndefined( + response.payload.error ?? response.payload.appIntent ?? response.payload.intentResolution, + 'Invalid response from Desktop Agent to raiseIntent!', + response, + ResolveError.NoAppsFound + ); + if (response.payload.appIntent) { // Needs further resolution, we need to invoke the resolver const result: IntentResolutionChoice | void = await this.intentResolver.chooseIntent( @@ -146,8 +154,8 @@ export class DefaultIntentSupport implements IntentSupport { const details = response.payload.intentResolution; return new DefaultIntentResolution(this.messaging, resultPromise, details.source, details.intent); } else { - //should never get here as exchange will throw above - throw new Error(ResolveError.NoAppsFound); + //Should never get here as we will throw above + throw new Error(response.payload.error); } } @@ -167,6 +175,14 @@ export class DefaultIntentSupport implements IntentSupport { 'raiseIntentForContextResponse', ResolveError.IntentDeliveryFailed ); + + throwIfUndefined( + response.payload.error ?? response.payload.appIntents ?? response.payload.intentResolution, + 'Invalid response from Desktop Agent to raiseIntentForContext!', + response, + ResolveError.NoAppsFound + ); + if (response.payload.appIntents) { // Needs further resolution, we need to invoke the resolver const result: IntentResolutionChoice | void = await this.intentResolver.chooseIntent( @@ -183,8 +199,8 @@ export class DefaultIntentSupport implements IntentSupport { const details = response.payload.intentResolution; return new DefaultIntentResolution(this.messaging, resultPromise, details.source, details.intent); } else { - //should never get here as exchange will throw above - throw new Error(ResolveError.NoAppsFound); + //should never get here as we will throw above + throw new Error(response.payload.error); } } diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 17a8dec51..297cc9694 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -79,7 +79,7 @@ export abstract class AbstractListener impleme async unsubscribe(): Promise { if (this.id) { - this.messaging.unregister(this.id!); + this.messaging.unregister(this.id); const unsubscribeMessage: UnsubscribeRequest = { meta: this.messaging.createMeta(), payload: { diff --git a/packages/fdc3-agent-proxy/src/util.ts b/packages/fdc3-agent-proxy/src/util.ts new file mode 100644 index 000000000..f9aae72f4 --- /dev/null +++ b/packages/fdc3-agent-proxy/src/util.ts @@ -0,0 +1,20 @@ +import { AgentEventMessage, AgentResponseMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { ChannelError, OpenError, ResolveError } from '@kite9/fdc3-standard'; + +export type ErrorMessages = ChannelError | OpenError | ResolveError; + +/** Utility function that logs and throws a specified error if a specified property does not exist. + * Used to lightly validate messages being processed primarily to catch errors in Desktop Agent + * implementations. + */ +export const throwIfUndefined = ( + property: object | string | number | null | undefined, + absentMessage: string, + message: AgentResponseMessage | AgentEventMessage, + absentError: ErrorMessages +): void => { + if (property === undefined) { + console.error(absentMessage, message); + throw new Error(absentError); + } +}; diff --git a/packages/fdc3-agent-proxy/test/features/private-channels.feature b/packages/fdc3-agent-proxy/test/features/private-channels.feature index 9d1ba3736..767f83841 100644 --- a/packages/fdc3-agent-proxy/test/features/private-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/private-channels.feature @@ -68,6 +68,18 @@ Feature: Basic Private Channels Support | contextType | | fdc3.instrument | + Scenario: Adding an event handler for all events on a given Private Channel to receive a notification + Given "onAddContextListenerMessage" is a PrivateChannelOnAddContextListenerEvent message on channel "{privateChannel.id}" with contextType as "fdc3.instrument" + Given "onUnsubscribeListenerMessage" is a PrivateChannelOnUnsubscribeEvent message on channel "{privateChannel.id}" with contextType as "fdc3.instrument" + Given "onDisconnectListenerMessage" is a PrivateChannelOnDisconnectEvent message on channel "{privateChannel.id}" + And "typesHandler" pipes events to "types" + And I call "{privateChannel}" with "addEventListener" with parameters "{null}" and "{typesHandler}" + And we wait for a period of "100" ms + And messaging receives "{onAddContextListenerMessage}" + And messaging receives "{onUnsubscribeListenerMessage}" + And messaging receives "{onDisconnectListenerMessage}" + Then "{types}" is an array of objects with length "3" + Scenario: Adding and then unsubscribing an "disconnect" listener will send a notification of each event to the agent Given "voidHandler" is a invocation counter into "count" When I call "{privateChannel}" with "addEventListener" with parameters "disconnect" and "{voidHandler}" diff --git a/packages/fdc3-agent-proxy/test/features/user-channels.feature b/packages/fdc3-agent-proxy/test/features/user-channels.feature index ca619eabd..8eb5f5b2f 100644 --- a/packages/fdc3-agent-proxy/test/features/user-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/user-channels.feature @@ -9,6 +9,7 @@ Feature: Basic User Channels Support Given "instrumentContext" is a "fdc3.instrument" context Given "userChannelMessage1" is a channelChangedEvent message on channel "one" Given "userChannelMessage2" is a channelChangedEvent message on channel "two" + Given "userChannelMessage3" is a channelChangedEvent message on channel "three" Scenario: List User Channels There should be a selection of user channels to choose from @@ -191,11 +192,14 @@ Feature: Basic User Channels Support When messaging receives "{userChannelMessage2}" Then "{channelId}" is "two" - Scenario: Adding A User Channel Event Listener + Scenario: Adding and removing A User Channel Changed Event Listener Given "typesHandler" pipes events to "types" When I call "{api}" with "addEventListener" with parameters "userChannelChanged" and "{typesHandler}" + And I refer to "{result}" as "theListener" And messaging receives "{userChannelMessage2}" And messaging receives "{userChannelMessage1}" + And I call "{theListener}" with "unsubscribe" + And messaging receives "{userChannelMessage3}" Then "{types}" is an array of objects with the following contents | newChannelId | | two | diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index 5ff3ca93c..d3df44187 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -101,9 +101,7 @@ export abstract class AbstractUIComponent implements Connectable { if (e.source == this.iframe?.contentWindow) { if (isFdc3UserInterfaceHello(e.data)) { const helloData = e.data; - if (helloData.payload.initialCSS) { - this.themeContainer(helloData.payload.initialCSS); - } + this.themeContainer(helloData.payload.initialCSS); const port = e.ports[0]; port.start(); globalThis.window.removeEventListener('message', ml); @@ -146,15 +144,13 @@ export abstract class AbstractUIComponent implements Connectable { } themeContainer(css: UpdatedCSS | InitialCSS) { - if (css) { - for (let i = 0; i < ALLOWED_CSS_ELEMENTS.length; i++) { - const k = ALLOWED_CSS_ELEMENTS[i]; - const value: string | undefined = css[k as string]; - if (value != null) { - this.container!.style.setProperty(this.toKebabCase(k), value); - } else { - this.container!.style.removeProperty(this.toKebabCase(k)); - } + for (let i = 0; i < ALLOWED_CSS_ELEMENTS.length; i++) { + const k = ALLOWED_CSS_ELEMENTS[i]; + const value: string | undefined = css[k as string]; + if (value != null) { + this.container!.style.setProperty(this.toKebabCase(k), value); + } else { + this.container!.style.removeProperty(this.toKebabCase(k)); } } } diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index 842cc9707..a27edcf5f 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -102,6 +102,13 @@ export function setupGenericSteps() { } ); + Then( + '{string} is an array of objects with length {string}', + function (this: PropsWorld, field: string, field2: string) { + expect(handleResolve(field, this).length).toEqual(Number.parseInt(handleResolve(field2, this))); + } + ); + Then( '{string} is an array of strings with the following values', function (this: PropsWorld, field: string, dt: DataTable) { diff --git a/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts b/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts index d98b2da4d..39e75703f 100644 --- a/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts +++ b/toolbox/fdc3-for-web/demo/src/client/apps/app6.ts @@ -13,11 +13,7 @@ getAgent().then(async fdc3 => { }, }); - if (log) { - log.textContent = `Got resolution: ${JSON.stringify(reso)}`; - const result = await reso.getResult(); - log.textContent += `Got result: ${JSON.stringify(result)}`; - } else { - console.error("Unable to load resolution as the log element didn't exist!"); - } + log!.textContent = `Got resolution: ${JSON.stringify(reso)}`; + const result = await reso.getResult(); + log!.textContent += `Got result: ${JSON.stringify(result)}`; }); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index da5659f1f..7d752ab26 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -38,7 +38,10 @@ export class BasicFDC3Server implements FDC3Server { this.sc = sc; } - receive(message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity, from: InstanceID): void { + receive( + message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity | WebConnectionProtocol6Goodbye, + from: InstanceID + ): void { // this.sc.log(`MessageReceived: \n ${JSON.stringify(message, null, 2)}`) this.handlers.forEach(h => h.accept(message, this.sc, from)); } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/apps.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/apps.feature index f5515f93c..e572c74d0 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/apps.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/apps.feature @@ -23,6 +23,12 @@ Feature: Opening and Requesting App Details | msg.payload.error | to.instanceId | msg.type | | TargetAppUnavailable | a1 | getAppMetadataResponse | + Scenario: Looking up DesktopAgent metadata + When "libraryApp/a1" requests info on the DesktopAgent + Then messaging will have outgoing posts + | msg.payload.implementationMetadata.provider | to.instanceId | msg.matches_type | + | cucumber-provider | a1 | getInfoResponse | + Scenario: Opening An App When "libraryApp/a1" opens app "storageApp" And "uuid-0" sends validate diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/heartbeat.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/heartbeat.feature index 1ece5be1c..bfff6d02d 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/heartbeat.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/heartbeat.feature @@ -38,7 +38,7 @@ Feature: Heartbeat Messages Between Apps and Server | a1 | Connected | Scenario: App Doesn't Respond to heartbeats -Apps are considered dead if they don't respond to a heartbeat request within 2 seconds + Apps are considered dead if they don't respond to a heartbeat request within 2 seconds When "libraryApp/a1" is opened with connection id "a1" And "a1" sends validate @@ -54,3 +54,12 @@ Apps are considered dead if they don't respond to a heartbeat request within 2 s And I shutdown the server And I get the heartbeat times Then "{result}" is empty + + Scenario: App says Goodbye + When "libraryApp/a1" is opened with connection id "a1" + And "a1" sends validate + And we wait for a period of "500" ms + And "libraryApp/a1" sends a goodbye message + Then I test the liveness of "libraryApp/a1" + Then "{result}" is false + And I shutdown the server diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts index 895257aec..3d67022d3 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts @@ -1,6 +1,9 @@ import { Given, Then } from '@cucumber/cucumber'; import { CustomWorld } from '../world'; -import { HeartbeatAcknowledgementRequest } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { + HeartbeatAcknowledgementRequest, + WebConnectionProtocol6Goodbye, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { createMeta } from './generic.steps'; import { HeartbeatHandler } from '../../src/handlers/HeartbeatHandler'; @@ -8,7 +11,7 @@ Given( '{string} sends a heartbeat response to eventUuid {string}', function (this: CustomWorld, appStr: string, eventUuid: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, @@ -22,6 +25,18 @@ Given( } ); +Given('{string} sends a goodbye message', function (this: CustomWorld, appStr: string) { + const meta = createMeta(this, appStr); + const uuid = this.sc.getInstanceUUID(meta.source)!; + + const message: WebConnectionProtocol6Goodbye = { + meta, + type: 'WCP6Goodbye', + }; + + this.server.receive(message, uuid); +}); + Then('I test the liveness of {string}', async function (this: CustomWorld, appStr: string) { const out = await this.sc.isAppConnected(createMeta(this, appStr).source.instanceId); this.props['result'] = out; diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts index f57dec361..120525fd5 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts @@ -4,6 +4,7 @@ import { contextMap, createMeta } from './generic.steps'; import { matchData } from '@kite9/testing'; import { BrowserTypes } from '@kite9/fdc3-schema'; import { State } from '../../src/ServerContext'; +import { GetInfoRequest } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; type OpenRequest = BrowserTypes.OpenRequest; type GetAppMetadataRequest = BrowserTypes.GetAppMetadataRequest; @@ -25,19 +26,23 @@ When('{string} is closed', function (this: CustomWorld, app: string) { When('{string} sends validate', function (this: CustomWorld, uuid: string) { const identity = this.sc.getInstanceDetails(uuid); - const message: WebConnectionProtocol4ValidateAppIdentity = { - type: 'WCP4ValidateAppIdentity', - meta: { - connectionAttemptUuid: this.sc.createUUID(), - timestamp: new Date(), - }, - payload: { - actualUrl: 'something', - identityUrl: 'something', - }, - }; - this.sc.setAppState(identity?.instanceId!!, State.Connected); - this.server.receive(message, uuid); + if (identity) { + const message: WebConnectionProtocol4ValidateAppIdentity = { + type: 'WCP4ValidateAppIdentity', + meta: { + connectionAttemptUuid: this.sc.createUUID(), + timestamp: new Date(), + }, + payload: { + actualUrl: 'something', + identityUrl: 'something', + }, + }; + this.sc.setAppState(identity.instanceId, State.Connected); + this.server.receive(message, uuid); + } else { + throw new Error(`Did not find app identity ${uuid}`); + } }); When('{string} revalidates', function (this: CustomWorld, uuid: string) { @@ -64,7 +69,7 @@ Then('running apps will be', async function (this: CustomWorld, dataTable: DataT When('{string} opens app {string}', function (this: CustomWorld, appStr: string, open: string) { const from = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(from.source)!!; + const uuid = this.sc.getInstanceUUID(from.source)!; const message: OpenRequest = { type: 'openRequest', meta: from, @@ -82,7 +87,7 @@ When( '{string} opens app {string} with context data {string}', function (this: CustomWorld, appStr: string, open: string, context: string) { const from = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(from.source)!!; + const uuid = this.sc.getInstanceUUID(from.source)!; const message: OpenRequest = { type: 'openRequest', meta: from, @@ -100,7 +105,7 @@ When( When('{string} requests metadata for {string}', function (this: CustomWorld, appStr: string, open: string) { const from = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(from.source)!!; + const uuid = this.sc.getInstanceUUID(from.source)!; const message: GetAppMetadataRequest = { type: 'getAppMetadataRequest', meta: from, @@ -114,9 +119,20 @@ When('{string} requests metadata for {string}', function (this: CustomWorld, app this.server.receive(message, uuid); }); +When('{string} requests info on the DesktopAgent', function (this: CustomWorld, appStr: string) { + const from = createMeta(this, appStr); + const uuid = this.sc.getInstanceUUID(from.source)!; + const message: GetInfoRequest = { + type: 'getInfoRequest', + meta: from, + payload: {}, + }; + this.server.receive(message, uuid); +}); + When('{string} findsInstances of {string}', function (this: CustomWorld, appStr: string, open: string) { const from = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(from.source)!!; + const uuid = this.sc.getInstanceUUID(from.source)!; const message: FindInstancesRequest = { type: 'findInstancesRequest', meta: from, @@ -130,7 +146,7 @@ When('{string} findsInstances of {string}', function (this: CustomWorld, appStr: }); When('we wait for the listener timeout', function (this: CustomWorld) { - return new Promise((resolve, _reject) => { + return new Promise(resolve => { setTimeout(() => resolve(), 3100); }); }); From fe42de47fc63c4141be9f2d9e4ee2a111d95bc6e Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 17 Dec 2024 17:37:58 +0000 Subject: [PATCH 55/90] Remove defunct code in DefaultIntentListener --- .../src/listeners/DefaultIntentListener.ts | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts index 9090919ad..5d389de20 100644 --- a/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/DefaultIntentListener.ts @@ -31,8 +31,6 @@ export class DefaultIntentListener extends AbstractListener Date: Tue, 17 Dec 2024 17:39:06 +0000 Subject: [PATCH 56/90] Fix error introduced into UI iframe test infrastructure --- packages/fdc3-get-agent/test/support/FrameTypes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fdc3-get-agent/test/support/FrameTypes.ts b/packages/fdc3-get-agent/test/support/FrameTypes.ts index 22bba0288..058dc7d21 100644 --- a/packages/fdc3-get-agent/test/support/FrameTypes.ts +++ b/packages/fdc3-get-agent/test/support/FrameTypes.ts @@ -80,7 +80,7 @@ export function handleChannelSelectorComms( parent.dispatchEvent(event); connection.port2.onmessage = e => { - if (isFdc3UserInterfaceHandshake(e)) { + if (isFdc3UserInterfaceHandshake(e.data)) { setTimeout(() => { const msg: Fdc3UserInterfaceRestyle = { type: 'Fdc3UserInterfaceRestyle', @@ -129,7 +129,7 @@ export function handleIntentResolverComms( parent.dispatchEvent(event); connection.port2.onmessage = e => { - if (isFdc3UserInterfaceHandshake(e)) { + if (isFdc3UserInterfaceHandshake(e.data)) { setTimeout(() => { const msg: Fdc3UserInterfaceRestyle = { type: 'Fdc3UserInterfaceRestyle', From 4da3542a80c937ecba4d86af074638fc10ae6065 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 17 Dec 2024 18:05:21 +0000 Subject: [PATCH 57/90] Resolving review comments from Julianna's final batch --- .../fdc3-agent-proxy/src/apps/AppSupport.ts | 1 - .../src/channels/ChannelSupport.ts | 1 - .../features/desktop-agent-strategy.feature | 5 ----- .../test/features/utils.feature | 6 +++++ .../fdc3UserInterfaceHandshake.schema.json | 2 +- .../fdc3-for-web/demo/src/client/ui/drag.ts | 2 +- .../fdc3-web-impl/src/BasicFDC3Server.ts | 1 - .../src/handlers/HeartbeatHandler.ts | 22 ++++++++----------- .../fdc3-web-impl/src/handlers/OpenHandler.ts | 21 ++++++++---------- 9 files changed, 26 insertions(+), 35 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/apps/AppSupport.ts b/packages/fdc3-agent-proxy/src/apps/AppSupport.ts index bf7553c8f..dd752f5b0 100644 --- a/packages/fdc3-agent-proxy/src/apps/AppSupport.ts +++ b/packages/fdc3-agent-proxy/src/apps/AppSupport.ts @@ -2,7 +2,6 @@ import { AppIdentifier, AppMetadata, ImplementationMetadata } from '@kite9/fdc3- import { Context } from '@kite9/fdc3-context'; export interface AppSupport { - findInstances(app: AppIdentifier): Promise>; findInstances(app: AppIdentifier): Promise>; getAppMetadata(app: AppIdentifier): Promise; open(app: AppIdentifier, context?: Context): Promise; diff --git a/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts index de47ab607..b6289f1f1 100644 --- a/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/ChannelSupport.ts @@ -1,7 +1,6 @@ import { Channel, ContextHandler, EventHandler, Listener, PrivateChannel } from '@kite9/fdc3-standard'; export interface ChannelSupport { - getUserChannel(): Promise; getUserChannel(): Promise; getUserChannels(): Promise; getOrCreate(id: string): Promise; diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index 00fe9e4ea..a28589efd 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -396,8 +396,3 @@ Scenario: Latch to Desktop Agent Preload via SessionStorage which has gone away And I refer to "{result}" as "desktopAgent2" And "{desktopAgent1}" is "{desktopAgent2}" And I call "{desktopAgent1}" with "disconnect" - - Scenario: We dump any open handles - Given I call "{parentDoc}" with "shutdown" - Then I call "{childDoc}" with "shutdown" - Then Testing ends after "8000" ms diff --git a/packages/fdc3-get-agent/test/features/utils.feature b/packages/fdc3-get-agent/test/features/utils.feature index e65525541..e7d91abb8 100644 --- a/packages/fdc3-get-agent/test/features/utils.feature +++ b/packages/fdc3-get-agent/test/features/utils.feature @@ -6,3 +6,9 @@ Scenario: Logger utility Scenario: UUID generator When A uuid is generated + +# Uncomment to debug the tests not exiting - will dump a list of open handles keeping node open +# Scenario: We dump any open handles +# Given I call "{parentDoc}" with "shutdown" +# Then I call "{childDoc}" with "shutdown" +# Then Testing ends after "8000" ms \ No newline at end of file diff --git a/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json b/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json index 9b4fb181f..29fa74150 100644 --- a/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json +++ b/packages/fdc3-schema/schemas/api/fdc3UserInterfaceHandshake.schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://fdc3.finos.org/schemas/next/api/fdc3UserInterfaceHandshake.schema.json", "title": "Fdc3 UserInterface Handshake", - "description": "Handshake message sent back to a user interface from the DA proxy code (setup by `getAgent()`) over the `MessagePort` provide in the preceding iFrameHello message, confirming that it is listening to the `MessagePort` for further communication.", + "description": "Handshake message sent back to a user interface from the DA proxy code (setup by `getAgent()`) over the `MessagePort` provided in the preceding Fdc3UserInterfaceHello message, confirming that it is listening to the `MessagePort` for further communication.", "type": "object", "allOf": [ { diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts b/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts index 3d9bb5fc8..d551712b3 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/drag.ts @@ -25,7 +25,7 @@ export function dragElement(drag: HTMLElement, selector: HTMLElement, position: } function dragMouseDown(e: MouseEvent) { - console.log('starting'); + console.debug('Channel Selector - DragMouseDown starting'); e.preventDefault(); // get the mouse cursor position at startup: posXStart = e.clientX; diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index 7d752ab26..4d5b46424 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -42,7 +42,6 @@ export class BasicFDC3Server implements FDC3Server { message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity | WebConnectionProtocol6Goodbye, from: InstanceID ): void { - // this.sc.log(`MessageReceived: \n ${JSON.stringify(message, null, 2)}`) this.handlers.forEach(h => h.accept(message, this.sc, from)); } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts index e2f660f52..a1f3e0916 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts @@ -40,8 +40,6 @@ export class HeartbeatHandler implements MessageHandler { constructor(pingInterval: number = 1000, disconnectedAfter: number = 5000, deadAfter: number = 20000) { this.timerFunction = setInterval(() => { - //console.log(`Contexts: ${this.contexts.length} Last Heartbeats: `, this.heartbeatTimes()) - this.contexts.forEach(async sc => { const apps = await sc.getAllApps(); apps @@ -126,16 +124,14 @@ export class HeartbeatHandler implements MessageHandler { } async sendHeartbeat(sc: ServerContext, app: FullAppIdentifier): Promise { - sc.post( - { - type: 'heartbeatEvent', - meta: { - timestamp: new Date(), - eventUuid: sc.createUUID(), - }, - payload: {}, - } as HeartbeatEvent, - app.instanceId - ); + const event: HeartbeatEvent = { + type: 'heartbeatEvent', + meta: { + timestamp: new Date(), + eventUuid: sc.createUUID(), + }, + payload: {}, + }; + sc.post(event, app.instanceId); } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts index 549e6da61..762493bff 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts @@ -183,8 +183,7 @@ export class OpenHandler implements MessageHandler { pendingOpen.setDone(); this.pending.delete(from); - //TODO: find a better/more certain way to get teh destination for this message - sc.post(message, arg0.meta.source?.instanceId!!); + sc.post(message, from); } } } @@ -302,16 +301,14 @@ export class OpenHandler implements MessageHandler { }; const returnError = () => { - sc.post( - { - meta: responseMeta, - type: 'WCP5ValidateAppIdentityFailedResponse', - payload: { - message: 'App Instance not found', - }, - } as WebConnectionProtocol5ValidateAppIdentityFailedResponse, - from - ); + const msg: WebConnectionProtocol5ValidateAppIdentityFailedResponse = { + meta: responseMeta, + type: 'WCP5ValidateAppIdentityFailedResponse', + payload: { + message: 'App Instance not found', + }, + }; + sc.post(msg, from); }; const returnSuccess = (appId: string, instanceId: string) => { From 180f24c181090322157bb84fcfb96f7a13bd09e1 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 18 Dec 2024 13:42:42 +0000 Subject: [PATCH 58/90] Refactored FailoverHandler into separate smaller functions, tidied up logging tests so it's clearer what they're doing --- .../src/strategies/FailoverHandler.ts | 117 +- .../test/features/utils.feature | 10 +- .../test/step-definitions/util.steps.ts | 12 +- .../fdc3-schema/generated/api/BrowserTypes.ts | 9645 +++++++++-------- 4 files changed, 5130 insertions(+), 4654 deletions(-) diff --git a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts index 931dce7a4..23b103948 100644 --- a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts @@ -5,6 +5,7 @@ import { v4 as uuidv4 } from 'uuid'; import { HelloHandler } from './HelloHandler'; import { IdentityValidationHandler } from './IdentityValidationHandler'; import { Logger } from '../util/Logger'; +import { ConnectionDetails } from '../messaging/MessagePortMessaging'; /** TypeGuard for a Desktop Agent */ function isDesktopAgent(da: WindowProxy | DesktopAgent): da is DesktopAgent { @@ -46,32 +47,13 @@ export class FailoverHandler { //set-up a event listeners in case the failover returns a Window that wants to message us const handshakePromise = this.helloHandler.listenForHelloResponses(); - //Run the failover function if (typeof this.options.failover === 'function') { const failoverResult = await this.options.failover(this.options); - //if the result was a Desktop Agent if (isDesktopAgent(failoverResult)) { - this.cancel(); - - //retrieve appId and instanceId from the DA - const implMetadata = await failoverResult.getInfo(); - const desktopAgentSelection: DesktopAgentSelection = { - agent: failoverResult, - details: { - agentType: WebDesktopAgentType.Failover, - identityUrl: globalThis.window.location.href, - actualUrl: globalThis.window.location.href, - appId: implMetadata.appMetadata.appId, - instanceId: implMetadata.appMetadata.instanceId ?? 'unknown', - instanceUuid: implMetadata.appMetadata.instanceId ?? 'unknown', // preload DAs don't issue these so repeat the instanceId - }, - }; - return desktopAgentSelection; + return await this.failoverResultIsDesktopAgent(failoverResult); } else if (isWindow(failoverResult)) { - //if the result was a Window/WindowProxy - //send a hello message - this.helloHandler.sendWCP1Hello(failoverResult, '*'); + return await this.failoverResultIsProxyWindow(failoverResult, handshakePromise); } else { Logger.error('Failover function returned an invalid result: ', failoverResult); throw AgentError.InvalidFailover; @@ -80,47 +62,70 @@ export class FailoverHandler { Logger.error('Failover was not a function, actual type: ', typeof this.options.failover); throw AgentError.InvalidFailover; } - - //if we received a WindowProxy from failover, and it sent us a handshake, try to validate its identity - const connectionDetails = await handshakePromise; - try { - this.identityValidationHandler = new IdentityValidationHandler( - connectionDetails.messagePort, - this.options, - this.connectionAttemptUuid - ); - const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); - this.identityValidationHandler.sendIdValidationMessage(); - const idDetails = await idValidationPromise; - const appIdentifier: AppIdentifier = { - appId: idDetails.payload.appId, - instanceId: idDetails.payload.instanceId, - }; - const desktopAgentSelection: DesktopAgentSelection = { - agent: await createDesktopAgentAPI(connectionDetails, appIdentifier), - details: { - agentType: connectionDetails.agentType, - agentUrl: connectionDetails.agentUrl ?? undefined, - identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, - actualUrl: connectionDetails.actualUrl, - appId: idDetails.payload.appId, - instanceId: idDetails.payload.instanceId, - instanceUuid: idDetails.payload.instanceUuid, - }, - }; - - return desktopAgentSelection; - } catch (e) { - //identity validation may have failed - Logger.error('Error during identity validation of Failover', e); - throw e; - } } finally { //cleanup any remaining listeners this.cancel(); } } + private async failoverResultIsProxyWindow(failoverResult: Window, handshakePromise: Promise) { + this.helloHandler.sendWCP1Hello(failoverResult, '*'); + + //if we received a WindowProxy from failover, and it sent us a handshake, try to validate its identity + const connectionDetails = await handshakePromise; + try { + this.identityValidationHandler = new IdentityValidationHandler( + connectionDetails.messagePort, + this.options, + this.connectionAttemptUuid + ); + const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + this.identityValidationHandler.sendIdValidationMessage(); + const idDetails = await idValidationPromise; + const appIdentifier: AppIdentifier = { + appId: idDetails.payload.appId, + instanceId: idDetails.payload.instanceId, + }; + const desktopAgentSelection: DesktopAgentSelection = { + agent: await createDesktopAgentAPI(connectionDetails, appIdentifier), + details: { + agentType: connectionDetails.agentType, + agentUrl: connectionDetails.agentUrl ?? undefined, + identityUrl: connectionDetails.options.identityUrl ?? connectionDetails.actualUrl, + actualUrl: connectionDetails.actualUrl, + appId: idDetails.payload.appId, + instanceId: idDetails.payload.instanceId, + instanceUuid: idDetails.payload.instanceUuid, + }, + }; + + return desktopAgentSelection; + } catch (e) { + //identity validation may have failed + Logger.error('Error during identity validation of Failover', e); + throw e; + } + } + + private async failoverResultIsDesktopAgent(failoverResult: DesktopAgent) { + this.cancel(); + + //retrieve appId and instanceId from the DA + const implMetadata = await failoverResult.getInfo(); + const desktopAgentSelection: DesktopAgentSelection = { + agent: failoverResult, + details: { + agentType: WebDesktopAgentType.Failover, + identityUrl: globalThis.window.location.href, + actualUrl: globalThis.window.location.href, + appId: implMetadata.appMetadata.appId, + instanceId: implMetadata.appMetadata.instanceId ?? 'unknown', + instanceUuid: implMetadata.appMetadata.instanceId ?? 'unknown', // preload DAs don't issue these so repeat the instanceId + }, + }; + return desktopAgentSelection; + } + /** Removes listeners so that events are no longer processed */ cancel() { this.helloHandler.cancel(); diff --git a/packages/fdc3-get-agent/test/features/utils.feature b/packages/fdc3-get-agent/test/features/utils.feature index e65525541..5f3026942 100644 --- a/packages/fdc3-get-agent/test/features/utils.feature +++ b/packages/fdc3-get-agent/test/features/utils.feature @@ -1,8 +1,8 @@ Feature: Utility functions -Scenario: Logger utility - When All log functions are used with a message - Then All log functions are used without a message + Scenario: Logger utility + When All log functions are used with a message + When All log functions are used with an error -Scenario: UUID generator - When A uuid is generated + Scenario: UUID generator + When A uuid is generated diff --git a/packages/fdc3-get-agent/test/step-definitions/util.steps.ts b/packages/fdc3-get-agent/test/step-definitions/util.steps.ts index 5ee511373..1648e6a00 100644 --- a/packages/fdc3-get-agent/test/step-definitions/util.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/util.steps.ts @@ -3,6 +3,8 @@ import { CustomWorld } from '../world'; import { Logger } from '../../src/util/Logger'; import { createUUID } from '../../src/util/Uuid'; +const TEST_ERROR = 'Test error - This is expected on the console'; + Given('All log functions are used with a message', async function (this: CustomWorld) { Logger.debug('Debug msg'); Logger.log('Log msg'); @@ -10,11 +12,11 @@ Given('All log functions are used with a message', async function (this: CustomW Logger.error('Error msg'); }); -Given('All log functions are used without a message', async function (this: CustomWorld) { - Logger.debug(new Error('Test error')); - Logger.log(new Error('Test error')); - Logger.warn(new Error('Test error')); - Logger.error(new Error('Test error')); +Given('All log functions are used with an error', async function (this: CustomWorld) { + Logger.debug(new Error(TEST_ERROR)); + Logger.log(new Error(TEST_ERROR)); + Logger.warn(new Error(TEST_ERROR)); + Logger.error(new Error(TEST_ERROR)); }); Given('A uuid is generated', async function (this: CustomWorld) { diff --git a/packages/fdc3-schema/generated/api/BrowserTypes.ts b/packages/fdc3-schema/generated/api/BrowserTypes.ts index 3b71a09d8..5f7a047c1 100644 --- a/packages/fdc3-schema/generated/api/BrowserTypes.ts +++ b/packages/fdc3-schema/generated/api/BrowserTypes.ts @@ -1,7 +1,15 @@ // To parse this data: // -// import { Convert, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannels, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage } from "./file"; +// import { Convert, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceChannels, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse } from "./file"; // +// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); +// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); +// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); +// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); +// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); +// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); +// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); +// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // const addContextListenerRequest = Convert.toAddContextListenerRequest(json); // const addContextListenerResponse = Convert.toAddContextListenerResponse(json); // const addEventListenerRequest = Convert.toAddEventListenerRequest(json); @@ -21,8 +29,8 @@ // const createPrivateChannelResponse = Convert.toCreatePrivateChannelResponse(json); // const eventListenerUnsubscribeRequest = Convert.toEventListenerUnsubscribeRequest(json); // const eventListenerUnsubscribeResponse = Convert.toEventListenerUnsubscribeResponse(json); -// const fdc3UserInterfaceChannels = Convert.toFdc3UserInterfaceChannels(json); // const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); +// const fdc3UserInterfaceChannels = Convert.toFdc3UserInterfaceChannels(json); // const fdc3UserInterfaceDrag = Convert.toFdc3UserInterfaceDrag(json); // const fdc3UserInterfaceHandshake = Convert.toFdc3UserInterfaceHandshake(json); // const fdc3UserInterfaceHello = Convert.toFdc3UserInterfaceHello(json); @@ -75,18 +83,542 @@ // const raiseIntentRequest = Convert.toRaiseIntentRequest(json); // const raiseIntentResponse = Convert.toRaiseIntentResponse(json); // const raiseIntentResultResponse = Convert.toRaiseIntentResultResponse(json); -// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); -// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); -// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); -// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); -// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); -// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); -// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); -// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // // These functions will throw an error if the JSON doesn't // match the expected interface, even if the JSON is valid. +/** + * Hello message sent by an application to a parent window or frame when attempting to + * establish connectivity to a Desktop Agent. + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol1Hello { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol1HelloPayload; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP1Hello'; +} + +/** + * Metadata for a Web Connection Protocol message. + */ +export interface WebConnectionProtocol1HelloMeta { + connectionAttemptUuid: string; + timestamp: Date; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol1HelloPayload { + /** + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. + */ + actualUrl: string; + /** + * A flag that may be used to indicate that a channel selector user interface is or is not + * required. Set to `false` if the app includes its own interface for selecting channels or + * does not work with user channels. + */ + channelSelector?: boolean; + /** + * The version of FDC3 API that the app supports. + */ + fdc3Version: string; + /** + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. + */ + identityUrl: string; + /** + * A flag that may be used to indicate that an intent resolver is or is not required. Set to + * `false` if no intents, or only targeted intents, are raised. + */ + intentResolver?: boolean; + [property: string]: any; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Response from a Desktop Agent to an application requesting access to it indicating that + * it should load a specified URL into a hidden iframe in order to establish connectivity to + * a Desktop Agent. + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol2LoadURL { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol2LoadURLPayload; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP2LoadUrl'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol2LoadURLPayload { + /** + * A URL which can be used to establish communication with the Desktop Agent, via loading + * the URL into an iframe and restarting the Web Connection protocol with the iframe as the + * target. + */ + iframeUrl: string; + [property: string]: any; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that + * should be used for subsequent communication steps. + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol3Handshake { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol3HandshakePayload; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP3Handshake'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol3HandshakePayload { + /** + * Indicates whether a channel selector user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the channel selector (as the + * Desktop Agent will handle it another way). + */ + channelSelectorUrl: boolean | string; + /** + * The version of FDC3 API that the Desktop Agent will provide support for. + */ + fdc3Version: string; + /** + * Indicates whether an intent resolver user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the intent resolver (as the + * Desktop Agent will handle it another way). + */ + intentResolverUrl: boolean | string; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Identity Validation request from an app attempting to connect to a Desktop Agent. + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol4ValidateAppIdentity { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol4ValidateAppIdentityPayload; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP4ValidateAppIdentity'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol4ValidateAppIdentityPayload { + /** + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. + */ + actualUrl: string; + /** + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. + */ + identityUrl: string; + /** + * If an application has previously connected to the Desktop Agent, it may specify its prior + * instance id and associated instance UUID to request the same same instance Id be assigned. + */ + instanceId?: string; + /** + * Instance UUID associated with the requested instanceId. + */ + instanceUuid?: string; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Message sent by the Desktop Agent to an app if their identity validation fails. + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP5ValidateAppIdentityFailedResponse'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { + message?: string; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Message sent by the Desktop Agent to an app after successful identity validation. + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol1HelloMeta; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP5ValidateAppIdentityResponse'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { + /** + * The appId that the app's identity was validated against. + */ + appId: string; + /** + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. + */ + implementationMetadata: ImplementationMetadata; + /** + * The instance Id granted to the application by the Desktop Agent. + */ + instanceId: string; + /** + * Instance UUID associated with the instanceId granted, which may be used to retrieve the + * same instanceId if the app is reloaded or navigates. + */ + instanceUuid: string; +} + +/** + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. + * + * Includes Metadata for the current application. + * + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + */ +export interface ImplementationMetadata { + /** + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). + */ + appMetadata: AppMetadata; + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). + * + * Extends an `AppIdentifier`, describing an application or instance of an application, with + * additional descriptive metadata that is usually provided by an FDC3 App Directory that + * the Desktop Agent connects to. + * + * The additional information from an app directory can aid in rendering UI elements, such + * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon + * and screenshot URLs. + * + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the + * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. + */ +export interface AppMetadata { + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * A longer, multi-paragraph description for the application that could include markup. + */ + description?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * A list of icon URLs for the application that can be used to render UI elements. + */ + icons?: Icon[]; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + /** + * An optional set of, implementation specific, metadata fields that can be used to + * disambiguate instances, such as a window title or screen position. Must only be set if + * `instanceId` is set. + */ + instanceMetadata?: { [key: string]: any }; + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now + * require an `AppIdentifier` wth `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to + * this field. + */ + name?: string; + /** + * The type of output returned for any intent specified during resolution. May express a + * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel + * that will receive a specified type (e.g. "channel"). + */ + resultType?: null | string; + /** + * Images representing the app in common usage scenarios that can be used to render UI + * elements. + */ + screenshots?: Image[]; + /** + * A more user-friendly application title that can be used to render UI elements. + */ + title?: string; + /** + * A tooltip for the application that can be used to render UI elements. + */ + tooltip?: string; + /** + * The Version of the application. + */ + version?: string; +} + +/** + * Describes an Icon image that may be used to represent the application. + */ +export interface Icon { + /** + * The icon dimension, formatted as `x`. + */ + size?: string; + /** + * The icon url. + */ + src: string; + /** + * Icon media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; +} + +/** + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. + */ +export interface Image { + /** + * Caption for the image. + */ + label?: string; + /** + * The image dimension, formatted as `x`. + */ + size?: string; + /** + * The image url. + */ + src: string; + /** + * Image media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; +} + +/** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ +export interface OptionalFeatures { + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + DesktopAgentBridging: boolean; + /** + * Used to indicate whether the exposure of 'originating app metadata' for + * context and intent messages is supported by the Desktop Agent. + */ + OriginatingAppMetadata: boolean; + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + UserChannelMembershipAPIs: boolean; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the + * window or navigating). Desktop Agents should close the MessagePort after receiving this + * message, but retain instance details in case the application reconnects (e.g. after a + * navigation event). + * + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocol6Goodbye { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: WebConnectionProtocol6GoodbyeMeta; + /** + * Identifies the type of the connection step message. + */ + type: 'WCP6Goodbye'; +} + +/** + * Metadata for a Web Connection Protocol message. + */ +export interface WebConnectionProtocol6GoodbyeMeta { + timestamp: Date; +} + +/** + * Identifies the type of the connection step message. + */ + +/** + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocolMessage { + /** + * Metadata for a Web Connection Protocol message. + */ + meta: ConnectionStepMetadata; + /** + * The message payload, containing data pertaining to this connection step. + */ + payload?: { [key: string]: any }; + /** + * Identifies the type of the connection step message. + */ + type: ConnectionStepMessageType; +} + +/** + * Metadata for a Web Connection Protocol message. + */ +export interface ConnectionStepMetadata { + timestamp: Date; + connectionAttemptUuid?: string; +} + +/** + * Identifies the type of the connection step message. + */ +export type ConnectionStepMessageType = + | 'WCP1Hello' + | 'WCP2LoadUrl' + | 'WCP3Handshake' + | 'WCP4ValidateAppIdentity' + | 'WCP5ValidateAppIdentityFailedResponse' + | 'WCP5ValidateAppIdentityResponse' + | 'WCP6Goodbye'; + /** * A request to add a context listener to a specified Channel OR to the current user * channel. Where the listener is added to the current user channel (channelId == null), and @@ -97,34 +629,34 @@ * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface AddContextListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddContextListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addContextListenerRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: AddContextListenerRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'addContextListenerRequest'; } /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ export interface AddContextListenerRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - */ - source?: AppIdentifier; - timestamp: Date; + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + */ + source?: AppIdentifier; + timestamp: Date; } /** @@ -156,38 +688,38 @@ export interface AddContextListenerRequestMeta { * received the intent. */ export interface AppIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; + /** + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + [property: string]: any; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface AddContextListenerRequestPayload { - /** - * The id of the channel to add the listener to or `null` indicating that it should listen - * to the current user channel (at the time of broadcast). - */ - channelId: null | string; - /** - * The type of context to listen for OR `null` indicating that it should listen to all - * context types. - */ - contextType: null | string; + /** + * The id of the channel to add the listener to or `null` indicating that it should listen + * to the current user channel (at the time of broadcast). + */ + channelId: null | string; + /** + * The type of context to listen for OR `null` indicating that it should listen to all + * context types. + */ + contextType: null | string; } /** @@ -205,35 +737,35 @@ export interface AddContextListenerRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface AddContextListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: AddContextListenerResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "addContextListenerResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: AddContextListenerResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'addContextListenerResponse'; } /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ export interface AddContextListenerResponseMeta { - requestUuid: string; - responseUuid: string; - /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - */ - source?: AppIdentifier; - timestamp: Date; + requestUuid: string; + responseUuid: string; + /** + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. + */ + source?: AppIdentifier; + timestamp: Date; } /** @@ -242,8 +774,8 @@ export interface AddContextListenerResponseMeta { * unsuccessful. */ export interface AddContextListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; + error?: PurpleError; + listenerUUID?: string; } /** @@ -254,7 +786,7 @@ export interface AddContextListenerResponsePayload { * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the * DesktopAgent (`fdc3`). */ -export type PurpleError = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound"; +export type PurpleError = 'AccessDenied' | 'CreationFailed' | 'MalformedContext' | 'NoChannelFound'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -267,29 +799,29 @@ export type PurpleError = "AccessDenied" | "CreationFailed" | "MalformedContext" * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface AddEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddEventListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addEventListenerRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: AddEventListenerRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'addEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface AddEventListenerRequestPayload { - /** - * The type of the event to be listened to or `null` to listen to all event types. - */ - type: "USER_CHANNEL_CHANGED" | null; + /** + * The type of the event to be listened to or `null` to listen to all event types. + */ + type: 'USER_CHANNEL_CHANGED' | null; } /** @@ -309,21 +841,21 @@ export interface AddEventListenerRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface AddEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: AddEventListenerResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "addEventListenerResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: AddEventListenerResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'addEventListenerResponse'; } /** @@ -332,8 +864,8 @@ export interface AddEventListenerResponse { * unsuccessful. */ export interface AddEventListenerResponsePayload { - error?: ResponsePayloadError; - listenerUUID?: string; + error?: ResponsePayloadError; + listenerUUID?: string; } /** @@ -344,7 +876,28 @@ export interface AddEventListenerResponsePayload { * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the * DesktopAgent (`fdc3`). */ -export type ResponsePayloadError = "AccessDenied" | "CreationFailed" | "MalformedContext" | "NoChannelFound" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "IntentHandlerRejected" | "NoResultReturned" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; +export type ResponsePayloadError = + | 'AccessDenied' + | 'CreationFailed' + | 'MalformedContext' + | 'NoChannelFound' + | 'AppNotFound' + | 'AppTimeout' + | 'DesktopAgentNotFound' + | 'ErrorOnLaunch' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution' + | 'IntentHandlerRejected' + | 'NoResultReturned' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -357,29 +910,29 @@ export type ResponsePayloadError = "AccessDenied" | "CreationFailed" | "Malforme * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface AddIntentListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: AddIntentListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "addIntentListenerRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: AddIntentListenerRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'addIntentListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface AddIntentListenerRequestPayload { - /** - * The name of the intent to listen for. - */ - intent: string; + /** + * The name of the intent to listen for. + */ + intent: string; } /** @@ -394,21 +947,21 @@ export interface AddIntentListenerRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface AddIntentListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: PayloadObject; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "addIntentListenerResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: PayloadObject; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'addIntentListenerResponse'; } /** @@ -417,9 +970,9 @@ export interface AddIntentListenerResponse { * unsuccessful. */ export interface PayloadObject { - error?: FluffyError; - listenerUUID?: string; - [property: string]: any; + error?: FluffyError; + listenerUUID?: string; + [property: string]: any; } /** @@ -430,34 +983,51 @@ export interface PayloadObject { * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the * DesktopAgent (`fdc3`). */ -export type FluffyError = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution"; +export type FluffyError = + | 'MalformedContext' + | 'DesktopAgentNotFound' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution'; /** * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ export interface AgentEventMessageMeta { - eventUuid: string; - timestamp: Date; + eventUuid: string; + timestamp: Date; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export type EventMessageType = "addEventListenerEvent" | "broadcastEvent" | "channelChangedEvent" | "heartbeatEvent" | "intentEvent" | "privateChannelOnAddContextListenerEvent" | "privateChannelOnDisconnectEvent" | "privateChannelOnUnsubscribeEvent"; +export type EventMessageType = + | 'addEventListenerEvent' + | 'broadcastEvent' + | 'channelChangedEvent' + | 'heartbeatEvent' + | 'intentEvent' + | 'privateChannelOnAddContextListenerEvent' + | 'privateChannelOnDisconnectEvent' + | 'privateChannelOnUnsubscribeEvent'; /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ export interface AgentResponseMessageMeta { - requestUuid: string; - responseUuid: string; - /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - */ - source?: AppIdentifier; - timestamp: Date; + requestUuid: string; + responseUuid: string; + /** + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. + */ + source?: AppIdentifier; + timestamp: Date; } /** @@ -466,36 +1036,90 @@ export interface AgentResponseMessageMeta { * unsuccessful. */ export interface AgentResponseMessageResponsePayload { - error?: ResponsePayloadError; - [property: string]: any; + error?: ResponsePayloadError; + [property: string]: any; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export type ResponseMessageType = "addContextListenerResponse" | "addEventListenerResponse" | "addIntentListenerResponse" | "broadcastResponse" | "contextListenerUnsubscribeResponse" | "createPrivateChannelResponse" | "eventListenerUnsubscribeResponse" | "findInstancesResponse" | "findIntentResponse" | "findIntentsByContextResponse" | "getAppMetadataResponse" | "getCurrentChannelResponse" | "getCurrentContextResponse" | "getInfoResponse" | "getOrCreateChannelResponse" | "getUserChannelsResponse" | "intentListenerUnsubscribeResponse" | "intentResultResponse" | "joinUserChannelResponse" | "leaveCurrentChannelResponse" | "openResponse" | "privateChannelAddEventListenerResponse" | "privateChannelDisconnectResponse" | "privateChannelUnsubscribeEventListenerResponse" | "raiseIntentForContextResponse" | "raiseIntentResponse" | "raiseIntentResultResponse"; +export type ResponseMessageType = + | 'addContextListenerResponse' + | 'addEventListenerResponse' + | 'addIntentListenerResponse' + | 'broadcastResponse' + | 'contextListenerUnsubscribeResponse' + | 'createPrivateChannelResponse' + | 'eventListenerUnsubscribeResponse' + | 'findInstancesResponse' + | 'findIntentResponse' + | 'findIntentsByContextResponse' + | 'getAppMetadataResponse' + | 'getCurrentChannelResponse' + | 'getCurrentContextResponse' + | 'getInfoResponse' + | 'getOrCreateChannelResponse' + | 'getUserChannelsResponse' + | 'intentListenerUnsubscribeResponse' + | 'intentResultResponse' + | 'joinUserChannelResponse' + | 'leaveCurrentChannelResponse' + | 'openResponse' + | 'privateChannelAddEventListenerResponse' + | 'privateChannelDisconnectResponse' + | 'privateChannelUnsubscribeEventListenerResponse' + | 'raiseIntentForContextResponse' + | 'raiseIntentResponse' + | 'raiseIntentResultResponse'; /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ export interface AppRequestMessageMeta { - requestUuid: string; - /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - */ - source?: AppIdentifier; - timestamp: Date; + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + */ + source?: AppIdentifier; + timestamp: Date; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export type RequestMessageType = "addContextListenerRequest" | "addEventListenerRequest" | "addIntentListenerRequest" | "broadcastRequest" | "contextListenerUnsubscribeRequest" | "createPrivateChannelRequest" | "eventListenerUnsubscribeRequest" | "findInstancesRequest" | "findIntentRequest" | "findIntentsByContextRequest" | "getAppMetadataRequest" | "getCurrentChannelRequest" | "getCurrentContextRequest" | "getInfoRequest" | "getOrCreateChannelRequest" | "getUserChannelsRequest" | "heartbeatAcknowledgementRequest" | "intentListenerUnsubscribeRequest" | "intentResultRequest" | "joinUserChannelRequest" | "leaveCurrentChannelRequest" | "openRequest" | "privateChannelAddEventListenerRequest" | "privateChannelDisconnectRequest" | "privateChannelUnsubscribeEventListenerRequest" | "raiseIntentForContextRequest" | "raiseIntentRequest"; +export type RequestMessageType = + | 'addContextListenerRequest' + | 'addEventListenerRequest' + | 'addIntentListenerRequest' + | 'broadcastRequest' + | 'contextListenerUnsubscribeRequest' + | 'createPrivateChannelRequest' + | 'eventListenerUnsubscribeRequest' + | 'findInstancesRequest' + | 'findIntentRequest' + | 'findIntentsByContextRequest' + | 'getAppMetadataRequest' + | 'getCurrentChannelRequest' + | 'getCurrentContextRequest' + | 'getInfoRequest' + | 'getOrCreateChannelRequest' + | 'getUserChannelsRequest' + | 'heartbeatAcknowledgementRequest' + | 'intentListenerUnsubscribeRequest' + | 'intentResultRequest' + | 'joinUserChannelRequest' + | 'leaveCurrentChannelRequest' + | 'openRequest' + | 'privateChannelAddEventListenerRequest' + | 'privateChannelDisconnectRequest' + | 'privateChannelUnsubscribeEventListenerRequest' + | 'raiseIntentForContextRequest' + | 'raiseIntentRequest'; /** * An event message from the Desktop Agent to an app indicating that context has been @@ -505,46 +1129,46 @@ export type RequestMessageType = "addContextListenerRequest" | "addEventListener * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface BroadcastEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: BroadcastEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "broadcastEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: BroadcastEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'broadcastEvent'; } /** * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ export interface BroadcastEventMeta { - eventUuid: string; - timestamp: Date; + eventUuid: string; + timestamp: Date; } /** * The message payload contains details of the event that the app is being notified about. */ export interface BroadcastEventPayload { - /** - * The Id of the channel that the broadcast was sent on. May be `null` if the context is - * being broadcast due to a call `fdc3.open` that passed context. - */ - channelId: null | string; - /** - * The context object that was broadcast. - */ - context: Context; - /** - * Details of the application instance that broadcast the context. - */ - originatingApp?: AppIdentifier; + /** + * The Id of the channel that the broadcast was sent on. May be `null` if the context is + * being broadcast due to a call `fdc3.open` that passed context. + */ + channelId: null | string; + /** + * The context object that was broadcast. + */ + context: Context; + /** + * Details of the application instance that broadcast the context. + */ + originatingApp?: AppIdentifier; } /** @@ -571,44 +1195,44 @@ export interface BroadcastEventPayload { * with custom fields as appropriate. */ export interface Context { - /** - * Context data objects may include a set of equivalent key-value pairs that can be used to - * help applications identify and look up the context type they receive in their own domain. - * The idea behind this design is that applications can provide as many equivalent - * identifiers to a target application as possible, e.g. an instrument may be represented by - * an ISIN, CUSIP or Bloomberg identifier. - * - * Identifiers do not make sense for all types of data, so the `id` property is therefore - * optional, but some derived types may choose to require at least one identifier. - * Identifier values SHOULD always be of type string. - */ - id?: { [key: string]: any }; - /** - * Context data objects may include a name property that can be used for more information, - * or display purposes. Some derived types may require the name object as mandatory, - * depending on use case. - */ - name?: string; - /** - * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 - * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present - * to route shared context data appropriately. - * - * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data - * types they support in an FDC3 [App - * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery - * and routing. - * - * Standardized FDC3 context types have well-known `type` properties prefixed with the - * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and - * used by a particular organization, the convention is to prefix them with an - * organization-specific namespace, e.g. `blackrock.fund`. - * - * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more - * information about context data types. - */ - type: string; - [property: string]: any; + /** + * Context data objects may include a set of equivalent key-value pairs that can be used to + * help applications identify and look up the context type they receive in their own domain. + * The idea behind this design is that applications can provide as many equivalent + * identifiers to a target application as possible, e.g. an instrument may be represented by + * an ISIN, CUSIP or Bloomberg identifier. + * + * Identifiers do not make sense for all types of data, so the `id` property is therefore + * optional, but some derived types may choose to require at least one identifier. + * Identifier values SHOULD always be of type string. + */ + id?: { [key: string]: any }; + /** + * Context data objects may include a name property that can be used for more information, + * or display purposes. Some derived types may require the name object as mandatory, + * depending on use case. + */ + name?: string; + /** + * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 + * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present + * to route shared context data appropriately. + * + * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data + * types they support in an FDC3 [App + * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery + * and routing. + * + * Standardized FDC3 context types have well-known `type` properties prefixed with the + * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and + * used by a particular organization, the convention is to prefix them with an + * organization-specific namespace, e.g. `blackrock.fund`. + * + * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more + * information about context data types. + */ + type: string; + [property: string]: any; } /** @@ -622,33 +1246,33 @@ export interface Context { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface BroadcastRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: BroadcastRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "broadcastRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: BroadcastRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'broadcastRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface BroadcastRequestPayload { - /** - * The Id of the Channel that the broadcast was sent on. - */ - channelId: string; - /** - * The context object that is to be broadcast. - */ - context: Context; + /** + * The Id of the Channel that the broadcast was sent on. + */ + channelId: string; + /** + * The context object that is to be broadcast. + */ + context: Context; } /** @@ -663,21 +1287,21 @@ export interface BroadcastRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface BroadcastResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: BroadcastResponseResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "broadcastResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'broadcastResponse'; } /** @@ -686,8 +1310,8 @@ export interface BroadcastResponse { * unsuccessful. */ export interface BroadcastResponseResponsePayload { - error?: ResponsePayloadError; - [property: string]: any; + error?: ResponsePayloadError; + [property: string]: any; } /** @@ -702,30 +1326,30 @@ export interface BroadcastResponseResponsePayload { * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface ChannelChangedEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: ChannelChangedEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "channelChangedEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: ChannelChangedEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'channelChangedEvent'; } /** * The message payload contains details of the event that the app is being notified about. */ export interface ChannelChangedEventPayload { - /** - * The Id of the channel that the app was added to or `null` if it was removed from a - * channel. - */ - newChannelId: null | string; + /** + * The Id of the channel that the app was added to or `null` if it was removed from a + * channel. + */ + newChannelId: null | string; } /** @@ -739,26 +1363,26 @@ export interface ChannelChangedEventPayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface ContextListenerUnsubscribeRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: ContextListenerUnsubscribeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "contextListenerUnsubscribeRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: ContextListenerUnsubscribeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'contextListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface ContextListenerUnsubscribeRequestPayload { - listenerUUID: string; + listenerUUID: string; } /** @@ -773,21 +1397,21 @@ export interface ContextListenerUnsubscribeRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface ContextListenerUnsubscribeResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: BroadcastResponseResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "contextListenerUnsubscribeResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'contextListenerUnsubscribeResponse'; } /** @@ -802,26 +1426,25 @@ export interface ContextListenerUnsubscribeResponse { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface CreatePrivateChannelRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: CreatePrivateChannelRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "createPrivateChannelRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: CreatePrivateChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'createPrivateChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface CreatePrivateChannelRequestPayload { -} +export interface CreatePrivateChannelRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -835,21 +1458,21 @@ export interface CreatePrivateChannelRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface CreatePrivateChannelResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: CreatePrivateChannelResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "createPrivateChannelResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: CreatePrivateChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'createPrivateChannelResponse'; } /** @@ -858,8 +1481,8 @@ export interface CreatePrivateChannelResponse { * unsuccessful. */ export interface CreatePrivateChannelResponsePayload { - error?: PurpleError; - privateChannel?: Channel; + error?: PurpleError; + privateChannel?: Channel; } /** @@ -877,21 +1500,21 @@ export interface CreatePrivateChannelResponsePayload { * function. */ export interface Channel { - /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. - */ - displayMetadata?: DisplayMetadata; - /** - * Constant that uniquely identifies this channel. - */ - id: string; - /** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". - */ - type: Type; + /** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + */ + displayMetadata?: DisplayMetadata; + /** + * Constant that uniquely identifies this channel. + */ + id: string; + /** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ + type: Type; } /** @@ -906,26 +1529,26 @@ export interface Channel { * this is their meaning. */ export interface DisplayMetadata { - /** - * The color that should be associated within this channel when displaying this channel in a - * UI, e.g: `0xFF0000`. - */ - color?: string; - /** - * A URL of an image that can be used to display this channel. - */ - glyph?: string; - /** - * A user-readable name for this channel, e.g: `"Red"`. - */ - name?: string; + /** + * The color that should be associated within this channel when displaying this channel in a + * UI, e.g: `0xFF0000`. + */ + color?: string; + /** + * A URL of an image that can be used to display this channel. + */ + glyph?: string; + /** + * A user-readable name for this channel, e.g: `"Red"`. + */ + name?: string; } /** * Uniquely defines each channel type. * Can be "user", "app" or "private". */ -export type Type = "app" | "private" | "user"; +export type Type = 'app' | 'private' | 'user'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -938,26 +1561,26 @@ export type Type = "app" | "private" | "user"; * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface EventListenerUnsubscribeRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: EventListenerUnsubscribeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "eventListenerUnsubscribeRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: EventListenerUnsubscribeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'eventListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface EventListenerUnsubscribeRequestPayload { - listenerUUID: string; + listenerUUID: string; } /** @@ -972,21 +1595,21 @@ export interface EventListenerUnsubscribeRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface EventListenerUnsubscribeResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: BroadcastResponseResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "eventListenerUnsubscribeResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'eventListenerUnsubscribeResponse'; } /** @@ -995,37 +1618,33 @@ export interface EventListenerUnsubscribeResponse { */ /** - * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an - * iframe with the channel definitions and current channel selection. + * Message from a channel selector UI to the DA proxy sent when the channel selection + * changes. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceChannels { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceChannelsPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceChannels"; +export interface Fdc3UserInterfaceChannelSelected { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelSelectedPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceChannelSelected'; } /** * The message payload. */ -export interface Fdc3UserInterfaceChannelsPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; - /** - * User Channel definitions.```````s - */ - userChannels: Channel[]; +export interface Fdc3UserInterfaceChannelSelectedPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; } /** @@ -1033,33 +1652,37 @@ export interface Fdc3UserInterfaceChannelsPayload { */ /** - * Message from a channel selector UI to the DA proxy sent when the channel selection - * changes. + * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an + * iframe with the channel definitions and current channel selection. * * A message used to communicate with user interface frames injected by `getAgent()` for * displaying UI elements such as the intent resolver or channel selector. Used for messages * sent in either direction. */ -export interface Fdc3UserInterfaceChannelSelected { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceChannelSelectedPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceChannelSelected"; +export interface Fdc3UserInterfaceChannels { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelsPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceChannels'; } /** * The message payload. */ -export interface Fdc3UserInterfaceChannelSelectedPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; +export interface Fdc3UserInterfaceChannelsPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; + /** + * User Channel definitions.```````s + */ + userChannels: Channel[]; } /** @@ -1077,32 +1700,32 @@ export interface Fdc3UserInterfaceChannelSelectedPayload { * sent in either direction. */ export interface Fdc3UserInterfaceDrag { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceDragPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceDrag"; + /** + * The message payload. + */ + payload: Fdc3UserInterfaceDragPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceDrag'; } /** * The message payload. */ export interface Fdc3UserInterfaceDragPayload { - /** - * The offset to move the frame by. - */ - mouseOffsets: MouseOffsets; + /** + * The offset to move the frame by. + */ + mouseOffsets: MouseOffsets; } /** * The offset to move the frame by. */ export interface MouseOffsets { - x: number; - y: number; + x: number; + y: number; } /** @@ -1119,24 +1742,24 @@ export interface MouseOffsets { * sent in either direction. */ export interface Fdc3UserInterfaceHandshake { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceHandshakePayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceHandshake"; + /** + * The message payload. + */ + payload: Fdc3UserInterfaceHandshakePayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceHandshake'; } /** * The message payload. */ export interface Fdc3UserInterfaceHandshakePayload { - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; + /** + * The version of FDC3 API that the Desktop Agent will provide support for. + */ + fdc3Version: string; } /** @@ -1153,29 +1776,29 @@ export interface Fdc3UserInterfaceHandshakePayload { * sent in either direction. */ export interface Fdc3UserInterfaceHello { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceHelloPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceHello"; + /** + * The message payload. + */ + payload: Fdc3UserInterfaceHelloPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceHello'; } /** * The message payload. */ export interface Fdc3UserInterfaceHelloPayload { - /** - * Details about the UI implementation, such as vendor and version, for logging purposes. - */ - implementationDetails: string; - /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. - */ - initialCSS: InitialCSS; + /** + * Details about the UI implementation, such as vendor and version, for logging purposes. + */ + implementationDetails: string; + /** + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + */ + initialCSS: InitialCSS; } /** @@ -1183,47 +1806,47 @@ export interface Fdc3UserInterfaceHelloPayload { * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. */ export interface InitialCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The initial height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; - /** - * The transition property to apply to the iframe. - */ - transition?: string; - /** - * The initial width of the iframe. - */ - width?: string; - /** - * The initial zindex to apply to the iframe. - */ - zIndex?: string; - [property: string]: any; + /** + * The initial bottom property to apply to the iframe. + */ + bottom?: string; + /** + * The initial height of the iframe. + */ + height?: string; + /** + * The initial left property to apply to the iframe. + */ + left?: string; + /** + * The maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; + /** + * The transition property to apply to the iframe. + */ + transition?: string; + /** + * The initial width of the iframe. + */ + width?: string; + /** + * The initial zindex to apply to the iframe. + */ + zIndex?: string; + [property: string]: any; } /** @@ -1236,20 +1859,28 @@ export interface InitialCSS { * sent in either direction. */ export interface Fdc3UserInterfaceMessage { - /** - * The message payload. - */ - payload?: { [key: string]: any }; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: Fdc3UserInterfaceMessageType; + /** + * The message payload. + */ + payload?: { [key: string]: any }; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: Fdc3UserInterfaceMessageType; } /** * Identifies the type of the message to or from the user interface frame. */ -export type Fdc3UserInterfaceMessageType = "Fdc3UserInterfaceHello" | "Fdc3UserInterfaceHandshake" | "Fdc3UserInterfaceRestyle" | "Fdc3UserInterfaceDrag" | "Fdc3UserInterfaceResolve" | "Fdc3UserInterfaceResolveAction" | "Fdc3UserInterfaceChannels" | "Fdc3UserInterfaceChannelSelected"; +export type Fdc3UserInterfaceMessageType = + | 'Fdc3UserInterfaceHello' + | 'Fdc3UserInterfaceHandshake' + | 'Fdc3UserInterfaceRestyle' + | 'Fdc3UserInterfaceDrag' + | 'Fdc3UserInterfaceResolve' + | 'Fdc3UserInterfaceResolveAction' + | 'Fdc3UserInterfaceChannels' + | 'Fdc3UserInterfaceChannelSelected'; /** * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the @@ -1260,25 +1891,25 @@ export type Fdc3UserInterfaceMessageType = "Fdc3UserInterfaceHello" | "Fdc3UserI * sent in either direction. */ export interface Fdc3UserInterfaceResolve { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceResolvePayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceResolve"; + /** + * The message payload. + */ + payload: Fdc3UserInterfaceResolvePayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceResolve'; } /** * The message payload. */ export interface Fdc3UserInterfaceResolvePayload { - /** - * An array of AppIntent objects defining the resolution options. - */ - appIntents: AppIntent[]; - context: Context; + /** + * An array of AppIntent objects defining the resolution options. + */ + appIntents: AppIntent[]; + context: Context; } /** @@ -1288,149 +1919,30 @@ export interface Fdc3UserInterfaceResolvePayload { * resolver) before it can be handled. */ export interface AppIntent { - /** - * Details of applications that can resolve the intent. - */ - apps: AppMetadata[]; - /** - * Details of the intent whose relationship to resolving applications is being described. - */ - intent: IntentMetadata; + /** + * Details of applications that can resolve the intent. + */ + apps: AppMetadata[]; + /** + * Details of the intent whose relationship to resolving applications is being described. + */ + intent: IntentMetadata; } /** - * Extends an `AppIdentifier`, describing an application or instance of an application, with - * additional descriptive metadata that is usually provided by an FDC3 App Directory that - * the Desktop Agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such - * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon - * and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the - * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. - * - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - */ -export interface AppMetadata { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * A longer, multi-paragraph description for the application that could include markup. - */ - description?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * A list of icon URLs for the application that can be used to render UI elements. - */ - icons?: Icon[]; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - /** - * An optional set of, implementation specific, metadata fields that can be used to - * disambiguate instances, such as a window title or screen position. Must only be set if - * `instanceId` is set. - */ - instanceMetadata?: { [key: string]: any }; - /** - * The 'friendly' app name. - * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now - * require an `AppIdentifier` wth `appId` set. - * Note that for display purposes the `title` field should be used, if set, in preference to - * this field. - */ - name?: string; - /** - * The type of output returned for any intent specified during resolution. May express a - * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel - * that will receive a specified type (e.g. "channel"). - */ - resultType?: null | string; - /** - * Images representing the app in common usage scenarios that can be used to render UI - * elements. - */ - screenshots?: Image[]; - /** - * A more user-friendly application title that can be used to render UI elements. - */ - title?: string; - /** - * A tooltip for the application that can be used to render UI elements. - */ - tooltip?: string; - /** - * The Version of the application. - */ - version?: string; -} - -/** - * Describes an Icon image that may be used to represent the application. - */ -export interface Icon { - /** - * The icon dimension, formatted as `x`. - */ - size?: string; - /** - * The icon url. - */ - src: string; - /** - * Icon media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Describes an image file, typically a screenshot, that often represents the application in - * a common usage scenario. - */ -export interface Image { - /** - * Caption for the image. - */ - label?: string; - /** - * The image dimension, formatted as `x`. - */ - size?: string; - /** - * The image url. - */ - src: string; - /** - * Image media type. If not present the Desktop Agent may use the src file extension. - */ - type?: string; -} - -/** - * Details of the intent whose relationship to resolving applications is being described. + * Details of the intent whose relationship to resolving applications is being described. * * Metadata describing an Intent. */ export interface IntentMetadata { - /** - * Display name for the intent. - */ - displayName?: string; - /** - * The unique name of the intent that can be invoked by the raiseIntent call. - */ - name: string; + /** + * Display name for the intent. + */ + displayName?: string; + /** + * The unique name of the intent that can be invoked by the raiseIntent call. + */ + name: string; } /** @@ -1446,32 +1958,32 @@ export interface IntentMetadata { * sent in either direction. */ export interface Fdc3UserInterfaceResolveAction { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceResolveActionPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceResolveAction"; + /** + * The message payload. + */ + payload: Fdc3UserInterfaceResolveActionPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceResolveAction'; } /** * The message payload. */ export interface Fdc3UserInterfaceResolveActionPayload { - action: Action; - /** - * The App resolution option chosen. - */ - appIdentifier?: AppIdentifier; - /** - * The intent resolved. - */ - intent?: string; + action: Action; + /** + * The App resolution option chosen. + */ + appIdentifier?: AppIdentifier; + /** + * The intent resolved. + */ + intent?: string; } -export type Action = "hover" | "click" | "cancel"; +export type Action = 'hover' | 'click' | 'cancel'; /** * Identifies the type of the message to or from the user interface frame. @@ -1487,25 +1999,25 @@ export type Action = "hover" | "click" | "cancel"; * sent in either direction. */ export interface Fdc3UserInterfaceRestyle { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceRestylePayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: "Fdc3UserInterfaceRestyle"; + /** + * The message payload. + */ + payload: Fdc3UserInterfaceRestylePayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceRestyle'; } /** * The message payload. */ export interface Fdc3UserInterfaceRestylePayload { - /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. - */ - updatedCSS: UpdatedCSS; + /** + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. + */ + updatedCSS: UpdatedCSS; } /** @@ -1513,47 +2025,47 @@ export interface Fdc3UserInterfaceRestylePayload { * `position` cannot be set, and should always be `fixed`. */ export interface UpdatedCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The updated height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The updated maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The updated maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; - /** - * The updated transition property to apply to the iframe. - */ - transition?: string; - /** - * The updated width of the iframe. - */ - width?: string; - /** - * The updated zIndex to apply to the iframe. - */ - zIndex?: string; - [property: string]: any; + /** + * The initial bottom property to apply to the iframe. + */ + bottom?: string; + /** + * The updated height of the iframe. + */ + height?: string; + /** + * The initial left property to apply to the iframe. + */ + left?: string; + /** + * The updated maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The updated maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; + /** + * The updated transition property to apply to the iframe. + */ + transition?: string; + /** + * The updated width of the iframe. + */ + width?: string; + /** + * The updated zIndex to apply to the iframe. + */ + zIndex?: string; + [property: string]: any; } /** @@ -1566,26 +2078,26 @@ export interface UpdatedCSS { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface FindInstancesRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindInstancesRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "findInstancesRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindInstancesRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'findInstancesRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface FindInstancesRequestPayload { - app: AppIdentifier; + app: AppIdentifier; } /** @@ -1600,21 +2112,21 @@ export interface FindInstancesRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface FindInstancesResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: FindInstancesResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "findInstancesResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: FindInstancesResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'findInstancesResponse'; } /** @@ -1627,8 +2139,8 @@ export interface FindInstancesResponse { * resulted in an error and including a standardized error message. */ export interface FindInstancesResponsePayload { - error?: FindInstancesErrors; - appIdentifiers?: AppMetadata[]; + error?: FindInstancesErrors; + appIdentifiers?: AppMetadata[]; } /** @@ -1639,6 +2151,10 @@ export interface FindInstancesResponsePayload { * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the * DesktopAgent (`fdc3`). * + * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID + * should be used in the first (WCP1Hello) message and should be quoted in all subsequent + * messages to link them to the same connection attempt. + * * Unique identifier for a request or event message. Required in all message types. * * Unique identifier for a response to a specific message and must always be accompanied by @@ -1650,13 +2166,22 @@ export interface FindInstancesResponsePayload { * * Unique identifier for an event message sent from a Desktop Agent to an app. * - * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID - * should be used in the first (WCP1Hello) message and should be quoted in all subsequent - * messages to link them to the same connection attempt. - * * Should be set if the raiseIntent request returned an error. */ -export type FindInstancesErrors = "MalformedContext" | "DesktopAgentNotFound" | "ResolverUnavailable" | "IntentDeliveryFailed" | "NoAppsFound" | "ResolverTimeout" | "TargetAppUnavailable" | "TargetInstanceUnavailable" | "UserCancelledResolution" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; +export type FindInstancesErrors = + | 'MalformedContext' + | 'DesktopAgentNotFound' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -1669,28 +2194,28 @@ export type FindInstancesErrors = "MalformedContext" | "DesktopAgentNotFound" | * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface FindIntentRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindIntentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "findIntentRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'findIntentRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface FindIntentRequestPayload { - context?: Context; - intent: string; - resultType?: string; + context?: Context; + intent: string; + resultType?: string; } /** @@ -1705,21 +2230,21 @@ export interface FindIntentRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface FindIntentResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: FindIntentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "findIntentResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: FindIntentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'findIntentResponse'; } /** @@ -1728,8 +2253,8 @@ export interface FindIntentResponse { * unsuccessful. */ export interface FindIntentResponsePayload { - error?: FindInstancesErrors; - appIntent?: AppIntent; + error?: FindInstancesErrors; + appIntent?: AppIntent; } /** @@ -1744,27 +2269,27 @@ export interface FindIntentResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface FindIntentsByContextRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: FindIntentsByContextRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "findIntentsByContextRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: FindIntentsByContextRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'findIntentsByContextRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface FindIntentsByContextRequestPayload { - context: Context; - resultType?: string; + context: Context; + resultType?: string; } /** @@ -1779,21 +2304,21 @@ export interface FindIntentsByContextRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface FindIntentsByContextResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: FindIntentsByContextResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "findIntentsByContextResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: FindIntentsByContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'findIntentsByContextResponse'; } /** @@ -1802,8 +2327,8 @@ export interface FindIntentsByContextResponse { * unsuccessful. */ export interface FindIntentsByContextResponsePayload { - error?: FindInstancesErrors; - appIntents?: AppIntent[]; + error?: FindInstancesErrors; + appIntents?: AppIntent[]; } /** @@ -1817,26 +2342,26 @@ export interface FindIntentsByContextResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface GetAppMetadataRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetAppMetadataRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "getAppMetadataRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetAppMetadataRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getAppMetadataRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface GetAppMetadataRequestPayload { - app: AppIdentifier; + app: AppIdentifier; } /** @@ -1851,21 +2376,21 @@ export interface GetAppMetadataRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface GetAppMetadataResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: GetAppMetadataResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "getAppMetadataResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: GetAppMetadataResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getAppMetadataResponse'; } /** @@ -1874,8 +2399,8 @@ export interface GetAppMetadataResponse { * unsuccessful. */ export interface GetAppMetadataResponsePayload { - error?: FindInstancesErrors; - appMetadata?: AppMetadata; + error?: FindInstancesErrors; + appMetadata?: AppMetadata; } /** @@ -1890,26 +2415,25 @@ export interface GetAppMetadataResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface GetCurrentChannelRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetCurrentChannelRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "getCurrentChannelRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetCurrentChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getCurrentChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentChannelRequestPayload { -} +export interface GetCurrentChannelRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -1923,21 +2447,21 @@ export interface GetCurrentChannelRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface GetCurrentChannelResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: GetCurrentChannelResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "getCurrentChannelResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: GetCurrentChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getCurrentChannelResponse'; } /** @@ -1946,8 +2470,8 @@ export interface GetCurrentChannelResponse { * unsuccessful. */ export interface GetCurrentChannelResponsePayload { - error?: ResponsePayloadError; - channel?: Channel | null; + error?: ResponsePayloadError; + channel?: Channel | null; } /** @@ -1963,34 +2487,34 @@ export interface GetCurrentChannelResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface GetCurrentContextRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetCurrentContextRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "getCurrentContextRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetCurrentContextRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getCurrentContextRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface GetCurrentContextRequestPayload { - /** - * The id of the channel to return the current context of. - */ - channelId: string; - /** - * The type of context to return for OR `null` indicating that the most recently broadcast - * context on the channel should be returned. - */ - contextType: null | string; + /** + * The id of the channel to return the current context of. + */ + channelId: string; + /** + * The type of context to return for OR `null` indicating that the most recently broadcast + * context on the channel should be returned. + */ + contextType: null | string; } /** @@ -2005,21 +2529,21 @@ export interface GetCurrentContextRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface GetCurrentContextResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: GetCurrentContextResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "getCurrentContextResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: GetCurrentContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getCurrentContextResponse'; } /** @@ -2028,12 +2552,12 @@ export interface GetCurrentContextResponse { * unsuccessful. */ export interface GetCurrentContextResponsePayload { - error?: PurpleError; - /** - * The most recently broadcast context object (of the specified type, if one was specified), - * or `null` if none was available in the channel. - */ - context?: null | Context; + error?: PurpleError; + /** + * The most recently broadcast context object (of the specified type, if one was specified), + * or `null` if none was available in the channel. + */ + context?: null | Context; } /** @@ -2048,26 +2572,25 @@ export interface GetCurrentContextResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface GetInfoRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetInfoRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "getInfoRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetInfoRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getInfoRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetInfoRequestPayload { -} +export interface GetInfoRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2081,21 +2604,21 @@ export interface GetInfoRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface GetInfoResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: GetInfoResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "getInfoResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: GetInfoResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getInfoResponse'; } /** @@ -2104,66 +2627,8 @@ export interface GetInfoResponse { * unsuccessful. */ export interface GetInfoResponsePayload { - error?: ResponsePayloadError; - implementationMetadata?: ImplementationMetadata; -} - -/** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - * - * Includes Metadata for the current application. - * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. - */ -export interface ImplementationMetadata { - /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - */ - appMetadata: AppMetadata; - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; -} - -/** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ -export interface OptionalFeatures { - /** - * Used to indicate whether the experimental Desktop Agent Bridging - * feature is implemented by the Desktop Agent. - */ - DesktopAgentBridging: boolean; - /** - * Used to indicate whether the exposure of 'originating app metadata' for - * context and intent messages is supported by the Desktop Agent. - */ - OriginatingAppMetadata: boolean; - /** - * Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent. - */ - UserChannelMembershipAPIs: boolean; + error?: ResponsePayloadError; + implementationMetadata?: ImplementationMetadata; } /** @@ -2178,29 +2643,29 @@ export interface OptionalFeatures { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface GetOrCreateChannelRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetOrCreateChannelRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "getOrCreateChannelRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetOrCreateChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getOrCreateChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface GetOrCreateChannelRequestPayload { - /** - * The id of the channel to return - */ - channelId: string; + /** + * The id of the channel to return + */ + channelId: string; } /** @@ -2215,21 +2680,21 @@ export interface GetOrCreateChannelRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface GetOrCreateChannelResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: GetOrCreateChannelResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "getOrCreateChannelResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: GetOrCreateChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getOrCreateChannelResponse'; } /** @@ -2238,8 +2703,8 @@ export interface GetOrCreateChannelResponse { * unsuccessful. */ export interface GetOrCreateChannelResponsePayload { - error?: PurpleError; - channel?: Channel; + error?: PurpleError; + channel?: Channel; } /** @@ -2253,26 +2718,25 @@ export interface GetOrCreateChannelResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface GetUserChannelsRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: GetUserChannelsRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "getUserChannelsRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: GetUserChannelsRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getUserChannelsRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetUserChannelsRequestPayload { -} +export interface GetUserChannelsRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2286,21 +2750,21 @@ export interface GetUserChannelsRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface GetUserChannelsResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: GetUserChannelsResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "getUserChannelsResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: GetUserChannelsResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getUserChannelsResponse'; } /** @@ -2309,8 +2773,8 @@ export interface GetUserChannelsResponse { * unsuccessful. */ export interface GetUserChannelsResponsePayload { - error?: PurpleError; - userChannels?: Channel[]; + error?: PurpleError; + userChannels?: Channel[]; } /** @@ -2325,29 +2789,29 @@ export interface GetUserChannelsResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface HeartbeatAcknowledgementRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: HeartbeatAcknowledgementRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "heartbeatAcknowledgementRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: HeartbeatAcknowledgementRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'heartbeatAcknowledgementRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface HeartbeatAcknowledgementRequestPayload { - /** - * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. - */ - heartbeatEventUuid: string; + /** + * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. + */ + heartbeatEventUuid: string; } /** @@ -2363,26 +2827,25 @@ export interface HeartbeatAcknowledgementRequestPayload { * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface HeartbeatEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: HeartbeatEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "heartbeatEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: HeartbeatEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'heartbeatEvent'; } /** * The message payload contains details of the event that the app is being notified about. */ -export interface HeartbeatEventPayload { -} +export interface HeartbeatEventPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2396,42 +2859,42 @@ export interface HeartbeatEventPayload { * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface IntentEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: IntentEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "intentEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: IntentEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'intentEvent'; } /** * The message payload contains details of the event that the app is being notified about. */ export interface IntentEventPayload { - /** - * The context object passed with the raised intent. - */ - context: Context; - /** - * The intent that was raised. - */ - intent: string; - /** - * Details of the application instance that raised the intent. - */ - originatingApp?: AppIdentifier; - /** - * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates - * to. - */ - raiseIntentRequestUuid: string; + /** + * The context object passed with the raised intent. + */ + context: Context; + /** + * The intent that was raised. + */ + intent: string; + /** + * Details of the application instance that raised the intent. + */ + originatingApp?: AppIdentifier; + /** + * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates + * to. + */ + raiseIntentRequestUuid: string; } /** @@ -2445,26 +2908,26 @@ export interface IntentEventPayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface IntentListenerUnsubscribeRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: IntentListenerUnsubscribeRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "intentListenerUnsubscribeRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: IntentListenerUnsubscribeRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'intentListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface IntentListenerUnsubscribeRequestPayload { - listenerUUID: string; + listenerUUID: string; } /** @@ -2479,21 +2942,21 @@ export interface IntentListenerUnsubscribeRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface IntentListenerUnsubscribeResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: BroadcastResponseResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "intentListenerUnsubscribeResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'intentListenerUnsubscribeResponse'; } /** @@ -2509,39 +2972,39 @@ export interface IntentListenerUnsubscribeResponse { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface IntentResultRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: IntentResultRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "intentResultRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: IntentResultRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'intentResultRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface IntentResultRequestPayload { - /** - * The eventUuid value of the intentEvent that the result being sent relates to. - */ - intentEventUuid: string; - intentResult: IntentResult; - /** - * The requestUuid value of the raiseIntentRequest that the result being sent relates to. - */ - raiseIntentRequestUuid: string; + /** + * The eventUuid value of the intentEvent that the result being sent relates to. + */ + intentEventUuid: string; + intentResult: IntentResult; + /** + * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + */ + raiseIntentRequestUuid: string; } export interface IntentResult { - context?: Context; - channel?: Channel; + context?: Context; + channel?: Channel; } /** @@ -2556,21 +3019,21 @@ export interface IntentResult { * payload contains an `error` property, the request was unsuccessful. */ export interface IntentResultResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: BroadcastResponseResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "intentResultResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'intentResultResponse'; } /** @@ -2586,29 +3049,29 @@ export interface IntentResultResponse { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface JoinUserChannelRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: JoinUserChannelRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "joinUserChannelRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: JoinUserChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'joinUserChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface JoinUserChannelRequestPayload { - /** - * The id of the channel to join. - */ - channelId: string; + /** + * The id of the channel to join. + */ + channelId: string; } /** @@ -2625,21 +3088,21 @@ export interface JoinUserChannelRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface JoinUserChannelResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: JoinUserChannelResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "joinUserChannelResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: JoinUserChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'joinUserChannelResponse'; } /** @@ -2648,7 +3111,7 @@ export interface JoinUserChannelResponse { * unsuccessful. */ export interface JoinUserChannelResponsePayload { - error?: PurpleError; + error?: PurpleError; } /** @@ -2662,26 +3125,25 @@ export interface JoinUserChannelResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface LeaveCurrentChannelRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: LeaveCurrentChannelRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "leaveCurrentChannelRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: LeaveCurrentChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'leaveCurrentChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface LeaveCurrentChannelRequestPayload { -} +export interface LeaveCurrentChannelRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2695,21 +3157,21 @@ export interface LeaveCurrentChannelRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface LeaveCurrentChannelResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: LeaveCurrentChannelResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "leaveCurrentChannelResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: LeaveCurrentChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'leaveCurrentChannelResponse'; } /** @@ -2718,7 +3180,7 @@ export interface LeaveCurrentChannelResponse { * unsuccessful. */ export interface LeaveCurrentChannelResponsePayload { - error?: PurpleError; + error?: PurpleError; } /** @@ -2732,32 +3194,32 @@ export interface LeaveCurrentChannelResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface OpenRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: OpenRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "openRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: OpenRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'openRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface OpenRequestPayload { - app: AppIdentifier; - /** - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. - */ - context?: Context; + app: AppIdentifier; + /** + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. + */ + context?: Context; } /** @@ -2772,21 +3234,21 @@ export interface OpenRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface OpenResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: OpenResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "openResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: OpenResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'openResponse'; } /** @@ -2795,8 +3257,8 @@ export interface OpenResponse { * unsuccessful. */ export interface OpenResponsePayload { - error?: OpenErrorResponsePayload; - appIdentifier?: AppIdentifier; + error?: OpenErrorResponsePayload; + appIdentifier?: AppIdentifier; } /** @@ -2807,7 +3269,17 @@ export interface OpenResponsePayload { * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the * DesktopAgent (`fdc3`). */ -export type OpenErrorResponsePayload = "MalformedContext" | "AppNotFound" | "AppTimeout" | "DesktopAgentNotFound" | "ErrorOnLaunch" | "ResolverUnavailable" | "AgentDisconnected" | "NotConnectedToBridge" | "ResponseToBridgeTimedOut" | "MalformedMessage"; +export type OpenErrorResponsePayload = + | 'MalformedContext' + | 'AppNotFound' + | 'AppTimeout' + | 'DesktopAgentNotFound' + | 'ErrorOnLaunch' + | 'ResolverUnavailable' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2820,40 +3292,40 @@ export type OpenErrorResponsePayload = "MalformedContext" | "AppNotFound" | "App * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface PrivateChannelAddEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelAddEventListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "privateChannelAddEventListenerRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelAddEventListenerRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'privateChannelAddEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface PrivateChannelAddEventListenerRequestPayload { - /** - * The type of PrivateChannel event that the listener should be applied to, or null for all - * event types. - */ - listenerType: PrivateChannelEventType | null; - /** - * The Id of the PrivateChannel that the listener should be added to. - */ - privateChannelId: string; + /** + * The type of PrivateChannel event that the listener should be applied to, or null for all + * event types. + */ + listenerType: PrivateChannelEventType | null; + /** + * The Id of the PrivateChannel that the listener should be added to. + */ + privateChannelId: string; } /** * Type defining valid type strings for Private Channel events. */ -export type PrivateChannelEventType = "addContextListener" | "unsubscribe" | "disconnect"; +export type PrivateChannelEventType = 'addContextListener' | 'unsubscribe' | 'disconnect'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2867,21 +3339,21 @@ export type PrivateChannelEventType = "addContextListener" | "unsubscribe" | "di * payload contains an `error` property, the request was unsuccessful. */ export interface PrivateChannelAddEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: PrivateChannelAddEventListenerResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "privateChannelAddEventListenerResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: PrivateChannelAddEventListenerResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelAddEventListenerResponse'; } /** @@ -2890,8 +3362,8 @@ export interface PrivateChannelAddEventListenerResponse { * unsuccessful. */ export interface PrivateChannelAddEventListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; + error?: PurpleError; + listenerUUID?: string; } /** @@ -2906,29 +3378,29 @@ export interface PrivateChannelAddEventListenerResponsePayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface PrivateChannelDisconnectRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelDisconnectRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "privateChannelDisconnectRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelDisconnectRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'privateChannelDisconnectRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface PrivateChannelDisconnectRequestPayload { - /** - * The Id of the Channel that should be disconnected from - */ - channelId: string; + /** + * The Id of the Channel that should be disconnected from + */ + channelId: string; } /** @@ -2943,21 +3415,21 @@ export interface PrivateChannelDisconnectRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface PrivateChannelDisconnectResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: PrivateChannelDisconnectResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "privateChannelDisconnectResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: PrivateChannelDisconnectResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelDisconnectResponse'; } /** @@ -2966,7 +3438,7 @@ export interface PrivateChannelDisconnectResponse { * unsuccessful. */ export interface PrivateChannelDisconnectResponsePayload { - error?: PurpleError; + error?: PurpleError; } /** @@ -2981,34 +3453,34 @@ export interface PrivateChannelDisconnectResponsePayload { * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface PrivateChannelOnAddContextListenerEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: PrivateChannelOnAddContextListenerEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "privateChannelOnAddContextListenerEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: PrivateChannelOnAddContextListenerEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelOnAddContextListenerEvent'; } /** * The message payload contains details of the event that the app is being notified about. */ export interface PrivateChannelOnAddContextListenerEventPayload { - /** - * The type of the context listener added to the channel by another app, or null if it will - * listen to all types. - */ - contextType: null | string; - /** - * The Id of the PrivateChannel that the listener was added to. - */ - privateChannelId: string; + /** + * The type of the context listener added to the channel by another app, or null if it will + * listen to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was added to. + */ + privateChannelId: string; } /** @@ -3023,29 +3495,29 @@ export interface PrivateChannelOnAddContextListenerEventPayload { * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface PrivateChannelOnDisconnectEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: PrivateChannelOnDisconnectEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "privateChannelOnDisconnectEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: PrivateChannelOnDisconnectEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelOnDisconnectEvent'; } /** * The message payload contains details of the event that the app is being notified about. */ export interface PrivateChannelOnDisconnectEventPayload { - /** - * The Id of the PrivateChannel that the app has disconnected from. - */ - privateChannelId: string; + /** + * The Id of the PrivateChannel that the app has disconnected from. + */ + privateChannelId: string; } /** @@ -3060,34 +3532,34 @@ export interface PrivateChannelOnDisconnectEventPayload { * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ export interface PrivateChannelOnUnsubscribeEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: PrivateChannelOnUnsubscribeEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "privateChannelOnUnsubscribeEvent"; + /** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ + meta: BroadcastEventMeta; + /** + * The message payload contains details of the event that the app is being notified about. + */ + payload: PrivateChannelOnUnsubscribeEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelOnUnsubscribeEvent'; } /** * The message payload contains details of the event that the app is being notified about. */ export interface PrivateChannelOnUnsubscribeEventPayload { - /** - * The type of the context listener unsubscribed from the channel by another app, or null if - * it was listening to all types. - */ - contextType: null | string; - /** - * The Id of the PrivateChannel that the listener was unsubscribed from. - */ - privateChannelId: string; + /** + * The type of the context listener unsubscribed from the channel by another app, or null if + * it was listening to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was unsubscribed from. + */ + privateChannelId: string; } /** @@ -3101,26 +3573,26 @@ export interface PrivateChannelOnUnsubscribeEventPayload { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface PrivateChannelUnsubscribeEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: PrivateChannelUnsubscribeEventListenerRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "privateChannelUnsubscribeEventListenerRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: PrivateChannelUnsubscribeEventListenerRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'privateChannelUnsubscribeEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface PrivateChannelUnsubscribeEventListenerRequestPayload { - listenerUUID: string; + listenerUUID: string; } /** @@ -3135,21 +3607,21 @@ export interface PrivateChannelUnsubscribeEventListenerRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface PrivateChannelUnsubscribeEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: BroadcastResponseResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "privateChannelUnsubscribeEventListenerResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelUnsubscribeEventListenerResponse'; } /** @@ -3163,27 +3635,27 @@ export interface PrivateChannelUnsubscribeEventListenerResponse { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface RaiseIntentForContextRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: RaiseIntentForContextRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "raiseIntentForContextRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: RaiseIntentForContextRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'raiseIntentForContextRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface RaiseIntentForContextRequestPayload { - app?: AppIdentifier; - context: Context; + app?: AppIdentifier; + context: Context; } /** @@ -3198,25 +3670,25 @@ export interface RaiseIntentForContextRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface RaiseIntentForContextResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). - */ - payload: RaiseIntentForContextResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "raiseIntentForContextResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). + */ + payload: RaiseIntentForContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'raiseIntentForContextResponse'; } /** @@ -3234,19 +3706,19 @@ export interface RaiseIntentForContextResponse { * Used if a raiseIntent request resulted in an error. */ export interface RaiseIntentForContextResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; - /** - * Used if the raiseIntent request was successfully resolved. - */ - intentResolution?: IntentResolution; - /** - * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing - * an intent resolver) before it can be handled. - */ - appIntents?: AppIntent[]; + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing + * an intent resolver) before it can be handled. + */ + appIntents?: AppIntent[]; } /** @@ -3278,17 +3750,17 @@ export interface RaiseIntentForContextResponsePayload { * ``` */ export interface IntentResolution { - /** - * The intent that was raised. May be used to determine which intent the user - * chose in response to `fdc3.raiseIntentForContext()`. - */ - intent: string; - /** - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ - source: AppIdentifier; + /** + * The intent that was raised. May be used to determine which intent the user + * chose in response to `fdc3.raiseIntentForContext()`. + */ + intent: string; + /** + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ + source: AppIdentifier; } /** @@ -3302,28 +3774,28 @@ export interface IntentResolution { * A request message from an FDC3-enabled app to a Desktop Agent. */ export interface RaiseIntentRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; - /** - * The message payload typically contains the arguments to FDC3 API functions. - */ - payload: RaiseIntentRequestPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - type: "raiseIntentRequest"; + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: RaiseIntentRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'raiseIntentRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ export interface RaiseIntentRequestPayload { - app?: AppIdentifier; - context: Context; - intent: string; + app?: AppIdentifier; + context: Context; + intent: string; } /** @@ -3338,25 +3810,25 @@ export interface RaiseIntentRequestPayload { * payload contains an `error` property, the request was unsuccessful. */ export interface RaiseIntentResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). - */ - payload: RaiseIntentResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "raiseIntentResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). + */ + payload: RaiseIntentResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'raiseIntentResponse'; } /** @@ -3374,19 +3846,19 @@ export interface RaiseIntentResponse { * Used if a raiseIntent request resulted in an error. */ export interface RaiseIntentResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; - /** - * Used if the raiseIntent request was successfully resolved. - */ - intentResolution?: IntentResolution; - /** - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. - */ - appIntent?: AppIntent; + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. + */ + appIntent?: AppIntent; } /** @@ -3403,21 +3875,21 @@ export interface RaiseIntentResponsePayload { * payload contains an `error` property, the request was unsuccessful. */ export interface RaiseIntentResultResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; - /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ - payload: RaiseIntentResultResponsePayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: "raiseIntentResultResponse"; + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: RaiseIntentResultResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'raiseIntentResultResponse'; } /** @@ -3426,8 +3898,8 @@ export interface RaiseIntentResultResponse { * unsuccessful. */ export interface RaiseIntentResultResponsePayload { - error?: ResponsePayloadError; - intentResult?: IntentResult; + error?: ResponsePayloadError; + intentResult?: IntentResult; } /** @@ -3435,3988 +3907,3985 @@ export interface RaiseIntentResultResponsePayload { * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -/** - * Hello message sent by an application to a parent window or frame when attempting to - * establish connectivity to a Desktop Agent. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol1Hello { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol1HelloPayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP1Hello"; -} +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { + return cast(JSON.parse(json), r('WebConnectionProtocol1Hello')); + } + + public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol1Hello')), null, 2); + } + + public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { + return cast(JSON.parse(json), r('WebConnectionProtocol2LoadURL')); + } + + public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol2LoadURL')), null, 2); + } + + public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { + return cast(JSON.parse(json), r('WebConnectionProtocol3Handshake')); + } + + public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol3Handshake')), null, 2); + } + + public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { + return cast(JSON.parse(json), r('WebConnectionProtocol4ValidateAppIdentity')); + } + + public static webConnectionProtocol4ValidateAppIdentityToJson( + value: WebConnectionProtocol4ValidateAppIdentity + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol4ValidateAppIdentity')), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse( + json: string + ): WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')); + } + + public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson( + value: WebConnectionProtocol5ValidateAppIdentityFailedResponse + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + json: string + ): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')); + } + + public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson( + value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')), null, 2); + } + + public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { + return cast(JSON.parse(json), r('WebConnectionProtocol6Goodbye')); + } + + public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol6Goodbye')), null, 2); + } + + public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { + return cast(JSON.parse(json), r('WebConnectionProtocolMessage')); + } + + public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocolMessage')), null, 2); + } + + public static toAddContextListenerRequest(json: string): AddContextListenerRequest { + return cast(JSON.parse(json), r('AddContextListenerRequest')); + } + + public static addContextListenerRequestToJson(value: AddContextListenerRequest): string { + return JSON.stringify(uncast(value, r('AddContextListenerRequest')), null, 2); + } + + public static toAddContextListenerResponse(json: string): AddContextListenerResponse { + return cast(JSON.parse(json), r('AddContextListenerResponse')); + } + + public static addContextListenerResponseToJson(value: AddContextListenerResponse): string { + return JSON.stringify(uncast(value, r('AddContextListenerResponse')), null, 2); + } + + public static toAddEventListenerRequest(json: string): AddEventListenerRequest { + return cast(JSON.parse(json), r('AddEventListenerRequest')); + } + + public static addEventListenerRequestToJson(value: AddEventListenerRequest): string { + return JSON.stringify(uncast(value, r('AddEventListenerRequest')), null, 2); + } + + public static toAddEventListenerResponse(json: string): AddEventListenerResponse { + return cast(JSON.parse(json), r('AddEventListenerResponse')); + } + + public static addEventListenerResponseToJson(value: AddEventListenerResponse): string { + return JSON.stringify(uncast(value, r('AddEventListenerResponse')), null, 2); + } + + public static toAddIntentListenerRequest(json: string): AddIntentListenerRequest { + return cast(JSON.parse(json), r('AddIntentListenerRequest')); + } + + public static addIntentListenerRequestToJson(value: AddIntentListenerRequest): string { + return JSON.stringify(uncast(value, r('AddIntentListenerRequest')), null, 2); + } + + public static toAddIntentListenerResponse(json: string): AddIntentListenerResponse { + return cast(JSON.parse(json), r('AddIntentListenerResponse')); + } + + public static addIntentListenerResponseToJson(value: AddIntentListenerResponse): string { + return JSON.stringify(uncast(value, r('AddIntentListenerResponse')), null, 2); + } + + public static toAgentEventMessage(json: string): AgentEventMessage { + return cast(JSON.parse(json), r('AgentEventMessage')); + } + + public static agentEventMessageToJson(value: AgentEventMessage): string { + return JSON.stringify(uncast(value, r('AgentEventMessage')), null, 2); + } + + public static toAgentResponseMessage(json: string): AgentResponseMessage { + return cast(JSON.parse(json), r('AgentResponseMessage')); + } + + public static agentResponseMessageToJson(value: AgentResponseMessage): string { + return JSON.stringify(uncast(value, r('AgentResponseMessage')), null, 2); + } + + public static toAppRequestMessage(json: string): AppRequestMessage { + return cast(JSON.parse(json), r('AppRequestMessage')); + } + + public static appRequestMessageToJson(value: AppRequestMessage): string { + return JSON.stringify(uncast(value, r('AppRequestMessage')), null, 2); + } -/** - * Metadata for a Web Connection Protocol message. - */ -export interface WebConnectionProtocol1HelloMeta { - connectionAttemptUuid: string; - timestamp: Date; -} + public static toBroadcastEvent(json: string): BroadcastEvent { + return cast(JSON.parse(json), r('BroadcastEvent')); + } -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol1HelloPayload { - /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. - */ - actualUrl: string; - /** - * A flag that may be used to indicate that a channel selector user interface is or is not - * required. Set to `false` if the app includes its own interface for selecting channels or - * does not work with user channels. - */ - channelSelector?: boolean; - /** - * The version of FDC3 API that the app supports. - */ - fdc3Version: string; - /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. - */ - identityUrl: string; - /** - * A flag that may be used to indicate that an intent resolver is or is not required. Set to - * `false` if no intents, or only targeted intents, are raised. - */ - intentResolver?: boolean; - [property: string]: any; -} + public static broadcastEventToJson(value: BroadcastEvent): string { + return JSON.stringify(uncast(value, r('BroadcastEvent')), null, 2); + } -/** - * Identifies the type of the connection step message. - */ + public static toBroadcastRequest(json: string): BroadcastRequest { + return cast(JSON.parse(json), r('BroadcastRequest')); + } -/** - * Response from a Desktop Agent to an application requesting access to it indicating that - * it should load a specified URL into a hidden iframe in order to establish connectivity to - * a Desktop Agent. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol2LoadURL { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol2LoadURLPayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP2LoadUrl"; -} + public static broadcastRequestToJson(value: BroadcastRequest): string { + return JSON.stringify(uncast(value, r('BroadcastRequest')), null, 2); + } -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol2LoadURLPayload { - /** - * A URL which can be used to establish communication with the Desktop Agent, via loading - * the URL into an iframe and restarting the Web Connection protocol with the iframe as the - * target. - */ - iframeUrl: string; - [property: string]: any; -} + public static toBroadcastResponse(json: string): BroadcastResponse { + return cast(JSON.parse(json), r('BroadcastResponse')); + } -/** - * Identifies the type of the connection step message. - */ + public static broadcastResponseToJson(value: BroadcastResponse): string { + return JSON.stringify(uncast(value, r('BroadcastResponse')), null, 2); + } -/** - * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that - * should be used for subsequent communication steps. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol3Handshake { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol3HandshakePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP3Handshake"; -} + public static toChannelChangedEvent(json: string): ChannelChangedEvent { + return cast(JSON.parse(json), r('ChannelChangedEvent')); + } -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol3HandshakePayload { - /** - * Indicates whether a channel selector user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the channel selector (as the - * Desktop Agent will handle it another way). - */ - channelSelectorUrl: boolean | string; - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; - /** - * Indicates whether an intent resolver user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the intent resolver (as the - * Desktop Agent will handle it another way). - */ - intentResolverUrl: boolean | string; -} + public static channelChangedEventToJson(value: ChannelChangedEvent): string { + return JSON.stringify(uncast(value, r('ChannelChangedEvent')), null, 2); + } -/** - * Identifies the type of the connection step message. - */ + public static toContextListenerUnsubscribeRequest(json: string): ContextListenerUnsubscribeRequest { + return cast(JSON.parse(json), r('ContextListenerUnsubscribeRequest')); + } -/** - * Identity Validation request from an app attempting to connect to a Desktop Agent. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol4ValidateAppIdentity { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol4ValidateAppIdentityPayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP4ValidateAppIdentity"; -} + public static contextListenerUnsubscribeRequestToJson(value: ContextListenerUnsubscribeRequest): string { + return JSON.stringify(uncast(value, r('ContextListenerUnsubscribeRequest')), null, 2); + } -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol4ValidateAppIdentityPayload { - /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. - */ - actualUrl: string; - /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. - */ - identityUrl: string; - /** - * If an application has previously connected to the Desktop Agent, it may specify its prior - * instance id and associated instance UUID to request the same same instance Id be assigned. - */ - instanceId?: string; - /** - * Instance UUID associated with the requested instanceId. - */ - instanceUuid?: string; -} + public static toContextListenerUnsubscribeResponse(json: string): ContextListenerUnsubscribeResponse { + return cast(JSON.parse(json), r('ContextListenerUnsubscribeResponse')); + } -/** - * Identifies the type of the connection step message. - */ + public static contextListenerUnsubscribeResponseToJson(value: ContextListenerUnsubscribeResponse): string { + return JSON.stringify(uncast(value, r('ContextListenerUnsubscribeResponse')), null, 2); + } -/** - * Message sent by the Desktop Agent to an app if their identity validation fails. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP5ValidateAppIdentityFailedResponse"; -} + public static toCreatePrivateChannelRequest(json: string): CreatePrivateChannelRequest { + return cast(JSON.parse(json), r('CreatePrivateChannelRequest')); + } -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { - message?: string; -} + public static createPrivateChannelRequestToJson(value: CreatePrivateChannelRequest): string { + return JSON.stringify(uncast(value, r('CreatePrivateChannelRequest')), null, 2); + } -/** - * Identifies the type of the connection step message. - */ + public static toCreatePrivateChannelResponse(json: string): CreatePrivateChannelResponse { + return cast(JSON.parse(json), r('CreatePrivateChannelResponse')); + } -/** - * Message sent by the Desktop Agent to an app after successful identity validation. - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol1HelloMeta; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; - /** - * Identifies the type of the connection step message. - */ - type: "WCP5ValidateAppIdentityResponse"; -} + public static createPrivateChannelResponseToJson(value: CreatePrivateChannelResponse): string { + return JSON.stringify(uncast(value, r('CreatePrivateChannelResponse')), null, 2); + } -/** - * The message payload, containing data pertaining to this connection step. - */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { - /** - * The appId that the app's identity was validated against. - */ - appId: string; - /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - */ - implementationMetadata: ImplementationMetadata; - /** - * The instance Id granted to the application by the Desktop Agent. - */ - instanceId: string; - /** - * Instance UUID associated with the instanceId granted, which may be used to retrieve the - * same instanceId if the app is reloaded or navigates. - */ - instanceUuid: string; -} + public static toEventListenerUnsubscribeRequest(json: string): EventListenerUnsubscribeRequest { + return cast(JSON.parse(json), r('EventListenerUnsubscribeRequest')); + } -/** - * Identifies the type of the connection step message. - */ + public static eventListenerUnsubscribeRequestToJson(value: EventListenerUnsubscribeRequest): string { + return JSON.stringify(uncast(value, r('EventListenerUnsubscribeRequest')), null, 2); + } -/** - * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the - * window or navigating). Desktop Agents should close the MessagePort after receiving this - * message, but retain instance details in case the application reconnects (e.g. after a - * navigation event). - * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocol6Goodbye { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: WebConnectionProtocol6GoodbyeMeta; - /** - * Identifies the type of the connection step message. - */ - type: "WCP6Goodbye"; -} + public static toEventListenerUnsubscribeResponse(json: string): EventListenerUnsubscribeResponse { + return cast(JSON.parse(json), r('EventListenerUnsubscribeResponse')); + } -/** - * Metadata for a Web Connection Protocol message. - */ -export interface WebConnectionProtocol6GoodbyeMeta { - timestamp: Date; -} + public static eventListenerUnsubscribeResponseToJson(value: EventListenerUnsubscribeResponse): string { + return JSON.stringify(uncast(value, r('EventListenerUnsubscribeResponse')), null, 2); + } -/** - * Identifies the type of the connection step message. - */ + public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { + return cast(JSON.parse(json), r('Fdc3UserInterfaceChannelSelected')); + } -/** - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. - */ -export interface WebConnectionProtocolMessage { - /** - * Metadata for a Web Connection Protocol message. - */ - meta: ConnectionStepMetadata; - /** - * The message payload, containing data pertaining to this connection step. - */ - payload?: { [key: string]: any }; - /** - * Identifies the type of the connection step message. - */ - type: ConnectionStepMessageType; -} + public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannelSelected')), null, 2); + } -/** - * Metadata for a Web Connection Protocol message. - */ -export interface ConnectionStepMetadata { - timestamp: Date; - connectionAttemptUuid?: string; -} + public static toFdc3UserInterfaceChannels(json: string): Fdc3UserInterfaceChannels { + return cast(JSON.parse(json), r('Fdc3UserInterfaceChannels')); + } -/** - * Identifies the type of the connection step message. - */ -export type ConnectionStepMessageType = "WCP1Hello" | "WCP2LoadUrl" | "WCP3Handshake" | "WCP4ValidateAppIdentity" | "WCP5ValidateAppIdentityFailedResponse" | "WCP5ValidateAppIdentityResponse" | "WCP6Goodbye"; + public static fdc3UserInterfaceChannelsToJson(value: Fdc3UserInterfaceChannels): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannels')), null, 2); + } -// Converts JSON strings to/from your types -// and asserts the results of JSON.parse at runtime -export class Convert { - public static toAddContextListenerRequest(json: string): AddContextListenerRequest { - return cast(JSON.parse(json), r("AddContextListenerRequest")); - } + public static toFdc3UserInterfaceDrag(json: string): Fdc3UserInterfaceDrag { + return cast(JSON.parse(json), r('Fdc3UserInterfaceDrag')); + } - public static addContextListenerRequestToJson(value: AddContextListenerRequest): string { - return JSON.stringify(uncast(value, r("AddContextListenerRequest")), null, 2); - } + public static fdc3UserInterfaceDragToJson(value: Fdc3UserInterfaceDrag): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceDrag')), null, 2); + } - public static toAddContextListenerResponse(json: string): AddContextListenerResponse { - return cast(JSON.parse(json), r("AddContextListenerResponse")); - } + public static toFdc3UserInterfaceHandshake(json: string): Fdc3UserInterfaceHandshake { + return cast(JSON.parse(json), r('Fdc3UserInterfaceHandshake')); + } - public static addContextListenerResponseToJson(value: AddContextListenerResponse): string { - return JSON.stringify(uncast(value, r("AddContextListenerResponse")), null, 2); - } + public static fdc3UserInterfaceHandshakeToJson(value: Fdc3UserInterfaceHandshake): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceHandshake')), null, 2); + } - public static toAddEventListenerRequest(json: string): AddEventListenerRequest { - return cast(JSON.parse(json), r("AddEventListenerRequest")); - } + public static toFdc3UserInterfaceHello(json: string): Fdc3UserInterfaceHello { + return cast(JSON.parse(json), r('Fdc3UserInterfaceHello')); + } - public static addEventListenerRequestToJson(value: AddEventListenerRequest): string { - return JSON.stringify(uncast(value, r("AddEventListenerRequest")), null, 2); - } + public static fdc3UserInterfaceHelloToJson(value: Fdc3UserInterfaceHello): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceHello')), null, 2); + } - public static toAddEventListenerResponse(json: string): AddEventListenerResponse { - return cast(JSON.parse(json), r("AddEventListenerResponse")); - } + public static toFdc3UserInterfaceMessage(json: string): Fdc3UserInterfaceMessage { + return cast(JSON.parse(json), r('Fdc3UserInterfaceMessage')); + } - public static addEventListenerResponseToJson(value: AddEventListenerResponse): string { - return JSON.stringify(uncast(value, r("AddEventListenerResponse")), null, 2); - } + public static fdc3UserInterfaceMessageToJson(value: Fdc3UserInterfaceMessage): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceMessage')), null, 2); + } - public static toAddIntentListenerRequest(json: string): AddIntentListenerRequest { - return cast(JSON.parse(json), r("AddIntentListenerRequest")); - } + public static toFdc3UserInterfaceResolve(json: string): Fdc3UserInterfaceResolve { + return cast(JSON.parse(json), r('Fdc3UserInterfaceResolve')); + } - public static addIntentListenerRequestToJson(value: AddIntentListenerRequest): string { - return JSON.stringify(uncast(value, r("AddIntentListenerRequest")), null, 2); - } + public static fdc3UserInterfaceResolveToJson(value: Fdc3UserInterfaceResolve): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceResolve')), null, 2); + } - public static toAddIntentListenerResponse(json: string): AddIntentListenerResponse { - return cast(JSON.parse(json), r("AddIntentListenerResponse")); - } + public static toFdc3UserInterfaceResolveAction(json: string): Fdc3UserInterfaceResolveAction { + return cast(JSON.parse(json), r('Fdc3UserInterfaceResolveAction')); + } - public static addIntentListenerResponseToJson(value: AddIntentListenerResponse): string { - return JSON.stringify(uncast(value, r("AddIntentListenerResponse")), null, 2); - } + public static fdc3UserInterfaceResolveActionToJson(value: Fdc3UserInterfaceResolveAction): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceResolveAction')), null, 2); + } - public static toAgentEventMessage(json: string): AgentEventMessage { - return cast(JSON.parse(json), r("AgentEventMessage")); - } + public static toFdc3UserInterfaceRestyle(json: string): Fdc3UserInterfaceRestyle { + return cast(JSON.parse(json), r('Fdc3UserInterfaceRestyle')); + } - public static agentEventMessageToJson(value: AgentEventMessage): string { - return JSON.stringify(uncast(value, r("AgentEventMessage")), null, 2); - } + public static fdc3UserInterfaceRestyleToJson(value: Fdc3UserInterfaceRestyle): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceRestyle')), null, 2); + } - public static toAgentResponseMessage(json: string): AgentResponseMessage { - return cast(JSON.parse(json), r("AgentResponseMessage")); - } + public static toFindInstancesRequest(json: string): FindInstancesRequest { + return cast(JSON.parse(json), r('FindInstancesRequest')); + } - public static agentResponseMessageToJson(value: AgentResponseMessage): string { - return JSON.stringify(uncast(value, r("AgentResponseMessage")), null, 2); - } + public static findInstancesRequestToJson(value: FindInstancesRequest): string { + return JSON.stringify(uncast(value, r('FindInstancesRequest')), null, 2); + } - public static toAppRequestMessage(json: string): AppRequestMessage { - return cast(JSON.parse(json), r("AppRequestMessage")); - } + public static toFindInstancesResponse(json: string): FindInstancesResponse { + return cast(JSON.parse(json), r('FindInstancesResponse')); + } - public static appRequestMessageToJson(value: AppRequestMessage): string { - return JSON.stringify(uncast(value, r("AppRequestMessage")), null, 2); - } + public static findInstancesResponseToJson(value: FindInstancesResponse): string { + return JSON.stringify(uncast(value, r('FindInstancesResponse')), null, 2); + } - public static toBroadcastEvent(json: string): BroadcastEvent { - return cast(JSON.parse(json), r("BroadcastEvent")); - } + public static toFindIntentRequest(json: string): FindIntentRequest { + return cast(JSON.parse(json), r('FindIntentRequest')); + } - public static broadcastEventToJson(value: BroadcastEvent): string { - return JSON.stringify(uncast(value, r("BroadcastEvent")), null, 2); - } + public static findIntentRequestToJson(value: FindIntentRequest): string { + return JSON.stringify(uncast(value, r('FindIntentRequest')), null, 2); + } - public static toBroadcastRequest(json: string): BroadcastRequest { - return cast(JSON.parse(json), r("BroadcastRequest")); - } + public static toFindIntentResponse(json: string): FindIntentResponse { + return cast(JSON.parse(json), r('FindIntentResponse')); + } - public static broadcastRequestToJson(value: BroadcastRequest): string { - return JSON.stringify(uncast(value, r("BroadcastRequest")), null, 2); - } + public static findIntentResponseToJson(value: FindIntentResponse): string { + return JSON.stringify(uncast(value, r('FindIntentResponse')), null, 2); + } - public static toBroadcastResponse(json: string): BroadcastResponse { - return cast(JSON.parse(json), r("BroadcastResponse")); - } + public static toFindIntentsByContextRequest(json: string): FindIntentsByContextRequest { + return cast(JSON.parse(json), r('FindIntentsByContextRequest')); + } - public static broadcastResponseToJson(value: BroadcastResponse): string { - return JSON.stringify(uncast(value, r("BroadcastResponse")), null, 2); - } + public static findIntentsByContextRequestToJson(value: FindIntentsByContextRequest): string { + return JSON.stringify(uncast(value, r('FindIntentsByContextRequest')), null, 2); + } - public static toChannelChangedEvent(json: string): ChannelChangedEvent { - return cast(JSON.parse(json), r("ChannelChangedEvent")); - } + public static toFindIntentsByContextResponse(json: string): FindIntentsByContextResponse { + return cast(JSON.parse(json), r('FindIntentsByContextResponse')); + } - public static channelChangedEventToJson(value: ChannelChangedEvent): string { - return JSON.stringify(uncast(value, r("ChannelChangedEvent")), null, 2); - } + public static findIntentsByContextResponseToJson(value: FindIntentsByContextResponse): string { + return JSON.stringify(uncast(value, r('FindIntentsByContextResponse')), null, 2); + } - public static toContextListenerUnsubscribeRequest(json: string): ContextListenerUnsubscribeRequest { - return cast(JSON.parse(json), r("ContextListenerUnsubscribeRequest")); - } + public static toGetAppMetadataRequest(json: string): GetAppMetadataRequest { + return cast(JSON.parse(json), r('GetAppMetadataRequest')); + } - public static contextListenerUnsubscribeRequestToJson(value: ContextListenerUnsubscribeRequest): string { - return JSON.stringify(uncast(value, r("ContextListenerUnsubscribeRequest")), null, 2); - } + public static getAppMetadataRequestToJson(value: GetAppMetadataRequest): string { + return JSON.stringify(uncast(value, r('GetAppMetadataRequest')), null, 2); + } - public static toContextListenerUnsubscribeResponse(json: string): ContextListenerUnsubscribeResponse { - return cast(JSON.parse(json), r("ContextListenerUnsubscribeResponse")); - } + public static toGetAppMetadataResponse(json: string): GetAppMetadataResponse { + return cast(JSON.parse(json), r('GetAppMetadataResponse')); + } - public static contextListenerUnsubscribeResponseToJson(value: ContextListenerUnsubscribeResponse): string { - return JSON.stringify(uncast(value, r("ContextListenerUnsubscribeResponse")), null, 2); - } + public static getAppMetadataResponseToJson(value: GetAppMetadataResponse): string { + return JSON.stringify(uncast(value, r('GetAppMetadataResponse')), null, 2); + } - public static toCreatePrivateChannelRequest(json: string): CreatePrivateChannelRequest { - return cast(JSON.parse(json), r("CreatePrivateChannelRequest")); - } + public static toGetCurrentChannelRequest(json: string): GetCurrentChannelRequest { + return cast(JSON.parse(json), r('GetCurrentChannelRequest')); + } - public static createPrivateChannelRequestToJson(value: CreatePrivateChannelRequest): string { - return JSON.stringify(uncast(value, r("CreatePrivateChannelRequest")), null, 2); - } + public static getCurrentChannelRequestToJson(value: GetCurrentChannelRequest): string { + return JSON.stringify(uncast(value, r('GetCurrentChannelRequest')), null, 2); + } - public static toCreatePrivateChannelResponse(json: string): CreatePrivateChannelResponse { - return cast(JSON.parse(json), r("CreatePrivateChannelResponse")); - } + public static toGetCurrentChannelResponse(json: string): GetCurrentChannelResponse { + return cast(JSON.parse(json), r('GetCurrentChannelResponse')); + } - public static createPrivateChannelResponseToJson(value: CreatePrivateChannelResponse): string { - return JSON.stringify(uncast(value, r("CreatePrivateChannelResponse")), null, 2); - } + public static getCurrentChannelResponseToJson(value: GetCurrentChannelResponse): string { + return JSON.stringify(uncast(value, r('GetCurrentChannelResponse')), null, 2); + } - public static toEventListenerUnsubscribeRequest(json: string): EventListenerUnsubscribeRequest { - return cast(JSON.parse(json), r("EventListenerUnsubscribeRequest")); - } + public static toGetCurrentContextRequest(json: string): GetCurrentContextRequest { + return cast(JSON.parse(json), r('GetCurrentContextRequest')); + } - public static eventListenerUnsubscribeRequestToJson(value: EventListenerUnsubscribeRequest): string { - return JSON.stringify(uncast(value, r("EventListenerUnsubscribeRequest")), null, 2); - } + public static getCurrentContextRequestToJson(value: GetCurrentContextRequest): string { + return JSON.stringify(uncast(value, r('GetCurrentContextRequest')), null, 2); + } - public static toEventListenerUnsubscribeResponse(json: string): EventListenerUnsubscribeResponse { - return cast(JSON.parse(json), r("EventListenerUnsubscribeResponse")); - } + public static toGetCurrentContextResponse(json: string): GetCurrentContextResponse { + return cast(JSON.parse(json), r('GetCurrentContextResponse')); + } - public static eventListenerUnsubscribeResponseToJson(value: EventListenerUnsubscribeResponse): string { - return JSON.stringify(uncast(value, r("EventListenerUnsubscribeResponse")), null, 2); - } + public static getCurrentContextResponseToJson(value: GetCurrentContextResponse): string { + return JSON.stringify(uncast(value, r('GetCurrentContextResponse')), null, 2); + } - public static toFdc3UserInterfaceChannels(json: string): Fdc3UserInterfaceChannels { - return cast(JSON.parse(json), r("Fdc3UserInterfaceChannels")); - } + public static toGetInfoRequest(json: string): GetInfoRequest { + return cast(JSON.parse(json), r('GetInfoRequest')); + } - public static fdc3UserInterfaceChannelsToJson(value: Fdc3UserInterfaceChannels): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannels")), null, 2); - } + public static getInfoRequestToJson(value: GetInfoRequest): string { + return JSON.stringify(uncast(value, r('GetInfoRequest')), null, 2); + } - public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { - return cast(JSON.parse(json), r("Fdc3UserInterfaceChannelSelected")); - } + public static toGetInfoResponse(json: string): GetInfoResponse { + return cast(JSON.parse(json), r('GetInfoResponse')); + } - public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceChannelSelected")), null, 2); - } + public static getInfoResponseToJson(value: GetInfoResponse): string { + return JSON.stringify(uncast(value, r('GetInfoResponse')), null, 2); + } - public static toFdc3UserInterfaceDrag(json: string): Fdc3UserInterfaceDrag { - return cast(JSON.parse(json), r("Fdc3UserInterfaceDrag")); - } + public static toGetOrCreateChannelRequest(json: string): GetOrCreateChannelRequest { + return cast(JSON.parse(json), r('GetOrCreateChannelRequest')); + } - public static fdc3UserInterfaceDragToJson(value: Fdc3UserInterfaceDrag): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceDrag")), null, 2); - } + public static getOrCreateChannelRequestToJson(value: GetOrCreateChannelRequest): string { + return JSON.stringify(uncast(value, r('GetOrCreateChannelRequest')), null, 2); + } - public static toFdc3UserInterfaceHandshake(json: string): Fdc3UserInterfaceHandshake { - return cast(JSON.parse(json), r("Fdc3UserInterfaceHandshake")); - } + public static toGetOrCreateChannelResponse(json: string): GetOrCreateChannelResponse { + return cast(JSON.parse(json), r('GetOrCreateChannelResponse')); + } - public static fdc3UserInterfaceHandshakeToJson(value: Fdc3UserInterfaceHandshake): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceHandshake")), null, 2); - } + public static getOrCreateChannelResponseToJson(value: GetOrCreateChannelResponse): string { + return JSON.stringify(uncast(value, r('GetOrCreateChannelResponse')), null, 2); + } - public static toFdc3UserInterfaceHello(json: string): Fdc3UserInterfaceHello { - return cast(JSON.parse(json), r("Fdc3UserInterfaceHello")); - } + public static toGetUserChannelsRequest(json: string): GetUserChannelsRequest { + return cast(JSON.parse(json), r('GetUserChannelsRequest')); + } - public static fdc3UserInterfaceHelloToJson(value: Fdc3UserInterfaceHello): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceHello")), null, 2); - } + public static getUserChannelsRequestToJson(value: GetUserChannelsRequest): string { + return JSON.stringify(uncast(value, r('GetUserChannelsRequest')), null, 2); + } - public static toFdc3UserInterfaceMessage(json: string): Fdc3UserInterfaceMessage { - return cast(JSON.parse(json), r("Fdc3UserInterfaceMessage")); - } + public static toGetUserChannelsResponse(json: string): GetUserChannelsResponse { + return cast(JSON.parse(json), r('GetUserChannelsResponse')); + } - public static fdc3UserInterfaceMessageToJson(value: Fdc3UserInterfaceMessage): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceMessage")), null, 2); - } + public static getUserChannelsResponseToJson(value: GetUserChannelsResponse): string { + return JSON.stringify(uncast(value, r('GetUserChannelsResponse')), null, 2); + } - public static toFdc3UserInterfaceResolve(json: string): Fdc3UserInterfaceResolve { - return cast(JSON.parse(json), r("Fdc3UserInterfaceResolve")); - } + public static toHeartbeatAcknowledgementRequest(json: string): HeartbeatAcknowledgementRequest { + return cast(JSON.parse(json), r('HeartbeatAcknowledgementRequest')); + } - public static fdc3UserInterfaceResolveToJson(value: Fdc3UserInterfaceResolve): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceResolve")), null, 2); - } + public static heartbeatAcknowledgementRequestToJson(value: HeartbeatAcknowledgementRequest): string { + return JSON.stringify(uncast(value, r('HeartbeatAcknowledgementRequest')), null, 2); + } - public static toFdc3UserInterfaceResolveAction(json: string): Fdc3UserInterfaceResolveAction { - return cast(JSON.parse(json), r("Fdc3UserInterfaceResolveAction")); - } + public static toHeartbeatEvent(json: string): HeartbeatEvent { + return cast(JSON.parse(json), r('HeartbeatEvent')); + } - public static fdc3UserInterfaceResolveActionToJson(value: Fdc3UserInterfaceResolveAction): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceResolveAction")), null, 2); - } + public static heartbeatEventToJson(value: HeartbeatEvent): string { + return JSON.stringify(uncast(value, r('HeartbeatEvent')), null, 2); + } - public static toFdc3UserInterfaceRestyle(json: string): Fdc3UserInterfaceRestyle { - return cast(JSON.parse(json), r("Fdc3UserInterfaceRestyle")); - } + public static toIntentEvent(json: string): IntentEvent { + return cast(JSON.parse(json), r('IntentEvent')); + } - public static fdc3UserInterfaceRestyleToJson(value: Fdc3UserInterfaceRestyle): string { - return JSON.stringify(uncast(value, r("Fdc3UserInterfaceRestyle")), null, 2); - } + public static intentEventToJson(value: IntentEvent): string { + return JSON.stringify(uncast(value, r('IntentEvent')), null, 2); + } - public static toFindInstancesRequest(json: string): FindInstancesRequest { - return cast(JSON.parse(json), r("FindInstancesRequest")); - } + public static toIntentListenerUnsubscribeRequest(json: string): IntentListenerUnsubscribeRequest { + return cast(JSON.parse(json), r('IntentListenerUnsubscribeRequest')); + } - public static findInstancesRequestToJson(value: FindInstancesRequest): string { - return JSON.stringify(uncast(value, r("FindInstancesRequest")), null, 2); - } + public static intentListenerUnsubscribeRequestToJson(value: IntentListenerUnsubscribeRequest): string { + return JSON.stringify(uncast(value, r('IntentListenerUnsubscribeRequest')), null, 2); + } - public static toFindInstancesResponse(json: string): FindInstancesResponse { - return cast(JSON.parse(json), r("FindInstancesResponse")); - } + public static toIntentListenerUnsubscribeResponse(json: string): IntentListenerUnsubscribeResponse { + return cast(JSON.parse(json), r('IntentListenerUnsubscribeResponse')); + } - public static findInstancesResponseToJson(value: FindInstancesResponse): string { - return JSON.stringify(uncast(value, r("FindInstancesResponse")), null, 2); - } + public static intentListenerUnsubscribeResponseToJson(value: IntentListenerUnsubscribeResponse): string { + return JSON.stringify(uncast(value, r('IntentListenerUnsubscribeResponse')), null, 2); + } - public static toFindIntentRequest(json: string): FindIntentRequest { - return cast(JSON.parse(json), r("FindIntentRequest")); - } + public static toIntentResultRequest(json: string): IntentResultRequest { + return cast(JSON.parse(json), r('IntentResultRequest')); + } - public static findIntentRequestToJson(value: FindIntentRequest): string { - return JSON.stringify(uncast(value, r("FindIntentRequest")), null, 2); - } + public static intentResultRequestToJson(value: IntentResultRequest): string { + return JSON.stringify(uncast(value, r('IntentResultRequest')), null, 2); + } - public static toFindIntentResponse(json: string): FindIntentResponse { - return cast(JSON.parse(json), r("FindIntentResponse")); - } + public static toIntentResultResponse(json: string): IntentResultResponse { + return cast(JSON.parse(json), r('IntentResultResponse')); + } - public static findIntentResponseToJson(value: FindIntentResponse): string { - return JSON.stringify(uncast(value, r("FindIntentResponse")), null, 2); - } + public static intentResultResponseToJson(value: IntentResultResponse): string { + return JSON.stringify(uncast(value, r('IntentResultResponse')), null, 2); + } - public static toFindIntentsByContextRequest(json: string): FindIntentsByContextRequest { - return cast(JSON.parse(json), r("FindIntentsByContextRequest")); - } + public static toJoinUserChannelRequest(json: string): JoinUserChannelRequest { + return cast(JSON.parse(json), r('JoinUserChannelRequest')); + } - public static findIntentsByContextRequestToJson(value: FindIntentsByContextRequest): string { - return JSON.stringify(uncast(value, r("FindIntentsByContextRequest")), null, 2); - } + public static joinUserChannelRequestToJson(value: JoinUserChannelRequest): string { + return JSON.stringify(uncast(value, r('JoinUserChannelRequest')), null, 2); + } - public static toFindIntentsByContextResponse(json: string): FindIntentsByContextResponse { - return cast(JSON.parse(json), r("FindIntentsByContextResponse")); - } + public static toJoinUserChannelResponse(json: string): JoinUserChannelResponse { + return cast(JSON.parse(json), r('JoinUserChannelResponse')); + } - public static findIntentsByContextResponseToJson(value: FindIntentsByContextResponse): string { - return JSON.stringify(uncast(value, r("FindIntentsByContextResponse")), null, 2); - } + public static joinUserChannelResponseToJson(value: JoinUserChannelResponse): string { + return JSON.stringify(uncast(value, r('JoinUserChannelResponse')), null, 2); + } - public static toGetAppMetadataRequest(json: string): GetAppMetadataRequest { - return cast(JSON.parse(json), r("GetAppMetadataRequest")); - } + public static toLeaveCurrentChannelRequest(json: string): LeaveCurrentChannelRequest { + return cast(JSON.parse(json), r('LeaveCurrentChannelRequest')); + } + + public static leaveCurrentChannelRequestToJson(value: LeaveCurrentChannelRequest): string { + return JSON.stringify(uncast(value, r('LeaveCurrentChannelRequest')), null, 2); + } + + public static toLeaveCurrentChannelResponse(json: string): LeaveCurrentChannelResponse { + return cast(JSON.parse(json), r('LeaveCurrentChannelResponse')); + } + + public static leaveCurrentChannelResponseToJson(value: LeaveCurrentChannelResponse): string { + return JSON.stringify(uncast(value, r('LeaveCurrentChannelResponse')), null, 2); + } + + public static toOpenRequest(json: string): OpenRequest { + return cast(JSON.parse(json), r('OpenRequest')); + } + + public static openRequestToJson(value: OpenRequest): string { + return JSON.stringify(uncast(value, r('OpenRequest')), null, 2); + } + + public static toOpenResponse(json: string): OpenResponse { + return cast(JSON.parse(json), r('OpenResponse')); + } + + public static openResponseToJson(value: OpenResponse): string { + return JSON.stringify(uncast(value, r('OpenResponse')), null, 2); + } + + public static toPrivateChannelAddEventListenerRequest(json: string): PrivateChannelAddEventListenerRequest { + return cast(JSON.parse(json), r('PrivateChannelAddEventListenerRequest')); + } + + public static privateChannelAddEventListenerRequestToJson(value: PrivateChannelAddEventListenerRequest): string { + return JSON.stringify(uncast(value, r('PrivateChannelAddEventListenerRequest')), null, 2); + } + + public static toPrivateChannelAddEventListenerResponse(json: string): PrivateChannelAddEventListenerResponse { + return cast(JSON.parse(json), r('PrivateChannelAddEventListenerResponse')); + } + + public static privateChannelAddEventListenerResponseToJson(value: PrivateChannelAddEventListenerResponse): string { + return JSON.stringify(uncast(value, r('PrivateChannelAddEventListenerResponse')), null, 2); + } + + public static toPrivateChannelDisconnectRequest(json: string): PrivateChannelDisconnectRequest { + return cast(JSON.parse(json), r('PrivateChannelDisconnectRequest')); + } + + public static privateChannelDisconnectRequestToJson(value: PrivateChannelDisconnectRequest): string { + return JSON.stringify(uncast(value, r('PrivateChannelDisconnectRequest')), null, 2); + } - public static getAppMetadataRequestToJson(value: GetAppMetadataRequest): string { - return JSON.stringify(uncast(value, r("GetAppMetadataRequest")), null, 2); - } + public static toPrivateChannelDisconnectResponse(json: string): PrivateChannelDisconnectResponse { + return cast(JSON.parse(json), r('PrivateChannelDisconnectResponse')); + } - public static toGetAppMetadataResponse(json: string): GetAppMetadataResponse { - return cast(JSON.parse(json), r("GetAppMetadataResponse")); - } + public static privateChannelDisconnectResponseToJson(value: PrivateChannelDisconnectResponse): string { + return JSON.stringify(uncast(value, r('PrivateChannelDisconnectResponse')), null, 2); + } - public static getAppMetadataResponseToJson(value: GetAppMetadataResponse): string { - return JSON.stringify(uncast(value, r("GetAppMetadataResponse")), null, 2); - } + public static toPrivateChannelOnAddContextListenerEvent(json: string): PrivateChannelOnAddContextListenerEvent { + return cast(JSON.parse(json), r('PrivateChannelOnAddContextListenerEvent')); + } - public static toGetCurrentChannelRequest(json: string): GetCurrentChannelRequest { - return cast(JSON.parse(json), r("GetCurrentChannelRequest")); - } + public static privateChannelOnAddContextListenerEventToJson(value: PrivateChannelOnAddContextListenerEvent): string { + return JSON.stringify(uncast(value, r('PrivateChannelOnAddContextListenerEvent')), null, 2); + } - public static getCurrentChannelRequestToJson(value: GetCurrentChannelRequest): string { - return JSON.stringify(uncast(value, r("GetCurrentChannelRequest")), null, 2); - } + public static toPrivateChannelOnDisconnectEvent(json: string): PrivateChannelOnDisconnectEvent { + return cast(JSON.parse(json), r('PrivateChannelOnDisconnectEvent')); + } - public static toGetCurrentChannelResponse(json: string): GetCurrentChannelResponse { - return cast(JSON.parse(json), r("GetCurrentChannelResponse")); - } + public static privateChannelOnDisconnectEventToJson(value: PrivateChannelOnDisconnectEvent): string { + return JSON.stringify(uncast(value, r('PrivateChannelOnDisconnectEvent')), null, 2); + } - public static getCurrentChannelResponseToJson(value: GetCurrentChannelResponse): string { - return JSON.stringify(uncast(value, r("GetCurrentChannelResponse")), null, 2); - } + public static toPrivateChannelOnUnsubscribeEvent(json: string): PrivateChannelOnUnsubscribeEvent { + return cast(JSON.parse(json), r('PrivateChannelOnUnsubscribeEvent')); + } - public static toGetCurrentContextRequest(json: string): GetCurrentContextRequest { - return cast(JSON.parse(json), r("GetCurrentContextRequest")); - } + public static privateChannelOnUnsubscribeEventToJson(value: PrivateChannelOnUnsubscribeEvent): string { + return JSON.stringify(uncast(value, r('PrivateChannelOnUnsubscribeEvent')), null, 2); + } - public static getCurrentContextRequestToJson(value: GetCurrentContextRequest): string { - return JSON.stringify(uncast(value, r("GetCurrentContextRequest")), null, 2); - } + public static toPrivateChannelUnsubscribeEventListenerRequest( + json: string + ): PrivateChannelUnsubscribeEventListenerRequest { + return cast(JSON.parse(json), r('PrivateChannelUnsubscribeEventListenerRequest')); + } + + public static privateChannelUnsubscribeEventListenerRequestToJson( + value: PrivateChannelUnsubscribeEventListenerRequest + ): string { + return JSON.stringify(uncast(value, r('PrivateChannelUnsubscribeEventListenerRequest')), null, 2); + } - public static toGetCurrentContextResponse(json: string): GetCurrentContextResponse { - return cast(JSON.parse(json), r("GetCurrentContextResponse")); - } + public static toPrivateChannelUnsubscribeEventListenerResponse( + json: string + ): PrivateChannelUnsubscribeEventListenerResponse { + return cast(JSON.parse(json), r('PrivateChannelUnsubscribeEventListenerResponse')); + } + + public static privateChannelUnsubscribeEventListenerResponseToJson( + value: PrivateChannelUnsubscribeEventListenerResponse + ): string { + return JSON.stringify(uncast(value, r('PrivateChannelUnsubscribeEventListenerResponse')), null, 2); + } - public static getCurrentContextResponseToJson(value: GetCurrentContextResponse): string { - return JSON.stringify(uncast(value, r("GetCurrentContextResponse")), null, 2); - } + public static toRaiseIntentForContextRequest(json: string): RaiseIntentForContextRequest { + return cast(JSON.parse(json), r('RaiseIntentForContextRequest')); + } - public static toGetInfoRequest(json: string): GetInfoRequest { - return cast(JSON.parse(json), r("GetInfoRequest")); - } + public static raiseIntentForContextRequestToJson(value: RaiseIntentForContextRequest): string { + return JSON.stringify(uncast(value, r('RaiseIntentForContextRequest')), null, 2); + } - public static getInfoRequestToJson(value: GetInfoRequest): string { - return JSON.stringify(uncast(value, r("GetInfoRequest")), null, 2); - } + public static toRaiseIntentForContextResponse(json: string): RaiseIntentForContextResponse { + return cast(JSON.parse(json), r('RaiseIntentForContextResponse')); + } - public static toGetInfoResponse(json: string): GetInfoResponse { - return cast(JSON.parse(json), r("GetInfoResponse")); - } + public static raiseIntentForContextResponseToJson(value: RaiseIntentForContextResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentForContextResponse')), null, 2); + } - public static getInfoResponseToJson(value: GetInfoResponse): string { - return JSON.stringify(uncast(value, r("GetInfoResponse")), null, 2); - } + public static toRaiseIntentRequest(json: string): RaiseIntentRequest { + return cast(JSON.parse(json), r('RaiseIntentRequest')); + } - public static toGetOrCreateChannelRequest(json: string): GetOrCreateChannelRequest { - return cast(JSON.parse(json), r("GetOrCreateChannelRequest")); - } - - public static getOrCreateChannelRequestToJson(value: GetOrCreateChannelRequest): string { - return JSON.stringify(uncast(value, r("GetOrCreateChannelRequest")), null, 2); - } - - public static toGetOrCreateChannelResponse(json: string): GetOrCreateChannelResponse { - return cast(JSON.parse(json), r("GetOrCreateChannelResponse")); - } - - public static getOrCreateChannelResponseToJson(value: GetOrCreateChannelResponse): string { - return JSON.stringify(uncast(value, r("GetOrCreateChannelResponse")), null, 2); - } - - public static toGetUserChannelsRequest(json: string): GetUserChannelsRequest { - return cast(JSON.parse(json), r("GetUserChannelsRequest")); - } - - public static getUserChannelsRequestToJson(value: GetUserChannelsRequest): string { - return JSON.stringify(uncast(value, r("GetUserChannelsRequest")), null, 2); - } - - public static toGetUserChannelsResponse(json: string): GetUserChannelsResponse { - return cast(JSON.parse(json), r("GetUserChannelsResponse")); - } + public static raiseIntentRequestToJson(value: RaiseIntentRequest): string { + return JSON.stringify(uncast(value, r('RaiseIntentRequest')), null, 2); + } - public static getUserChannelsResponseToJson(value: GetUserChannelsResponse): string { - return JSON.stringify(uncast(value, r("GetUserChannelsResponse")), null, 2); - } - - public static toHeartbeatAcknowledgementRequest(json: string): HeartbeatAcknowledgementRequest { - return cast(JSON.parse(json), r("HeartbeatAcknowledgementRequest")); - } + public static toRaiseIntentResponse(json: string): RaiseIntentResponse { + return cast(JSON.parse(json), r('RaiseIntentResponse')); + } - public static heartbeatAcknowledgementRequestToJson(value: HeartbeatAcknowledgementRequest): string { - return JSON.stringify(uncast(value, r("HeartbeatAcknowledgementRequest")), null, 2); - } + public static raiseIntentResponseToJson(value: RaiseIntentResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentResponse')), null, 2); + } - public static toHeartbeatEvent(json: string): HeartbeatEvent { - return cast(JSON.parse(json), r("HeartbeatEvent")); - } - - public static heartbeatEventToJson(value: HeartbeatEvent): string { - return JSON.stringify(uncast(value, r("HeartbeatEvent")), null, 2); - } - - public static toIntentEvent(json: string): IntentEvent { - return cast(JSON.parse(json), r("IntentEvent")); - } - - public static intentEventToJson(value: IntentEvent): string { - return JSON.stringify(uncast(value, r("IntentEvent")), null, 2); - } - - public static toIntentListenerUnsubscribeRequest(json: string): IntentListenerUnsubscribeRequest { - return cast(JSON.parse(json), r("IntentListenerUnsubscribeRequest")); - } - - public static intentListenerUnsubscribeRequestToJson(value: IntentListenerUnsubscribeRequest): string { - return JSON.stringify(uncast(value, r("IntentListenerUnsubscribeRequest")), null, 2); - } - - public static toIntentListenerUnsubscribeResponse(json: string): IntentListenerUnsubscribeResponse { - return cast(JSON.parse(json), r("IntentListenerUnsubscribeResponse")); - } - - public static intentListenerUnsubscribeResponseToJson(value: IntentListenerUnsubscribeResponse): string { - return JSON.stringify(uncast(value, r("IntentListenerUnsubscribeResponse")), null, 2); - } - - public static toIntentResultRequest(json: string): IntentResultRequest { - return cast(JSON.parse(json), r("IntentResultRequest")); - } - - public static intentResultRequestToJson(value: IntentResultRequest): string { - return JSON.stringify(uncast(value, r("IntentResultRequest")), null, 2); - } - - public static toIntentResultResponse(json: string): IntentResultResponse { - return cast(JSON.parse(json), r("IntentResultResponse")); - } - - public static intentResultResponseToJson(value: IntentResultResponse): string { - return JSON.stringify(uncast(value, r("IntentResultResponse")), null, 2); - } - - public static toJoinUserChannelRequest(json: string): JoinUserChannelRequest { - return cast(JSON.parse(json), r("JoinUserChannelRequest")); - } - - public static joinUserChannelRequestToJson(value: JoinUserChannelRequest): string { - return JSON.stringify(uncast(value, r("JoinUserChannelRequest")), null, 2); - } - - public static toJoinUserChannelResponse(json: string): JoinUserChannelResponse { - return cast(JSON.parse(json), r("JoinUserChannelResponse")); - } - - public static joinUserChannelResponseToJson(value: JoinUserChannelResponse): string { - return JSON.stringify(uncast(value, r("JoinUserChannelResponse")), null, 2); - } - - public static toLeaveCurrentChannelRequest(json: string): LeaveCurrentChannelRequest { - return cast(JSON.parse(json), r("LeaveCurrentChannelRequest")); - } - - public static leaveCurrentChannelRequestToJson(value: LeaveCurrentChannelRequest): string { - return JSON.stringify(uncast(value, r("LeaveCurrentChannelRequest")), null, 2); - } - - public static toLeaveCurrentChannelResponse(json: string): LeaveCurrentChannelResponse { - return cast(JSON.parse(json), r("LeaveCurrentChannelResponse")); - } - - public static leaveCurrentChannelResponseToJson(value: LeaveCurrentChannelResponse): string { - return JSON.stringify(uncast(value, r("LeaveCurrentChannelResponse")), null, 2); - } - - public static toOpenRequest(json: string): OpenRequest { - return cast(JSON.parse(json), r("OpenRequest")); - } - - public static openRequestToJson(value: OpenRequest): string { - return JSON.stringify(uncast(value, r("OpenRequest")), null, 2); - } - - public static toOpenResponse(json: string): OpenResponse { - return cast(JSON.parse(json), r("OpenResponse")); - } - - public static openResponseToJson(value: OpenResponse): string { - return JSON.stringify(uncast(value, r("OpenResponse")), null, 2); - } - - public static toPrivateChannelAddEventListenerRequest(json: string): PrivateChannelAddEventListenerRequest { - return cast(JSON.parse(json), r("PrivateChannelAddEventListenerRequest")); - } - - public static privateChannelAddEventListenerRequestToJson(value: PrivateChannelAddEventListenerRequest): string { - return JSON.stringify(uncast(value, r("PrivateChannelAddEventListenerRequest")), null, 2); - } - - public static toPrivateChannelAddEventListenerResponse(json: string): PrivateChannelAddEventListenerResponse { - return cast(JSON.parse(json), r("PrivateChannelAddEventListenerResponse")); - } - - public static privateChannelAddEventListenerResponseToJson(value: PrivateChannelAddEventListenerResponse): string { - return JSON.stringify(uncast(value, r("PrivateChannelAddEventListenerResponse")), null, 2); - } - - public static toPrivateChannelDisconnectRequest(json: string): PrivateChannelDisconnectRequest { - return cast(JSON.parse(json), r("PrivateChannelDisconnectRequest")); - } - - public static privateChannelDisconnectRequestToJson(value: PrivateChannelDisconnectRequest): string { - return JSON.stringify(uncast(value, r("PrivateChannelDisconnectRequest")), null, 2); - } - - public static toPrivateChannelDisconnectResponse(json: string): PrivateChannelDisconnectResponse { - return cast(JSON.parse(json), r("PrivateChannelDisconnectResponse")); - } + public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { + return cast(JSON.parse(json), r('RaiseIntentResultResponse')); + } - public static privateChannelDisconnectResponseToJson(value: PrivateChannelDisconnectResponse): string { - return JSON.stringify(uncast(value, r("PrivateChannelDisconnectResponse")), null, 2); - } - - public static toPrivateChannelOnAddContextListenerEvent(json: string): PrivateChannelOnAddContextListenerEvent { - return cast(JSON.parse(json), r("PrivateChannelOnAddContextListenerEvent")); - } - - public static privateChannelOnAddContextListenerEventToJson(value: PrivateChannelOnAddContextListenerEvent): string { - return JSON.stringify(uncast(value, r("PrivateChannelOnAddContextListenerEvent")), null, 2); - } - - public static toPrivateChannelOnDisconnectEvent(json: string): PrivateChannelOnDisconnectEvent { - return cast(JSON.parse(json), r("PrivateChannelOnDisconnectEvent")); - } - - public static privateChannelOnDisconnectEventToJson(value: PrivateChannelOnDisconnectEvent): string { - return JSON.stringify(uncast(value, r("PrivateChannelOnDisconnectEvent")), null, 2); - } - - public static toPrivateChannelOnUnsubscribeEvent(json: string): PrivateChannelOnUnsubscribeEvent { - return cast(JSON.parse(json), r("PrivateChannelOnUnsubscribeEvent")); - } - - public static privateChannelOnUnsubscribeEventToJson(value: PrivateChannelOnUnsubscribeEvent): string { - return JSON.stringify(uncast(value, r("PrivateChannelOnUnsubscribeEvent")), null, 2); - } - - public static toPrivateChannelUnsubscribeEventListenerRequest(json: string): PrivateChannelUnsubscribeEventListenerRequest { - return cast(JSON.parse(json), r("PrivateChannelUnsubscribeEventListenerRequest")); - } - - public static privateChannelUnsubscribeEventListenerRequestToJson(value: PrivateChannelUnsubscribeEventListenerRequest): string { - return JSON.stringify(uncast(value, r("PrivateChannelUnsubscribeEventListenerRequest")), null, 2); - } - - public static toPrivateChannelUnsubscribeEventListenerResponse(json: string): PrivateChannelUnsubscribeEventListenerResponse { - return cast(JSON.parse(json), r("PrivateChannelUnsubscribeEventListenerResponse")); - } - - public static privateChannelUnsubscribeEventListenerResponseToJson(value: PrivateChannelUnsubscribeEventListenerResponse): string { - return JSON.stringify(uncast(value, r("PrivateChannelUnsubscribeEventListenerResponse")), null, 2); - } - - public static toRaiseIntentForContextRequest(json: string): RaiseIntentForContextRequest { - return cast(JSON.parse(json), r("RaiseIntentForContextRequest")); - } - - public static raiseIntentForContextRequestToJson(value: RaiseIntentForContextRequest): string { - return JSON.stringify(uncast(value, r("RaiseIntentForContextRequest")), null, 2); - } - - public static toRaiseIntentForContextResponse(json: string): RaiseIntentForContextResponse { - return cast(JSON.parse(json), r("RaiseIntentForContextResponse")); - } - - public static raiseIntentForContextResponseToJson(value: RaiseIntentForContextResponse): string { - return JSON.stringify(uncast(value, r("RaiseIntentForContextResponse")), null, 2); - } - - public static toRaiseIntentRequest(json: string): RaiseIntentRequest { - return cast(JSON.parse(json), r("RaiseIntentRequest")); - } - - public static raiseIntentRequestToJson(value: RaiseIntentRequest): string { - return JSON.stringify(uncast(value, r("RaiseIntentRequest")), null, 2); - } - - public static toRaiseIntentResponse(json: string): RaiseIntentResponse { - return cast(JSON.parse(json), r("RaiseIntentResponse")); - } - - public static raiseIntentResponseToJson(value: RaiseIntentResponse): string { - return JSON.stringify(uncast(value, r("RaiseIntentResponse")), null, 2); - } - - public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { - return cast(JSON.parse(json), r("RaiseIntentResultResponse")); - } - - public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { - return JSON.stringify(uncast(value, r("RaiseIntentResultResponse")), null, 2); - } + public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentResultResponse')), null, 2); + } +} - public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { - return cast(JSON.parse(json), r("WebConnectionProtocol1Hello")); - } +function invalidValue(typ: any, val: any, key: any, parent: any = ''): never { + const prettyTyp = prettyTypeName(typ); + const parentText = parent ? ` on ${parent}` : ''; + const keyText = key ? ` for key "${key}"` : ''; + throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`); +} - public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol1Hello")), null, 2); +function prettyTypeName(typ: any): string { + if (Array.isArray(typ)) { + if (typ.length === 2 && typ[0] === undefined) { + return `an optional ${prettyTypeName(typ[1])}`; + } else { + return `one of [${typ + .map(a => { + return prettyTypeName(a); + }) + .join(', ')}]`; } + } else if (typeof typ === 'object' && typ.literal !== undefined) { + return typ.literal; + } else { + return typeof typ; + } +} - public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { - return cast(JSON.parse(json), r("WebConnectionProtocol2LoadURL")); - } +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => (map[p.json] = { key: p.js, typ: p.typ })); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} - public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol2LoadURL")), null, 2); - } +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => (map[p.js] = { key: p.json, typ: p.typ })); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} - public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { - return cast(JSON.parse(json), r("WebConnectionProtocol3Handshake")); - } +function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val, key, parent); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val, key, parent); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue( + cases.map(a => { + return l(a); + }), + val, + key, + parent + ); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue(l('array'), val, key, parent); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue(l('Date'), val, key, parent); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== 'object' || Array.isArray(val)) { + return invalidValue(l(ref || 'object'), val, key, parent); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps, key, ref); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps, key, ref); + } + }); + return result; + } + + if (typ === 'any') return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val, key, parent); + } + if (typ === false) return invalidValue(typ, val, key, parent); + let ref: any = undefined; + while (typeof typ === 'object' && typ.ref !== undefined) { + ref = typ.ref; + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === 'object') { + return typ.hasOwnProperty('unionMembers') + ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty('arrayItems') + ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty('props') + ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val, key, parent); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== 'number') return transformDate(val); + return transformPrimitive(typ, val); +} - public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol3Handshake")), null, 2); - } +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} - public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { - return cast(JSON.parse(json), r("WebConnectionProtocol4ValidateAppIdentity")); - } +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} - public static webConnectionProtocol4ValidateAppIdentityToJson(value: WebConnectionProtocol4ValidateAppIdentity): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol4ValidateAppIdentity")), null, 2); - } +function l(typ: any) { + return { literal: typ }; +} - public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json: string): WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")); - } +function a(typ: any) { + return { arrayItems: typ }; +} - public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value: WebConnectionProtocol5ValidateAppIdentityFailedResponse): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentityFailedResponse")), null, 2); - } +function u(...typs: any[]) { + return { unionMembers: typs }; +} - public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json: string): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return cast(JSON.parse(json), r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")); - } +function o(props: any[], additional: any) { + return { props, additional }; +} - public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol5ValidateAppIdentitySuccessResponse")), null, 2); - } +function m(additional: any) { + return { props: [], additional }; +} - public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { - return cast(JSON.parse(json), r("WebConnectionProtocol6Goodbye")); - } +function r(name: string) { + return { ref: name }; +} - public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocol6Goodbye")), null, 2); - } +const typeMap: any = { + WebConnectionProtocol1Hello: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol1HelloPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol1HelloType') }, + ], + false + ), + WebConnectionProtocol1HelloMeta: o( + [ + { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: '' }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + WebConnectionProtocol1HelloPayload: o( + [ + { json: 'actualUrl', js: 'actualUrl', typ: '' }, + { json: 'channelSelector', js: 'channelSelector', typ: u(undefined, true) }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'identityUrl', js: 'identityUrl', typ: '' }, + { json: 'intentResolver', js: 'intentResolver', typ: u(undefined, true) }, + ], + 'any' + ), + WebConnectionProtocol2LoadURL: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol2LoadURLPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol2LoadURLType') }, + ], + false + ), + WebConnectionProtocol2LoadURLPayload: o([{ json: 'iframeUrl', js: 'iframeUrl', typ: '' }], 'any'), + WebConnectionProtocol3Handshake: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol3HandshakePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol3HandshakeType') }, + ], + false + ), + WebConnectionProtocol3HandshakePayload: o( + [ + { json: 'channelSelectorUrl', js: 'channelSelectorUrl', typ: u(true, '') }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'intentResolverUrl', js: 'intentResolverUrl', typ: u(true, '') }, + ], + false + ), + WebConnectionProtocol4ValidateAppIdentity: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol4ValidateAppIdentityPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol4ValidateAppIdentityType') }, + ], + false + ), + WebConnectionProtocol4ValidateAppIdentityPayload: o( + [ + { json: 'actualUrl', js: 'actualUrl', typ: '' }, + { json: 'identityUrl', js: 'identityUrl', typ: '' }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + { json: 'instanceUuid', js: 'instanceUuid', typ: u(undefined, '') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentityFailedResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponseType') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload: o( + [{ json: 'message', js: 'message', typ: u(undefined, '') }], + false + ), + WebConnectionProtocol5ValidateAppIdentitySuccessResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponseType') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'implementationMetadata', js: 'implementationMetadata', typ: r('ImplementationMetadata') }, + { json: 'instanceId', js: 'instanceId', typ: '' }, + { json: 'instanceUuid', js: 'instanceUuid', typ: '' }, + ], + false + ), + ImplementationMetadata: o( + [ + { json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, + { json: 'provider', js: 'provider', typ: '' }, + { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, + ], + false + ), + AppMetadata: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'description', js: 'description', typ: u(undefined, '') }, + { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, + { json: 'icons', js: 'icons', typ: u(undefined, a(r('Icon'))) }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + { json: 'instanceMetadata', js: 'instanceMetadata', typ: u(undefined, m('any')) }, + { json: 'name', js: 'name', typ: u(undefined, '') }, + { json: 'resultType', js: 'resultType', typ: u(undefined, u(null, '')) }, + { json: 'screenshots', js: 'screenshots', typ: u(undefined, a(r('Image'))) }, + { json: 'title', js: 'title', typ: u(undefined, '') }, + { json: 'tooltip', js: 'tooltip', typ: u(undefined, '') }, + { json: 'version', js: 'version', typ: u(undefined, '') }, + ], + false + ), + Icon: o( + [ + { json: 'size', js: 'size', typ: u(undefined, '') }, + { json: 'src', js: 'src', typ: '' }, + { json: 'type', js: 'type', typ: u(undefined, '') }, + ], + false + ), + Image: o( + [ + { json: 'label', js: 'label', typ: u(undefined, '') }, + { json: 'size', js: 'size', typ: u(undefined, '') }, + { json: 'src', js: 'src', typ: '' }, + { json: 'type', js: 'type', typ: u(undefined, '') }, + ], + false + ), + OptionalFeatures: o( + [ + { json: 'DesktopAgentBridging', js: 'DesktopAgentBridging', typ: true }, + { json: 'OriginatingAppMetadata', js: 'OriginatingAppMetadata', typ: true }, + { json: 'UserChannelMembershipAPIs', js: 'UserChannelMembershipAPIs', typ: true }, + ], + false + ), + WebConnectionProtocol6Goodbye: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol6GoodbyeMeta') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol6GoodbyeType') }, + ], + false + ), + WebConnectionProtocol6GoodbyeMeta: o([{ json: 'timestamp', js: 'timestamp', typ: Date }], false), + WebConnectionProtocolMessage: o( + [ + { json: 'meta', js: 'meta', typ: r('ConnectionStepMetadata') }, + { json: 'payload', js: 'payload', typ: u(undefined, m('any')) }, + { json: 'type', js: 'type', typ: r('ConnectionStepMessageType') }, + ], + false + ), + ConnectionStepMetadata: o( + [ + { json: 'timestamp', js: 'timestamp', typ: Date }, + { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: u(undefined, '') }, + ], + false + ), + AddContextListenerRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('AddContextListenerRequestPayload') }, + { json: 'type', js: 'type', typ: r('AddContextListenerRequestType') }, + ], + false + ), + AddContextListenerRequestMeta: o( + [ + { json: 'requestUuid', js: 'requestUuid', typ: '' }, + { json: 'source', js: 'source', typ: u(undefined, r('AppIdentifier')) }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + AppIdentifier: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + ], + 'any' + ), + AddContextListenerRequestPayload: o( + [ + { json: 'channelId', js: 'channelId', typ: u(null, '') }, + { json: 'contextType', js: 'contextType', typ: u(null, '') }, + ], + false + ), + AddContextListenerResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('AddContextListenerResponsePayload') }, + { json: 'type', js: 'type', typ: r('AddContextListenerResponseType') }, + ], + false + ), + AddContextListenerResponseMeta: o( + [ + { json: 'requestUuid', js: 'requestUuid', typ: '' }, + { json: 'responseUuid', js: 'responseUuid', typ: '' }, + { json: 'source', js: 'source', typ: u(undefined, r('AppIdentifier')) }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + AddContextListenerResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }, + { json: 'listenerUUID', js: 'listenerUUID', typ: u(undefined, '') }, + ], + false + ), + AddEventListenerRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('AddEventListenerRequestPayload') }, + { json: 'type', js: 'type', typ: r('AddEventListenerRequestType') }, + ], + false + ), + AddEventListenerRequestPayload: o([{ json: 'type', js: 'type', typ: u(r('FDC3EventType'), null) }], false), + AddEventListenerResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('AddEventListenerResponsePayload') }, + { json: 'type', js: 'type', typ: r('AddEventListenerResponseType') }, + ], + false + ), + AddEventListenerResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, + { json: 'listenerUUID', js: 'listenerUUID', typ: u(undefined, '') }, + ], + false + ), + AddIntentListenerRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('AddIntentListenerRequestPayload') }, + { json: 'type', js: 'type', typ: r('AddIntentListenerRequestType') }, + ], + false + ), + AddIntentListenerRequestPayload: o([{ json: 'intent', js: 'intent', typ: '' }], false), + AddIntentListenerResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('PayloadObject') }, + { json: 'type', js: 'type', typ: r('AddIntentListenerResponseType') }, + ], + false + ), + PayloadObject: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FluffyError')) }, + { json: 'listenerUUID', js: 'listenerUUID', typ: u(undefined, '') }, + ], + 'any' + ), + AgentEventMessage: o( + [ + { json: 'meta', js: 'meta', typ: r('AgentEventMessageMeta') }, + { json: 'payload', js: 'payload', typ: m('any') }, + { json: 'type', js: 'type', typ: r('EventMessageType') }, + ], + false + ), + AgentEventMessageMeta: o( + [ + { json: 'eventUuid', js: 'eventUuid', typ: '' }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + AgentResponseMessage: o( + [ + { json: 'meta', js: 'meta', typ: r('AgentResponseMessageMeta') }, + { json: 'payload', js: 'payload', typ: r('AgentResponseMessageResponsePayload') }, + { json: 'type', js: 'type', typ: r('ResponseMessageType') }, + ], + false + ), + AgentResponseMessageMeta: o( + [ + { json: 'requestUuid', js: 'requestUuid', typ: '' }, + { json: 'responseUuid', js: 'responseUuid', typ: '' }, + { json: 'source', js: 'source', typ: u(undefined, r('AppIdentifier')) }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + AgentResponseMessageResponsePayload: o( + [{ json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }], + 'any' + ), + AppRequestMessage: o( + [ + { json: 'meta', js: 'meta', typ: r('AppRequestMessageMeta') }, + { json: 'payload', js: 'payload', typ: m('any') }, + { json: 'type', js: 'type', typ: r('RequestMessageType') }, + ], + false + ), + AppRequestMessageMeta: o( + [ + { json: 'requestUuid', js: 'requestUuid', typ: '' }, + { json: 'source', js: 'source', typ: u(undefined, r('AppIdentifier')) }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + BroadcastEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastEventPayload') }, + { json: 'type', js: 'type', typ: r('BroadcastEventType') }, + ], + false + ), + BroadcastEventMeta: o( + [ + { json: 'eventUuid', js: 'eventUuid', typ: '' }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + BroadcastEventPayload: o( + [ + { json: 'channelId', js: 'channelId', typ: u(null, '') }, + { json: 'context', js: 'context', typ: r('Context') }, + { json: 'originatingApp', js: 'originatingApp', typ: u(undefined, r('AppIdentifier')) }, + ], + false + ), + Context: o( + [ + { json: 'id', js: 'id', typ: u(undefined, m('any')) }, + { json: 'name', js: 'name', typ: u(undefined, '') }, + { json: 'type', js: 'type', typ: '' }, + ], + 'any' + ), + BroadcastRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastRequestPayload') }, + { json: 'type', js: 'type', typ: r('BroadcastRequestType') }, + ], + false + ), + BroadcastRequestPayload: o( + [ + { json: 'channelId', js: 'channelId', typ: '' }, + { json: 'context', js: 'context', typ: r('Context') }, + ], + false + ), + BroadcastResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastResponseResponsePayload') }, + { json: 'type', js: 'type', typ: r('BroadcastResponseType') }, + ], + false + ), + BroadcastResponseResponsePayload: o( + [{ json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }], + 'any' + ), + ChannelChangedEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('ChannelChangedEventPayload') }, + { json: 'type', js: 'type', typ: r('ChannelChangedEventType') }, + ], + false + ), + ChannelChangedEventPayload: o([{ json: 'newChannelId', js: 'newChannelId', typ: u(null, '') }], false), + ContextListenerUnsubscribeRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('ContextListenerUnsubscribeRequestPayload') }, + { json: 'type', js: 'type', typ: r('ContextListenerUnsubscribeRequestType') }, + ], + false + ), + ContextListenerUnsubscribeRequestPayload: o([{ json: 'listenerUUID', js: 'listenerUUID', typ: '' }], false), + ContextListenerUnsubscribeResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastResponseResponsePayload') }, + { json: 'type', js: 'type', typ: r('ContextListenerUnsubscribeResponseType') }, + ], + false + ), + CreatePrivateChannelRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('CreatePrivateChannelRequestPayload') }, + { json: 'type', js: 'type', typ: r('CreatePrivateChannelRequestType') }, + ], + false + ), + CreatePrivateChannelRequestPayload: o([], false), + CreatePrivateChannelResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('CreatePrivateChannelResponsePayload') }, + { json: 'type', js: 'type', typ: r('CreatePrivateChannelResponseType') }, + ], + false + ), + CreatePrivateChannelResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }, + { json: 'privateChannel', js: 'privateChannel', typ: u(undefined, r('Channel')) }, + ], + false + ), + Channel: o( + [ + { json: 'displayMetadata', js: 'displayMetadata', typ: u(undefined, r('DisplayMetadata')) }, + { json: 'id', js: 'id', typ: '' }, + { json: 'type', js: 'type', typ: r('Type') }, + ], + false + ), + DisplayMetadata: o( + [ + { json: 'color', js: 'color', typ: u(undefined, '') }, + { json: 'glyph', js: 'glyph', typ: u(undefined, '') }, + { json: 'name', js: 'name', typ: u(undefined, '') }, + ], + false + ), + EventListenerUnsubscribeRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('EventListenerUnsubscribeRequestPayload') }, + { json: 'type', js: 'type', typ: r('EventListenerUnsubscribeRequestType') }, + ], + false + ), + EventListenerUnsubscribeRequestPayload: o([{ json: 'listenerUUID', js: 'listenerUUID', typ: '' }], false), + EventListenerUnsubscribeResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastResponseResponsePayload') }, + { json: 'type', js: 'type', typ: r('EventListenerUnsubscribeResponseType') }, + ], + false + ), + Fdc3UserInterfaceChannelSelected: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelSelectedPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceChannelSelectedType') }, + ], + false + ), + Fdc3UserInterfaceChannelSelectedPayload: o([{ json: 'selected', js: 'selected', typ: u(null, '') }], false), + Fdc3UserInterfaceChannels: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelsPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceChannelsType') }, + ], + false + ), + Fdc3UserInterfaceChannelsPayload: o( + [ + { json: 'selected', js: 'selected', typ: u(null, '') }, + { json: 'userChannels', js: 'userChannels', typ: a(r('Channel')) }, + ], + false + ), + Fdc3UserInterfaceDrag: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceDragPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceDragType') }, + ], + false + ), + Fdc3UserInterfaceDragPayload: o([{ json: 'mouseOffsets', js: 'mouseOffsets', typ: r('MouseOffsets') }], false), + MouseOffsets: o( + [ + { json: 'x', js: 'x', typ: 0 }, + { json: 'y', js: 'y', typ: 0 }, + ], + false + ), + Fdc3UserInterfaceHandshake: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceHandshakePayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceHandshakeType') }, + ], + false + ), + Fdc3UserInterfaceHandshakePayload: o([{ json: 'fdc3Version', js: 'fdc3Version', typ: '' }], false), + Fdc3UserInterfaceHello: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceHelloPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceHelloType') }, + ], + false + ), + Fdc3UserInterfaceHelloPayload: o( + [ + { json: 'implementationDetails', js: 'implementationDetails', typ: '' }, + { json: 'initialCSS', js: 'initialCSS', typ: r('InitialCSS') }, + ], + false + ), + InitialCSS: o( + [ + { json: 'bottom', js: 'bottom', typ: u(undefined, '') }, + { json: 'height', js: 'height', typ: u(undefined, '') }, + { json: 'left', js: 'left', typ: u(undefined, '') }, + { json: 'maxHeight', js: 'maxHeight', typ: u(undefined, '') }, + { json: 'maxWidth', js: 'maxWidth', typ: u(undefined, '') }, + { json: 'right', js: 'right', typ: u(undefined, '') }, + { json: 'top', js: 'top', typ: u(undefined, '') }, + { json: 'transition', js: 'transition', typ: u(undefined, '') }, + { json: 'width', js: 'width', typ: u(undefined, '') }, + { json: 'zIndex', js: 'zIndex', typ: u(undefined, '') }, + ], + 'any' + ), + Fdc3UserInterfaceMessage: o( + [ + { json: 'payload', js: 'payload', typ: u(undefined, m('any')) }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceMessageType') }, + ], + false + ), + Fdc3UserInterfaceResolve: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceResolvePayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceResolveType') }, + ], + false + ), + Fdc3UserInterfaceResolvePayload: o( + [ + { json: 'appIntents', js: 'appIntents', typ: a(r('AppIntent')) }, + { json: 'context', js: 'context', typ: r('Context') }, + ], + false + ), + AppIntent: o( + [ + { json: 'apps', js: 'apps', typ: a(r('AppMetadata')) }, + { json: 'intent', js: 'intent', typ: r('IntentMetadata') }, + ], + false + ), + IntentMetadata: o( + [ + { json: 'displayName', js: 'displayName', typ: u(undefined, '') }, + { json: 'name', js: 'name', typ: '' }, + ], + false + ), + Fdc3UserInterfaceResolveAction: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceResolveActionPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceResolveActionType') }, + ], + false + ), + Fdc3UserInterfaceResolveActionPayload: o( + [ + { json: 'action', js: 'action', typ: r('Action') }, + { json: 'appIdentifier', js: 'appIdentifier', typ: u(undefined, r('AppIdentifier')) }, + { json: 'intent', js: 'intent', typ: u(undefined, '') }, + ], + false + ), + Fdc3UserInterfaceRestyle: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceRestylePayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceRestyleType') }, + ], + false + ), + Fdc3UserInterfaceRestylePayload: o([{ json: 'updatedCSS', js: 'updatedCSS', typ: r('UpdatedCSS') }], false), + UpdatedCSS: o( + [ + { json: 'bottom', js: 'bottom', typ: u(undefined, '') }, + { json: 'height', js: 'height', typ: u(undefined, '') }, + { json: 'left', js: 'left', typ: u(undefined, '') }, + { json: 'maxHeight', js: 'maxHeight', typ: u(undefined, '') }, + { json: 'maxWidth', js: 'maxWidth', typ: u(undefined, '') }, + { json: 'right', js: 'right', typ: u(undefined, '') }, + { json: 'top', js: 'top', typ: u(undefined, '') }, + { json: 'transition', js: 'transition', typ: u(undefined, '') }, + { json: 'width', js: 'width', typ: u(undefined, '') }, + { json: 'zIndex', js: 'zIndex', typ: u(undefined, '') }, + ], + 'any' + ), + FindInstancesRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('FindInstancesRequestPayload') }, + { json: 'type', js: 'type', typ: r('FindInstancesRequestType') }, + ], + false + ), + FindInstancesRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppIdentifier') }], false), + FindInstancesResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('FindInstancesResponsePayload') }, + { json: 'type', js: 'type', typ: r('FindInstancesResponseType') }, + ], + false + ), + FindInstancesResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FindInstancesErrors')) }, + { json: 'appIdentifiers', js: 'appIdentifiers', typ: u(undefined, a(r('AppMetadata'))) }, + ], + false + ), + FindIntentRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('FindIntentRequestPayload') }, + { json: 'type', js: 'type', typ: r('FindIntentRequestType') }, + ], + false + ), + FindIntentRequestPayload: o( + [ + { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, + { json: 'intent', js: 'intent', typ: '' }, + { json: 'resultType', js: 'resultType', typ: u(undefined, '') }, + ], + false + ), + FindIntentResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('FindIntentResponsePayload') }, + { json: 'type', js: 'type', typ: r('FindIntentResponseType') }, + ], + false + ), + FindIntentResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FindInstancesErrors')) }, + { json: 'appIntent', js: 'appIntent', typ: u(undefined, r('AppIntent')) }, + ], + false + ), + FindIntentsByContextRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('FindIntentsByContextRequestPayload') }, + { json: 'type', js: 'type', typ: r('FindIntentsByContextRequestType') }, + ], + false + ), + FindIntentsByContextRequestPayload: o( + [ + { json: 'context', js: 'context', typ: r('Context') }, + { json: 'resultType', js: 'resultType', typ: u(undefined, '') }, + ], + false + ), + FindIntentsByContextResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('FindIntentsByContextResponsePayload') }, + { json: 'type', js: 'type', typ: r('FindIntentsByContextResponseType') }, + ], + false + ), + FindIntentsByContextResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FindInstancesErrors')) }, + { json: 'appIntents', js: 'appIntents', typ: u(undefined, a(r('AppIntent'))) }, + ], + false + ), + GetAppMetadataRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('GetAppMetadataRequestPayload') }, + { json: 'type', js: 'type', typ: r('GetAppMetadataRequestType') }, + ], + false + ), + GetAppMetadataRequestPayload: o([{ json: 'app', js: 'app', typ: r('AppIdentifier') }], false), + GetAppMetadataResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('GetAppMetadataResponsePayload') }, + { json: 'type', js: 'type', typ: r('GetAppMetadataResponseType') }, + ], + false + ), + GetAppMetadataResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FindInstancesErrors')) }, + { json: 'appMetadata', js: 'appMetadata', typ: u(undefined, r('AppMetadata')) }, + ], + false + ), + GetCurrentChannelRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('GetCurrentChannelRequestPayload') }, + { json: 'type', js: 'type', typ: r('GetCurrentChannelRequestType') }, + ], + false + ), + GetCurrentChannelRequestPayload: o([], false), + GetCurrentChannelResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('GetCurrentChannelResponsePayload') }, + { json: 'type', js: 'type', typ: r('GetCurrentChannelResponseType') }, + ], + false + ), + GetCurrentChannelResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, + { json: 'channel', js: 'channel', typ: u(undefined, u(r('Channel'), null)) }, + ], + false + ), + GetCurrentContextRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('GetCurrentContextRequestPayload') }, + { json: 'type', js: 'type', typ: r('GetCurrentContextRequestType') }, + ], + false + ), + GetCurrentContextRequestPayload: o( + [ + { json: 'channelId', js: 'channelId', typ: '' }, + { json: 'contextType', js: 'contextType', typ: u(null, '') }, + ], + false + ), + GetCurrentContextResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('GetCurrentContextResponsePayload') }, + { json: 'type', js: 'type', typ: r('GetCurrentContextResponseType') }, + ], + false + ), + GetCurrentContextResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }, + { json: 'context', js: 'context', typ: u(undefined, u(null, r('Context'))) }, + ], + false + ), + GetInfoRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('GetInfoRequestPayload') }, + { json: 'type', js: 'type', typ: r('GetInfoRequestType') }, + ], + false + ), + GetInfoRequestPayload: o([], false), + GetInfoResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('GetInfoResponsePayload') }, + { json: 'type', js: 'type', typ: r('GetInfoResponseType') }, + ], + false + ), + GetInfoResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, + { json: 'implementationMetadata', js: 'implementationMetadata', typ: u(undefined, r('ImplementationMetadata')) }, + ], + false + ), + GetOrCreateChannelRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('GetOrCreateChannelRequestPayload') }, + { json: 'type', js: 'type', typ: r('GetOrCreateChannelRequestType') }, + ], + false + ), + GetOrCreateChannelRequestPayload: o([{ json: 'channelId', js: 'channelId', typ: '' }], false), + GetOrCreateChannelResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('GetOrCreateChannelResponsePayload') }, + { json: 'type', js: 'type', typ: r('GetOrCreateChannelResponseType') }, + ], + false + ), + GetOrCreateChannelResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }, + { json: 'channel', js: 'channel', typ: u(undefined, r('Channel')) }, + ], + false + ), + GetUserChannelsRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('GetUserChannelsRequestPayload') }, + { json: 'type', js: 'type', typ: r('GetUserChannelsRequestType') }, + ], + false + ), + GetUserChannelsRequestPayload: o([], false), + GetUserChannelsResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('GetUserChannelsResponsePayload') }, + { json: 'type', js: 'type', typ: r('GetUserChannelsResponseType') }, + ], + false + ), + GetUserChannelsResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }, + { json: 'userChannels', js: 'userChannels', typ: u(undefined, a(r('Channel'))) }, + ], + false + ), + HeartbeatAcknowledgementRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('HeartbeatAcknowledgementRequestPayload') }, + { json: 'type', js: 'type', typ: r('HeartbeatAcknowledgementRequestType') }, + ], + false + ), + HeartbeatAcknowledgementRequestPayload: o([{ json: 'heartbeatEventUuid', js: 'heartbeatEventUuid', typ: '' }], false), + HeartbeatEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('HeartbeatEventPayload') }, + { json: 'type', js: 'type', typ: r('HeartbeatEventType') }, + ], + false + ), + HeartbeatEventPayload: o([], false), + IntentEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('IntentEventPayload') }, + { json: 'type', js: 'type', typ: r('IntentEventType') }, + ], + false + ), + IntentEventPayload: o( + [ + { json: 'context', js: 'context', typ: r('Context') }, + { json: 'intent', js: 'intent', typ: '' }, + { json: 'originatingApp', js: 'originatingApp', typ: u(undefined, r('AppIdentifier')) }, + { json: 'raiseIntentRequestUuid', js: 'raiseIntentRequestUuid', typ: '' }, + ], + false + ), + IntentListenerUnsubscribeRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('IntentListenerUnsubscribeRequestPayload') }, + { json: 'type', js: 'type', typ: r('IntentListenerUnsubscribeRequestType') }, + ], + false + ), + IntentListenerUnsubscribeRequestPayload: o([{ json: 'listenerUUID', js: 'listenerUUID', typ: '' }], false), + IntentListenerUnsubscribeResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastResponseResponsePayload') }, + { json: 'type', js: 'type', typ: r('IntentListenerUnsubscribeResponseType') }, + ], + false + ), + IntentResultRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('IntentResultRequestPayload') }, + { json: 'type', js: 'type', typ: r('IntentResultRequestType') }, + ], + false + ), + IntentResultRequestPayload: o( + [ + { json: 'intentEventUuid', js: 'intentEventUuid', typ: '' }, + { json: 'intentResult', js: 'intentResult', typ: r('IntentResult') }, + { json: 'raiseIntentRequestUuid', js: 'raiseIntentRequestUuid', typ: '' }, + ], + false + ), + IntentResult: o( + [ + { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, + { json: 'channel', js: 'channel', typ: u(undefined, r('Channel')) }, + ], + false + ), + IntentResultResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastResponseResponsePayload') }, + { json: 'type', js: 'type', typ: r('IntentResultResponseType') }, + ], + false + ), + JoinUserChannelRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('JoinUserChannelRequestPayload') }, + { json: 'type', js: 'type', typ: r('JoinUserChannelRequestType') }, + ], + false + ), + JoinUserChannelRequestPayload: o([{ json: 'channelId', js: 'channelId', typ: '' }], false), + JoinUserChannelResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('JoinUserChannelResponsePayload') }, + { json: 'type', js: 'type', typ: r('JoinUserChannelResponseType') }, + ], + false + ), + JoinUserChannelResponsePayload: o([{ json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }], false), + LeaveCurrentChannelRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('LeaveCurrentChannelRequestPayload') }, + { json: 'type', js: 'type', typ: r('LeaveCurrentChannelRequestType') }, + ], + false + ), + LeaveCurrentChannelRequestPayload: o([], false), + LeaveCurrentChannelResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('LeaveCurrentChannelResponsePayload') }, + { json: 'type', js: 'type', typ: r('LeaveCurrentChannelResponseType') }, + ], + false + ), + LeaveCurrentChannelResponsePayload: o([{ json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }], false), + OpenRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('OpenRequestPayload') }, + { json: 'type', js: 'type', typ: r('OpenRequestType') }, + ], + false + ), + OpenRequestPayload: o( + [ + { json: 'app', js: 'app', typ: r('AppIdentifier') }, + { json: 'context', js: 'context', typ: u(undefined, r('Context')) }, + ], + false + ), + OpenResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('OpenResponsePayload') }, + { json: 'type', js: 'type', typ: r('OpenResponseType') }, + ], + false + ), + OpenResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('OpenErrorResponsePayload')) }, + { json: 'appIdentifier', js: 'appIdentifier', typ: u(undefined, r('AppIdentifier')) }, + ], + false + ), + PrivateChannelAddEventListenerRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelAddEventListenerRequestPayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelAddEventListenerRequestType') }, + ], + false + ), + PrivateChannelAddEventListenerRequestPayload: o( + [ + { json: 'listenerType', js: 'listenerType', typ: u(r('PrivateChannelEventType'), null) }, + { json: 'privateChannelId', js: 'privateChannelId', typ: '' }, + ], + false + ), + PrivateChannelAddEventListenerResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelAddEventListenerResponsePayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelAddEventListenerResponseType') }, + ], + false + ), + PrivateChannelAddEventListenerResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }, + { json: 'listenerUUID', js: 'listenerUUID', typ: u(undefined, '') }, + ], + false + ), + PrivateChannelDisconnectRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelDisconnectRequestPayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelDisconnectRequestType') }, + ], + false + ), + PrivateChannelDisconnectRequestPayload: o([{ json: 'channelId', js: 'channelId', typ: '' }], false), + PrivateChannelDisconnectResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelDisconnectResponsePayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelDisconnectResponseType') }, + ], + false + ), + PrivateChannelDisconnectResponsePayload: o( + [{ json: 'error', js: 'error', typ: u(undefined, r('PurpleError')) }], + false + ), + PrivateChannelOnAddContextListenerEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelOnAddContextListenerEventPayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelOnAddContextListenerEventType') }, + ], + false + ), + PrivateChannelOnAddContextListenerEventPayload: o( + [ + { json: 'contextType', js: 'contextType', typ: u(null, '') }, + { json: 'privateChannelId', js: 'privateChannelId', typ: '' }, + ], + false + ), + PrivateChannelOnDisconnectEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelOnDisconnectEventPayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelOnDisconnectEventType') }, + ], + false + ), + PrivateChannelOnDisconnectEventPayload: o([{ json: 'privateChannelId', js: 'privateChannelId', typ: '' }], false), + PrivateChannelOnUnsubscribeEvent: o( + [ + { json: 'meta', js: 'meta', typ: r('BroadcastEventMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelOnUnsubscribeEventPayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelOnUnsubscribeEventType') }, + ], + false + ), + PrivateChannelOnUnsubscribeEventPayload: o( + [ + { json: 'contextType', js: 'contextType', typ: u(null, '') }, + { json: 'privateChannelId', js: 'privateChannelId', typ: '' }, + ], + false + ), + PrivateChannelUnsubscribeEventListenerRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('PrivateChannelUnsubscribeEventListenerRequestPayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelUnsubscribeEventListenerRequestType') }, + ], + false + ), + PrivateChannelUnsubscribeEventListenerRequestPayload: o( + [{ json: 'listenerUUID', js: 'listenerUUID', typ: '' }], + false + ), + PrivateChannelUnsubscribeEventListenerResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('BroadcastResponseResponsePayload') }, + { json: 'type', js: 'type', typ: r('PrivateChannelUnsubscribeEventListenerResponseType') }, + ], + false + ), + RaiseIntentForContextRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentForContextRequestPayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentForContextRequestType') }, + ], + false + ), + RaiseIntentForContextRequestPayload: o( + [ + { json: 'app', js: 'app', typ: u(undefined, r('AppIdentifier')) }, + { json: 'context', js: 'context', typ: r('Context') }, + ], + false + ), + RaiseIntentForContextResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentForContextResponsePayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentForContextResponseType') }, + ], + false + ), + RaiseIntentForContextResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FindInstancesErrors')) }, + { json: 'intentResolution', js: 'intentResolution', typ: u(undefined, r('IntentResolution')) }, + { json: 'appIntents', js: 'appIntents', typ: u(undefined, a(r('AppIntent'))) }, + ], + false + ), + IntentResolution: o( + [ + { json: 'intent', js: 'intent', typ: '' }, + { json: 'source', js: 'source', typ: r('AppIdentifier') }, + ], + false + ), + RaiseIntentRequest: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentRequestPayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentRequestType') }, + ], + false + ), + RaiseIntentRequestPayload: o( + [ + { json: 'app', js: 'app', typ: u(undefined, r('AppIdentifier')) }, + { json: 'context', js: 'context', typ: r('Context') }, + { json: 'intent', js: 'intent', typ: '' }, + ], + false + ), + RaiseIntentResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentResponsePayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentResponseType') }, + ], + false + ), + RaiseIntentResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('FindInstancesErrors')) }, + { json: 'intentResolution', js: 'intentResolution', typ: u(undefined, r('IntentResolution')) }, + { json: 'appIntent', js: 'appIntent', typ: u(undefined, r('AppIntent')) }, + ], + false + ), + RaiseIntentResultResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentResultResponsePayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentResultResponseType') }, + ], + false + ), + RaiseIntentResultResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, + { json: 'intentResult', js: 'intentResult', typ: u(undefined, r('IntentResult')) }, + ], + false + ), + WebConnectionProtocol1HelloType: ['WCP1Hello'], + WebConnectionProtocol2LoadURLType: ['WCP2LoadUrl'], + WebConnectionProtocol3HandshakeType: ['WCP3Handshake'], + WebConnectionProtocol4ValidateAppIdentityType: ['WCP4ValidateAppIdentity'], + WebConnectionProtocol5ValidateAppIdentityFailedResponseType: ['WCP5ValidateAppIdentityFailedResponse'], + WebConnectionProtocol5ValidateAppIdentitySuccessResponseType: ['WCP5ValidateAppIdentityResponse'], + WebConnectionProtocol6GoodbyeType: ['WCP6Goodbye'], + ConnectionStepMessageType: [ + 'WCP1Hello', + 'WCP2LoadUrl', + 'WCP3Handshake', + 'WCP4ValidateAppIdentity', + 'WCP5ValidateAppIdentityFailedResponse', + 'WCP5ValidateAppIdentityResponse', + 'WCP6Goodbye', + ], + AddContextListenerRequestType: ['addContextListenerRequest'], + PurpleError: ['AccessDenied', 'CreationFailed', 'MalformedContext', 'NoChannelFound'], + AddContextListenerResponseType: ['addContextListenerResponse'], + FDC3EventType: ['USER_CHANNEL_CHANGED'], + AddEventListenerRequestType: ['addEventListenerRequest'], + ResponsePayloadError: [ + 'AccessDenied', + 'AgentDisconnected', + 'AppNotFound', + 'AppTimeout', + 'CreationFailed', + 'DesktopAgentNotFound', + 'ErrorOnLaunch', + 'IntentDeliveryFailed', + 'IntentHandlerRejected', + 'MalformedContext', + 'MalformedMessage', + 'NoAppsFound', + 'NoChannelFound', + 'NoResultReturned', + 'NotConnectedToBridge', + 'ResolverTimeout', + 'ResolverUnavailable', + 'ResponseToBridgeTimedOut', + 'TargetAppUnavailable', + 'TargetInstanceUnavailable', + 'UserCancelledResolution', + ], + AddEventListenerResponseType: ['addEventListenerResponse'], + AddIntentListenerRequestType: ['addIntentListenerRequest'], + FluffyError: [ + 'DesktopAgentNotFound', + 'IntentDeliveryFailed', + 'MalformedContext', + 'NoAppsFound', + 'ResolverTimeout', + 'ResolverUnavailable', + 'TargetAppUnavailable', + 'TargetInstanceUnavailable', + 'UserCancelledResolution', + ], + AddIntentListenerResponseType: ['addIntentListenerResponse'], + EventMessageType: [ + 'addEventListenerEvent', + 'broadcastEvent', + 'channelChangedEvent', + 'heartbeatEvent', + 'intentEvent', + 'privateChannelOnAddContextListenerEvent', + 'privateChannelOnDisconnectEvent', + 'privateChannelOnUnsubscribeEvent', + ], + ResponseMessageType: [ + 'addContextListenerResponse', + 'addEventListenerResponse', + 'addIntentListenerResponse', + 'broadcastResponse', + 'contextListenerUnsubscribeResponse', + 'createPrivateChannelResponse', + 'eventListenerUnsubscribeResponse', + 'findInstancesResponse', + 'findIntentResponse', + 'findIntentsByContextResponse', + 'getAppMetadataResponse', + 'getCurrentChannelResponse', + 'getCurrentContextResponse', + 'getInfoResponse', + 'getOrCreateChannelResponse', + 'getUserChannelsResponse', + 'intentListenerUnsubscribeResponse', + 'intentResultResponse', + 'joinUserChannelResponse', + 'leaveCurrentChannelResponse', + 'openResponse', + 'privateChannelAddEventListenerResponse', + 'privateChannelDisconnectResponse', + 'privateChannelUnsubscribeEventListenerResponse', + 'raiseIntentForContextResponse', + 'raiseIntentResponse', + 'raiseIntentResultResponse', + ], + RequestMessageType: [ + 'addContextListenerRequest', + 'addEventListenerRequest', + 'addIntentListenerRequest', + 'broadcastRequest', + 'contextListenerUnsubscribeRequest', + 'createPrivateChannelRequest', + 'eventListenerUnsubscribeRequest', + 'findInstancesRequest', + 'findIntentRequest', + 'findIntentsByContextRequest', + 'getAppMetadataRequest', + 'getCurrentChannelRequest', + 'getCurrentContextRequest', + 'getInfoRequest', + 'getOrCreateChannelRequest', + 'getUserChannelsRequest', + 'heartbeatAcknowledgementRequest', + 'intentListenerUnsubscribeRequest', + 'intentResultRequest', + 'joinUserChannelRequest', + 'leaveCurrentChannelRequest', + 'openRequest', + 'privateChannelAddEventListenerRequest', + 'privateChannelDisconnectRequest', + 'privateChannelUnsubscribeEventListenerRequest', + 'raiseIntentForContextRequest', + 'raiseIntentRequest', + ], + BroadcastEventType: ['broadcastEvent'], + BroadcastRequestType: ['broadcastRequest'], + BroadcastResponseType: ['broadcastResponse'], + ChannelChangedEventType: ['channelChangedEvent'], + ContextListenerUnsubscribeRequestType: ['contextListenerUnsubscribeRequest'], + ContextListenerUnsubscribeResponseType: ['contextListenerUnsubscribeResponse'], + CreatePrivateChannelRequestType: ['createPrivateChannelRequest'], + Type: ['app', 'private', 'user'], + CreatePrivateChannelResponseType: ['createPrivateChannelResponse'], + EventListenerUnsubscribeRequestType: ['eventListenerUnsubscribeRequest'], + EventListenerUnsubscribeResponseType: ['eventListenerUnsubscribeResponse'], + Fdc3UserInterfaceChannelSelectedType: ['Fdc3UserInterfaceChannelSelected'], + Fdc3UserInterfaceChannelsType: ['Fdc3UserInterfaceChannels'], + Fdc3UserInterfaceDragType: ['Fdc3UserInterfaceDrag'], + Fdc3UserInterfaceHandshakeType: ['Fdc3UserInterfaceHandshake'], + Fdc3UserInterfaceHelloType: ['Fdc3UserInterfaceHello'], + Fdc3UserInterfaceMessageType: [ + 'Fdc3UserInterfaceChannelSelected', + 'Fdc3UserInterfaceChannels', + 'Fdc3UserInterfaceDrag', + 'Fdc3UserInterfaceHandshake', + 'Fdc3UserInterfaceHello', + 'Fdc3UserInterfaceResolve', + 'Fdc3UserInterfaceResolveAction', + 'Fdc3UserInterfaceRestyle', + ], + Fdc3UserInterfaceResolveType: ['Fdc3UserInterfaceResolve'], + Action: ['cancel', 'click', 'hover'], + Fdc3UserInterfaceResolveActionType: ['Fdc3UserInterfaceResolveAction'], + Fdc3UserInterfaceRestyleType: ['Fdc3UserInterfaceRestyle'], + FindInstancesRequestType: ['findInstancesRequest'], + FindInstancesErrors: [ + 'AgentDisconnected', + 'DesktopAgentNotFound', + 'IntentDeliveryFailed', + 'MalformedContext', + 'MalformedMessage', + 'NoAppsFound', + 'NotConnectedToBridge', + 'ResolverTimeout', + 'ResolverUnavailable', + 'ResponseToBridgeTimedOut', + 'TargetAppUnavailable', + 'TargetInstanceUnavailable', + 'UserCancelledResolution', + ], + FindInstancesResponseType: ['findInstancesResponse'], + FindIntentRequestType: ['findIntentRequest'], + FindIntentResponseType: ['findIntentResponse'], + FindIntentsByContextRequestType: ['findIntentsByContextRequest'], + FindIntentsByContextResponseType: ['findIntentsByContextResponse'], + GetAppMetadataRequestType: ['getAppMetadataRequest'], + GetAppMetadataResponseType: ['getAppMetadataResponse'], + GetCurrentChannelRequestType: ['getCurrentChannelRequest'], + GetCurrentChannelResponseType: ['getCurrentChannelResponse'], + GetCurrentContextRequestType: ['getCurrentContextRequest'], + GetCurrentContextResponseType: ['getCurrentContextResponse'], + GetInfoRequestType: ['getInfoRequest'], + GetInfoResponseType: ['getInfoResponse'], + GetOrCreateChannelRequestType: ['getOrCreateChannelRequest'], + GetOrCreateChannelResponseType: ['getOrCreateChannelResponse'], + GetUserChannelsRequestType: ['getUserChannelsRequest'], + GetUserChannelsResponseType: ['getUserChannelsResponse'], + HeartbeatAcknowledgementRequestType: ['heartbeatAcknowledgementRequest'], + HeartbeatEventType: ['heartbeatEvent'], + IntentEventType: ['intentEvent'], + IntentListenerUnsubscribeRequestType: ['intentListenerUnsubscribeRequest'], + IntentListenerUnsubscribeResponseType: ['intentListenerUnsubscribeResponse'], + IntentResultRequestType: ['intentResultRequest'], + IntentResultResponseType: ['intentResultResponse'], + JoinUserChannelRequestType: ['joinUserChannelRequest'], + JoinUserChannelResponseType: ['joinUserChannelResponse'], + LeaveCurrentChannelRequestType: ['leaveCurrentChannelRequest'], + LeaveCurrentChannelResponseType: ['leaveCurrentChannelResponse'], + OpenRequestType: ['openRequest'], + OpenErrorResponsePayload: [ + 'AgentDisconnected', + 'AppNotFound', + 'AppTimeout', + 'DesktopAgentNotFound', + 'ErrorOnLaunch', + 'MalformedContext', + 'MalformedMessage', + 'NotConnectedToBridge', + 'ResolverUnavailable', + 'ResponseToBridgeTimedOut', + ], + OpenResponseType: ['openResponse'], + PrivateChannelEventType: ['addContextListener', 'disconnect', 'unsubscribe'], + PrivateChannelAddEventListenerRequestType: ['privateChannelAddEventListenerRequest'], + PrivateChannelAddEventListenerResponseType: ['privateChannelAddEventListenerResponse'], + PrivateChannelDisconnectRequestType: ['privateChannelDisconnectRequest'], + PrivateChannelDisconnectResponseType: ['privateChannelDisconnectResponse'], + PrivateChannelOnAddContextListenerEventType: ['privateChannelOnAddContextListenerEvent'], + PrivateChannelOnDisconnectEventType: ['privateChannelOnDisconnectEvent'], + PrivateChannelOnUnsubscribeEventType: ['privateChannelOnUnsubscribeEvent'], + PrivateChannelUnsubscribeEventListenerRequestType: ['privateChannelUnsubscribeEventListenerRequest'], + PrivateChannelUnsubscribeEventListenerResponseType: ['privateChannelUnsubscribeEventListenerResponse'], + RaiseIntentForContextRequestType: ['raiseIntentForContextRequest'], + RaiseIntentForContextResponseType: ['raiseIntentForContextResponse'], + RaiseIntentRequestType: ['raiseIntentRequest'], + RaiseIntentResponseType: ['raiseIntentResponse'], + RaiseIntentResultResponseType: ['raiseIntentResultResponse'], +}; - public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { - return cast(JSON.parse(json), r("WebConnectionProtocolMessage")); - } +export type AppRequestMessage = + | AddContextListenerRequest + | AddEventListenerRequest + | AddIntentListenerRequest + | BroadcastRequest + | ContextListenerUnsubscribeRequest + | CreatePrivateChannelRequest + | EventListenerUnsubscribeRequest + | FindInstancesRequest + | FindIntentRequest + | FindIntentsByContextRequest + | GetAppMetadataRequest + | GetCurrentChannelRequest + | GetCurrentContextRequest + | GetInfoRequest + | GetOrCreateChannelRequest + | GetUserChannelsRequest + | HeartbeatAcknowledgementRequest + | IntentListenerUnsubscribeRequest + | IntentResultRequest + | JoinUserChannelRequest + | LeaveCurrentChannelRequest + | OpenRequest + | PrivateChannelAddEventListenerRequest + | PrivateChannelDisconnectRequest + | PrivateChannelUnsubscribeEventListenerRequest + | RaiseIntentForContextRequest + | RaiseIntentRequest; + +export type AgentResponseMessage = + | AddContextListenerResponse + | AddEventListenerResponse + | AddIntentListenerResponse + | BroadcastResponse + | ContextListenerUnsubscribeResponse + | CreatePrivateChannelResponse + | EventListenerUnsubscribeResponse + | FindInstancesResponse + | FindIntentResponse + | FindIntentsByContextResponse + | GetAppMetadataResponse + | GetCurrentChannelResponse + | GetCurrentContextResponse + | GetInfoResponse + | GetOrCreateChannelResponse + | GetUserChannelsResponse + | IntentListenerUnsubscribeResponse + | IntentResultResponse + | JoinUserChannelResponse + | LeaveCurrentChannelResponse + | OpenResponse + | PrivateChannelAddEventListenerResponse + | PrivateChannelDisconnectResponse + | PrivateChannelUnsubscribeEventListenerResponse + | RaiseIntentForContextResponse + | RaiseIntentResponse + | RaiseIntentResultResponse; + +export type AgentEventMessage = + | BroadcastEvent + | ChannelChangedEvent + | HeartbeatEvent + | IntentEvent + | PrivateChannelOnAddContextListenerEvent + | PrivateChannelOnDisconnectEvent + | PrivateChannelOnUnsubscribeEvent; - public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { - return JSON.stringify(uncast(value, r("WebConnectionProtocolMessage")), null, 2); - } +/** + * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + return value != null && value.type === 'WCP1Hello'; } -function invalidValue(typ: any, val: any, key: any, parent: any = ''): never { - const prettyTyp = prettyTypeName(typ); - const parentText = parent ? ` on ${parent}` : ''; - const keyText = key ? ` for key "${key}"` : ''; - throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`); +/** + * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + try { + Convert.webConnectionProtocol1HelloToJson(value); + return true; + } catch (_e: any) { + return false; + } } -function prettyTypeName(typ: any): string { - if (Array.isArray(typ)) { - if (typ.length === 2 && typ[0] === undefined) { - return `an optional ${prettyTypeName(typ[1])}`; - } else { - return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`; - } - } else if (typeof typ === "object" && typ.literal !== undefined) { - return typ.literal; - } else { - return typeof typ; - } -} +export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = 'WebConnectionProtocol1Hello'; -function jsonToJSProps(typ: any): any { - if (typ.jsonToJS === undefined) { - const map: any = {}; - typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); - typ.jsonToJS = map; - } - return typ.jsonToJS; +/** + * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + return value != null && value.type === 'WCP2LoadUrl'; } -function jsToJSONProps(typ: any): any { - if (typ.jsToJSON === undefined) { - const map: any = {}; - typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); - typ.jsToJSON = map; - } - return typ.jsToJSON; +/** + * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + try { + Convert.webConnectionProtocol2LoadURLToJson(value); + return true; + } catch (_e: any) { + return false; + } } -function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any { - function transformPrimitive(typ: string, val: any): any { - if (typeof typ === typeof val) return val; - return invalidValue(typ, val, key, parent); - } - - function transformUnion(typs: any[], val: any): any { - // val must validate against one typ in typs - const l = typs.length; - for (let i = 0; i < l; i++) { - const typ = typs[i]; - try { - return transform(val, typ, getProps); - } catch (_) { } - } - return invalidValue(typs, val, key, parent); - } - - function transformEnum(cases: string[], val: any): any { - if (cases.indexOf(val) !== -1) return val; - return invalidValue(cases.map(a => { return l(a); }), val, key, parent); - } +export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = 'WebConnectionProtocol2LoadURL'; - function transformArray(typ: any, val: any): any { - // val must be an array with no invalid elements - if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent); - return val.map(el => transform(el, typ, getProps)); - } +/** + * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + return value != null && value.type === 'WCP3Handshake'; +} - function transformDate(val: any): any { - if (val === null) { - return null; - } - const d = new Date(val); - if (isNaN(d.valueOf())) { - return invalidValue(l("Date"), val, key, parent); - } - return d; - } +/** + * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + try { + Convert.webConnectionProtocol3HandshakeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} - function transformObject(props: { [k: string]: any }, additional: any, val: any): any { - if (val === null || typeof val !== "object" || Array.isArray(val)) { - return invalidValue(l(ref || "object"), val, key, parent); - } - const result: any = {}; - Object.getOwnPropertyNames(props).forEach(key => { - const prop = props[key]; - const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; - result[prop.key] = transform(v, prop.typ, getProps, key, ref); - }); - Object.getOwnPropertyNames(val).forEach(key => { - if (!Object.prototype.hasOwnProperty.call(props, key)) { - result[key] = transform(val[key], additional, getProps, key, ref); - } - }); - return result; - } +export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = 'WebConnectionProtocol3Handshake'; - if (typ === "any") return val; - if (typ === null) { - if (val === null) return val; - return invalidValue(typ, val, key, parent); - } - if (typ === false) return invalidValue(typ, val, key, parent); - let ref: any = undefined; - while (typeof typ === "object" && typ.ref !== undefined) { - ref = typ.ref; - typ = typeMap[typ.ref]; - } - if (Array.isArray(typ)) return transformEnum(typ, val); - if (typeof typ === "object") { - return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) - : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) - : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) - : invalidValue(typ, val, key, parent); - } - // Numbers can be parsed by Date but shouldn't be. - if (typ === Date && typeof val !== "number") return transformDate(val); - return transformPrimitive(typ, val); +/** + * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol4ValidateAppIdentity( + value: any +): value is WebConnectionProtocol4ValidateAppIdentity { + return value != null && value.type === 'WCP4ValidateAppIdentity'; } -function cast(val: any, typ: any): T { - return transform(val, typ, jsonToJSProps); +/** + * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol4ValidateAppIdentity( + value: any +): value is WebConnectionProtocol4ValidateAppIdentity { + try { + Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); + return true; + } catch (_e: any) { + return false; + } } -function uncast(val: T, typ: any): any { - return transform(val, typ, jsToJSONProps); -} +export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = 'WebConnectionProtocol4ValidateAppIdentity'; -function l(typ: any) { - return { literal: typ }; +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; } -function a(typ: any) { - return { arrayItems: typ }; +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -function u(...typs: any[]) { - return { unionMembers: typs }; +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = + 'WebConnectionProtocol5ValidateAppIdentityFailedResponse'; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; } -function o(props: any[], additional: any) { - return { props, additional }; +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -function m(additional: any) { - return { props: [], additional }; +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = + 'WebConnectionProtocol5ValidateAppIdentitySuccessResponse'; + +/** + * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + return value != null && value.type === 'WCP6Goodbye'; } -function r(name: string) { - return { ref: name }; +/** + * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + try { + Convert.webConnectionProtocol6GoodbyeToJson(value); + return true; + } catch (_e: any) { + return false; + } } -const typeMap: any = { - "AddContextListenerRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("AddContextListenerRequestPayload") }, - { json: "type", js: "type", typ: r("AddContextListenerRequestType") }, - ], false), - "AddContextListenerRequestMeta": o([ - { json: "requestUuid", js: "requestUuid", typ: "" }, - { json: "source", js: "source", typ: u(undefined, r("AppIdentifier")) }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "AppIdentifier": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - ], "any"), - "AddContextListenerRequestPayload": o([ - { json: "channelId", js: "channelId", typ: u(null, "") }, - { json: "contextType", js: "contextType", typ: u(null, "") }, - ], false), - "AddContextListenerResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("AddContextListenerResponsePayload") }, - { json: "type", js: "type", typ: r("AddContextListenerResponseType") }, - ], false), - "AddContextListenerResponseMeta": o([ - { json: "requestUuid", js: "requestUuid", typ: "" }, - { json: "responseUuid", js: "responseUuid", typ: "" }, - { json: "source", js: "source", typ: u(undefined, r("AppIdentifier")) }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "AddContextListenerResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - { json: "listenerUUID", js: "listenerUUID", typ: u(undefined, "") }, - ], false), - "AddEventListenerRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("AddEventListenerRequestPayload") }, - { json: "type", js: "type", typ: r("AddEventListenerRequestType") }, - ], false), - "AddEventListenerRequestPayload": o([ - { json: "type", js: "type", typ: u(r("FDC3EventType"), null) }, - ], false), - "AddEventListenerResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("AddEventListenerResponsePayload") }, - { json: "type", js: "type", typ: r("AddEventListenerResponseType") }, - ], false), - "AddEventListenerResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - { json: "listenerUUID", js: "listenerUUID", typ: u(undefined, "") }, - ], false), - "AddIntentListenerRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("AddIntentListenerRequestPayload") }, - { json: "type", js: "type", typ: r("AddIntentListenerRequestType") }, - ], false), - "AddIntentListenerRequestPayload": o([ - { json: "intent", js: "intent", typ: "" }, - ], false), - "AddIntentListenerResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("PayloadObject") }, - { json: "type", js: "type", typ: r("AddIntentListenerResponseType") }, - ], false), - "PayloadObject": o([ - { json: "error", js: "error", typ: u(undefined, r("FluffyError")) }, - { json: "listenerUUID", js: "listenerUUID", typ: u(undefined, "") }, - ], "any"), - "AgentEventMessage": o([ - { json: "meta", js: "meta", typ: r("AgentEventMessageMeta") }, - { json: "payload", js: "payload", typ: m("any") }, - { json: "type", js: "type", typ: r("EventMessageType") }, - ], false), - "AgentEventMessageMeta": o([ - { json: "eventUuid", js: "eventUuid", typ: "" }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "AgentResponseMessage": o([ - { json: "meta", js: "meta", typ: r("AgentResponseMessageMeta") }, - { json: "payload", js: "payload", typ: r("AgentResponseMessageResponsePayload") }, - { json: "type", js: "type", typ: r("ResponseMessageType") }, - ], false), - "AgentResponseMessageMeta": o([ - { json: "requestUuid", js: "requestUuid", typ: "" }, - { json: "responseUuid", js: "responseUuid", typ: "" }, - { json: "source", js: "source", typ: u(undefined, r("AppIdentifier")) }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "AgentResponseMessageResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - ], "any"), - "AppRequestMessage": o([ - { json: "meta", js: "meta", typ: r("AppRequestMessageMeta") }, - { json: "payload", js: "payload", typ: m("any") }, - { json: "type", js: "type", typ: r("RequestMessageType") }, - ], false), - "AppRequestMessageMeta": o([ - { json: "requestUuid", js: "requestUuid", typ: "" }, - { json: "source", js: "source", typ: u(undefined, r("AppIdentifier")) }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "BroadcastEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastEventPayload") }, - { json: "type", js: "type", typ: r("BroadcastEventType") }, - ], false), - "BroadcastEventMeta": o([ - { json: "eventUuid", js: "eventUuid", typ: "" }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "BroadcastEventPayload": o([ - { json: "channelId", js: "channelId", typ: u(null, "") }, - { json: "context", js: "context", typ: r("Context") }, - { json: "originatingApp", js: "originatingApp", typ: u(undefined, r("AppIdentifier")) }, - ], false), - "Context": o([ - { json: "id", js: "id", typ: u(undefined, m("any")) }, - { json: "name", js: "name", typ: u(undefined, "") }, - { json: "type", js: "type", typ: "" }, - ], "any"), - "BroadcastRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastRequestPayload") }, - { json: "type", js: "type", typ: r("BroadcastRequestType") }, - ], false), - "BroadcastRequestPayload": o([ - { json: "channelId", js: "channelId", typ: "" }, - { json: "context", js: "context", typ: r("Context") }, - ], false), - "BroadcastResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, - { json: "type", js: "type", typ: r("BroadcastResponseType") }, - ], false), - "BroadcastResponseResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - ], "any"), - "ChannelChangedEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("ChannelChangedEventPayload") }, - { json: "type", js: "type", typ: r("ChannelChangedEventType") }, - ], false), - "ChannelChangedEventPayload": o([ - { json: "newChannelId", js: "newChannelId", typ: u(null, "") }, - ], false), - "ContextListenerUnsubscribeRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("ContextListenerUnsubscribeRequestPayload") }, - { json: "type", js: "type", typ: r("ContextListenerUnsubscribeRequestType") }, - ], false), - "ContextListenerUnsubscribeRequestPayload": o([ - { json: "listenerUUID", js: "listenerUUID", typ: "" }, - ], false), - "ContextListenerUnsubscribeResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, - { json: "type", js: "type", typ: r("ContextListenerUnsubscribeResponseType") }, - ], false), - "CreatePrivateChannelRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("CreatePrivateChannelRequestPayload") }, - { json: "type", js: "type", typ: r("CreatePrivateChannelRequestType") }, - ], false), - "CreatePrivateChannelRequestPayload": o([ - ], false), - "CreatePrivateChannelResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("CreatePrivateChannelResponsePayload") }, - { json: "type", js: "type", typ: r("CreatePrivateChannelResponseType") }, - ], false), - "CreatePrivateChannelResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - { json: "privateChannel", js: "privateChannel", typ: u(undefined, r("Channel")) }, - ], false), - "Channel": o([ - { json: "displayMetadata", js: "displayMetadata", typ: u(undefined, r("DisplayMetadata")) }, - { json: "id", js: "id", typ: "" }, - { json: "type", js: "type", typ: r("Type") }, - ], false), - "DisplayMetadata": o([ - { json: "color", js: "color", typ: u(undefined, "") }, - { json: "glyph", js: "glyph", typ: u(undefined, "") }, - { json: "name", js: "name", typ: u(undefined, "") }, - ], false), - "EventListenerUnsubscribeRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("EventListenerUnsubscribeRequestPayload") }, - { json: "type", js: "type", typ: r("EventListenerUnsubscribeRequestType") }, - ], false), - "EventListenerUnsubscribeRequestPayload": o([ - { json: "listenerUUID", js: "listenerUUID", typ: "" }, - ], false), - "EventListenerUnsubscribeResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, - { json: "type", js: "type", typ: r("EventListenerUnsubscribeResponseType") }, - ], false), - "Fdc3UserInterfaceChannels": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelsPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelsType") }, - ], false), - "Fdc3UserInterfaceChannelsPayload": o([ - { json: "selected", js: "selected", typ: u(null, "") }, - { json: "userChannels", js: "userChannels", typ: a(r("Channel")) }, - ], false), - "Fdc3UserInterfaceChannelSelected": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceChannelSelectedPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceChannelSelectedType") }, - ], false), - "Fdc3UserInterfaceChannelSelectedPayload": o([ - { json: "selected", js: "selected", typ: u(null, "") }, - ], false), - "Fdc3UserInterfaceDrag": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceDragPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceDragType") }, - ], false), - "Fdc3UserInterfaceDragPayload": o([ - { json: "mouseOffsets", js: "mouseOffsets", typ: r("MouseOffsets") }, - ], false), - "MouseOffsets": o([ - { json: "x", js: "x", typ: 0 }, - { json: "y", js: "y", typ: 0 }, - ], false), - "Fdc3UserInterfaceHandshake": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceHandshakePayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceHandshakeType") }, - ], false), - "Fdc3UserInterfaceHandshakePayload": o([ - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - ], false), - "Fdc3UserInterfaceHello": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceHelloPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceHelloType") }, - ], false), - "Fdc3UserInterfaceHelloPayload": o([ - { json: "implementationDetails", js: "implementationDetails", typ: "" }, - { json: "initialCSS", js: "initialCSS", typ: r("InitialCSS") }, - ], false), - "InitialCSS": o([ - { json: "bottom", js: "bottom", typ: u(undefined, "") }, - { json: "height", js: "height", typ: u(undefined, "") }, - { json: "left", js: "left", typ: u(undefined, "") }, - { json: "maxHeight", js: "maxHeight", typ: u(undefined, "") }, - { json: "maxWidth", js: "maxWidth", typ: u(undefined, "") }, - { json: "right", js: "right", typ: u(undefined, "") }, - { json: "top", js: "top", typ: u(undefined, "") }, - { json: "transition", js: "transition", typ: u(undefined, "") }, - { json: "width", js: "width", typ: u(undefined, "") }, - { json: "zIndex", js: "zIndex", typ: u(undefined, "") }, - ], "any"), - "Fdc3UserInterfaceMessage": o([ - { json: "payload", js: "payload", typ: u(undefined, m("any")) }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceMessageType") }, - ], false), - "Fdc3UserInterfaceResolve": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceResolvePayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceResolveType") }, - ], false), - "Fdc3UserInterfaceResolvePayload": o([ - { json: "appIntents", js: "appIntents", typ: a(r("AppIntent")) }, - { json: "context", js: "context", typ: r("Context") }, - ], false), - "AppIntent": o([ - { json: "apps", js: "apps", typ: a(r("AppMetadata")) }, - { json: "intent", js: "intent", typ: r("IntentMetadata") }, - ], false), - "AppMetadata": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "description", js: "description", typ: u(undefined, "") }, - { json: "desktopAgent", js: "desktopAgent", typ: u(undefined, "") }, - { json: "icons", js: "icons", typ: u(undefined, a(r("Icon"))) }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - { json: "instanceMetadata", js: "instanceMetadata", typ: u(undefined, m("any")) }, - { json: "name", js: "name", typ: u(undefined, "") }, - { json: "resultType", js: "resultType", typ: u(undefined, u(null, "")) }, - { json: "screenshots", js: "screenshots", typ: u(undefined, a(r("Image"))) }, - { json: "title", js: "title", typ: u(undefined, "") }, - { json: "tooltip", js: "tooltip", typ: u(undefined, "") }, - { json: "version", js: "version", typ: u(undefined, "") }, - ], false), - "Icon": o([ - { json: "size", js: "size", typ: u(undefined, "") }, - { json: "src", js: "src", typ: "" }, - { json: "type", js: "type", typ: u(undefined, "") }, - ], false), - "Image": o([ - { json: "label", js: "label", typ: u(undefined, "") }, - { json: "size", js: "size", typ: u(undefined, "") }, - { json: "src", js: "src", typ: "" }, - { json: "type", js: "type", typ: u(undefined, "") }, - ], false), - "IntentMetadata": o([ - { json: "displayName", js: "displayName", typ: u(undefined, "") }, - { json: "name", js: "name", typ: "" }, - ], false), - "Fdc3UserInterfaceResolveAction": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceResolveActionPayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceResolveActionType") }, - ], false), - "Fdc3UserInterfaceResolveActionPayload": o([ - { json: "action", js: "action", typ: r("Action") }, - { json: "appIdentifier", js: "appIdentifier", typ: u(undefined, r("AppIdentifier")) }, - { json: "intent", js: "intent", typ: u(undefined, "") }, - ], false), - "Fdc3UserInterfaceRestyle": o([ - { json: "payload", js: "payload", typ: r("Fdc3UserInterfaceRestylePayload") }, - { json: "type", js: "type", typ: r("Fdc3UserInterfaceRestyleType") }, - ], false), - "Fdc3UserInterfaceRestylePayload": o([ - { json: "updatedCSS", js: "updatedCSS", typ: r("UpdatedCSS") }, - ], false), - "UpdatedCSS": o([ - { json: "bottom", js: "bottom", typ: u(undefined, "") }, - { json: "height", js: "height", typ: u(undefined, "") }, - { json: "left", js: "left", typ: u(undefined, "") }, - { json: "maxHeight", js: "maxHeight", typ: u(undefined, "") }, - { json: "maxWidth", js: "maxWidth", typ: u(undefined, "") }, - { json: "right", js: "right", typ: u(undefined, "") }, - { json: "top", js: "top", typ: u(undefined, "") }, - { json: "transition", js: "transition", typ: u(undefined, "") }, - { json: "width", js: "width", typ: u(undefined, "") }, - { json: "zIndex", js: "zIndex", typ: u(undefined, "") }, - ], "any"), - "FindInstancesRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("FindInstancesRequestPayload") }, - { json: "type", js: "type", typ: r("FindInstancesRequestType") }, - ], false), - "FindInstancesRequestPayload": o([ - { json: "app", js: "app", typ: r("AppIdentifier") }, - ], false), - "FindInstancesResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("FindInstancesResponsePayload") }, - { json: "type", js: "type", typ: r("FindInstancesResponseType") }, - ], false), - "FindInstancesResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "appIdentifiers", js: "appIdentifiers", typ: u(undefined, a(r("AppMetadata"))) }, - ], false), - "FindIntentRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("FindIntentRequestPayload") }, - { json: "type", js: "type", typ: r("FindIntentRequestType") }, - ], false), - "FindIntentRequestPayload": o([ - { json: "context", js: "context", typ: u(undefined, r("Context")) }, - { json: "intent", js: "intent", typ: "" }, - { json: "resultType", js: "resultType", typ: u(undefined, "") }, - ], false), - "FindIntentResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("FindIntentResponsePayload") }, - { json: "type", js: "type", typ: r("FindIntentResponseType") }, - ], false), - "FindIntentResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "appIntent", js: "appIntent", typ: u(undefined, r("AppIntent")) }, - ], false), - "FindIntentsByContextRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("FindIntentsByContextRequestPayload") }, - { json: "type", js: "type", typ: r("FindIntentsByContextRequestType") }, - ], false), - "FindIntentsByContextRequestPayload": o([ - { json: "context", js: "context", typ: r("Context") }, - { json: "resultType", js: "resultType", typ: u(undefined, "") }, - ], false), - "FindIntentsByContextResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("FindIntentsByContextResponsePayload") }, - { json: "type", js: "type", typ: r("FindIntentsByContextResponseType") }, - ], false), - "FindIntentsByContextResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "appIntents", js: "appIntents", typ: u(undefined, a(r("AppIntent"))) }, - ], false), - "GetAppMetadataRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("GetAppMetadataRequestPayload") }, - { json: "type", js: "type", typ: r("GetAppMetadataRequestType") }, - ], false), - "GetAppMetadataRequestPayload": o([ - { json: "app", js: "app", typ: r("AppIdentifier") }, - ], false), - "GetAppMetadataResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("GetAppMetadataResponsePayload") }, - { json: "type", js: "type", typ: r("GetAppMetadataResponseType") }, - ], false), - "GetAppMetadataResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "appMetadata", js: "appMetadata", typ: u(undefined, r("AppMetadata")) }, - ], false), - "GetCurrentChannelRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("GetCurrentChannelRequestPayload") }, - { json: "type", js: "type", typ: r("GetCurrentChannelRequestType") }, - ], false), - "GetCurrentChannelRequestPayload": o([ - ], false), - "GetCurrentChannelResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("GetCurrentChannelResponsePayload") }, - { json: "type", js: "type", typ: r("GetCurrentChannelResponseType") }, - ], false), - "GetCurrentChannelResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - { json: "channel", js: "channel", typ: u(undefined, u(r("Channel"), null)) }, - ], false), - "GetCurrentContextRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("GetCurrentContextRequestPayload") }, - { json: "type", js: "type", typ: r("GetCurrentContextRequestType") }, - ], false), - "GetCurrentContextRequestPayload": o([ - { json: "channelId", js: "channelId", typ: "" }, - { json: "contextType", js: "contextType", typ: u(null, "") }, - ], false), - "GetCurrentContextResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("GetCurrentContextResponsePayload") }, - { json: "type", js: "type", typ: r("GetCurrentContextResponseType") }, - ], false), - "GetCurrentContextResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - { json: "context", js: "context", typ: u(undefined, u(null, r("Context"))) }, - ], false), - "GetInfoRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("GetInfoRequestPayload") }, - { json: "type", js: "type", typ: r("GetInfoRequestType") }, - ], false), - "GetInfoRequestPayload": o([ - ], false), - "GetInfoResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("GetInfoResponsePayload") }, - { json: "type", js: "type", typ: r("GetInfoResponseType") }, - ], false), - "GetInfoResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - { json: "implementationMetadata", js: "implementationMetadata", typ: u(undefined, r("ImplementationMetadata")) }, - ], false), - "ImplementationMetadata": o([ - { json: "appMetadata", js: "appMetadata", typ: r("AppMetadata") }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "optionalFeatures", js: "optionalFeatures", typ: r("OptionalFeatures") }, - { json: "provider", js: "provider", typ: "" }, - { json: "providerVersion", js: "providerVersion", typ: u(undefined, "") }, - ], false), - "OptionalFeatures": o([ - { json: "DesktopAgentBridging", js: "DesktopAgentBridging", typ: true }, - { json: "OriginatingAppMetadata", js: "OriginatingAppMetadata", typ: true }, - { json: "UserChannelMembershipAPIs", js: "UserChannelMembershipAPIs", typ: true }, - ], false), - "GetOrCreateChannelRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("GetOrCreateChannelRequestPayload") }, - { json: "type", js: "type", typ: r("GetOrCreateChannelRequestType") }, - ], false), - "GetOrCreateChannelRequestPayload": o([ - { json: "channelId", js: "channelId", typ: "" }, - ], false), - "GetOrCreateChannelResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("GetOrCreateChannelResponsePayload") }, - { json: "type", js: "type", typ: r("GetOrCreateChannelResponseType") }, - ], false), - "GetOrCreateChannelResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - { json: "channel", js: "channel", typ: u(undefined, r("Channel")) }, - ], false), - "GetUserChannelsRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("GetUserChannelsRequestPayload") }, - { json: "type", js: "type", typ: r("GetUserChannelsRequestType") }, - ], false), - "GetUserChannelsRequestPayload": o([ - ], false), - "GetUserChannelsResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("GetUserChannelsResponsePayload") }, - { json: "type", js: "type", typ: r("GetUserChannelsResponseType") }, - ], false), - "GetUserChannelsResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - { json: "userChannels", js: "userChannels", typ: u(undefined, a(r("Channel"))) }, - ], false), - "HeartbeatAcknowledgementRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("HeartbeatAcknowledgementRequestPayload") }, - { json: "type", js: "type", typ: r("HeartbeatAcknowledgementRequestType") }, - ], false), - "HeartbeatAcknowledgementRequestPayload": o([ - { json: "heartbeatEventUuid", js: "heartbeatEventUuid", typ: "" }, - ], false), - "HeartbeatEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("HeartbeatEventPayload") }, - { json: "type", js: "type", typ: r("HeartbeatEventType") }, - ], false), - "HeartbeatEventPayload": o([ - ], false), - "IntentEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("IntentEventPayload") }, - { json: "type", js: "type", typ: r("IntentEventType") }, - ], false), - "IntentEventPayload": o([ - { json: "context", js: "context", typ: r("Context") }, - { json: "intent", js: "intent", typ: "" }, - { json: "originatingApp", js: "originatingApp", typ: u(undefined, r("AppIdentifier")) }, - { json: "raiseIntentRequestUuid", js: "raiseIntentRequestUuid", typ: "" }, - ], false), - "IntentListenerUnsubscribeRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("IntentListenerUnsubscribeRequestPayload") }, - { json: "type", js: "type", typ: r("IntentListenerUnsubscribeRequestType") }, - ], false), - "IntentListenerUnsubscribeRequestPayload": o([ - { json: "listenerUUID", js: "listenerUUID", typ: "" }, - ], false), - "IntentListenerUnsubscribeResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, - { json: "type", js: "type", typ: r("IntentListenerUnsubscribeResponseType") }, - ], false), - "IntentResultRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("IntentResultRequestPayload") }, - { json: "type", js: "type", typ: r("IntentResultRequestType") }, - ], false), - "IntentResultRequestPayload": o([ - { json: "intentEventUuid", js: "intentEventUuid", typ: "" }, - { json: "intentResult", js: "intentResult", typ: r("IntentResult") }, - { json: "raiseIntentRequestUuid", js: "raiseIntentRequestUuid", typ: "" }, - ], false), - "IntentResult": o([ - { json: "context", js: "context", typ: u(undefined, r("Context")) }, - { json: "channel", js: "channel", typ: u(undefined, r("Channel")) }, - ], false), - "IntentResultResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, - { json: "type", js: "type", typ: r("IntentResultResponseType") }, - ], false), - "JoinUserChannelRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("JoinUserChannelRequestPayload") }, - { json: "type", js: "type", typ: r("JoinUserChannelRequestType") }, - ], false), - "JoinUserChannelRequestPayload": o([ - { json: "channelId", js: "channelId", typ: "" }, - ], false), - "JoinUserChannelResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("JoinUserChannelResponsePayload") }, - { json: "type", js: "type", typ: r("JoinUserChannelResponseType") }, - ], false), - "JoinUserChannelResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - ], false), - "LeaveCurrentChannelRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("LeaveCurrentChannelRequestPayload") }, - { json: "type", js: "type", typ: r("LeaveCurrentChannelRequestType") }, - ], false), - "LeaveCurrentChannelRequestPayload": o([ - ], false), - "LeaveCurrentChannelResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("LeaveCurrentChannelResponsePayload") }, - { json: "type", js: "type", typ: r("LeaveCurrentChannelResponseType") }, - ], false), - "LeaveCurrentChannelResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - ], false), - "OpenRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("OpenRequestPayload") }, - { json: "type", js: "type", typ: r("OpenRequestType") }, - ], false), - "OpenRequestPayload": o([ - { json: "app", js: "app", typ: r("AppIdentifier") }, - { json: "context", js: "context", typ: u(undefined, r("Context")) }, - ], false), - "OpenResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("OpenResponsePayload") }, - { json: "type", js: "type", typ: r("OpenResponseType") }, - ], false), - "OpenResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("OpenErrorResponsePayload")) }, - { json: "appIdentifier", js: "appIdentifier", typ: u(undefined, r("AppIdentifier")) }, - ], false), - "PrivateChannelAddEventListenerRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelAddEventListenerRequestPayload") }, - { json: "type", js: "type", typ: r("PrivateChannelAddEventListenerRequestType") }, - ], false), - "PrivateChannelAddEventListenerRequestPayload": o([ - { json: "listenerType", js: "listenerType", typ: u(r("PrivateChannelEventType"), null) }, - { json: "privateChannelId", js: "privateChannelId", typ: "" }, - ], false), - "PrivateChannelAddEventListenerResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelAddEventListenerResponsePayload") }, - { json: "type", js: "type", typ: r("PrivateChannelAddEventListenerResponseType") }, - ], false), - "PrivateChannelAddEventListenerResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - { json: "listenerUUID", js: "listenerUUID", typ: u(undefined, "") }, - ], false), - "PrivateChannelDisconnectRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelDisconnectRequestPayload") }, - { json: "type", js: "type", typ: r("PrivateChannelDisconnectRequestType") }, - ], false), - "PrivateChannelDisconnectRequestPayload": o([ - { json: "channelId", js: "channelId", typ: "" }, - ], false), - "PrivateChannelDisconnectResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelDisconnectResponsePayload") }, - { json: "type", js: "type", typ: r("PrivateChannelDisconnectResponseType") }, - ], false), - "PrivateChannelDisconnectResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("PurpleError")) }, - ], false), - "PrivateChannelOnAddContextListenerEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelOnAddContextListenerEventPayload") }, - { json: "type", js: "type", typ: r("PrivateChannelOnAddContextListenerEventType") }, - ], false), - "PrivateChannelOnAddContextListenerEventPayload": o([ - { json: "contextType", js: "contextType", typ: u(null, "") }, - { json: "privateChannelId", js: "privateChannelId", typ: "" }, - ], false), - "PrivateChannelOnDisconnectEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelOnDisconnectEventPayload") }, - { json: "type", js: "type", typ: r("PrivateChannelOnDisconnectEventType") }, - ], false), - "PrivateChannelOnDisconnectEventPayload": o([ - { json: "privateChannelId", js: "privateChannelId", typ: "" }, - ], false), - "PrivateChannelOnUnsubscribeEvent": o([ - { json: "meta", js: "meta", typ: r("BroadcastEventMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelOnUnsubscribeEventPayload") }, - { json: "type", js: "type", typ: r("PrivateChannelOnUnsubscribeEventType") }, - ], false), - "PrivateChannelOnUnsubscribeEventPayload": o([ - { json: "contextType", js: "contextType", typ: u(null, "") }, - { json: "privateChannelId", js: "privateChannelId", typ: "" }, - ], false), - "PrivateChannelUnsubscribeEventListenerRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("PrivateChannelUnsubscribeEventListenerRequestPayload") }, - { json: "type", js: "type", typ: r("PrivateChannelUnsubscribeEventListenerRequestType") }, - ], false), - "PrivateChannelUnsubscribeEventListenerRequestPayload": o([ - { json: "listenerUUID", js: "listenerUUID", typ: "" }, - ], false), - "PrivateChannelUnsubscribeEventListenerResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("BroadcastResponseResponsePayload") }, - { json: "type", js: "type", typ: r("PrivateChannelUnsubscribeEventListenerResponseType") }, - ], false), - "RaiseIntentForContextRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentForContextRequestPayload") }, - { json: "type", js: "type", typ: r("RaiseIntentForContextRequestType") }, - ], false), - "RaiseIntentForContextRequestPayload": o([ - { json: "app", js: "app", typ: u(undefined, r("AppIdentifier")) }, - { json: "context", js: "context", typ: r("Context") }, - ], false), - "RaiseIntentForContextResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentForContextResponsePayload") }, - { json: "type", js: "type", typ: r("RaiseIntentForContextResponseType") }, - ], false), - "RaiseIntentForContextResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "intentResolution", js: "intentResolution", typ: u(undefined, r("IntentResolution")) }, - { json: "appIntents", js: "appIntents", typ: u(undefined, a(r("AppIntent"))) }, - ], false), - "IntentResolution": o([ - { json: "intent", js: "intent", typ: "" }, - { json: "source", js: "source", typ: r("AppIdentifier") }, - ], false), - "RaiseIntentRequest": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerRequestMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentRequestPayload") }, - { json: "type", js: "type", typ: r("RaiseIntentRequestType") }, - ], false), - "RaiseIntentRequestPayload": o([ - { json: "app", js: "app", typ: u(undefined, r("AppIdentifier")) }, - { json: "context", js: "context", typ: r("Context") }, - { json: "intent", js: "intent", typ: "" }, - ], false), - "RaiseIntentResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentResponsePayload") }, - { json: "type", js: "type", typ: r("RaiseIntentResponseType") }, - ], false), - "RaiseIntentResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("FindInstancesErrors")) }, - { json: "intentResolution", js: "intentResolution", typ: u(undefined, r("IntentResolution")) }, - { json: "appIntent", js: "appIntent", typ: u(undefined, r("AppIntent")) }, - ], false), - "RaiseIntentResultResponse": o([ - { json: "meta", js: "meta", typ: r("AddContextListenerResponseMeta") }, - { json: "payload", js: "payload", typ: r("RaiseIntentResultResponsePayload") }, - { json: "type", js: "type", typ: r("RaiseIntentResultResponseType") }, - ], false), - "RaiseIntentResultResponsePayload": o([ - { json: "error", js: "error", typ: u(undefined, r("ResponsePayloadError")) }, - { json: "intentResult", js: "intentResult", typ: u(undefined, r("IntentResult")) }, - ], false), - "WebConnectionProtocol1Hello": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol1HelloPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol1HelloType") }, - ], false), - "WebConnectionProtocol1HelloMeta": o([ - { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: "" }, - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "WebConnectionProtocol1HelloPayload": o([ - { json: "actualUrl", js: "actualUrl", typ: "" }, - { json: "channelSelector", js: "channelSelector", typ: u(undefined, true) }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "identityUrl", js: "identityUrl", typ: "" }, - { json: "intentResolver", js: "intentResolver", typ: u(undefined, true) }, - ], "any"), - "WebConnectionProtocol2LoadURL": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol2LoadURLPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol2LoadURLType") }, - ], false), - "WebConnectionProtocol2LoadURLPayload": o([ - { json: "iframeUrl", js: "iframeUrl", typ: "" }, - ], "any"), - "WebConnectionProtocol3Handshake": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol3HandshakePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol3HandshakeType") }, - ], false), - "WebConnectionProtocol3HandshakePayload": o([ - { json: "channelSelectorUrl", js: "channelSelectorUrl", typ: u(true, "") }, - { json: "fdc3Version", js: "fdc3Version", typ: "" }, - { json: "intentResolverUrl", js: "intentResolverUrl", typ: u(true, "") }, - ], false), - "WebConnectionProtocol4ValidateAppIdentity": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol4ValidateAppIdentityPayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol4ValidateAppIdentityType") }, - ], false), - "WebConnectionProtocol4ValidateAppIdentityPayload": o([ - { json: "actualUrl", js: "actualUrl", typ: "" }, - { json: "identityUrl", js: "identityUrl", typ: "" }, - { json: "instanceId", js: "instanceId", typ: u(undefined, "") }, - { json: "instanceUuid", js: "instanceUuid", typ: u(undefined, "") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentityFailedResponse": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentityFailedResponseType") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload": o([ - { json: "message", js: "message", typ: u(undefined, "") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentitySuccessResponse": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol1HelloMeta") }, - { json: "payload", js: "payload", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol5ValidateAppIdentitySuccessResponseType") }, - ], false), - "WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload": o([ - { json: "appId", js: "appId", typ: "" }, - { json: "implementationMetadata", js: "implementationMetadata", typ: r("ImplementationMetadata") }, - { json: "instanceId", js: "instanceId", typ: "" }, - { json: "instanceUuid", js: "instanceUuid", typ: "" }, - ], false), - "WebConnectionProtocol6Goodbye": o([ - { json: "meta", js: "meta", typ: r("WebConnectionProtocol6GoodbyeMeta") }, - { json: "type", js: "type", typ: r("WebConnectionProtocol6GoodbyeType") }, - ], false), - "WebConnectionProtocol6GoodbyeMeta": o([ - { json: "timestamp", js: "timestamp", typ: Date }, - ], false), - "WebConnectionProtocolMessage": o([ - { json: "meta", js: "meta", typ: r("ConnectionStepMetadata") }, - { json: "payload", js: "payload", typ: u(undefined, m("any")) }, - { json: "type", js: "type", typ: r("ConnectionStepMessageType") }, - ], false), - "ConnectionStepMetadata": o([ - { json: "timestamp", js: "timestamp", typ: Date }, - { json: "connectionAttemptUuid", js: "connectionAttemptUuid", typ: u(undefined, "") }, - ], false), - "AddContextListenerRequestType": [ - "addContextListenerRequest", - ], - "PurpleError": [ - "AccessDenied", - "CreationFailed", - "MalformedContext", - "NoChannelFound", - ], - "AddContextListenerResponseType": [ - "addContextListenerResponse", - ], - "FDC3EventType": [ - "USER_CHANNEL_CHANGED", - ], - "AddEventListenerRequestType": [ - "addEventListenerRequest", - ], - "ResponsePayloadError": [ - "AccessDenied", - "AgentDisconnected", - "AppNotFound", - "AppTimeout", - "CreationFailed", - "DesktopAgentNotFound", - "ErrorOnLaunch", - "IntentDeliveryFailed", - "IntentHandlerRejected", - "MalformedContext", - "MalformedMessage", - "NoAppsFound", - "NoChannelFound", - "NoResultReturned", - "NotConnectedToBridge", - "ResolverTimeout", - "ResolverUnavailable", - "ResponseToBridgeTimedOut", - "TargetAppUnavailable", - "TargetInstanceUnavailable", - "UserCancelledResolution", - ], - "AddEventListenerResponseType": [ - "addEventListenerResponse", - ], - "AddIntentListenerRequestType": [ - "addIntentListenerRequest", - ], - "FluffyError": [ - "DesktopAgentNotFound", - "IntentDeliveryFailed", - "MalformedContext", - "NoAppsFound", - "ResolverTimeout", - "ResolverUnavailable", - "TargetAppUnavailable", - "TargetInstanceUnavailable", - "UserCancelledResolution", - ], - "AddIntentListenerResponseType": [ - "addIntentListenerResponse", - ], - "EventMessageType": [ - "addEventListenerEvent", - "broadcastEvent", - "channelChangedEvent", - "heartbeatEvent", - "intentEvent", - "privateChannelOnAddContextListenerEvent", - "privateChannelOnDisconnectEvent", - "privateChannelOnUnsubscribeEvent", - ], - "ResponseMessageType": [ - "addContextListenerResponse", - "addEventListenerResponse", - "addIntentListenerResponse", - "broadcastResponse", - "contextListenerUnsubscribeResponse", - "createPrivateChannelResponse", - "eventListenerUnsubscribeResponse", - "findInstancesResponse", - "findIntentResponse", - "findIntentsByContextResponse", - "getAppMetadataResponse", - "getCurrentChannelResponse", - "getCurrentContextResponse", - "getInfoResponse", - "getOrCreateChannelResponse", - "getUserChannelsResponse", - "intentListenerUnsubscribeResponse", - "intentResultResponse", - "joinUserChannelResponse", - "leaveCurrentChannelResponse", - "openResponse", - "privateChannelAddEventListenerResponse", - "privateChannelDisconnectResponse", - "privateChannelUnsubscribeEventListenerResponse", - "raiseIntentForContextResponse", - "raiseIntentResponse", - "raiseIntentResultResponse", - ], - "RequestMessageType": [ - "addContextListenerRequest", - "addEventListenerRequest", - "addIntentListenerRequest", - "broadcastRequest", - "contextListenerUnsubscribeRequest", - "createPrivateChannelRequest", - "eventListenerUnsubscribeRequest", - "findInstancesRequest", - "findIntentRequest", - "findIntentsByContextRequest", - "getAppMetadataRequest", - "getCurrentChannelRequest", - "getCurrentContextRequest", - "getInfoRequest", - "getOrCreateChannelRequest", - "getUserChannelsRequest", - "heartbeatAcknowledgementRequest", - "intentListenerUnsubscribeRequest", - "intentResultRequest", - "joinUserChannelRequest", - "leaveCurrentChannelRequest", - "openRequest", - "privateChannelAddEventListenerRequest", - "privateChannelDisconnectRequest", - "privateChannelUnsubscribeEventListenerRequest", - "raiseIntentForContextRequest", - "raiseIntentRequest", - ], - "BroadcastEventType": [ - "broadcastEvent", - ], - "BroadcastRequestType": [ - "broadcastRequest", - ], - "BroadcastResponseType": [ - "broadcastResponse", - ], - "ChannelChangedEventType": [ - "channelChangedEvent", - ], - "ContextListenerUnsubscribeRequestType": [ - "contextListenerUnsubscribeRequest", - ], - "ContextListenerUnsubscribeResponseType": [ - "contextListenerUnsubscribeResponse", - ], - "CreatePrivateChannelRequestType": [ - "createPrivateChannelRequest", - ], - "Type": [ - "app", - "private", - "user", - ], - "CreatePrivateChannelResponseType": [ - "createPrivateChannelResponse", - ], - "EventListenerUnsubscribeRequestType": [ - "eventListenerUnsubscribeRequest", - ], - "EventListenerUnsubscribeResponseType": [ - "eventListenerUnsubscribeResponse", - ], - "Fdc3UserInterfaceChannelsType": [ - "Fdc3UserInterfaceChannels", - ], - "Fdc3UserInterfaceChannelSelectedType": [ - "Fdc3UserInterfaceChannelSelected", - ], - "Fdc3UserInterfaceDragType": [ - "Fdc3UserInterfaceDrag", - ], - "Fdc3UserInterfaceHandshakeType": [ - "Fdc3UserInterfaceHandshake", - ], - "Fdc3UserInterfaceHelloType": [ - "Fdc3UserInterfaceHello", - ], - "Fdc3UserInterfaceMessageType": [ - "Fdc3UserInterfaceChannelSelected", - "Fdc3UserInterfaceChannels", - "Fdc3UserInterfaceDrag", - "Fdc3UserInterfaceHandshake", - "Fdc3UserInterfaceHello", - "Fdc3UserInterfaceResolve", - "Fdc3UserInterfaceResolveAction", - "Fdc3UserInterfaceRestyle", - ], - "Fdc3UserInterfaceResolveType": [ - "Fdc3UserInterfaceResolve", - ], - "Action": [ - "cancel", - "click", - "hover", - ], - "Fdc3UserInterfaceResolveActionType": [ - "Fdc3UserInterfaceResolveAction", - ], - "Fdc3UserInterfaceRestyleType": [ - "Fdc3UserInterfaceRestyle", - ], - "FindInstancesRequestType": [ - "findInstancesRequest", - ], - "FindInstancesErrors": [ - "AgentDisconnected", - "DesktopAgentNotFound", - "IntentDeliveryFailed", - "MalformedContext", - "MalformedMessage", - "NoAppsFound", - "NotConnectedToBridge", - "ResolverTimeout", - "ResolverUnavailable", - "ResponseToBridgeTimedOut", - "TargetAppUnavailable", - "TargetInstanceUnavailable", - "UserCancelledResolution", - ], - "FindInstancesResponseType": [ - "findInstancesResponse", - ], - "FindIntentRequestType": [ - "findIntentRequest", - ], - "FindIntentResponseType": [ - "findIntentResponse", - ], - "FindIntentsByContextRequestType": [ - "findIntentsByContextRequest", - ], - "FindIntentsByContextResponseType": [ - "findIntentsByContextResponse", - ], - "GetAppMetadataRequestType": [ - "getAppMetadataRequest", - ], - "GetAppMetadataResponseType": [ - "getAppMetadataResponse", - ], - "GetCurrentChannelRequestType": [ - "getCurrentChannelRequest", - ], - "GetCurrentChannelResponseType": [ - "getCurrentChannelResponse", - ], - "GetCurrentContextRequestType": [ - "getCurrentContextRequest", - ], - "GetCurrentContextResponseType": [ - "getCurrentContextResponse", - ], - "GetInfoRequestType": [ - "getInfoRequest", - ], - "GetInfoResponseType": [ - "getInfoResponse", - ], - "GetOrCreateChannelRequestType": [ - "getOrCreateChannelRequest", - ], - "GetOrCreateChannelResponseType": [ - "getOrCreateChannelResponse", - ], - "GetUserChannelsRequestType": [ - "getUserChannelsRequest", - ], - "GetUserChannelsResponseType": [ - "getUserChannelsResponse", - ], - "HeartbeatAcknowledgementRequestType": [ - "heartbeatAcknowledgementRequest", - ], - "HeartbeatEventType": [ - "heartbeatEvent", - ], - "IntentEventType": [ - "intentEvent", - ], - "IntentListenerUnsubscribeRequestType": [ - "intentListenerUnsubscribeRequest", - ], - "IntentListenerUnsubscribeResponseType": [ - "intentListenerUnsubscribeResponse", - ], - "IntentResultRequestType": [ - "intentResultRequest", - ], - "IntentResultResponseType": [ - "intentResultResponse", - ], - "JoinUserChannelRequestType": [ - "joinUserChannelRequest", - ], - "JoinUserChannelResponseType": [ - "joinUserChannelResponse", - ], - "LeaveCurrentChannelRequestType": [ - "leaveCurrentChannelRequest", - ], - "LeaveCurrentChannelResponseType": [ - "leaveCurrentChannelResponse", - ], - "OpenRequestType": [ - "openRequest", - ], - "OpenErrorResponsePayload": [ - "AgentDisconnected", - "AppNotFound", - "AppTimeout", - "DesktopAgentNotFound", - "ErrorOnLaunch", - "MalformedContext", - "MalformedMessage", - "NotConnectedToBridge", - "ResolverUnavailable", - "ResponseToBridgeTimedOut", - ], - "OpenResponseType": [ - "openResponse", - ], - "PrivateChannelEventType": [ - "addContextListener", - "disconnect", - "unsubscribe", - ], - "PrivateChannelAddEventListenerRequestType": [ - "privateChannelAddEventListenerRequest", - ], - "PrivateChannelAddEventListenerResponseType": [ - "privateChannelAddEventListenerResponse", - ], - "PrivateChannelDisconnectRequestType": [ - "privateChannelDisconnectRequest", - ], - "PrivateChannelDisconnectResponseType": [ - "privateChannelDisconnectResponse", - ], - "PrivateChannelOnAddContextListenerEventType": [ - "privateChannelOnAddContextListenerEvent", - ], - "PrivateChannelOnDisconnectEventType": [ - "privateChannelOnDisconnectEvent", - ], - "PrivateChannelOnUnsubscribeEventType": [ - "privateChannelOnUnsubscribeEvent", - ], - "PrivateChannelUnsubscribeEventListenerRequestType": [ - "privateChannelUnsubscribeEventListenerRequest", - ], - "PrivateChannelUnsubscribeEventListenerResponseType": [ - "privateChannelUnsubscribeEventListenerResponse", - ], - "RaiseIntentForContextRequestType": [ - "raiseIntentForContextRequest", - ], - "RaiseIntentForContextResponseType": [ - "raiseIntentForContextResponse", - ], - "RaiseIntentRequestType": [ - "raiseIntentRequest", - ], - "RaiseIntentResponseType": [ - "raiseIntentResponse", - ], - "RaiseIntentResultResponseType": [ - "raiseIntentResultResponse", - ], - "WebConnectionProtocol1HelloType": [ - "WCP1Hello", - ], - "WebConnectionProtocol2LoadURLType": [ - "WCP2LoadUrl", - ], - "WebConnectionProtocol3HandshakeType": [ - "WCP3Handshake", - ], - "WebConnectionProtocol4ValidateAppIdentityType": [ - "WCP4ValidateAppIdentity", - ], - "WebConnectionProtocol5ValidateAppIdentityFailedResponseType": [ - "WCP5ValidateAppIdentityFailedResponse", - ], - "WebConnectionProtocol5ValidateAppIdentitySuccessResponseType": [ - "WCP5ValidateAppIdentityResponse", - ], - "WebConnectionProtocol6GoodbyeType": [ - "WCP6Goodbye", - ], - "ConnectionStepMessageType": [ - "WCP1Hello", - "WCP2LoadUrl", - "WCP3Handshake", - "WCP4ValidateAppIdentity", - "WCP5ValidateAppIdentityFailedResponse", - "WCP5ValidateAppIdentityResponse", - "WCP6Goodbye", - ], -}; - -export type AppRequestMessage = AddContextListenerRequest | AddEventListenerRequest | AddIntentListenerRequest | BroadcastRequest | ContextListenerUnsubscribeRequest | CreatePrivateChannelRequest | EventListenerUnsubscribeRequest | FindInstancesRequest | FindIntentRequest | FindIntentsByContextRequest | GetAppMetadataRequest | GetCurrentChannelRequest | GetCurrentContextRequest | GetInfoRequest | GetOrCreateChannelRequest | GetUserChannelsRequest | HeartbeatAcknowledgementRequest | IntentListenerUnsubscribeRequest | IntentResultRequest | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest | PrivateChannelAddEventListenerRequest | PrivateChannelDisconnectRequest | PrivateChannelUnsubscribeEventListenerRequest | RaiseIntentForContextRequest | RaiseIntentRequest; +export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = 'WebConnectionProtocol6Goodbye'; -export type AgentResponseMessage = AddContextListenerResponse | AddEventListenerResponse | AddIntentListenerResponse | BroadcastResponse | ContextListenerUnsubscribeResponse | CreatePrivateChannelResponse | EventListenerUnsubscribeResponse | FindInstancesResponse | FindIntentResponse | FindIntentsByContextResponse | GetAppMetadataResponse | GetCurrentChannelResponse | GetCurrentContextResponse | GetInfoResponse | GetOrCreateChannelResponse | GetUserChannelsResponse | IntentListenerUnsubscribeResponse | IntentResultResponse | JoinUserChannelResponse | LeaveCurrentChannelResponse | OpenResponse | PrivateChannelAddEventListenerResponse | PrivateChannelDisconnectResponse | PrivateChannelUnsubscribeEventListenerResponse | RaiseIntentForContextResponse | RaiseIntentResponse | RaiseIntentResultResponse; +/** + * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { + try { + Convert.webConnectionProtocolMessageToJson(value); + return true; + } catch (_e: any) { + return false; + } +} -export type AgentEventMessage = BroadcastEvent | ChannelChangedEvent | HeartbeatEvent | IntentEvent | PrivateChannelOnAddContextListenerEvent | PrivateChannelOnDisconnectEvent | PrivateChannelOnUnsubscribeEvent; +export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = 'WebConnectionProtocolMessage'; /** * Returns true if the value has a type property with value 'addContextListenerRequest'. This is a fast check that does not check the format of the message */ export function isAddContextListenerRequest(value: any): value is AddContextListenerRequest { - return value != null && value.type === 'addContextListenerRequest'; + return value != null && value.type === 'addContextListenerRequest'; } /** * Returns true if value is a valid AddContextListenerRequest. This checks the type against the json schema for the message and will be slower */ export function isValidAddContextListenerRequest(value: any): value is AddContextListenerRequest { - try { - Convert.addContextListenerRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.addContextListenerRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const ADD_CONTEXT_LISTENER_REQUEST_TYPE = "AddContextListenerRequest"; +export const ADD_CONTEXT_LISTENER_REQUEST_TYPE = 'AddContextListenerRequest'; /** * Returns true if the value has a type property with value 'addContextListenerResponse'. This is a fast check that does not check the format of the message */ export function isAddContextListenerResponse(value: any): value is AddContextListenerResponse { - return value != null && value.type === 'addContextListenerResponse'; + return value != null && value.type === 'addContextListenerResponse'; } /** * Returns true if value is a valid AddContextListenerResponse. This checks the type against the json schema for the message and will be slower */ export function isValidAddContextListenerResponse(value: any): value is AddContextListenerResponse { - try { - Convert.addContextListenerResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.addContextListenerResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const ADD_CONTEXT_LISTENER_RESPONSE_TYPE = "AddContextListenerResponse"; +export const ADD_CONTEXT_LISTENER_RESPONSE_TYPE = 'AddContextListenerResponse'; /** * Returns true if the value has a type property with value 'addEventListenerRequest'. This is a fast check that does not check the format of the message */ export function isAddEventListenerRequest(value: any): value is AddEventListenerRequest { - return value != null && value.type === 'addEventListenerRequest'; + return value != null && value.type === 'addEventListenerRequest'; } /** * Returns true if value is a valid AddEventListenerRequest. This checks the type against the json schema for the message and will be slower */ export function isValidAddEventListenerRequest(value: any): value is AddEventListenerRequest { - try { - Convert.addEventListenerRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.addEventListenerRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const ADD_EVENT_LISTENER_REQUEST_TYPE = "AddEventListenerRequest"; +export const ADD_EVENT_LISTENER_REQUEST_TYPE = 'AddEventListenerRequest'; /** * Returns true if the value has a type property with value 'addEventListenerResponse'. This is a fast check that does not check the format of the message */ export function isAddEventListenerResponse(value: any): value is AddEventListenerResponse { - return value != null && value.type === 'addEventListenerResponse'; + return value != null && value.type === 'addEventListenerResponse'; } /** * Returns true if value is a valid AddEventListenerResponse. This checks the type against the json schema for the message and will be slower */ export function isValidAddEventListenerResponse(value: any): value is AddEventListenerResponse { - try { - Convert.addEventListenerResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.addEventListenerResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const ADD_EVENT_LISTENER_RESPONSE_TYPE = "AddEventListenerResponse"; +export const ADD_EVENT_LISTENER_RESPONSE_TYPE = 'AddEventListenerResponse'; /** * Returns true if the value has a type property with value 'addIntentListenerRequest'. This is a fast check that does not check the format of the message */ export function isAddIntentListenerRequest(value: any): value is AddIntentListenerRequest { - return value != null && value.type === 'addIntentListenerRequest'; + return value != null && value.type === 'addIntentListenerRequest'; } /** * Returns true if value is a valid AddIntentListenerRequest. This checks the type against the json schema for the message and will be slower */ export function isValidAddIntentListenerRequest(value: any): value is AddIntentListenerRequest { - try { - Convert.addIntentListenerRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.addIntentListenerRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const ADD_INTENT_LISTENER_REQUEST_TYPE = "AddIntentListenerRequest"; +export const ADD_INTENT_LISTENER_REQUEST_TYPE = 'AddIntentListenerRequest'; /** * Returns true if the value has a type property with value 'addIntentListenerResponse'. This is a fast check that does not check the format of the message */ export function isAddIntentListenerResponse(value: any): value is AddIntentListenerResponse { - return value != null && value.type === 'addIntentListenerResponse'; + return value != null && value.type === 'addIntentListenerResponse'; } /** * Returns true if value is a valid AddIntentListenerResponse. This checks the type against the json schema for the message and will be slower */ export function isValidAddIntentListenerResponse(value: any): value is AddIntentListenerResponse { - try { - Convert.addIntentListenerResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.addIntentListenerResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const ADD_INTENT_LISTENER_RESPONSE_TYPE = "AddIntentListenerResponse"; +export const ADD_INTENT_LISTENER_RESPONSE_TYPE = 'AddIntentListenerResponse'; /** * Returns true if the value has a type property with value 'broadcastEvent'. This is a fast check that does not check the format of the message */ export function isBroadcastEvent(value: any): value is BroadcastEvent { - return value != null && value.type === 'broadcastEvent'; + return value != null && value.type === 'broadcastEvent'; } /** * Returns true if value is a valid BroadcastEvent. This checks the type against the json schema for the message and will be slower */ export function isValidBroadcastEvent(value: any): value is BroadcastEvent { - try { - Convert.broadcastEventToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.broadcastEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const BROADCAST_EVENT_TYPE = "BroadcastEvent"; +export const BROADCAST_EVENT_TYPE = 'BroadcastEvent'; /** * Returns true if the value has a type property with value 'broadcastRequest'. This is a fast check that does not check the format of the message */ export function isBroadcastRequest(value: any): value is BroadcastRequest { - return value != null && value.type === 'broadcastRequest'; + return value != null && value.type === 'broadcastRequest'; } /** * Returns true if value is a valid BroadcastRequest. This checks the type against the json schema for the message and will be slower */ export function isValidBroadcastRequest(value: any): value is BroadcastRequest { - try { - Convert.broadcastRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.broadcastRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const BROADCAST_REQUEST_TYPE = "BroadcastRequest"; +export const BROADCAST_REQUEST_TYPE = 'BroadcastRequest'; /** * Returns true if the value has a type property with value 'broadcastResponse'. This is a fast check that does not check the format of the message */ export function isBroadcastResponse(value: any): value is BroadcastResponse { - return value != null && value.type === 'broadcastResponse'; + return value != null && value.type === 'broadcastResponse'; } /** * Returns true if value is a valid BroadcastResponse. This checks the type against the json schema for the message and will be slower */ export function isValidBroadcastResponse(value: any): value is BroadcastResponse { - try { - Convert.broadcastResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.broadcastResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const BROADCAST_RESPONSE_TYPE = "BroadcastResponse"; +export const BROADCAST_RESPONSE_TYPE = 'BroadcastResponse'; /** * Returns true if the value has a type property with value 'channelChangedEvent'. This is a fast check that does not check the format of the message */ export function isChannelChangedEvent(value: any): value is ChannelChangedEvent { - return value != null && value.type === 'channelChangedEvent'; + return value != null && value.type === 'channelChangedEvent'; } /** * Returns true if value is a valid ChannelChangedEvent. This checks the type against the json schema for the message and will be slower */ export function isValidChannelChangedEvent(value: any): value is ChannelChangedEvent { - try { - Convert.channelChangedEventToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.channelChangedEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const CHANNEL_CHANGED_EVENT_TYPE = "ChannelChangedEvent"; +export const CHANNEL_CHANGED_EVENT_TYPE = 'ChannelChangedEvent'; /** * Returns true if the value has a type property with value 'contextListenerUnsubscribeRequest'. This is a fast check that does not check the format of the message */ export function isContextListenerUnsubscribeRequest(value: any): value is ContextListenerUnsubscribeRequest { - return value != null && value.type === 'contextListenerUnsubscribeRequest'; + return value != null && value.type === 'contextListenerUnsubscribeRequest'; } /** * Returns true if value is a valid ContextListenerUnsubscribeRequest. This checks the type against the json schema for the message and will be slower */ export function isValidContextListenerUnsubscribeRequest(value: any): value is ContextListenerUnsubscribeRequest { - try { - Convert.contextListenerUnsubscribeRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.contextListenerUnsubscribeRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const CONTEXT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = "ContextListenerUnsubscribeRequest"; +export const CONTEXT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = 'ContextListenerUnsubscribeRequest'; /** * Returns true if the value has a type property with value 'contextListenerUnsubscribeResponse'. This is a fast check that does not check the format of the message */ export function isContextListenerUnsubscribeResponse(value: any): value is ContextListenerUnsubscribeResponse { - return value != null && value.type === 'contextListenerUnsubscribeResponse'; + return value != null && value.type === 'contextListenerUnsubscribeResponse'; } /** * Returns true if value is a valid ContextListenerUnsubscribeResponse. This checks the type against the json schema for the message and will be slower */ export function isValidContextListenerUnsubscribeResponse(value: any): value is ContextListenerUnsubscribeResponse { - try { - Convert.contextListenerUnsubscribeResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.contextListenerUnsubscribeResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const CONTEXT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "ContextListenerUnsubscribeResponse"; +export const CONTEXT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = 'ContextListenerUnsubscribeResponse'; /** * Returns true if the value has a type property with value 'createPrivateChannelRequest'. This is a fast check that does not check the format of the message */ export function isCreatePrivateChannelRequest(value: any): value is CreatePrivateChannelRequest { - return value != null && value.type === 'createPrivateChannelRequest'; + return value != null && value.type === 'createPrivateChannelRequest'; } /** * Returns true if value is a valid CreatePrivateChannelRequest. This checks the type against the json schema for the message and will be slower */ export function isValidCreatePrivateChannelRequest(value: any): value is CreatePrivateChannelRequest { - try { - Convert.createPrivateChannelRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.createPrivateChannelRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const CREATE_PRIVATE_CHANNEL_REQUEST_TYPE = "CreatePrivateChannelRequest"; +export const CREATE_PRIVATE_CHANNEL_REQUEST_TYPE = 'CreatePrivateChannelRequest'; /** * Returns true if the value has a type property with value 'createPrivateChannelResponse'. This is a fast check that does not check the format of the message */ export function isCreatePrivateChannelResponse(value: any): value is CreatePrivateChannelResponse { - return value != null && value.type === 'createPrivateChannelResponse'; + return value != null && value.type === 'createPrivateChannelResponse'; } /** * Returns true if value is a valid CreatePrivateChannelResponse. This checks the type against the json schema for the message and will be slower */ export function isValidCreatePrivateChannelResponse(value: any): value is CreatePrivateChannelResponse { - try { - Convert.createPrivateChannelResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.createPrivateChannelResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const CREATE_PRIVATE_CHANNEL_RESPONSE_TYPE = "CreatePrivateChannelResponse"; +export const CREATE_PRIVATE_CHANNEL_RESPONSE_TYPE = 'CreatePrivateChannelResponse'; /** * Returns true if the value has a type property with value 'eventListenerUnsubscribeRequest'. This is a fast check that does not check the format of the message */ export function isEventListenerUnsubscribeRequest(value: any): value is EventListenerUnsubscribeRequest { - return value != null && value.type === 'eventListenerUnsubscribeRequest'; + return value != null && value.type === 'eventListenerUnsubscribeRequest'; } /** * Returns true if value is a valid EventListenerUnsubscribeRequest. This checks the type against the json schema for the message and will be slower */ export function isValidEventListenerUnsubscribeRequest(value: any): value is EventListenerUnsubscribeRequest { - try { - Convert.eventListenerUnsubscribeRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.eventListenerUnsubscribeRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const EVENT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = "EventListenerUnsubscribeRequest"; +export const EVENT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = 'EventListenerUnsubscribeRequest'; /** * Returns true if the value has a type property with value 'eventListenerUnsubscribeResponse'. This is a fast check that does not check the format of the message */ export function isEventListenerUnsubscribeResponse(value: any): value is EventListenerUnsubscribeResponse { - return value != null && value.type === 'eventListenerUnsubscribeResponse'; + return value != null && value.type === 'eventListenerUnsubscribeResponse'; } /** * Returns true if value is a valid EventListenerUnsubscribeResponse. This checks the type against the json schema for the message and will be slower */ export function isValidEventListenerUnsubscribeResponse(value: any): value is EventListenerUnsubscribeResponse { - try { - Convert.eventListenerUnsubscribeResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.eventListenerUnsubscribeResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "EventListenerUnsubscribeResponse"; +export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = 'EventListenerUnsubscribeResponse'; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { - return value != null && value.type === 'Fdc3UserInterfaceChannels'; +export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { + return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { - try { - Convert.fdc3UserInterfaceChannelsToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { + try { + Convert.fdc3UserInterfaceChannelSelectedToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_CHANNELS_TYPE = "Fdc3UserInterfaceChannels"; +export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = 'Fdc3UserInterfaceChannelSelected'; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { - return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; +export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { + return value != null && value.type === 'Fdc3UserInterfaceChannels'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { - try { - Convert.fdc3UserInterfaceChannelSelectedToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { + try { + Convert.fdc3UserInterfaceChannelsToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = "Fdc3UserInterfaceChannelSelected"; +export const FDC3_USER_INTERFACE_CHANNELS_TYPE = 'Fdc3UserInterfaceChannels'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceDrag'. This is a fast check that does not check the format of the message */ export function isFdc3UserInterfaceDrag(value: any): value is Fdc3UserInterfaceDrag { - return value != null && value.type === 'Fdc3UserInterfaceDrag'; + return value != null && value.type === 'Fdc3UserInterfaceDrag'; } /** * Returns true if value is a valid Fdc3UserInterfaceDrag. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceDrag(value: any): value is Fdc3UserInterfaceDrag { - try { - Convert.fdc3UserInterfaceDragToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceDragToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_DRAG_TYPE = "Fdc3UserInterfaceDrag"; +export const FDC3_USER_INTERFACE_DRAG_TYPE = 'Fdc3UserInterfaceDrag'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceHandshake'. This is a fast check that does not check the format of the message */ export function isFdc3UserInterfaceHandshake(value: any): value is Fdc3UserInterfaceHandshake { - return value != null && value.type === 'Fdc3UserInterfaceHandshake'; + return value != null && value.type === 'Fdc3UserInterfaceHandshake'; } /** * Returns true if value is a valid Fdc3UserInterfaceHandshake. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceHandshake(value: any): value is Fdc3UserInterfaceHandshake { - try { - Convert.fdc3UserInterfaceHandshakeToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceHandshakeToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_HANDSHAKE_TYPE = "Fdc3UserInterfaceHandshake"; +export const FDC3_USER_INTERFACE_HANDSHAKE_TYPE = 'Fdc3UserInterfaceHandshake'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceHello'. This is a fast check that does not check the format of the message */ export function isFdc3UserInterfaceHello(value: any): value is Fdc3UserInterfaceHello { - return value != null && value.type === 'Fdc3UserInterfaceHello'; + return value != null && value.type === 'Fdc3UserInterfaceHello'; } /** * Returns true if value is a valid Fdc3UserInterfaceHello. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceHello(value: any): value is Fdc3UserInterfaceHello { - try { - Convert.fdc3UserInterfaceHelloToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceHelloToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_HELLO_TYPE = "Fdc3UserInterfaceHello"; +export const FDC3_USER_INTERFACE_HELLO_TYPE = 'Fdc3UserInterfaceHello'; /** * Returns true if value is a valid Fdc3UserInterfaceMessage. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceMessage(value: any): value is Fdc3UserInterfaceMessage { - try { - Convert.fdc3UserInterfaceMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceMessageToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_MESSAGE_TYPE = "Fdc3UserInterfaceMessage"; +export const FDC3_USER_INTERFACE_MESSAGE_TYPE = 'Fdc3UserInterfaceMessage'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceResolve'. This is a fast check that does not check the format of the message */ export function isFdc3UserInterfaceResolve(value: any): value is Fdc3UserInterfaceResolve { - return value != null && value.type === 'Fdc3UserInterfaceResolve'; + return value != null && value.type === 'Fdc3UserInterfaceResolve'; } /** * Returns true if value is a valid Fdc3UserInterfaceResolve. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceResolve(value: any): value is Fdc3UserInterfaceResolve { - try { - Convert.fdc3UserInterfaceResolveToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceResolveToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_RESOLVE_TYPE = "Fdc3UserInterfaceResolve"; +export const FDC3_USER_INTERFACE_RESOLVE_TYPE = 'Fdc3UserInterfaceResolve'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceResolveAction'. This is a fast check that does not check the format of the message */ export function isFdc3UserInterfaceResolveAction(value: any): value is Fdc3UserInterfaceResolveAction { - return value != null && value.type === 'Fdc3UserInterfaceResolveAction'; + return value != null && value.type === 'Fdc3UserInterfaceResolveAction'; } /** * Returns true if value is a valid Fdc3UserInterfaceResolveAction. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceResolveAction(value: any): value is Fdc3UserInterfaceResolveAction { - try { - Convert.fdc3UserInterfaceResolveActionToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceResolveActionToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE = "Fdc3UserInterfaceResolveAction"; +export const FDC3_USER_INTERFACE_RESOLVE_ACTION_TYPE = 'Fdc3UserInterfaceResolveAction'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceRestyle'. This is a fast check that does not check the format of the message */ export function isFdc3UserInterfaceRestyle(value: any): value is Fdc3UserInterfaceRestyle { - return value != null && value.type === 'Fdc3UserInterfaceRestyle'; + return value != null && value.type === 'Fdc3UserInterfaceRestyle'; } /** * Returns true if value is a valid Fdc3UserInterfaceRestyle. This checks the type against the json schema for the message and will be slower */ export function isValidFdc3UserInterfaceRestyle(value: any): value is Fdc3UserInterfaceRestyle { - try { - Convert.fdc3UserInterfaceRestyleToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.fdc3UserInterfaceRestyleToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FDC3_USER_INTERFACE_RESTYLE_TYPE = "Fdc3UserInterfaceRestyle"; +export const FDC3_USER_INTERFACE_RESTYLE_TYPE = 'Fdc3UserInterfaceRestyle'; /** * Returns true if the value has a type property with value 'findInstancesRequest'. This is a fast check that does not check the format of the message */ export function isFindInstancesRequest(value: any): value is FindInstancesRequest { - return value != null && value.type === 'findInstancesRequest'; + return value != null && value.type === 'findInstancesRequest'; } /** * Returns true if value is a valid FindInstancesRequest. This checks the type against the json schema for the message and will be slower */ export function isValidFindInstancesRequest(value: any): value is FindInstancesRequest { - try { - Convert.findInstancesRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.findInstancesRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FIND_INSTANCES_REQUEST_TYPE = "FindInstancesRequest"; +export const FIND_INSTANCES_REQUEST_TYPE = 'FindInstancesRequest'; /** * Returns true if the value has a type property with value 'findInstancesResponse'. This is a fast check that does not check the format of the message */ export function isFindInstancesResponse(value: any): value is FindInstancesResponse { - return value != null && value.type === 'findInstancesResponse'; + return value != null && value.type === 'findInstancesResponse'; } /** * Returns true if value is a valid FindInstancesResponse. This checks the type against the json schema for the message and will be slower */ export function isValidFindInstancesResponse(value: any): value is FindInstancesResponse { - try { - Convert.findInstancesResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.findInstancesResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FIND_INSTANCES_RESPONSE_TYPE = "FindInstancesResponse"; +export const FIND_INSTANCES_RESPONSE_TYPE = 'FindInstancesResponse'; /** * Returns true if the value has a type property with value 'findIntentRequest'. This is a fast check that does not check the format of the message */ export function isFindIntentRequest(value: any): value is FindIntentRequest { - return value != null && value.type === 'findIntentRequest'; + return value != null && value.type === 'findIntentRequest'; } /** * Returns true if value is a valid FindIntentRequest. This checks the type against the json schema for the message and will be slower */ export function isValidFindIntentRequest(value: any): value is FindIntentRequest { - try { - Convert.findIntentRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.findIntentRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FIND_INTENT_REQUEST_TYPE = "FindIntentRequest"; +export const FIND_INTENT_REQUEST_TYPE = 'FindIntentRequest'; /** * Returns true if the value has a type property with value 'findIntentResponse'. This is a fast check that does not check the format of the message */ export function isFindIntentResponse(value: any): value is FindIntentResponse { - return value != null && value.type === 'findIntentResponse'; + return value != null && value.type === 'findIntentResponse'; } /** * Returns true if value is a valid FindIntentResponse. This checks the type against the json schema for the message and will be slower */ export function isValidFindIntentResponse(value: any): value is FindIntentResponse { - try { - Convert.findIntentResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.findIntentResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FIND_INTENT_RESPONSE_TYPE = "FindIntentResponse"; +export const FIND_INTENT_RESPONSE_TYPE = 'FindIntentResponse'; /** * Returns true if the value has a type property with value 'findIntentsByContextRequest'. This is a fast check that does not check the format of the message */ export function isFindIntentsByContextRequest(value: any): value is FindIntentsByContextRequest { - return value != null && value.type === 'findIntentsByContextRequest'; + return value != null && value.type === 'findIntentsByContextRequest'; } /** * Returns true if value is a valid FindIntentsByContextRequest. This checks the type against the json schema for the message and will be slower */ export function isValidFindIntentsByContextRequest(value: any): value is FindIntentsByContextRequest { - try { - Convert.findIntentsByContextRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.findIntentsByContextRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FIND_INTENTS_BY_CONTEXT_REQUEST_TYPE = "FindIntentsByContextRequest"; +export const FIND_INTENTS_BY_CONTEXT_REQUEST_TYPE = 'FindIntentsByContextRequest'; /** * Returns true if the value has a type property with value 'findIntentsByContextResponse'. This is a fast check that does not check the format of the message */ export function isFindIntentsByContextResponse(value: any): value is FindIntentsByContextResponse { - return value != null && value.type === 'findIntentsByContextResponse'; + return value != null && value.type === 'findIntentsByContextResponse'; } /** * Returns true if value is a valid FindIntentsByContextResponse. This checks the type against the json schema for the message and will be slower */ export function isValidFindIntentsByContextResponse(value: any): value is FindIntentsByContextResponse { - try { - Convert.findIntentsByContextResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.findIntentsByContextResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const FIND_INTENTS_BY_CONTEXT_RESPONSE_TYPE = "FindIntentsByContextResponse"; +export const FIND_INTENTS_BY_CONTEXT_RESPONSE_TYPE = 'FindIntentsByContextResponse'; /** * Returns true if the value has a type property with value 'getAppMetadataRequest'. This is a fast check that does not check the format of the message */ export function isGetAppMetadataRequest(value: any): value is GetAppMetadataRequest { - return value != null && value.type === 'getAppMetadataRequest'; + return value != null && value.type === 'getAppMetadataRequest'; } /** * Returns true if value is a valid GetAppMetadataRequest. This checks the type against the json schema for the message and will be slower */ export function isValidGetAppMetadataRequest(value: any): value is GetAppMetadataRequest { - try { - Convert.getAppMetadataRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getAppMetadataRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_APP_METADATA_REQUEST_TYPE = "GetAppMetadataRequest"; +export const GET_APP_METADATA_REQUEST_TYPE = 'GetAppMetadataRequest'; /** * Returns true if the value has a type property with value 'getAppMetadataResponse'. This is a fast check that does not check the format of the message */ export function isGetAppMetadataResponse(value: any): value is GetAppMetadataResponse { - return value != null && value.type === 'getAppMetadataResponse'; + return value != null && value.type === 'getAppMetadataResponse'; } /** * Returns true if value is a valid GetAppMetadataResponse. This checks the type against the json schema for the message and will be slower */ export function isValidGetAppMetadataResponse(value: any): value is GetAppMetadataResponse { - try { - Convert.getAppMetadataResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getAppMetadataResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_APP_METADATA_RESPONSE_TYPE = "GetAppMetadataResponse"; +export const GET_APP_METADATA_RESPONSE_TYPE = 'GetAppMetadataResponse'; /** * Returns true if the value has a type property with value 'getCurrentChannelRequest'. This is a fast check that does not check the format of the message */ export function isGetCurrentChannelRequest(value: any): value is GetCurrentChannelRequest { - return value != null && value.type === 'getCurrentChannelRequest'; + return value != null && value.type === 'getCurrentChannelRequest'; } /** * Returns true if value is a valid GetCurrentChannelRequest. This checks the type against the json schema for the message and will be slower */ export function isValidGetCurrentChannelRequest(value: any): value is GetCurrentChannelRequest { - try { - Convert.getCurrentChannelRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getCurrentChannelRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_CURRENT_CHANNEL_REQUEST_TYPE = "GetCurrentChannelRequest"; +export const GET_CURRENT_CHANNEL_REQUEST_TYPE = 'GetCurrentChannelRequest'; /** * Returns true if the value has a type property with value 'getCurrentChannelResponse'. This is a fast check that does not check the format of the message */ export function isGetCurrentChannelResponse(value: any): value is GetCurrentChannelResponse { - return value != null && value.type === 'getCurrentChannelResponse'; + return value != null && value.type === 'getCurrentChannelResponse'; } /** * Returns true if value is a valid GetCurrentChannelResponse. This checks the type against the json schema for the message and will be slower */ export function isValidGetCurrentChannelResponse(value: any): value is GetCurrentChannelResponse { - try { - Convert.getCurrentChannelResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getCurrentChannelResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_CURRENT_CHANNEL_RESPONSE_TYPE = "GetCurrentChannelResponse"; +export const GET_CURRENT_CHANNEL_RESPONSE_TYPE = 'GetCurrentChannelResponse'; /** * Returns true if the value has a type property with value 'getCurrentContextRequest'. This is a fast check that does not check the format of the message */ export function isGetCurrentContextRequest(value: any): value is GetCurrentContextRequest { - return value != null && value.type === 'getCurrentContextRequest'; + return value != null && value.type === 'getCurrentContextRequest'; } /** * Returns true if value is a valid GetCurrentContextRequest. This checks the type against the json schema for the message and will be slower */ export function isValidGetCurrentContextRequest(value: any): value is GetCurrentContextRequest { - try { - Convert.getCurrentContextRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getCurrentContextRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_CURRENT_CONTEXT_REQUEST_TYPE = "GetCurrentContextRequest"; +export const GET_CURRENT_CONTEXT_REQUEST_TYPE = 'GetCurrentContextRequest'; /** * Returns true if the value has a type property with value 'getCurrentContextResponse'. This is a fast check that does not check the format of the message */ export function isGetCurrentContextResponse(value: any): value is GetCurrentContextResponse { - return value != null && value.type === 'getCurrentContextResponse'; + return value != null && value.type === 'getCurrentContextResponse'; } /** * Returns true if value is a valid GetCurrentContextResponse. This checks the type against the json schema for the message and will be slower */ export function isValidGetCurrentContextResponse(value: any): value is GetCurrentContextResponse { - try { - Convert.getCurrentContextResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getCurrentContextResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_CURRENT_CONTEXT_RESPONSE_TYPE = "GetCurrentContextResponse"; +export const GET_CURRENT_CONTEXT_RESPONSE_TYPE = 'GetCurrentContextResponse'; /** * Returns true if the value has a type property with value 'getInfoRequest'. This is a fast check that does not check the format of the message */ export function isGetInfoRequest(value: any): value is GetInfoRequest { - return value != null && value.type === 'getInfoRequest'; + return value != null && value.type === 'getInfoRequest'; } /** * Returns true if value is a valid GetInfoRequest. This checks the type against the json schema for the message and will be slower */ export function isValidGetInfoRequest(value: any): value is GetInfoRequest { - try { - Convert.getInfoRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getInfoRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_INFO_REQUEST_TYPE = "GetInfoRequest"; +export const GET_INFO_REQUEST_TYPE = 'GetInfoRequest'; /** * Returns true if the value has a type property with value 'getInfoResponse'. This is a fast check that does not check the format of the message */ export function isGetInfoResponse(value: any): value is GetInfoResponse { - return value != null && value.type === 'getInfoResponse'; + return value != null && value.type === 'getInfoResponse'; } /** * Returns true if value is a valid GetInfoResponse. This checks the type against the json schema for the message and will be slower */ export function isValidGetInfoResponse(value: any): value is GetInfoResponse { - try { - Convert.getInfoResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getInfoResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_INFO_RESPONSE_TYPE = "GetInfoResponse"; +export const GET_INFO_RESPONSE_TYPE = 'GetInfoResponse'; /** * Returns true if the value has a type property with value 'getOrCreateChannelRequest'. This is a fast check that does not check the format of the message */ export function isGetOrCreateChannelRequest(value: any): value is GetOrCreateChannelRequest { - return value != null && value.type === 'getOrCreateChannelRequest'; + return value != null && value.type === 'getOrCreateChannelRequest'; } /** * Returns true if value is a valid GetOrCreateChannelRequest. This checks the type against the json schema for the message and will be slower */ export function isValidGetOrCreateChannelRequest(value: any): value is GetOrCreateChannelRequest { - try { - Convert.getOrCreateChannelRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getOrCreateChannelRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_OR_CREATE_CHANNEL_REQUEST_TYPE = "GetOrCreateChannelRequest"; +export const GET_OR_CREATE_CHANNEL_REQUEST_TYPE = 'GetOrCreateChannelRequest'; /** * Returns true if the value has a type property with value 'getOrCreateChannelResponse'. This is a fast check that does not check the format of the message */ export function isGetOrCreateChannelResponse(value: any): value is GetOrCreateChannelResponse { - return value != null && value.type === 'getOrCreateChannelResponse'; + return value != null && value.type === 'getOrCreateChannelResponse'; } /** * Returns true if value is a valid GetOrCreateChannelResponse. This checks the type against the json schema for the message and will be slower */ export function isValidGetOrCreateChannelResponse(value: any): value is GetOrCreateChannelResponse { - try { - Convert.getOrCreateChannelResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getOrCreateChannelResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_OR_CREATE_CHANNEL_RESPONSE_TYPE = "GetOrCreateChannelResponse"; +export const GET_OR_CREATE_CHANNEL_RESPONSE_TYPE = 'GetOrCreateChannelResponse'; /** * Returns true if the value has a type property with value 'getUserChannelsRequest'. This is a fast check that does not check the format of the message */ export function isGetUserChannelsRequest(value: any): value is GetUserChannelsRequest { - return value != null && value.type === 'getUserChannelsRequest'; + return value != null && value.type === 'getUserChannelsRequest'; } /** * Returns true if value is a valid GetUserChannelsRequest. This checks the type against the json schema for the message and will be slower */ export function isValidGetUserChannelsRequest(value: any): value is GetUserChannelsRequest { - try { - Convert.getUserChannelsRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getUserChannelsRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_USER_CHANNELS_REQUEST_TYPE = "GetUserChannelsRequest"; +export const GET_USER_CHANNELS_REQUEST_TYPE = 'GetUserChannelsRequest'; /** * Returns true if the value has a type property with value 'getUserChannelsResponse'. This is a fast check that does not check the format of the message */ export function isGetUserChannelsResponse(value: any): value is GetUserChannelsResponse { - return value != null && value.type === 'getUserChannelsResponse'; + return value != null && value.type === 'getUserChannelsResponse'; } /** * Returns true if value is a valid GetUserChannelsResponse. This checks the type against the json schema for the message and will be slower */ export function isValidGetUserChannelsResponse(value: any): value is GetUserChannelsResponse { - try { - Convert.getUserChannelsResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.getUserChannelsResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const GET_USER_CHANNELS_RESPONSE_TYPE = "GetUserChannelsResponse"; +export const GET_USER_CHANNELS_RESPONSE_TYPE = 'GetUserChannelsResponse'; /** * Returns true if the value has a type property with value 'heartbeatAcknowledgementRequest'. This is a fast check that does not check the format of the message */ export function isHeartbeatAcknowledgementRequest(value: any): value is HeartbeatAcknowledgementRequest { - return value != null && value.type === 'heartbeatAcknowledgementRequest'; + return value != null && value.type === 'heartbeatAcknowledgementRequest'; } /** * Returns true if value is a valid HeartbeatAcknowledgementRequest. This checks the type against the json schema for the message and will be slower */ export function isValidHeartbeatAcknowledgementRequest(value: any): value is HeartbeatAcknowledgementRequest { - try { - Convert.heartbeatAcknowledgementRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.heartbeatAcknowledgementRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const HEARTBEAT_ACKNOWLEDGEMENT_REQUEST_TYPE = "HeartbeatAcknowledgementRequest"; +export const HEARTBEAT_ACKNOWLEDGEMENT_REQUEST_TYPE = 'HeartbeatAcknowledgementRequest'; /** * Returns true if the value has a type property with value 'heartbeatEvent'. This is a fast check that does not check the format of the message */ export function isHeartbeatEvent(value: any): value is HeartbeatEvent { - return value != null && value.type === 'heartbeatEvent'; + return value != null && value.type === 'heartbeatEvent'; } /** * Returns true if value is a valid HeartbeatEvent. This checks the type against the json schema for the message and will be slower */ export function isValidHeartbeatEvent(value: any): value is HeartbeatEvent { - try { - Convert.heartbeatEventToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.heartbeatEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const HEARTBEAT_EVENT_TYPE = "HeartbeatEvent"; +export const HEARTBEAT_EVENT_TYPE = 'HeartbeatEvent'; /** * Returns true if the value has a type property with value 'intentEvent'. This is a fast check that does not check the format of the message */ export function isIntentEvent(value: any): value is IntentEvent { - return value != null && value.type === 'intentEvent'; + return value != null && value.type === 'intentEvent'; } /** * Returns true if value is a valid IntentEvent. This checks the type against the json schema for the message and will be slower */ export function isValidIntentEvent(value: any): value is IntentEvent { - try { - Convert.intentEventToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.intentEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const INTENT_EVENT_TYPE = "IntentEvent"; +export const INTENT_EVENT_TYPE = 'IntentEvent'; /** * Returns true if the value has a type property with value 'intentListenerUnsubscribeRequest'. This is a fast check that does not check the format of the message */ export function isIntentListenerUnsubscribeRequest(value: any): value is IntentListenerUnsubscribeRequest { - return value != null && value.type === 'intentListenerUnsubscribeRequest'; + return value != null && value.type === 'intentListenerUnsubscribeRequest'; } /** * Returns true if value is a valid IntentListenerUnsubscribeRequest. This checks the type against the json schema for the message and will be slower */ export function isValidIntentListenerUnsubscribeRequest(value: any): value is IntentListenerUnsubscribeRequest { - try { - Convert.intentListenerUnsubscribeRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.intentListenerUnsubscribeRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const INTENT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = "IntentListenerUnsubscribeRequest"; +export const INTENT_LISTENER_UNSUBSCRIBE_REQUEST_TYPE = 'IntentListenerUnsubscribeRequest'; /** * Returns true if the value has a type property with value 'intentListenerUnsubscribeResponse'. This is a fast check that does not check the format of the message */ export function isIntentListenerUnsubscribeResponse(value: any): value is IntentListenerUnsubscribeResponse { - return value != null && value.type === 'intentListenerUnsubscribeResponse'; + return value != null && value.type === 'intentListenerUnsubscribeResponse'; } /** * Returns true if value is a valid IntentListenerUnsubscribeResponse. This checks the type against the json schema for the message and will be slower */ export function isValidIntentListenerUnsubscribeResponse(value: any): value is IntentListenerUnsubscribeResponse { - try { - Convert.intentListenerUnsubscribeResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.intentListenerUnsubscribeResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const INTENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = "IntentListenerUnsubscribeResponse"; +export const INTENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = 'IntentListenerUnsubscribeResponse'; /** * Returns true if the value has a type property with value 'intentResultRequest'. This is a fast check that does not check the format of the message */ export function isIntentResultRequest(value: any): value is IntentResultRequest { - return value != null && value.type === 'intentResultRequest'; + return value != null && value.type === 'intentResultRequest'; } /** * Returns true if value is a valid IntentResultRequest. This checks the type against the json schema for the message and will be slower */ export function isValidIntentResultRequest(value: any): value is IntentResultRequest { - try { - Convert.intentResultRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.intentResultRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const INTENT_RESULT_REQUEST_TYPE = "IntentResultRequest"; +export const INTENT_RESULT_REQUEST_TYPE = 'IntentResultRequest'; /** * Returns true if the value has a type property with value 'intentResultResponse'. This is a fast check that does not check the format of the message */ export function isIntentResultResponse(value: any): value is IntentResultResponse { - return value != null && value.type === 'intentResultResponse'; + return value != null && value.type === 'intentResultResponse'; } /** * Returns true if value is a valid IntentResultResponse. This checks the type against the json schema for the message and will be slower */ export function isValidIntentResultResponse(value: any): value is IntentResultResponse { - try { - Convert.intentResultResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.intentResultResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const INTENT_RESULT_RESPONSE_TYPE = "IntentResultResponse"; +export const INTENT_RESULT_RESPONSE_TYPE = 'IntentResultResponse'; /** * Returns true if the value has a type property with value 'joinUserChannelRequest'. This is a fast check that does not check the format of the message */ export function isJoinUserChannelRequest(value: any): value is JoinUserChannelRequest { - return value != null && value.type === 'joinUserChannelRequest'; + return value != null && value.type === 'joinUserChannelRequest'; } /** * Returns true if value is a valid JoinUserChannelRequest. This checks the type against the json schema for the message and will be slower */ export function isValidJoinUserChannelRequest(value: any): value is JoinUserChannelRequest { - try { - Convert.joinUserChannelRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.joinUserChannelRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const JOIN_USER_CHANNEL_REQUEST_TYPE = "JoinUserChannelRequest"; +export const JOIN_USER_CHANNEL_REQUEST_TYPE = 'JoinUserChannelRequest'; /** * Returns true if the value has a type property with value 'joinUserChannelResponse'. This is a fast check that does not check the format of the message */ export function isJoinUserChannelResponse(value: any): value is JoinUserChannelResponse { - return value != null && value.type === 'joinUserChannelResponse'; + return value != null && value.type === 'joinUserChannelResponse'; } /** * Returns true if value is a valid JoinUserChannelResponse. This checks the type against the json schema for the message and will be slower */ export function isValidJoinUserChannelResponse(value: any): value is JoinUserChannelResponse { - try { - Convert.joinUserChannelResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.joinUserChannelResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const JOIN_USER_CHANNEL_RESPONSE_TYPE = "JoinUserChannelResponse"; +export const JOIN_USER_CHANNEL_RESPONSE_TYPE = 'JoinUserChannelResponse'; /** * Returns true if the value has a type property with value 'leaveCurrentChannelRequest'. This is a fast check that does not check the format of the message */ export function isLeaveCurrentChannelRequest(value: any): value is LeaveCurrentChannelRequest { - return value != null && value.type === 'leaveCurrentChannelRequest'; + return value != null && value.type === 'leaveCurrentChannelRequest'; } /** * Returns true if value is a valid LeaveCurrentChannelRequest. This checks the type against the json schema for the message and will be slower */ export function isValidLeaveCurrentChannelRequest(value: any): value is LeaveCurrentChannelRequest { - try { - Convert.leaveCurrentChannelRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.leaveCurrentChannelRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const LEAVE_CURRENT_CHANNEL_REQUEST_TYPE = "LeaveCurrentChannelRequest"; +export const LEAVE_CURRENT_CHANNEL_REQUEST_TYPE = 'LeaveCurrentChannelRequest'; /** * Returns true if the value has a type property with value 'leaveCurrentChannelResponse'. This is a fast check that does not check the format of the message */ export function isLeaveCurrentChannelResponse(value: any): value is LeaveCurrentChannelResponse { - return value != null && value.type === 'leaveCurrentChannelResponse'; + return value != null && value.type === 'leaveCurrentChannelResponse'; } /** * Returns true if value is a valid LeaveCurrentChannelResponse. This checks the type against the json schema for the message and will be slower */ export function isValidLeaveCurrentChannelResponse(value: any): value is LeaveCurrentChannelResponse { - try { - Convert.leaveCurrentChannelResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.leaveCurrentChannelResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const LEAVE_CURRENT_CHANNEL_RESPONSE_TYPE = "LeaveCurrentChannelResponse"; +export const LEAVE_CURRENT_CHANNEL_RESPONSE_TYPE = 'LeaveCurrentChannelResponse'; /** * Returns true if the value has a type property with value 'openRequest'. This is a fast check that does not check the format of the message */ export function isOpenRequest(value: any): value is OpenRequest { - return value != null && value.type === 'openRequest'; + return value != null && value.type === 'openRequest'; } /** * Returns true if value is a valid OpenRequest. This checks the type against the json schema for the message and will be slower */ export function isValidOpenRequest(value: any): value is OpenRequest { - try { - Convert.openRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.openRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const OPEN_REQUEST_TYPE = "OpenRequest"; +export const OPEN_REQUEST_TYPE = 'OpenRequest'; /** * Returns true if the value has a type property with value 'openResponse'. This is a fast check that does not check the format of the message */ export function isOpenResponse(value: any): value is OpenResponse { - return value != null && value.type === 'openResponse'; + return value != null && value.type === 'openResponse'; } /** * Returns true if value is a valid OpenResponse. This checks the type against the json schema for the message and will be slower */ export function isValidOpenResponse(value: any): value is OpenResponse { - try { - Convert.openResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.openResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const OPEN_RESPONSE_TYPE = "OpenResponse"; +export const OPEN_RESPONSE_TYPE = 'OpenResponse'; /** * Returns true if the value has a type property with value 'privateChannelAddEventListenerRequest'. This is a fast check that does not check the format of the message */ export function isPrivateChannelAddEventListenerRequest(value: any): value is PrivateChannelAddEventListenerRequest { - return value != null && value.type === 'privateChannelAddEventListenerRequest'; + return value != null && value.type === 'privateChannelAddEventListenerRequest'; } /** * Returns true if value is a valid PrivateChannelAddEventListenerRequest. This checks the type against the json schema for the message and will be slower */ -export function isValidPrivateChannelAddEventListenerRequest(value: any): value is PrivateChannelAddEventListenerRequest { - try { - Convert.privateChannelAddEventListenerRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidPrivateChannelAddEventListenerRequest( + value: any +): value is PrivateChannelAddEventListenerRequest { + try { + Convert.privateChannelAddEventListenerRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_ADD_EVENT_LISTENER_REQUEST_TYPE = "PrivateChannelAddEventListenerRequest"; +export const PRIVATE_CHANNEL_ADD_EVENT_LISTENER_REQUEST_TYPE = 'PrivateChannelAddEventListenerRequest'; /** * Returns true if the value has a type property with value 'privateChannelAddEventListenerResponse'. This is a fast check that does not check the format of the message */ export function isPrivateChannelAddEventListenerResponse(value: any): value is PrivateChannelAddEventListenerResponse { - return value != null && value.type === 'privateChannelAddEventListenerResponse'; + return value != null && value.type === 'privateChannelAddEventListenerResponse'; } /** * Returns true if value is a valid PrivateChannelAddEventListenerResponse. This checks the type against the json schema for the message and will be slower */ -export function isValidPrivateChannelAddEventListenerResponse(value: any): value is PrivateChannelAddEventListenerResponse { - try { - Convert.privateChannelAddEventListenerResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidPrivateChannelAddEventListenerResponse( + value: any +): value is PrivateChannelAddEventListenerResponse { + try { + Convert.privateChannelAddEventListenerResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_ADD_EVENT_LISTENER_RESPONSE_TYPE = "PrivateChannelAddEventListenerResponse"; +export const PRIVATE_CHANNEL_ADD_EVENT_LISTENER_RESPONSE_TYPE = 'PrivateChannelAddEventListenerResponse'; /** * Returns true if the value has a type property with value 'privateChannelDisconnectRequest'. This is a fast check that does not check the format of the message */ export function isPrivateChannelDisconnectRequest(value: any): value is PrivateChannelDisconnectRequest { - return value != null && value.type === 'privateChannelDisconnectRequest'; + return value != null && value.type === 'privateChannelDisconnectRequest'; } /** * Returns true if value is a valid PrivateChannelDisconnectRequest. This checks the type against the json schema for the message and will be slower */ export function isValidPrivateChannelDisconnectRequest(value: any): value is PrivateChannelDisconnectRequest { - try { - Convert.privateChannelDisconnectRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.privateChannelDisconnectRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_DISCONNECT_REQUEST_TYPE = "PrivateChannelDisconnectRequest"; +export const PRIVATE_CHANNEL_DISCONNECT_REQUEST_TYPE = 'PrivateChannelDisconnectRequest'; /** * Returns true if the value has a type property with value 'privateChannelDisconnectResponse'. This is a fast check that does not check the format of the message */ export function isPrivateChannelDisconnectResponse(value: any): value is PrivateChannelDisconnectResponse { - return value != null && value.type === 'privateChannelDisconnectResponse'; + return value != null && value.type === 'privateChannelDisconnectResponse'; } /** * Returns true if value is a valid PrivateChannelDisconnectResponse. This checks the type against the json schema for the message and will be slower */ export function isValidPrivateChannelDisconnectResponse(value: any): value is PrivateChannelDisconnectResponse { - try { - Convert.privateChannelDisconnectResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.privateChannelDisconnectResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_DISCONNECT_RESPONSE_TYPE = "PrivateChannelDisconnectResponse"; +export const PRIVATE_CHANNEL_DISCONNECT_RESPONSE_TYPE = 'PrivateChannelDisconnectResponse'; /** * Returns true if the value has a type property with value 'privateChannelOnAddContextListenerEvent'. This is a fast check that does not check the format of the message */ -export function isPrivateChannelOnAddContextListenerEvent(value: any): value is PrivateChannelOnAddContextListenerEvent { - return value != null && value.type === 'privateChannelOnAddContextListenerEvent'; +export function isPrivateChannelOnAddContextListenerEvent( + value: any +): value is PrivateChannelOnAddContextListenerEvent { + return value != null && value.type === 'privateChannelOnAddContextListenerEvent'; } /** * Returns true if value is a valid PrivateChannelOnAddContextListenerEvent. This checks the type against the json schema for the message and will be slower */ -export function isValidPrivateChannelOnAddContextListenerEvent(value: any): value is PrivateChannelOnAddContextListenerEvent { - try { - Convert.privateChannelOnAddContextListenerEventToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidPrivateChannelOnAddContextListenerEvent( + value: any +): value is PrivateChannelOnAddContextListenerEvent { + try { + Convert.privateChannelOnAddContextListenerEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_ON_ADD_CONTEXT_LISTENER_EVENT_TYPE = "PrivateChannelOnAddContextListenerEvent"; +export const PRIVATE_CHANNEL_ON_ADD_CONTEXT_LISTENER_EVENT_TYPE = 'PrivateChannelOnAddContextListenerEvent'; /** * Returns true if the value has a type property with value 'privateChannelOnDisconnectEvent'. This is a fast check that does not check the format of the message */ export function isPrivateChannelOnDisconnectEvent(value: any): value is PrivateChannelOnDisconnectEvent { - return value != null && value.type === 'privateChannelOnDisconnectEvent'; + return value != null && value.type === 'privateChannelOnDisconnectEvent'; } /** * Returns true if value is a valid PrivateChannelOnDisconnectEvent. This checks the type against the json schema for the message and will be slower */ export function isValidPrivateChannelOnDisconnectEvent(value: any): value is PrivateChannelOnDisconnectEvent { - try { - Convert.privateChannelOnDisconnectEventToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.privateChannelOnDisconnectEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_ON_DISCONNECT_EVENT_TYPE = "PrivateChannelOnDisconnectEvent"; +export const PRIVATE_CHANNEL_ON_DISCONNECT_EVENT_TYPE = 'PrivateChannelOnDisconnectEvent'; /** * Returns true if the value has a type property with value 'privateChannelOnUnsubscribeEvent'. This is a fast check that does not check the format of the message */ export function isPrivateChannelOnUnsubscribeEvent(value: any): value is PrivateChannelOnUnsubscribeEvent { - return value != null && value.type === 'privateChannelOnUnsubscribeEvent'; + return value != null && value.type === 'privateChannelOnUnsubscribeEvent'; } /** * Returns true if value is a valid PrivateChannelOnUnsubscribeEvent. This checks the type against the json schema for the message and will be slower */ export function isValidPrivateChannelOnUnsubscribeEvent(value: any): value is PrivateChannelOnUnsubscribeEvent { - try { - Convert.privateChannelOnUnsubscribeEventToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.privateChannelOnUnsubscribeEventToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_ON_UNSUBSCRIBE_EVENT_TYPE = "PrivateChannelOnUnsubscribeEvent"; +export const PRIVATE_CHANNEL_ON_UNSUBSCRIBE_EVENT_TYPE = 'PrivateChannelOnUnsubscribeEvent'; /** * Returns true if the value has a type property with value 'privateChannelUnsubscribeEventListenerRequest'. This is a fast check that does not check the format of the message */ -export function isPrivateChannelUnsubscribeEventListenerRequest(value: any): value is PrivateChannelUnsubscribeEventListenerRequest { - return value != null && value.type === 'privateChannelUnsubscribeEventListenerRequest'; +export function isPrivateChannelUnsubscribeEventListenerRequest( + value: any +): value is PrivateChannelUnsubscribeEventListenerRequest { + return value != null && value.type === 'privateChannelUnsubscribeEventListenerRequest'; } /** * Returns true if value is a valid PrivateChannelUnsubscribeEventListenerRequest. This checks the type against the json schema for the message and will be slower */ -export function isValidPrivateChannelUnsubscribeEventListenerRequest(value: any): value is PrivateChannelUnsubscribeEventListenerRequest { - try { - Convert.privateChannelUnsubscribeEventListenerRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidPrivateChannelUnsubscribeEventListenerRequest( + value: any +): value is PrivateChannelUnsubscribeEventListenerRequest { + try { + Convert.privateChannelUnsubscribeEventListenerRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_UNSUBSCRIBE_EVENT_LISTENER_REQUEST_TYPE = "PrivateChannelUnsubscribeEventListenerRequest"; +export const PRIVATE_CHANNEL_UNSUBSCRIBE_EVENT_LISTENER_REQUEST_TYPE = 'PrivateChannelUnsubscribeEventListenerRequest'; /** * Returns true if the value has a type property with value 'privateChannelUnsubscribeEventListenerResponse'. This is a fast check that does not check the format of the message */ -export function isPrivateChannelUnsubscribeEventListenerResponse(value: any): value is PrivateChannelUnsubscribeEventListenerResponse { - return value != null && value.type === 'privateChannelUnsubscribeEventListenerResponse'; +export function isPrivateChannelUnsubscribeEventListenerResponse( + value: any +): value is PrivateChannelUnsubscribeEventListenerResponse { + return value != null && value.type === 'privateChannelUnsubscribeEventListenerResponse'; } /** * Returns true if value is a valid PrivateChannelUnsubscribeEventListenerResponse. This checks the type against the json schema for the message and will be slower */ -export function isValidPrivateChannelUnsubscribeEventListenerResponse(value: any): value is PrivateChannelUnsubscribeEventListenerResponse { - try { - Convert.privateChannelUnsubscribeEventListenerResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } +export function isValidPrivateChannelUnsubscribeEventListenerResponse( + value: any +): value is PrivateChannelUnsubscribeEventListenerResponse { + try { + Convert.privateChannelUnsubscribeEventListenerResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const PRIVATE_CHANNEL_UNSUBSCRIBE_EVENT_LISTENER_RESPONSE_TYPE = "PrivateChannelUnsubscribeEventListenerResponse"; +export const PRIVATE_CHANNEL_UNSUBSCRIBE_EVENT_LISTENER_RESPONSE_TYPE = + 'PrivateChannelUnsubscribeEventListenerResponse'; /** * Returns true if the value has a type property with value 'raiseIntentForContextRequest'. This is a fast check that does not check the format of the message */ export function isRaiseIntentForContextRequest(value: any): value is RaiseIntentForContextRequest { - return value != null && value.type === 'raiseIntentForContextRequest'; + return value != null && value.type === 'raiseIntentForContextRequest'; } /** * Returns true if value is a valid RaiseIntentForContextRequest. This checks the type against the json schema for the message and will be slower */ export function isValidRaiseIntentForContextRequest(value: any): value is RaiseIntentForContextRequest { - try { - Convert.raiseIntentForContextRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.raiseIntentForContextRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const RAISE_INTENT_FOR_CONTEXT_REQUEST_TYPE = "RaiseIntentForContextRequest"; +export const RAISE_INTENT_FOR_CONTEXT_REQUEST_TYPE = 'RaiseIntentForContextRequest'; /** * Returns true if the value has a type property with value 'raiseIntentForContextResponse'. This is a fast check that does not check the format of the message */ export function isRaiseIntentForContextResponse(value: any): value is RaiseIntentForContextResponse { - return value != null && value.type === 'raiseIntentForContextResponse'; + return value != null && value.type === 'raiseIntentForContextResponse'; } /** * Returns true if value is a valid RaiseIntentForContextResponse. This checks the type against the json schema for the message and will be slower */ export function isValidRaiseIntentForContextResponse(value: any): value is RaiseIntentForContextResponse { - try { - Convert.raiseIntentForContextResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.raiseIntentForContextResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const RAISE_INTENT_FOR_CONTEXT_RESPONSE_TYPE = "RaiseIntentForContextResponse"; +export const RAISE_INTENT_FOR_CONTEXT_RESPONSE_TYPE = 'RaiseIntentForContextResponse'; /** * Returns true if the value has a type property with value 'raiseIntentRequest'. This is a fast check that does not check the format of the message */ export function isRaiseIntentRequest(value: any): value is RaiseIntentRequest { - return value != null && value.type === 'raiseIntentRequest'; + return value != null && value.type === 'raiseIntentRequest'; } /** * Returns true if value is a valid RaiseIntentRequest. This checks the type against the json schema for the message and will be slower */ export function isValidRaiseIntentRequest(value: any): value is RaiseIntentRequest { - try { - Convert.raiseIntentRequestToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.raiseIntentRequestToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const RAISE_INTENT_REQUEST_TYPE = "RaiseIntentRequest"; +export const RAISE_INTENT_REQUEST_TYPE = 'RaiseIntentRequest'; /** * Returns true if the value has a type property with value 'raiseIntentResponse'. This is a fast check that does not check the format of the message */ export function isRaiseIntentResponse(value: any): value is RaiseIntentResponse { - return value != null && value.type === 'raiseIntentResponse'; + return value != null && value.type === 'raiseIntentResponse'; } /** * Returns true if value is a valid RaiseIntentResponse. This checks the type against the json schema for the message and will be slower */ export function isValidRaiseIntentResponse(value: any): value is RaiseIntentResponse { - try { - Convert.raiseIntentResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.raiseIntentResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const RAISE_INTENT_RESPONSE_TYPE = "RaiseIntentResponse"; +export const RAISE_INTENT_RESPONSE_TYPE = 'RaiseIntentResponse'; /** * Returns true if the value has a type property with value 'raiseIntentResultResponse'. This is a fast check that does not check the format of the message */ export function isRaiseIntentResultResponse(value: any): value is RaiseIntentResultResponse { - return value != null && value.type === 'raiseIntentResultResponse'; + return value != null && value.type === 'raiseIntentResultResponse'; } /** * Returns true if value is a valid RaiseIntentResultResponse. This checks the type against the json schema for the message and will be slower */ export function isValidRaiseIntentResultResponse(value: any): value is RaiseIntentResultResponse { - try { - Convert.raiseIntentResultResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const RAISE_INTENT_RESULT_RESPONSE_TYPE = "RaiseIntentResultResponse"; - -/** - * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - return value != null && value.type === 'WCP1Hello'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - try { - Convert.webConnectionProtocol1HelloToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = "WebConnectionProtocol1Hello"; - -/** - * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - return value != null && value.type === 'WCP2LoadUrl'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - try { - Convert.webConnectionProtocol2LoadURLToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = "WebConnectionProtocol2LoadURL"; - -/** - * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - return value != null && value.type === 'WCP3Handshake'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - try { - Convert.webConnectionProtocol3HandshakeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = "WebConnectionProtocol3Handshake"; - -/** - * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { - return value != null && value.type === 'WCP4ValidateAppIdentity'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol4ValidateAppIdentity(value: any): value is WebConnectionProtocol4ValidateAppIdentity { - try { - Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = "WebConnectionProtocol4ValidateAppIdentity"; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentityFailedResponse"; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse(value: any): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = "WebConnectionProtocol5ValidateAppIdentitySuccessResponse"; - -/** - * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - return value != null && value.type === 'WCP6Goodbye'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - try { - Convert.webConnectionProtocol6GoodbyeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = "WebConnectionProtocol6Goodbye"; - -/** - * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { - try { - Convert.webConnectionProtocolMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } + try { + Convert.raiseIntentResultResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } } -export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = "WebConnectionProtocolMessage"; +export const RAISE_INTENT_RESULT_RESPONSE_TYPE = 'RaiseIntentResultResponse'; From f2b1b1d8509d4829554bc22d092c47c56f8806e3 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 18 Dec 2024 14:14:05 +0000 Subject: [PATCH 59/90] Note on wtfnode use --- .../fdc3-get-agent/test/step-definitions/port-creation.steps.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts index c686f859a..0b8a69942 100644 --- a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts @@ -1,6 +1,8 @@ import { Given, Then } from '@cucumber/cucumber'; import { CustomWorld } from '../world'; import { handleResolve } from '@kite9/testing'; +// used to debug tests not ending - only availabel as a commonJs module +// eslint-disable-next-line @typescript-eslint/no-require-imports const wtf = require('wtfnode'); Given( From 10aba7f623c2e2629789fbaf9b4e1a26ebafe8ba Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 19 Dec 2024 12:44:06 +0000 Subject: [PATCH 60/90] Update packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts --- packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index b4c52220f..8db44bfed 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -177,7 +177,7 @@ export class DefaultIntentSupport implements IntentSupport { ); throwIfUndefined( - response.payload.error ?? response.payload.appIntents ?? response.payload.intentResolution, + response.payload.appIntents ?? response.payload.intentResolution, 'Invalid response from Desktop Agent to raiseIntentForContext!', response, ResolveError.NoAppsFound From 1ec12371c9cc626932242b1fc7e2561bebefa020 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 19 Dec 2024 15:40:57 +0000 Subject: [PATCH 61/90] Resolving comments from Rob's review --- .../src/channels/DefaultChannelSupport.ts | 13 +- .../src/intents/DefaultIntentSupport.ts | 8 +- .../src/listeners/AbstractListener.ts | 16 +- .../listeners/PrivateChannelEventListener.ts | 4 +- packages/fdc3-agent-proxy/src/util.ts | 2 +- .../test/features/utils.feature | 6 + .../test/step-definitions/util.steps.ts | 63 + .../src/strategies/HelloHandler.ts | 30 +- .../fdc3-get-agent/src/strategies/getAgent.ts | 5 +- .../features/desktop-agent-strategy.feature | 15 + .../fdc3-schema/generated/api/BrowserTypes.ts | 5318 ++++++++--------- .../reference-ui/src/intent_resolver.ts | 23 +- 12 files changed, 2799 insertions(+), 2704 deletions(-) create mode 100644 packages/fdc3-agent-proxy/test/features/utils.feature create mode 100644 packages/fdc3-agent-proxy/test/step-definitions/util.steps.ts diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index 4bd240500..ae49155d9 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -65,6 +65,14 @@ export class DefaultChannelSupport implements ChannelSupport { payload: {}, }; const response = await this.messaging.exchange(request, 'getCurrentChannelResponse'); + + throwIfUndefined( + response.payload.channel, + 'Invalid response from Desktop Agent to getCurrentChannel (channel should be explicitly null if no channel is set)!', + response, + ChannelError.NoChannelFound + ); + //handle successful responses - errors will already have been thrown by exchange above if (response.payload.channel) { return new DefaultChannel( @@ -77,10 +85,7 @@ export class DefaultChannelSupport implements ChannelSupport { //this is a valid response if no channel is set return null; } else { - console.warn( - 'Invalid response from Desktop Agent to getCurrentChannel (channel should be explicitly null if no channel is set)!', - response.payload - ); + //Should not reach here as we will throw in exchange or throwIfNotFound return null; } } diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index 8db44bfed..f3cb392cd 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -154,8 +154,8 @@ export class DefaultIntentSupport implements IntentSupport { const details = response.payload.intentResolution; return new DefaultIntentResolution(this.messaging, resultPromise, details.source, details.intent); } else { - //Should never get here as we will throw above - throw new Error(response.payload.error); + //Should never get here as we will throw in exchange or throwIfUndefined above + throw new Error(response.payload.error ?? 'Unexpected error processing raiseIntent'); } } @@ -199,8 +199,8 @@ export class DefaultIntentSupport implements IntentSupport { const details = response.payload.intentResolution; return new DefaultIntentResolution(this.messaging, resultPromise, details.source, details.intent); } else { - //should never get here as we will throw above - throw new Error(response.payload.error); + //Should never get here as we will throw in exchange or throwIfUndefined above + throw new Error(response.payload.error ?? 'Unexpected error processing raiseIntentForContext'); } } diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 297cc9694..237bafda2 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -19,6 +19,8 @@ import { } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Messaging } from '../Messaging'; import { RegisterableListener } from './RegisterableListener'; +import { throwIfUndefined } from '../util'; +import { ChannelError } from '@kite9/fdc3-standard'; type SubscriptionRequest = | AddContextListenerRequest @@ -104,12 +106,14 @@ export abstract class AbstractListener impleme const response = await this.messaging.exchange(subscribeMessage, this.subscribeResponseType); this.id = response?.payload?.listenerUUID ?? null; - if (!this.id) { - console.error( - "The Desktop Agent's response did not include a listenerUUID, which will mean this listener can't be removed!", - response - ); - } + //coalesce so that nullish values become undefined + throwIfUndefined( + this.id ?? undefined, + "The Desktop Agent's response did not include a listenerUUID, which will mean this listener can't be removed!", + response, + ChannelError.CreationFailed + ); + this.messaging.register(this); } } diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index 7b65cc93e..36be45630 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -133,7 +133,7 @@ export class PrivateChannelAddContextEventListener extends AbstractPrivateChanne }; handler(event); } else { - console.error('PrivateChannelDisconnectEventListener was called for a different message type!', msg); + console.error('PrivateChannelAddContextEventListener was called for a different message type!', msg); } }; super(messaging, channelId, ['privateChannelOnAddContextListenerEvent'], 'addContextListener', wrappedHandler); @@ -150,7 +150,7 @@ export class PrivateChannelUnsubscribeEventListener extends AbstractPrivateChann }; handler(event); } else { - console.error('PrivateChannelDisconnectEventListener was called for a different message type!', msg); + console.error('PrivateChannelUnsubscribeEventListener was called for a different message type!', msg); } }; super(messaging, channelId, ['privateChannelOnUnsubscribeEvent'], 'unsubscribe', wrappedHandler); diff --git a/packages/fdc3-agent-proxy/src/util.ts b/packages/fdc3-agent-proxy/src/util.ts index f9aae72f4..43ab41872 100644 --- a/packages/fdc3-agent-proxy/src/util.ts +++ b/packages/fdc3-agent-proxy/src/util.ts @@ -14,7 +14,7 @@ export const throwIfUndefined = ( absentError: ErrorMessages ): void => { if (property === undefined) { - console.error(absentMessage, message); + console.error(absentMessage, '\nDACP message that resulted in the undefined property: ', message); throw new Error(absentError); } }; diff --git a/packages/fdc3-agent-proxy/test/features/utils.feature b/packages/fdc3-agent-proxy/test/features/utils.feature new file mode 100644 index 000000000..36ac80faa --- /dev/null +++ b/packages/fdc3-agent-proxy/test/features/utils.feature @@ -0,0 +1,6 @@ +Feature: Utility functions + + Scenario: throwIfUndefined is used to check properties + When I call throwIfUndefined it throws if a specified property is not defined + And I call throwIfUndefined it does NOT throw if a specified property IS defined + \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/test/step-definitions/util.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/util.steps.ts new file mode 100644 index 000000000..a2ecc16bd --- /dev/null +++ b/packages/fdc3-agent-proxy/test/step-definitions/util.steps.ts @@ -0,0 +1,63 @@ +import { When } from '@cucumber/cucumber'; +import { CustomWorld } from '../world'; +import { throwIfUndefined } from '../../src/util'; +import { AgentResponseMessage } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { OpenError } from '@kite9/fdc3-standard'; +import expect from 'expect'; + +When('I call throwIfUndefined it throws if a specified property is not defined', async function (this: CustomWorld) { + let thrown: Error | null = null; + const someObject: Record = { someProperty: 'value' }; + const dummyMessage: AgentResponseMessage = { + type: 'broadcastResponse', + meta: { + requestUuid: '123', + responseUuid: '456', + timestamp: new Date(), + }, + payload: {}, + }; + try { + throwIfUndefined( + someObject.nonExistent, + 'Deliberately undefined prop did not exist ;-)', + dummyMessage, + OpenError.MalformedContext + ); + } catch (e) { + thrown = e as Error; + } + + expect(thrown).not.toBeNull(); + //should be an error object, with the message we passed in + expect(thrown?.message).toEqual(OpenError.MalformedContext); +}); + +When( + 'I call throwIfUndefined it does NOT throw if a specified property IS defined', + async function (this: CustomWorld) { + let thrown: Error | null = null; + const someObject: Record = { someProperty: 'value' }; + const dummyMessage: AgentResponseMessage = { + type: 'broadcastResponse', + meta: { + requestUuid: '123', + responseUuid: '456', + timestamp: new Date(), + }, + payload: {}, + }; + try { + throwIfUndefined( + someObject.someProperty, + 'Deliberately undefined prop did not exist ;-)', + dummyMessage, + OpenError.MalformedContext + ); + } catch (e) { + thrown = e as Error; + } + + expect(thrown).toBeNull(); + } +); diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index 69273baeb..940de4bb8 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -79,32 +79,34 @@ export class HelloHandler { this.agentUrl = url; // create a new one - const ifrm = document.createElement('iframe'); + const iframe = document.createElement('iframe'); //Wait for the iframe to load... then send it a hello message - ifrm.addEventListener('load', () => { - if (ifrm.contentWindow) { + iframe.addEventListener('load', () => { + if (iframe.contentWindow) { Logger.debug('Sending hello message to communication iframe'); - this.sendWCP1Hello(ifrm.contentWindow, '*'); + this.sendWCP1Hello(iframe.contentWindow, '*'); } else { - Logger.error('iframe does not have a contentWindow, despite firing its load event!'); + throw new Error( + `An iframe (url: ${url}) added to support communication with a Desktop Agent does not have a contentWindow, despite firing its load event!` + ); } }); - ifrm.setAttribute('src', url); - ifrm.setAttribute('id', IFRAME_ID); - ifrm.setAttribute('name', 'FDC3 Communications'); - ifrm.style.width = '0px'; - ifrm.style.height = '0px'; - ifrm.style.border = '0'; - ifrm.style.position = 'fixed'; + iframe.setAttribute('src', url); + iframe.setAttribute('id', IFRAME_ID); + iframe.setAttribute('name', 'FDC3 Communications'); + iframe.style.width = '0px'; + iframe.style.height = '0px'; + iframe.style.border = '0'; + iframe.style.position = 'fixed'; - document.body.appendChild(ifrm); + document.body.appendChild(iframe); } /** Listen for WCP responses from 'parent' windows and frames and handle them. * Resolves when a response is received. - * @returns A Promise resolving to a set of connectiondetails + * @returns A Promise resolving to a set of ConnectionDetails */ listenForHelloResponses(): Promise { return new Promise(resolve => { diff --git a/packages/fdc3-get-agent/src/strategies/getAgent.ts b/packages/fdc3-get-agent/src/strategies/getAgent.ts index b9bb9773a..d5ec2ab41 100644 --- a/packages/fdc3-get-agent/src/strategies/getAgent.ts +++ b/packages/fdc3-get-agent/src/strategies/getAgent.ts @@ -33,10 +33,6 @@ export function clearAgentPromise() { theAgentPromise = null; } -export function getAgentPromise(): Promise | null { - return theAgentPromise; -} - function initAgentPromise(options: GetAgentParams): Promise { Logger.log(`Initiating Desktop Agent discovery at ${new Date().toISOString()}`); let strategies: Loader[]; @@ -64,6 +60,7 @@ function initAgentPromise(options: GetAgentParams): Promise { strategies = []; break; default: + Logger.warn('Unexpected agentType value in SessionStorage, ignoring. Stored data:', persistedData); strategies = [new DesktopAgentPreloadLoader(), new PostMessageLoader()]; } } else { diff --git a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature index a28589efd..96913616b 100644 --- a/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature +++ b/packages/fdc3-get-agent/test/features/desktop-agent-strategy.feature @@ -371,6 +371,21 @@ Scenario: Latch to Desktop Agent Preload via SessionStorage which has gone away Then the promise "{theAPIPromise}" should resolve And "{result}" is an error with message "AgentNotFound" + Scenario: Ignore invalid agentType in SessionStorage + Here, we recover the details of the session from session storage, + but it has an invalid agentType field - the connection should still succeed. + Given A Dummy Desktop Agent in "dummy-api" + And SessionStorage contains instanceUuid "{instanceID}", appId "cucumber-app" with identityUrl "https://dummyOrigin.test/path" and agentType "SPOON" + And `window.fdc3` is injected into the runtime with the value in "{dummy-api}" + And I call fdc3Ready for a promise result + And I refer to "{result}" as "theAPIPromise" + Then the promise "{theAPIPromise}" should resolve + And I refer to "{result}" as "desktopAgent" + And I call "{desktopAgent}" with "getInfo" + Then "{result}" is an object with the following contents + | fdc3Version | appMetadata.appId | provider | + | 2.0 | cucumber-app | preload-provider | + Scenario: Nothing works and we timeout When I call getAgent for a promise result with the following options | dontSetWindowFdc3 | timeoutMs | intentResolver | channelSelector | diff --git a/packages/fdc3-schema/generated/api/BrowserTypes.ts b/packages/fdc3-schema/generated/api/BrowserTypes.ts index 5f7a047c1..7e2af2655 100644 --- a/packages/fdc3-schema/generated/api/BrowserTypes.ts +++ b/packages/fdc3-schema/generated/api/BrowserTypes.ts @@ -1,15 +1,7 @@ // To parse this data: // -// import { Convert, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceChannels, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse } from "./file"; +// import { Convert, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannels, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage } from "./file"; // -// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); -// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); -// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); -// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); -// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); -// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); -// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); -// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // const addContextListenerRequest = Convert.toAddContextListenerRequest(json); // const addContextListenerResponse = Convert.toAddContextListenerResponse(json); // const addEventListenerRequest = Convert.toAddEventListenerRequest(json); @@ -29,8 +21,8 @@ // const createPrivateChannelResponse = Convert.toCreatePrivateChannelResponse(json); // const eventListenerUnsubscribeRequest = Convert.toEventListenerUnsubscribeRequest(json); // const eventListenerUnsubscribeResponse = Convert.toEventListenerUnsubscribeResponse(json); -// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceChannels = Convert.toFdc3UserInterfaceChannels(json); +// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceDrag = Convert.toFdc3UserInterfaceDrag(json); // const fdc3UserInterfaceHandshake = Convert.toFdc3UserInterfaceHandshake(json); // const fdc3UserInterfaceHello = Convert.toFdc3UserInterfaceHello(json); @@ -83,552 +75,960 @@ // const raiseIntentRequest = Convert.toRaiseIntentRequest(json); // const raiseIntentResponse = Convert.toRaiseIntentResponse(json); // const raiseIntentResultResponse = Convert.toRaiseIntentResultResponse(json); +// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); +// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); +// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); +// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); +// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); +// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); +// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); +// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // // These functions will throw an error if the JSON doesn't // match the expected interface, even if the JSON is valid. /** - * Hello message sent by an application to a parent window or frame when attempting to - * establish connectivity to a Desktop Agent. + * A request to add a context listener to a specified Channel OR to the current user + * channel. Where the listener is added to the current user channel (channelId == null), and + * this app has already been added to a user channel, client code should make a subsequent + * request to get the current context of that channel for this listener and then call its + * handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1Hello { +export interface AddContextListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol1HelloPayload; + payload: AddContextListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'WCP1Hello'; + type: 'addContextListenerRequest'; } /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1HelloMeta { - connectionAttemptUuid: string; +export interface AddContextListenerRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + */ + source?: AppIdentifier; timestamp: Date; } /** - * The message payload, containing data pertaining to this connection step. + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. + * + * Details of the application instance that broadcast the context. + * + * The App resolution option chosen. + * + * Details of the application instance that raised the intent. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. */ -export interface WebConnectionProtocol1HelloPayload { +export interface AppIdentifier { /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. */ - actualUrl: string; + appId: string; /** - * A flag that may be used to indicate that a channel selector user interface is or is not - * required. Set to `false` if the app includes its own interface for selecting channels or - * does not work with user channels. + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. */ - channelSelector?: boolean; + desktopAgent?: string; /** - * The version of FDC3 API that the app supports. + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. */ - fdc3Version: string; + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface AddContextListenerRequestPayload { /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. + * The id of the channel to add the listener to or `null` indicating that it should listen + * to the current user channel (at the time of broadcast). */ - identityUrl: string; + channelId: null | string; /** - * A flag that may be used to indicate that an intent resolver is or is not required. Set to - * `false` if no intents, or only targeted intents, are raised. + * The type of context to listen for OR `null` indicating that it should listen to all + * context types. */ - intentResolver?: boolean; - [property: string]: any; + contextType: null | string; } /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Response from a Desktop Agent to an application requesting access to it indicating that - * it should load a specified URL into a hidden iframe in order to establish connectivity to - * a Desktop Agent. + * A response to a addContextListener request. Where the listener was added to the current + * user channel (channelId == null), and this app has already been added to a user channel, + * client code should make a subsequent request to get the current context of that channel + * for this listener and then call its handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol2LoadURL { +export interface AddContextListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: WebConnectionProtocol2LoadURLPayload; + payload: AddContextListenerResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP2LoadUrl'; + type: 'addContextListenerResponse'; } /** - * The message payload, containing data pertaining to this connection step. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ -export interface WebConnectionProtocol2LoadURLPayload { +export interface AddContextListenerResponseMeta { + requestUuid: string; + responseUuid: string; /** - * A URL which can be used to establish communication with the Desktop Agent, via loading - * the URL into an iframe and restarting the Web Connection protocol with the iframe as the - * target. + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. */ - iframeUrl: string; - [property: string]: any; + source?: AppIdentifier; + timestamp: Date; } /** - * Identifies the type of the connection step message. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ +export interface AddContextListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; +} /** - * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that - * should be used for subsequent communication steps. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface WebConnectionProtocol3Handshake { +export type PurpleError = 'AccessDenied' | 'CreationFailed' | 'MalformedContext' | 'NoChannelFound'; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to add an event listener for a specified event type to the Desktop Agent. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface AddEventListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol3HandshakePayload; + payload: AddEventListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'WCP3Handshake'; + type: 'addEventListenerRequest'; } /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface WebConnectionProtocol3HandshakePayload { - /** - * Indicates whether a channel selector user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the channel selector (as the - * Desktop Agent will handle it another way). - */ - channelSelectorUrl: boolean | string; - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; +export interface AddEventListenerRequestPayload { /** - * Indicates whether an intent resolver user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the intent resolver (as the - * Desktop Agent will handle it another way). + * The type of the event to be listened to or `null` to listen to all event types. */ - intentResolverUrl: boolean | string; + type: 'USER_CHANNEL_CHANGED' | null; } /** - * Identifies the type of the connection step message. + * The type of a (non-context and non-intent) event that may be received via the FDC3 API's + * addEventListener function. */ /** - * Identity Validation request from an app attempting to connect to a Desktop Agent. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to an addEventListener request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol4ValidateAppIdentity { +export interface AddEventListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol4ValidateAppIdentityPayload; + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: AddEventListenerResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP4ValidateAppIdentity'; + type: 'addEventListenerResponse'; } /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface WebConnectionProtocol4ValidateAppIdentityPayload { - /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. - */ - actualUrl: string; - /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. - */ - identityUrl: string; - /** - * If an application has previously connected to the Desktop Agent, it may specify its prior - * instance id and associated instance UUID to request the same same instance Id be assigned. - */ - instanceId?: string; - /** - * Instance UUID associated with the requested instanceId. - */ - instanceUuid?: string; +export interface AddEventListenerResponsePayload { + error?: ResponsePayloadError; + listenerUUID?: string; } /** - * Identifies the type of the connection step message. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + */ +export type ResponsePayloadError = + | 'AccessDenied' + | 'CreationFailed' + | 'MalformedContext' + | 'NoChannelFound' + | 'AppNotFound' + | 'AppTimeout' + | 'DesktopAgentNotFound' + | 'ErrorOnLaunch' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution' + | 'IntentHandlerRejected' + | 'NoResultReturned' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message sent by the Desktop Agent to an app if their identity validation fails. + * A request to add an Intent listener for a specified intent type. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { +export interface AddIntentListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; + payload: AddIntentListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'WCP5ValidateAppIdentityFailedResponse'; + type: 'addIntentListenerRequest'; } /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { - message?: string; +export interface AddIntentListenerRequestPayload { + /** + * The name of the intent to listen for. + */ + intent: string; } /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Message sent by the Desktop Agent to an app after successful identity validation. + * A response to a addIntentListener request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { +export interface AddIntentListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; + payload: PayloadObject; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP5ValidateAppIdentityResponse'; + type: 'addIntentListenerResponse'; } /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { - /** - * The appId that the app's identity was validated against. - */ - appId: string; - /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - */ - implementationMetadata: ImplementationMetadata; - /** - * The instance Id granted to the application by the Desktop Agent. - */ - instanceId: string; - /** - * Instance UUID associated with the instanceId granted, which may be used to retrieve the - * same instanceId if the app is reloaded or navigates. - */ - instanceUuid: string; +export interface PayloadObject { + error?: FluffyError; + listenerUUID?: string; + [property: string]: any; } /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - * - * Includes Metadata for the current application. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface ImplementationMetadata { - /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - */ - appMetadata: AppMetadata; - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; +export type FluffyError = + | 'MalformedContext' + | 'DesktopAgentNotFound' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution'; + +/** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ +export interface AgentEventMessageMeta { + eventUuid: string; + timestamp: Date; } /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - * - * Extends an `AppIdentifier`, describing an application or instance of an application, with - * additional descriptive metadata that is usually provided by an FDC3 App Directory that - * the Desktop Agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such - * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon - * and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the - * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export interface AppMetadata { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * A longer, multi-paragraph description for the application that could include markup. - */ - description?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; +export type EventMessageType = + | 'addEventListenerEvent' + | 'broadcastEvent' + | 'channelChangedEvent' + | 'heartbeatEvent' + | 'intentEvent' + | 'privateChannelOnAddContextListenerEvent' + | 'privateChannelOnDisconnectEvent' + | 'privateChannelOnUnsubscribeEvent'; + +/** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ +export interface AgentResponseMessageMeta { + requestUuid: string; + responseUuid: string; /** - * A list of icon URLs for the application that can be used to render UI elements. + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. */ - icons?: Icon[]; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. + source?: AppIdentifier; + timestamp: Date; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface AgentResponseMessageResponsePayload { + error?: ResponsePayloadError; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ +export type ResponseMessageType = + | 'addContextListenerResponse' + | 'addEventListenerResponse' + | 'addIntentListenerResponse' + | 'broadcastResponse' + | 'contextListenerUnsubscribeResponse' + | 'createPrivateChannelResponse' + | 'eventListenerUnsubscribeResponse' + | 'findInstancesResponse' + | 'findIntentResponse' + | 'findIntentsByContextResponse' + | 'getAppMetadataResponse' + | 'getCurrentChannelResponse' + | 'getCurrentContextResponse' + | 'getInfoResponse' + | 'getOrCreateChannelResponse' + | 'getUserChannelsResponse' + | 'intentListenerUnsubscribeResponse' + | 'intentResultResponse' + | 'joinUserChannelResponse' + | 'leaveCurrentChannelResponse' + | 'openResponse' + | 'privateChannelAddEventListenerResponse' + | 'privateChannelDisconnectResponse' + | 'privateChannelUnsubscribeEventListenerResponse' + | 'raiseIntentForContextResponse' + | 'raiseIntentResponse' + | 'raiseIntentResultResponse'; + +/** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ +export interface AppRequestMessageMeta { + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. */ - instanceId?: string; + source?: AppIdentifier; + timestamp: Date; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ +export type RequestMessageType = + | 'addContextListenerRequest' + | 'addEventListenerRequest' + | 'addIntentListenerRequest' + | 'broadcastRequest' + | 'contextListenerUnsubscribeRequest' + | 'createPrivateChannelRequest' + | 'eventListenerUnsubscribeRequest' + | 'findInstancesRequest' + | 'findIntentRequest' + | 'findIntentsByContextRequest' + | 'getAppMetadataRequest' + | 'getCurrentChannelRequest' + | 'getCurrentContextRequest' + | 'getInfoRequest' + | 'getOrCreateChannelRequest' + | 'getUserChannelsRequest' + | 'heartbeatAcknowledgementRequest' + | 'intentListenerUnsubscribeRequest' + | 'intentResultRequest' + | 'joinUserChannelRequest' + | 'leaveCurrentChannelRequest' + | 'openRequest' + | 'privateChannelAddEventListenerRequest' + | 'privateChannelDisconnectRequest' + | 'privateChannelUnsubscribeEventListenerRequest' + | 'raiseIntentForContextRequest' + | 'raiseIntentRequest'; + +/** + * An event message from the Desktop Agent to an app indicating that context has been + * broadcast on a channel it is listening to, or specifically to this app instance if it was + * launched via `fdc3.open` and context was passed. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface BroadcastEvent { /** - * An optional set of, implementation specific, metadata fields that can be used to - * disambiguate instances, such as a window title or screen position. Must only be set if - * `instanceId` is set. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - instanceMetadata?: { [key: string]: any }; + meta: BroadcastEventMeta; /** - * The 'friendly' app name. - * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now - * require an `AppIdentifier` wth `appId` set. - * Note that for display purposes the `title` field should be used, if set, in preference to - * this field. + * The message payload contains details of the event that the app is being notified about. + */ + payload: BroadcastEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'broadcastEvent'; +} + +/** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ +export interface BroadcastEventMeta { + eventUuid: string; + timestamp: Date; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface BroadcastEventPayload { + /** + * The Id of the channel that the broadcast was sent on. May be `null` if the context is + * being broadcast due to a call `fdc3.open` that passed context. + */ + channelId: null | string; + /** + * The context object that was broadcast. + */ + context: Context; + /** + * Details of the application instance that broadcast the context. + */ + originatingApp?: AppIdentifier; +} + +/** + * The context object that was broadcast. + * + * The context object that is to be broadcast. + * + * The context object passed with the raised intent. + * + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. + * + * The `fdc3.context` type defines the basic contract or "shape" for all data exchanged by + * FDC3 operations. As such, it is not really meant to be used on its own, but is imported + * by more specific type definitions (standardized or custom) to provide the structure and + * properties shared by all FDC3 context data types. + * + * The key element of FDC3 context types is their mandatory `type` property, which is used + * to identify what type of data the object represents, and what shape it has. + * + * The FDC3 context type, and all derived types, define the minimum set of fields a context + * data object of a particular type can be expected to have, but this can always be extended + * with custom fields as appropriate. + */ +export interface Context { + /** + * Context data objects may include a set of equivalent key-value pairs that can be used to + * help applications identify and look up the context type they receive in their own domain. + * The idea behind this design is that applications can provide as many equivalent + * identifiers to a target application as possible, e.g. an instrument may be represented by + * an ISIN, CUSIP or Bloomberg identifier. + * + * Identifiers do not make sense for all types of data, so the `id` property is therefore + * optional, but some derived types may choose to require at least one identifier. + * Identifier values SHOULD always be of type string. + */ + id?: { [key: string]: any }; + /** + * Context data objects may include a name property that can be used for more information, + * or display purposes. Some derived types may require the name object as mandatory, + * depending on use case. */ name?: string; /** - * The type of output returned for any intent specified during resolution. May express a - * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel - * that will receive a specified type (e.g. "channel"). + * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 + * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present + * to route shared context data appropriately. + * + * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data + * types they support in an FDC3 [App + * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery + * and routing. + * + * Standardized FDC3 context types have well-known `type` properties prefixed with the + * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and + * used by a particular organization, the convention is to prefix them with an + * organization-specific namespace, e.g. `blackrock.fund`. + * + * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more + * information about context data types. */ - resultType?: null | string; + type: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to broadcast context on a channel. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface BroadcastRequest { /** - * Images representing the app in common usage scenarios that can be used to render UI - * elements. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - screenshots?: Image[]; + meta: AddContextListenerRequestMeta; /** - * A more user-friendly application title that can be used to render UI elements. + * The message payload typically contains the arguments to FDC3 API functions. */ - title?: string; + payload: BroadcastRequestPayload; /** - * A tooltip for the application that can be used to render UI elements. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - tooltip?: string; + type: 'broadcastRequest'; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface BroadcastRequestPayload { /** - * The Version of the application. + * The Id of the Channel that the broadcast was sent on. */ - version?: string; + channelId: string; + /** + * The context object that is to be broadcast. + */ + context: Context; } /** - * Describes an Icon image that may be used to represent the application. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export interface Icon { + +/** + * A response to a request to broadcast context on a channel. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface BroadcastResponse { /** - * The icon dimension, formatted as `x`. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - size?: string; + meta: AddContextListenerResponseMeta; /** - * The icon url. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - src: string; + payload: BroadcastResponseResponsePayload; /** - * Icon media type. If not present the Desktop Agent may use the src file extension. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type?: string; + type: 'broadcastResponse'; } /** - * Describes an image file, typically a screenshot, that often represents the application in - * a common usage scenario. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Image { +export interface BroadcastResponseResponsePayload { + error?: ResponsePayloadError; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * An event message from the Desktop Agent to an app indicating that its current user + * channel has changed. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface ChannelChangedEvent { /** - * Caption for the image. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - label?: string; + meta: BroadcastEventMeta; /** - * The image dimension, formatted as `x`. + * The message payload contains details of the event that the app is being notified about. */ - size?: string; + payload: ChannelChangedEventPayload; /** - * The image url. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - src: string; + type: 'channelChangedEvent'; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface ChannelChangedEventPayload { /** - * Image media type. If not present the Desktop Agent may use the src file extension. + * The Id of the channel that the app was added to or `null` if it was removed from a + * channel. */ - type?: string; + newChannelId: null | string; } /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export interface OptionalFeatures { + +/** + * A request to unsubscribe a context listener. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface ContextListenerUnsubscribeRequest { /** - * Used to indicate whether the experimental Desktop Agent Bridging - * feature is implemented by the Desktop Agent. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - DesktopAgentBridging: boolean; + meta: AddContextListenerRequestMeta; /** - * Used to indicate whether the exposure of 'originating app metadata' for - * context and intent messages is supported by the Desktop Agent. + * The message payload typically contains the arguments to FDC3 API functions. */ - OriginatingAppMetadata: boolean; + payload: ContextListenerUnsubscribeRequestPayload; /** - * Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - UserChannelMembershipAPIs: boolean; + type: 'contextListenerUnsubscribeRequest'; } /** - * Identifies the type of the connection step message. + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface ContextListenerUnsubscribeRequestPayload { + listenerUUID: string; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the - * window or navigating). Desktop Agents should close the MessagePort after receiving this - * message, but retain instance details in case the application reconnects (e.g. after a - * navigation event). + * A response to a contextListenerUnsubscribe request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol6Goodbye { +export interface ContextListenerUnsubscribeResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'contextListenerUnsubscribeResponse'; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface CreatePrivateChannelRequest { + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: CreatePrivateChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'createPrivateChannelRequest'; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface CreatePrivateChannelRequestPayload {} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a createPrivateChannel request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface CreatePrivateChannelResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - meta: WebConnectionProtocol6GoodbyeMeta; + payload: CreatePrivateChannelResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP6Goodbye'; + type: 'createPrivateChannelResponse'; } /** - * Metadata for a Web Connection Protocol message. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface WebConnectionProtocol6GoodbyeMeta { - timestamp: Date; +export interface CreatePrivateChannelResponsePayload { + error?: PurpleError; + privateChannel?: Channel; } /** - * Identifies the type of the connection step message. + * Represents a context channel that applications can use to send and receive + * context data. + * + * Please note that There are differences in behavior when you interact with a + * User channel via the `DesktopAgent` interface and the `Channel` interface. + * Specifically, when 'joining' a User channel or adding a context listener + * when already joined to a channel via the `DesktopAgent` interface, existing + * context (matching the type of the context listener) on the channel is + * received by the context listener immediately. Whereas, when a context + * listener is added via the Channel interface, context is not received + * automatically, but may be retrieved manually via the `getCurrentContext()` + * function. */ +export interface Channel { + /** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + */ + displayMetadata?: DisplayMetadata; + /** + * Constant that uniquely identifies this channel. + */ + id: string; + /** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ + type: Type; +} /** - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + * + * A system channel will be global enough to have a presence across many apps. This gives us + * some hints + * to render them in a standard way. It is assumed it may have other properties too, but if + * it has these, + * this is their meaning. */ -export interface WebConnectionProtocolMessage { +export interface DisplayMetadata { /** - * Metadata for a Web Connection Protocol message. + * The color that should be associated within this channel when displaying this channel in a + * UI, e.g: `0xFF0000`. */ - meta: ConnectionStepMetadata; + color?: string; /** - * The message payload, containing data pertaining to this connection step. + * A URL of an image that can be used to display this channel. */ - payload?: { [key: string]: any }; + glyph?: string; /** - * Identifies the type of the connection step message. + * A user-readable name for this channel, e.g: `"Red"`. */ - type: ConnectionStepMessageType; + name?: string; } /** - * Metadata for a Web Connection Protocol message. + * Uniquely defines each channel type. + * Can be "user", "app" or "private". */ -export interface ConnectionStepMetadata { - timestamp: Date; - connectionAttemptUuid?: string; -} +export type Type = 'app' | 'private' | 'user'; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export type ConnectionStepMessageType = - | 'WCP1Hello' - | 'WCP2LoadUrl' - | 'WCP3Handshake' - | 'WCP4ValidateAppIdentity' - | 'WCP5ValidateAppIdentityFailedResponse' - | 'WCP5ValidateAppIdentityResponse' - | 'WCP6Goodbye'; /** - * A request to add a context listener to a specified Channel OR to the current user - * channel. Where the listener is added to the current user channel (channelId == null), and - * this app has already been added to a user channel, client code should make a subsequent - * request to get the current context of that channel for this listener and then call its - * handler with it. + * A request to unsubscribe an event listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface AddContextListenerRequest { +export interface EventListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -636,90 +1036,19 @@ export interface AddContextListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: AddContextListenerRequestPayload; + payload: EventListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'addContextListenerRequest'; -} - -/** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ -export interface AddContextListenerRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - * - * Details of the application instance that broadcast the context. - * - * The App resolution option chosen. - * - * Details of the application instance that raised the intent. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; + type: 'eventListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface AddContextListenerRequestPayload { - /** - * The id of the channel to add the listener to or `null` indicating that it should listen - * to the current user channel (at the time of broadcast). - */ - channelId: null | string; - /** - * The type of context to listen for OR `null` indicating that it should listen to all - * context types. - */ - contextType: null | string; +export interface EventListenerUnsubscribeRequestPayload { + listenerUUID: string; } /** @@ -728,15 +1057,12 @@ export interface AddContextListenerRequestPayload { */ /** - * A response to a addContextListener request. Where the listener was added to the current - * user channel (channelId == null), and this app has already been added to a user channel, - * client code should make a subsequent request to get the current context of that channel - * for this listener and then call its handler with it. + * A response to an eventListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface AddContextListenerResponse { +export interface EventListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -746,686 +1072,599 @@ export interface AddContextListenerResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: AddContextListenerResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'addContextListenerResponse'; + type: 'eventListenerUnsubscribeResponse'; } /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export interface AddContextListenerResponseMeta { - requestUuid: string; - responseUuid: string; - /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - */ - source?: AppIdentifier; - timestamp: Date; -} /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an + * iframe with the channel definitions and current channel selection. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddContextListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; +export interface Fdc3UserInterfaceChannels { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelsPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceChannels'; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). + * The message payload. */ -export type PurpleError = 'AccessDenied' | 'CreationFailed' | 'MalformedContext' | 'NoChannelFound'; +export interface Fdc3UserInterfaceChannelsPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; + /** + * User Channel definitions.```````s + */ + userChannels: Channel[]; +} /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A request to add an event listener for a specified event type to the Desktop Agent. + * Message from a channel selector UI to the DA proxy sent when the channel selection + * changes. * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AddEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceChannelSelected { /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ - payload: AddEventListenerRequestPayload; + payload: Fdc3UserInterfaceChannelSelectedPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addEventListenerRequest'; + type: 'Fdc3UserInterfaceChannelSelected'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface AddEventListenerRequestPayload { +export interface Fdc3UserInterfaceChannelSelectedPayload { /** - * The type of the event to be listened to or `null` to listen to all event types. + * The id of the channel that should be currently selected, or `null` if none should be + * selected. */ - type: 'USER_CHANNEL_CHANGED' | null; + selected: null | string; } /** - * The type of a (non-context and non-intent) event that may be received via the FDC3 API's - * addEventListener function. - */ - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A response to an addEventListener request. + * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user + * is dragging the UI to a new location and providing the offset to apply to the location. + * The DA proxy implementation should limit the location to the current bounds of the + * window's viewport. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface Fdc3UserInterfaceDrag { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ - payload: AddEventListenerResponsePayload; + payload: Fdc3UserInterfaceDragPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addEventListenerResponse'; + type: 'Fdc3UserInterfaceDrag'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ -export interface AddEventListenerResponsePayload { - error?: ResponsePayloadError; - listenerUUID?: string; +export interface Fdc3UserInterfaceDragPayload { + /** + * The offset to move the frame by. + */ + mouseOffsets: MouseOffsets; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). + * The offset to move the frame by. */ -export type ResponsePayloadError = - | 'AccessDenied' - | 'CreationFailed' - | 'MalformedContext' - | 'NoChannelFound' - | 'AppNotFound' - | 'AppTimeout' - | 'DesktopAgentNotFound' - | 'ErrorOnLaunch' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution' - | 'IntentHandlerRejected' - | 'NoResultReturned' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; +export interface MouseOffsets { + x: number; + y: number; +} /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A request to add an Intent listener for a specified intent type. + * Handshake message sent back to a user interface from the DA proxy code (setup by + * `getAgent()`) over the `MessagePort` provided in the preceding Fdc3UserInterfaceHello + * message, confirming that it is listening to the `MessagePort` for further communication. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddIntentListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; +export interface Fdc3UserInterfaceHandshake { /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ - payload: AddIntentListenerRequestPayload; + payload: Fdc3UserInterfaceHandshakePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addIntentListenerRequest'; + type: 'Fdc3UserInterfaceHandshake'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface AddIntentListenerRequestPayload { +export interface Fdc3UserInterfaceHandshakePayload { /** - * The name of the intent to listen for. + * The version of FDC3 API that the Desktop Agent will provide support for. */ - intent: string; + fdc3Version: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A response to a addIntentListener request. + * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate + * it is ready to communicate, containing initial CSS to set on the iframe, and including an + * appended `MessagePort` to be used for further communication. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddIntentListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface Fdc3UserInterfaceHello { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ - payload: PayloadObject; + payload: Fdc3UserInterfaceHelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addIntentListenerResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface PayloadObject { - error?: FluffyError; - listenerUUID?: string; - [property: string]: any; + type: 'Fdc3UserInterfaceHello'; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type FluffyError = - | 'MalformedContext' - | 'DesktopAgentNotFound' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution'; - -/** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The message payload. */ -export interface AgentEventMessageMeta { - eventUuid: string; - timestamp: Date; +export interface Fdc3UserInterfaceHelloPayload { + /** + * Details about the UI implementation, such as vendor and version, for logging purposes. + */ + implementationDetails: string; + /** + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + */ + initialCSS: InitialCSS; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ -export type EventMessageType = - | 'addEventListenerEvent' - | 'broadcastEvent' - | 'channelChangedEvent' - | 'heartbeatEvent' - | 'intentEvent' - | 'privateChannelOnAddContextListenerEvent' - | 'privateChannelOnDisconnectEvent' - | 'privateChannelOnUnsubscribeEvent'; - -/** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. */ -export interface AgentResponseMessageMeta { - requestUuid: string; - responseUuid: string; +export interface InitialCSS { + /** + * The initial bottom property to apply to the iframe. + */ + bottom?: string; + /** + * The initial height of the iframe. + */ + height?: string; + /** + * The initial left property to apply to the iframe. + */ + left?: string; + /** + * The maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. + * The transition property to apply to the iframe. */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface AgentResponseMessageResponsePayload { - error?: ResponsePayloadError; + transition?: string; + /** + * The initial width of the iframe. + */ + width?: string; + /** + * The initial zindex to apply to the iframe. + */ + zIndex?: string; [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ -export type ResponseMessageType = - | 'addContextListenerResponse' - | 'addEventListenerResponse' - | 'addIntentListenerResponse' - | 'broadcastResponse' - | 'contextListenerUnsubscribeResponse' - | 'createPrivateChannelResponse' - | 'eventListenerUnsubscribeResponse' - | 'findInstancesResponse' - | 'findIntentResponse' - | 'findIntentsByContextResponse' - | 'getAppMetadataResponse' - | 'getCurrentChannelResponse' - | 'getCurrentContextResponse' - | 'getInfoResponse' - | 'getOrCreateChannelResponse' - | 'getUserChannelsResponse' - | 'intentListenerUnsubscribeResponse' - | 'intentResultResponse' - | 'joinUserChannelResponse' - | 'leaveCurrentChannelResponse' - | 'openResponse' - | 'privateChannelAddEventListenerResponse' - | 'privateChannelDisconnectResponse' - | 'privateChannelUnsubscribeEventListenerResponse' - | 'raiseIntentForContextResponse' - | 'raiseIntentResponse' - | 'raiseIntentResultResponse'; /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AppRequestMessageMeta { - requestUuid: string; +export interface Fdc3UserInterfaceMessage { /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. + * The message payload. */ - source?: AppIdentifier; - timestamp: Date; + payload?: { [key: string]: any }; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: Fdc3UserInterfaceMessageType; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ -export type RequestMessageType = - | 'addContextListenerRequest' - | 'addEventListenerRequest' - | 'addIntentListenerRequest' - | 'broadcastRequest' - | 'contextListenerUnsubscribeRequest' - | 'createPrivateChannelRequest' - | 'eventListenerUnsubscribeRequest' - | 'findInstancesRequest' - | 'findIntentRequest' - | 'findIntentsByContextRequest' - | 'getAppMetadataRequest' - | 'getCurrentChannelRequest' - | 'getCurrentContextRequest' - | 'getInfoRequest' - | 'getOrCreateChannelRequest' - | 'getUserChannelsRequest' - | 'heartbeatAcknowledgementRequest' - | 'intentListenerUnsubscribeRequest' - | 'intentResultRequest' - | 'joinUserChannelRequest' - | 'leaveCurrentChannelRequest' - | 'openRequest' - | 'privateChannelAddEventListenerRequest' - | 'privateChannelDisconnectRequest' - | 'privateChannelUnsubscribeEventListenerRequest' - | 'raiseIntentForContextRequest' - | 'raiseIntentRequest'; +export type Fdc3UserInterfaceMessageType = + | 'Fdc3UserInterfaceHello' + | 'Fdc3UserInterfaceHandshake' + | 'Fdc3UserInterfaceRestyle' + | 'Fdc3UserInterfaceDrag' + | 'Fdc3UserInterfaceResolve' + | 'Fdc3UserInterfaceResolveAction' + | 'Fdc3UserInterfaceChannels' + | 'Fdc3UserInterfaceChannelSelected'; /** - * An event message from the Desktop Agent to an app indicating that context has been - * broadcast on a channel it is listening to, or specifically to this app instance if it was - * launched via `fdc3.open` and context was passed. + * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the + * resolver data to setup the UI. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface BroadcastEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; +export interface Fdc3UserInterfaceResolve { /** - * The message payload contains details of the event that the app is being notified about. + * The message payload. */ - payload: BroadcastEventPayload; + payload: Fdc3UserInterfaceResolvePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'broadcastEvent'; + type: 'Fdc3UserInterfaceResolve'; } /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The message payload. */ -export interface BroadcastEventMeta { - eventUuid: string; - timestamp: Date; +export interface Fdc3UserInterfaceResolvePayload { + /** + * An array of AppIntent objects defining the resolution options. + */ + appIntents: AppIntent[]; + context: Context; } /** - * The message payload contains details of the event that the app is being notified about. + * An interface that relates an intent to apps. + * + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. */ -export interface BroadcastEventPayload { - /** - * The Id of the channel that the broadcast was sent on. May be `null` if the context is - * being broadcast due to a call `fdc3.open` that passed context. - */ - channelId: null | string; +export interface AppIntent { /** - * The context object that was broadcast. + * Details of applications that can resolve the intent. */ - context: Context; + apps: AppMetadata[]; /** - * Details of the application instance that broadcast the context. + * Details of the intent whose relationship to resolving applications is being described. */ - originatingApp?: AppIdentifier; + intent: IntentMetadata; } /** - * The context object that was broadcast. - * - * The context object that is to be broadcast. - * - * The context object passed with the raised intent. - * - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. + * Extends an `AppIdentifier`, describing an application or instance of an application, with + * additional descriptive metadata that is usually provided by an FDC3 App Directory that + * the Desktop Agent connects to. * - * The `fdc3.context` type defines the basic contract or "shape" for all data exchanged by - * FDC3 operations. As such, it is not really meant to be used on its own, but is imported - * by more specific type definitions (standardized or custom) to provide the structure and - * properties shared by all FDC3 context data types. + * The additional information from an app directory can aid in rendering UI elements, such + * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon + * and screenshot URLs. * - * The key element of FDC3 context types is their mandatory `type` property, which is used - * to identify what type of data the object represents, and what shape it has. + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the + * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. * - * The FDC3 context type, and all derived types, define the minimum set of fields a context - * data object of a particular type can be expected to have, but this can always be extended - * with custom fields as appropriate. + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). */ -export interface Context { +export interface AppMetadata { /** - * Context data objects may include a set of equivalent key-value pairs that can be used to - * help applications identify and look up the context type they receive in their own domain. - * The idea behind this design is that applications can provide as many equivalent - * identifiers to a target application as possible, e.g. an instrument may be represented by - * an ISIN, CUSIP or Bloomberg identifier. - * - * Identifiers do not make sense for all types of data, so the `id` property is therefore - * optional, but some derived types may choose to require at least one identifier. - * Identifier values SHOULD always be of type string. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * A longer, multi-paragraph description for the application that could include markup. + */ + description?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * A list of icon URLs for the application that can be used to render UI elements. + */ + icons?: Icon[]; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + /** + * An optional set of, implementation specific, metadata fields that can be used to + * disambiguate instances, such as a window title or screen position. Must only be set if + * `instanceId` is set. + */ + instanceMetadata?: { [key: string]: any }; + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now + * require an `AppIdentifier` wth `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to + * this field. + */ + name?: string; + /** + * The type of output returned for any intent specified during resolution. May express a + * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel + * that will receive a specified type (e.g. "channel"). + */ + resultType?: null | string; + /** + * Images representing the app in common usage scenarios that can be used to render UI + * elements. + */ + screenshots?: Image[]; + /** + * A more user-friendly application title that can be used to render UI elements. */ - id?: { [key: string]: any }; + title?: string; /** - * Context data objects may include a name property that can be used for more information, - * or display purposes. Some derived types may require the name object as mandatory, - * depending on use case. + * A tooltip for the application that can be used to render UI elements. */ - name?: string; + tooltip?: string; /** - * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 - * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present - * to route shared context data appropriately. - * - * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data - * types they support in an FDC3 [App - * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery - * and routing. - * - * Standardized FDC3 context types have well-known `type` properties prefixed with the - * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and - * used by a particular organization, the convention is to prefix them with an - * organization-specific namespace, e.g. `blackrock.fund`. - * - * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more - * information about context data types. + * The Version of the application. */ - type: string; - [property: string]: any; + version?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to broadcast context on a channel. - * - * A request message from an FDC3-enabled app to a Desktop Agent. + * Describes an Icon image that may be used to represent the application. */ -export interface BroadcastRequest { +export interface Icon { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * The icon dimension, formatted as `x`. */ - meta: AddContextListenerRequestMeta; + size?: string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The icon url. */ - payload: BroadcastRequestPayload; + src: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Icon media type. If not present the Desktop Agent may use the src file extension. */ - type: 'broadcastRequest'; + type?: string; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. */ -export interface BroadcastRequestPayload { +export interface Image { /** - * The Id of the Channel that the broadcast was sent on. + * Caption for the image. */ - channelId: string; + label?: string; /** - * The context object that is to be broadcast. + * The image dimension, formatted as `x`. */ - context: Context; + size?: string; + /** + * The image url. + */ + src: string; + /** + * Image media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a request to broadcast context on a channel. + * Details of the intent whose relationship to resolving applications is being described. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * Metadata describing an Intent. */ -export interface BroadcastResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface IntentMetadata { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Display name for the intent. */ - payload: BroadcastResponseResponsePayload; + displayName?: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The unique name of the intent that can be invoked by the raiseIntent call. */ - type: 'broadcastResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface BroadcastResponseResponsePayload { - error?: ResponsePayloadError; - [property: string]: any; + name: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * An event message from the Desktop Agent to an app indicating that its current user - * channel has changed. + * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user + * action. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface ChannelChangedEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; +export interface Fdc3UserInterfaceResolveAction { /** - * The message payload contains details of the event that the app is being notified about. + * The message payload. */ - payload: ChannelChangedEventPayload; + payload: Fdc3UserInterfaceResolveActionPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'channelChangedEvent'; + type: 'Fdc3UserInterfaceResolveAction'; } /** - * The message payload contains details of the event that the app is being notified about. + * The message payload. */ -export interface ChannelChangedEventPayload { +export interface Fdc3UserInterfaceResolveActionPayload { + action: Action; /** - * The Id of the channel that the app was added to or `null` if it was removed from a - * channel. + * The App resolution option chosen. */ - newChannelId: null | string; + appIdentifier?: AppIdentifier; + /** + * The intent resolved. + */ + intent?: string; } +export type Action = 'hover' | 'click' | 'cancel'; + /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A request to unsubscribe a context listener. + * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling + * information to apply to it. Can be used to implement a pop-open or close interaction or + * other transition needed by a UI implementation. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface ContextListenerUnsubscribeRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; +export interface Fdc3UserInterfaceRestyle { /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ - payload: ContextListenerUnsubscribeRequestPayload; + payload: Fdc3UserInterfaceRestylePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'contextListenerUnsubscribeRequest'; + type: 'Fdc3UserInterfaceRestyle'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface ContextListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface Fdc3UserInterfaceRestylePayload { + /** + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. + */ + updatedCSS: UpdatedCSS; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a contextListenerUnsubscribe request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. */ -export interface ContextListenerUnsubscribeResponse { +export interface UpdatedCSS { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The initial bottom property to apply to the iframe. */ - meta: AddContextListenerResponseMeta; + bottom?: string; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The updated height of the iframe. */ - payload: BroadcastResponseResponsePayload; + height?: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The initial left property to apply to the iframe. */ - type: 'contextListenerUnsubscribeResponse'; + left?: string; + /** + * The updated maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The updated maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; + /** + * The updated transition property to apply to the iframe. + */ + transition?: string; + /** + * The updated width of the iframe. + */ + width?: string; + /** + * The updated zIndex to apply to the iframe. + */ + zIndex?: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * A request for details of instances of a particular app. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface CreatePrivateChannelRequest { +export interface FindInstancesRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -1433,18 +1672,20 @@ export interface CreatePrivateChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: CreatePrivateChannelRequestPayload; + payload: FindInstancesRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'createPrivateChannelRequest'; + type: 'findInstancesRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface CreatePrivateChannelRequestPayload {} +export interface FindInstancesRequestPayload { + app: AppIdentifier; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -1452,12 +1693,12 @@ export interface CreatePrivateChannelRequestPayload {} */ /** - * A response to a createPrivateChannel request. + * A response to a findInstances request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface CreatePrivateChannelResponse { +export interface FindInstancesResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -1467,88 +1708,67 @@ export interface CreatePrivateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: CreatePrivateChannelResponsePayload; + payload: FindInstancesResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'createPrivateChannelResponse'; + type: 'findInstancesResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - */ -export interface CreatePrivateChannelResponsePayload { - error?: PurpleError; - privateChannel?: Channel; -} - -/** - * Represents a context channel that applications can use to send and receive - * context data. * - * Please note that There are differences in behavior when you interact with a - * User channel via the `DesktopAgent` interface and the `Channel` interface. - * Specifically, when 'joining' a User channel or adding a context listener - * when already joined to a channel via the `DesktopAgent` interface, existing - * context (matching the type of the context listener) on the channel is - * received by the context listener immediately. Whereas, when a context - * listener is added via the Channel interface, context is not received - * automatically, but may be retrieved manually via the `getCurrentContext()` - * function. + * The message payload contains a flag indicating whether the API call was successful, plus + * any return values for the FDC3 API function called, or indicating that the request + * resulted in an error and including a standardized error message. */ -export interface Channel { - /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. - */ - displayMetadata?: DisplayMetadata; - /** - * Constant that uniquely identifies this channel. - */ - id: string; - /** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". - */ - type: Type; +export interface FindInstancesResponsePayload { + error?: FindInstancesErrors; + appIdentifiers?: AppMetadata[]; } /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * A system channel will be global enough to have a presence across many apps. This gives us - * some hints - * to render them in a standard way. It is assumed it may have other properties too, but if - * it has these, - * this is their meaning. - */ -export interface DisplayMetadata { - /** - * The color that should be associated within this channel when displaying this channel in a - * UI, e.g: `0xFF0000`. - */ - color?: string; - /** - * A URL of an image that can be used to display this channel. - */ - glyph?: string; - /** - * A user-readable name for this channel, e.g: `"Red"`. - */ - name?: string; -} - -/** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + * + * Unique identifier for a `listener` object returned by a Desktop Agent to an app in + * response to addContextListener, addIntentListener or one of the PrivateChannel event + * listeners and used to identify it in messages (e.g. when unsubscribing). + * + * Unique identifier for an event message sent from a Desktop Agent to an app. + * + * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID + * should be used in the first (WCP1Hello) message and should be quoted in all subsequent + * messages to link them to the same connection attempt. + * + * Should be set if the raiseIntent request returned an error. */ -export type Type = 'app' | 'private' | 'user'; +export type FindInstancesErrors = + | 'MalformedContext' + | 'DesktopAgentNotFound' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -1556,11 +1776,11 @@ export type Type = 'app' | 'private' | 'user'; */ /** - * A request to unsubscribe an event listener. + * A request for details of apps available to resolve a particular intent and context pair. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface EventListenerUnsubscribeRequest { +export interface FindIntentRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -1568,19 +1788,21 @@ export interface EventListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: EventListenerUnsubscribeRequestPayload; + payload: FindIntentRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'eventListenerUnsubscribeRequest'; + type: 'findIntentRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface EventListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface FindIntentRequestPayload { + context?: Context; + intent: string; + resultType?: string; } /** @@ -1589,12 +1811,12 @@ export interface EventListenerUnsubscribeRequestPayload { */ /** - * A response to an eventListenerUnsubscribe request. + * A response to a findIntent request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface EventListenerUnsubscribeResponse { +export interface FindIntentResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -1604,480 +1826,339 @@ export interface EventListenerUnsubscribeResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: FindIntentResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'eventListenerUnsubscribeResponse'; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * Message from a channel selector UI to the DA proxy sent when the channel selection - * changes. - * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. - */ -export interface Fdc3UserInterfaceChannelSelected { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceChannelSelectedPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: 'Fdc3UserInterfaceChannelSelected'; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceChannelSelectedPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; -} - -/** - * Identifies the type of the message to or from the user interface frame. - */ - -/** - * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an - * iframe with the channel definitions and current channel selection. - * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. - */ -export interface Fdc3UserInterfaceChannels { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceChannelsPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: 'Fdc3UserInterfaceChannels'; + type: 'findIntentResponse'; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceChannelsPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; - /** - * User Channel definitions.```````s - */ - userChannels: Channel[]; +export interface FindIntentResponsePayload { + error?: FindInstancesErrors; + appIntent?: AppIntent; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user - * is dragging the UI to a new location and providing the offset to apply to the location. - * The DA proxy implementation should limit the location to the current bounds of the - * window's viewport. + * A request for details of intents and apps available to resolve them for a particular + * context. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceDrag { +export interface FindIntentsByContextRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceDragPayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceDrag'; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceDragPayload { + payload: FindIntentsByContextRequestPayload; /** - * The offset to move the frame by. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - mouseOffsets: MouseOffsets; + type: 'findIntentsByContextRequest'; } /** - * The offset to move the frame by. - */ -export interface MouseOffsets { - x: number; - y: number; + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface FindIntentsByContextRequestPayload { + context: Context; + resultType?: string; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Handshake message sent back to a user interface from the DA proxy code (setup by - * `getAgent()`) over the `MessagePort` provide in the preceding iFrameHello message, - * confirming that it is listening to the `MessagePort` for further communication. + * A response to a findIntentsByContext request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceHandshake { +export interface FindIntentsByContextResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceHandshakePayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: 'Fdc3UserInterfaceHandshake'; + payload: FindIntentsByContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'findIntentsByContextResponse'; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceHandshakePayload { - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; +export interface FindIntentsByContextResponsePayload { + error?: FindInstancesErrors; + appIntents?: AppIntent[]; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate - * it is ready to communicate, containing initial CSS to set on the iframe, and including an - * appended `MessagePort` to be used for further communication. + * A request for metadata about an app. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceHello { +export interface GetAppMetadataRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceHelloPayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceHello'; + payload: GetAppMetadataRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getAppMetadataRequest'; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceHelloPayload { - /** - * Details about the UI implementation, such as vendor and version, for logging purposes. - */ - implementationDetails: string; - /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. - */ - initialCSS: InitialCSS; +export interface GetAppMetadataRequestPayload { + app: AppIdentifier; } /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export interface InitialCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The initial height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; + +/** + * A response to a getAppMetadata request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface GetAppMetadataResponse { /** - * The transition property to apply to the iframe. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - transition?: string; + meta: AddContextListenerResponseMeta; /** - * The initial width of the iframe. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - width?: string; + payload: GetAppMetadataResponsePayload; /** - * The initial zindex to apply to the iframe. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - zIndex?: string; - [property: string]: any; + type: 'getAppMetadataResponse'; } /** - * Identifies the type of the message to or from the user interface frame. - */ - -/** - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceMessage { - /** - * The message payload. - */ - payload?: { [key: string]: any }; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: Fdc3UserInterfaceMessageType; +export interface GetAppMetadataResponsePayload { + error?: FindInstancesErrors; + appMetadata?: AppMetadata; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export type Fdc3UserInterfaceMessageType = - | 'Fdc3UserInterfaceHello' - | 'Fdc3UserInterfaceHandshake' - | 'Fdc3UserInterfaceRestyle' - | 'Fdc3UserInterfaceDrag' - | 'Fdc3UserInterfaceResolve' - | 'Fdc3UserInterfaceResolveAction' - | 'Fdc3UserInterfaceChannels' - | 'Fdc3UserInterfaceChannelSelected'; /** - * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the - * resolver data to setup the UI. + * A request to return the Channel object for the current User channel membership. Returns + * `null` if the app is not joined to a channel. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceResolve { +export interface GetCurrentChannelRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceResolvePayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceResolve'; + payload: GetCurrentChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getCurrentChannelRequest'; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceResolvePayload { - /** - * An array of AppIntent objects defining the resolution options. - */ - appIntents: AppIntent[]; - context: Context; -} +export interface GetCurrentChannelRequestPayload {} /** - * An interface that relates an intent to apps. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a getCurrentChannel request. * - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface AppIntent { +export interface GetCurrentChannelResponse { /** - * Details of applications that can resolve the intent. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - apps: AppMetadata[]; + meta: AddContextListenerResponseMeta; /** - * Details of the intent whose relationship to resolving applications is being described. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - intent: IntentMetadata; + payload: GetCurrentChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getCurrentChannelResponse'; } /** - * Details of the intent whose relationship to resolving applications is being described. - * - * Metadata describing an Intent. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface IntentMetadata { - /** - * Display name for the intent. - */ - displayName?: string; - /** - * The unique name of the intent that can be invoked by the raiseIntent call. - */ - name: string; +export interface GetCurrentChannelResponsePayload { + error?: ResponsePayloadError; + channel?: Channel | null; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user - * action. + * A request to return the current context (either of a specified type or most recent + * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if + * one was specified) is available in the channel. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceResolveAction { +export interface GetCurrentContextRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceResolveActionPayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceResolveAction'; + payload: GetCurrentContextRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getCurrentContextRequest'; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceResolveActionPayload { - action: Action; +export interface GetCurrentContextRequestPayload { /** - * The App resolution option chosen. + * The id of the channel to return the current context of. */ - appIdentifier?: AppIdentifier; + channelId: string; /** - * The intent resolved. + * The type of context to return for OR `null` indicating that the most recently broadcast + * context on the channel should be returned. */ - intent?: string; + contextType: null | string; } -export type Action = 'hover' | 'click' | 'cancel'; - /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling - * information to apply to it. Can be used to implement a pop-open or close interaction or - * other transition needed by a UI implementation. + * A response to a getCurrentContext request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceRestyle { +export interface GetCurrentContextResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceRestylePayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: 'Fdc3UserInterfaceRestyle'; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceRestylePayload { + payload: GetCurrentContextResponsePayload; /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - updatedCSS: UpdatedCSS; + type: 'getCurrentContextResponse'; } /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface UpdatedCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The updated height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The updated maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The updated maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; - /** - * The updated transition property to apply to the iframe. - */ - transition?: string; - /** - * The updated width of the iframe. - */ - width?: string; +export interface GetCurrentContextResponsePayload { + error?: PurpleError; /** - * The updated zIndex to apply to the iframe. + * The most recently broadcast context object (of the specified type, if one was specified), + * or `null` if none was available in the channel. */ - zIndex?: string; - [property: string]: any; + context?: null | Context; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request for details of instances of a particular app. + * Request to retrieve information about the FDC3 Desktop Agent implementation and the + * metadata of the calling application according to the Desktop Agent. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindInstancesRequest { +export interface GetInfoRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2085,20 +2166,18 @@ export interface FindInstancesRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindInstancesRequestPayload; + payload: GetInfoRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'findInstancesRequest'; + type: 'getInfoRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindInstancesRequestPayload { - app: AppIdentifier; -} +export interface GetInfoRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2106,12 +2185,12 @@ export interface FindInstancesRequestPayload { */ /** - * A response to a findInstances request. + * A response to a getInfo request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindInstancesResponse { +export interface GetInfoResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2121,67 +2200,81 @@ export interface FindInstancesResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindInstancesResponsePayload; + payload: GetInfoResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'findInstancesResponse'; + type: 'getInfoResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - * - * The message payload contains a flag indicating whether the API call was successful, plus - * any return values for the FDC3 API function called, or indicating that the request - * resulted in an error and including a standardized error message. */ -export interface FindInstancesResponsePayload { - error?: FindInstancesErrors; - appIdentifiers?: AppMetadata[]; +export interface GetInfoResponsePayload { + error?: ResponsePayloadError; + implementationMetadata?: ImplementationMetadata; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - * - * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID - * should be used in the first (WCP1Hello) message and should be quoted in all subsequent - * messages to link them to the same connection attempt. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - * - * Unique identifier for a `listener` object returned by a Desktop Agent to an app in - * response to addContextListener, addIntentListener or one of the PrivateChannel event - * listeners and used to identify it in messages (e.g. when unsubscribing). + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. * - * Unique identifier for an event message sent from a Desktop Agent to an app. + * Includes Metadata for the current application. * - * Should be set if the raiseIntent request returned an error. + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. */ -export type FindInstancesErrors = - | 'MalformedContext' - | 'DesktopAgentNotFound' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; +export interface ImplementationMetadata { + /** + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). + */ + appMetadata: AppMetadata; + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ +export interface OptionalFeatures { + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + DesktopAgentBridging: boolean; + /** + * Used to indicate whether the exposure of 'originating app metadata' for + * context and intent messages is supported by the Desktop Agent. + */ + OriginatingAppMetadata: boolean; + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + UserChannelMembershipAPIs: boolean; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2189,11 +2282,12 @@ export type FindInstancesErrors = */ /** - * A request for details of apps available to resolve a particular intent and context pair. + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentRequest { +export interface GetOrCreateChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2201,21 +2295,22 @@ export interface FindIntentRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentRequestPayload; + payload: GetOrCreateChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'findIntentRequest'; + type: 'getOrCreateChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentRequestPayload { - context?: Context; - intent: string; - resultType?: string; +export interface GetOrCreateChannelRequestPayload { + /** + * The id of the channel to return + */ + channelId: string; } /** @@ -2224,12 +2319,12 @@ export interface FindIntentRequestPayload { */ /** - * A response to a findIntent request. + * A response to a getOrCreateChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentResponse { +export interface GetOrCreateChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2239,12 +2334,12 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentResponsePayload; + payload: GetOrCreateChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'findIntentResponse'; + type: 'getOrCreateChannelResponse'; } /** @@ -2252,9 +2347,9 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentResponsePayload { - error?: FindInstancesErrors; - appIntent?: AppIntent; +export interface GetOrCreateChannelResponsePayload { + error?: PurpleError; + channel?: Channel; } /** @@ -2263,12 +2358,11 @@ export interface FindIntentResponsePayload { */ /** - * A request for details of intents and apps available to resolve them for a particular - * context. + * Request to retrieve a list of the User Channels available for the app to join. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentsByContextRequest { +export interface GetUserChannelsRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2276,21 +2370,18 @@ export interface FindIntentsByContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentsByContextRequestPayload; + payload: GetUserChannelsRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'findIntentsByContextRequest'; + type: 'getUserChannelsRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentsByContextRequestPayload { - context: Context; - resultType?: string; -} +export interface GetUserChannelsRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2298,12 +2389,12 @@ export interface FindIntentsByContextRequestPayload { */ /** - * A response to a findIntentsByContext request. + * A response to a getUserChannels request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentsByContextResponse { +export interface GetUserChannelsResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2313,12 +2404,12 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentsByContextResponsePayload; + payload: GetUserChannelsResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'findIntentsByContextResponse'; + type: 'getUserChannelsResponse'; } /** @@ -2326,9 +2417,9 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentsByContextResponsePayload { - error?: FindInstancesErrors; - appIntents?: AppIntent[]; +export interface GetUserChannelsResponsePayload { + error?: PurpleError; + userChannels?: Channel[]; } /** @@ -2337,11 +2428,12 @@ export interface FindIntentsByContextResponsePayload { */ /** - * A request for metadata about an app. + * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent + * and indicates that an application window or frame is still alive. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetAppMetadataRequest { +export interface HeartbeatAcknowledgementRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2349,19 +2441,22 @@ export interface GetAppMetadataRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetAppMetadataRequestPayload; + payload: HeartbeatAcknowledgementRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getAppMetadataRequest'; + type: 'heartbeatAcknowledgementRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetAppMetadataRequestPayload { - app: AppIdentifier; +export interface HeartbeatAcknowledgementRequestPayload { + /** + * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. + */ + heartbeatEventUuid: string; } /** @@ -2370,38 +2465,32 @@ export interface GetAppMetadataRequestPayload { */ /** - * A response to a getAppMetadata request. + * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is + * alive and that the application should send a heartbeatResponseRequest to the agent in + * response. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface GetAppMetadataResponse { +export interface HeartbeatEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: GetAppMetadataResponsePayload; + payload: HeartbeatEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getAppMetadataResponse'; + type: 'heartbeatEvent'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface GetAppMetadataResponsePayload { - error?: FindInstancesErrors; - appMetadata?: AppMetadata; -} +export interface HeartbeatEventPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2409,69 +2498,48 @@ export interface GetAppMetadataResponsePayload { */ /** - * A request to return the Channel object for the current User channel membership. Returns - * `null` if the app is not joined to a channel. + * An event message from the Desktop Agent to an app indicating that it has been selected to + * resolve a raised intent and context. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface GetCurrentChannelRequest { +export interface IntentEvent { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerRequestMeta; + meta: BroadcastEventMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ - payload: GetCurrentChannelRequestPayload; + payload: IntentEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getCurrentChannelRequest'; + type: 'intentEvent'; } /** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface GetCurrentChannelRequestPayload {} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a getCurrentChannel request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface GetCurrentChannelResponse { +export interface IntentEventPayload { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The context object passed with the raised intent. */ - meta: AddContextListenerResponseMeta; + context: Context; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The intent that was raised. */ - payload: GetCurrentChannelResponsePayload; + intent: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Details of the application instance that raised the intent. */ - type: 'getCurrentChannelResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetCurrentChannelResponsePayload { - error?: ResponsePayloadError; - channel?: Channel | null; + originatingApp?: AppIdentifier; + /** + * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates + * to. + */ + raiseIntentRequestUuid: string; } /** @@ -2480,13 +2548,11 @@ export interface GetCurrentChannelResponsePayload { */ /** - * A request to return the current context (either of a specified type or most recent - * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if - * one was specified) is available in the channel. + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetCurrentContextRequest { +export interface IntentListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2494,27 +2560,19 @@ export interface GetCurrentContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetCurrentContextRequestPayload; + payload: IntentListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getCurrentContextRequest'; + type: 'intentListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentContextRequestPayload { - /** - * The id of the channel to return the current context of. - */ - channelId: string; - /** - * The type of context to return for OR `null` indicating that the most recently broadcast - * context on the channel should be returned. - */ - contextType: null | string; +export interface IntentListenerUnsubscribeRequestPayload { + listenerUUID: string; } /** @@ -2523,12 +2581,12 @@ export interface GetCurrentContextRequestPayload { */ /** - * A response to a getCurrentContext request. + * A response to a intentListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetCurrentContextResponse { +export interface IntentListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2538,26 +2596,12 @@ export interface GetCurrentContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetCurrentContextResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getCurrentContextResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetCurrentContextResponsePayload { - error?: PurpleError; - /** - * The most recently broadcast context object (of the specified type, if one was specified), - * or `null` if none was available in the channel. - */ - context?: null | Context; + type: 'intentListenerUnsubscribeResponse'; } /** @@ -2566,12 +2610,13 @@ export interface GetCurrentContextResponsePayload { */ /** - * Request to retrieve information about the FDC3 Desktop Agent implementation and the - * metadata of the calling application according to the Desktop Agent. + * A request to deliver a result for an intent (which may include a `void` result that just + * indicates that the handler has run, returning no result). The result is tied to the + * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetInfoRequest { +export interface IntentResultRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2579,18 +2624,33 @@ export interface GetInfoRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetInfoRequestPayload; + payload: IntentResultRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getInfoRequest'; + type: 'intentResultRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetInfoRequestPayload {} +export interface IntentResultRequestPayload { + /** + * The eventUuid value of the intentEvent that the result being sent relates to. + */ + intentEventUuid: string; + intentResult: IntentResult; + /** + * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + */ + raiseIntentRequestUuid: string; +} + +export interface IntentResult { + context?: Context; + channel?: Channel; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2598,12 +2658,12 @@ export interface GetInfoRequestPayload {} */ /** - * A response to a getInfo request. + * A response to a request to deliver an intent result. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetInfoResponse { +export interface IntentResultResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2613,22 +2673,12 @@ export interface GetInfoResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetInfoResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'getInfoResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetInfoResponsePayload { - error?: ResponsePayloadError; - implementationMetadata?: ImplementationMetadata; + */ + type: 'intentResultResponse'; } /** @@ -2637,12 +2687,13 @@ export interface GetInfoResponsePayload { */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * Request to join the app to the specified User channel. On successfully joining a channel, + * client code should make subsequent requests to get the current context of that channel + * for all registered context listeners and then call their handlers with it. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetOrCreateChannelRequest { +export interface JoinUserChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2650,20 +2701,20 @@ export interface GetOrCreateChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetOrCreateChannelRequestPayload; + payload: JoinUserChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getOrCreateChannelRequest'; + type: 'joinUserChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetOrCreateChannelRequestPayload { +export interface JoinUserChannelRequestPayload { /** - * The id of the channel to return + * The id of the channel to join. */ channelId: string; } @@ -2674,12 +2725,14 @@ export interface GetOrCreateChannelRequestPayload { */ /** - * A response to a getOrCreateChannel request. + * A response to a joinUserChannel request. On receipt of this response, client code should + * make subsequent requests to get the current context of that channel for all registered + * context listeners and then call their handlers with it. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetOrCreateChannelResponse { +export interface JoinUserChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2689,12 +2742,12 @@ export interface GetOrCreateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetOrCreateChannelResponsePayload; + payload: JoinUserChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getOrCreateChannelResponse'; + type: 'joinUserChannelResponse'; } /** @@ -2702,9 +2755,8 @@ export interface GetOrCreateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetOrCreateChannelResponsePayload { +export interface JoinUserChannelResponsePayload { error?: PurpleError; - channel?: Channel; } /** @@ -2713,11 +2765,11 @@ export interface GetOrCreateChannelResponsePayload { */ /** - * Request to retrieve a list of the User Channels available for the app to join. + * Request to remove the app from any User channel membership. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetUserChannelsRequest { +export interface LeaveCurrentChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2725,18 +2777,18 @@ export interface GetUserChannelsRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetUserChannelsRequestPayload; + payload: LeaveCurrentChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getUserChannelsRequest'; + type: 'leaveCurrentChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetUserChannelsRequestPayload {} +export interface LeaveCurrentChannelRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2744,12 +2796,12 @@ export interface GetUserChannelsRequestPayload {} */ /** - * A response to a getUserChannels request. + * A response to a leaveCurrentChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetUserChannelsResponse { +export interface LeaveCurrentChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2759,12 +2811,12 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetUserChannelsResponsePayload; + payload: LeaveCurrentChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getUserChannelsResponse'; + type: 'leaveCurrentChannelResponse'; } /** @@ -2772,9 +2824,8 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetUserChannelsResponsePayload { +export interface LeaveCurrentChannelResponsePayload { error?: PurpleError; - userChannels?: Channel[]; } /** @@ -2783,12 +2834,11 @@ export interface GetUserChannelsResponsePayload { */ /** - * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent - * and indicates that an application window or frame is still alive. + * A request to open an application. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface HeartbeatAcknowledgementRequest { +export interface OpenRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2796,22 +2846,25 @@ export interface HeartbeatAcknowledgementRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: HeartbeatAcknowledgementRequestPayload; + payload: OpenRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'heartbeatAcknowledgementRequest'; + type: 'openRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface HeartbeatAcknowledgementRequestPayload { +export interface OpenRequestPayload { + app: AppIdentifier; /** - * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. */ - heartbeatEventUuid: string; + context?: Context; } /** @@ -2820,82 +2873,58 @@ export interface HeartbeatAcknowledgementRequestPayload { */ /** - * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is - * alive and that the application should send a heartbeatResponseRequest to the agent in - * response. + * A response to a open request. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface HeartbeatEvent { +export interface OpenResponse { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: BroadcastEventMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: HeartbeatEventPayload; + payload: OpenResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'heartbeatEvent'; + type: 'openResponse'; } /** - * The message payload contains details of the event that the app is being notified about. - */ -export interface HeartbeatEventPayload {} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that it has been selected to - * resolve a raised intent and context. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface IntentEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: IntentEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'intentEvent'; +export interface OpenResponsePayload { + error?: OpenErrorResponsePayload; + appIdentifier?: AppIdentifier; } /** - * The message payload contains details of the event that the app is being notified about. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface IntentEventPayload { - /** - * The context object passed with the raised intent. - */ - context: Context; - /** - * The intent that was raised. - */ - intent: string; - /** - * Details of the application instance that raised the intent. - */ - originatingApp?: AppIdentifier; - /** - * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates - * to. - */ - raiseIntentRequestUuid: string; -} +export type OpenErrorResponsePayload = + | 'MalformedContext' + | 'AppNotFound' + | 'AppTimeout' + | 'DesktopAgentNotFound' + | 'ErrorOnLaunch' + | 'ResolverUnavailable' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2903,11 +2932,11 @@ export interface IntentEventPayload { */ /** - * A request to unsubscribe a context listener. + * A request to add an event listener to a specific PrivateChannel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentListenerUnsubscribeRequest { +export interface PrivateChannelAddEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2915,33 +2944,46 @@ export interface IntentListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentListenerUnsubscribeRequestPayload; + payload: PrivateChannelAddEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'intentListenerUnsubscribeRequest'; + type: 'privateChannelAddEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface PrivateChannelAddEventListenerRequestPayload { + /** + * The type of PrivateChannel event that the listener should be applied to, or null for all + * event types. + */ + listenerType: PrivateChannelEventType | null; + /** + * The Id of the PrivateChannel that the listener should be added to. + */ + privateChannelId: string; } +/** + * Type defining valid type strings for Private Channel events. + */ +export type PrivateChannelEventType = 'addContextListener' | 'unsubscribe' | 'disconnect'; + /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * A response to a intentListenerUnsubscribe request. + * A response to a privateChannelAddEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentListenerUnsubscribeResponse { +export interface PrivateChannelAddEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2951,12 +2993,22 @@ export interface IntentListenerUnsubscribeResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: PrivateChannelAddEventListenerResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'intentListenerUnsubscribeResponse'; + type: 'privateChannelAddEventListenerResponse'; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface PrivateChannelAddEventListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; } /** @@ -2965,13 +3017,12 @@ export interface IntentListenerUnsubscribeResponse { */ /** - * A request to deliver a result for an intent (which may include a `void` result that just - * indicates that the handler has run, returning no result). The result is tied to the - * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. + * Request that indicates that a participant will no longer interact with a specified + * `PrivateChannel`. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentResultRequest { +export interface PrivateChannelDisconnectRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2979,61 +3030,102 @@ export interface IntentResultRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentResultRequestPayload; + payload: PrivateChannelDisconnectRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'intentResultRequest'; + type: 'privateChannelDisconnectRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentResultRequestPayload { - /** - * The eventUuid value of the intentEvent that the result being sent relates to. - */ - intentEventUuid: string; - intentResult: IntentResult; +export interface PrivateChannelDisconnectRequestPayload { /** - * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + * The Id of the Channel that should be disconnected from */ - raiseIntentRequestUuid: string; + channelId: string; } -export interface IntentResult { - context?: Context; - channel?: Channel; +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a privateChannelDisconnect request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface PrivateChannelDisconnectResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: PrivateChannelDisconnectResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelDisconnectResponse'; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface PrivateChannelDisconnectResponsePayload { + error?: PurpleError; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a request to deliver an intent result. + * An event message from the Desktop Agent to an app indicating that another app has added a + * context listener to a specific PrivateChannel. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface IntentResultResponse { +export interface PrivateChannelOnAddContextListenerEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: BroadcastResponseResponsePayload; + payload: PrivateChannelOnAddContextListenerEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'intentResultResponse'; + type: 'privateChannelOnAddContextListenerEvent'; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface PrivateChannelOnAddContextListenerEventPayload { + /** + * The type of the context listener added to the channel by another app, or null if it will + * listen to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was added to. + */ + privateChannelId: string; } /** @@ -3042,76 +3134,77 @@ export interface IntentResultResponse { */ /** - * Request to join the app to the specified User channel. On successfully joining a channel, - * client code should make subsequent requests to get the current context of that channel - * for all registered context listeners and then call their handlers with it. + * An event message from the Desktop Agent to an app indicating that another app has + * disconnected from a specific PrivateChannel and will no longer interact with it. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface JoinUserChannelRequest { +export interface PrivateChannelOnDisconnectEvent { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerRequestMeta; + meta: BroadcastEventMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ - payload: JoinUserChannelRequestPayload; + payload: PrivateChannelOnDisconnectEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'joinUserChannelRequest'; + type: 'privateChannelOnDisconnectEvent'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ -export interface JoinUserChannelRequestPayload { +export interface PrivateChannelOnDisconnectEventPayload { /** - * The id of the channel to join. + * The Id of the PrivateChannel that the app has disconnected from. */ - channelId: string; + privateChannelId: string; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a joinUserChannel request. On receipt of this response, client code should - * make subsequent requests to get the current context of that channel for all registered - * context listeners and then call their handlers with it. + * An event message from the Desktop Agent to an app indicating that another app has + * unsubscribed a context listener from a specific PrivateChannel. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface JoinUserChannelResponse { +export interface PrivateChannelOnUnsubscribeEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: JoinUserChannelResponsePayload; + payload: PrivateChannelOnUnsubscribeEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'joinUserChannelResponse'; + type: 'privateChannelOnUnsubscribeEvent'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface JoinUserChannelResponsePayload { - error?: PurpleError; +export interface PrivateChannelOnUnsubscribeEventPayload { + /** + * The type of the context listener unsubscribed from the channel by another app, or null if + * it was listening to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was unsubscribed from. + */ + privateChannelId: string; } /** @@ -3120,11 +3213,11 @@ export interface JoinUserChannelResponsePayload { */ /** - * Request to remove the app from any User channel membership. + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface LeaveCurrentChannelRequest { +export interface PrivateChannelUnsubscribeEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3132,18 +3225,20 @@ export interface LeaveCurrentChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: LeaveCurrentChannelRequestPayload; + payload: PrivateChannelUnsubscribeEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'leaveCurrentChannelRequest'; + type: 'privateChannelUnsubscribeEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface LeaveCurrentChannelRequestPayload {} +export interface PrivateChannelUnsubscribeEventListenerRequestPayload { + listenerUUID: string; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -3151,12 +3246,12 @@ export interface LeaveCurrentChannelRequestPayload {} */ /** - * A response to a leaveCurrentChannel request. + * A response to a privateChannelUnsubscribeEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface LeaveCurrentChannelResponse { +export interface PrivateChannelUnsubscribeEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3166,21 +3261,12 @@ export interface LeaveCurrentChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: LeaveCurrentChannelResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'leaveCurrentChannelResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface LeaveCurrentChannelResponsePayload { - error?: PurpleError; + type: 'privateChannelUnsubscribeEventListenerResponse'; } /** @@ -3189,11 +3275,11 @@ export interface LeaveCurrentChannelResponsePayload { */ /** - * A request to open an application. + * A request to raise an unspecified intent for a specified context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface OpenRequest { +export interface RaiseIntentForContextRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3201,25 +3287,20 @@ export interface OpenRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: OpenRequestPayload; + payload: RaiseIntentForContextRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'openRequest'; + type: 'raiseIntentForContextRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface OpenRequestPayload { - app: AppIdentifier; - /** - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. - */ - context?: Context; +export interface RaiseIntentForContextRequestPayload { + app?: AppIdentifier; + context: Context; } /** @@ -3228,12 +3309,12 @@ export interface OpenRequestPayload { */ /** - * A response to a open request. + * A response to a raiseIntentForContext request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface OpenResponse { +export interface RaiseIntentForContextResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3242,44 +3323,90 @@ export interface OpenResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). */ - payload: OpenResponsePayload; + payload: RaiseIntentForContextResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'openResponse'; + type: 'raiseIntentForContextResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). + * + * Response to a raiseIntentForContext request that needs additional resolution (i.e. show + * an intent resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface OpenResponsePayload { - error?: OpenErrorResponsePayload; - appIdentifier?: AppIdentifier; +export interface RaiseIntentForContextResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing + * an intent resolver) before it can be handled. + */ + appIntents?: AppIntent[]; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). + * Used if the raiseIntent request was successfully resolved. * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). + * IntentResolution provides a standard format for data returned upon resolving an intent. + * + * ```javascript + * //resolve a "Chain" type intent + * let resolution = await agent.raiseIntent("intentName", context); + * + * //resolve a "Client-Service" type intent with a data response or a Channel + * let resolution = await agent.raiseIntent("intentName", context); + * try { + * const result = await resolution.getResult(); + * if (result && result.broadcast) { + * console.log(`${resolution.source} returned a channel with id ${result.id}`); + * } else if (result){ + * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); + * } else { + * console.error(`${resolution.source} didn't return data` + * } + * } catch(error) { + * console.error(`${resolution.source} returned an error: ${error}`); + * } + * + * // Use metadata about the resolving app instance to target a further intent + * await agent.raiseIntent("intentName", context, resolution.source); + * ``` */ -export type OpenErrorResponsePayload = - | 'MalformedContext' - | 'AppNotFound' - | 'AppTimeout' - | 'DesktopAgentNotFound' - | 'ErrorOnLaunch' - | 'ResolverUnavailable' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; +export interface IntentResolution { + /** + * The intent that was raised. May be used to determine which intent the user + * chose in response to `fdc3.raiseIntentForContext()`. + */ + intent: string; + /** + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ + source: AppIdentifier; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -3287,11 +3414,11 @@ export type OpenErrorResponsePayload = */ /** - * A request to add an event listener to a specific PrivateChannel. + * A request to raise an intent for a context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface PrivateChannelAddEventListenerRequest { +export interface RaiseIntentRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3299,46 +3426,35 @@ export interface PrivateChannelAddEventListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: PrivateChannelAddEventListenerRequestPayload; + payload: RaiseIntentRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'privateChannelAddEventListenerRequest'; + type: 'raiseIntentRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface PrivateChannelAddEventListenerRequestPayload { - /** - * The type of PrivateChannel event that the listener should be applied to, or null for all - * event types. - */ - listenerType: PrivateChannelEventType | null; - /** - * The Id of the PrivateChannel that the listener should be added to. - */ - privateChannelId: string; +export interface RaiseIntentRequestPayload { + app?: AppIdentifier; + context: Context; + intent: string; } -/** - * Type defining valid type strings for Private Channel events. - */ -export type PrivateChannelEventType = 'addContextListener' | 'unsubscribe' | 'disconnect'; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * A response to a privateChannelAddEventListener request. + * A response to a raiseIntent request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelAddEventListenerResponse { +export interface RaiseIntentResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3347,74 +3463,63 @@ export interface PrivateChannelAddEventListenerResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). */ - payload: PrivateChannelAddEventListenerResponsePayload; + payload: RaiseIntentResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'privateChannelAddEventListenerResponse'; + type: 'raiseIntentResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - */ -export interface PrivateChannelAddEventListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * Request that indicates that a participant will no longer interact with a specified - * `PrivateChannel`. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). + * + * Response to a raiseIntent request that needs additional resolution (i.e. show an intent + * resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface PrivateChannelDisconnectRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; +export interface RaiseIntentResponsePayload { /** - * The message payload typically contains the arguments to FDC3 API functions. + * Should be set if the raiseIntent request returned an error. */ - payload: PrivateChannelDisconnectRequestPayload; + error?: FindInstancesErrors; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Used if the raiseIntent request was successfully resolved. */ - type: 'privateChannelDisconnectRequest'; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelDisconnectRequestPayload { + intentResolution?: IntentResolution; /** - * The Id of the Channel that should be disconnected from + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. */ - channelId: string; + appIntent?: AppIntent; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a privateChannelDisconnect request. + * A secondary response to a request to raise an intent used to deliver the intent result. + * This message should quote the original requestUuid of the raiseIntentRequest message in + * its `meta.requestUuid` field. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelDisconnectResponse { +export interface RaiseIntentResultResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3424,12 +3529,12 @@ export interface PrivateChannelDisconnectResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: PrivateChannelDisconnectResponsePayload; + payload: RaiseIntentResultResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'privateChannelDisconnectResponse'; + type: 'raiseIntentResultResponse'; } /** @@ -3437,50 +3542,9 @@ export interface PrivateChannelDisconnectResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface PrivateChannelDisconnectResponsePayload { - error?: PurpleError; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that another app has added a - * context listener to a specific PrivateChannel. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. - */ -export interface PrivateChannelOnAddContextListenerEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: PrivateChannelOnAddContextListenerEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'privateChannelOnAddContextListenerEvent'; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface PrivateChannelOnAddContextListenerEventPayload { - /** - * The type of the context listener added to the channel by another app, or null if it will - * listen to all types. - */ - contextType: null | string; - /** - * The Id of the PrivateChannel that the listener was added to. - */ - privateChannelId: string; +export interface RaiseIntentResultResponsePayload { + error?: ResponsePayloadError; + intentResult?: IntentResult; } /** @@ -3489,501 +3553,363 @@ export interface PrivateChannelOnAddContextListenerEventPayload { */ /** - * An event message from the Desktop Agent to an app indicating that another app has - * disconnected from a specific PrivateChannel and will no longer interact with it. + * Hello message sent by an application to a parent window or frame when attempting to + * establish connectivity to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelOnDisconnectEvent { +export interface WebConnectionProtocol1Hello { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for a Web Connection Protocol message. */ - meta: BroadcastEventMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload contains details of the event that the app is being notified about. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelOnDisconnectEventPayload; + payload: WebConnectionProtocol1HelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'privateChannelOnDisconnectEvent'; + type: 'WCP1Hello'; } /** - * The message payload contains details of the event that the app is being notified about. + * Metadata for a Web Connection Protocol message. */ -export interface PrivateChannelOnDisconnectEventPayload { - /** - * The Id of the PrivateChannel that the app has disconnected from. - */ - privateChannelId: string; +export interface WebConnectionProtocol1HelloMeta { + connectionAttemptUuid: string; + timestamp: Date; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that another app has - * unsubscribed a context listener from a specific PrivateChannel. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelOnUnsubscribeEvent { +export interface WebConnectionProtocol1HelloPayload { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - meta: BroadcastEventMeta; + actualUrl: string; /** - * The message payload contains details of the event that the app is being notified about. + * A flag that may be used to indicate that a channel selector user interface is or is not + * required. Set to `false` if the app includes its own interface for selecting channels or + * does not work with user channels. */ - payload: PrivateChannelOnUnsubscribeEventPayload; + channelSelector?: boolean; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The version of FDC3 API that the app supports. */ - type: 'privateChannelOnUnsubscribeEvent'; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface PrivateChannelOnUnsubscribeEventPayload { + fdc3Version: string; /** - * The type of the context listener unsubscribed from the channel by another app, or null if - * it was listening to all types. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - contextType: null | string; + identityUrl: string; /** - * The Id of the PrivateChannel that the listener was unsubscribed from. + * A flag that may be used to indicate that an intent resolver is or is not required. Set to + * `false` if no intents, or only targeted intents, are raised. */ - privateChannelId: string; + intentResolver?: boolean; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to unsubscribe a context listener. + * Response from a Desktop Agent to an application requesting access to it indicating that + * it should load a specified URL into a hidden iframe in order to establish connectivity to + * a Desktop Agent. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerRequest { +export interface WebConnectionProtocol2LoadURL { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelUnsubscribeEventListenerRequestPayload; + payload: WebConnectionProtocol2LoadURLPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: 'privateChannelUnsubscribeEventListenerRequest'; + type: 'WCP2LoadUrl'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelUnsubscribeEventListenerRequestPayload { - listenerUUID: string; +export interface WebConnectionProtocol2LoadURLPayload { + /** + * A URL which can be used to establish communication with the Desktop Agent, via loading + * the URL into an iframe and restarting the Web Connection protocol with the iframe as the + * target. + */ + iframeUrl: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a privateChannelUnsubscribeEventListener request. + * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that + * should be used for subsequent communication steps. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerResponse { +export interface WebConnectionProtocol3Handshake { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: BroadcastResponseResponsePayload; + payload: WebConnectionProtocol3HandshakePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'privateChannelUnsubscribeEventListenerResponse'; + type: 'WCP3Handshake'; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to raise an unspecified intent for a specified context. - * - * A request message from an FDC3-enabled app to a Desktop Agent. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextRequest { +export interface WebConnectionProtocol3HandshakePayload { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Indicates whether a channel selector user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the channel selector (as the + * Desktop Agent will handle it another way). */ - meta: AddContextListenerRequestMeta; + channelSelectorUrl: boolean | string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The version of FDC3 API that the Desktop Agent will provide support for. */ - payload: RaiseIntentForContextRequestPayload; + fdc3Version: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Indicates whether an intent resolver user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the intent resolver (as the + * Desktop Agent will handle it another way). */ - type: 'raiseIntentForContextRequest'; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface RaiseIntentForContextRequestPayload { - app?: AppIdentifier; - context: Context; + intentResolverUrl: boolean | string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntentForContext request. + * Identity Validation request from an app attempting to connect to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentForContextResponse { +export interface WebConnectionProtocol4ValidateAppIdentity { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentForContextResponsePayload; + payload: WebConnectionProtocol4ValidateAppIdentityPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentForContextResponse'; + type: 'WCP4ValidateAppIdentity'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). - * - * Response to a raiseIntentForContext request that needs additional resolution (i.e. show - * an intent resolver UI). - * - * Used if a raiseIntent request resulted in an error. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol4ValidateAppIdentityPayload { /** - * Used if the raiseIntent request was successfully resolved. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - intentResolution?: IntentResolution; + actualUrl: string; /** - * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing - * an intent resolver) before it can be handled. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - appIntents?: AppIntent[]; -} - -/** - * Used if the raiseIntent request was successfully resolved. - * - * IntentResolution provides a standard format for data returned upon resolving an intent. - * - * ```javascript - * //resolve a "Chain" type intent - * let resolution = await agent.raiseIntent("intentName", context); - * - * //resolve a "Client-Service" type intent with a data response or a Channel - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { - * console.log(`${resolution.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return data` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * - * // Use metadata about the resolving app instance to target a further intent - * await agent.raiseIntent("intentName", context, resolution.source); - * ``` - */ -export interface IntentResolution { + identityUrl: string; /** - * The intent that was raised. May be used to determine which intent the user - * chose in response to `fdc3.raiseIntentForContext()`. + * If an application has previously connected to the Desktop Agent, it may specify its prior + * instance id and associated instance UUID to request the same same instance Id be assigned. */ - intent: string; + instanceId?: string; /** - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. + * Instance UUID associated with the requested instanceId. */ - source: AppIdentifier; + instanceUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to raise an intent for a context. + * Message sent by the Desktop Agent to an app if their identity validation fails. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentRequest { +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentRequestPayload; + payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentRequest'; + type: 'WCP5ValidateAppIdentityFailedResponse'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentRequestPayload { - app?: AppIdentifier; - context: Context; - intent: string; +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { + message?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntent request. + * Message sent by the Desktop Agent to an app after successful identity validation. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentResponse { +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentResponsePayload; + payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentResponse'; + type: 'WCP5ValidateAppIdentityResponse'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { + /** + * The appId that the app's identity was validated against. + */ + appId: string; + /** + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. + */ + implementationMetadata: ImplementationMetadata; + /** + * The instance Id granted to the application by the Desktop Agent. + */ + instanceId: string; + /** + * Instance UUID associated with the instanceId granted, which may be used to retrieve the + * same instanceId if the app is reloaded or navigates. + */ + instanceUuid: string; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). - * - * Response to a raiseIntent request that needs additional resolution (i.e. show an intent - * resolver UI). + * Identifies the type of the connection step message. + */ + +/** + * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the + * window or navigating). Desktop Agents should close the MessagePort after receiving this + * message, but retain instance details in case the application reconnects (e.g. after a + * navigation event). * - * Used if a raiseIntent request resulted in an error. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol6Goodbye { /** - * Used if the raiseIntent request was successfully resolved. + * Metadata for a Web Connection Protocol message. */ - intentResolution?: IntentResolution; + meta: WebConnectionProtocol6GoodbyeMeta; /** - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * Identifies the type of the connection step message. */ - appIntent?: AppIntent; + type: 'WCP6Goodbye'; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Metadata for a Web Connection Protocol message. */ +export interface WebConnectionProtocol6GoodbyeMeta { + timestamp: Date; +} /** - * A secondary response to a request to raise an intent used to deliver the intent result. - * This message should quote the original requestUuid of the raiseIntentRequest message in - * its `meta.requestUuid` field. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * Identifies the type of the connection step message. */ -export interface RaiseIntentResultResponse { + +/** + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocolMessage { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: ConnectionStepMetadata; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentResultResponsePayload; + payload?: { [key: string]: any }; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentResultResponse'; + type: ConnectionStepMessageType; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Metadata for a Web Connection Protocol message. */ -export interface RaiseIntentResultResponsePayload { - error?: ResponsePayloadError; - intentResult?: IntentResult; +export interface ConnectionStepMetadata { + timestamp: Date; + connectionAttemptUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ +export type ConnectionStepMessageType = + | 'WCP1Hello' + | 'WCP2LoadUrl' + | 'WCP3Handshake' + | 'WCP4ValidateAppIdentity' + | 'WCP5ValidateAppIdentityFailedResponse' + | 'WCP5ValidateAppIdentityResponse' + | 'WCP6Goodbye'; // Converts JSON strings to/from your types // and asserts the results of JSON.parse at runtime export class Convert { - public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { - return cast(JSON.parse(json), r('WebConnectionProtocol1Hello')); - } - - public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol1Hello')), null, 2); - } - - public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { - return cast(JSON.parse(json), r('WebConnectionProtocol2LoadURL')); - } - - public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol2LoadURL')), null, 2); - } - - public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { - return cast(JSON.parse(json), r('WebConnectionProtocol3Handshake')); - } - - public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol3Handshake')), null, 2); - } - - public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { - return cast(JSON.parse(json), r('WebConnectionProtocol4ValidateAppIdentity')); - } - - public static webConnectionProtocol4ValidateAppIdentityToJson( - value: WebConnectionProtocol4ValidateAppIdentity - ): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol4ValidateAppIdentity')), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse( - json: string - ): WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')); - } - - public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson( - value: WebConnectionProtocol5ValidateAppIdentityFailedResponse - ): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse( - json: string - ): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')); - } - - public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson( - value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse - ): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')), null, 2); - } - - public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { - return cast(JSON.parse(json), r('WebConnectionProtocol6Goodbye')); - } - - public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol6Goodbye')), null, 2); - } - - public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { - return cast(JSON.parse(json), r('WebConnectionProtocolMessage')); - } - - public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocolMessage')), null, 2); - } - public static toAddContextListenerRequest(json: string): AddContextListenerRequest { return cast(JSON.parse(json), r('AddContextListenerRequest')); } @@ -4136,14 +4062,6 @@ export class Convert { return JSON.stringify(uncast(value, r('EventListenerUnsubscribeResponse')), null, 2); } - public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { - return cast(JSON.parse(json), r('Fdc3UserInterfaceChannelSelected')); - } - - public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { - return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannelSelected')), null, 2); - } - public static toFdc3UserInterfaceChannels(json: string): Fdc3UserInterfaceChannels { return cast(JSON.parse(json), r('Fdc3UserInterfaceChannels')); } @@ -4152,6 +4070,14 @@ export class Convert { return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannels')), null, 2); } + public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { + return cast(JSON.parse(json), r('Fdc3UserInterfaceChannelSelected')); + } + + public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannelSelected')), null, 2); + } + public static toFdc3UserInterfaceDrag(json: string): Fdc3UserInterfaceDrag { return cast(JSON.parse(json), r('Fdc3UserInterfaceDrag')); } @@ -4564,16 +4490,90 @@ export class Convert { return cast(JSON.parse(json), r('RaiseIntentResponse')); } - public static raiseIntentResponseToJson(value: RaiseIntentResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResponse')), null, 2); + public static raiseIntentResponseToJson(value: RaiseIntentResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentResponse')), null, 2); + } + + public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { + return cast(JSON.parse(json), r('RaiseIntentResultResponse')); + } + + public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentResultResponse')), null, 2); + } + + public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { + return cast(JSON.parse(json), r('WebConnectionProtocol1Hello')); + } + + public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol1Hello')), null, 2); + } + + public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { + return cast(JSON.parse(json), r('WebConnectionProtocol2LoadURL')); + } + + public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol2LoadURL')), null, 2); + } + + public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { + return cast(JSON.parse(json), r('WebConnectionProtocol3Handshake')); + } + + public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol3Handshake')), null, 2); + } + + public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { + return cast(JSON.parse(json), r('WebConnectionProtocol4ValidateAppIdentity')); + } + + public static webConnectionProtocol4ValidateAppIdentityToJson( + value: WebConnectionProtocol4ValidateAppIdentity + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol4ValidateAppIdentity')), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse( + json: string + ): WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')); + } + + public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson( + value: WebConnectionProtocol5ValidateAppIdentityFailedResponse + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + json: string + ): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')); + } + + public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson( + value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')), null, 2); + } + + public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { + return cast(JSON.parse(json), r('WebConnectionProtocol6Goodbye')); + } + + public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol6Goodbye')), null, 2); } - public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { - return cast(JSON.parse(json), r('RaiseIntentResultResponse')); + public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { + return cast(JSON.parse(json), r('WebConnectionProtocolMessage')); } - public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResultResponse')), null, 2); + public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocolMessage')), null, 2); } } @@ -4671,250 +4671,79 @@ function transform(val: any, typ: any, getProps: any, key: any = '', parent: any if (val === null || typeof val !== 'object' || Array.isArray(val)) { return invalidValue(l(ref || 'object'), val, key, parent); } - const result: any = {}; - Object.getOwnPropertyNames(props).forEach(key => { - const prop = props[key]; - const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; - result[prop.key] = transform(v, prop.typ, getProps, key, ref); - }); - Object.getOwnPropertyNames(val).forEach(key => { - if (!Object.prototype.hasOwnProperty.call(props, key)) { - result[key] = transform(val[key], additional, getProps, key, ref); - } - }); - return result; - } - - if (typ === 'any') return val; - if (typ === null) { - if (val === null) return val; - return invalidValue(typ, val, key, parent); - } - if (typ === false) return invalidValue(typ, val, key, parent); - let ref: any = undefined; - while (typeof typ === 'object' && typ.ref !== undefined) { - ref = typ.ref; - typ = typeMap[typ.ref]; - } - if (Array.isArray(typ)) return transformEnum(typ, val); - if (typeof typ === 'object') { - return typ.hasOwnProperty('unionMembers') - ? transformUnion(typ.unionMembers, val) - : typ.hasOwnProperty('arrayItems') - ? transformArray(typ.arrayItems, val) - : typ.hasOwnProperty('props') - ? transformObject(getProps(typ), typ.additional, val) - : invalidValue(typ, val, key, parent); - } - // Numbers can be parsed by Date but shouldn't be. - if (typ === Date && typeof val !== 'number') return transformDate(val); - return transformPrimitive(typ, val); -} - -function cast(val: any, typ: any): T { - return transform(val, typ, jsonToJSProps); -} - -function uncast(val: T, typ: any): any { - return transform(val, typ, jsToJSONProps); -} - -function l(typ: any) { - return { literal: typ }; -} - -function a(typ: any) { - return { arrayItems: typ }; -} - -function u(...typs: any[]) { - return { unionMembers: typs }; -} - -function o(props: any[], additional: any) { - return { props, additional }; -} - -function m(additional: any) { - return { props: [], additional }; -} - -function r(name: string) { - return { ref: name }; -} - -const typeMap: any = { - WebConnectionProtocol1Hello: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol1HelloPayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol1HelloType') }, - ], - false - ), - WebConnectionProtocol1HelloMeta: o( - [ - { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - WebConnectionProtocol1HelloPayload: o( - [ - { json: 'actualUrl', js: 'actualUrl', typ: '' }, - { json: 'channelSelector', js: 'channelSelector', typ: u(undefined, true) }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'identityUrl', js: 'identityUrl', typ: '' }, - { json: 'intentResolver', js: 'intentResolver', typ: u(undefined, true) }, - ], - 'any' - ), - WebConnectionProtocol2LoadURL: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol2LoadURLPayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol2LoadURLType') }, - ], - false - ), - WebConnectionProtocol2LoadURLPayload: o([{ json: 'iframeUrl', js: 'iframeUrl', typ: '' }], 'any'), - WebConnectionProtocol3Handshake: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol3HandshakePayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol3HandshakeType') }, - ], - false - ), - WebConnectionProtocol3HandshakePayload: o( - [ - { json: 'channelSelectorUrl', js: 'channelSelectorUrl', typ: u(true, '') }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'intentResolverUrl', js: 'intentResolverUrl', typ: u(true, '') }, - ], - false - ), - WebConnectionProtocol4ValidateAppIdentity: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol4ValidateAppIdentityPayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol4ValidateAppIdentityType') }, - ], - false - ), - WebConnectionProtocol4ValidateAppIdentityPayload: o( - [ - { json: 'actualUrl', js: 'actualUrl', typ: '' }, - { json: 'identityUrl', js: 'identityUrl', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - { json: 'instanceUuid', js: 'instanceUuid', typ: u(undefined, '') }, - ], - false - ), - WebConnectionProtocol5ValidateAppIdentityFailedResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponseType') }, - ], - false - ), - WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload: o( - [{ json: 'message', js: 'message', typ: u(undefined, '') }], - false - ), - WebConnectionProtocol5ValidateAppIdentitySuccessResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponseType') }, - ], - false - ), - WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'implementationMetadata', js: 'implementationMetadata', typ: r('ImplementationMetadata') }, - { json: 'instanceId', js: 'instanceId', typ: '' }, - { json: 'instanceUuid', js: 'instanceUuid', typ: '' }, - ], - false - ), - ImplementationMetadata: o( - [ - { json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, - { json: 'provider', js: 'provider', typ: '' }, - { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, - ], - false - ), - AppMetadata: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'description', js: 'description', typ: u(undefined, '') }, - { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, - { json: 'icons', js: 'icons', typ: u(undefined, a(r('Icon'))) }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - { json: 'instanceMetadata', js: 'instanceMetadata', typ: u(undefined, m('any')) }, - { json: 'name', js: 'name', typ: u(undefined, '') }, - { json: 'resultType', js: 'resultType', typ: u(undefined, u(null, '')) }, - { json: 'screenshots', js: 'screenshots', typ: u(undefined, a(r('Image'))) }, - { json: 'title', js: 'title', typ: u(undefined, '') }, - { json: 'tooltip', js: 'tooltip', typ: u(undefined, '') }, - { json: 'version', js: 'version', typ: u(undefined, '') }, - ], - false - ), - Icon: o( - [ - { json: 'size', js: 'size', typ: u(undefined, '') }, - { json: 'src', js: 'src', typ: '' }, - { json: 'type', js: 'type', typ: u(undefined, '') }, - ], - false - ), - Image: o( - [ - { json: 'label', js: 'label', typ: u(undefined, '') }, - { json: 'size', js: 'size', typ: u(undefined, '') }, - { json: 'src', js: 'src', typ: '' }, - { json: 'type', js: 'type', typ: u(undefined, '') }, - ], - false - ), - OptionalFeatures: o( - [ - { json: 'DesktopAgentBridging', js: 'DesktopAgentBridging', typ: true }, - { json: 'OriginatingAppMetadata', js: 'OriginatingAppMetadata', typ: true }, - { json: 'UserChannelMembershipAPIs', js: 'UserChannelMembershipAPIs', typ: true }, - ], - false - ), - WebConnectionProtocol6Goodbye: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol6GoodbyeMeta') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol6GoodbyeType') }, - ], - false - ), - WebConnectionProtocol6GoodbyeMeta: o([{ json: 'timestamp', js: 'timestamp', typ: Date }], false), - WebConnectionProtocolMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStepMetadata') }, - { json: 'payload', js: 'payload', typ: u(undefined, m('any')) }, - { json: 'type', js: 'type', typ: r('ConnectionStepMessageType') }, - ], - false - ), - ConnectionStepMetadata: o( - [ - { json: 'timestamp', js: 'timestamp', typ: Date }, - { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: u(undefined, '') }, - ], - false - ), + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps, key, ref); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps, key, ref); + } + }); + return result; + } + + if (typ === 'any') return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val, key, parent); + } + if (typ === false) return invalidValue(typ, val, key, parent); + let ref: any = undefined; + while (typeof typ === 'object' && typ.ref !== undefined) { + ref = typ.ref; + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === 'object') { + return typ.hasOwnProperty('unionMembers') + ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty('arrayItems') + ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty('props') + ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val, key, parent); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== 'number') return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function l(typ: any) { + return { literal: typ }; +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { AddContextListenerRequest: o( [ { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, @@ -5211,14 +5040,6 @@ const typeMap: any = { ], false ), - Fdc3UserInterfaceChannelSelected: o( - [ - { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelSelectedPayload') }, - { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceChannelSelectedType') }, - ], - false - ), - Fdc3UserInterfaceChannelSelectedPayload: o([{ json: 'selected', js: 'selected', typ: u(null, '') }], false), Fdc3UserInterfaceChannels: o( [ { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelsPayload') }, @@ -5233,6 +5054,14 @@ const typeMap: any = { ], false ), + Fdc3UserInterfaceChannelSelected: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelSelectedPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceChannelSelectedType') }, + ], + false + ), + Fdc3UserInterfaceChannelSelectedPayload: o([{ json: 'selected', js: 'selected', typ: u(null, '') }], false), Fdc3UserInterfaceDrag: o( [ { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceDragPayload') }, @@ -5313,6 +5142,40 @@ const typeMap: any = { ], false ), + AppMetadata: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'description', js: 'description', typ: u(undefined, '') }, + { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, + { json: 'icons', js: 'icons', typ: u(undefined, a(r('Icon'))) }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + { json: 'instanceMetadata', js: 'instanceMetadata', typ: u(undefined, m('any')) }, + { json: 'name', js: 'name', typ: u(undefined, '') }, + { json: 'resultType', js: 'resultType', typ: u(undefined, u(null, '')) }, + { json: 'screenshots', js: 'screenshots', typ: u(undefined, a(r('Image'))) }, + { json: 'title', js: 'title', typ: u(undefined, '') }, + { json: 'tooltip', js: 'tooltip', typ: u(undefined, '') }, + { json: 'version', js: 'version', typ: u(undefined, '') }, + ], + false + ), + Icon: o( + [ + { json: 'size', js: 'size', typ: u(undefined, '') }, + { json: 'src', js: 'src', typ: '' }, + { json: 'type', js: 'type', typ: u(undefined, '') }, + ], + false + ), + Image: o( + [ + { json: 'label', js: 'label', typ: u(undefined, '') }, + { json: 'size', js: 'size', typ: u(undefined, '') }, + { json: 'src', js: 'src', typ: '' }, + { json: 'type', js: 'type', typ: u(undefined, '') }, + ], + false + ), IntentMetadata: o( [ { json: 'displayName', js: 'displayName', typ: u(undefined, '') }, @@ -5545,6 +5408,24 @@ const typeMap: any = { ], false ), + ImplementationMetadata: o( + [ + { json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, + { json: 'provider', js: 'provider', typ: '' }, + { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, + ], + false + ), + OptionalFeatures: o( + [ + { json: 'DesktopAgentBridging', js: 'DesktopAgentBridging', typ: true }, + { json: 'OriginatingAppMetadata', js: 'OriginatingAppMetadata', typ: true }, + { json: 'UserChannelMembershipAPIs', js: 'UserChannelMembershipAPIs', typ: true }, + ], + false + ), GetOrCreateChannelRequest: o( [ { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, @@ -5922,37 +5803,140 @@ const typeMap: any = { ], false ), - RaiseIntentResultResponse: o( + RaiseIntentResultResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentResultResponsePayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentResultResponseType') }, + ], + false + ), + RaiseIntentResultResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, + { json: 'intentResult', js: 'intentResult', typ: u(undefined, r('IntentResult')) }, + ], + false + ), + WebConnectionProtocol1Hello: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol1HelloPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol1HelloType') }, + ], + false + ), + WebConnectionProtocol1HelloMeta: o( + [ + { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: '' }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + WebConnectionProtocol1HelloPayload: o( + [ + { json: 'actualUrl', js: 'actualUrl', typ: '' }, + { json: 'channelSelector', js: 'channelSelector', typ: u(undefined, true) }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'identityUrl', js: 'identityUrl', typ: '' }, + { json: 'intentResolver', js: 'intentResolver', typ: u(undefined, true) }, + ], + 'any' + ), + WebConnectionProtocol2LoadURL: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol2LoadURLPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol2LoadURLType') }, + ], + false + ), + WebConnectionProtocol2LoadURLPayload: o([{ json: 'iframeUrl', js: 'iframeUrl', typ: '' }], 'any'), + WebConnectionProtocol3Handshake: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol3HandshakePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol3HandshakeType') }, + ], + false + ), + WebConnectionProtocol3HandshakePayload: o( + [ + { json: 'channelSelectorUrl', js: 'channelSelectorUrl', typ: u(true, '') }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'intentResolverUrl', js: 'intentResolverUrl', typ: u(true, '') }, + ], + false + ), + WebConnectionProtocol4ValidateAppIdentity: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol4ValidateAppIdentityPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol4ValidateAppIdentityType') }, + ], + false + ), + WebConnectionProtocol4ValidateAppIdentityPayload: o( + [ + { json: 'actualUrl', js: 'actualUrl', typ: '' }, + { json: 'identityUrl', js: 'identityUrl', typ: '' }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + { json: 'instanceUuid', js: 'instanceUuid', typ: u(undefined, '') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentityFailedResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponseType') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload: o( + [{ json: 'message', js: 'message', typ: u(undefined, '') }], + false + ), + WebConnectionProtocol5ValidateAppIdentitySuccessResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponseType') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'implementationMetadata', js: 'implementationMetadata', typ: r('ImplementationMetadata') }, + { json: 'instanceId', js: 'instanceId', typ: '' }, + { json: 'instanceUuid', js: 'instanceUuid', typ: '' }, + ], + false + ), + WebConnectionProtocol6Goodbye: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol6GoodbyeMeta') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol6GoodbyeType') }, + ], + false + ), + WebConnectionProtocol6GoodbyeMeta: o([{ json: 'timestamp', js: 'timestamp', typ: Date }], false), + WebConnectionProtocolMessage: o( [ - { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentResultResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentResultResponseType') }, + { json: 'meta', js: 'meta', typ: r('ConnectionStepMetadata') }, + { json: 'payload', js: 'payload', typ: u(undefined, m('any')) }, + { json: 'type', js: 'type', typ: r('ConnectionStepMessageType') }, ], false ), - RaiseIntentResultResponsePayload: o( + ConnectionStepMetadata: o( [ - { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, - { json: 'intentResult', js: 'intentResult', typ: u(undefined, r('IntentResult')) }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: u(undefined, '') }, ], false ), - WebConnectionProtocol1HelloType: ['WCP1Hello'], - WebConnectionProtocol2LoadURLType: ['WCP2LoadUrl'], - WebConnectionProtocol3HandshakeType: ['WCP3Handshake'], - WebConnectionProtocol4ValidateAppIdentityType: ['WCP4ValidateAppIdentity'], - WebConnectionProtocol5ValidateAppIdentityFailedResponseType: ['WCP5ValidateAppIdentityFailedResponse'], - WebConnectionProtocol5ValidateAppIdentitySuccessResponseType: ['WCP5ValidateAppIdentityResponse'], - WebConnectionProtocol6GoodbyeType: ['WCP6Goodbye'], - ConnectionStepMessageType: [ - 'WCP1Hello', - 'WCP2LoadUrl', - 'WCP3Handshake', - 'WCP4ValidateAppIdentity', - 'WCP5ValidateAppIdentityFailedResponse', - 'WCP5ValidateAppIdentityResponse', - 'WCP6Goodbye', - ], AddContextListenerRequestType: ['addContextListenerRequest'], PurpleError: ['AccessDenied', 'CreationFailed', 'MalformedContext', 'NoChannelFound'], AddContextListenerResponseType: ['addContextListenerResponse'], @@ -6074,8 +6058,8 @@ const typeMap: any = { CreatePrivateChannelResponseType: ['createPrivateChannelResponse'], EventListenerUnsubscribeRequestType: ['eventListenerUnsubscribeRequest'], EventListenerUnsubscribeResponseType: ['eventListenerUnsubscribeResponse'], - Fdc3UserInterfaceChannelSelectedType: ['Fdc3UserInterfaceChannelSelected'], Fdc3UserInterfaceChannelsType: ['Fdc3UserInterfaceChannels'], + Fdc3UserInterfaceChannelSelectedType: ['Fdc3UserInterfaceChannelSelected'], Fdc3UserInterfaceDragType: ['Fdc3UserInterfaceDrag'], Fdc3UserInterfaceHandshakeType: ['Fdc3UserInterfaceHandshake'], Fdc3UserInterfaceHelloType: ['Fdc3UserInterfaceHello'], @@ -6166,6 +6150,22 @@ const typeMap: any = { RaiseIntentRequestType: ['raiseIntentRequest'], RaiseIntentResponseType: ['raiseIntentResponse'], RaiseIntentResultResponseType: ['raiseIntentResultResponse'], + WebConnectionProtocol1HelloType: ['WCP1Hello'], + WebConnectionProtocol2LoadURLType: ['WCP2LoadUrl'], + WebConnectionProtocol3HandshakeType: ['WCP3Handshake'], + WebConnectionProtocol4ValidateAppIdentityType: ['WCP4ValidateAppIdentity'], + WebConnectionProtocol5ValidateAppIdentityFailedResponseType: ['WCP5ValidateAppIdentityFailedResponse'], + WebConnectionProtocol5ValidateAppIdentitySuccessResponseType: ['WCP5ValidateAppIdentityResponse'], + WebConnectionProtocol6GoodbyeType: ['WCP6Goodbye'], + ConnectionStepMessageType: [ + 'WCP1Hello', + 'WCP2LoadUrl', + 'WCP3Handshake', + 'WCP4ValidateAppIdentity', + 'WCP5ValidateAppIdentityFailedResponse', + 'WCP5ValidateAppIdentityResponse', + 'WCP6Goodbye', + ], }; export type AppRequestMessage = @@ -6191,224 +6191,49 @@ export type AppRequestMessage = | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest - | PrivateChannelAddEventListenerRequest - | PrivateChannelDisconnectRequest - | PrivateChannelUnsubscribeEventListenerRequest - | RaiseIntentForContextRequest - | RaiseIntentRequest; - -export type AgentResponseMessage = - | AddContextListenerResponse - | AddEventListenerResponse - | AddIntentListenerResponse - | BroadcastResponse - | ContextListenerUnsubscribeResponse - | CreatePrivateChannelResponse - | EventListenerUnsubscribeResponse - | FindInstancesResponse - | FindIntentResponse - | FindIntentsByContextResponse - | GetAppMetadataResponse - | GetCurrentChannelResponse - | GetCurrentContextResponse - | GetInfoResponse - | GetOrCreateChannelResponse - | GetUserChannelsResponse - | IntentListenerUnsubscribeResponse - | IntentResultResponse - | JoinUserChannelResponse - | LeaveCurrentChannelResponse - | OpenResponse - | PrivateChannelAddEventListenerResponse - | PrivateChannelDisconnectResponse - | PrivateChannelUnsubscribeEventListenerResponse - | RaiseIntentForContextResponse - | RaiseIntentResponse - | RaiseIntentResultResponse; - -export type AgentEventMessage = - | BroadcastEvent - | ChannelChangedEvent - | HeartbeatEvent - | IntentEvent - | PrivateChannelOnAddContextListenerEvent - | PrivateChannelOnDisconnectEvent - | PrivateChannelOnUnsubscribeEvent; - -/** - * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - return value != null && value.type === 'WCP1Hello'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - try { - Convert.webConnectionProtocol1HelloToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = 'WebConnectionProtocol1Hello'; - -/** - * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - return value != null && value.type === 'WCP2LoadUrl'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - try { - Convert.webConnectionProtocol2LoadURLToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = 'WebConnectionProtocol2LoadURL'; - -/** - * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - return value != null && value.type === 'WCP3Handshake'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - try { - Convert.webConnectionProtocol3HandshakeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = 'WebConnectionProtocol3Handshake'; - -/** - * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol4ValidateAppIdentity( - value: any -): value is WebConnectionProtocol4ValidateAppIdentity { - return value != null && value.type === 'WCP4ValidateAppIdentity'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol4ValidateAppIdentity( - value: any -): value is WebConnectionProtocol4ValidateAppIdentity { - try { - Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = 'WebConnectionProtocol4ValidateAppIdentity'; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = - 'WebConnectionProtocol5ValidateAppIdentityFailedResponse'; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = - 'WebConnectionProtocol5ValidateAppIdentitySuccessResponse'; - -/** - * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - return value != null && value.type === 'WCP6Goodbye'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - try { - Convert.webConnectionProtocol6GoodbyeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = 'WebConnectionProtocol6Goodbye'; + | PrivateChannelAddEventListenerRequest + | PrivateChannelDisconnectRequest + | PrivateChannelUnsubscribeEventListenerRequest + | RaiseIntentForContextRequest + | RaiseIntentRequest; -/** - * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { - try { - Convert.webConnectionProtocolMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } -} +export type AgentResponseMessage = + | AddContextListenerResponse + | AddEventListenerResponse + | AddIntentListenerResponse + | BroadcastResponse + | ContextListenerUnsubscribeResponse + | CreatePrivateChannelResponse + | EventListenerUnsubscribeResponse + | FindInstancesResponse + | FindIntentResponse + | FindIntentsByContextResponse + | GetAppMetadataResponse + | GetCurrentChannelResponse + | GetCurrentContextResponse + | GetInfoResponse + | GetOrCreateChannelResponse + | GetUserChannelsResponse + | IntentListenerUnsubscribeResponse + | IntentResultResponse + | JoinUserChannelResponse + | LeaveCurrentChannelResponse + | OpenResponse + | PrivateChannelAddEventListenerResponse + | PrivateChannelDisconnectResponse + | PrivateChannelUnsubscribeEventListenerResponse + | RaiseIntentForContextResponse + | RaiseIntentResponse + | RaiseIntentResultResponse; -export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = 'WebConnectionProtocolMessage'; +export type AgentEventMessage = + | BroadcastEvent + | ChannelChangedEvent + | HeartbeatEvent + | IntentEvent + | PrivateChannelOnAddContextListenerEvent + | PrivateChannelOnDisconnectEvent + | PrivateChannelOnUnsubscribeEvent; /** * Returns true if the value has a type property with value 'addContextListenerRequest'. This is a fast check that does not check the format of the message @@ -6747,46 +6572,46 @@ export function isValidEventListenerUnsubscribeResponse(value: any): value is Ev export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = 'EventListenerUnsubscribeResponse'; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { - return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; +export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { + return value != null && value.type === 'Fdc3UserInterfaceChannels'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { +export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { try { - Convert.fdc3UserInterfaceChannelSelectedToJson(value); + Convert.fdc3UserInterfaceChannelsToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = 'Fdc3UserInterfaceChannelSelected'; +export const FDC3_USER_INTERFACE_CHANNELS_TYPE = 'Fdc3UserInterfaceChannels'; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { - return value != null && value.type === 'Fdc3UserInterfaceChannels'; +export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { + return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { +export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { try { - Convert.fdc3UserInterfaceChannelsToJson(value); + Convert.fdc3UserInterfaceChannelSelectedToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNELS_TYPE = 'Fdc3UserInterfaceChannels'; +export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = 'Fdc3UserInterfaceChannelSelected'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceDrag'. This is a fast check that does not check the format of the message @@ -7889,3 +7714,178 @@ export function isValidRaiseIntentResultResponse(value: any): value is RaiseInte } export const RAISE_INTENT_RESULT_RESPONSE_TYPE = 'RaiseIntentResultResponse'; + +/** + * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + return value != null && value.type === 'WCP1Hello'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + try { + Convert.webConnectionProtocol1HelloToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = 'WebConnectionProtocol1Hello'; + +/** + * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + return value != null && value.type === 'WCP2LoadUrl'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + try { + Convert.webConnectionProtocol2LoadURLToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = 'WebConnectionProtocol2LoadURL'; + +/** + * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + return value != null && value.type === 'WCP3Handshake'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + try { + Convert.webConnectionProtocol3HandshakeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = 'WebConnectionProtocol3Handshake'; + +/** + * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol4ValidateAppIdentity( + value: any +): value is WebConnectionProtocol4ValidateAppIdentity { + return value != null && value.type === 'WCP4ValidateAppIdentity'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol4ValidateAppIdentity( + value: any +): value is WebConnectionProtocol4ValidateAppIdentity { + try { + Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = 'WebConnectionProtocol4ValidateAppIdentity'; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = + 'WebConnectionProtocol5ValidateAppIdentityFailedResponse'; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = + 'WebConnectionProtocol5ValidateAppIdentitySuccessResponse'; + +/** + * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + return value != null && value.type === 'WCP6Goodbye'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + try { + Convert.webConnectionProtocol6GoodbyeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = 'WebConnectionProtocol6Goodbye'; + +/** + * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { + try { + Convert.webConnectionProtocolMessageToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = 'WebConnectionProtocolMessage'; diff --git a/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts b/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts index 329f34c57..9ce69445f 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts @@ -31,13 +31,16 @@ const setup = ( intentSelect.appendChild(option); }); - intentSelect.addEventListener('change', e => - fillList( - data.appIntents.filter(ai => ai.intent.name == e?.target?.value), - e?.target?.value, - callback - ) - ); + intentSelect.addEventListener('change', e => { + if (e.target) { + const option = e.target as HTMLOptionElement; + fillList( + data.appIntents.filter(ai => ai.intent.name == option.value), + option.value, + callback + ); + } + }); fillList( data.appIntents.filter(ai => ai.intent.name == intentSelect.value), @@ -58,8 +61,8 @@ const setup = ( }); tab.setAttribute('aria-selected', 'true'); - const listRef = tab.getAttribute('data-list-ref')!!; - document.getElementById(listRef)!!.setAttribute('data-visible', 'true'); + const listRef = tab.getAttribute('data-list-ref')!; + document.getElementById(listRef)!.setAttribute('data-visible', 'true'); }); }); @@ -131,7 +134,7 @@ const fillList = ( }); // then, populate the "Open Apps" tab - const openList = document.getElementById('open-list')!!; + const openList = document.getElementById('open-list')!; openList.innerHTML = ''; openApps.forEach(({ appId, title, icons, instanceId }) => { From 1f42fa64edb293927e1d95bee0297be13b463d95 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 19 Dec 2024 17:56:31 +0000 Subject: [PATCH 62/90] Addressing Rob's coverage comments --- packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts | 1 + .../fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts | 1 + packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts | 2 ++ packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts | 4 +++- .../test/step-definitions/port-creation.steps.ts | 2 +- toolbox/fdc3-for-web/reference-ui/public/intent_resolver.html | 4 ++-- 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index a256ea491..701486e8d 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -56,6 +56,7 @@ export class DefaultChannel implements Channel { let theContextType: string | null; let theHandler: ContextHandler; + /* istanbul ignore else */ if (contextTypeOrHandler == null && handler) { theContextType = null; theHandler = handler; diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index ae49155d9..a825b1185 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -74,6 +74,7 @@ export class DefaultChannelSupport implements ChannelSupport { ); //handle successful responses - errors will already have been thrown by exchange above + /* istanbul ignore else */ if (response.payload.channel) { return new DefaultChannel( this.messaging, diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index f3cb392cd..cfc517152 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -138,6 +138,7 @@ export class DefaultIntentSupport implements IntentSupport { ResolveError.NoAppsFound ); + /* istanbul ignore else */ if (response.payload.appIntent) { // Needs further resolution, we need to invoke the resolver const result: IntentResolutionChoice | void = await this.intentResolver.chooseIntent( @@ -183,6 +184,7 @@ export class DefaultIntentSupport implements IntentSupport { ResolveError.NoAppsFound ); + /* istanbul ignore else */ if (response.payload.appIntents) { // Needs further resolution, we need to invoke the resolver const result: IntentResolutionChoice | void = await this.intentResolver.chooseIntent( diff --git a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts index 237bafda2..2e22b5e51 100644 --- a/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/AbstractListener.ts @@ -80,6 +80,7 @@ export abstract class AbstractListener impleme abstract action(m: AgentEventMessage): void; async unsubscribe(): Promise { + /* istanbul ignore else */ if (this.id) { this.messaging.unregister(this.id); const unsubscribeMessage: UnsubscribeRequest = { @@ -92,7 +93,8 @@ export abstract class AbstractListener impleme await this.messaging.exchange(unsubscribeMessage, this.unsubscribeResponseType); return; } else { - console.error("This listener doesn't have an id and hence can't be removed!"); + //should never happen as we throw on creating a listener without an ID + throw new Error("This listener doesn't have an id and hence can't be removed!"); } } diff --git a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts index 0b8a69942..044581de4 100644 --- a/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts +++ b/packages/fdc3-get-agent/test/step-definitions/port-creation.steps.ts @@ -31,7 +31,7 @@ Given( ); Given('{string} pipes messages to {string}', async function (this: CustomWorld, port: string, output: string) { - const out: { type: string; data: any }[] = []; + const out: { type: string; data: unknown }[] = []; this.props[output] = out; const internalPort = handleResolve(port, this); diff --git a/toolbox/fdc3-for-web/reference-ui/public/intent_resolver.html b/toolbox/fdc3-for-web/reference-ui/public/intent_resolver.html index b090ad3d5..46397dd11 100644 --- a/toolbox/fdc3-for-web/reference-ui/public/intent_resolver.html +++ b/toolbox/fdc3-for-web/reference-ui/public/intent_resolver.html @@ -124,8 +124,8 @@

Intent Resolver

Resolve intent for: -
+ +
From 279bad32c460a4c757336d8fd845cd2c8b4b8880 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 19 Dec 2024 18:29:15 +0000 Subject: [PATCH 63/90] SSimplify DefaultIntentSupport.raiseIntent* coverage --- .../src/intents/DefaultIntentSupport.ts | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts index cfc517152..7d09a86a7 100644 --- a/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts +++ b/packages/fdc3-agent-proxy/src/intents/DefaultIntentSupport.ts @@ -132,13 +132,12 @@ export class DefaultIntentSupport implements IntentSupport { ); throwIfUndefined( - response.payload.error ?? response.payload.appIntent ?? response.payload.intentResolution, - 'Invalid response from Desktop Agent to raiseIntent!', + response.payload.appIntent ?? response.payload.intentResolution, + 'Invalid response from Desktop Agent to raiseIntent, either payload.appIntent or payload.intentResolution must be set!', response, ResolveError.NoAppsFound ); - /* istanbul ignore else */ if (response.payload.appIntent) { // Needs further resolution, we need to invoke the resolver const result: IntentResolutionChoice | void = await this.intentResolver.chooseIntent( @@ -150,13 +149,10 @@ export class DefaultIntentSupport implements IntentSupport { } else { throw new Error(ResolveError.UserCancelled); } - } else if (response.payload.intentResolution) { + } else { // Was resolved - const details = response.payload.intentResolution; + const details = response.payload.intentResolution!; return new DefaultIntentResolution(this.messaging, resultPromise, details.source, details.intent); - } else { - //Should never get here as we will throw in exchange or throwIfUndefined above - throw new Error(response.payload.error ?? 'Unexpected error processing raiseIntent'); } } @@ -179,12 +175,11 @@ export class DefaultIntentSupport implements IntentSupport { throwIfUndefined( response.payload.appIntents ?? response.payload.intentResolution, - 'Invalid response from Desktop Agent to raiseIntentForContext!', + 'Invalid response from Desktop Agent to raiseIntentForContext, either payload.appIntents or payload.intentResolution must be set!', response, ResolveError.NoAppsFound ); - /* istanbul ignore else */ if (response.payload.appIntents) { // Needs further resolution, we need to invoke the resolver const result: IntentResolutionChoice | void = await this.intentResolver.chooseIntent( @@ -196,13 +191,10 @@ export class DefaultIntentSupport implements IntentSupport { } else { throw new Error(ResolveError.UserCancelled); } - } else if (response.payload.intentResolution) { + } else { // Was resolved - const details = response.payload.intentResolution; + const details = response.payload.intentResolution!; return new DefaultIntentResolution(this.messaging, resultPromise, details.source, details.intent); - } else { - //Should never get here as we will throw in exchange or throwIfUndefined above - throw new Error(response.payload.error ?? 'Unexpected error processing raiseIntentForContext'); } } From 442956d906577fdac8bd1d0f75caf4f7611b6b1d Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 20 Dec 2024 13:09:16 +0000 Subject: [PATCH 64/90] Test channel selector callback --- .../src/channels/DefaultChannelSupport.ts | 3 +- .../features/user-channel-selector.feature | 18 +++++ .../test/features/user-channel-sync.feature | 2 +- .../step-definitions/channelSelector.steps.ts | 65 +++++++++++++++++++ .../test/support/TestChannelSelector.ts | 47 ++++++++++++++ .../fdc3-standard/src/ui/ChannelSelector.ts | 2 +- 6 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 packages/fdc3-agent-proxy/test/features/user-channel-selector.feature create mode 100644 packages/fdc3-agent-proxy/test/step-definitions/channelSelector.steps.ts create mode 100644 packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index a825b1185..d09033bcb 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -40,6 +40,7 @@ export class DefaultChannelSupport implements ChannelSupport { this.messaging = messaging; this.channelSelector = channelSelector; this.channelSelector.setChannelChangeCallback((channelId: string | null) => { + console.log('CHANNEL SELECTOR CALLBACK!'); if (channelId == null) { this.leaveUserChannel(); } else { @@ -48,7 +49,7 @@ export class DefaultChannelSupport implements ChannelSupport { }); this.addChannelChangedEventHandler(e => { - this.channelSelector.updateChannel(e.details.newChannelId, this.userChannels ?? []); + this.channelSelector.updateChannel(e.details.newChannelId, this.userChannels); }); } diff --git a/packages/fdc3-agent-proxy/test/features/user-channel-selector.feature b/packages/fdc3-agent-proxy/test/features/user-channel-selector.feature new file mode 100644 index 000000000..cecbb46fe --- /dev/null +++ b/packages/fdc3-agent-proxy/test/features/user-channel-selector.feature @@ -0,0 +1,18 @@ +Feature: Updating User Channel State + + Background: + Given schemas loaded + Given User Channels one, two and three + And A Channel Selector in "selector" and a Desktop Agent in "api" + + Scenario: Selecting a channel updates the DA + When The first channel is selected via the channel selector in "selector" + And The second channel is selected via the channel selector in "selector" + Then messaging will have posts + | payload.channelId | matches_type | + | one | joinUserChannelRequest | + | two | joinUserChannelRequest | + And The channel is deselected via the channel selector in "selector" + Then messaging will have posts + | matches_type | + | leaveCurrentChannelRequest | diff --git a/packages/fdc3-agent-proxy/test/features/user-channel-sync.feature b/packages/fdc3-agent-proxy/test/features/user-channel-sync.feature index e318cd62b..8432dec43 100644 --- a/packages/fdc3-agent-proxy/test/features/user-channel-sync.feature +++ b/packages/fdc3-agent-proxy/test/features/user-channel-sync.feature @@ -28,7 +28,7 @@ Feature: Updating User Channel State | {null} | {null} | {null} | getCurrentChannelRequest | | one | fdc3.instrument | {null} | getCurrentContextRequest | - Scenario: Changing User Channel Doesn't Receive Incoorrect Context on Listener + Scenario: Changing User Channel Doesn't Receive Incorrect Context on Listener Given "resultHandler" pipes context to "contexts" And I call "{api}" with "addContextListener" with parameters "fdc3.instrument" and "{resultHandler}" When I call "{api}" with "joinUserChannel" with parameter "two" diff --git a/packages/fdc3-agent-proxy/test/step-definitions/channelSelector.steps.ts b/packages/fdc3-agent-proxy/test/step-definitions/channelSelector.steps.ts new file mode 100644 index 000000000..9d91faac9 --- /dev/null +++ b/packages/fdc3-agent-proxy/test/step-definitions/channelSelector.steps.ts @@ -0,0 +1,65 @@ +import { Given, When } from '@cucumber/cucumber'; +import { SimpleIntentResolver } from '@kite9/testing'; +import { CustomWorld } from '../world/index'; +import { CHANNEL_STATE } from '@kite9/testing'; +import { + DefaultChannelSupport, + DefaultHeartbeatSupport, + DefaultIntentSupport, + DefaultAppSupport, + DesktopAgentProxy, +} from '../../src'; +import { TestChannelSelector } from '../support/TestChannelSelector'; +import { TestMessaging } from '../support/TestMessaging'; + +Given( + 'A Channel Selector in {string} and a Desktop Agent in {string}', + async function (this: CustomWorld, selectorField: string, daField: string) { + if (!this.messaging) { + this.messaging = new TestMessaging(this.props[CHANNEL_STATE]); + } + + const ts = new TestChannelSelector(); + this.props[selectorField] = ts; + + const cs = new DefaultChannelSupport(this.messaging, ts); + const hs = new DefaultHeartbeatSupport(this.messaging); + const is = new DefaultIntentSupport(this.messaging, new SimpleIntentResolver(this)); + const as = new DefaultAppSupport(this.messaging); + + const da = new DesktopAgentProxy(hs, cs, is, as, [hs]); + await da.connect(); + + this.props[daField] = da; + this.props['result'] = null; + + //populate the channel selector + const channel = await cs.getUserChannel(); + const userChannels = await cs.getUserChannels(); + ts.updateChannel(channel?.id ?? null, userChannels); + } +); + +When( + 'The first channel is selected via the channel selector in {string}', + async function (this: CustomWorld, selectorField: string) { + const selector = this.props[selectorField] as TestChannelSelector; + selector.selectFirstChannel(); + } +); + +When( + 'The second channel is selected via the channel selector in {string}', + async function (this: CustomWorld, selectorField: string) { + const selector = this.props[selectorField] as TestChannelSelector; + selector.selectSecondChannel(); + } +); + +When( + 'The channel is deselected via the channel selector in {string}', + async function (this: CustomWorld, selectorField: string) { + const selector = this.props[selectorField] as TestChannelSelector; + selector.deselectChannel(); + } +); diff --git a/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts b/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts new file mode 100644 index 000000000..c23e5850a --- /dev/null +++ b/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts @@ -0,0 +1,47 @@ +import { Channel, ChannelSelector } from '@kite9/fdc3-standard'; + +export class TestChannelSelector implements ChannelSelector { + private callback: ((channelId: string | null) => void) | null = null; + channelId: string | null = null; + channels: Channel[] = []; + + constructor() {} + + updateChannel(channelId: string | null, availableChannels: Channel[]): void { + this.channelId = channelId; + this.channels = availableChannels; + } + + setChannelChangeCallback(callback: (channelId: string | null) => void): void { + this.callback = callback; + } + + async connect(): Promise { + console.log('TestChannelSelector was connected'); + } + + async disconnect(): Promise { + console.log('TestChannelSelector was diconnected'); + } + + selectChannel(channelId: string | null): void { + this.channelId = channelId; + if (this.callback) { + this.callback(this.channelId); + } else { + throw new Error('Channel selected before Channel Change callback was set!'); + } + } + + selectFirstChannel(): void { + this.selectChannel(this.channels[0].id); + } + + selectSecondChannel(): void { + this.selectChannel(this.channels[1].id); + } + + deselectChannel(): void { + this.selectChannel(null); + } +} diff --git a/packages/fdc3-standard/src/ui/ChannelSelector.ts b/packages/fdc3-standard/src/ui/ChannelSelector.ts index 7c6ab4aa5..07f36626e 100644 --- a/packages/fdc3-standard/src/ui/ChannelSelector.ts +++ b/packages/fdc3-standard/src/ui/ChannelSelector.ts @@ -11,7 +11,7 @@ export interface ChannelSelector extends Connectable { updateChannel(channelId: string | null, availableChannels: Channel[]): void; /** - * Called on initialisation. The channel selector will invoke the callback after the + * Called on initialization. The channel selector will invoke the callback after the * channel is changed. */ setChannelChangeCallback(callback: (channelId: string | null) => void): void; From d65d1db07b5861ae8f2df20ae0aa1bcbc27c26d3 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 23 Dec 2024 18:20:49 +0000 Subject: [PATCH 65/90] Make sure MessagePort is started for identity validation --- .../src/messaging/MessagePortMessaging.ts | 4 +-- .../src/messaging/message-port.ts | 3 +- .../src/strategies/FailoverHandler.ts | 4 +++ .../strategies/IdentityValidationHandler.ts | 28 +++++++++---------- .../src/strategies/PostMessageLoader.ts | 4 +++ 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts index 6cb4d55c5..9be07e660 100644 --- a/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts +++ b/packages/fdc3-get-agent/src/messaging/MessagePortMessaging.ts @@ -35,13 +35,13 @@ export class MessagePortMessaging extends AbstractMessaging { * post-connection. */ this.messageExchangeTimeout = MESSAGE_EXCHANGE_TIMEOUT; - this.cd.messagePort.onmessage = m => { + this.cd.messagePort.addEventListener('message', m => { this.listeners.forEach(v => { if (v.filter(m.data)) { v.action(m.data); } }); - }; + }); } createUUID(): string { diff --git a/packages/fdc3-get-agent/src/messaging/message-port.ts b/packages/fdc3-get-agent/src/messaging/message-port.ts index ba1dc56f4..66435bc9d 100644 --- a/packages/fdc3-get-agent/src/messaging/message-port.ts +++ b/packages/fdc3-get-agent/src/messaging/message-port.ts @@ -23,7 +23,8 @@ export async function createDesktopAgentAPI( appIdentifier: AppIdentifier ): Promise { Logger.debug('message-port: Creating Desktop Agent...'); - cd.messagePort.start(); + + //Message port should have already been started for use in identity validation function string(o: string | boolean): string | null { if (o == true || o == false) { diff --git a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts index 23b103948..41510f7b4 100644 --- a/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/FailoverHandler.ts @@ -80,6 +80,10 @@ export class FailoverHandler { this.connectionAttemptUuid ); const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + + //start the message port so that we can receive responses + connectionDetails.messagePort.start(); + this.identityValidationHandler.sendIdValidationMessage(); const idDetails = await idValidationPromise; const appIdentifier: AppIdentifier = { diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts index 18eb88e9d..8659ea152 100644 --- a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -69,20 +69,6 @@ export class IdentityValidationHandler { /** Listen for WCP responses over the message port to identity validation messages. */ listenForIDValidationResponses(): Promise { return new Promise((resolve, reject) => { - //timeout for id validation only - const timeout = setTimeout(() => { - Logger.warn(`IdentityValidationHandler: Identity validation timed out`); - - if (this.idValidationResponseListener) { - //remove the event listener as we won't proceed further - this.messagePort.removeEventListener('message', this.idValidationResponseListener); - } - Logger.error( - `The Desktop Agent didn't respond to ID validation within ${ID_VALIDATION_TIMEOUT / 1000} seconds` - ); - reject(AgentError.ErrorOnConnect); - }, ID_VALIDATION_TIMEOUT); - // setup listener for message and retrieve JS URL from it this.idValidationResponseListener = (event: MessageEvent) => { const data = event.data; @@ -126,6 +112,20 @@ export class IdentityValidationHandler { //listening on a message port this.messagePort.addEventListener('message', this.idValidationResponseListener); + + //timeout for id validation only + const timeout = setTimeout(() => { + Logger.warn(`IdentityValidationHandler: Identity validation timed out`); + + if (this.idValidationResponseListener) { + //remove the event listener as we won't proceed further + this.messagePort.removeEventListener('message', this.idValidationResponseListener); + } + Logger.error( + `The Desktop Agent didn't respond to ID validation within ${ID_VALIDATION_TIMEOUT / 1000} seconds` + ); + reject(AgentError.ErrorOnConnect); + }, ID_VALIDATION_TIMEOUT); }); } diff --git a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts index 07b1591c4..a4f6b18bd 100644 --- a/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts +++ b/packages/fdc3-get-agent/src/strategies/PostMessageLoader.ts @@ -114,6 +114,10 @@ export class PostMessageLoader implements Loader { this.connectionAttemptUuid ); const idValidationPromise = this.identityValidationHandler.listenForIDValidationResponses(); + + //start the message port so that we can receive responses + connectionDetails.messagePort.start(); + this.identityValidationHandler.sendIdValidationMessage(); idValidationPromise From 9b06c26fc5d4c29401acd54f95b102c84e3ad6c8 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 23 Dec 2024 19:49:18 +0000 Subject: [PATCH 66/90] fix dependency mismatches --- package-lock.json | 3822 +++++++---------- packages/fdc3-agent-proxy/package.json | 10 +- packages/fdc3-context/package.json | 14 +- packages/fdc3-get-agent/package.json | 4 +- packages/fdc3-schema/package.json | 16 +- packages/fdc3-standard/package.json | 18 +- packages/fdc3/package.json | 2 +- packages/testing/package.json | 12 +- .../fdc3-for-web/fdc3-web-impl/package.json | 10 +- .../fdc3-for-web/reference-ui/package.json | 4 +- toolbox/fdc3-workbench/package.json | 12 +- 11 files changed, 1674 insertions(+), 2250 deletions(-) diff --git a/package-lock.json b/package-lock.json index 750448698..1939d2108 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2483,11 +2483,10 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", - "dev": true, + "version": "0.19.1", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", "dependencies": { - "@eslint/object-schema": "^2.1.4", + "@eslint/object-schema": "^2.1.5", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -2496,9 +2495,11 @@ } }, "node_modules/@eslint/core": { - "version": "0.6.0", - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", - "dev": true, + "version": "0.9.1", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -2506,7 +2507,6 @@ "node_modules/@eslint/eslintrc": { "version": "3.2.0", "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", - "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -2528,7 +2528,6 @@ "node_modules/@eslint/eslintrc/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2543,7 +2542,6 @@ "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, "engines": { "node": ">=18" }, @@ -2553,8 +2551,7 @@ }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/@eslint/js": { "version": "9.16.0", @@ -2567,7 +2564,6 @@ "node_modules/@eslint/object-schema": { "version": "2.1.5", "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", - "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -2575,7 +2571,6 @@ "node_modules/@eslint/plugin-kit": { "version": "0.2.3", "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", - "dev": true, "dependencies": { "levn": "^0.4.1" }, @@ -2650,7 +2645,6 @@ "node_modules/@humanfs/core": { "version": "0.19.1", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, "engines": { "node": ">=18.18.0" } @@ -2658,7 +2652,6 @@ "node_modules/@humanfs/node": { "version": "0.16.6", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -2671,6 +2664,7 @@ "version": "0.13.0", "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", + "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -2694,12 +2688,12 @@ "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead" + "deprecated": "Use @eslint/object-schema instead", + "peer": true }, "node_modules/@humanwhocodes/retry": { "version": "0.3.1", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, "engines": { "node": ">=18.18" }, @@ -4014,8 +4008,7 @@ }, "node_modules/@types/estree": { "version": "1.0.6", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "node_modules/@types/expect": { "version": "24.3.0", @@ -4165,11 +4158,6 @@ "version": "2.4.4", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==" }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, "node_modules/@types/prop-types": { "version": "15.7.13", "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" @@ -4215,7 +4203,8 @@ }, "node_modules/@types/semver": { "version": "7.5.8", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true }, "node_modules/@types/send": { "version": "0.17.4", @@ -4284,6 +4273,9 @@ "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.1.1", "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", "@typescript-eslint/scope-manager": "7.1.1", @@ -4317,6 +4309,9 @@ "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { "version": "7.6.3", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "optional": true, + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -4327,6 +4322,9 @@ "node_modules/@typescript-eslint/parser": { "version": "7.1.0", "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.1.0", "@typescript-eslint/types": "7.1.0", @@ -4353,6 +4351,9 @@ "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { "version": "7.1.0", "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "7.1.0", "@typescript-eslint/visitor-keys": "7.1.0" @@ -4368,6 +4369,9 @@ "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { "version": "7.1.0", "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "7.1.0", "eslint-visitor-keys": "^3.4.1" @@ -4383,6 +4387,7 @@ "node_modules/@typescript-eslint/scope-manager": { "version": "7.1.1", "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", + "dev": true, "dependencies": { "@typescript-eslint/types": "7.1.1", "@typescript-eslint/visitor-keys": "7.1.1" @@ -4398,6 +4403,7 @@ "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { "version": "7.1.1", "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", + "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4409,6 +4415,9 @@ "node_modules/@typescript-eslint/type-utils": { "version": "7.1.1", "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/typescript-estree": "7.1.1", "@typescript-eslint/utils": "7.1.1", @@ -4434,6 +4443,9 @@ "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { "version": "7.1.1", "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", + "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4445,6 +4457,9 @@ "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "7.1.1", "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "7.1.1", "@typescript-eslint/visitor-keys": "7.1.1", @@ -4471,6 +4486,9 @@ "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { "version": "2.0.1", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -4478,6 +4496,9 @@ "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { "version": "9.0.3", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4491,6 +4512,9 @@ "node_modules/@typescript-eslint/type-utils/node_modules/semver": { "version": "7.6.3", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "optional": true, + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -4501,6 +4525,9 @@ "node_modules/@typescript-eslint/types": { "version": "7.1.0", "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4512,6 +4539,9 @@ "node_modules/@typescript-eslint/typescript-estree": { "version": "7.1.0", "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "7.1.0", "@typescript-eslint/visitor-keys": "7.1.0", @@ -4538,6 +4568,9 @@ "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/visitor-keys": { "version": "7.1.0", "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "7.1.0", "eslint-visitor-keys": "^3.4.1" @@ -4553,6 +4586,9 @@ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "2.0.1", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -4560,6 +4596,9 @@ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.3", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4573,6 +4612,9 @@ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.6.3", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "optional": true, + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -4583,6 +4625,7 @@ "node_modules/@typescript-eslint/utils": { "version": "7.1.1", "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", + "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", @@ -4606,6 +4649,7 @@ "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { "version": "7.1.1", "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", + "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4617,6 +4661,7 @@ "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { "version": "7.1.1", "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", + "dev": true, "dependencies": { "@typescript-eslint/types": "7.1.1", "@typescript-eslint/visitor-keys": "7.1.1", @@ -4643,6 +4688,7 @@ "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { "version": "2.0.1", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -4650,6 +4696,7 @@ "node_modules/@typescript-eslint/utils/node_modules/minimatch": { "version": "9.0.3", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4663,6 +4710,7 @@ "node_modules/@typescript-eslint/utils/node_modules/semver": { "version": "7.6.3", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -4673,6 +4721,7 @@ "node_modules/@typescript-eslint/visitor-keys": { "version": "7.1.1", "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", + "dev": true, "dependencies": { "@typescript-eslint/types": "7.1.1", "eslint-visitor-keys": "^3.4.1" @@ -4688,6 +4737,7 @@ "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { "version": "7.1.1", "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", + "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4698,7 +4748,8 @@ }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "peer": true }, "node_modules/@vitejs/plugin-legacy": { "version": "5.4.3", @@ -5018,6 +5069,7 @@ "node_modules/array-union": { "version": "2.1.0", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, "engines": { "node": ">=8" } @@ -5140,14 +5192,6 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, - "node_modules/astral-regex": { - "version": "2.0.0", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async": { "version": "3.2.6", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", @@ -6529,6 +6573,7 @@ "node_modules/dir-glob": { "version": "3.0.1", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -6539,6 +6584,7 @@ "node_modules/doctrine": { "version": "3.0.0", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -7042,6 +7088,7 @@ "version": "8.57.1", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -7335,6 +7382,7 @@ "node_modules/eslint-scope": { "version": "7.2.2", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -7359,6 +7407,7 @@ "node_modules/eslint/node_modules/@eslint/eslintrc": { "version": "2.1.4", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -7380,6 +7429,7 @@ "node_modules/eslint/node_modules/@eslint/js": { "version": "8.57.1", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -7387,6 +7437,7 @@ "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7401,6 +7452,7 @@ "node_modules/eslint/node_modules/espree": { "version": "9.6.1", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "peer": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -7416,6 +7468,7 @@ "node_modules/eslint/node_modules/globals": { "version": "13.24.0", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -7428,11 +7481,13 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "peer": true }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "peer": true, "engines": { "node": ">=10" }, @@ -7443,7 +7498,6 @@ "node_modules/espree": { "version": "10.3.0", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", @@ -7459,7 +7513,6 @@ "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "4.2.0", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7767,6 +7820,7 @@ "node_modules/file-entry-cache": { "version": "6.0.1", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -7901,6 +7955,7 @@ "node_modules/flat-cache": { "version": "3.2.0", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -7914,6 +7969,7 @@ "version": "7.2.3", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7933,6 +7989,7 @@ "version": "3.0.2", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -8100,11 +8157,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, "node_modules/get-package-type": { "version": "0.1.0", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", @@ -8237,6 +8289,7 @@ "node_modules/globby": { "version": "11.1.0", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -8967,14 +9020,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", @@ -9010,14 +9055,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-set": { "version": "2.0.3", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", @@ -9182,7 +9219,6 @@ "node_modules/istanbul-lib-instrument": { "version": "6.0.3", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -9197,7 +9233,6 @@ "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "7.6.3", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -11621,7 +11656,6 @@ "node_modules/nyc": { "version": "17.1.0", "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", - "dev": true, "dependencies": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", @@ -11661,7 +11695,6 @@ "node_modules/nyc/node_modules/ansi-styles": { "version": "4.3.0", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -11675,7 +11708,6 @@ "node_modules/nyc/node_modules/cliui": { "version": "6.0.0", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -11685,7 +11717,6 @@ "node_modules/nyc/node_modules/color-convert": { "version": "2.0.1", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11695,18 +11726,15 @@ }, "node_modules/nyc/node_modules/color-name": { "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/nyc/node_modules/convert-source-map": { "version": "1.9.0", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/nyc/node_modules/find-up": { "version": "4.1.0", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -11719,7 +11747,6 @@ "version": "7.2.3", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11738,7 +11765,6 @@ "node_modules/nyc/node_modules/locate-path": { "version": "5.0.0", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -11749,7 +11775,6 @@ "node_modules/nyc/node_modules/make-dir": { "version": "3.1.0", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, "dependencies": { "semver": "^6.0.0" }, @@ -11763,7 +11788,6 @@ "node_modules/nyc/node_modules/p-limit": { "version": "2.3.0", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "dependencies": { "p-try": "^2.0.0" }, @@ -11777,7 +11801,6 @@ "node_modules/nyc/node_modules/p-locate": { "version": "4.1.0", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -11788,7 +11811,6 @@ "node_modules/nyc/node_modules/resolve-from": { "version": "5.0.0", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "engines": { "node": ">=8" } @@ -11797,7 +11819,6 @@ "version": "3.0.2", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -11811,20 +11832,17 @@ "node_modules/nyc/node_modules/semver": { "version": "6.3.1", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/nyc/node_modules/signal-exit": { "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/nyc/node_modules/wrap-ansi": { "version": "6.2.0", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -11836,13 +11854,11 @@ }, "node_modules/nyc/node_modules/y18n": { "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, "node_modules/nyc/node_modules/yargs": { "version": "15.4.1", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -11863,7 +11879,6 @@ "node_modules/nyc/node_modules/yargs-parser": { "version": "18.1.3", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -12384,6 +12399,7 @@ "node_modules/path-type": { "version": "4.0.0", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "engines": { "node": ">=8" } @@ -12480,14 +12496,6 @@ "node": ">=8" } }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "dependencies": { - "semver-compare": "^1.0.0" - } - }, "node_modules/pluralize": { "version": "8.0.0", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", @@ -13668,11 +13676,6 @@ "node": ">=10" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true - }, "node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", @@ -14328,19 +14331,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -14645,7 +14635,8 @@ }, "node_modules/text-table": { "version": "0.2.0", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "peer": true }, "node_modules/thenify": { "version": "3.3.1", @@ -14664,11 +14655,6 @@ "node": ">=0.8" } }, - "node_modules/through": { - "version": "2.3.8", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, "node_modules/tightrope": { "version": "0.2.0", "integrity": "sha512-Kw36UHxJEELq2VUqdaSGR2/8cAsPgMtvX8uGVU6Jk26O66PhXec0A5ZnRYs47btbtwPDpXXF66+Fo3vimCM9aQ==", @@ -16643,10 +16629,10 @@ "@types/lodash": "4.14.167", "@types/node": "^20.16.11", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "cucumber-console-formatter": "1.0.0", - "eslint": "^8.57.0", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", @@ -16654,8 +16640,8 @@ "globals": "^15.13.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", - "prettier": "3.2.5", + "nyc": "17.1.0", + "prettier": "3.4.1", "rimraf": "^6.0.1", "ts-node": "^10.9.2", "tsx": "^4.19.1", @@ -16664,298 +16650,348 @@ "uuid": "^9.0.1" } }, - "packages/fdc3-agent-proxy/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "packages/fdc3-agent-proxy/node_modules/@eslint/js": { + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/fdc3-agent-proxy/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "packages/fdc3-agent-proxy/node_modules/cliui": { - "version": "6.0.0", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-agent-proxy/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/parser": { + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4" }, "engines": { - "node": ">=7.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-agent-proxy/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/convert-source-map": { - "version": "1.9.0", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/find-up": { - "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/fdc3-agent-proxy/node_modules/foreground-child": { - "version": "2.0.0", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/type-utils": { + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-agent-proxy/node_modules/glob": { - "version": "7.2.3", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/fdc3-agent-proxy/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-agent-proxy/node_modules/locate-path": { - "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "packages/fdc3-agent-proxy/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/utils": { + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dev": true, "dependencies": { - "semver": "^6.0.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-agent-proxy/node_modules/nyc": { - "version": "15.1.0", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "packages/fdc3-agent-proxy/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dev": true, "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": ">=8.9" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/fdc3-agent-proxy/node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "packages/fdc3-agent-proxy/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/fdc3-agent-proxy/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "packages/fdc3-agent-proxy/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "balanced-match": "^1.0.0" } }, - "packages/fdc3-agent-proxy/node_modules/p-locate": { - "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "packages/fdc3-agent-proxy/node_modules/eslint": { + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "packages/fdc3-agent-proxy/node_modules/prettier": { - "version": "3.2.5", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "packages/fdc3-agent-proxy/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=14" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "packages/fdc3-agent-proxy/node_modules/resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "packages/fdc3-agent-proxy/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "packages/fdc3-agent-proxy/node_modules/semver": { - "version": "6.3.1", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "packages/fdc3-agent-proxy/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "packages/fdc3-agent-proxy/node_modules/signal-exit": { - "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/wrap-ansi": { - "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "packages/fdc3-agent-proxy/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "packages/fdc3-agent-proxy/node_modules/y18n": { - "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "packages/fdc3-agent-proxy/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "packages/fdc3-agent-proxy/node_modules/yargs": { - "version": "15.4.1", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "packages/fdc3-agent-proxy/node_modules/semver": { + "version": "7.6.3", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/yargs-parser": { - "version": "18.1.3", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" + "node": ">=10" } }, "packages/fdc3-context": { @@ -16964,41 +17000,53 @@ "license": "Apache-2.0", "devDependencies": { "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", + "@eslint/js": "^9.16.0", "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "28.8.3", "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", + "globals": "^15.13.0", "mkdirp": "^3.0.1", "quicktype": "23.0.78", "rimraf": "^6.0.1", "ts-jest": "29.2.5", "tslib": "^2.7.0", - "typescript": "~5.5.0" + "typescript": "^5.6.3" } }, "packages/fdc3-context/node_modules/@eslint/js": { - "version": "9.12.0", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "packages/fdc3-context/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "packages/fdc3-context/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.9.0", - "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==", + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/type-utils": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -17013,23 +17061,19 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "packages/fdc3-context/node_modules/@typescript-eslint/parser": { - "version": "8.9.0", - "integrity": "sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==", + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "debug": "^4.3.4" }, "engines": { @@ -17040,21 +17084,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "packages/fdc3-context/node_modules/@typescript-eslint/scope-manager": { - "version": "8.9.0", - "integrity": "sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==", + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17065,12 +17105,12 @@ } }, "packages/fdc3-context/node_modules/@typescript-eslint/type-utils": { - "version": "8.9.0", - "integrity": "sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==", + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/utils": "8.9.0", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -17081,15 +17121,14 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "packages/fdc3-context/node_modules/@typescript-eslint/types": { - "version": "8.9.0", - "integrity": "sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==", + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17100,12 +17139,12 @@ } }, "packages/fdc3-context/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.9.0", - "integrity": "sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==", + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -17120,10 +17159,8 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "packages/fdc3-context/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { @@ -17141,14 +17178,14 @@ } }, "packages/fdc3-context/node_modules/@typescript-eslint/utils": { - "version": "8.9.0", - "integrity": "sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==", + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0" + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17158,16 +17195,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "packages/fdc3-context/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.9.0", - "integrity": "sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==", + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.9.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17201,30 +17239,30 @@ } }, "packages/fdc3-context/node_modules/eslint": { - "version": "9.12.0", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -17238,8 +17276,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -17274,7 +17311,7 @@ "url": "https://opencollective.com/eslint" } }, - "packages/fdc3-context/node_modules/eslint/node_modules/eslint-visitor-keys": { + "packages/fdc3-context/node_modules/eslint-visitor-keys": { "version": "4.2.0", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, @@ -17324,18 +17361,6 @@ "node": ">=10" } }, - "packages/fdc3-context/node_modules/typescript": { - "version": "5.5.4", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "packages/fdc3-get-agent": { "name": "@kite9/fdc3-get-agent", "version": "2.2.0-beta.29", @@ -17354,14 +17379,14 @@ "@eslint/js": "^9.16.0", "@kite9/fdc3-web-impl": "2.2.0-beta.29", "@kite9/testing": "2.2.0-beta.29", - "@types/node": "^20.14.11", + "@types/node": "^20.16.11", "@types/wtfnode": "^0.7.3", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "expect": "^29.7.0", "globals": "^15.13.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", + "nyc": "17.1.0", "rimraf": "^6.0.1", "tsx": "^4.19.1", "typescript": "^5.6.3", @@ -17369,27 +17394,6 @@ "wtfnode": "^0.9.3" } }, - "packages/fdc3-get-agent/node_modules/@eslint/config-array": { - "version": "0.19.0", - "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "packages/fdc3-get-agent/node_modules/@eslint/core": { - "version": "0.9.0", - "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "packages/fdc3-get-agent/node_modules/@humanwhocodes/retry": { "version": "0.4.1", "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", @@ -17417,51 +17421,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/fdc3-get-agent/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "packages/fdc3-get-agent/node_modules/cliui": { - "version": "6.0.0", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "packages/fdc3-get-agent/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "packages/fdc3-get-agent/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "packages/fdc3-get-agent/node_modules/convert-source-map": { - "version": "1.9.0", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, "packages/fdc3-get-agent/node_modules/eslint": { "version": "9.16.0", "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", @@ -17546,829 +17505,155 @@ "url": "https://opencollective.com/eslint" } }, - "packages/fdc3-get-agent/node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "packages/fdc3-get-agent/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16.0.0" } }, - "packages/fdc3-get-agent/node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "packages/fdc3-get-agent/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16" } }, - "packages/fdc3-get-agent/node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "packages/fdc3-get-agent/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "packages/fdc3-schema": { + "name": "@kite9/fdc3-schema", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", + "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.16.0", + "@types/jest": "29.5.13", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "28.8.3", + "eslint-plugin-jsx-a11y": "^6.10.0", + "globals": "^15.13.0", + "message-await": "^1.1.0", + "mkdirp": "^3.0.1", + "quicktype": "23.0.78", + "rimraf": "^6.0.1", + "ts-jest": "29.2.5", + "ts-morph": "^24.0.0", + "tslib": "^2.7.0", + "typescript": "^5.6.3" + } + }, + "packages/fdc3-schema/node_modules/@eslint/js": { + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "packages/fdc3-get-agent/node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "packages/fdc3-schema/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" + "node": ">=18.18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "packages/fdc3-get-agent/node_modules/file-entry-cache": { - "version": "8.0.0", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "packages/fdc3-schema/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, "dependencies": { - "flat-cache": "^4.0.0" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-get-agent/node_modules/find-up": { - "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "packages/fdc3-schema/node_modules/@typescript-eslint/parser": { + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-get-agent/node_modules/flat-cache": { - "version": "4.0.1", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "packages/fdc3-schema/node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dev": true, "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" }, "engines": { - "node": ">=16" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/fdc3-get-agent/node_modules/foreground-child": { - "version": "2.0.0", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "packages/fdc3-schema/node_modules/@typescript-eslint/type-utils": { + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "packages/fdc3-get-agent/node_modules/glob": { - "version": "7.2.3", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/fdc3-get-agent/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-get-agent/node_modules/json-schema-traverse": { - "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "packages/fdc3-get-agent/node_modules/locate-path": { - "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-get-agent/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/fdc3-get-agent/node_modules/nyc": { - "version": "15.1.0", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "packages/fdc3-get-agent/node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/fdc3-get-agent/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/fdc3-get-agent/node_modules/p-locate": { - "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-get-agent/node_modules/resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-get-agent/node_modules/semver": { - "version": "6.3.1", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "packages/fdc3-get-agent/node_modules/signal-exit": { - "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "packages/fdc3-get-agent/node_modules/wrap-ansi": { - "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-get-agent/node_modules/y18n": { - "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "packages/fdc3-get-agent/node_modules/yargs": { - "version": "15.4.1", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-get-agent/node_modules/yargs-parser": { - "version": "18.1.3", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "packages/fdc3-schema": { - "name": "@kite9/fdc3-schema", - "version": "2.2.0-beta.29", - "license": "Apache-2.0", - "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", - "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-jest": "28.8.3", - "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", - "message-await": "^1.1.0", - "mkdirp": "^3.0.1", - "quicktype": "23.0.78", - "rimraf": "^6.0.1", - "ts-jest": "29.2.5", - "ts-morph": "^24.0.0", - "tslib": "^2.7.0", - "typescript": "~5.5.0" - } - }, - "packages/fdc3-schema/node_modules/@eslint/js": { - "version": "9.12.0", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.9.0", - "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/type-utils": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/parser": { - "version": "8.9.0", - "integrity": "sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/scope-manager": { - "version": "8.9.0", - "integrity": "sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/type-utils": { - "version": "8.9.0", - "integrity": "sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/types": { - "version": "8.9.0", - "integrity": "sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.9.0", - "integrity": "sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/utils": { - "version": "8.9.0", - "integrity": "sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "packages/fdc3-schema/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.9.0", - "integrity": "sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "packages/fdc3-schema/node_modules/ajv": { - "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "packages/fdc3-schema/node_modules/brace-expansion": { - "version": "2.0.1", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "packages/fdc3-schema/node_modules/eslint": { - "version": "9.12.0", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "packages/fdc3-schema/node_modules/eslint-scope": { - "version": "8.2.0", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "packages/fdc3-schema/node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "packages/fdc3-schema/node_modules/file-entry-cache": { - "version": "8.0.0", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "packages/fdc3-schema/node_modules/flat-cache": { - "version": "4.0.1", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "packages/fdc3-schema/node_modules/json-schema-traverse": { - "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "packages/fdc3-schema/node_modules/semver": { - "version": "7.6.3", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "packages/fdc3-schema/node_modules/typescript": { - "version": "5.5.4", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "packages/fdc3-standard": { - "name": "@kite9/fdc3-standard", - "version": "2.2.0-beta.29", - "license": "Apache-2.0", - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" - }, - "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", - "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-jest": "28.8.3", - "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", - "jest": "29.7.0", - "jest-environment-jsdom": "29.7.0", - "jest-junit": "^16.0.0", - "jest-mock-extended": "3.0.5", - "prettier": "3.2.5", - "quicktype": "23.0.78", - "rimraf": "^6.0.1", - "ts-jest": "29.2.5", - "tslib": "^2.7.0", - "typescript": "~5.5.0" - } - }, - "packages/fdc3-standard/node_modules/@eslint/js": { - "version": "9.12.0", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "packages/fdc3-standard/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.9.0", - "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/type-utils": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/fdc3-standard/node_modules/@typescript-eslint/parser": { - "version": "8.9.0", - "integrity": "sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/fdc3-standard/node_modules/@typescript-eslint/scope-manager": { - "version": "8.9.0", - "integrity": "sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "packages/fdc3-standard/node_modules/@typescript-eslint/type-utils": { - "version": "8.9.0", - "integrity": "sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.9.0", - "@typescript-eslint/utils": "8.9.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -18377,15 +17662,14 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-standard/node_modules/@typescript-eslint/types": { - "version": "8.9.0", - "integrity": "sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==", + "packages/fdc3-schema/node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -18395,13 +17679,13 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "packages/fdc3-standard/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.9.0", - "integrity": "sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==", + "packages/fdc3-schema/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/visitor-keys": "8.9.0", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -18416,13 +17700,11 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-standard/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "packages/fdc3-schema/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, @@ -18436,15 +17718,15 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/fdc3-standard/node_modules/@typescript-eslint/utils": { - "version": "8.9.0", - "integrity": "sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==", + "packages/fdc3-schema/node_modules/@typescript-eslint/utils": { + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.9.0", - "@typescript-eslint/types": "8.9.0", - "@typescript-eslint/typescript-estree": "8.9.0" + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -18454,16 +17736,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-standard/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.9.0", - "integrity": "sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==", + "packages/fdc3-schema/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.9.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -18473,7 +17756,7 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "packages/fdc3-standard/node_modules/ajv": { + "packages/fdc3-schema/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, @@ -18488,7 +17771,7 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/fdc3-standard/node_modules/brace-expansion": { + "packages/fdc3-schema/node_modules/brace-expansion": { "version": "2.0.1", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, @@ -18496,31 +17779,31 @@ "balanced-match": "^1.0.0" } }, - "packages/fdc3-standard/node_modules/eslint": { - "version": "9.12.0", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", + "packages/fdc3-schema/node_modules/eslint": { + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -18534,8 +17817,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -18555,7 +17837,7 @@ } } }, - "packages/fdc3-standard/node_modules/eslint-scope": { + "packages/fdc3-schema/node_modules/eslint-scope": { "version": "8.2.0", "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, @@ -18570,7 +17852,7 @@ "url": "https://opencollective.com/eslint" } }, - "packages/fdc3-standard/node_modules/eslint/node_modules/eslint-visitor-keys": { + "packages/fdc3-schema/node_modules/eslint-visitor-keys": { "version": "4.2.0", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, @@ -18581,7 +17863,7 @@ "url": "https://opencollective.com/eslint" } }, - "packages/fdc3-standard/node_modules/file-entry-cache": { + "packages/fdc3-schema/node_modules/file-entry-cache": { "version": "8.0.0", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, @@ -18592,7 +17874,7 @@ "node": ">=16.0.0" } }, - "packages/fdc3-standard/node_modules/flat-cache": { + "packages/fdc3-schema/node_modules/flat-cache": { "version": "4.0.1", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, @@ -18604,569 +17886,753 @@ "node": ">=16" } }, - "packages/fdc3-standard/node_modules/json-schema-traverse": { + "packages/fdc3-schema/node_modules/json-schema-traverse": { "version": "0.4.1", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "packages/fdc3-standard/node_modules/prettier": { - "version": "3.2.5", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "packages/fdc3-schema/node_modules/semver": { + "version": "7.6.3", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { - "prettier": "bin/prettier.cjs" + "semver": "bin/semver.js" }, "engines": { - "node": ">=14" + "node": ">=10" + } + }, + "packages/fdc3-standard": { + "name": "@kite9/fdc3-standard", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.16.0", + "@types/jest": "29.5.13", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "28.8.3", + "eslint-plugin-jsx-a11y": "^6.10.0", + "globals": "^15.13.0", + "jest": "29.7.0", + "jest-environment-jsdom": "29.7.0", + "jest-junit": "^16.0.0", + "jest-mock-extended": "3.0.5", + "prettier": "3.4.1", + "quicktype": "23.0.78", + "rimraf": "^6.0.1", + "ts-jest": "29.2.5", + "tslib": "^2.7.0", + "typescript": "^5.6.3" + } + }, + "packages/fdc3-standard/node_modules/@eslint/js": { + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "packages/fdc3-standard/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "packages/fdc3-standard/node_modules/semver": { - "version": "7.6.3", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "packages/fdc3-standard/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/fdc3-standard/node_modules/typescript": { - "version": "5.5.4", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "packages/fdc3-standard/node_modules/@typescript-eslint/parser": { + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "dependencies": { + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4" }, "engines": { - "node": ">=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing": { - "name": "@kite9/testing", - "version": "2.2.0-beta.29", - "license": "Apache-2.0", + "packages/fdc3-standard/node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", + "dev": true, "dependencies": { - "@cucumber/cucumber": "10.3.1", - "@cucumber/html-formatter": "11.0.4", - "@cucumber/pretty-formatter": "1.0.1", - "@kite9/fdc3-standard": "2.2.0-beta.29", - "@types/expect": "24.3.0", - "@types/lodash": "4.14.167", - "@types/node": "^20.16.11", - "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "cucumber-console-formatter": "1.0.0", - "eslint": "8.57.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-prettier": "3.3.1", - "expect": "^29.7.0", - "is-ci": "2.0.0", - "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", - "prettier": "3.2.5", - "rimraf": "^6.0.1", - "ts-node": "^10.9.2", - "tsx": "^4.19.1", - "typescript": "^5.6.3", - "uuid": "^9.0.1" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/testing/node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "packages/fdc3-standard/node_modules/@typescript-eslint/type-utils": { + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", + "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "packages/fdc3-standard/node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/fdc3-standard/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/@eslint/js": { - "version": "8.57.0", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "packages/fdc3-standard/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "packages/testing/node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", + "packages/fdc3-standard/node_modules/@typescript-eslint/utils": { + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", + "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "packages/fdc3-standard/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", + "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/testing/node_modules/cliui": { - "version": "6.0.0", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "packages/fdc3-standard/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/testing/node_modules/color-convert": { + "packages/fdc3-standard/node_modules/brace-expansion": { "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "balanced-match": "^1.0.0" } }, - "packages/testing/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "packages/testing/node_modules/convert-source-map": { - "version": "1.9.0", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "packages/testing/node_modules/eslint": { - "version": "8.57.0", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "packages/fdc3-standard/node_modules/eslint": { + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "packages/testing/node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "packages/fdc3-standard/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/eslint" } }, - "packages/testing/node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, + "packages/fdc3-standard/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "packages/testing/node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "packages/fdc3-standard/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16.0.0" } }, - "packages/testing/node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "packages/fdc3-standard/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16" } }, - "packages/testing/node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" + "packages/fdc3-standard/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "packages/fdc3-standard/node_modules/semver": { + "version": "7.6.3", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/testing/node_modules/espree": { - "version": "9.6.1", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "packages/testing": { + "name": "@kite9/testing", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "@cucumber/cucumber": "10.3.1", + "@cucumber/html-formatter": "11.0.4", + "@cucumber/pretty-formatter": "1.0.1", + "@kite9/fdc3-standard": "2.2.0-beta.29", + "@types/expect": "24.3.0", + "@types/lodash": "4.14.167", + "@types/node": "^20.16.11", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "cucumber-console-formatter": "1.0.0", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-prettier": "3.3.1", + "expect": "^29.7.0", + "is-ci": "2.0.0", + "jsonpath-plus": "^10.1.0", + "nyc": "17.1.0", + "prettier": "3.4.1", + "rimraf": "^6.0.1", + "ts-node": "^10.9.2", + "tsx": "^4.19.1", + "typescript": "^5.6.3", + "uuid": "^9.0.1" + } + }, + "packages/testing/node_modules/@eslint/js": { + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "packages/testing/node_modules/find-up": { - "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, + "packages/testing/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "engines": { - "node": ">=8" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "packages/testing/node_modules/foreground-child": { - "version": "2.0.0", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "packages/testing/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/glob": { - "version": "7.2.3", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "packages/testing/node_modules/@typescript-eslint/parser": { + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", + "dependencies": { + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4" }, "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/globals": { - "version": "13.24.0", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "packages/testing/node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dependencies": { - "type-fest": "^0.20.2" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/testing/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "packages/testing/node_modules/@typescript-eslint/type-utils": { + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/json-schema-traverse": { - "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "packages/testing/node_modules/locate-path": { - "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, + "packages/testing/node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/testing/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "packages/testing/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", "dependencies": { - "semver": "^6.0.0" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/nyc": { - "version": "15.1.0", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "packages/testing/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8.9" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "packages/testing/node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "packages/testing/node_modules/@typescript-eslint/utils": { + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dependencies": { - "glob": "^7.1.3" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "packages/testing/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "packages/testing/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dependencies": { - "p-try": "^2.0.0" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": ">=6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "packages/testing/node_modules/p-locate": { - "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "packages/testing/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" + "balanced-match": "^1.0.0" } }, - "packages/testing/node_modules/prettier": { - "version": "3.2.5", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "packages/testing/node_modules/eslint": { + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, "bin": { - "prettier": "bin/prettier.cjs" + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=14" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "packages/testing/node_modules/resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "packages/testing/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "packages/testing/node_modules/semver": { - "version": "6.3.1", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" + "packages/testing/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "packages/testing/node_modules/signal-exit": { - "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "packages/testing/node_modules/type-fest": { - "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" + "packages/testing/node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/testing/node_modules/wrap-ansi": { - "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "packages/testing/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "packages/testing/node_modules/y18n": { - "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "packages/testing/node_modules/yargs": { - "version": "15.4.1", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "packages/testing/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "packages/testing/node_modules/yargs-parser": { - "version": "18.1.3", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "packages/testing/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "packages/testing/node_modules/semver": { + "version": "7.6.3", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=6" + "node": ">=10" } }, "toolbox/fdc3-for-web/demo": { @@ -19197,30 +18663,6 @@ "vite": "^5.4.9" } }, - "toolbox/fdc3-for-web/demo/node_modules/@eslint/config-array": { - "version": "0.19.1", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.5", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "toolbox/fdc3-for-web/demo/node_modules/@eslint/core": { - "version": "0.9.1", - "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "toolbox/fdc3-for-web/demo/node_modules/@humanwhocodes/retry": { "version": "0.4.1", "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", @@ -19380,10 +18822,10 @@ "@types/lodash": "4.14.167", "@types/node": "^20.16.11", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "cucumber-console-formatter": "1.0.0", - "eslint": "^8.57.0", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", @@ -19391,9 +18833,9 @@ "globals": "^15.13.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", + "nyc": "17.1.0", "openapi-typescript": "^6.7.6", - "prettier": "3.2.5", + "prettier": "3.4.1", "rimraf": "^6.0.1", "ts-node": "^10.9.2", "typescript": "^5.6.3", @@ -19401,298 +18843,348 @@ "uuid": "^9.0.1" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@eslint/js": { + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/cliui": { - "version": "6.0.0", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/parser": { + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" }, "engines": { - "node": ">=7.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/convert-source-map": { - "version": "1.9.0", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/find-up": { - "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/type-utils": { + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/foreground-child": { - "version": "2.0.0", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/glob": { - "version": "7.2.3", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/utils": { + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dev": true, "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/locate-path": { - "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/nyc": { - "version": "15.1.0", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" + "balanced-match": "^1.0.0" + } + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/eslint": { + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" }, "bin": { - "nyc": "bin/nyc.js" + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=8.9" - } - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" + "url": "https://eslint.org/donate" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "jiti": "*" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/p-locate": { - "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/prettier": { - "version": "3.2.5", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=14" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "engines": { - "node": ">=8" - } - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/semver": { - "version": "6.3.1", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/signal-exit": { - "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/wrap-ansi": { - "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/y18n": { - "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/yargs": { - "version": "15.4.1", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/yargs-parser": { - "version": "18.1.3", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "toolbox/fdc3-for-web/fdc3-web-impl/node_modules/semver": { + "version": "7.6.3", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=6" + "node": ">=10" } }, "toolbox/fdc3-for-web/reference-ui": { @@ -19706,33 +19198,9 @@ "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.13.0", - "typescript": "^5.3.2", + "typescript": "^5.6.3", "typescript-eslint": "^8.17.0", - "vite": "^5.2.0" - } - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@eslint/config-array": { - "version": "0.19.1", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.5", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@eslint/core": { - "version": "0.9.1", - "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "vite": "^5.4.9" } }, "toolbox/fdc3-for-web/reference-ui/node_modules/@humanwhocodes/retry": { @@ -19887,17 +19355,17 @@ "@material-ui/lab": "4.0.0-alpha.61", "@types/jsoneditor": "^8.6.1", "@types/react-dom": "18.3.1", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "@vitejs/plugin-legacy": "^5.4.2", "@vitejs/plugin-react": "^4.3.2", - "eslint": "8.57.0", - "eslint-config-prettier": "9.1.0", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-react": "^7.37.1", "fdc3-1.2": "npm:@finos/fdc3@1.2.x", "jsoneditor": "^9.10.5", - "lint-staged": "^11.2.6", + "lint-staged": "^15.2.10", "mobx": "^6.13.3", "mobx-react": "^7.6.0", "nanoid": "^3.3.7", @@ -19912,392 +19380,348 @@ "web-vitals": "^1.1.2" } }, - "toolbox/fdc3-workbench/node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "toolbox/fdc3-workbench/node_modules/@eslint/js": { + "version": "9.17.0", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "toolbox/fdc3-workbench/node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.2", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-workbench/node_modules/@eslint/js": { - "version": "8.57.0", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/parser": { + "version": "8.18.2", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-workbench/node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.2", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/type-utils": { + "version": "8.18.2", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/types": { + "version": "8.18.2", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.2", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": ">=10.10.0" + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-workbench/node_modules/ajv": { - "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/isaacs" } }, - "toolbox/fdc3-workbench/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/utils": { + "version": "8.18.2", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "toolbox/fdc3-workbench/node_modules/cli-truncate": { - "version": "2.1.0", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "toolbox/fdc3-workbench/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.2", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dev": true, "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "@typescript-eslint/types": "8.18.2", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "toolbox/fdc3-workbench/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "toolbox/fdc3-workbench/node_modules/ajv": { + "version": "6.12.6", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=7.0.0" - } - }, - "toolbox/fdc3-workbench/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "toolbox/fdc3-workbench/node_modules/colorette": { - "version": "1.4.0", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true - }, - "toolbox/fdc3-workbench/node_modules/commander": { - "version": "8.3.0", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "toolbox/fdc3-workbench/node_modules/cosmiconfig": { - "version": "7.1.0", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "toolbox/fdc3-workbench/node_modules/brace-expansion": { + "version": "2.0.1", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0" } }, "toolbox/fdc3-workbench/node_modules/eslint": { - "version": "8.57.0", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.17.0", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "toolbox/fdc3-workbench/node_modules/espree": { - "version": "9.6.1", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "toolbox/fdc3-workbench/node_modules/globals": { - "version": "13.24.0", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "toolbox/fdc3-workbench/node_modules/json-schema-traverse": { - "version": "0.4.1", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "toolbox/fdc3-workbench/node_modules/lint-staged": { - "version": "11.2.6", - "integrity": "sha512-Vti55pUnpvPE0J9936lKl0ngVeTdSZpEdTNhASbkaWX7J5R9OEifo1INBGQuGW4zmy6OG+TcWPJ3m5yuy5Q8Tg==", - "dev": true, - "dependencies": { - "cli-truncate": "2.1.0", - "colorette": "^1.4.0", - "commander": "^8.2.0", - "cosmiconfig": "^7.0.1", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "execa": "^5.1.1", - "listr2": "^3.12.2", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.2.0", - "string-argv": "0.3.1", - "stringify-object": "3.3.0", - "supports-color": "8.1.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "toolbox/fdc3-workbench/node_modules/listr2": { - "version": "3.14.0", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" + "url": "https://eslint.org/donate" }, "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" + "jiti": "*" }, "peerDependenciesMeta": { - "enquirer": { + "jiti": { "optional": true } } }, - "toolbox/fdc3-workbench/node_modules/listr2/node_modules/colorette": { - "version": "2.0.20", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "toolbox/fdc3-workbench/node_modules/log-update": { - "version": "4.0.0", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "toolbox/fdc3-workbench/node_modules/eslint-scope": { + "version": "8.2.0", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "toolbox/fdc3-workbench/node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "toolbox/fdc3-workbench/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "toolbox/fdc3-workbench/node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" + "url": "https://opencollective.com/eslint" } }, - "toolbox/fdc3-workbench/node_modules/p-map": { - "version": "4.0.0", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "toolbox/fdc3-workbench/node_modules/file-entry-cache": { + "version": "8.0.0", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "aggregate-error": "^3.0.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16.0.0" } }, - "toolbox/fdc3-workbench/node_modules/slice-ansi": { - "version": "3.0.0", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "toolbox/fdc3-workbench/node_modules/flat-cache": { + "version": "4.0.1", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "toolbox/fdc3-workbench/node_modules/type-fest": { - "version": "0.20.2", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "toolbox/fdc3-workbench/node_modules/json-schema-traverse": { + "version": "0.4.1", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, - "toolbox/fdc3-workbench/node_modules/wrap-ansi": { - "version": "7.0.0", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "toolbox/fdc3-workbench/node_modules/semver": { + "version": "7.6.3", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "toolbox/fdc3-workbench/node_modules/yaml": { - "version": "1.10.2", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" } } } diff --git a/packages/fdc3-agent-proxy/package.json b/packages/fdc3-agent-proxy/package.json index fb148ba84..e910557fe 100644 --- a/packages/fdc3-agent-proxy/package.json +++ b/packages/fdc3-agent-proxy/package.json @@ -35,10 +35,10 @@ "@types/lodash": "4.14.167", "@types/node": "^20.16.11", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "cucumber-console-formatter": "1.0.0", - "eslint": "^8.57.0", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", @@ -46,8 +46,8 @@ "globals": "^15.13.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", - "prettier": "3.2.5", + "nyc": "17.1.0", + "prettier": "3.4.1", "rimraf": "^6.0.1", "ts-node": "^10.9.2", "tsx": "^4.19.1", diff --git a/packages/fdc3-context/package.json b/packages/fdc3-context/package.json index 92aefb66e..4947d6bd1 100644 --- a/packages/fdc3-context/package.json +++ b/packages/fdc3-context/package.json @@ -27,20 +27,20 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", + "@eslint/js": "^9.16.0", "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "28.8.3", "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", + "globals": "^15.13.0", "mkdirp": "^3.0.1", "quicktype": "23.0.78", "rimraf": "^6.0.1", "ts-jest": "29.2.5", "tslib": "^2.7.0", - "typescript": "~5.5.0" + "typescript": "^5.6.3" } } diff --git a/packages/fdc3-get-agent/package.json b/packages/fdc3-get-agent/package.json index 54d0e86ee..7ac309ab0 100644 --- a/packages/fdc3-get-agent/package.json +++ b/packages/fdc3-get-agent/package.json @@ -36,14 +36,14 @@ "@eslint/js": "^9.16.0", "@kite9/fdc3-web-impl": "2.2.0-beta.29", "@kite9/testing": "2.2.0-beta.29", - "@types/node": "^20.14.11", + "@types/node": "^20.16.11", "@types/wtfnode": "^0.7.3", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "expect": "^29.7.0", "globals": "^15.13.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", + "nyc": "17.1.0", "rimraf": "^6.0.1", "tsx": "^4.19.1", "typescript": "^5.6.3", diff --git a/packages/fdc3-schema/package.json b/packages/fdc3-schema/package.json index ab469a6bb..7a30cc8d9 100644 --- a/packages/fdc3-schema/package.json +++ b/packages/fdc3-schema/package.json @@ -30,15 +30,15 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", + "@eslint/js": "^9.16.0", "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "28.8.3", "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", + "globals": "^15.13.0", "message-await": "^1.1.0", "mkdirp": "^3.0.1", "quicktype": "23.0.78", @@ -46,6 +46,6 @@ "ts-jest": "29.2.5", "ts-morph": "^24.0.0", "tslib": "^2.7.0", - "typescript": "~5.5.0" + "typescript": "^5.6.3" } -} \ No newline at end of file +} diff --git a/packages/fdc3-standard/package.json b/packages/fdc3-standard/package.json index 0fd3425c8..01b620589 100644 --- a/packages/fdc3-standard/package.json +++ b/packages/fdc3-standard/package.json @@ -39,24 +39,24 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", + "@eslint/js": "^9.16.0", "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "28.8.3", "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", + "globals": "^15.13.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-junit": "^16.0.0", "jest-mock-extended": "3.0.5", - "prettier": "3.2.5", + "prettier": "3.4.1", "quicktype": "23.0.78", "rimraf": "^6.0.1", "ts-jest": "29.2.5", "tslib": "^2.7.0", - "typescript": "~5.5.0" + "typescript": "^5.6.3" } -} \ No newline at end of file +} diff --git a/packages/fdc3/package.json b/packages/fdc3/package.json index 9bd33baaf..45dfca347 100644 --- a/packages/fdc3/package.json +++ b/packages/fdc3/package.json @@ -26,4 +26,4 @@ "@kite9/fdc3-get-agent": "2.2.0-beta.29", "@kite9/fdc3-context": "2.2.0-beta.29" } -} \ No newline at end of file +} diff --git a/packages/testing/package.json b/packages/testing/package.json index 5306f0779..df4362043 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -31,20 +31,20 @@ "@types/lodash": "4.14.167", "@types/node": "^20.16.11", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "cucumber-console-formatter": "1.0.0", - "eslint": "8.57.0", - "eslint-config-prettier": "9.1.0", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", "expect": "^29.7.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", - "prettier": "3.2.5", + "nyc": "17.1.0", + "prettier": "3.4.1", "rimraf": "^6.0.1", "ts-node": "^10.9.2", "tsx": "^4.19.1", diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/package.json b/toolbox/fdc3-for-web/fdc3-web-impl/package.json index c6e6958e1..ae6780e8f 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/package.json +++ b/toolbox/fdc3-for-web/fdc3-web-impl/package.json @@ -39,10 +39,10 @@ "@types/lodash": "4.14.167", "@types/node": "^20.16.11", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "cucumber-console-formatter": "1.0.0", - "eslint": "^8.57.0", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "3.3.1", @@ -50,9 +50,9 @@ "globals": "^15.13.0", "is-ci": "2.0.0", "jsonpath-plus": "^10.1.0", - "nyc": "15.1.0", + "nyc": "17.1.0", "openapi-typescript": "^6.7.6", - "prettier": "3.2.5", + "prettier": "3.4.1", "rimraf": "^6.0.1", "ts-node": "^10.9.2", "typescript": "^5.6.3", diff --git a/toolbox/fdc3-for-web/reference-ui/package.json b/toolbox/fdc3-for-web/reference-ui/package.json index b86e428b8..73c3b1fc3 100644 --- a/toolbox/fdc3-for-web/reference-ui/package.json +++ b/toolbox/fdc3-for-web/reference-ui/package.json @@ -15,9 +15,9 @@ "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.13.0", - "typescript": "^5.3.2", + "typescript": "^5.6.3", "typescript-eslint": "^8.17.0", - "vite": "^5.2.0" + "vite": "^5.4.9" }, "dependencies": { "@kite9/fdc3": "2.2.0-beta.29" diff --git a/toolbox/fdc3-workbench/package.json b/toolbox/fdc3-workbench/package.json index 6c24ab3de..5d398e850 100644 --- a/toolbox/fdc3-workbench/package.json +++ b/toolbox/fdc3-workbench/package.json @@ -39,17 +39,17 @@ "@material-ui/lab": "4.0.0-alpha.61", "@types/jsoneditor": "^8.6.1", "@types/react-dom": "18.3.1", - "@typescript-eslint/eslint-plugin": "7.1.1", - "@typescript-eslint/parser": "7.1.0", + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", "@vitejs/plugin-legacy": "^5.4.2", "@vitejs/plugin-react": "^4.3.2", - "eslint": "8.57.0", - "eslint-config-prettier": "9.1.0", + "eslint": "^9.16.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-react": "^7.37.1", "fdc3-1.2": "npm:@finos/fdc3@1.2.x", "jsoneditor": "^9.10.5", - "lint-staged": "^11.2.6", + "lint-staged": "^15.2.10", "mobx": "^6.13.3", "mobx-react": "^7.6.0", "nanoid": "^3.3.7", @@ -72,4 +72,4 @@ "*.js": "eslint --cache --fix", "*.{js,css,md}": "prettier --write" } -} \ No newline at end of file +} From 0468da6ecb58a61c90ef151532d1293a6e7e6a2b Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 2 Jan 2025 13:04:55 +0000 Subject: [PATCH 67/90] Correcting issues with reconnection in fdc3-for-web-impl and demo Reconnections (e.g. on refresh) were being rejected as the instance UUIDs Were delted on disconnect. Adjusted the agent to cache past connections for upto N seconds (currently set to 60). Once reconnection was allowed, double broadcasts and other state was observed as these were not being cleaned up on disconnect, which was also corrected. --- .../test/support/MockFDC3Server.ts | 6 +- .../test/support/TestServerContext.ts | 9 + .../demo/src/client/da/DemoServerContext.ts | 164 ++++++++++++++---- .../demo/src/client/da/dummy-desktop-agent.ts | 110 ++++-------- .../fdc3-for-web/demo/src/client/da/embed.ts | 74 ++++---- toolbox/fdc3-for-web/demo/src/server/main.ts | 4 +- .../fdc3-for-web/demo/static/da/nested.html | 2 +- .../fdc3-web-impl/src/BasicFDC3Server.ts | 10 ++ .../fdc3-web-impl/src/FDC3Server.ts | 5 + .../fdc3-web-impl/src/ServerContext.ts | 17 +- .../src/handlers/BroadcastHandler.ts | 97 +++++++++-- .../src/handlers/HeartbeatHandler.ts | 5 + .../src/handlers/IntentHandler.ts | 15 +- .../fdc3-web-impl/src/handlers/OpenHandler.ts | 36 ++-- .../test/support/TestServerContext.ts | 20 ++- 15 files changed, 380 insertions(+), 194 deletions(-) diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index 7940bbeb3..2f9fa1f80 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -1,4 +1,4 @@ -import { FDC3Server } from '@kite9/fdc3-web-impl'; +import { FDC3Server, InstanceID } from '@kite9/fdc3-web-impl'; import { TestServerContext } from './TestServerContext'; import { MockWindow } from './MockWindow'; import { AutomaticResponse } from './responses/AutomaticResponses'; @@ -52,6 +52,10 @@ export class MockFDC3Server implements FDC3Server { this.init(); } + cleanup(instanceId: InstanceID): void { + this.tsc.goodbye(instanceId); + } + receive(message: AppRequestMessage, from: string): void { this.automaticResponses.forEach(r => { if (r.filter(message.type)) { diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index 026d8882a..51eecbf04 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -26,6 +26,7 @@ export class TestServerContext implements ServerContext { public postedMessages: MessageRecord[] = []; public readonly cw: CustomWorld; private instances: ConnectionDetails[] = []; + private nextInstanceId: number = 0; private nextUUID: number = 0; @@ -33,6 +34,10 @@ export class TestServerContext implements ServerContext { this.cw = cw; } + goodbye(instanceId: string): void { + this.instances = this.instances.filter(instance => instance.instanceId !== instanceId); + } + async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[] /*, _context: Context*/): Promise { return appIntents; } @@ -41,6 +46,10 @@ export class TestServerContext implements ServerContext { return this.instances.find(ca => ca.instanceId === uuid); } + getPastInstanceDetails(/*uuid: InstanceID*/): ConnectionDetails | undefined { + return; + } + setInstanceDetails(uuid: InstanceID, appId: ConnectionDetails) { this.instances = this.instances.filter(ca => ca.connectionId !== uuid); this.instances.push({ diff --git a/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts b/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts index 453159283..18c911c8d 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts @@ -10,20 +10,41 @@ enum Opener { Nested, } -type DemoRegistration = AppRegistration & { +type DemoAppRegistration = AppRegistration & { window: Window; url: string; }; -//Typeguard used to check if application launch details have a URL +type DemoLaunchRegistration = AppRegistration & { + windowPromise: Promise; + url: string; +}; + +type DemoRegistration = DemoAppRegistration | DemoLaunchRegistration; + +//Type guard used to check if application launch details have a URL function isWebAppLaunchDetails(details: object): details is { url: string } { return (details as { url: string }).url !== undefined; } +//Type guard used to check if application has been launched or if we are still waiting on the window reference +function isDemoLaunchRegistration( + details: DemoAppRegistration | DemoLaunchRegistration +): details is DemoLaunchRegistration { + return !!(details as DemoLaunchRegistration).windowPromise; +} + +//Type guard used to check if application has been launched or if we are still waiting on the window reference +function isDemoAppRegistration(details: DemoAppRegistration | DemoLaunchRegistration): details is DemoAppRegistration { + return !!(details as DemoAppRegistration).window; +} + export class DemoServerContext implements ServerContext { private readonly socket: Socket; private readonly directory: Directory; - private connections: DemoRegistration[] = []; + private connections: (DemoAppRegistration | DemoLaunchRegistration)[] = []; + private pastConnections: { registration: DemoAppRegistration; timestamp: number }[] = []; + private static PAST_CONNECTIONS_MAX_AGE_MS = 60 * 1000; constructor(socket: Socket, directory: Directory) { this.socket = socket; @@ -34,20 +55,98 @@ export class DemoServerContext implements ServerContext { return appIntents; } + private prunePastConnections = () => { + const threshold = Date.now() - DemoServerContext.PAST_CONNECTIONS_MAX_AGE_MS; + this.pastConnections = this.pastConnections.filter(pc => pc.timestamp > threshold); + }; + /** - * Sets the appId and instanceId for a given connection UUID + * Sets the appId, url, state and either the window or a Promise for a given connection UUID. */ - setInstanceDetails(uuid: InstanceID, meta: DemoRegistration): void { + setInstanceDetails(uuid: InstanceID, meta: DemoAppRegistration | DemoLaunchRegistration): void { + //remove any existing records with this uuid this.connections = this.connections.filter(ca => ca.instanceId !== uuid); + this.pastConnections = this.pastConnections.filter(i => i.registration.instanceId != uuid); - this.connections.push({ + const instanceDetails = { ...meta, instanceId: uuid, - }); + }; + this.connections.push(instanceDetails); + + if (isDemoLaunchRegistration(meta)) { + //If the window wasn't fully realized yet, monitor the window promise so that it + // sets window when resolved. + meta.windowPromise.then((window: Window | null) => { + if (window) { + const launchedMeta: DemoAppRegistration = { + window: window, + url: meta.url, + appId: meta.appId, + instanceId: meta.instanceId, + state: meta.state, + }; + //will replace any existing record + this.setInstanceDetails(uuid, launchedMeta); + } else { + //delete this record as launch failed + this.connections = this.connections.filter(ca => ca.instanceId !== uuid); + console.error( + 'We did not receive a window reference after launching app: ', + meta.url, + '\nn.b. this may occur if a popup blocker prevented launch or the Cross-Origin-Opener-Policy opener policy is set' + ); + } + }); + } + } + + async getInstanceForWindow(window: Window): Promise { + const registration = this.connections.filter(isDemoAppRegistration).find(i => i.window == window); + if (registration) { + return registration; + } + + //check for as yet unrealized windows and then wait on those... + const launchingApps = this.connections.filter(isDemoLaunchRegistration); + + if (launchingApps.length == 0) { + console.warn('Could not locate an app registration for a window and there are no window launches in progress!'); + return; + } else { + //we need to wait on all currently launching windows as it could be any one of those + return new Promise(resolve => { + const toMonitor = launchingApps.length; + let doneCount = 0; + launchingApps.forEach(launchingApp => { + launchingApp.windowPromise.then(realizedWindow => { + doneCount++; + if (realizedWindow == window) { + //note that this record will separately be converting itself into a DemoAppRegistration + resolve({ + window: realizedWindow, + url: launchingApp.url, + appId: launchingApp.appId, + instanceId: launchingApp.instanceId, + state: launchingApp.state, + }); + } else if (doneCount >= toMonitor) { + //we did not find it :-( + resolve(undefined); + } + }); + }); + }); + } + } + + getInstanceDetails(uuid: InstanceID): DemoRegistration | undefined { + return this.connections.find(i => i.instanceId == uuid); } - getInstanceForWindow(window: Window): DemoRegistration | undefined { - return this.connections.find(i => i.window == window); + getPastInstanceDetails(uuid: InstanceID): DemoAppRegistration | undefined { + this.prunePastConnections(); + return this.pastConnections.find(i => i.registration.instanceId == uuid)?.registration; } getOpener(): Opener { @@ -65,12 +164,18 @@ export class DemoServerContext implements ServerContext { * Post an outgoing message to a particular app */ async post(message: object, to: InstanceID): Promise { - console.debug(`Responding to app instance:`, to, message); this.socket.emit(FDC3_DA_EVENT, message, to); } goodbye(id: string) { + const registration = this.connections.find(i => i.instanceId == id); this.connections = this.connections.filter(i => i.instanceId !== id); + + //cache the connection details in case the app tries to reconnect + if (registration && isDemoAppRegistration(registration)) { + this.pastConnections.push({ registration, timestamp: Date.now() }); + } + console.debug(`Closed instance`, id); console.debug( `Open apps:`, @@ -131,27 +236,22 @@ export class DemoServerContext implements ServerContext { const launchDetails = details[0].details; if (isWebAppLaunchDetails(launchDetails)) { const url = launchDetails.url ?? undefined; - const window = await this.openUrl(url); - if (window) { - const instanceId: InstanceID = this.createUUID(); - const metadata = { - appId, - instanceId, - window, - url, - state: State.Pending, - }; - this.setInstanceDetails(instanceId, metadata); - return instanceId; - } else { - console.error( - 'We did not receive a window reference after launching app: ', - details[0], - '\nn.b. this may occur if a popup blocker prevented launch or the Cross-Origin-Opener-Policy opener policy is set' - ); - throw new Error(OpenError.ErrorOnLaunch); - } + //We do not await the window or frame opening here as that can cause a race condition + // where the app loads and attempts to connect before we call `this.setInstanceDetails`. + //const window = await this.openUrl(url); + const windowPromise = this.openUrl(url); + const instanceId: InstanceID = this.createUUID(); + const metadata: DemoLaunchRegistration = { + appId, + instanceId, + windowPromise, + url, + state: State.Pending, + }; + + this.setInstanceDetails(instanceId, metadata); + return instanceId; } else { console.error('Unable to launch app without a URL, app: ', details[0]); throw new Error(OpenError.ErrorOnLaunch); @@ -187,10 +287,6 @@ export class DemoServerContext implements ServerContext { }); } - getInstanceDetails(uuid: InstanceID): DemoRegistration | undefined { - return this.connections.find(i => i.instanceId == uuid); - } - log(message: string): void { console.log(message); } diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index 52f08442d..aef4fa372 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -7,6 +7,7 @@ import { AppRegistration, DefaultFDC3Server, DirectoryApp, ServerContext } from import { ChannelState, ChannelType } from '@kite9/fdc3-web-impl/src/handlers/BroadcastHandler'; import { link, UI, UI_URLS } from './util'; import { BrowserTypes } from '@kite9/fdc3-schema'; +import { WebConnectionProtocol3Handshake } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; type WebConnectionProtocol2LoadURL = BrowserTypes.WebConnectionProtocol2LoadURL; @@ -55,6 +56,7 @@ window.addEventListener('load', () => { const directory = new FDC3_2_1_JSONDirectory(); await directory.load('/static/da/appd.json'); + //await directory.load('/static/da/local-conformance-2_0.v2.json'); const sc = new DemoServerContext(socket, directory); const channelDetails: ChannelState[] = [ @@ -74,7 +76,7 @@ window.addEventListener('load', () => { }); socket.on(APP_GOODBYE, (id: string) => { - sc.goodbye(id); + fdc3Server.cleanup(id); }); // let's create buttons for some apps @@ -86,7 +88,7 @@ window.addEventListener('load', () => { // set up Desktop Agent Proxy interface here // disabling rule for checks on origin of messages - this could be improved by validating for origins we know we are working with // nosemgrep: javascript.browser.security.insufficient-postmessage-origin-validation.insufficient-postmessage-origin-validation - window.addEventListener('message', e => { + window.addEventListener('message', async e => { const event = e as MessageEvent; const data = event.data; const source = event.source as Window; @@ -94,24 +96,23 @@ window.addEventListener('load', () => { console.log('Received: ' + JSON.stringify(event.data)); if (data.type == 'WCP1Hello') { - const instance = sc.getInstanceForWindow(source); + const instance = await sc.getInstanceForWindow(source); if (instance) { if (getApproach() == Approach.IFRAME) { - source.postMessage( - { - type: 'WCP2LoadUrl', - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - iframeUrl: - window.location.origin + - `/static/da/embed.html?connectionAttemptUuid=${data.meta.connectionAttemptUuid}&desktopAgentId=${desktopAgentUUID}&instanceId=${instance.instanceId}&UI=${getUIKey()}`, - }, - } as WebConnectionProtocol2LoadURL, - origin - ); + const message: WebConnectionProtocol2LoadURL = { + type: 'WCP2LoadUrl', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + iframeUrl: + window.location.origin + + `/static/da/embed.html?&desktopAgentId=${desktopAgentUUID}&instanceId=${instance.instanceId}&UI=${getUIKey()}`, + }, + }; + + source.postMessage(message, origin); } else { const channel = new MessageChannel(); link(socket, channel, instance.instanceId); @@ -119,74 +120,23 @@ window.addEventListener('load', () => { const ui = UI_URLS[getUIKey()]; // send the other end of the channel to the app - source.postMessage( - { - type: 'WCP3Handshake', - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - fdc3Version: '2.2', - ...ui, - }, + const message: WebConnectionProtocol3Handshake = { + type: 'WCP3Handshake', + meta: { + connectionAttemptUuid: data.meta.connectionAttemptUuid, + timestamp: new Date(), }, - origin, - [channel.port1] - ); + payload: { + fdc3Version: '2.2', + ...ui, + }, + }; + source.postMessage(message, origin, [channel.port1]); } } else { console.error(`Couldn't locate an instance for Window.name: ${source.name}`); } } - - // If this is in an iframe... - if (getApproach() == Approach.IFRAME) { - const instance = sc.getInstanceForWindow(source); - const message: WebConnectionProtocol2LoadURL = { - type: 'WCP2LoadUrl', - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - iframeUrl: - window.location.origin + - `/static/da/embed.html?connectionAttemptUuid=${data.meta.connectionAttemptUuid}&desktopAgentId=${desktopAgentUUID}&instanceId=${instance?.instanceId}`, - }, - }; - source.postMessage(message, origin); - return; - } - - const instance = sc.getInstanceForWindow(source); - - if (!instance) { - throw new Error('Unable to find registration for this window'); - } - - const channel = new MessageChannel(); - link(socket, channel, instance.instanceId); - - socket.emit(APP_HELLO, desktopAgentUUID, instance.instanceId); - - // send the other end of the channel to the app - source.postMessage( - { - type: 'WCP3Handshake', - meta: { - connectionAttemptUuid: data.meta.connectionAttemptUuid, - timestamp: new Date(), - }, - payload: { - fdc3Version: '2.2', - intentResolverUrl: window.location.origin + '/static/da/intent-resolver.html', - channelSelectorUrl: window.location.origin + '/static/da/channel-selector.html', - }, - }, - origin, - [channel.port1] - ); }); }); }); diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index 560640e90..6adb47b7f 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -1,6 +1,7 @@ import { io } from 'socket.io-client'; import { link, UI, UI_URLS } from './util'; import { APP_HELLO } from '../../message-types'; +import { isWebConnectionProtocol1Hello } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; const appWindow = window.parent; @@ -17,10 +18,6 @@ function getQueryVariable(variable: string): string { return ''; } -function getConnectionAttemptUuid(): string { - return getQueryVariable('connectionAttemptUuid'); -} - function getSource(): string { return getQueryVariable('instanceId'); } @@ -34,34 +31,51 @@ function getUIKey(): UI { return parseInt(ui) as UI; } -window.addEventListener('load', () => { - const socket = io(); - const channel = new MessageChannel(); - const source = getSource(); - const desktopAgentUUID = getDesktopAgentId(); +const helloListener = (e: MessageEvent) => { + const messageData = e.data; + const eventSource = e.source; + const eventSourceName = (eventSource as Window)?.name ?? 'unknown'; - socket.on('connect', () => { - link(socket, channel, source); + if (isWebConnectionProtocol1Hello(messageData)) { + console.debug( + 'Received hello message from: ', + eventSourceName, + eventSource == appWindow ? '(parent window): ' : '(NOT parent win): ', + messageData + ); - socket.emit(APP_HELLO, desktopAgentUUID, source); + window.removeEventListener('message', helloListener); - const ui = UI_URLS[getUIKey()]; + const socket = io(); + const channel = new MessageChannel(); + const source = getSource(); + const desktopAgentUUID = getDesktopAgentId(); - // send the other end of the channel to the app - appWindow.postMessage( - { - type: 'WCP3Handshake', - meta: { - connectionAttemptUuid: getConnectionAttemptUuid(), - timestamp: new Date(), - }, - payload: { - fdc3Version: '2.2', - ...ui, + socket.on('connect', () => { + link(socket, channel, source); + + socket.emit(APP_HELLO, desktopAgentUUID, source); + + const ui = UI_URLS[getUIKey()]; + + // send the other end of the channel to the app + appWindow.postMessage( + { + type: 'WCP3Handshake', + meta: { + connectionAttemptUuid: messageData.meta.connectionAttemptUuid, + timestamp: new Date(), + }, + payload: { + fdc3Version: '2.2', + ...ui, + }, }, - }, - '*', - [channel.port1] - ); - }); -}); + '*', + [channel.port1] + ); + }); + } +}; + +window.addEventListener('message', helloListener); diff --git a/toolbox/fdc3-for-web/demo/src/server/main.ts b/toolbox/fdc3-for-web/demo/src/server/main.ts index ee66dba2d..6aba8031d 100644 --- a/toolbox/fdc3-for-web/demo/src/server/main.ts +++ b/toolbox/fdc3-for-web/demo/src/server/main.ts @@ -44,7 +44,7 @@ io.on('connection', (socket: Socket) => { connectionType = ConnectionType.DA; console.log('instances ' + instances.size); myInstance = instance; - console.log('A da connected: ' + id); + console.log('Desktop Agent connected: ' + id); }); socket.on(APP_HELLO, function (id: string, appId: string) { @@ -63,7 +63,6 @@ io.on('connection', (socket: Socket) => { socket.on(FDC3_APP_EVENT, function (data, from): void { // message from app to da - console.log(`APP Sent ${JSON.stringify(data, null, 2)}`); if (myInstance == null && data.type == 'intentResolutionChoice') { // message from app's intent resolver @@ -84,7 +83,6 @@ io.on('connection', (socket: Socket) => { // send message to app const destSocket = myInstance?.apps.get(to); if (destSocket) { - console.log(`DA Sent ${JSON.stringify(data, null, 2)} to ${to}`); destSocket.emit(FDC3_DA_EVENT, data, to); } else { console.log('Failed to send message to app ' + to); diff --git a/toolbox/fdc3-for-web/demo/static/da/nested.html b/toolbox/fdc3-for-web/demo/static/da/nested.html index f26a014fc..5af270175 100644 --- a/toolbox/fdc3-for-web/demo/static/da/nested.html +++ b/toolbox/fdc3-for-web/demo/static/da/nested.html @@ -19,7 +19,7 @@ width: 100px; } - + diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index 4d5b46424..92ac661a4 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -23,6 +23,11 @@ export interface MessageHandler { from: InstanceID ): void; + /** + * Clean-up any state relating to a instance that has disconnected. + */ + cleanup(instanceId: InstanceID, sc: ServerContext): void; + shutdown(): void; } @@ -38,6 +43,11 @@ export class BasicFDC3Server implements FDC3Server { this.sc = sc; } + cleanup(instanceId: InstanceID): void { + this.handlers.forEach(handler => handler.cleanup(instanceId, this.sc)); + this.sc.goodbye(instanceId); + } + receive( message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity | WebConnectionProtocol6Goodbye, from: InstanceID diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts index 6f33364f2..02b163bd9 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts @@ -8,4 +8,9 @@ export interface FDC3Server { * Receive an incoming message */ receive(message: AppRequestMessage, from: InstanceID): void; + + /** + * Cleanup state relating to an instance that has disconnected + */ + cleanup(instanceId: InstanceID): void; } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts index 29de2f6fe..048df7fb3 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts @@ -47,17 +47,30 @@ export interface ServerContext { */ open(appId: string): Promise; + /** + * Handle clean-up of state after an app instance disconnects. + */ + goodbye(instanceId: string): void; + /** * Registers a particular instance id with a given app id */ setInstanceDetails(uuid: InstanceID, details: X): void; /** - * Returns the UUID for a particular instance of an app. - * This is used in situations where an app is reconnecting to the same desktop agent. + * Returns the connection details for a particular instance of an app. + * Used in a variety of MessageHandler classes to retrieve details for + * an app and when validating an app's identity when connecting. */ getInstanceDetails(uuid: InstanceID): X | undefined; + /** + * Returns the connection details for a particular instance of an app that + * was previously connected to the Desktop Agent. Used when validating an + * app's identity when reconnecting. + */ + getPastInstanceDetails(uuid: InstanceID): X | undefined; + /** * Registers an app as connected to the desktop agent. */ diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index cc44fef03..75a0d73b9 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -1,5 +1,5 @@ import { MessageHandler } from '../BasicFDC3Server'; -import { InstanceID, ServerContext } from '../ServerContext'; +import { AppRegistration, InstanceID, ServerContext } from '../ServerContext'; import { Context } from '@kite9/fdc3-context'; import { AppIdentifier, ChannelError, DisplayMetadata, PrivateChannelEventTypes } from '@kite9/fdc3-standard'; import { successResponse, errorResponse, FullAppIdentifier, onlyUnique } from './support'; @@ -61,7 +61,7 @@ export type ChannelState = { export class BroadcastHandler implements MessageHandler { private contextListeners: ContextListenerRegistration[] = []; - private readonly eventListeners: PrivateChannelEventListener[] = []; + private eventListeners: PrivateChannelEventListener[] = []; private readonly state: ChannelState[] = []; private readonly currentChannel: { [instanceId: string]: ChannelState } = {}; @@ -71,6 +71,37 @@ export class BroadcastHandler implements MessageHandler { shutdown(): void {} + cleanup(instanceId: InstanceID, sc: ServerContext): void { + const toUnsubscribe = this.contextListeners.filter(r => r.instanceId == instanceId); + + //handle privateChannel disconnects + const privateChannelsToUnsubscribe = toUnsubscribe.filter( + u => this.state.find(chan => chan.id == u.channelId)?.type == ChannelType.private + ); + + const privateChannelsToDisconnect = new Set(); + privateChannelsToUnsubscribe.forEach(u => { + this.invokePrivateChannelEventListeners( + u.channelId, + 'unsubscribe', + 'privateChannelOnUnsubscribeEvent', + sc, + u.contextType ?? undefined + ); + if (u.channelId) { + privateChannelsToDisconnect.add(u.channelId); + } + }); + + privateChannelsToDisconnect.forEach(chan => { + this.invokePrivateChannelEventListeners(chan, 'disconnect', 'privateChannelOnDisconnectEvent', sc); + }); + + //clean up state entries + this.contextListeners = this.contextListeners.filter(listener => listener.instanceId !== instanceId); + this.eventListeners = this.eventListeners.filter(listener => listener.instanceId !== instanceId); + } + getCurrentChannel(from: FullAppIdentifier): ChannelState | null { return this.currentChannel[from.instanceId]; } @@ -113,7 +144,7 @@ export class BroadcastHandler implements MessageHandler { } } - accept(msg: AppRequestMessage, sc: ServerContext, uuid: InstanceID) { + accept(msg: AppRequestMessage, sc: ServerContext, uuid: InstanceID) { const from = sc.getInstanceDetails(uuid); if (from == null) { @@ -171,15 +202,15 @@ export class BroadcastHandler implements MessageHandler { case 'getCurrentContextRequest': return this.handleGetCurrentContextRequest(msg as GetCurrentContextRequest, sc, from); } - } catch (e: any) { + } catch (e) { const responseType = msg.type.replace(new RegExp('Request$'), 'Response'); - errorResponse(sc, msg, from, e.message ?? e, responseType as AgentResponseMessage['type']); + errorResponse(sc, msg, from, (e as Error).message ?? e, responseType as AgentResponseMessage['type']); } } handleCreatePrivateChannelRequest( arg0: CreatePrivateChannelRequest, - sc: ServerContext, + sc: ServerContext, from: FullAppIdentifier ) { const id = sc.createUUID(); @@ -199,7 +230,11 @@ export class BroadcastHandler implements MessageHandler { ); } - handleGetCurrentContextRequest(arg0: GetCurrentContextRequest, sc: ServerContext, from: FullAppIdentifier) { + handleGetCurrentContextRequest( + arg0: GetCurrentContextRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { const channel = this.getChannelById(arg0.payload.channelId); const type = arg0.payload.contextType; @@ -213,7 +248,7 @@ export class BroadcastHandler implements MessageHandler { handlePrivateChannelUnsubscribeEventListenerRequest( arg0: PrivateChannelUnsubscribeEventListenerRequest, - sc: ServerContext, + sc: ServerContext, from: FullAppIdentifier ) { const i = this.eventListeners.findIndex(r => r.listenerUuid == arg0.payload.listenerUUID); @@ -227,7 +262,7 @@ export class BroadcastHandler implements MessageHandler { handlePrivateChannelDisconnectRequest( arg0: PrivateChannelDisconnectRequest, - sc: ServerContext, + sc: ServerContext, from: FullAppIdentifier ) { const toUnsubscribe = this.contextListeners @@ -256,7 +291,7 @@ export class BroadcastHandler implements MessageHandler { handleContextListenerUnsubscribeRequest( arg0: ContextListenerUnsubscribeRequest, - sc: ServerContext, + sc: ServerContext, from: FullAppIdentifier ) { const i = this.contextListeners.findIndex( @@ -280,7 +315,11 @@ export class BroadcastHandler implements MessageHandler { } } - handleAddContextListenerRequest(arg0: AddContextListenerRequest, sc: ServerContext, from: FullAppIdentifier) { + handleAddContextListenerRequest( + arg0: AddContextListenerRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { let channelId = null; let channelType = ChannelType.user; @@ -316,7 +355,7 @@ export class BroadcastHandler implements MessageHandler { successResponse(sc, arg0, from, { listenerUUID: lr.listenerUuid }, 'addContextListenerResponse'); } - handleBroadcastRequest(arg0: BroadcastRequest, sc: ServerContext, from: FullAppIdentifier) { + handleBroadcastRequest(arg0: BroadcastRequest, sc: ServerContext, from: FullAppIdentifier) { const matchingListeners = this.contextListeners .filter(r => r.channelId == arg0.payload.channelId) .filter(r => r.contextType == null || r.contextType == arg0.payload.context.type); @@ -348,7 +387,11 @@ export class BroadcastHandler implements MessageHandler { successResponse(sc, arg0, from, {}, 'broadcastResponse'); } - handleGetCurrentChannelRequest(arg0: GetCurrentChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + handleGetCurrentChannelRequest( + arg0: GetCurrentChannelRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { const currentChannel = this.getCurrentChannel(from); if (currentChannel) { successResponse( @@ -369,7 +412,11 @@ export class BroadcastHandler implements MessageHandler { } } - handleJoinUserChannelRequest(arg0: JoinUserChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + handleJoinUserChannelRequest( + arg0: JoinUserChannelRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { // check it's a user channel const newChannel = this.getChannelById(arg0.payload.channelId); if (newChannel == null || newChannel.type != ChannelType.user) { @@ -383,7 +430,11 @@ export class BroadcastHandler implements MessageHandler { successResponse(sc, arg0, from, {}, 'joinUserChannelResponse'); } - handleLeaveCurrentChannelRequest(arg0: LeaveCurrentChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + handleLeaveCurrentChannelRequest( + arg0: LeaveCurrentChannelRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { const instanceId = from.instanceId ?? 'no-instance-id'; const currentChannel = this.currentChannel[instanceId]; if (currentChannel) { @@ -393,7 +444,11 @@ export class BroadcastHandler implements MessageHandler { successResponse(sc, arg0, from, {}, 'leaveCurrentChannelResponse'); } - handleGetOrCreateRequest(arg0: GetOrCreateChannelRequest, sc: ServerContext, from: FullAppIdentifier) { + handleGetOrCreateRequest( + arg0: GetOrCreateChannelRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { const id = arg0.payload.channelId; let channel = this.getChannelById(id); if (channel) { @@ -413,7 +468,11 @@ export class BroadcastHandler implements MessageHandler { successResponse(sc, arg0, from, { channel: { id: channel.id, type: channel.type } }, 'getOrCreateChannelResponse'); } - handleGetUserChannelsRequest(arg0: GetUserChannelsRequest, sc: ServerContext, from: FullAppIdentifier) { + handleGetUserChannelsRequest( + arg0: GetUserChannelsRequest, + sc: ServerContext, + from: FullAppIdentifier + ) { const userChannels = this.state.filter(c => c.type == ChannelType.user); successResponse( sc, @@ -433,7 +492,7 @@ export class BroadcastHandler implements MessageHandler { handlePrivateChannelAddEventListenerRequest( arg0: PrivateChannelAddEventListenerRequest, from: FullAppIdentifier, - sc: ServerContext + sc: ServerContext ) { const channel = this.getChannelById(arg0.payload.privateChannelId); @@ -459,7 +518,7 @@ export class BroadcastHandler implements MessageHandler { | 'privateChannelOnAddContextListenerEvent' | 'privateChannelOnUnsubscribeEvent' | 'privateChannelOnDisconnectEvent', - sc: ServerContext, + sc: ServerContext, contextType?: string ) { if (privateChannelId) { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts index a1f3e0916..bb63d6fa8 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts @@ -82,6 +82,11 @@ export class HeartbeatHandler implements MessageHandler { }, pingInterval); } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + cleanup(_instanceId: InstanceID, _sc: ServerContext): void { + //TODO: Consider whether to clean-up last heartbeat times + } + heartbeatTimes(): HeartbeatDetails[] { const now = new Date().getTime(); return Array.from(this.lastHeartbeats) diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts index 1eb38e388..79c654fc4 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts @@ -125,7 +125,7 @@ class PendingIntent { export class IntentHandler implements MessageHandler { private readonly directory: Directory; - private readonly registrations: ListenerRegistration[] = []; + private registrations: ListenerRegistration[] = []; readonly pendingIntents: Set = new Set(); readonly pendingResolutions: Map = new Map(); readonly timeoutMs: number; @@ -135,6 +135,19 @@ export class IntentHandler implements MessageHandler { this.timeoutMs = timeoutMs; } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + cleanup(instanceId: InstanceID, _sc: ServerContext): void { + this.registrations = this.registrations.filter(reg => reg.instanceId != instanceId); + //don't clean up pendingIntents as some apps may load + + //cleanup pendingResolutions + this.pendingResolutions.forEach((val, key) => { + if (val.instanceId === instanceId) { + this.pendingResolutions.delete(key); + } + }); + } + shutdown(): void {} async narrowIntents( diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts index 762493bff..535d57a52 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts @@ -34,9 +34,6 @@ enum AppState { Done, } -//TODO: Explain the naming of this file and clarify its purpose (what is it responsible for) - you can't intuit this from the name - -//TODO document this class, its purpose and why it is in this file class PendingApp { private readonly sc: ServerContext; private readonly msg: OpenRequest; @@ -65,15 +62,15 @@ class PendingApp { } private onSuccess() { - this.sc.setAppState(this.openedApp?.instanceId!!, State.Connected); + this.sc.setAppState(this.openedApp!.instanceId!, State.Connected); successResponse( this.sc, this.msg, this.source, { appIdentifier: { - appId: this.openedApp!!.appId, - instanceId: this.openedApp!!.instanceId, + appId: this.openedApp!.appId, + instanceId: this.openedApp!.instanceId, }, }, 'openResponse' @@ -109,6 +106,10 @@ export class OpenHandler implements MessageHandler { this.timeoutMs = timeoutMs; } + cleanup(/*instanceId: InstanceID, sc: ServerContext*/): void { + //don't cleanup pending if the opening app closes as we should still deliver context + } + shutdown(): void {} async accept( @@ -137,7 +138,6 @@ export class OpenHandler implements MessageHandler { } } catch (e) { const responseType = msg.type.replace(new RegExp('Request$'), 'Response') as AgentResponseMessage['type']; - //TODO: create a typeguard for response message types and use it to replace the 'as' below errorResponse(sc, msg, from, (e as Error).message ?? e, responseType); } } else { @@ -155,16 +155,11 @@ export class OpenHandler implements MessageHandler { from: InstanceID ): void { const pendingOpen = this.pending.get(from); - if (pendingOpen) { - //TODO: Find out why this is asserted non-null - context is only sent to the user channel listener - const channelId = arg0.payload.channelId!!; const contextType = arg0.payload.contextType; - if (pendingOpen.context && pendingOpen.state == AppState.DeliveringContext) { if (contextType == pendingOpen.context.type || contextType == undefined) { // ok, we can deliver to this listener - const message: BroadcastEvent = { meta: { eventUuid: sc.createUUID(), @@ -172,7 +167,7 @@ export class OpenHandler implements MessageHandler { }, type: 'broadcastEvent', payload: { - channelId, + channelId: null, context: pendingOpen.context, originatingApp: { appId: pendingOpen.source.appId, @@ -248,11 +243,11 @@ export class OpenHandler implements MessageHandler { } async open(arg0: OpenRequest, sc: ServerContext, from: FullAppIdentifier): Promise { - const source = arg0.payload.app; + const toOpen = arg0.payload.app; const context = arg0.payload.context; try { - const uuid = await sc.open(source.appId); + const uuid = await sc.open(toOpen.appId); this.pending.set(uuid, new PendingApp(sc, arg0, context, from, this.timeoutMs)); } catch (e) { errorResponse(sc, arg0, from, (e as Error).message ?? e, 'openResponse'); @@ -328,24 +323,29 @@ export class OpenHandler implements MessageHandler { if (arg0.payload.instanceUuid) { // existing app reconnecting - const appIdentity = sc.getInstanceDetails(arg0.payload.instanceUuid); + console.log('App attempting to reconnect:', arg0.payload.instanceUuid); + const appIdentity = sc.getPastInstanceDetails(arg0.payload.instanceUuid); if (appIdentity) { // in this case, the app is reconnecting, so let's just re-assign the // identity + console.log(`Reassigned existing identity (appId: ${appIdentity.appId}): `, arg0.payload.instanceUuid); sc.setInstanceDetails(from, appIdentity); sc.setAppState(from, State.Connected); return returnSuccess(appIdentity.appId, appIdentity.instanceId); + } else { + //we didn't find the identity, assign a new one + console.log('Existing identity not found for, assigning a new one: ', arg0.payload.instanceUuid); } } - // we need to assign an identity to this app + // we need to assign an identity to this app - this should have been generated when it was launched const appIdentity = sc.getInstanceDetails(from); if (appIdentity) { sc.setAppState(appIdentity.instanceId, State.Connected); returnSuccess(appIdentity.appId, appIdentity.instanceId); - // make sure if the opener is listening for this app to open gets informed + // make sure, if the opener is listening for this app to open, then it gets informed const pendingOpen = this.pending.get(from); if (pendingOpen) { if (pendingOpen.state == AppState.Opening) { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts index 904967cbc..6cc2fc109 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts @@ -24,6 +24,11 @@ export class TestServerContext implements ServerContext { this.cw = cw; } + goodbye(instanceId: string): void { + this.instances = this.instances.filter(instance => instance.instanceId !== instanceId); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[], _context: Context): Promise { return appIntents; } @@ -32,6 +37,11 @@ export class TestServerContext implements ServerContext { return this.instances.find(ca => ca.instanceId === uuid); } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getPastInstanceDetails(_uuid: string) { + return undefined; + } + setInstanceDetails(uuid: InstanceID, appId: ConnectionDetails) { if (uuid != appId.instanceId) { throw new Error('UUID mismatch'); @@ -102,8 +112,8 @@ export class TestServerContext implements ServerContext { const id = this.getInstanceDetails(to); const app = id ? { - appId: id!!.appId, - instanceId: id!!.instanceId, + appId: id!.appId, + instanceId: id!.instanceId, } : undefined; this.postedMessages.push({ @@ -122,11 +132,11 @@ export class TestServerContext implements ServerContext { * USED FOR TESTING */ getInstanceUUID(appId: AppIdentifier): InstanceID { - this.setInstanceDetails(appId.instanceId!!, { + this.setInstanceDetails(appId.instanceId!, { appId: appId.appId, - instanceId: appId.instanceId!!, + instanceId: appId.instanceId!, state: State.Connected, }); - return appId.instanceId!!; + return appId.instanceId!; } } From 9d1317cac1e38ec1bb080e51a5b4c78278a0236e Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 2 Jan 2025 15:08:22 +0000 Subject: [PATCH 68/90] IntentHandler test coverage --- packages/fdc3-agent-proxy/src/Messaging.ts | 2 +- .../demo/src/client/da/dummy-desktop-agent.ts | 4 +- .../src/handlers/IntentHandler.ts | 18 +++- .../raise-intent-with-context.feature | 18 ++-- .../test/features/raise-intent.feature | 50 +++++++--- .../test/step-definitions/generic.steps.ts | 12 ++- .../test/step-definitions/heartbeat.steps.ts | 2 +- .../test/step-definitions/intents.steps.ts | 97 +++++++++++++++---- .../test/step-definitions/start-app.steps.ts | 5 +- .../test/support/TestServerContext.ts | 4 - 10 files changed, 159 insertions(+), 53 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/Messaging.ts b/packages/fdc3-agent-proxy/src/Messaging.ts index 358497473..724c0547e 100644 --- a/packages/fdc3-agent-proxy/src/Messaging.ts +++ b/packages/fdc3-agent-proxy/src/Messaging.ts @@ -6,7 +6,7 @@ import { WebConnectionProtocol6Goodbye, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -export interface Messaging /*extends Connectable*/ { +export interface Messaging { /** * Creates UUIDs used in outgoing messages */ diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index aef4fa372..6f45b089b 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -55,8 +55,8 @@ window.addEventListener('load', () => { socket.emit(DA_HELLO, desktopAgentUUID); const directory = new FDC3_2_1_JSONDirectory(); - await directory.load('/static/da/appd.json'); - //await directory.load('/static/da/local-conformance-2_0.v2.json'); + //await directory.load('/static/da/appd.json'); + await directory.load('/static/da/local-conformance-2_0.v2.json'); const sc = new DemoServerContext(socket, directory); const channelDetails: ChannelState[] = [ diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts index 79c654fc4..266ab669a 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts @@ -75,7 +75,7 @@ async function forwardRequest( { intentResolution: { intent: arg0.intent, - source: to, + source: { appId: to.appId, instanceId: to.instanceId }, //make sure we're not carrying any excess fields from internal state }, }, arg0.type @@ -503,7 +503,13 @@ export class IntentHandler implements MessageHandler { } else { //invalid target console.warn('Received an invalid target argument for raiseIntent', target, arg0); - return this.raiseIntentToAnyApp([intentRequest], sc); + return errorResponseId( + sc, + arg0.meta.requestUuid, + from, + ResolveError.TargetAppUnavailable, + 'raiseIntentResponse' + ); } } else { //No target @@ -548,7 +554,13 @@ export class IntentHandler implements MessageHandler { } else { //invalid target console.warn('Received an invalid target argument for raiseIntentForContext', target, arg0); - return this.raiseIntentToAnyApp(possibleIntentRequests, sc); + return errorResponseId( + sc, + arg0.meta.requestUuid, + from, + ResolveError.TargetAppUnavailable, + 'raiseIntentForContextResponse' + ); } } else { //No target diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent-with-context.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent-with-context.feature index 5b71c3df0..908b2cdb6 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent-with-context.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent-with-context.feature @@ -17,26 +17,32 @@ Feature: Raising Intents For Context And "listenerApp/b1" is opened with connection id "b1" And "listenerApp/b1" registers an intent listener for "returnBook" - Scenario: Raising an Intent to a Non-Existent App + Scenario: Raising an Intent With Context to a Non-Existent App And "App1/a1" raises an intent with contextType "fdc3.magazine" on app "completelyMadeUp" Then messaging will have outgoing posts | msg.type | msg.payload.error | to.instanceId | to.appId | | raiseIntentForContextResponse | TargetAppUnavailable | a1 | App1 | - Scenario: Raising An Intent To A Non-Existent App Instance + Scenario: Raising An Intent With Context To A Non-Existent App Instance When "App1/a1" raises an intent with contextType "fdc3.book" on app "libraryApp/unknownInstance" Then messaging will have outgoing posts | msg.type | msg.payload.error | to.instanceId | | raiseIntentForContextResponse | TargetInstanceUnavailable | a1 | - Scenario: Raising An Intent To A Running App +Scenario: Raising An Intent With Context To An Invalid Instance + When "App1/a1" raises an intent with contextType "fdc3.book" on an invalid app instance + Then messaging will have outgoing posts + | msg.type | msg.payload.error | to.instanceId | + | raiseIntentForContextResponse | TargetAppUnavailable | a1 | + + Scenario: Raising An Intent With Context To A Running App When "App1/a1" raises an intent with contextType "fdc3.book" on app "listenerApp/b1" Then messaging will have outgoing posts | msg.matches_type | msg.payload.context.type | msg.payload.intent | msg.payload.originatingApp.appId | msg.payload.originatingApp.instanceId | msg.payload.intentResolution.intent | to.instanceId | to.appId | msg.payload.intentResolution.source.appId | | intentEvent | fdc3.book | returnBook | App1 | a1 | {null} | b1 | listenerApp | {null} | | raiseIntentForContextResponse | {null} | {null} | {null} | {null} | returnBook | a1 | App1 | listenerApp | - Scenario: Raising An Intent To A Non-Running App + Scenario: Raising An Intent With Context To A Non-Running App When "App1/a1" raises an intent with contextType "fdc3.magazine" on app "libraryApp" And "uuid-0" sends validate And "libraryApp/0" registers an intent listener for "borrowMagazine" @@ -46,13 +52,13 @@ Feature: Raising Intents For Context | intentEvent | borrowMagazine | 0 | libraryApp | fdc3.magazine | | raiseIntentForContextResponse | {null} | a1 | App1 | {null} | - Scenario: Raising an Intent to a Non-Existent App Instance + Scenario: Raising an Intent With Context to a Non-Existent App Instance And "App1/a1" raises an intent with contextType "fdc3.book" on app "unusedApp/u1" Then messaging will have outgoing posts | msg.type | msg.payload.error | to.instanceId | to.appId | | raiseIntentForContextResponse | TargetInstanceUnavailable | a1 | App1 | - Scenario: Raising An Intent To A Broken App that doesn't add an intent listener + Scenario: Raising An Intent With Context To A Broken App that doesn't add an intent listener When "App1/a1" raises an intent with contextType "fdc3.magazine" on app "libraryApp" And "uuid-0" sends validate And we wait for the intent timeout diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent.feature index c83e70078..c287be31e 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/raise-intent.feature @@ -9,9 +9,14 @@ Feature: Raising Intents And "listenerApp" is an app with the following intents | Intent Name | Context Type | Result Type | | borrowBook | fdc3.book | {empty} | + And "uniqueIntentApp" is an app with the following intents + | Intent Name | Context Type | Result Type | + | uniqueIntent | fdc3.magazine | {empty} | And "unusedApp" is an app with the following intents | Intent Name | Context Type | Result Type | And A newly instantiated FDC3 Server + And "uniqueIntentApp/c1" is opened with connection id "c1" + And "uniqueIntentApp/c1" registers an intent listener for "uniqueIntent" And "App1/a1" is opened with connection id "a1" And "listenerApp/b1" is opened with connection id "b1" And "listenerApp/b1" registers an intent listener for "returnBook" @@ -22,6 +27,13 @@ Feature: Raising Intents | msg.type | msg.payload.error | to.instanceId | | raiseIntentResponse | NoAppsFound | a1 | + Scenario: Raising an Intent that should auto-resolve (only one option) + And "App1/a1" raises an intent for "uniqueIntent" with contextType "fdc3.magazine" + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.context.type | msg.payload.intent | msg.payload.originatingApp.appId | msg.payload.originatingApp.instanceId | msg.payload.intentResolution.intent | to.instanceId | to.appId | msg.payload.intentResolution.source.appId | + | intentEvent | fdc3.magazine | uniqueIntent | App1 | a1 | {null} | c1 | uniqueIntentApp | {null} | + | raiseIntentResponse | {null} | {null} | {null} | {null} | uniqueIntent | a1 | App1 | uniqueIntentApp | + Scenario: Raising an Intent to a Non-Existent App And "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on app "completelyMadeUp" Then messaging will have outgoing posts @@ -34,13 +46,21 @@ Feature: Raising Intents | msg.type | msg.payload.error | to.instanceId | | raiseIntentResponse | TargetInstanceUnavailable | a1 | - Scenario: Raising An Intent To A Running App + Scenario: Raising An Intent To A Running App instance by instanceId When "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on app "listenerApp/b1" Then messaging will have outgoing posts | msg.matches_type | msg.payload.context.type | msg.payload.intent | msg.payload.originatingApp.appId | msg.payload.originatingApp.instanceId | msg.payload.intentResolution.intent | to.instanceId | to.appId | msg.payload.intentResolution.source.appId | | intentEvent | fdc3.book | returnBook | App1 | a1 | {null} | b1 | listenerApp | {null} | | raiseIntentResponse | {null} | {null} | {null} | {null} | returnBook | a1 | App1 | listenerApp | +Scenario: Raising An Intent To A Running App instance by appId + When "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on app "listenerApp" + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.context.type | msg.payload.intent | msg.payload.originatingApp.appId | msg.payload.originatingApp.instanceId | msg.payload.intentResolution.intent | to.instanceId | to.appId | msg.payload.intentResolution.source.appId | + | intentEvent | fdc3.book | returnBook | App1 | a1 | {null} | b1 | listenerApp | {null} | + | raiseIntentResponse | {null} | {null} | {null} | {null} | returnBook | a1 | App1 | listenerApp | + + Scenario: Raising An Intent To A Non-Running App When "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on app "libraryApp" And "uuid-0" sends validate @@ -57,6 +77,12 @@ Feature: Raising Intents | msg.type | msg.payload.error | to.instanceId | to.appId | | raiseIntentResponse | TargetInstanceUnavailable | a1 | App1 | + Scenario: Raising an Intent to an invalid App Instance + And "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on an invalid app instance + Then messaging will have outgoing posts + | msg.type | msg.payload.error | to.instanceId | to.appId | + | raiseIntentResponse | TargetAppUnavailable | a1 | App1 | + Scenario: Raising An Intent To A Non-Running App without A Context Type in the listener When "App1/a1" raises an intent for "stampBook" with contextType "fdc3.book" on app "libraryApp" And "uuid-0" sends validate @@ -67,20 +93,22 @@ Feature: Raising Intents | intentEvent | stampBook | uuid-0 | libraryApp | fdc3.book | | raiseIntentResponse | {null} | a1 | App1 | {null} | And running apps will be - | appId | instanceId | - | listenerApp | b1 | - | App1 | a1 | - | libraryApp | uuid-0 | + | appId | instanceId | + | uniqueIntentApp | c1 | + | listenerApp | b1 | + | App1 | a1 | + | libraryApp | uuid-0 | Scenario: Raising An Intent To A Broken App that doesn't add an intent listener When "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on app "libraryApp" And "uuid-0" sends validate And we wait for the intent timeout Then running apps will be - | appId | instanceId | - | listenerApp | b1 | - | App1 | a1 | - | libraryApp | uuid-0 | + | appId | instanceId | + | uniqueIntentApp | c1 | + | listenerApp | b1 | + | App1 | a1 | + | libraryApp | uuid-0 | Then messaging will have outgoing posts | msg.type | msg.payload.error | to.instanceId | to.appId | | raiseIntentResponse | IntentDeliveryFailed | a1 | App1 | @@ -101,7 +129,7 @@ Feature: Raising Intents | listenerApp | {null} | Scenario: Raising An Invalid Intent to the server (no instance) - When "App1/a1" raises an intent for "borrowBook" with contextType "fdc3.book" on app "listenerApp/c1" + When "App1/a1" raises an intent for "borrowBook" with contextType "fdc3.book" on app "listenerApp/z1" Then messaging will have outgoing posts | msg.payload.error | msg.type | | TargetInstanceUnavailable | raiseIntentResponse | @@ -118,7 +146,7 @@ Feature: Raising Intents | msg.payload.error | msg.type | | NoAppsFound | raiseIntentResponse | - Scenario: Raising An Invalid Intent (non existent intent but valid app) + Scenario: Raising An Invalid Intent (non existent intent but valid app) When "App1/a1" raises an intent for "nonExistentIntent" with contextType "fdc3.book" on app "listenerApp/b1" Then messaging will have outgoing posts | msg.payload.error | msg.type | diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts index d701688a7..5caac467e 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts @@ -4,10 +4,11 @@ import { TestServerContext } from '../support/TestServerContext'; import { DefaultFDC3Server } from '../../src/BasicFDC3Server'; import { BasicDirectory } from '../../src/directory/BasicDirectory'; import { ChannelType } from '../../src/handlers/BroadcastHandler'; +import { Context } from '@kite9/fdc3-context'; export const APP_FIELD = 'apps'; -export const contextMap: Record = { +export const contextMap: Record = { 'fdc3.instrument': { type: 'fdc3.instrument', name: 'Apple', @@ -78,8 +79,13 @@ function defaultChannels() { } export function createMeta(cw: CustomWorld, appStr: string) { - const [appId, instanceId] = appStr.split('/'); - const app = { appId, instanceId }; + let app; + if (appStr.includes('/')) { + const [appId, instanceId] = appStr.split('/'); + app = { appId, instanceId }; + } else { + app = { appId: appStr }; + } return { requestUuid: cw.sc.createUUID(), diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts index 3d67022d3..38b676b27 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/heartbeat.steps.ts @@ -38,7 +38,7 @@ Given('{string} sends a goodbye message', function (this: CustomWorld, appStr: s }); Then('I test the liveness of {string}', async function (this: CustomWorld, appStr: string) { - const out = await this.sc.isAppConnected(createMeta(this, appStr).source.instanceId); + const out = await this.sc.isAppConnected(createMeta(this, appStr).source.instanceId ?? 'UNKNOWN'); this.props['result'] = out; }); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts index 099423bb2..97eacea5d 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts @@ -32,7 +32,7 @@ function decamelize(str: string, separator: string) { function convertDataTableToListensFor(cw: CustomWorld, dt: DataTable): ListensFor { const hashes = dt.hashes(); - const out: { [key: string]: any } = {}; + const out: ListensFor = {}; hashes.forEach(h => { out[h['Intent Name']] = { displayName: decamelize(h['Intent Name'], ' '), @@ -69,11 +69,11 @@ When( '{string} finds intents with intent {string} and contextType {string} and result type {string}', function (this: CustomWorld, appStr: string, intentName: string, contextType: string, resultType: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { - intent: handleResolve(intentName, this)!!, + intent: handleResolve(intentName, this)!, resultType: handleResolve(resultType, this), context: contextMap[contextType], }, @@ -88,7 +88,7 @@ When( '{string} finds intents with contextType {string}', function (this: CustomWorld, appStr: string, contextType: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { @@ -105,7 +105,7 @@ Given( '{string} registers an intent listener for {string}', function (this: CustomWorld, appStr: string, intent: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { type: 'addIntentListenerRequest', @@ -122,7 +122,7 @@ Given( '{string} registers an intent listener for {string} with contextType {string}', function (this: CustomWorld, appStr: string, intent: string, contextType: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { type: 'addIntentListenerRequest', meta, @@ -139,7 +139,7 @@ Given( '{string} unsubscribes an intent listener with id {string}', function (this: CustomWorld, appStr: string, id: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { type: 'intentListenerUnsubscribeRequest', meta, @@ -156,7 +156,7 @@ function raise( intentName: string, contextType: string, dest: string | null, - meta: any + meta: RaiseIntentRequest['meta'] ): RaiseIntentRequest { const destMeta = dest != null ? createMeta(cw, dest) : null; const message = { @@ -167,7 +167,7 @@ function raise( payload: { intent: handleResolve(intentName, cw), context: contextMap[contextType], - app: dest ? destMeta!!.source : null, + app: dest ? destMeta!.source : null, }, } as RaiseIntentRequest; return message; @@ -177,7 +177,7 @@ function raiseWithContext( cw: CustomWorld, contextType: string, dest: string | null, - meta: any + meta: RaiseIntentForContextRequest['meta'] ): RaiseIntentForContextRequest { const destMeta = dest != null ? createMeta(cw, dest) : null; const message = { @@ -187,17 +187,54 @@ function raiseWithContext( }, payload: { context: contextMap[contextType], - app: dest ? destMeta!!.source : null, + app: dest ? destMeta!.source : null, }, } as RaiseIntentForContextRequest; return message; } +function raiseWithInvalidTarget( + cw: CustomWorld, + intentName: string, + contextType: string, + meta: RaiseIntentRequest['meta'] +): RaiseIntentRequest { + const message = { + type: 'raiseIntentRequest', + meta: { + ...meta, + }, + payload: { + intent: handleResolve(intentName, cw), + context: contextMap[contextType], + app: 'SPOON', + }, + } as unknown as RaiseIntentRequest; + return message; +} + +function raiseWithContextAnInvalidTarget( + contextType: string, + meta: RaiseIntentForContextRequest['meta'] +): RaiseIntentForContextRequest { + const message = { + type: 'raiseIntentForContextRequest', + meta: { + ...meta, + }, + payload: { + context: contextMap[contextType], + app: 'SPOON', + }, + } as unknown as RaiseIntentForContextRequest; + return message; +} + When( '{string} raises an intent with contextType {string}', function (this: CustomWorld, appStr: string, contextType: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raiseWithContext(this, contextType, null, meta); this.server.receive(message, uuid); } @@ -207,7 +244,7 @@ When( '{string} raises an intent with contextType {string} on app {string}', function (this: CustomWorld, appStr: string, contextType: string, dest: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raiseWithContext(this, contextType, dest, meta); this.server.receive(message, uuid); } @@ -217,7 +254,7 @@ When( '{string} raises an intent for {string} with contextType {string}', function (this: CustomWorld, appStr: string, intentName: string, contextType: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raise(this, intentName, contextType, null, meta); this.server.receive(message, uuid); } @@ -227,12 +264,32 @@ When( '{string} raises an intent for {string} with contextType {string} on app {string}', function (this: CustomWorld, appStr: string, intentName: string, contextType: string, dest: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raise(this, intentName, contextType, dest, meta); this.server.receive(message, uuid); } ); +When( + '{string} raises an intent for {string} with contextType {string} on an invalid app instance', + function (this: CustomWorld, appStr: string, intentName: string, contextType: string) { + const meta = createMeta(this, appStr); + const uuid = this.sc.getInstanceUUID(meta.source)!; + const message = raiseWithInvalidTarget(this, intentName, contextType, meta); + this.server.receive(message, uuid); + } +); + +When( + '{string} raises an intent with contextType {string} on an invalid app instance', + function (this: CustomWorld, appStr: string, contextType: string) { + const meta = createMeta(this, appStr); + const uuid = this.sc.getInstanceUUID(meta.source)!; + const message = raiseWithContextAnInvalidTarget(contextType, meta); + this.server.receive(message, uuid); + } +); + When( '{string} raises an intent for {string} with contextType {string} on app {string} with requestUuid {string}', function ( @@ -247,14 +304,14 @@ When( ...createMeta(this, appStr), requestUuid, }; - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raise(this, intentName, contextType, dest, meta); this.server.receive(message, uuid); } ); When('we wait for the intent timeout', function (this: CustomWorld) { - return new Promise((resolve, _reject) => { + return new Promise(resolve => { setTimeout(() => resolve(), 2100); }); }); @@ -263,7 +320,7 @@ When( '{string} sends a intentResultRequest with eventUuid {string} and contextType {string} and raiseIntentUuid {string}', function (this: CustomWorld, appStr: string, eventUuid: string, contextType: string, raiseIntentUuid: string) { const meta = createMeta(this, appStr); - const uuid1 = this.sc.getInstanceUUID(meta.source)!!; + const uuid1 = this.sc.getInstanceUUID(meta.source)!; const message: IntentResultRequest = { type: 'intentResultRequest', meta: { @@ -285,7 +342,7 @@ When( '{string} sends a intentResultRequest with eventUuid {string} and void contents and raiseIntentUuid {string}', function (this: CustomWorld, appStr: string, eventUuid: string, raiseIntentUuid: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message: IntentResultRequest = { type: 'intentResultRequest', meta: { @@ -305,7 +362,7 @@ When( '{string} sends a intentResultRequest with eventUuid {string} and private channel {string} and raiseIntentUuid {string}', function (this: CustomWorld, appStr: string, eventUuid: string, channelId: string, raiseIntentUuid: string) { const meta = createMeta(this, appStr); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message: IntentResultRequest = { type: 'intentResultRequest', diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts index 120525fd5..fcc69935c 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/start-app.steps.ts @@ -14,14 +14,15 @@ type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProto When('{string} is opened with connection id {string}', function (this: CustomWorld, app: string, uuid: string) { const meta = createMeta(this, app); this.sc.setInstanceDetails(uuid, { - ...meta.source, + appId: meta.source.appId, + instanceId: meta.source.instanceId!, state: State.Connected, }); }); When('{string} is closed', function (this: CustomWorld, app: string) { const meta = createMeta(this, app); - this.sc.disconnectApp(meta.source); + this.server.cleanup(meta.source.instanceId!); }); When('{string} sends validate', function (this: CustomWorld, uuid: string) { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts index 6cc2fc109..5bbd41e92 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts @@ -50,10 +50,6 @@ export class TestServerContext implements ServerContext { this.instances.push(appId); } - async disconnectApp(app: AppIdentifier): Promise { - this.instances = this.instances.filter(ca => ca.instanceId !== app.instanceId); - } - async open(appId: string): Promise { const ni = this.nextInstanceId++; if (appId.includes('missing')) { From 3b795eaf274ce57d358f8ab9cacc757f5f84c617 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 2 Jan 2025 16:52:36 +0000 Subject: [PATCH 69/90] catch cross-domain window.name accesses --- .../src/sessionStorage/DesktopAgentDetails.ts | 38 ++++++++++--------- .../src/ui/AbstractUIComponent.ts | 9 +---- .../demo/src/client/da/dummy-desktop-agent.ts | 8 +++- .../fdc3-for-web/demo/src/client/da/embed.ts | 10 ++++- .../demo/src/client/ui/channel-selector.ts | 1 - .../test/step-definitions/generic.steps.ts | 3 +- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts index 4c76c7e25..d1f832f60 100644 --- a/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts +++ b/packages/fdc3-get-agent/src/sessionStorage/DesktopAgentDetails.ts @@ -67,24 +67,26 @@ export function retrieveDesktopAgentDetails(identityUrl: string): DesktopAgentDe if (allDetails) { const theData: DesktopAgentDetails = allDetails[identityUrl]; - //check we got the minimum properties - if ( - typeof theData.agentType === 'string' && - theData.agentType && //TODO: check this is one of the enum values - typeof theData.appId === 'string' && - theData.appId && - typeof theData.instanceId === 'string' && - theData.instanceId - ) { - return theData; - } else { - //ignore it and post a warning - Logger.warn( - `DesktopAgentDetails: Stored details do not meet minimum requirements and will be ignored:\n${JSON.stringify(theData, null, 2)}` - ); - return null; + if (theData) { + //check we got the minimum properties + if ( + typeof theData.agentType === 'string' && + theData.agentType && //TODO: check this is one of the enum values + typeof theData.appId === 'string' && + theData.appId && + typeof theData.instanceId === 'string' && + theData.instanceId + ) { + return theData; + } else { + //ignore it and post a warning + Logger.warn( + `DesktopAgentDetails: Stored details do not meet minimum requirements and will be ignored:\n${JSON.stringify(theData, null, 2)}` + ); + return null; + } } - } else { - return null; } + + return null; } diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index d3df44187..dd3288c46 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -110,14 +110,7 @@ export abstract class AbstractUIComponent implements Connectable { Logger.debug('AbstractUIComponent: ignored UI Message from UI iframe while awaiting hello: ', e.data); } } else { - Logger.debug( - "AbstractUIComponent: ignored Message that didn't come from expected UI frame\n", - e.data, - '\nexpected window name: ', - this.iframe?.contentWindow?.name, - '\ngot window name: ', - (e.source as Window).name - ); + Logger.debug("AbstractUIComponent: ignored Message that didn't come from expected UI frame\n", e.data); } }; diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index 6f45b089b..145508e3d 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -134,7 +134,13 @@ window.addEventListener('load', () => { source.postMessage(message, origin, [channel.port1]); } } else { - console.error(`Couldn't locate an instance for Window.name: ${source.name}`); + let sourceName; + try { + sourceName = source.name; + } catch (e: unknown) { + sourceName = `{a cross-origin window: ${(e as Error).message ?? e}}`; + } + console.error(`Couldn't locate an instance for window: ${sourceName}`); } } }); diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index 6adb47b7f..fcd67d0c7 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -34,7 +34,15 @@ function getUIKey(): UI { const helloListener = (e: MessageEvent) => { const messageData = e.data; const eventSource = e.source; - const eventSourceName = (eventSource as Window)?.name ?? 'unknown'; + let eventSourceName; + try { + eventSourceName = (eventSource as Window)?.name; + } catch (e) { + eventSourceName = '{a cross-origin window} '; + } + if (!eventSourceName) { + eventSourceName = '{no window name set} '; + } if (isWebConnectionProtocol1Hello(messageData)) { console.debug( diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts index 06cf8f12a..52f9a39da 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts @@ -87,7 +87,6 @@ window.addEventListener('load', () => { } myPort.addEventListener('message', e => { - console.log(e.data.type); if (e.data.type == BrowserTypes.FDC3_USER_INTERFACE_HANDSHAKE_TYPE) { // ok, port is ready, send the iframe position detials myPort.postMessage({ diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts index 5caac467e..630df0256 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts @@ -5,6 +5,7 @@ import { DefaultFDC3Server } from '../../src/BasicFDC3Server'; import { BasicDirectory } from '../../src/directory/BasicDirectory'; import { ChannelType } from '../../src/handlers/BroadcastHandler'; import { Context } from '@kite9/fdc3-context'; +import { AppIdentifier } from '@kite9/fdc3-standard'; export const APP_FIELD = 'apps'; @@ -79,7 +80,7 @@ function defaultChannels() { } export function createMeta(cw: CustomWorld, appStr: string) { - let app; + let app: AppIdentifier; if (appStr.includes('/')) { const [appId, instanceId] = appStr.split('/'); app = { appId, instanceId }; From 455b20544b17070c894db2b781e6d6f1c5614846 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 2 Jan 2025 17:56:04 +0000 Subject: [PATCH 70/90] some lint and logging --- .../src/ui/AbstractUIComponent.ts | 7 ++++++- .../fdc3-for-web/demo/src/client/da/embed.ts | 4 ++-- .../demo/src/client/ui/channel-selector.ts | 18 +++++++++--------- .../reference-ui/src/channel_selector.ts | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index dd3288c46..f7511ccf4 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -110,7 +110,12 @@ export abstract class AbstractUIComponent implements Connectable { Logger.debug('AbstractUIComponent: ignored UI Message from UI iframe while awaiting hello: ', e.data); } } else { - Logger.debug("AbstractUIComponent: ignored Message that didn't come from expected UI frame\n", e.data); + Logger.debug( + "AbstractUIComponent: ignored Message that didn't come from expected UI frame\nmessage: ", + e.data, + 'my URL: ', + this.url + ); } }; diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index fcd67d0c7..7f144f0d9 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -37,8 +37,8 @@ const helloListener = (e: MessageEvent) => { let eventSourceName; try { eventSourceName = (eventSource as Window)?.name; - } catch (e) { - eventSourceName = '{a cross-origin window} '; + } catch (e: unknown) { + eventSourceName = `{a cross-origin window: ${(e as Error).message ?? e}} `; } if (!eventSourceName) { eventSourceName = '{no window name set} '; diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts index 52f9a39da..f55512fec 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts @@ -1,9 +1,9 @@ import { BrowserTypes } from '@kite9/fdc3-schema'; import { dragElement } from './drag'; -import { Fdc3UserInterfaceRestyle } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { Channel, Fdc3UserInterfaceRestyle } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; // TODO: Update typings -let channels: any[] = []; +let channels: Channel[] = []; let channelId: string | null = null; export const DEFAULT_COLLAPSED_CSS = { @@ -38,11 +38,11 @@ const position: Position = { window.addEventListener('load', () => { const parent = window.parent; - const logo = document.getElementById('logo')!!; - const close = document.getElementById('close')!!; - const drag = document.getElementById('drag')!!; - const selector = document.getElementById('selector')!!; - const list = document.getElementById('channel-list')!!; + const logo = document.getElementById('logo')!; + const close = document.getElementById('close')!; + const drag = document.getElementById('drag')!; + const selector = document.getElementById('selector')!; + const list = document.getElementById('channel-list')!; const mc = new MessageChannel(); const myPort = mc.port1; @@ -113,9 +113,9 @@ window.addEventListener('load', () => { list.innerHTML = ''; channels.forEach(channel => { const li = document.createElement('div'); - li.style.backgroundColor = channel.displayMetadata.color; + li.style.backgroundColor = channel.displayMetadata!.color!; const description = document.createElement('em'); - description.textContent = channel.displayMetadata.name = channel.id == channelId ? ' CURRENT CHANNEL ' : ''; + description.textContent = channel.displayMetadata!.name = channel.id == channelId ? ' CURRENT CHANNEL ' : ''; li.textContent = channel.id; li.appendChild(description); diff --git a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts index b58a5115d..b22a521b5 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts @@ -7,7 +7,7 @@ import { } from '@kite9/fdc3-schema/dist/generated/api/BrowserTypes'; const fillChannels = (data: Channel[], selected: string | null, messageClickedChannel: (s: string | null) => void) => { - const list = document.getElementById('list')!!; + const list = document.getElementById('list')!; list.innerHTML = ''; data.forEach(({ id, displayMetadata }) => { From 5312abb20dcdb5540944b457d4ff421550761b14 Mon Sep 17 00:00:00 2001 From: Kris West Date: Tue, 7 Jan 2025 15:27:29 +0000 Subject: [PATCH 71/90] cleanup package-lock --- package-lock.json | 354 ++-------------------------------------------- 1 file changed, 15 insertions(+), 339 deletions(-) diff --git a/package-lock.json b/package-lock.json index c73cc6eb3..2acfa9150 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16822,345 +16822,6 @@ "uuid": "^9.0.1" } }, - "packages/fdc3-agent-proxy/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "packages/fdc3-agent-proxy/node_modules/cliui": { - "version": "6.0.0", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "packages/fdc3-agent-proxy/node_modules/color-convert": { - "version": "2.0.1", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "packages/fdc3-agent-proxy/node_modules/color-name": { - "version": "1.1.4", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/convert-source-map": { - "version": "1.9.0", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/find-up": { - "version": "4.1.0", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/foreground-child": { - "version": "2.0.0", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "packages/fdc3-agent-proxy/node_modules/glob": { - "version": "7.2.3", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/fdc3-agent-proxy/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/locate-path": { - "version": "5.0.0", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/make-dir": { - "version": "3.1.0", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/fdc3-agent-proxy/node_modules/nyc": { - "version": "15.1.0", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "packages/fdc3-agent-proxy/node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/fdc3-agent-proxy/node_modules/p-limit": { - "version": "2.3.0", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/fdc3-agent-proxy/node_modules/p-locate": { - "version": "4.1.0", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/prettier": { - "version": "3.2.5", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "packages/fdc3-agent-proxy/node_modules/resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/semver": { - "version": "6.3.1", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "packages/fdc3-agent-proxy/node_modules/signal-exit": { - "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/wrap-ansi": { - "version": "6.2.0", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/y18n": { - "version": "4.0.3", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "packages/fdc3-agent-proxy/node_modules/yargs": { - "version": "15.4.1", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "packages/fdc3-agent-proxy/node_modules/yargs-parser": { - "version": "18.1.3", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "packages/fdc3-commonjs": { - "version": "2.2.0-beta.29", - "license": "Apache-2.0", - "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.1", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.3.0", - "@rollup/plugin-typescript": "^12.1.1", - "rollup": "^4.27.4" - } - }, - "packages/fdc3-context": { - "name": "@kite9/fdc3-context", - "version": "2.2.0-beta.29", - "license": "Apache-2.0", - "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.12.0", - "@types/jest": "29.5.13", - "@typescript-eslint/eslint-plugin": "8.9.0", - "@typescript-eslint/parser": "8.9.0", - "eslint": "9.12.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-jest": "28.8.3", - "eslint-plugin-jsx-a11y": "^6.10.0", - "globals": "^15.11.0", - "mkdirp": "^3.0.1", - "quicktype": "23.0.78", - "rimraf": "^6.0.1", - "ts-jest": "29.2.5", - "tslib": "^2.7.0", - "typescript": "~5.5.0" - } - }, - "packages/fdc3-context/node_modules/@eslint/js": { - "version": "9.12.0", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "packages/fdc3-agent-proxy/node_modules/@humanwhocodes/retry": { "version": "0.4.1", "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", @@ -17497,6 +17158,21 @@ "node": ">=10" } }, + "packages/fdc3-commonjs": { + "name": "@kite9/fdc3-commonjs", + "version": "2.2.0-beta.29", + "license": "Apache-2.0", + "dependencies": { + "@kite9/fdc3": "2.2.0-beta.29" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^28.0.1", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-typescript": "^12.1.1", + "rollup": "^4.27.4" + } + }, "packages/fdc3-context": { "name": "@kite9/fdc3-context", "version": "2.2.0-beta.29", From 31c07817779098cf3bda1aa7e89d02fc2adfdbb7 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 8 Jan 2025 15:42:46 +0000 Subject: [PATCH 72/90] Better validation of addContextListener args and testing of error on invalid args --- .../fdc3-agent-proxy/src/DesktopAgentProxy.ts | 25 ++++++++++++++++--- .../src/channels/DefaultChannel.ts | 5 ++-- .../src/channels/DefaultChannelSupport.ts | 2 +- .../test/features/app-channels.feature | 10 ++++++-- .../test/features/user-channels.feature | 7 ++++++ packages/testing/src/steps/generic.steps.ts | 4 +++ 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts b/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts index 3ea7aae71..4b1a39d22 100644 --- a/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts +++ b/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts @@ -65,9 +65,28 @@ export class DesktopAgentProxy implements DesktopAgent, Connectable { } } - addContextListener(context: ContextHandler | string | null, handler?: ContextHandler): Promise { - const theHandler: ContextHandler = handler ? handler : (context as ContextHandler); - const theContextType: string | null = context && handler ? (context as string) : null; + addContextListener( + contextTypeOrHandler: ContextHandler | string | null, + handler?: ContextHandler + ): Promise { + let theContextType: string | null; + let theHandler: ContextHandler; + + if (contextTypeOrHandler == null && typeof handler === 'function') { + theContextType = null; + theHandler = handler; + } else if (typeof contextTypeOrHandler === 'string' && typeof handler === 'function') { + theContextType = contextTypeOrHandler; + theHandler = handler; + } else if (typeof contextTypeOrHandler === 'function') { + // deprecated one-arg version + theContextType = null; + theHandler = contextTypeOrHandler as ContextHandler; + } else { + //invalid call + throw new Error('Invalid arguments passed to addContextListener!'); + } + return this.channels.addContextListener(theHandler, theContextType); } diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index 701486e8d..7ec11f7e2 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -56,11 +56,10 @@ export class DefaultChannel implements Channel { let theContextType: string | null; let theHandler: ContextHandler; - /* istanbul ignore else */ - if (contextTypeOrHandler == null && handler) { + if (contextTypeOrHandler == null && typeof handler === 'function') { theContextType = null; theHandler = handler; - } else if (typeof contextTypeOrHandler === 'string' && handler) { + } else if (typeof contextTypeOrHandler === 'string' && typeof handler === 'function') { theContextType = contextTypeOrHandler; theHandler = handler; } else if (typeof contextTypeOrHandler === 'function') { diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts index d09033bcb..ba64c2879 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannelSupport.ts @@ -40,7 +40,7 @@ export class DefaultChannelSupport implements ChannelSupport { this.messaging = messaging; this.channelSelector = channelSelector; this.channelSelector.setChannelChangeCallback((channelId: string | null) => { - console.log('CHANNEL SELECTOR CALLBACK!'); + console.debug('Channel selector reports channel changed: ' + channelId); if (channelId == null) { this.leaveUserChannel(); } else { diff --git a/packages/fdc3-agent-proxy/test/features/app-channels.feature b/packages/fdc3-agent-proxy/test/features/app-channels.feature index 658c96ec6..ed110e781 100644 --- a/packages/fdc3-agent-proxy/test/features/app-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/app-channels.feature @@ -40,7 +40,6 @@ Feature: Channel Listeners Support Scenario: I can create a listener which listens for any context type In this version we are using the deprecated 1-arg approach - When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name" And I refer to "{result}" as "channel1" And I call "{channel1}" with "addContextListener" with parameter "{resultHandler}" @@ -57,7 +56,6 @@ Feature: Channel Listeners Support Scenario: I can create a listener which listens for any context type In this version we are using the non-deprecated 2 args approach - When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name" And I refer to "{result}" as "channel1" And I call "{channel1}" with "addContextListener" with parameters "{null}" and "{resultHandler}" @@ -71,3 +69,11 @@ Feature: Channel Listeners Support | payload.channelId | payload.contextType | matches_type | | channel-name | {null} | getOrCreateChannelRequest | | channel-name | {null} | addContextListenerRequest | + + Scenario: Passing invalid arguments to an app channel's addContextListener fn throws an error + When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name" + And I refer to "{result}" as "channel1" + And I call "{channel1}" with "addContextListener" with parameters "{true}" and "{resultHandler}" + Then "{result}" is an error + And I call "{channel1}" with "addContextListener" with parameters "{null}" and "{true}" + Then "{result}" is an error \ No newline at end of file diff --git a/packages/fdc3-agent-proxy/test/features/user-channels.feature b/packages/fdc3-agent-proxy/test/features/user-channels.feature index 8eb5f5b2f..f3584389b 100644 --- a/packages/fdc3-agent-proxy/test/features/user-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/user-channels.feature @@ -161,6 +161,13 @@ Feature: Basic User Channels Support When I call "{api}" with "joinUserChannel" with parameter "nonexistent" Then "{result}" is an error with message "NoChannelFound" + Scenario: Passing invalid arguments to a user channel's addContextListener fn throws an error + Given "resultHandler" pipes context to "contexts" + When I call "{api}" with "addContextListener" with parameters "{true}" and "{resultHandler}" + Then "{result}" is an error + And I call "{api}" with "addContextListener" with parameters "{null}" and "{true}" + Then "{result}" is an error + Scenario: You can get the details of the last context type sent Given "resultHandler" pipes context to "contexts" When I call "{api}" with "joinUserChannel" with parameter "one" diff --git a/packages/testing/src/steps/generic.steps.ts b/packages/testing/src/steps/generic.steps.ts index a27edcf5f..957758c26 100644 --- a/packages/testing/src/steps/generic.steps.ts +++ b/packages/testing/src/steps/generic.steps.ts @@ -161,6 +161,10 @@ export function setupGenericSteps() { expect(handleResolve(field, this)['message']).toBe(errorType); }); + Then('{string} is an error', function (this: PropsWorld, field: string) { + expect(handleResolve(field, this)).toBeInstanceOf(Error); + }); + Given( '{string} is a invocation counter into {string}', function (this: PropsWorld, handlerName: string, field: string) { From 50a47317670fd7d70c63c9253f16078f888b0756 Mon Sep 17 00:00:00 2001 From: Kris West Date: Wed, 8 Jan 2025 18:47:13 +0000 Subject: [PATCH 73/90] Revert to importing all of BrowserTypes as CommonJS compile doesn't like them --- .../listeners/PrivateChannelEventListener.ts | 19 ++++++++++--------- .../src/strategies/HelloHandler.ts | 10 ++++------ .../strategies/IdentityValidationHandler.ts | 17 ++++++++++------- .../src/ui/AbstractUIComponent.ts | 12 +++++------- .../ui/DefaultDesktopAgentChannelSelector.ts | 7 +++---- .../ui/DefaultDesktopAgentIntentResolver.ts | 7 +++---- 6 files changed, 35 insertions(+), 37 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts index 36be45630..0f7542c51 100644 --- a/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts +++ b/packages/fdc3-agent-proxy/src/listeners/PrivateChannelEventListener.ts @@ -1,12 +1,3 @@ -import { - isPrivateChannelOnAddContextListenerEvent, - isPrivateChannelOnDisconnectEvent, - isPrivateChannelOnUnsubscribeEvent, - PrivateChannelAddEventListenerRequest, - PrivateChannelOnAddContextListenerEvent, - PrivateChannelOnDisconnectEvent, - PrivateChannelOnUnsubscribeEvent, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Messaging } from '../Messaging'; import { AbstractListener } from './AbstractListener'; import { @@ -18,6 +9,16 @@ import { PrivateChannelEventTypes, PrivateChannelUnsubscribeEvent, } from '@kite9/fdc3-standard'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +const { + isPrivateChannelOnAddContextListenerEvent, + isPrivateChannelOnDisconnectEvent, + isPrivateChannelOnUnsubscribeEvent, +} = BrowserTypes; +type PrivateChannelAddEventListenerRequest = BrowserTypes.PrivateChannelAddEventListenerRequest; +type PrivateChannelOnAddContextListenerEvent = BrowserTypes.PrivateChannelOnAddContextListenerEvent; +type PrivateChannelOnDisconnectEvent = BrowserTypes.PrivateChannelOnDisconnectEvent; +type PrivateChannelOnUnsubscribeEvent = BrowserTypes.PrivateChannelOnUnsubscribeEvent; type PrivateChannelEventMessages = | PrivateChannelOnAddContextListenerEvent diff --git a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts index 940de4bb8..4c778ae55 100644 --- a/packages/fdc3-get-agent/src/strategies/HelloHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/HelloHandler.ts @@ -1,12 +1,10 @@ -import { - WebConnectionProtocolMessage, - WebConnectionProtocol1Hello, - isWebConnectionProtocol2LoadURL, - isWebConnectionProtocol3Handshake, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { FDC3_VERSION, GetAgentParams, WebDesktopAgentType } from '@kite9/fdc3-standard'; import { ConnectionDetails } from '../messaging/MessagePortMessaging'; import { Logger } from '../util/Logger'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +const { isWebConnectionProtocol2LoadURL, isWebConnectionProtocol3Handshake } = BrowserTypes; +type WebConnectionProtocolMessage = BrowserTypes.WebConnectionProtocolMessage; +type WebConnectionProtocol1Hello = BrowserTypes.WebConnectionProtocol1Hello; export class HelloHandler { constructor( diff --git a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts index 8659ea152..c6b7b5325 100644 --- a/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts +++ b/packages/fdc3-get-agent/src/strategies/IdentityValidationHandler.ts @@ -1,14 +1,17 @@ -import { - WebConnectionProtocol4ValidateAppIdentity, - WebConnectionProtocol5ValidateAppIdentitySuccessResponse, - WebConnectionProtocolMessage, - isWebConnectionProtocol5ValidateAppIdentitySuccessResponse, - isWebConnectionProtocol5ValidateAppIdentityFailedResponse, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { GetAgentParams, AgentError } from '@kite9/fdc3-standard'; import { retrieveDesktopAgentDetails } from '../sessionStorage/DesktopAgentDetails'; import { Logger } from '../util/Logger'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +const { + isWebConnectionProtocol5ValidateAppIdentitySuccessResponse, + isWebConnectionProtocol5ValidateAppIdentityFailedResponse, +} = BrowserTypes; +type WebConnectionProtocol4ValidateAppIdentity = BrowserTypes.WebConnectionProtocol4ValidateAppIdentity; +type WebConnectionProtocol5ValidateAppIdentitySuccessResponse = + BrowserTypes.WebConnectionProtocol5ValidateAppIdentitySuccessResponse; +type WebConnectionProtocolMessage = BrowserTypes.WebConnectionProtocolMessage; + /** Timeout allowed for id validation to occur and for the DA to respond with details. * This is additional to the app's specified timeout for discovery - we have already * found an agent at that point we are just finishing setting up the connection. */ diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index f7511ccf4..0b8a27f54 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -1,12 +1,10 @@ -import { - Fdc3UserInterfaceHandshake, - InitialCSS, - isFdc3UserInterfaceHello, - isFdc3UserInterfaceRestyle, - UpdatedCSS, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Connectable, FDC3_VERSION } from '@kite9/fdc3-standard'; import { Logger } from '../util/Logger'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +const { isFdc3UserInterfaceHello, isFdc3UserInterfaceRestyle } = BrowserTypes; +type Fdc3UserInterfaceHandshake = BrowserTypes.Fdc3UserInterfaceHandshake; +type InitialCSS = BrowserTypes.InitialCSS; +type UpdatedCSS = BrowserTypes.UpdatedCSS; export interface CSSPositioning { [key: string]: string; diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts index 2a2f729aa..ac77f545a 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts @@ -1,10 +1,9 @@ import { Channel } from '@kite9/fdc3-standard'; import { ChannelSelector } from '@kite9/fdc3-standard'; import { AbstractUIComponent } from './AbstractUIComponent'; -import { - Fdc3UserInterfaceChannels, - isFdc3UserInterfaceChannelSelected, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +const { isFdc3UserInterfaceChannelSelected } = BrowserTypes; +type Fdc3UserInterfaceChannels = BrowserTypes.Fdc3UserInterfaceChannels; /** * Works with the desktop agent to provide a simple channel selector. diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts index 8d3c3b35a..47d76412f 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts @@ -2,11 +2,10 @@ import { AppIntent } from '@kite9/fdc3-standard'; import { IntentResolver, IntentResolutionChoice } from '@kite9/fdc3-standard'; import { AbstractUIComponent } from './AbstractUIComponent'; import { Context } from '@kite9/fdc3-context'; -import { - Fdc3UserInterfaceResolve, - isFdc3UserInterfaceResolveAction, -} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { Logger } from '../util/Logger'; +import { BrowserTypes } from '@kite9/fdc3-schema'; +const { isFdc3UserInterfaceResolveAction } = BrowserTypes; +type Fdc3UserInterfaceResolve = BrowserTypes.Fdc3UserInterfaceResolve; /** * Works with the desktop agent to provide a resolution to the intent choices. From d248137f8ea633f600108fda70a4a861c1a70a81 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 9 Jan 2025 13:16:27 +0000 Subject: [PATCH 74/90] Addressing review comments including using appState.terminated for past connections --- packages/fdc3-get-agent/src/util/Logger.ts | 2 +- .../test/support/MockFDC3Server.ts | 5 +- .../test/support/TestServerContext.ts | 20 +- .../fdc3-schema/generated/api/BrowserTypes.ts | 5316 ++++++++--------- .../demo/src/client/da/DemoServerContext.ts | 104 +- .../fdc3-for-web/demo/src/client/da/util.ts | 1 + .../fdc3-web-impl/src/BasicFDC3Server.ts | 4 +- .../fdc3-web-impl/src/ServerContext.ts | 21 +- .../src/handlers/IntentHandler.ts | 11 +- .../fdc3-web-impl/src/handlers/OpenHandler.ts | 12 +- .../test/support/TestServerContext.ts | 19 +- 11 files changed, 2753 insertions(+), 2762 deletions(-) diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 761d99425..f20d7d89b 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import pc from 'picocolors'; +import * as pc from 'picocolors'; const GET_AGENT_LOG_PREFIX = 'FDC3 getAgent: '; diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index 2f9fa1f80..b95dfe52d 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -1,4 +1,4 @@ -import { FDC3Server, InstanceID } from '@kite9/fdc3-web-impl'; +import { FDC3Server, InstanceID, State } from '@kite9/fdc3-web-impl'; import { TestServerContext } from './TestServerContext'; import { MockWindow } from './MockWindow'; import { AutomaticResponse } from './responses/AutomaticResponses'; @@ -53,7 +53,8 @@ export class MockFDC3Server implements FDC3Server { } cleanup(instanceId: InstanceID): void { - this.tsc.goodbye(instanceId); + //message handler are faked with automated responses, so no need to clean up their state + this.tsc.setAppState(instanceId, State.Terminated); } receive(message: AppRequestMessage, from: string): void { diff --git a/packages/fdc3-get-agent/test/support/TestServerContext.ts b/packages/fdc3-get-agent/test/support/TestServerContext.ts index 51eecbf04..f55bb4548 100644 --- a/packages/fdc3-get-agent/test/support/TestServerContext.ts +++ b/packages/fdc3-get-agent/test/support/TestServerContext.ts @@ -1,4 +1,4 @@ -import { ServerContext, InstanceID } from '@kite9/fdc3-web-impl'; +import { ServerContext, InstanceID, FDC3Server } from '@kite9/fdc3-web-impl'; import { CustomWorld } from '../world'; import { OpenError, AppIdentifier, AppIntent } from '@kite9/fdc3-standard'; import { AppRegistration, State } from '@kite9/fdc3-web-impl'; @@ -26,6 +26,7 @@ export class TestServerContext implements ServerContext { public postedMessages: MessageRecord[] = []; public readonly cw: CustomWorld; private instances: ConnectionDetails[] = []; + private server: FDC3Server | null = null; private nextInstanceId: number = 0; private nextUUID: number = 0; @@ -34,8 +35,8 @@ export class TestServerContext implements ServerContext { this.cw = cw; } - goodbye(instanceId: string): void { - this.instances = this.instances.filter(instance => instance.instanceId !== instanceId); + setFDC3Server(server: FDC3Server): void { + this.server = server; } async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[] /*, _context: Context*/): Promise { @@ -46,10 +47,6 @@ export class TestServerContext implements ServerContext { return this.instances.find(ca => ca.instanceId === uuid); } - getPastInstanceDetails(/*uuid: InstanceID*/): ConnectionDetails | undefined { - return; - } - setInstanceDetails(uuid: InstanceID, appId: ConnectionDetails) { this.instances = this.instances.filter(ca => ca.connectionId !== uuid); this.instances.push({ @@ -127,12 +124,17 @@ export class TestServerContext implements ServerContext { return found != null; } - async setAppState(app: InstanceID, state: State): Promise { + async setAppState(app: InstanceID, newState: State): Promise { const found = this.instances.find(a => a.instanceId == app); if (found) { - found.state = state; + const currentState = found.state; + if (currentState !== State.Terminated && newState === State.Terminated) { + this.server?.cleanup(app); + } + found.state = newState; } } + async getAllApps(): Promise { return this.instances.map(x => { return { diff --git a/packages/fdc3-schema/generated/api/BrowserTypes.ts b/packages/fdc3-schema/generated/api/BrowserTypes.ts index 50ed6d23a..7e2af2655 100644 --- a/packages/fdc3-schema/generated/api/BrowserTypes.ts +++ b/packages/fdc3-schema/generated/api/BrowserTypes.ts @@ -1,15 +1,7 @@ // To parse this data: // -// import { Convert, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceChannels, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse } from "./file"; +// import { Convert, AddContextListenerRequest, AddContextListenerResponse, AddEventListenerRequest, AddEventListenerResponse, AddIntentListenerRequest, AddIntentListenerResponse, AgentEventMessage, AgentResponseMessage, AppRequestMessage, BroadcastEvent, BroadcastRequest, BroadcastResponse, ChannelChangedEvent, ContextListenerUnsubscribeRequest, ContextListenerUnsubscribeResponse, CreatePrivateChannelRequest, CreatePrivateChannelResponse, EventListenerUnsubscribeRequest, EventListenerUnsubscribeResponse, Fdc3UserInterfaceChannels, Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceDrag, Fdc3UserInterfaceHandshake, Fdc3UserInterfaceHello, Fdc3UserInterfaceMessage, Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, FindInstancesRequest, FindInstancesResponse, FindIntentRequest, FindIntentResponse, FindIntentsByContextRequest, FindIntentsByContextResponse, GetAppMetadataRequest, GetAppMetadataResponse, GetCurrentChannelRequest, GetCurrentChannelResponse, GetCurrentContextRequest, GetCurrentContextResponse, GetInfoRequest, GetInfoResponse, GetOrCreateChannelRequest, GetOrCreateChannelResponse, GetUserChannelsRequest, GetUserChannelsResponse, HeartbeatAcknowledgementRequest, HeartbeatEvent, IntentEvent, IntentListenerUnsubscribeRequest, IntentListenerUnsubscribeResponse, IntentResultRequest, IntentResultResponse, JoinUserChannelRequest, JoinUserChannelResponse, LeaveCurrentChannelRequest, LeaveCurrentChannelResponse, OpenRequest, OpenResponse, PrivateChannelAddEventListenerRequest, PrivateChannelAddEventListenerResponse, PrivateChannelDisconnectRequest, PrivateChannelDisconnectResponse, PrivateChannelOnAddContextListenerEvent, PrivateChannelOnDisconnectEvent, PrivateChannelOnUnsubscribeEvent, PrivateChannelUnsubscribeEventListenerRequest, PrivateChannelUnsubscribeEventListenerResponse, RaiseIntentForContextRequest, RaiseIntentForContextResponse, RaiseIntentRequest, RaiseIntentResponse, RaiseIntentResultResponse, WebConnectionProtocol1Hello, WebConnectionProtocol2LoadURL, WebConnectionProtocol3Handshake, WebConnectionProtocol4ValidateAppIdentity, WebConnectionProtocol5ValidateAppIdentityFailedResponse, WebConnectionProtocol5ValidateAppIdentitySuccessResponse, WebConnectionProtocol6Goodbye, WebConnectionProtocolMessage } from "./file"; // -// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); -// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); -// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); -// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); -// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); -// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); -// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); -// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // const addContextListenerRequest = Convert.toAddContextListenerRequest(json); // const addContextListenerResponse = Convert.toAddContextListenerResponse(json); // const addEventListenerRequest = Convert.toAddEventListenerRequest(json); @@ -29,8 +21,8 @@ // const createPrivateChannelResponse = Convert.toCreatePrivateChannelResponse(json); // const eventListenerUnsubscribeRequest = Convert.toEventListenerUnsubscribeRequest(json); // const eventListenerUnsubscribeResponse = Convert.toEventListenerUnsubscribeResponse(json); -// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceChannels = Convert.toFdc3UserInterfaceChannels(json); +// const fdc3UserInterfaceChannelSelected = Convert.toFdc3UserInterfaceChannelSelected(json); // const fdc3UserInterfaceDrag = Convert.toFdc3UserInterfaceDrag(json); // const fdc3UserInterfaceHandshake = Convert.toFdc3UserInterfaceHandshake(json); // const fdc3UserInterfaceHello = Convert.toFdc3UserInterfaceHello(json); @@ -83,552 +75,960 @@ // const raiseIntentRequest = Convert.toRaiseIntentRequest(json); // const raiseIntentResponse = Convert.toRaiseIntentResponse(json); // const raiseIntentResultResponse = Convert.toRaiseIntentResultResponse(json); +// const webConnectionProtocol1Hello = Convert.toWebConnectionProtocol1Hello(json); +// const webConnectionProtocol2LoadURL = Convert.toWebConnectionProtocol2LoadURL(json); +// const webConnectionProtocol3Handshake = Convert.toWebConnectionProtocol3Handshake(json); +// const webConnectionProtocol4ValidateAppIdentity = Convert.toWebConnectionProtocol4ValidateAppIdentity(json); +// const webConnectionProtocol5ValidateAppIdentityFailedResponse = Convert.toWebConnectionProtocol5ValidateAppIdentityFailedResponse(json); +// const webConnectionProtocol5ValidateAppIdentitySuccessResponse = Convert.toWebConnectionProtocol5ValidateAppIdentitySuccessResponse(json); +// const webConnectionProtocol6Goodbye = Convert.toWebConnectionProtocol6Goodbye(json); +// const webConnectionProtocolMessage = Convert.toWebConnectionProtocolMessage(json); // // These functions will throw an error if the JSON doesn't // match the expected interface, even if the JSON is valid. /** - * Hello message sent by an application to a parent window or frame when attempting to - * establish connectivity to a Desktop Agent. + * A request to add a context listener to a specified Channel OR to the current user + * channel. Where the listener is added to the current user channel (channelId == null), and + * this app has already been added to a user channel, client code should make a subsequent + * request to get the current context of that channel for this listener and then call its + * handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1Hello { +export interface AddContextListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol1HelloPayload; + payload: AddContextListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'WCP1Hello'; + type: 'addContextListenerRequest'; } /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol1HelloMeta { - connectionAttemptUuid: string; +export interface AddContextListenerRequestMeta { + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + */ + source?: AppIdentifier; timestamp: Date; } /** - * The message payload, containing data pertaining to this connection step. + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. + * + * Identifies an application, or instance of an application, and is used to target FDC3 API + * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application + * instances. + * + * Will always include at least an `appId` field, which uniquely identifies a specific app. + * + * If the `instanceId` field is set then the `AppMetadata` object represents a specific + * instance of the application that may be addressed using that Id. + * + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. + * + * Details of the application instance that broadcast the context. + * + * The App resolution option chosen. + * + * Details of the application instance that raised the intent. + * + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. */ -export interface WebConnectionProtocol1HelloPayload { +export interface AppIdentifier { /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. */ - actualUrl: string; + appId: string; /** - * A flag that may be used to indicate that a channel selector user interface is or is not - * required. Set to `false` if the app includes its own interface for selecting channels or - * does not work with user channels. + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. */ - channelSelector?: boolean; + desktopAgent?: string; /** - * The version of FDC3 API that the app supports. + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. */ - fdc3Version: string; + instanceId?: string; + [property: string]: any; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface AddContextListenerRequestPayload { /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. + * The id of the channel to add the listener to or `null` indicating that it should listen + * to the current user channel (at the time of broadcast). */ - identityUrl: string; + channelId: null | string; /** - * A flag that may be used to indicate that an intent resolver is or is not required. Set to - * `false` if no intents, or only targeted intents, are raised. + * The type of context to listen for OR `null` indicating that it should listen to all + * context types. */ - intentResolver?: boolean; - [property: string]: any; + contextType: null | string; } /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Response from a Desktop Agent to an application requesting access to it indicating that - * it should load a specified URL into a hidden iframe in order to establish connectivity to - * a Desktop Agent. + * A response to a addContextListener request. Where the listener was added to the current + * user channel (channelId == null), and this app has already been added to a user channel, + * client code should make a subsequent request to get the current context of that channel + * for this listener and then call its handler with it. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol2LoadURL { +export interface AddContextListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: WebConnectionProtocol2LoadURLPayload; + payload: AddContextListenerResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP2LoadUrl'; + type: 'addContextListenerResponse'; } /** - * The message payload, containing data pertaining to this connection step. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ -export interface WebConnectionProtocol2LoadURLPayload { +export interface AddContextListenerResponseMeta { + requestUuid: string; + responseUuid: string; /** - * A URL which can be used to establish communication with the Desktop Agent, via loading - * the URL into an iframe and restarting the Web Connection protocol with the iframe as the - * target. + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. */ - iframeUrl: string; - [property: string]: any; + source?: AppIdentifier; + timestamp: Date; } /** - * Identifies the type of the connection step message. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ +export interface AddContextListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; +} /** - * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that - * should be used for subsequent communication steps. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface WebConnectionProtocol3Handshake { +export type PurpleError = 'AccessDenied' | 'CreationFailed' | 'MalformedContext' | 'NoChannelFound'; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to add an event listener for a specified event type to the Desktop Agent. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface AddEventListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol3HandshakePayload; + payload: AddEventListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'WCP3Handshake'; + type: 'addEventListenerRequest'; } /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface WebConnectionProtocol3HandshakePayload { - /** - * Indicates whether a channel selector user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the channel selector (as the - * Desktop Agent will handle it another way). - */ - channelSelectorUrl: boolean | string; - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; +export interface AddEventListenerRequestPayload { /** - * Indicates whether an intent resolver user interface is required and the URL to use to do - * so. Set to `true` to use the default or `false` to disable the intent resolver (as the - * Desktop Agent will handle it another way). + * The type of the event to be listened to or `null` to listen to all event types. */ - intentResolverUrl: boolean | string; + type: 'USER_CHANNEL_CHANGED' | null; } /** - * Identifies the type of the connection step message. + * The type of a (non-context and non-intent) event that may be received via the FDC3 API's + * addEventListener function. */ /** - * Identity Validation request from an app attempting to connect to a Desktop Agent. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to an addEventListener request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol4ValidateAppIdentity { +export interface AddEventListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. - */ - payload: WebConnectionProtocol4ValidateAppIdentityPayload; + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: AddEventListenerResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP4ValidateAppIdentity'; + type: 'addEventListenerResponse'; } /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface WebConnectionProtocol4ValidateAppIdentityPayload { - /** - * The current URL of the page attempting to connect. This may differ from the identityUrl, - * but the origins MUST match. - */ - actualUrl: string; - /** - * URL to use for the identity of the application. Desktop Agents MUST validate that the - * origin of the message matches the URL, but MAY implement custom comparison logic. - */ - identityUrl: string; - /** - * If an application has previously connected to the Desktop Agent, it may specify its prior - * instance id and associated instance UUID to request the same same instance Id be assigned. - */ - instanceId?: string; - /** - * Instance UUID associated with the requested instanceId. - */ - instanceUuid?: string; +export interface AddEventListenerResponsePayload { + error?: ResponsePayloadError; + listenerUUID?: string; } /** - * Identifies the type of the connection step message. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + */ +export type ResponsePayloadError = + | 'AccessDenied' + | 'CreationFailed' + | 'MalformedContext' + | 'NoChannelFound' + | 'AppNotFound' + | 'AppTimeout' + | 'DesktopAgentNotFound' + | 'ErrorOnLaunch' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution' + | 'IntentHandlerRejected' + | 'NoResultReturned' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message sent by the Desktop Agent to an app if their identity validation fails. + * A request to add an Intent listener for a specified intent type. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { +export interface AddIntentListenerRequest { /** - * Metadata for a Web Connection Protocol message. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerRequestMeta; /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ - payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; + payload: AddIntentListenerRequestPayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'WCP5ValidateAppIdentityFailedResponse'; + type: 'addIntentListenerRequest'; } /** - * The message payload, containing data pertaining to this connection step. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { - message?: string; +export interface AddIntentListenerRequestPayload { + /** + * The name of the intent to listen for. + */ + intent: string; } /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Message sent by the Desktop Agent to an app after successful identity validation. + * A response to a addIntentListener request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { +export interface AddIntentListenerResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol1HelloMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; + payload: PayloadObject; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP5ValidateAppIdentityResponse'; + type: 'addIntentListenerResponse'; } /** - * The message payload, containing data pertaining to this connection step. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { - /** - * The appId that the app's identity was validated against. - */ - appId: string; - /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - */ - implementationMetadata: ImplementationMetadata; - /** - * The instance Id granted to the application by the Desktop Agent. - */ - instanceId: string; - /** - * Instance UUID associated with the instanceId granted, which may be used to retrieve the - * same instanceId if the app is reloaded or navigates. - */ - instanceUuid: string; +export interface PayloadObject { + error?: FluffyError; + listenerUUID?: string; + [property: string]: any; } /** - * Implementation metadata for the Desktop Agent, which includes an appMetadata element - * containing a copy of the app's own metadata. - * - * Includes Metadata for the current application. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * Metadata relating to the FDC3 Desktop Agent implementation and its provider. + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface ImplementationMetadata { - /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - */ - appMetadata: AppMetadata; - /** - * The version number of the FDC3 specification that the implementation provides. - * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. - */ - fdc3Version: string; - /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. - */ - optionalFeatures: OptionalFeatures; - /** - * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, - * OpenFin etc.). - */ - provider: string; - /** - * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). - */ - providerVersion?: string; +export type FluffyError = + | 'MalformedContext' + | 'DesktopAgentNotFound' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution'; + +/** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ +export interface AgentEventMessageMeta { + eventUuid: string; + timestamp: Date; } /** - * The calling application instance's own metadata, according to the Desktop Agent (MUST - * include at least the `appId` and `instanceId`). - * - * Extends an `AppIdentifier`, describing an application or instance of an application, with - * additional descriptive metadata that is usually provided by an FDC3 App Directory that - * the Desktop Agent connects to. - * - * The additional information from an app directory can aid in rendering UI elements, such - * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon - * and screenshot URLs. - * - * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the - * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export interface AppMetadata { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * A longer, multi-paragraph description for the application that could include markup. - */ - description?: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; +export type EventMessageType = + | 'addEventListenerEvent' + | 'broadcastEvent' + | 'channelChangedEvent' + | 'heartbeatEvent' + | 'intentEvent' + | 'privateChannelOnAddContextListenerEvent' + | 'privateChannelOnDisconnectEvent' + | 'privateChannelOnUnsubscribeEvent'; + +/** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ +export interface AgentResponseMessageMeta { + requestUuid: string; + responseUuid: string; /** - * A list of icon URLs for the application that can be used to render UI elements. + * Field that represents the source application that the request being responded to was + * received from, for debugging purposes. */ - icons?: Icon[]; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. + source?: AppIdentifier; + timestamp: Date; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface AgentResponseMessageResponsePayload { + error?: ResponsePayloadError; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ +export type ResponseMessageType = + | 'addContextListenerResponse' + | 'addEventListenerResponse' + | 'addIntentListenerResponse' + | 'broadcastResponse' + | 'contextListenerUnsubscribeResponse' + | 'createPrivateChannelResponse' + | 'eventListenerUnsubscribeResponse' + | 'findInstancesResponse' + | 'findIntentResponse' + | 'findIntentsByContextResponse' + | 'getAppMetadataResponse' + | 'getCurrentChannelResponse' + | 'getCurrentContextResponse' + | 'getInfoResponse' + | 'getOrCreateChannelResponse' + | 'getUserChannelsResponse' + | 'intentListenerUnsubscribeResponse' + | 'intentResultResponse' + | 'joinUserChannelResponse' + | 'leaveCurrentChannelResponse' + | 'openResponse' + | 'privateChannelAddEventListenerResponse' + | 'privateChannelDisconnectResponse' + | 'privateChannelUnsubscribeEventListenerResponse' + | 'raiseIntentForContextResponse' + | 'raiseIntentResponse' + | 'raiseIntentResultResponse'; + +/** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ +export interface AppRequestMessageMeta { + requestUuid: string; + /** + * Field that represents the source application that a request or response was received + * from. Please note that this may be set by an app or Desktop Agent proxy for debugging + * purposes but a Desktop Agent should make its own determination of the source of a message + * to avoid spoofing. */ - instanceId?: string; + source?: AppIdentifier; + timestamp: Date; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ +export type RequestMessageType = + | 'addContextListenerRequest' + | 'addEventListenerRequest' + | 'addIntentListenerRequest' + | 'broadcastRequest' + | 'contextListenerUnsubscribeRequest' + | 'createPrivateChannelRequest' + | 'eventListenerUnsubscribeRequest' + | 'findInstancesRequest' + | 'findIntentRequest' + | 'findIntentsByContextRequest' + | 'getAppMetadataRequest' + | 'getCurrentChannelRequest' + | 'getCurrentContextRequest' + | 'getInfoRequest' + | 'getOrCreateChannelRequest' + | 'getUserChannelsRequest' + | 'heartbeatAcknowledgementRequest' + | 'intentListenerUnsubscribeRequest' + | 'intentResultRequest' + | 'joinUserChannelRequest' + | 'leaveCurrentChannelRequest' + | 'openRequest' + | 'privateChannelAddEventListenerRequest' + | 'privateChannelDisconnectRequest' + | 'privateChannelUnsubscribeEventListenerRequest' + | 'raiseIntentForContextRequest' + | 'raiseIntentRequest'; + +/** + * An event message from the Desktop Agent to an app indicating that context has been + * broadcast on a channel it is listening to, or specifically to this app instance if it was + * launched via `fdc3.open` and context was passed. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface BroadcastEvent { /** - * An optional set of, implementation specific, metadata fields that can be used to - * disambiguate instances, such as a window title or screen position. Must only be set if - * `instanceId` is set. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - instanceMetadata?: { [key: string]: any }; + meta: BroadcastEventMeta; /** - * The 'friendly' app name. - * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now - * require an `AppIdentifier` wth `appId` set. - * Note that for display purposes the `title` field should be used, if set, in preference to - * this field. + * The message payload contains details of the event that the app is being notified about. + */ + payload: BroadcastEventPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'broadcastEvent'; +} + +/** + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + */ +export interface BroadcastEventMeta { + eventUuid: string; + timestamp: Date; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface BroadcastEventPayload { + /** + * The Id of the channel that the broadcast was sent on. May be `null` if the context is + * being broadcast due to a call `fdc3.open` that passed context. + */ + channelId: null | string; + /** + * The context object that was broadcast. + */ + context: Context; + /** + * Details of the application instance that broadcast the context. + */ + originatingApp?: AppIdentifier; +} + +/** + * The context object that was broadcast. + * + * The context object that is to be broadcast. + * + * The context object passed with the raised intent. + * + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. + * + * The `fdc3.context` type defines the basic contract or "shape" for all data exchanged by + * FDC3 operations. As such, it is not really meant to be used on its own, but is imported + * by more specific type definitions (standardized or custom) to provide the structure and + * properties shared by all FDC3 context data types. + * + * The key element of FDC3 context types is their mandatory `type` property, which is used + * to identify what type of data the object represents, and what shape it has. + * + * The FDC3 context type, and all derived types, define the minimum set of fields a context + * data object of a particular type can be expected to have, but this can always be extended + * with custom fields as appropriate. + */ +export interface Context { + /** + * Context data objects may include a set of equivalent key-value pairs that can be used to + * help applications identify and look up the context type they receive in their own domain. + * The idea behind this design is that applications can provide as many equivalent + * identifiers to a target application as possible, e.g. an instrument may be represented by + * an ISIN, CUSIP or Bloomberg identifier. + * + * Identifiers do not make sense for all types of data, so the `id` property is therefore + * optional, but some derived types may choose to require at least one identifier. + * Identifier values SHOULD always be of type string. + */ + id?: { [key: string]: any }; + /** + * Context data objects may include a name property that can be used for more information, + * or display purposes. Some derived types may require the name object as mandatory, + * depending on use case. */ name?: string; /** - * The type of output returned for any intent specified during resolution. May express a - * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel - * that will receive a specified type (e.g. "channel"). + * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 + * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present + * to route shared context data appropriately. + * + * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data + * types they support in an FDC3 [App + * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery + * and routing. + * + * Standardized FDC3 context types have well-known `type` properties prefixed with the + * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and + * used by a particular organization, the convention is to prefix them with an + * organization-specific namespace, e.g. `blackrock.fund`. + * + * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more + * information about context data types. */ - resultType?: null | string; + type: string; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * A request to broadcast context on a channel. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface BroadcastRequest { /** - * Images representing the app in common usage scenarios that can be used to render UI - * elements. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - screenshots?: Image[]; + meta: AddContextListenerRequestMeta; /** - * A more user-friendly application title that can be used to render UI elements. + * The message payload typically contains the arguments to FDC3 API functions. */ - title?: string; + payload: BroadcastRequestPayload; /** - * A tooltip for the application that can be used to render UI elements. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - tooltip?: string; + type: 'broadcastRequest'; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface BroadcastRequestPayload { /** - * The Version of the application. + * The Id of the Channel that the broadcast was sent on. */ - version?: string; + channelId: string; + /** + * The context object that is to be broadcast. + */ + context: Context; } /** - * Describes an Icon image that may be used to represent the application. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export interface Icon { + +/** + * A response to a request to broadcast context on a channel. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface BroadcastResponse { /** - * The icon dimension, formatted as `x`. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - size?: string; + meta: AddContextListenerResponseMeta; /** - * The icon url. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - src: string; + payload: BroadcastResponseResponsePayload; /** - * Icon media type. If not present the Desktop Agent may use the src file extension. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type?: string; + type: 'broadcastResponse'; } /** - * Describes an image file, typically a screenshot, that often represents the application in - * a common usage scenario. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Image { +export interface BroadcastResponseResponsePayload { + error?: ResponsePayloadError; + [property: string]: any; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * An event message from the Desktop Agent to an app indicating that its current user + * channel has changed. + * + * A message from a Desktop Agent to an FDC3-enabled app representing an event. + */ +export interface ChannelChangedEvent { /** - * Caption for the image. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - label?: string; + meta: BroadcastEventMeta; /** - * The image dimension, formatted as `x`. + * The message payload contains details of the event that the app is being notified about. */ - size?: string; + payload: ChannelChangedEventPayload; /** - * The image url. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - src: string; + type: 'channelChangedEvent'; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface ChannelChangedEventPayload { /** - * Image media type. If not present the Desktop Agent may use the src file extension. + * The Id of the channel that the app was added to or `null` if it was removed from a + * channel. */ - type?: string; + newChannelId: null | string; } /** - * Metadata indicating whether the Desktop Agent implements optional features of - * the Desktop Agent API. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export interface OptionalFeatures { + +/** + * A request to unsubscribe a context listener. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface ContextListenerUnsubscribeRequest { /** - * Used to indicate whether the experimental Desktop Agent Bridging - * feature is implemented by the Desktop Agent. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - DesktopAgentBridging: boolean; + meta: AddContextListenerRequestMeta; /** - * Used to indicate whether the exposure of 'originating app metadata' for - * context and intent messages is supported by the Desktop Agent. + * The message payload typically contains the arguments to FDC3 API functions. */ - OriginatingAppMetadata: boolean; + payload: ContextListenerUnsubscribeRequestPayload; /** - * Used to indicate whether the optional `fdc3.joinUserChannel`, - * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by - * the Desktop Agent. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - UserChannelMembershipAPIs: boolean; + type: 'contextListenerUnsubscribeRequest'; } /** - * Identifies the type of the connection step message. + * The message payload typically contains the arguments to FDC3 API functions. */ +export interface ContextListenerUnsubscribeRequestPayload { + listenerUUID: string; +} /** - * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the - * window or navigating). Desktop Agents should close the MessagePort after receiving this - * message, but retain instance details in case the application reconnects (e.g. after a - * navigation event). + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a contextListenerUnsubscribe request. * - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface WebConnectionProtocol6Goodbye { +export interface ContextListenerUnsubscribeResponse { /** - * Metadata for a Web Connection Protocol message. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: WebConnectionProtocol6GoodbyeMeta; + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: BroadcastResponseResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'contextListenerUnsubscribeResponse'; +} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + +/** + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. + * + * A request message from an FDC3-enabled app to a Desktop Agent. + */ +export interface CreatePrivateChannelRequest { + /** + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + */ + meta: AddContextListenerRequestMeta; + /** + * The message payload typically contains the arguments to FDC3 API functions. + */ + payload: CreatePrivateChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'createPrivateChannelRequest'; +} + +/** + * The message payload typically contains the arguments to FDC3 API functions. + */ +export interface CreatePrivateChannelRequestPayload {} + +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a createPrivateChannel request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface CreatePrivateChannelResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: CreatePrivateChannelResponsePayload; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'WCP6Goodbye'; + type: 'createPrivateChannelResponse'; } /** - * Metadata for a Web Connection Protocol message. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface WebConnectionProtocol6GoodbyeMeta { - timestamp: Date; +export interface CreatePrivateChannelResponsePayload { + error?: PurpleError; + privateChannel?: Channel; } /** - * Identifies the type of the connection step message. + * Represents a context channel that applications can use to send and receive + * context data. + * + * Please note that There are differences in behavior when you interact with a + * User channel via the `DesktopAgent` interface and the `Channel` interface. + * Specifically, when 'joining' a User channel or adding a context listener + * when already joined to a channel via the `DesktopAgent` interface, existing + * context (matching the type of the context listener) on the channel is + * received by the context listener immediately. Whereas, when a context + * listener is added via the Channel interface, context is not received + * automatically, but may be retrieved manually via the `getCurrentContext()` + * function. */ +export interface Channel { + /** + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + */ + displayMetadata?: DisplayMetadata; + /** + * Constant that uniquely identifies this channel. + */ + id: string; + /** + * Uniquely defines each channel type. + * Can be "user", "app" or "private". + */ + type: Type; +} /** - * A message used during the connection flow for an application to a Desktop Agent in a - * browser window. Used for messages sent in either direction. + * Channels may be visualized and selectable by users. DisplayMetadata may be used to + * provide hints on how to see them. + * For App channels, displayMetadata would typically not be present. + * + * A system channel will be global enough to have a presence across many apps. This gives us + * some hints + * to render them in a standard way. It is assumed it may have other properties too, but if + * it has these, + * this is their meaning. */ -export interface WebConnectionProtocolMessage { +export interface DisplayMetadata { /** - * Metadata for a Web Connection Protocol message. + * The color that should be associated within this channel when displaying this channel in a + * UI, e.g: `0xFF0000`. */ - meta: ConnectionStepMetadata; + color?: string; /** - * The message payload, containing data pertaining to this connection step. + * A URL of an image that can be used to display this channel. */ - payload?: { [key: string]: any }; + glyph?: string; /** - * Identifies the type of the connection step message. + * A user-readable name for this channel, e.g: `"Red"`. */ - type: ConnectionStepMessageType; + name?: string; } /** - * Metadata for a Web Connection Protocol message. + * Uniquely defines each channel type. + * Can be "user", "app" or "private". */ -export interface ConnectionStepMetadata { - timestamp: Date; - connectionAttemptUuid?: string; -} +export type Type = 'app' | 'private' | 'user'; /** - * Identifies the type of the connection step message. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export type ConnectionStepMessageType = - | 'WCP1Hello' - | 'WCP2LoadUrl' - | 'WCP3Handshake' - | 'WCP4ValidateAppIdentity' - | 'WCP5ValidateAppIdentityFailedResponse' - | 'WCP5ValidateAppIdentityResponse' - | 'WCP6Goodbye'; /** - * A request to add a context listener to a specified Channel OR to the current user - * channel. Where the listener is added to the current user channel (channelId == null), and - * this app has already been added to a user channel, client code should make a subsequent - * request to get the current context of that channel for this listener and then call its - * handler with it. + * A request to unsubscribe an event listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface AddContextListenerRequest { +export interface EventListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -636,90 +1036,19 @@ export interface AddContextListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: AddContextListenerRequestPayload; + payload: EventListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'addContextListenerRequest'; -} - -/** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ -export interface AddContextListenerRequestMeta { - requestUuid: string; - /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. - * - * Identifies an application, or instance of an application, and is used to target FDC3 API - * calls, such as `fdc3.open` or `fdc3.raiseIntent` at specific applications or application - * instances. - * - * Will always include at least an `appId` field, which uniquely identifies a specific app. - * - * If the `instanceId` field is set then the `AppMetadata` object represents a specific - * instance of the application that may be addressed using that Id. - * - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - * - * Details of the application instance that broadcast the context. - * - * The App resolution option chosen. - * - * Details of the application instance that raised the intent. - * - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. - */ -export interface AppIdentifier { - /** - * The unique application identifier located within a specific application directory - * instance. An example of an appId might be 'app@sub.root'. - */ - appId: string; - /** - * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to - * identify the Desktop Agent to target. - */ - desktopAgent?: string; - /** - * An optional instance identifier, indicating that this object represents a specific - * instance of the application described. - */ - instanceId?: string; - [property: string]: any; + type: 'eventListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface AddContextListenerRequestPayload { - /** - * The id of the channel to add the listener to or `null` indicating that it should listen - * to the current user channel (at the time of broadcast). - */ - channelId: null | string; - /** - * The type of context to listen for OR `null` indicating that it should listen to all - * context types. - */ - contextType: null | string; +export interface EventListenerUnsubscribeRequestPayload { + listenerUUID: string; } /** @@ -728,15 +1057,12 @@ export interface AddContextListenerRequestPayload { */ /** - * A response to a addContextListener request. Where the listener was added to the current - * user channel (channelId == null), and this app has already been added to a user channel, - * client code should make a subsequent request to get the current context of that channel - * for this listener and then call its handler with it. + * A response to an eventListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface AddContextListenerResponse { +export interface EventListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -746,686 +1072,599 @@ export interface AddContextListenerResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: AddContextListenerResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'addContextListenerResponse'; + type: 'eventListenerUnsubscribeResponse'; } /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export interface AddContextListenerResponseMeta { - requestUuid: string; - responseUuid: string; - /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. - */ - source?: AppIdentifier; - timestamp: Date; -} /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an + * iframe with the channel definitions and current channel selection. + * + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddContextListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; +export interface Fdc3UserInterfaceChannels { + /** + * The message payload. + */ + payload: Fdc3UserInterfaceChannelsPayload; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: 'Fdc3UserInterfaceChannels'; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). + * The message payload. */ -export type PurpleError = 'AccessDenied' | 'CreationFailed' | 'MalformedContext' | 'NoChannelFound'; +export interface Fdc3UserInterfaceChannelsPayload { + /** + * The id of the channel that should be currently selected, or `null` if none should be + * selected. + */ + selected: null | string; + /** + * User Channel definitions.```````s + */ + userChannels: Channel[]; +} /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A request to add an event listener for a specified event type to the Desktop Agent. + * Message from a channel selector UI to the DA proxy sent when the channel selection + * changes. * - * A request message from an FDC3-enabled app to a Desktop Agent. - */ -export interface AddEventListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. + */ +export interface Fdc3UserInterfaceChannelSelected { /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ - payload: AddEventListenerRequestPayload; + payload: Fdc3UserInterfaceChannelSelectedPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addEventListenerRequest'; + type: 'Fdc3UserInterfaceChannelSelected'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface AddEventListenerRequestPayload { +export interface Fdc3UserInterfaceChannelSelectedPayload { /** - * The type of the event to be listened to or `null` to listen to all event types. + * The id of the channel that should be currently selected, or `null` if none should be + * selected. */ - type: 'USER_CHANNEL_CHANGED' | null; + selected: null | string; } /** - * The type of a (non-context and non-intent) event that may be received via the FDC3 API's - * addEventListener function. - */ - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A response to an addEventListener request. + * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user + * is dragging the UI to a new location and providing the offset to apply to the location. + * The DA proxy implementation should limit the location to the current bounds of the + * window's viewport. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddEventListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface Fdc3UserInterfaceDrag { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ - payload: AddEventListenerResponsePayload; + payload: Fdc3UserInterfaceDragPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addEventListenerResponse'; + type: 'Fdc3UserInterfaceDrag'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ -export interface AddEventListenerResponsePayload { - error?: ResponsePayloadError; - listenerUUID?: string; +export interface Fdc3UserInterfaceDragPayload { + /** + * The offset to move the frame by. + */ + mouseOffsets: MouseOffsets; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). + * The offset to move the frame by. */ -export type ResponsePayloadError = - | 'AccessDenied' - | 'CreationFailed' - | 'MalformedContext' - | 'NoChannelFound' - | 'AppNotFound' - | 'AppTimeout' - | 'DesktopAgentNotFound' - | 'ErrorOnLaunch' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution' - | 'IntentHandlerRejected' - | 'NoResultReturned' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; +export interface MouseOffsets { + x: number; + y: number; +} /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A request to add an Intent listener for a specified intent type. + * Handshake message sent back to a user interface from the DA proxy code (setup by + * `getAgent()`) over the `MessagePort` provided in the preceding Fdc3UserInterfaceHello + * message, confirming that it is listening to the `MessagePort` for further communication. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddIntentListenerRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; +export interface Fdc3UserInterfaceHandshake { /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ - payload: AddIntentListenerRequestPayload; + payload: Fdc3UserInterfaceHandshakePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addIntentListenerRequest'; + type: 'Fdc3UserInterfaceHandshake'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface AddIntentListenerRequestPayload { +export interface Fdc3UserInterfaceHandshakePayload { /** - * The name of the intent to listen for. + * The version of FDC3 API that the Desktop Agent will provide support for. */ - intent: string; + fdc3Version: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A response to a addIntentListener request. + * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate + * it is ready to communicate, containing initial CSS to set on the iframe, and including an + * appended `MessagePort` to be used for further communication. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AddIntentListenerResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface Fdc3UserInterfaceHello { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload. */ - payload: PayloadObject; + payload: Fdc3UserInterfaceHelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'addIntentListenerResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface PayloadObject { - error?: FluffyError; - listenerUUID?: string; - [property: string]: any; + type: 'Fdc3UserInterfaceHello'; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - */ -export type FluffyError = - | 'MalformedContext' - | 'DesktopAgentNotFound' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution'; - -/** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The message payload. */ -export interface AgentEventMessageMeta { - eventUuid: string; - timestamp: Date; +export interface Fdc3UserInterfaceHelloPayload { + /** + * Details about the UI implementation, such as vendor and version, for logging purposes. + */ + implementationDetails: string; + /** + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + */ + initialCSS: InitialCSS; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ -export type EventMessageType = - | 'addEventListenerEvent' - | 'broadcastEvent' - | 'channelChangedEvent' - | 'heartbeatEvent' - | 'intentEvent' - | 'privateChannelOnAddContextListenerEvent' - | 'privateChannelOnDisconnectEvent' - | 'privateChannelOnUnsubscribeEvent'; - -/** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * A constrained set of styling properties that should be set on the user interface before + * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. */ -export interface AgentResponseMessageMeta { - requestUuid: string; - responseUuid: string; +export interface InitialCSS { + /** + * The initial bottom property to apply to the iframe. + */ + bottom?: string; + /** + * The initial height of the iframe. + */ + height?: string; + /** + * The initial left property to apply to the iframe. + */ + left?: string; + /** + * The maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; /** - * Field that represents the source application that the request being responded to was - * received from, for debugging purposes. + * The transition property to apply to the iframe. */ - source?: AppIdentifier; - timestamp: Date; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface AgentResponseMessageResponsePayload { - error?: ResponsePayloadError; + transition?: string; + /** + * The initial width of the iframe. + */ + width?: string; + /** + * The initial zindex to apply to the iframe. + */ + zIndex?: string; [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ -export type ResponseMessageType = - | 'addContextListenerResponse' - | 'addEventListenerResponse' - | 'addIntentListenerResponse' - | 'broadcastResponse' - | 'contextListenerUnsubscribeResponse' - | 'createPrivateChannelResponse' - | 'eventListenerUnsubscribeResponse' - | 'findInstancesResponse' - | 'findIntentResponse' - | 'findIntentsByContextResponse' - | 'getAppMetadataResponse' - | 'getCurrentChannelResponse' - | 'getCurrentContextResponse' - | 'getInfoResponse' - | 'getOrCreateChannelResponse' - | 'getUserChannelsResponse' - | 'intentListenerUnsubscribeResponse' - | 'intentResultResponse' - | 'joinUserChannelResponse' - | 'leaveCurrentChannelResponse' - | 'openResponse' - | 'privateChannelAddEventListenerResponse' - | 'privateChannelDisconnectResponse' - | 'privateChannelUnsubscribeEventListenerResponse' - | 'raiseIntentForContextResponse' - | 'raiseIntentResponse' - | 'raiseIntentResultResponse'; /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface AppRequestMessageMeta { - requestUuid: string; +export interface Fdc3UserInterfaceMessage { /** - * Field that represents the source application that a request or response was received - * from. Please note that this may be set by an app or Desktop Agent proxy for debugging - * purposes but a Desktop Agent should make its own determination of the source of a message - * to avoid spoofing. + * The message payload. */ - source?: AppIdentifier; - timestamp: Date; + payload?: { [key: string]: any }; + /** + * Identifies the type of the message to or from the user interface frame. + */ + type: Fdc3UserInterfaceMessageType; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ -export type RequestMessageType = - | 'addContextListenerRequest' - | 'addEventListenerRequest' - | 'addIntentListenerRequest' - | 'broadcastRequest' - | 'contextListenerUnsubscribeRequest' - | 'createPrivateChannelRequest' - | 'eventListenerUnsubscribeRequest' - | 'findInstancesRequest' - | 'findIntentRequest' - | 'findIntentsByContextRequest' - | 'getAppMetadataRequest' - | 'getCurrentChannelRequest' - | 'getCurrentContextRequest' - | 'getInfoRequest' - | 'getOrCreateChannelRequest' - | 'getUserChannelsRequest' - | 'heartbeatAcknowledgementRequest' - | 'intentListenerUnsubscribeRequest' - | 'intentResultRequest' - | 'joinUserChannelRequest' - | 'leaveCurrentChannelRequest' - | 'openRequest' - | 'privateChannelAddEventListenerRequest' - | 'privateChannelDisconnectRequest' - | 'privateChannelUnsubscribeEventListenerRequest' - | 'raiseIntentForContextRequest' - | 'raiseIntentRequest'; +export type Fdc3UserInterfaceMessageType = + | 'Fdc3UserInterfaceHello' + | 'Fdc3UserInterfaceHandshake' + | 'Fdc3UserInterfaceRestyle' + | 'Fdc3UserInterfaceDrag' + | 'Fdc3UserInterfaceResolve' + | 'Fdc3UserInterfaceResolveAction' + | 'Fdc3UserInterfaceChannels' + | 'Fdc3UserInterfaceChannelSelected'; /** - * An event message from the Desktop Agent to an app indicating that context has been - * broadcast on a channel it is listening to, or specifically to this app instance if it was - * launched via `fdc3.open` and context was passed. + * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the + * resolver data to setup the UI. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface BroadcastEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; +export interface Fdc3UserInterfaceResolve { /** - * The message payload contains details of the event that the app is being notified about. + * The message payload. */ - payload: BroadcastEventPayload; + payload: Fdc3UserInterfaceResolvePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'broadcastEvent'; + type: 'Fdc3UserInterfaceResolve'; } /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The message payload. */ -export interface BroadcastEventMeta { - eventUuid: string; - timestamp: Date; +export interface Fdc3UserInterfaceResolvePayload { + /** + * An array of AppIntent objects defining the resolution options. + */ + appIntents: AppIntent[]; + context: Context; } /** - * The message payload contains details of the event that the app is being notified about. + * An interface that relates an intent to apps. + * + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. */ -export interface BroadcastEventPayload { - /** - * The Id of the channel that the broadcast was sent on. May be `null` if the context is - * being broadcast due to a call `fdc3.open` that passed context. - */ - channelId: null | string; +export interface AppIntent { /** - * The context object that was broadcast. + * Details of applications that can resolve the intent. */ - context: Context; + apps: AppMetadata[]; /** - * Details of the application instance that broadcast the context. + * Details of the intent whose relationship to resolving applications is being described. */ - originatingApp?: AppIdentifier; + intent: IntentMetadata; } /** - * The context object that was broadcast. - * - * The context object that is to be broadcast. - * - * The context object passed with the raised intent. - * - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. + * Extends an `AppIdentifier`, describing an application or instance of an application, with + * additional descriptive metadata that is usually provided by an FDC3 App Directory that + * the Desktop Agent connects to. * - * The `fdc3.context` type defines the basic contract or "shape" for all data exchanged by - * FDC3 operations. As such, it is not really meant to be used on its own, but is imported - * by more specific type definitions (standardized or custom) to provide the structure and - * properties shared by all FDC3 context data types. + * The additional information from an app directory can aid in rendering UI elements, such + * as a launcher menu or resolver UI. This includes a title, description, tooltip and icon + * and screenshot URLs. * - * The key element of FDC3 context types is their mandatory `type` property, which is used - * to identify what type of data the object represents, and what shape it has. + * Note that as `AppMetadata` instances are also `AppIdentifiers` they may be passed to the + * `app` argument of `fdc3.open`, `fdc3.raiseIntent` etc. * - * The FDC3 context type, and all derived types, define the minimum set of fields a context - * data object of a particular type can be expected to have, but this can always be extended - * with custom fields as appropriate. + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). */ -export interface Context { +export interface AppMetadata { /** - * Context data objects may include a set of equivalent key-value pairs that can be used to - * help applications identify and look up the context type they receive in their own domain. - * The idea behind this design is that applications can provide as many equivalent - * identifiers to a target application as possible, e.g. an instrument may be represented by - * an ISIN, CUSIP or Bloomberg identifier. - * - * Identifiers do not make sense for all types of data, so the `id` property is therefore - * optional, but some derived types may choose to require at least one identifier. - * Identifier values SHOULD always be of type string. + * The unique application identifier located within a specific application directory + * instance. An example of an appId might be 'app@sub.root'. + */ + appId: string; + /** + * A longer, multi-paragraph description for the application that could include markup. + */ + description?: string; + /** + * The Desktop Agent that the app is available on. Used in Desktop Agent Bridging to + * identify the Desktop Agent to target. + */ + desktopAgent?: string; + /** + * A list of icon URLs for the application that can be used to render UI elements. + */ + icons?: Icon[]; + /** + * An optional instance identifier, indicating that this object represents a specific + * instance of the application described. + */ + instanceId?: string; + /** + * An optional set of, implementation specific, metadata fields that can be used to + * disambiguate instances, such as a window title or screen position. Must only be set if + * `instanceId` is set. + */ + instanceMetadata?: { [key: string]: any }; + /** + * The 'friendly' app name. + * This field was used with the `open` and `raiseIntent` calls in FDC3 <2.0, which now + * require an `AppIdentifier` wth `appId` set. + * Note that for display purposes the `title` field should be used, if set, in preference to + * this field. + */ + name?: string; + /** + * The type of output returned for any intent specified during resolution. May express a + * particular context type (e.g. "fdc3.instrument"), channel (e.g. "channel") or a channel + * that will receive a specified type (e.g. "channel"). + */ + resultType?: null | string; + /** + * Images representing the app in common usage scenarios that can be used to render UI + * elements. + */ + screenshots?: Image[]; + /** + * A more user-friendly application title that can be used to render UI elements. */ - id?: { [key: string]: any }; + title?: string; /** - * Context data objects may include a name property that can be used for more information, - * or display purposes. Some derived types may require the name object as mandatory, - * depending on use case. + * A tooltip for the application that can be used to render UI elements. */ - name?: string; + tooltip?: string; /** - * The type property is the only _required_ part of the FDC3 context data schema. The FDC3 - * [API](https://fdc3.finos.org/docs/api/spec) relies on the `type` property being present - * to route shared context data appropriately. - * - * FDC3 [Intents](https://fdc3.finos.org/docs/intents/spec) also register the context data - * types they support in an FDC3 [App - * Directory](https://fdc3.finos.org/docs/app-directory/overview), used for intent discovery - * and routing. - * - * Standardized FDC3 context types have well-known `type` properties prefixed with the - * `fdc3` namespace, e.g. `fdc3.instrument`. For non-standard types, e.g. those defined and - * used by a particular organization, the convention is to prefix them with an - * organization-specific namespace, e.g. `blackrock.fund`. - * - * See the [Context Data Specification](https://fdc3.finos.org/docs/context/spec) for more - * information about context data types. + * The Version of the application. */ - type: string; - [property: string]: any; + version?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to broadcast context on a channel. - * - * A request message from an FDC3-enabled app to a Desktop Agent. + * Describes an Icon image that may be used to represent the application. */ -export interface BroadcastRequest { +export interface Icon { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * The icon dimension, formatted as `x`. */ - meta: AddContextListenerRequestMeta; + size?: string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The icon url. */ - payload: BroadcastRequestPayload; + src: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Icon media type. If not present the Desktop Agent may use the src file extension. */ - type: 'broadcastRequest'; + type?: string; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * Describes an image file, typically a screenshot, that often represents the application in + * a common usage scenario. */ -export interface BroadcastRequestPayload { +export interface Image { /** - * The Id of the Channel that the broadcast was sent on. + * Caption for the image. */ - channelId: string; + label?: string; /** - * The context object that is to be broadcast. + * The image dimension, formatted as `x`. */ - context: Context; + size?: string; + /** + * The image url. + */ + src: string; + /** + * Image media type. If not present the Desktop Agent may use the src file extension. + */ + type?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a request to broadcast context on a channel. + * Details of the intent whose relationship to resolving applications is being described. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * Metadata describing an Intent. */ -export interface BroadcastResponse { - /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. - */ - meta: AddContextListenerResponseMeta; +export interface IntentMetadata { /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Display name for the intent. */ - payload: BroadcastResponseResponsePayload; + displayName?: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The unique name of the intent that can be invoked by the raiseIntent call. */ - type: 'broadcastResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface BroadcastResponseResponsePayload { - error?: ResponsePayloadError; - [property: string]: any; + name: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * An event message from the Desktop Agent to an app indicating that its current user - * channel has changed. + * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user + * action. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface ChannelChangedEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; +export interface Fdc3UserInterfaceResolveAction { /** - * The message payload contains details of the event that the app is being notified about. + * The message payload. */ - payload: ChannelChangedEventPayload; + payload: Fdc3UserInterfaceResolveActionPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'channelChangedEvent'; + type: 'Fdc3UserInterfaceResolveAction'; } /** - * The message payload contains details of the event that the app is being notified about. + * The message payload. */ -export interface ChannelChangedEventPayload { +export interface Fdc3UserInterfaceResolveActionPayload { + action: Action; /** - * The Id of the channel that the app was added to or `null` if it was removed from a - * channel. + * The App resolution option chosen. */ - newChannelId: null | string; + appIdentifier?: AppIdentifier; + /** + * The intent resolved. + */ + intent?: string; } +export type Action = 'hover' | 'click' | 'cancel'; + /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * A request to unsubscribe a context listener. + * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling + * information to apply to it. Can be used to implement a pop-open or close interaction or + * other transition needed by a UI implementation. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used to communicate with user interface frames injected by `getAgent()` for + * displaying UI elements such as the intent resolver or channel selector. Used for messages + * sent in either direction. */ -export interface ContextListenerUnsubscribeRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; +export interface Fdc3UserInterfaceRestyle { /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ - payload: ContextListenerUnsubscribeRequestPayload; + payload: Fdc3UserInterfaceRestylePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the message to or from the user interface frame. */ - type: 'contextListenerUnsubscribeRequest'; + type: 'Fdc3UserInterfaceRestyle'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload. */ -export interface ContextListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface Fdc3UserInterfaceRestylePayload { + /** + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. + */ + updatedCSS: UpdatedCSS; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a contextListenerUnsubscribe request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A constrained set of styling properties that should be applied to the frame. Note + * `position` cannot be set, and should always be `fixed`. */ -export interface ContextListenerUnsubscribeResponse { +export interface UpdatedCSS { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The initial bottom property to apply to the iframe. */ - meta: AddContextListenerResponseMeta; + bottom?: string; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The updated height of the iframe. */ - payload: BroadcastResponseResponsePayload; + height?: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The initial left property to apply to the iframe. */ - type: 'contextListenerUnsubscribeResponse'; + left?: string; + /** + * The updated maximum height to apply to the iframe. + */ + maxHeight?: string; + /** + * The updated maximum with to apply to the iframe. + */ + maxWidth?: string; + /** + * The initial right property to apply to the iframe. + */ + right?: string; + /** + * The initial top property to apply to the iframe. + */ + top?: string; + /** + * The updated transition property to apply to the iframe. + */ + transition?: string; + /** + * The updated width of the iframe. + */ + width?: string; + /** + * The updated zIndex to apply to the iframe. + */ + zIndex?: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the message to or from the user interface frame. */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * A request for details of instances of a particular app. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface CreatePrivateChannelRequest { +export interface FindInstancesRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -1433,18 +1672,20 @@ export interface CreatePrivateChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: CreatePrivateChannelRequestPayload; + payload: FindInstancesRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'createPrivateChannelRequest'; + type: 'findInstancesRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface CreatePrivateChannelRequestPayload {} +export interface FindInstancesRequestPayload { + app: AppIdentifier; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -1452,12 +1693,12 @@ export interface CreatePrivateChannelRequestPayload {} */ /** - * A response to a createPrivateChannel request. + * A response to a findInstances request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface CreatePrivateChannelResponse { +export interface FindInstancesResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -1467,88 +1708,67 @@ export interface CreatePrivateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: CreatePrivateChannelResponsePayload; + payload: FindInstancesResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'createPrivateChannelResponse'; + type: 'findInstancesResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - */ -export interface CreatePrivateChannelResponsePayload { - error?: PurpleError; - privateChannel?: Channel; -} - -/** - * Represents a context channel that applications can use to send and receive - * context data. * - * Please note that There are differences in behavior when you interact with a - * User channel via the `DesktopAgent` interface and the `Channel` interface. - * Specifically, when 'joining' a User channel or adding a context listener - * when already joined to a channel via the `DesktopAgent` interface, existing - * context (matching the type of the context listener) on the channel is - * received by the context listener immediately. Whereas, when a context - * listener is added via the Channel interface, context is not received - * automatically, but may be retrieved manually via the `getCurrentContext()` - * function. + * The message payload contains a flag indicating whether the API call was successful, plus + * any return values for the FDC3 API function called, or indicating that the request + * resulted in an error and including a standardized error message. */ -export interface Channel { - /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. - */ - displayMetadata?: DisplayMetadata; - /** - * Constant that uniquely identifies this channel. - */ - id: string; - /** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". - */ - type: Type; +export interface FindInstancesResponsePayload { + error?: FindInstancesErrors; + appIdentifiers?: AppMetadata[]; } /** - * Channels may be visualized and selectable by users. DisplayMetadata may be used to - * provide hints on how to see them. - * For App channels, displayMetadata would typically not be present. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). * - * A system channel will be global enough to have a presence across many apps. This gives us - * some hints - * to render them in a standard way. It is assumed it may have other properties too, but if - * it has these, - * this is their meaning. - */ -export interface DisplayMetadata { - /** - * The color that should be associated within this channel when displaying this channel in a - * UI, e.g: `0xFF0000`. - */ - color?: string; - /** - * A URL of an image that can be used to display this channel. - */ - glyph?: string; - /** - * A user-readable name for this channel, e.g: `"Red"`. - */ - name?: string; -} - -/** - * Uniquely defines each channel type. - * Can be "user", "app" or "private". + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). + * + * Unique identifier for a request or event message. Required in all message types. + * + * Unique identifier for a response to a specific message and must always be accompanied by + * a RequestUuid. + * + * Unique identifier for a `listener` object returned by a Desktop Agent to an app in + * response to addContextListener, addIntentListener or one of the PrivateChannel event + * listeners and used to identify it in messages (e.g. when unsubscribing). + * + * Unique identifier for an event message sent from a Desktop Agent to an app. + * + * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID + * should be used in the first (WCP1Hello) message and should be quoted in all subsequent + * messages to link them to the same connection attempt. + * + * Should be set if the raiseIntent request returned an error. */ -export type Type = 'app' | 'private' | 'user'; +export type FindInstancesErrors = + | 'MalformedContext' + | 'DesktopAgentNotFound' + | 'ResolverUnavailable' + | 'IntentDeliveryFailed' + | 'NoAppsFound' + | 'ResolverTimeout' + | 'TargetAppUnavailable' + | 'TargetInstanceUnavailable' + | 'UserCancelledResolution' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -1556,11 +1776,11 @@ export type Type = 'app' | 'private' | 'user'; */ /** - * A request to unsubscribe an event listener. + * A request for details of apps available to resolve a particular intent and context pair. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface EventListenerUnsubscribeRequest { +export interface FindIntentRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -1568,19 +1788,21 @@ export interface EventListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: EventListenerUnsubscribeRequestPayload; + payload: FindIntentRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'eventListenerUnsubscribeRequest'; + type: 'findIntentRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface EventListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface FindIntentRequestPayload { + context?: Context; + intent: string; + resultType?: string; } /** @@ -1589,12 +1811,12 @@ export interface EventListenerUnsubscribeRequestPayload { */ /** - * A response to an eventListenerUnsubscribe request. + * A response to a findIntent request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface EventListenerUnsubscribeResponse { +export interface FindIntentResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -1604,480 +1826,339 @@ export interface EventListenerUnsubscribeResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: FindIntentResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'eventListenerUnsubscribeResponse'; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * Message from a channel selector UI to the DA proxy sent when the channel selection - * changes. - * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. - */ -export interface Fdc3UserInterfaceChannelSelected { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceChannelSelectedPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: 'Fdc3UserInterfaceChannelSelected'; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceChannelSelectedPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; -} - -/** - * Identifies the type of the message to or from the user interface frame. - */ - -/** - * Setup message sent by the DA proxy code in getAgent() to a channel selector UI in an - * iframe with the channel definitions and current channel selection. - * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. - */ -export interface Fdc3UserInterfaceChannels { - /** - * The message payload. - */ - payload: Fdc3UserInterfaceChannelsPayload; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: 'Fdc3UserInterfaceChannels'; + type: 'findIntentResponse'; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceChannelsPayload { - /** - * The id of the channel that should be currently selected, or `null` if none should be - * selected. - */ - selected: null | string; - /** - * User Channel definitions.```````s - */ - userChannels: Channel[]; +export interface FindIntentResponsePayload { + error?: FindInstancesErrors; + appIntent?: AppIntent; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message from a UI iframe to the DA proxy (setup by `getAgent()`) indicating that the user - * is dragging the UI to a new location and providing the offset to apply to the location. - * The DA proxy implementation should limit the location to the current bounds of the - * window's viewport. + * A request for details of intents and apps available to resolve them for a particular + * context. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceDrag { +export interface FindIntentsByContextRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceDragPayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceDrag'; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceDragPayload { + payload: FindIntentsByContextRequestPayload; /** - * The offset to move the frame by. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - mouseOffsets: MouseOffsets; + type: 'findIntentsByContextRequest'; } /** - * The offset to move the frame by. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface MouseOffsets { - x: number; - y: number; +export interface FindIntentsByContextRequestPayload { + context: Context; + resultType?: string; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Handshake message sent back to a user interface from the DA proxy code (setup by - * `getAgent()`) over the `MessagePort` provided in the preceding Fdc3UserInterfaceHello - * message, confirming that it is listening to the `MessagePort` for further communication. + * A response to a findIntentsByContext request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceHandshake { +export interface FindIntentsByContextResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceHandshakePayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: 'Fdc3UserInterfaceHandshake'; + payload: FindIntentsByContextResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'findIntentsByContextResponse'; } /** - * The message payload. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceHandshakePayload { - /** - * The version of FDC3 API that the Desktop Agent will provide support for. - */ - fdc3Version: string; +export interface FindIntentsByContextResponsePayload { + error?: FindInstancesErrors; + appIntents?: AppIntent[]; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Hello message sent by a UI to the Desktop Agent proxy setup by `getAgent()` to indicate - * it is ready to communicate, containing initial CSS to set on the iframe, and including an - * appended `MessagePort` to be used for further communication. + * A request for metadata about an app. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceHello { +export interface GetAppMetadataRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceHelloPayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceHello'; + payload: GetAppMetadataRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getAppMetadataRequest'; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceHelloPayload { - /** - * Details about the UI implementation, such as vendor and version, for logging purposes. - */ - implementationDetails: string; - /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. - */ - initialCSS: InitialCSS; +export interface GetAppMetadataRequestPayload { + app: AppIdentifier; } /** - * A constrained set of styling properties that should be set on the user interface before - * it is displayed. Note `position` cannot be specified and should always be set to `fixed`. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ -export interface InitialCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The initial height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; + +/** + * A response to a getAppMetadata request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface GetAppMetadataResponse { /** - * The transition property to apply to the iframe. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - transition?: string; + meta: AddContextListenerResponseMeta; /** - * The initial width of the iframe. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - width?: string; + payload: GetAppMetadataResponsePayload; /** - * The initial zindex to apply to the iframe. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - zIndex?: string; - [property: string]: any; + type: 'getAppMetadataResponse'; } /** - * Identifies the type of the message to or from the user interface frame. - */ - -/** - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface Fdc3UserInterfaceMessage { - /** - * The message payload. - */ - payload?: { [key: string]: any }; - /** - * Identifies the type of the message to or from the user interface frame. - */ - type: Fdc3UserInterfaceMessageType; +export interface GetAppMetadataResponsePayload { + error?: FindInstancesErrors; + appMetadata?: AppMetadata; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ -export type Fdc3UserInterfaceMessageType = - | 'Fdc3UserInterfaceHello' - | 'Fdc3UserInterfaceHandshake' - | 'Fdc3UserInterfaceRestyle' - | 'Fdc3UserInterfaceDrag' - | 'Fdc3UserInterfaceResolve' - | 'Fdc3UserInterfaceResolveAction' - | 'Fdc3UserInterfaceChannels' - | 'Fdc3UserInterfaceChannelSelected'; /** - * Setup message sent by the DA proxy code in getAgent() to an intent resolver UI with the - * resolver data to setup the UI. + * A request to return the Channel object for the current User channel membership. Returns + * `null` if the app is not joined to a channel. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceResolve { +export interface GetCurrentChannelRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceResolvePayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceResolve'; + payload: GetCurrentChannelRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getCurrentChannelRequest'; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceResolvePayload { - /** - * An array of AppIntent objects defining the resolution options. - */ - appIntents: AppIntent[]; - context: Context; -} +export interface GetCurrentChannelRequestPayload {} /** - * An interface that relates an intent to apps. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a getCurrentChannel request. * - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface AppIntent { +export interface GetCurrentChannelResponse { /** - * Details of applications that can resolve the intent. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - apps: AppMetadata[]; + meta: AddContextListenerResponseMeta; /** - * Details of the intent whose relationship to resolving applications is being described. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - intent: IntentMetadata; + payload: GetCurrentChannelResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'getCurrentChannelResponse'; } /** - * Details of the intent whose relationship to resolving applications is being described. - * - * Metadata describing an Intent. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface IntentMetadata { - /** - * Display name for the intent. - */ - displayName?: string; - /** - * The unique name of the intent that can be invoked by the raiseIntent call. - */ - name: string; +export interface GetCurrentChannelResponsePayload { + error?: ResponsePayloadError; + channel?: Channel | null; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * Message from an intent resolver UI to DA proxy code in getAgent() reporting a user - * action. + * A request to return the current context (either of a specified type or most recent + * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if + * one was specified) is available in the channel. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface Fdc3UserInterfaceResolveAction { +export interface GetCurrentContextRequest { /** - * The message payload. + * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ - payload: Fdc3UserInterfaceResolveActionPayload; + meta: AddContextListenerRequestMeta; /** - * Identifies the type of the message to or from the user interface frame. + * The message payload typically contains the arguments to FDC3 API functions. */ - type: 'Fdc3UserInterfaceResolveAction'; + payload: GetCurrentContextRequestPayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + type: 'getCurrentContextRequest'; } /** - * The message payload. + * The message payload typically contains the arguments to FDC3 API functions. */ -export interface Fdc3UserInterfaceResolveActionPayload { - action: Action; +export interface GetCurrentContextRequestPayload { /** - * The App resolution option chosen. + * The id of the channel to return the current context of. */ - appIdentifier?: AppIdentifier; + channelId: string; /** - * The intent resolved. + * The type of context to return for OR `null` indicating that the most recently broadcast + * context on the channel should be returned. */ - intent?: string; + contextType: null | string; } -export type Action = 'hover' | 'click' | 'cancel'; - /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * Message from a UI frame to the DA proxy code (setup by `getAgent()`) with updated styling - * information to apply to it. Can be used to implement a pop-open or close interaction or - * other transition needed by a UI implementation. + * A response to a getCurrentContext request. * - * A message used to communicate with user interface frames injected by `getAgent()` for - * displaying UI elements such as the intent resolver or channel selector. Used for messages - * sent in either direction. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface Fdc3UserInterfaceRestyle { +export interface GetCurrentContextResponse { /** - * The message payload. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - payload: Fdc3UserInterfaceRestylePayload; + meta: AddContextListenerResponseMeta; /** - * Identifies the type of the message to or from the user interface frame. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - type: 'Fdc3UserInterfaceRestyle'; -} - -/** - * The message payload. - */ -export interface Fdc3UserInterfaceRestylePayload { + payload: GetCurrentContextResponsePayload; /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - updatedCSS: UpdatedCSS; + type: 'getCurrentContextResponse'; } /** - * A constrained set of styling properties that should be applied to the frame. Note - * `position` cannot be set, and should always be `fixed`. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface UpdatedCSS { - /** - * The initial bottom property to apply to the iframe. - */ - bottom?: string; - /** - * The updated height of the iframe. - */ - height?: string; - /** - * The initial left property to apply to the iframe. - */ - left?: string; - /** - * The updated maximum height to apply to the iframe. - */ - maxHeight?: string; - /** - * The updated maximum with to apply to the iframe. - */ - maxWidth?: string; - /** - * The initial right property to apply to the iframe. - */ - right?: string; - /** - * The initial top property to apply to the iframe. - */ - top?: string; - /** - * The updated transition property to apply to the iframe. - */ - transition?: string; - /** - * The updated width of the iframe. - */ - width?: string; +export interface GetCurrentContextResponsePayload { + error?: PurpleError; /** - * The updated zIndex to apply to the iframe. + * The most recently broadcast context object (of the specified type, if one was specified), + * or `null` if none was available in the channel. */ - zIndex?: string; - [property: string]: any; + context?: null | Context; } /** - * Identifies the type of the message to or from the user interface frame. + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A request for details of instances of a particular app. + * Request to retrieve information about the FDC3 Desktop Agent implementation and the + * metadata of the calling application according to the Desktop Agent. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindInstancesRequest { +export interface GetInfoRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2085,20 +2166,18 @@ export interface FindInstancesRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindInstancesRequestPayload; + payload: GetInfoRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'findInstancesRequest'; + type: 'getInfoRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindInstancesRequestPayload { - app: AppIdentifier; -} +export interface GetInfoRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2106,12 +2185,12 @@ export interface FindInstancesRequestPayload { */ /** - * A response to a findInstances request. + * A response to a getInfo request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindInstancesResponse { +export interface GetInfoResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2121,67 +2200,81 @@ export interface FindInstancesResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindInstancesResponsePayload; + payload: GetInfoResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'findInstancesResponse'; + type: 'getInfoResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - * - * The message payload contains a flag indicating whether the API call was successful, plus - * any return values for the FDC3 API function called, or indicating that the request - * resulted in an error and including a standardized error message. */ -export interface FindInstancesResponsePayload { - error?: FindInstancesErrors; - appIdentifiers?: AppMetadata[]; +export interface GetInfoResponsePayload { + error?: ResponsePayloadError; + implementationMetadata?: ImplementationMetadata; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). - * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). - * - * Unique identifier for a for an attempt to connect to a Desktop Agent. A Unique UUID - * should be used in the first (WCP1Hello) message and should be quoted in all subsequent - * messages to link them to the same connection attempt. - * - * Unique identifier for a request or event message. Required in all message types. - * - * Unique identifier for a response to a specific message and must always be accompanied by - * a RequestUuid. - * - * Unique identifier for a `listener` object returned by a Desktop Agent to an app in - * response to addContextListener, addIntentListener or one of the PrivateChannel event - * listeners and used to identify it in messages (e.g. when unsubscribing). + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. * - * Unique identifier for an event message sent from a Desktop Agent to an app. + * Includes Metadata for the current application. * - * Should be set if the raiseIntent request returned an error. + * Metadata relating to the FDC3 Desktop Agent implementation and its provider. */ -export type FindInstancesErrors = - | 'MalformedContext' - | 'DesktopAgentNotFound' - | 'ResolverUnavailable' - | 'IntentDeliveryFailed' - | 'NoAppsFound' - | 'ResolverTimeout' - | 'TargetAppUnavailable' - | 'TargetInstanceUnavailable' - | 'UserCancelledResolution' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; +export interface ImplementationMetadata { + /** + * The calling application instance's own metadata, according to the Desktop Agent (MUST + * include at least the `appId` and `instanceId`). + */ + appMetadata: AppMetadata; + /** + * The version number of the FDC3 specification that the implementation provides. + * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. + */ + fdc3Version: string; + /** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ + optionalFeatures: OptionalFeatures; + /** + * The name of the provider of the Desktop Agent implementation (e.g. Finsemble, Glue42, + * OpenFin etc.). + */ + provider: string; + /** + * The version of the provider of the Desktop Agent implementation (e.g. 5.3.0). + */ + providerVersion?: string; +} + +/** + * Metadata indicating whether the Desktop Agent implements optional features of + * the Desktop Agent API. + */ +export interface OptionalFeatures { + /** + * Used to indicate whether the experimental Desktop Agent Bridging + * feature is implemented by the Desktop Agent. + */ + DesktopAgentBridging: boolean; + /** + * Used to indicate whether the exposure of 'originating app metadata' for + * context and intent messages is supported by the Desktop Agent. + */ + OriginatingAppMetadata: boolean; + /** + * Used to indicate whether the optional `fdc3.joinUserChannel`, + * `fdc3.getCurrentChannel` and `fdc3.leaveCurrentChannel` are implemented by + * the Desktop Agent. + */ + UserChannelMembershipAPIs: boolean; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2189,11 +2282,12 @@ export type FindInstancesErrors = */ /** - * A request for details of apps available to resolve a particular intent and context pair. + * Request to return a Channel with an auto-generated identity that is intended for private + * communication between applications. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentRequest { +export interface GetOrCreateChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2201,21 +2295,22 @@ export interface FindIntentRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentRequestPayload; + payload: GetOrCreateChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'findIntentRequest'; + type: 'getOrCreateChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentRequestPayload { - context?: Context; - intent: string; - resultType?: string; +export interface GetOrCreateChannelRequestPayload { + /** + * The id of the channel to return + */ + channelId: string; } /** @@ -2224,12 +2319,12 @@ export interface FindIntentRequestPayload { */ /** - * A response to a findIntent request. + * A response to a getOrCreateChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentResponse { +export interface GetOrCreateChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2239,12 +2334,12 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentResponsePayload; + payload: GetOrCreateChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'findIntentResponse'; + type: 'getOrCreateChannelResponse'; } /** @@ -2252,9 +2347,9 @@ export interface FindIntentResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentResponsePayload { - error?: FindInstancesErrors; - appIntent?: AppIntent; +export interface GetOrCreateChannelResponsePayload { + error?: PurpleError; + channel?: Channel; } /** @@ -2263,12 +2358,11 @@ export interface FindIntentResponsePayload { */ /** - * A request for details of intents and apps available to resolve them for a particular - * context. + * Request to retrieve a list of the User Channels available for the app to join. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface FindIntentsByContextRequest { +export interface GetUserChannelsRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2276,21 +2370,18 @@ export interface FindIntentsByContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: FindIntentsByContextRequestPayload; + payload: GetUserChannelsRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'findIntentsByContextRequest'; + type: 'getUserChannelsRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface FindIntentsByContextRequestPayload { - context: Context; - resultType?: string; -} +export interface GetUserChannelsRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2298,12 +2389,12 @@ export interface FindIntentsByContextRequestPayload { */ /** - * A response to a findIntentsByContext request. + * A response to a getUserChannels request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface FindIntentsByContextResponse { +export interface GetUserChannelsResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2313,12 +2404,12 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: FindIntentsByContextResponsePayload; + payload: GetUserChannelsResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'findIntentsByContextResponse'; + type: 'getUserChannelsResponse'; } /** @@ -2326,9 +2417,9 @@ export interface FindIntentsByContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface FindIntentsByContextResponsePayload { - error?: FindInstancesErrors; - appIntents?: AppIntent[]; +export interface GetUserChannelsResponsePayload { + error?: PurpleError; + userChannels?: Channel[]; } /** @@ -2337,11 +2428,12 @@ export interface FindIntentsByContextResponsePayload { */ /** - * A request for metadata about an app. + * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent + * and indicates that an application window or frame is still alive. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetAppMetadataRequest { +export interface HeartbeatAcknowledgementRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2349,19 +2441,22 @@ export interface GetAppMetadataRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetAppMetadataRequestPayload; + payload: HeartbeatAcknowledgementRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getAppMetadataRequest'; + type: 'heartbeatAcknowledgementRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetAppMetadataRequestPayload { - app: AppIdentifier; +export interface HeartbeatAcknowledgementRequestPayload { + /** + * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. + */ + heartbeatEventUuid: string; } /** @@ -2370,38 +2465,32 @@ export interface GetAppMetadataRequestPayload { */ /** - * A response to a getAppMetadata request. + * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is + * alive and that the application should send a heartbeatResponseRequest to the agent in + * response. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface GetAppMetadataResponse { +export interface HeartbeatEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: GetAppMetadataResponsePayload; + payload: HeartbeatEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getAppMetadataResponse'; + type: 'heartbeatEvent'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface GetAppMetadataResponsePayload { - error?: FindInstancesErrors; - appMetadata?: AppMetadata; -} +export interface HeartbeatEventPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2409,69 +2498,48 @@ export interface GetAppMetadataResponsePayload { */ /** - * A request to return the Channel object for the current User channel membership. Returns - * `null` if the app is not joined to a channel. + * An event message from the Desktop Agent to an app indicating that it has been selected to + * resolve a raised intent and context. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface GetCurrentChannelRequest { +export interface IntentEvent { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerRequestMeta; + meta: BroadcastEventMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ - payload: GetCurrentChannelRequestPayload; + payload: IntentEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getCurrentChannelRequest'; + type: 'intentEvent'; } /** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface GetCurrentChannelRequestPayload {} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. - */ - -/** - * A response to a getCurrentChannel request. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface GetCurrentChannelResponse { +export interface IntentEventPayload { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * The context object passed with the raised intent. */ - meta: AddContextListenerResponseMeta; + context: Context; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The intent that was raised. */ - payload: GetCurrentChannelResponsePayload; + intent: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Details of the application instance that raised the intent. */ - type: 'getCurrentChannelResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetCurrentChannelResponsePayload { - error?: ResponsePayloadError; - channel?: Channel | null; + originatingApp?: AppIdentifier; + /** + * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates + * to. + */ + raiseIntentRequestUuid: string; } /** @@ -2480,13 +2548,11 @@ export interface GetCurrentChannelResponsePayload { */ /** - * A request to return the current context (either of a specified type or most recent - * broadcast) of a specified Channel. Returns `null` if no context (of the requested type if - * one was specified) is available in the channel. + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetCurrentContextRequest { +export interface IntentListenerUnsubscribeRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2494,27 +2560,19 @@ export interface GetCurrentContextRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetCurrentContextRequestPayload; + payload: IntentListenerUnsubscribeRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getCurrentContextRequest'; + type: 'intentListenerUnsubscribeRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetCurrentContextRequestPayload { - /** - * The id of the channel to return the current context of. - */ - channelId: string; - /** - * The type of context to return for OR `null` indicating that the most recently broadcast - * context on the channel should be returned. - */ - contextType: null | string; +export interface IntentListenerUnsubscribeRequestPayload { + listenerUUID: string; } /** @@ -2523,12 +2581,12 @@ export interface GetCurrentContextRequestPayload { */ /** - * A response to a getCurrentContext request. + * A response to a intentListenerUnsubscribe request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetCurrentContextResponse { +export interface IntentListenerUnsubscribeResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2538,26 +2596,12 @@ export interface GetCurrentContextResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetCurrentContextResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getCurrentContextResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetCurrentContextResponsePayload { - error?: PurpleError; - /** - * The most recently broadcast context object (of the specified type, if one was specified), - * or `null` if none was available in the channel. - */ - context?: null | Context; + type: 'intentListenerUnsubscribeResponse'; } /** @@ -2566,12 +2610,13 @@ export interface GetCurrentContextResponsePayload { */ /** - * Request to retrieve information about the FDC3 Desktop Agent implementation and the - * metadata of the calling application according to the Desktop Agent. + * A request to deliver a result for an intent (which may include a `void` result that just + * indicates that the handler has run, returning no result). The result is tied to the + * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetInfoRequest { +export interface IntentResultRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2579,18 +2624,33 @@ export interface GetInfoRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetInfoRequestPayload; + payload: IntentResultRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getInfoRequest'; + type: 'intentResultRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetInfoRequestPayload {} +export interface IntentResultRequestPayload { + /** + * The eventUuid value of the intentEvent that the result being sent relates to. + */ + intentEventUuid: string; + intentResult: IntentResult; + /** + * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + */ + raiseIntentRequestUuid: string; +} + +export interface IntentResult { + context?: Context; + channel?: Channel; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2598,12 +2658,12 @@ export interface GetInfoRequestPayload {} */ /** - * A response to a getInfo request. + * A response to a request to deliver an intent result. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetInfoResponse { +export interface IntentResultResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2613,22 +2673,12 @@ export interface GetInfoResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetInfoResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'getInfoResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface GetInfoResponsePayload { - error?: ResponsePayloadError; - implementationMetadata?: ImplementationMetadata; + */ + type: 'intentResultResponse'; } /** @@ -2637,12 +2687,13 @@ export interface GetInfoResponsePayload { */ /** - * Request to return a Channel with an auto-generated identity that is intended for private - * communication between applications. + * Request to join the app to the specified User channel. On successfully joining a channel, + * client code should make subsequent requests to get the current context of that channel + * for all registered context listeners and then call their handlers with it. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetOrCreateChannelRequest { +export interface JoinUserChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2650,20 +2701,20 @@ export interface GetOrCreateChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetOrCreateChannelRequestPayload; + payload: JoinUserChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getOrCreateChannelRequest'; + type: 'joinUserChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetOrCreateChannelRequestPayload { +export interface JoinUserChannelRequestPayload { /** - * The id of the channel to return + * The id of the channel to join. */ channelId: string; } @@ -2674,12 +2725,14 @@ export interface GetOrCreateChannelRequestPayload { */ /** - * A response to a getOrCreateChannel request. + * A response to a joinUserChannel request. On receipt of this response, client code should + * make subsequent requests to get the current context of that channel for all registered + * context listeners and then call their handlers with it. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetOrCreateChannelResponse { +export interface JoinUserChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2689,12 +2742,12 @@ export interface GetOrCreateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetOrCreateChannelResponsePayload; + payload: JoinUserChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getOrCreateChannelResponse'; + type: 'joinUserChannelResponse'; } /** @@ -2702,9 +2755,8 @@ export interface GetOrCreateChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetOrCreateChannelResponsePayload { +export interface JoinUserChannelResponsePayload { error?: PurpleError; - channel?: Channel; } /** @@ -2713,11 +2765,11 @@ export interface GetOrCreateChannelResponsePayload { */ /** - * Request to retrieve a list of the User Channels available for the app to join. + * Request to remove the app from any User channel membership. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface GetUserChannelsRequest { +export interface LeaveCurrentChannelRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2725,18 +2777,18 @@ export interface GetUserChannelsRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: GetUserChannelsRequestPayload; + payload: LeaveCurrentChannelRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'getUserChannelsRequest'; + type: 'leaveCurrentChannelRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface GetUserChannelsRequestPayload {} +export interface LeaveCurrentChannelRequestPayload {} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2744,12 +2796,12 @@ export interface GetUserChannelsRequestPayload {} */ /** - * A response to a getUserChannels request. + * A response to a leaveCurrentChannel request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface GetUserChannelsResponse { +export interface LeaveCurrentChannelResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2759,12 +2811,12 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: GetUserChannelsResponsePayload; + payload: LeaveCurrentChannelResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'getUserChannelsResponse'; + type: 'leaveCurrentChannelResponse'; } /** @@ -2772,9 +2824,8 @@ export interface GetUserChannelsResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface GetUserChannelsResponsePayload { +export interface LeaveCurrentChannelResponsePayload { error?: PurpleError; - userChannels?: Channel[]; } /** @@ -2783,12 +2834,11 @@ export interface GetUserChannelsResponsePayload { */ /** - * A request that serves as an acknowledgement of a heartbeat event from the Desktop Agent - * and indicates that an application window or frame is still alive. + * A request to open an application. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface HeartbeatAcknowledgementRequest { +export interface OpenRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2796,22 +2846,25 @@ export interface HeartbeatAcknowledgementRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: HeartbeatAcknowledgementRequestPayload; + payload: OpenRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'heartbeatAcknowledgementRequest'; + type: 'openRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface HeartbeatAcknowledgementRequestPayload { +export interface OpenRequestPayload { + app: AppIdentifier; /** - * The eventUuid value of the HeartbeatEvent that the acknowledgement being sent relates to. + * If a Context object is passed in, this object will be provided to the opened application + * via a contextListener. The Context argument is functionally equivalent to opening the + * target app with no context and broadcasting the context directly to it. */ - heartbeatEventUuid: string; + context?: Context; } /** @@ -2820,82 +2873,58 @@ export interface HeartbeatAcknowledgementRequestPayload { */ /** - * A heartbeat message from the Desktop Agent to an app indicating that the Desktop Agent is - * alive and that the application should send a heartbeatResponseRequest to the agent in - * response. + * A response to a open request. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. */ -export interface HeartbeatEvent { +export interface OpenResponse { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ - meta: BroadcastEventMeta; + meta: AddContextListenerResponseMeta; /** - * The message payload contains details of the event that the app is being notified about. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ - payload: HeartbeatEventPayload; + payload: OpenResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'heartbeatEvent'; + type: 'openResponse'; } /** - * The message payload contains details of the event that the app is being notified about. - */ -export interface HeartbeatEventPayload {} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that it has been selected to - * resolve a raised intent and context. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. */ -export interface IntentEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: IntentEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'intentEvent'; +export interface OpenResponsePayload { + error?: OpenErrorResponsePayload; + appIdentifier?: AppIdentifier; } /** - * The message payload contains details of the event that the app is being notified about. + * Constants representing the errors that can be encountered when calling the `open` method + * on the DesktopAgent object (`fdc3`). + * + * Constants representing the errors that can be encountered when calling the `findIntent`, + * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the + * DesktopAgent (`fdc3`). */ -export interface IntentEventPayload { - /** - * The context object passed with the raised intent. - */ - context: Context; - /** - * The intent that was raised. - */ - intent: string; - /** - * Details of the application instance that raised the intent. - */ - originatingApp?: AppIdentifier; - /** - * The requestUuid value of the raiseIntentRequest that the intentEvent being sent relates - * to. - */ - raiseIntentRequestUuid: string; -} +export type OpenErrorResponsePayload = + | 'MalformedContext' + | 'AppNotFound' + | 'AppTimeout' + | 'DesktopAgentNotFound' + | 'ErrorOnLaunch' + | 'ResolverUnavailable' + | 'AgentDisconnected' + | 'NotConnectedToBridge' + | 'ResponseToBridgeTimedOut' + | 'MalformedMessage'; /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -2903,11 +2932,11 @@ export interface IntentEventPayload { */ /** - * A request to unsubscribe a context listener. + * A request to add an event listener to a specific PrivateChannel. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentListenerUnsubscribeRequest { +export interface PrivateChannelAddEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2915,33 +2944,46 @@ export interface IntentListenerUnsubscribeRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentListenerUnsubscribeRequestPayload; + payload: PrivateChannelAddEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'intentListenerUnsubscribeRequest'; + type: 'privateChannelAddEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentListenerUnsubscribeRequestPayload { - listenerUUID: string; +export interface PrivateChannelAddEventListenerRequestPayload { + /** + * The type of PrivateChannel event that the listener should be applied to, or null for all + * event types. + */ + listenerType: PrivateChannelEventType | null; + /** + * The Id of the PrivateChannel that the listener should be added to. + */ + privateChannelId: string; } +/** + * Type defining valid type strings for Private Channel events. + */ +export type PrivateChannelEventType = 'addContextListener' | 'unsubscribe' | 'disconnect'; + /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * A response to a intentListenerUnsubscribe request. + * A response to a privateChannelAddEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface IntentListenerUnsubscribeResponse { +export interface PrivateChannelAddEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -2951,12 +2993,22 @@ export interface IntentListenerUnsubscribeResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: BroadcastResponseResponsePayload; + payload: PrivateChannelAddEventListenerResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'intentListenerUnsubscribeResponse'; + type: 'privateChannelAddEventListenerResponse'; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface PrivateChannelAddEventListenerResponsePayload { + error?: PurpleError; + listenerUUID?: string; } /** @@ -2965,13 +3017,12 @@ export interface IntentListenerUnsubscribeResponse { */ /** - * A request to deliver a result for an intent (which may include a `void` result that just - * indicates that the handler has run, returning no result). The result is tied to the - * intentEvent it relates to by quoting the `eventUuid` of the intentEvent in its payload. + * Request that indicates that a participant will no longer interact with a specified + * `PrivateChannel`. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface IntentResultRequest { +export interface PrivateChannelDisconnectRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -2979,61 +3030,102 @@ export interface IntentResultRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: IntentResultRequestPayload; + payload: PrivateChannelDisconnectRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'intentResultRequest'; + type: 'privateChannelDisconnectRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface IntentResultRequestPayload { - /** - * The eventUuid value of the intentEvent that the result being sent relates to. - */ - intentEventUuid: string; - intentResult: IntentResult; +export interface PrivateChannelDisconnectRequestPayload { /** - * The requestUuid value of the raiseIntentRequest that the result being sent relates to. + * The Id of the Channel that should be disconnected from */ - raiseIntentRequestUuid: string; + channelId: string; } -export interface IntentResult { - context?: Context; - channel?: Channel; +/** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Request' appended. + */ + +/** + * A response to a privateChannelDisconnect request. + * + * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the + * payload contains an `error` property, the request was unsuccessful. + */ +export interface PrivateChannelDisconnectResponse { + /** + * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + */ + meta: AddContextListenerResponseMeta; + /** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ + payload: PrivateChannelDisconnectResponsePayload; + /** + * Identifies the type of the message and it is typically set to the FDC3 function name that + * the message relates to, e.g. 'findIntent', with 'Response' appended. + */ + type: 'privateChannelDisconnectResponse'; +} + +/** + * A payload for a response to an API call that will contain any return values or an `error` + * property containing a standardized error message indicating that the request was + * unsuccessful. + */ +export interface PrivateChannelDisconnectResponsePayload { + error?: PurpleError; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a request to deliver an intent result. + * An event message from the Desktop Agent to an app indicating that another app has added a + * context listener to a specific PrivateChannel. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface IntentResultResponse { +export interface PrivateChannelOnAddContextListenerEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: BroadcastResponseResponsePayload; + payload: PrivateChannelOnAddContextListenerEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'intentResultResponse'; + type: 'privateChannelOnAddContextListenerEvent'; +} + +/** + * The message payload contains details of the event that the app is being notified about. + */ +export interface PrivateChannelOnAddContextListenerEventPayload { + /** + * The type of the context listener added to the channel by another app, or null if it will + * listen to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was added to. + */ + privateChannelId: string; } /** @@ -3042,76 +3134,77 @@ export interface IntentResultResponse { */ /** - * Request to join the app to the specified User channel. On successfully joining a channel, - * client code should make subsequent requests to get the current context of that channel - * for all registered context listeners and then call their handlers with it. + * An event message from the Desktop Agent to an app indicating that another app has + * disconnected from a specific PrivateChannel and will no longer interact with it. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface JoinUserChannelRequest { +export interface PrivateChannelOnDisconnectEvent { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerRequestMeta; + meta: BroadcastEventMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ - payload: JoinUserChannelRequestPayload; + payload: PrivateChannelOnDisconnectEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'joinUserChannelRequest'; + type: 'privateChannelOnDisconnectEvent'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload contains details of the event that the app is being notified about. */ -export interface JoinUserChannelRequestPayload { +export interface PrivateChannelOnDisconnectEventPayload { /** - * The id of the channel to join. + * The Id of the PrivateChannel that the app has disconnected from. */ - channelId: string; + privateChannelId: string; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a joinUserChannel request. On receipt of this response, client code should - * make subsequent requests to get the current context of that channel for all registered - * context listeners and then call their handlers with it. + * An event message from the Desktop Agent to an app indicating that another app has + * unsubscribed a context listener from a specific PrivateChannel. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message from a Desktop Agent to an FDC3-enabled app representing an event. */ -export interface JoinUserChannelResponse { +export interface PrivateChannelOnUnsubscribeEvent { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. */ - meta: AddContextListenerResponseMeta; + meta: BroadcastEventMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ - payload: JoinUserChannelResponsePayload; + payload: PrivateChannelOnUnsubscribeEventPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'joinUserChannelResponse'; + type: 'privateChannelOnUnsubscribeEvent'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload contains details of the event that the app is being notified about. */ -export interface JoinUserChannelResponsePayload { - error?: PurpleError; +export interface PrivateChannelOnUnsubscribeEventPayload { + /** + * The type of the context listener unsubscribed from the channel by another app, or null if + * it was listening to all types. + */ + contextType: null | string; + /** + * The Id of the PrivateChannel that the listener was unsubscribed from. + */ + privateChannelId: string; } /** @@ -3120,11 +3213,11 @@ export interface JoinUserChannelResponsePayload { */ /** - * Request to remove the app from any User channel membership. + * A request to unsubscribe a context listener. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface LeaveCurrentChannelRequest { +export interface PrivateChannelUnsubscribeEventListenerRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3132,18 +3225,20 @@ export interface LeaveCurrentChannelRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: LeaveCurrentChannelRequestPayload; + payload: PrivateChannelUnsubscribeEventListenerRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'leaveCurrentChannelRequest'; + type: 'privateChannelUnsubscribeEventListenerRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface LeaveCurrentChannelRequestPayload {} +export interface PrivateChannelUnsubscribeEventListenerRequestPayload { + listenerUUID: string; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -3151,12 +3246,12 @@ export interface LeaveCurrentChannelRequestPayload {} */ /** - * A response to a leaveCurrentChannel request. + * A response to a privateChannelUnsubscribeEventListener request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface LeaveCurrentChannelResponse { +export interface PrivateChannelUnsubscribeEventListenerResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3166,21 +3261,12 @@ export interface LeaveCurrentChannelResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: LeaveCurrentChannelResponsePayload; + payload: BroadcastResponseResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'leaveCurrentChannelResponse'; -} - -/** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - */ -export interface LeaveCurrentChannelResponsePayload { - error?: PurpleError; + type: 'privateChannelUnsubscribeEventListenerResponse'; } /** @@ -3189,11 +3275,11 @@ export interface LeaveCurrentChannelResponsePayload { */ /** - * A request to open an application. + * A request to raise an unspecified intent for a specified context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface OpenRequest { +export interface RaiseIntentForContextRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3201,25 +3287,20 @@ export interface OpenRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: OpenRequestPayload; + payload: RaiseIntentForContextRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'openRequest'; + type: 'raiseIntentForContextRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface OpenRequestPayload { - app: AppIdentifier; - /** - * If a Context object is passed in, this object will be provided to the opened application - * via a contextListener. The Context argument is functionally equivalent to opening the - * target app with no context and broadcasting the context directly to it. - */ - context?: Context; +export interface RaiseIntentForContextRequestPayload { + app?: AppIdentifier; + context: Context; } /** @@ -3228,12 +3309,12 @@ export interface OpenRequestPayload { */ /** - * A response to a open request. + * A response to a raiseIntentForContext request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface OpenResponse { +export interface RaiseIntentForContextResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3242,44 +3323,90 @@ export interface OpenResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). */ - payload: OpenResponsePayload; + payload: RaiseIntentForContextResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'openResponse'; + type: 'raiseIntentForContextResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntentForContext request, each of which sets a + * single property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntents`) or Error (`error`). + * + * Response to a raiseIntentForContext request that needs additional resolution (i.e. show + * an intent resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface OpenResponsePayload { - error?: OpenErrorResponsePayload; - appIdentifier?: AppIdentifier; +export interface RaiseIntentForContextResponsePayload { + /** + * Should be set if the raiseIntent request returned an error. + */ + error?: FindInstancesErrors; + /** + * Used if the raiseIntent request was successfully resolved. + */ + intentResolution?: IntentResolution; + /** + * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing + * an intent resolver) before it can be handled. + */ + appIntents?: AppIntent[]; } /** - * Constants representing the errors that can be encountered when calling the `open` method - * on the DesktopAgent object (`fdc3`). + * Used if the raiseIntent request was successfully resolved. * - * Constants representing the errors that can be encountered when calling the `findIntent`, - * `findIntentsByContext`, `raiseIntent` or `raiseIntentForContext` methods on the - * DesktopAgent (`fdc3`). + * IntentResolution provides a standard format for data returned upon resolving an intent. + * + * ```javascript + * //resolve a "Chain" type intent + * let resolution = await agent.raiseIntent("intentName", context); + * + * //resolve a "Client-Service" type intent with a data response or a Channel + * let resolution = await agent.raiseIntent("intentName", context); + * try { + * const result = await resolution.getResult(); + * if (result && result.broadcast) { + * console.log(`${resolution.source} returned a channel with id ${result.id}`); + * } else if (result){ + * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); + * } else { + * console.error(`${resolution.source} didn't return data` + * } + * } catch(error) { + * console.error(`${resolution.source} returned an error: ${error}`); + * } + * + * // Use metadata about the resolving app instance to target a further intent + * await agent.raiseIntent("intentName", context, resolution.source); + * ``` */ -export type OpenErrorResponsePayload = - | 'MalformedContext' - | 'AppNotFound' - | 'AppTimeout' - | 'DesktopAgentNotFound' - | 'ErrorOnLaunch' - | 'ResolverUnavailable' - | 'AgentDisconnected' - | 'NotConnectedToBridge' - | 'ResponseToBridgeTimedOut' - | 'MalformedMessage'; +export interface IntentResolution { + /** + * The intent that was raised. May be used to determine which intent the user + * chose in response to `fdc3.raiseIntentForContext()`. + */ + intent: string; + /** + * Identifier for the app instance that was selected (or started) to resolve the intent. + * `source.instanceId` MUST be set, indicating the specific app instance that + * received the intent. + */ + source: AppIdentifier; +} /** * Identifies the type of the message and it is typically set to the FDC3 function name that @@ -3287,11 +3414,11 @@ export type OpenErrorResponsePayload = */ /** - * A request to add an event listener to a specific PrivateChannel. + * A request to raise an intent for a context. * * A request message from an FDC3-enabled app to a Desktop Agent. */ -export interface PrivateChannelAddEventListenerRequest { +export interface RaiseIntentRequest { /** * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. */ @@ -3299,46 +3426,35 @@ export interface PrivateChannelAddEventListenerRequest { /** * The message payload typically contains the arguments to FDC3 API functions. */ - payload: PrivateChannelAddEventListenerRequestPayload; + payload: RaiseIntentRequestPayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ - type: 'privateChannelAddEventListenerRequest'; + type: 'raiseIntentRequest'; } /** * The message payload typically contains the arguments to FDC3 API functions. */ -export interface PrivateChannelAddEventListenerRequestPayload { - /** - * The type of PrivateChannel event that the listener should be applied to, or null for all - * event types. - */ - listenerType: PrivateChannelEventType | null; - /** - * The Id of the PrivateChannel that the listener should be added to. - */ - privateChannelId: string; +export interface RaiseIntentRequestPayload { + app?: AppIdentifier; + context: Context; + intent: string; } -/** - * Type defining valid type strings for Private Channel events. - */ -export type PrivateChannelEventType = 'addContextListener' | 'unsubscribe' | 'disconnect'; - /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Request' appended. */ /** - * A response to a privateChannelAddEventListener request. + * A response to a raiseIntent request. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelAddEventListenerResponse { +export interface RaiseIntentResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3347,74 +3463,63 @@ export interface PrivateChannelAddEventListenerResponse { * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. + * + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). */ - payload: PrivateChannelAddEventListenerResponsePayload; + payload: RaiseIntentResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'privateChannelAddEventListenerResponse'; + type: 'raiseIntentResponse'; } /** * A payload for a response to an API call that will contain any return values or an `error` * property containing a standardized error message indicating that the request was * unsuccessful. - */ -export interface PrivateChannelAddEventListenerResponsePayload { - error?: PurpleError; - listenerUUID?: string; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * Request that indicates that a participant will no longer interact with a specified - * `PrivateChannel`. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * There are 3 possible responses to a raiseIntent request, each of which sets a single + * property in the payload: Success (`intentResolution`), Needs further resolution + * (`appIntent`) or Error (`error`). + * + * Response to a raiseIntent request that needs additional resolution (i.e. show an intent + * resolver UI). + * + * Used if a raiseIntent request resulted in an error. */ -export interface PrivateChannelDisconnectRequest { - /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. - */ - meta: AddContextListenerRequestMeta; +export interface RaiseIntentResponsePayload { /** - * The message payload typically contains the arguments to FDC3 API functions. + * Should be set if the raiseIntent request returned an error. */ - payload: PrivateChannelDisconnectRequestPayload; + error?: FindInstancesErrors; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Used if the raiseIntent request was successfully resolved. */ - type: 'privateChannelDisconnectRequest'; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface PrivateChannelDisconnectRequestPayload { + intentResolution?: IntentResolution; /** - * The Id of the Channel that should be disconnected from + * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent + * resolver) before it can be handled. */ - channelId: string; + appIntent?: AppIntent; } /** * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * the message relates to, e.g. 'findIntent', with 'Response' appended. */ /** - * A response to a privateChannelDisconnect request. + * A secondary response to a request to raise an intent used to deliver the intent result. + * This message should quote the original requestUuid of the raiseIntentRequest message in + * its `meta.requestUuid` field. * * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the * payload contains an `error` property, the request was unsuccessful. */ -export interface PrivateChannelDisconnectResponse { +export interface RaiseIntentResultResponse { /** * Metadata for messages sent by a Desktop Agent to an app in response to an API call. */ @@ -3424,12 +3529,12 @@ export interface PrivateChannelDisconnectResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ - payload: PrivateChannelDisconnectResponsePayload; + payload: RaiseIntentResultResponsePayload; /** * Identifies the type of the message and it is typically set to the FDC3 function name that * the message relates to, e.g. 'findIntent', with 'Response' appended. */ - type: 'privateChannelDisconnectResponse'; + type: 'raiseIntentResultResponse'; } /** @@ -3437,50 +3542,9 @@ export interface PrivateChannelDisconnectResponse { * property containing a standardized error message indicating that the request was * unsuccessful. */ -export interface PrivateChannelDisconnectResponsePayload { - error?: PurpleError; -} - -/** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that another app has added a - * context listener to a specific PrivateChannel. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. - */ -export interface PrivateChannelOnAddContextListenerEvent { - /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. - */ - meta: BroadcastEventMeta; - /** - * The message payload contains details of the event that the app is being notified about. - */ - payload: PrivateChannelOnAddContextListenerEventPayload; - /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - type: 'privateChannelOnAddContextListenerEvent'; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface PrivateChannelOnAddContextListenerEventPayload { - /** - * The type of the context listener added to the channel by another app, or null if it will - * listen to all types. - */ - contextType: null | string; - /** - * The Id of the PrivateChannel that the listener was added to. - */ - privateChannelId: string; +export interface RaiseIntentResultResponsePayload { + error?: ResponsePayloadError; + intentResult?: IntentResult; } /** @@ -3489,501 +3553,363 @@ export interface PrivateChannelOnAddContextListenerEventPayload { */ /** - * An event message from the Desktop Agent to an app indicating that another app has - * disconnected from a specific PrivateChannel and will no longer interact with it. + * Hello message sent by an application to a parent window or frame when attempting to + * establish connectivity to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelOnDisconnectEvent { +export interface WebConnectionProtocol1Hello { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * Metadata for a Web Connection Protocol message. */ - meta: BroadcastEventMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload contains details of the event that the app is being notified about. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelOnDisconnectEventPayload; + payload: WebConnectionProtocol1HelloPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'privateChannelOnDisconnectEvent'; + type: 'WCP1Hello'; } /** - * The message payload contains details of the event that the app is being notified about. + * Metadata for a Web Connection Protocol message. */ -export interface PrivateChannelOnDisconnectEventPayload { - /** - * The Id of the PrivateChannel that the app has disconnected from. - */ - privateChannelId: string; +export interface WebConnectionProtocol1HelloMeta { + connectionAttemptUuid: string; + timestamp: Date; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * An event message from the Desktop Agent to an app indicating that another app has - * unsubscribed a context listener from a specific PrivateChannel. - * - * A message from a Desktop Agent to an FDC3-enabled app representing an event. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelOnUnsubscribeEvent { +export interface WebConnectionProtocol1HelloPayload { /** - * Metadata for messages sent by a Desktop Agent to an app notifying it of an event. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - meta: BroadcastEventMeta; + actualUrl: string; /** - * The message payload contains details of the event that the app is being notified about. + * A flag that may be used to indicate that a channel selector user interface is or is not + * required. Set to `false` if the app includes its own interface for selecting channels or + * does not work with user channels. */ - payload: PrivateChannelOnUnsubscribeEventPayload; + channelSelector?: boolean; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * The version of FDC3 API that the app supports. */ - type: 'privateChannelOnUnsubscribeEvent'; -} - -/** - * The message payload contains details of the event that the app is being notified about. - */ -export interface PrivateChannelOnUnsubscribeEventPayload { + fdc3Version: string; /** - * The type of the context listener unsubscribed from the channel by another app, or null if - * it was listening to all types. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - contextType: null | string; + identityUrl: string; /** - * The Id of the PrivateChannel that the listener was unsubscribed from. + * A flag that may be used to indicate that an intent resolver is or is not required. Set to + * `false` if no intents, or only targeted intents, are raised. */ - privateChannelId: string; + intentResolver?: boolean; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to unsubscribe a context listener. + * Response from a Desktop Agent to an application requesting access to it indicating that + * it should load a specified URL into a hidden iframe in order to establish connectivity to + * a Desktop Agent. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerRequest { +export interface WebConnectionProtocol2LoadURL { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: PrivateChannelUnsubscribeEventListenerRequestPayload; + payload: WebConnectionProtocol2LoadURLPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: 'privateChannelUnsubscribeEventListenerRequest'; + type: 'WCP2LoadUrl'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface PrivateChannelUnsubscribeEventListenerRequestPayload { - listenerUUID: string; +export interface WebConnectionProtocol2LoadURLPayload { + /** + * A URL which can be used to establish communication with the Desktop Agent, via loading + * the URL into an iframe and restarting the Web Connection protocol with the iframe as the + * target. + */ + iframeUrl: string; + [property: string]: any; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a privateChannelUnsubscribeEventListener request. + * Handshake message sent by the Desktop Agent to the app (with a MessagePort appended) that + * should be used for subsequent communication steps. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface PrivateChannelUnsubscribeEventListenerResponse { +export interface WebConnectionProtocol3Handshake { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: BroadcastResponseResponsePayload; + payload: WebConnectionProtocol3HandshakePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'privateChannelUnsubscribeEventListenerResponse'; + type: 'WCP3Handshake'; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. - */ - -/** - * A request to raise an unspecified intent for a specified context. - * - * A request message from an FDC3-enabled app to a Desktop Agent. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextRequest { +export interface WebConnectionProtocol3HandshakePayload { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Indicates whether a channel selector user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the channel selector (as the + * Desktop Agent will handle it another way). */ - meta: AddContextListenerRequestMeta; + channelSelectorUrl: boolean | string; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The version of FDC3 API that the Desktop Agent will provide support for. */ - payload: RaiseIntentForContextRequestPayload; + fdc3Version: string; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Indicates whether an intent resolver user interface is required and the URL to use to do + * so. Set to `true` to use the default or `false` to disable the intent resolver (as the + * Desktop Agent will handle it another way). */ - type: 'raiseIntentForContextRequest'; -} - -/** - * The message payload typically contains the arguments to FDC3 API functions. - */ -export interface RaiseIntentForContextRequestPayload { - app?: AppIdentifier; - context: Context; + intentResolverUrl: boolean | string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntentForContext request. + * Identity Validation request from an app attempting to connect to a Desktop Agent. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentForContextResponse { +export interface WebConnectionProtocol4ValidateAppIdentity { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentForContextResponsePayload; + payload: WebConnectionProtocol4ValidateAppIdentityPayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentForContextResponse'; + type: 'WCP4ValidateAppIdentity'; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntentForContext request, each of which sets a - * single property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntents`) or Error (`error`). - * - * Response to a raiseIntentForContext request that needs additional resolution (i.e. show - * an intent resolver UI). - * - * Used if a raiseIntent request resulted in an error. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentForContextResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol4ValidateAppIdentityPayload { /** - * Used if the raiseIntent request was successfully resolved. + * The current URL of the page attempting to connect. This may differ from the identityUrl, + * but the origins MUST match. */ - intentResolution?: IntentResolution; + actualUrl: string; /** - * Used if a raiseIntentForContext request requires additional resolution (e.g. by showing - * an intent resolver) before it can be handled. + * URL to use for the identity of the application. Desktop Agents MUST validate that the + * origin of the message matches the URL, but MAY implement custom comparison logic. */ - appIntents?: AppIntent[]; -} - -/** - * Used if the raiseIntent request was successfully resolved. - * - * IntentResolution provides a standard format for data returned upon resolving an intent. - * - * ```javascript - * //resolve a "Chain" type intent - * let resolution = await agent.raiseIntent("intentName", context); - * - * //resolve a "Client-Service" type intent with a data response or a Channel - * let resolution = await agent.raiseIntent("intentName", context); - * try { - * const result = await resolution.getResult(); - * if (result && result.broadcast) { - * console.log(`${resolution.source} returned a channel with id ${result.id}`); - * } else if (result){ - * console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`); - * } else { - * console.error(`${resolution.source} didn't return data` - * } - * } catch(error) { - * console.error(`${resolution.source} returned an error: ${error}`); - * } - * - * // Use metadata about the resolving app instance to target a further intent - * await agent.raiseIntent("intentName", context, resolution.source); - * ``` - */ -export interface IntentResolution { + identityUrl: string; /** - * The intent that was raised. May be used to determine which intent the user - * chose in response to `fdc3.raiseIntentForContext()`. + * If an application has previously connected to the Desktop Agent, it may specify its prior + * instance id and associated instance UUID to request the same same instance Id be assigned. */ - intent: string; + instanceId?: string; /** - * Identifier for the app instance that was selected (or started) to resolve the intent. - * `source.instanceId` MUST be set, indicating the specific app instance that - * received the intent. + * Instance UUID associated with the requested instanceId. */ - source: AppIdentifier; + instanceUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ /** - * A request to raise an intent for a context. + * Message sent by the Desktop Agent to an app if their identity validation fails. * - * A request message from an FDC3-enabled app to a Desktop Agent. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentRequest { +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponse { /** - * Metadata for a request message sent by an FDC3-enabled app to a Desktop Agent. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerRequestMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentRequestPayload; + payload: WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentRequest'; + type: 'WCP5ValidateAppIdentityFailedResponse'; } /** - * The message payload typically contains the arguments to FDC3 API functions. + * The message payload, containing data pertaining to this connection step. */ -export interface RaiseIntentRequestPayload { - app?: AppIdentifier; - context: Context; - intent: string; +export interface WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload { + message?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Request' appended. + * Identifies the type of the connection step message. */ /** - * A response to a raiseIntent request. + * Message sent by the Desktop Agent to an app after successful identity validation. * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentResponse { +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponse { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: WebConnectionProtocol1HelloMeta; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentResponsePayload; + payload: WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentResponse'; + type: 'WCP5ValidateAppIdentityResponse'; +} + +/** + * The message payload, containing data pertaining to this connection step. + */ +export interface WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload { + /** + * The appId that the app's identity was validated against. + */ + appId: string; + /** + * Implementation metadata for the Desktop Agent, which includes an appMetadata element + * containing a copy of the app's own metadata. + */ + implementationMetadata: ImplementationMetadata; + /** + * The instance Id granted to the application by the Desktop Agent. + */ + instanceId: string; + /** + * Instance UUID associated with the instanceId granted, which may be used to retrieve the + * same instanceId if the app is reloaded or navigates. + */ + instanceUuid: string; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. - * - * There are 3 possible responses to a raiseIntent request, each of which sets a single - * property in the payload: Success (`intentResolution`), Needs further resolution - * (`appIntent`) or Error (`error`). - * - * Response to a raiseIntent request that needs additional resolution (i.e. show an intent - * resolver UI). + * Identifies the type of the connection step message. + */ + +/** + * Goodbye message to be sent to the Desktop Agent when disconnecting (e.g. when closing the + * window or navigating). Desktop Agents should close the MessagePort after receiving this + * message, but retain instance details in case the application reconnects (e.g. after a + * navigation event). * - * Used if a raiseIntent request resulted in an error. + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. */ -export interface RaiseIntentResponsePayload { - /** - * Should be set if the raiseIntent request returned an error. - */ - error?: FindInstancesErrors; +export interface WebConnectionProtocol6Goodbye { /** - * Used if the raiseIntent request was successfully resolved. + * Metadata for a Web Connection Protocol message. */ - intentResolution?: IntentResolution; + meta: WebConnectionProtocol6GoodbyeMeta; /** - * Used if a raiseIntent request requires additional resolution (e.g. by showing an intent - * resolver) before it can be handled. + * Identifies the type of the connection step message. */ - appIntent?: AppIntent; + type: 'WCP6Goodbye'; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Metadata for a Web Connection Protocol message. */ +export interface WebConnectionProtocol6GoodbyeMeta { + timestamp: Date; +} /** - * A secondary response to a request to raise an intent used to deliver the intent result. - * This message should quote the original requestUuid of the raiseIntentRequest message in - * its `meta.requestUuid` field. - * - * A message from a Desktop Agent to an FDC3-enabled app responding to an API call. If the - * payload contains an `error` property, the request was unsuccessful. + * Identifies the type of the connection step message. */ -export interface RaiseIntentResultResponse { + +/** + * A message used during the connection flow for an application to a Desktop Agent in a + * browser window. Used for messages sent in either direction. + */ +export interface WebConnectionProtocolMessage { /** - * Metadata for messages sent by a Desktop Agent to an app in response to an API call. + * Metadata for a Web Connection Protocol message. */ - meta: AddContextListenerResponseMeta; + meta: ConnectionStepMetadata; /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * The message payload, containing data pertaining to this connection step. */ - payload: RaiseIntentResultResponsePayload; + payload?: { [key: string]: any }; /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ - type: 'raiseIntentResultResponse'; + type: ConnectionStepMessageType; } /** - * A payload for a response to an API call that will contain any return values or an `error` - * property containing a standardized error message indicating that the request was - * unsuccessful. + * Metadata for a Web Connection Protocol message. */ -export interface RaiseIntentResultResponsePayload { - error?: ResponsePayloadError; - intentResult?: IntentResult; +export interface ConnectionStepMetadata { + timestamp: Date; + connectionAttemptUuid?: string; } /** - * Identifies the type of the message and it is typically set to the FDC3 function name that - * the message relates to, e.g. 'findIntent', with 'Response' appended. + * Identifies the type of the connection step message. */ +export type ConnectionStepMessageType = + | 'WCP1Hello' + | 'WCP2LoadUrl' + | 'WCP3Handshake' + | 'WCP4ValidateAppIdentity' + | 'WCP5ValidateAppIdentityFailedResponse' + | 'WCP5ValidateAppIdentityResponse' + | 'WCP6Goodbye'; // Converts JSON strings to/from your types // and asserts the results of JSON.parse at runtime export class Convert { - public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { - return cast(JSON.parse(json), r('WebConnectionProtocol1Hello')); - } - - public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol1Hello')), null, 2); - } - - public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { - return cast(JSON.parse(json), r('WebConnectionProtocol2LoadURL')); - } - - public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol2LoadURL')), null, 2); - } - - public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { - return cast(JSON.parse(json), r('WebConnectionProtocol3Handshake')); - } - - public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol3Handshake')), null, 2); - } - - public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { - return cast(JSON.parse(json), r('WebConnectionProtocol4ValidateAppIdentity')); - } - - public static webConnectionProtocol4ValidateAppIdentityToJson( - value: WebConnectionProtocol4ValidateAppIdentity - ): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol4ValidateAppIdentity')), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse( - json: string - ): WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')); - } - - public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson( - value: WebConnectionProtocol5ValidateAppIdentityFailedResponse - ): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')), null, 2); - } - - public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse( - json: string - ): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')); - } - - public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson( - value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse - ): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')), null, 2); - } - - public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { - return cast(JSON.parse(json), r('WebConnectionProtocol6Goodbye')); - } - - public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocol6Goodbye')), null, 2); - } - - public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { - return cast(JSON.parse(json), r('WebConnectionProtocolMessage')); - } - - public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { - return JSON.stringify(uncast(value, r('WebConnectionProtocolMessage')), null, 2); - } - public static toAddContextListenerRequest(json: string): AddContextListenerRequest { return cast(JSON.parse(json), r('AddContextListenerRequest')); } @@ -4136,14 +4062,6 @@ export class Convert { return JSON.stringify(uncast(value, r('EventListenerUnsubscribeResponse')), null, 2); } - public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { - return cast(JSON.parse(json), r('Fdc3UserInterfaceChannelSelected')); - } - - public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { - return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannelSelected')), null, 2); - } - public static toFdc3UserInterfaceChannels(json: string): Fdc3UserInterfaceChannels { return cast(JSON.parse(json), r('Fdc3UserInterfaceChannels')); } @@ -4152,6 +4070,14 @@ export class Convert { return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannels')), null, 2); } + public static toFdc3UserInterfaceChannelSelected(json: string): Fdc3UserInterfaceChannelSelected { + return cast(JSON.parse(json), r('Fdc3UserInterfaceChannelSelected')); + } + + public static fdc3UserInterfaceChannelSelectedToJson(value: Fdc3UserInterfaceChannelSelected): string { + return JSON.stringify(uncast(value, r('Fdc3UserInterfaceChannelSelected')), null, 2); + } + public static toFdc3UserInterfaceDrag(json: string): Fdc3UserInterfaceDrag { return cast(JSON.parse(json), r('Fdc3UserInterfaceDrag')); } @@ -4564,16 +4490,90 @@ export class Convert { return cast(JSON.parse(json), r('RaiseIntentResponse')); } - public static raiseIntentResponseToJson(value: RaiseIntentResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResponse')), null, 2); + public static raiseIntentResponseToJson(value: RaiseIntentResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentResponse')), null, 2); + } + + public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { + return cast(JSON.parse(json), r('RaiseIntentResultResponse')); + } + + public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { + return JSON.stringify(uncast(value, r('RaiseIntentResultResponse')), null, 2); + } + + public static toWebConnectionProtocol1Hello(json: string): WebConnectionProtocol1Hello { + return cast(JSON.parse(json), r('WebConnectionProtocol1Hello')); + } + + public static webConnectionProtocol1HelloToJson(value: WebConnectionProtocol1Hello): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol1Hello')), null, 2); + } + + public static toWebConnectionProtocol2LoadURL(json: string): WebConnectionProtocol2LoadURL { + return cast(JSON.parse(json), r('WebConnectionProtocol2LoadURL')); + } + + public static webConnectionProtocol2LoadURLToJson(value: WebConnectionProtocol2LoadURL): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol2LoadURL')), null, 2); + } + + public static toWebConnectionProtocol3Handshake(json: string): WebConnectionProtocol3Handshake { + return cast(JSON.parse(json), r('WebConnectionProtocol3Handshake')); + } + + public static webConnectionProtocol3HandshakeToJson(value: WebConnectionProtocol3Handshake): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol3Handshake')), null, 2); + } + + public static toWebConnectionProtocol4ValidateAppIdentity(json: string): WebConnectionProtocol4ValidateAppIdentity { + return cast(JSON.parse(json), r('WebConnectionProtocol4ValidateAppIdentity')); + } + + public static webConnectionProtocol4ValidateAppIdentityToJson( + value: WebConnectionProtocol4ValidateAppIdentity + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol4ValidateAppIdentity')), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentityFailedResponse( + json: string + ): WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')); + } + + public static webConnectionProtocol5ValidateAppIdentityFailedResponseToJson( + value: WebConnectionProtocol5ValidateAppIdentityFailedResponse + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentityFailedResponse')), null, 2); + } + + public static toWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + json: string + ): WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return cast(JSON.parse(json), r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')); + } + + public static webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson( + value: WebConnectionProtocol5ValidateAppIdentitySuccessResponse + ): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol5ValidateAppIdentitySuccessResponse')), null, 2); + } + + public static toWebConnectionProtocol6Goodbye(json: string): WebConnectionProtocol6Goodbye { + return cast(JSON.parse(json), r('WebConnectionProtocol6Goodbye')); + } + + public static webConnectionProtocol6GoodbyeToJson(value: WebConnectionProtocol6Goodbye): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocol6Goodbye')), null, 2); } - public static toRaiseIntentResultResponse(json: string): RaiseIntentResultResponse { - return cast(JSON.parse(json), r('RaiseIntentResultResponse')); + public static toWebConnectionProtocolMessage(json: string): WebConnectionProtocolMessage { + return cast(JSON.parse(json), r('WebConnectionProtocolMessage')); } - public static raiseIntentResultResponseToJson(value: RaiseIntentResultResponse): string { - return JSON.stringify(uncast(value, r('RaiseIntentResultResponse')), null, 2); + public static webConnectionProtocolMessageToJson(value: WebConnectionProtocolMessage): string { + return JSON.stringify(uncast(value, r('WebConnectionProtocolMessage')), null, 2); } } @@ -4671,250 +4671,79 @@ function transform(val: any, typ: any, getProps: any, key: any = '', parent: any if (val === null || typeof val !== 'object' || Array.isArray(val)) { return invalidValue(l(ref || 'object'), val, key, parent); } - const result: any = {}; - Object.getOwnPropertyNames(props).forEach(key => { - const prop = props[key]; - const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; - result[prop.key] = transform(v, prop.typ, getProps, key, ref); - }); - Object.getOwnPropertyNames(val).forEach(key => { - if (!Object.prototype.hasOwnProperty.call(props, key)) { - result[key] = transform(val[key], additional, getProps, key, ref); - } - }); - return result; - } - - if (typ === 'any') return val; - if (typ === null) { - if (val === null) return val; - return invalidValue(typ, val, key, parent); - } - if (typ === false) return invalidValue(typ, val, key, parent); - let ref: any = undefined; - while (typeof typ === 'object' && typ.ref !== undefined) { - ref = typ.ref; - typ = typeMap[typ.ref]; - } - if (Array.isArray(typ)) return transformEnum(typ, val); - if (typeof typ === 'object') { - return typ.hasOwnProperty('unionMembers') - ? transformUnion(typ.unionMembers, val) - : typ.hasOwnProperty('arrayItems') - ? transformArray(typ.arrayItems, val) - : typ.hasOwnProperty('props') - ? transformObject(getProps(typ), typ.additional, val) - : invalidValue(typ, val, key, parent); - } - // Numbers can be parsed by Date but shouldn't be. - if (typ === Date && typeof val !== 'number') return transformDate(val); - return transformPrimitive(typ, val); -} - -function cast(val: any, typ: any): T { - return transform(val, typ, jsonToJSProps); -} - -function uncast(val: T, typ: any): any { - return transform(val, typ, jsToJSONProps); -} - -function l(typ: any) { - return { literal: typ }; -} - -function a(typ: any) { - return { arrayItems: typ }; -} - -function u(...typs: any[]) { - return { unionMembers: typs }; -} - -function o(props: any[], additional: any) { - return { props, additional }; -} - -function m(additional: any) { - return { props: [], additional }; -} - -function r(name: string) { - return { ref: name }; -} - -const typeMap: any = { - WebConnectionProtocol1Hello: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol1HelloPayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol1HelloType') }, - ], - false - ), - WebConnectionProtocol1HelloMeta: o( - [ - { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: '' }, - { json: 'timestamp', js: 'timestamp', typ: Date }, - ], - false - ), - WebConnectionProtocol1HelloPayload: o( - [ - { json: 'actualUrl', js: 'actualUrl', typ: '' }, - { json: 'channelSelector', js: 'channelSelector', typ: u(undefined, true) }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'identityUrl', js: 'identityUrl', typ: '' }, - { json: 'intentResolver', js: 'intentResolver', typ: u(undefined, true) }, - ], - 'any' - ), - WebConnectionProtocol2LoadURL: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol2LoadURLPayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol2LoadURLType') }, - ], - false - ), - WebConnectionProtocol2LoadURLPayload: o([{ json: 'iframeUrl', js: 'iframeUrl', typ: '' }], 'any'), - WebConnectionProtocol3Handshake: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol3HandshakePayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol3HandshakeType') }, - ], - false - ), - WebConnectionProtocol3HandshakePayload: o( - [ - { json: 'channelSelectorUrl', js: 'channelSelectorUrl', typ: u(true, '') }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'intentResolverUrl', js: 'intentResolverUrl', typ: u(true, '') }, - ], - false - ), - WebConnectionProtocol4ValidateAppIdentity: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol4ValidateAppIdentityPayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol4ValidateAppIdentityType') }, - ], - false - ), - WebConnectionProtocol4ValidateAppIdentityPayload: o( - [ - { json: 'actualUrl', js: 'actualUrl', typ: '' }, - { json: 'identityUrl', js: 'identityUrl', typ: '' }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - { json: 'instanceUuid', js: 'instanceUuid', typ: u(undefined, '') }, - ], - false - ), - WebConnectionProtocol5ValidateAppIdentityFailedResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponseType') }, - ], - false - ), - WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload: o( - [{ json: 'message', js: 'message', typ: u(undefined, '') }], - false - ), - WebConnectionProtocol5ValidateAppIdentitySuccessResponse: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, - { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponseType') }, - ], - false - ), - WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'implementationMetadata', js: 'implementationMetadata', typ: r('ImplementationMetadata') }, - { json: 'instanceId', js: 'instanceId', typ: '' }, - { json: 'instanceUuid', js: 'instanceUuid', typ: '' }, - ], - false - ), - ImplementationMetadata: o( - [ - { json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }, - { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, - { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, - { json: 'provider', js: 'provider', typ: '' }, - { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, - ], - false - ), - AppMetadata: o( - [ - { json: 'appId', js: 'appId', typ: '' }, - { json: 'description', js: 'description', typ: u(undefined, '') }, - { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, - { json: 'icons', js: 'icons', typ: u(undefined, a(r('Icon'))) }, - { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, - { json: 'instanceMetadata', js: 'instanceMetadata', typ: u(undefined, m('any')) }, - { json: 'name', js: 'name', typ: u(undefined, '') }, - { json: 'resultType', js: 'resultType', typ: u(undefined, u(null, '')) }, - { json: 'screenshots', js: 'screenshots', typ: u(undefined, a(r('Image'))) }, - { json: 'title', js: 'title', typ: u(undefined, '') }, - { json: 'tooltip', js: 'tooltip', typ: u(undefined, '') }, - { json: 'version', js: 'version', typ: u(undefined, '') }, - ], - false - ), - Icon: o( - [ - { json: 'size', js: 'size', typ: u(undefined, '') }, - { json: 'src', js: 'src', typ: '' }, - { json: 'type', js: 'type', typ: u(undefined, '') }, - ], - false - ), - Image: o( - [ - { json: 'label', js: 'label', typ: u(undefined, '') }, - { json: 'size', js: 'size', typ: u(undefined, '') }, - { json: 'src', js: 'src', typ: '' }, - { json: 'type', js: 'type', typ: u(undefined, '') }, - ], - false - ), - OptionalFeatures: o( - [ - { json: 'DesktopAgentBridging', js: 'DesktopAgentBridging', typ: true }, - { json: 'OriginatingAppMetadata', js: 'OriginatingAppMetadata', typ: true }, - { json: 'UserChannelMembershipAPIs', js: 'UserChannelMembershipAPIs', typ: true }, - ], - false - ), - WebConnectionProtocol6Goodbye: o( - [ - { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol6GoodbyeMeta') }, - { json: 'type', js: 'type', typ: r('WebConnectionProtocol6GoodbyeType') }, - ], - false - ), - WebConnectionProtocol6GoodbyeMeta: o([{ json: 'timestamp', js: 'timestamp', typ: Date }], false), - WebConnectionProtocolMessage: o( - [ - { json: 'meta', js: 'meta', typ: r('ConnectionStepMetadata') }, - { json: 'payload', js: 'payload', typ: u(undefined, m('any')) }, - { json: 'type', js: 'type', typ: r('ConnectionStepMessageType') }, - ], - false - ), - ConnectionStepMetadata: o( - [ - { json: 'timestamp', js: 'timestamp', typ: Date }, - { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: u(undefined, '') }, - ], - false - ), + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps, key, ref); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps, key, ref); + } + }); + return result; + } + + if (typ === 'any') return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val, key, parent); + } + if (typ === false) return invalidValue(typ, val, key, parent); + let ref: any = undefined; + while (typeof typ === 'object' && typ.ref !== undefined) { + ref = typ.ref; + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === 'object') { + return typ.hasOwnProperty('unionMembers') + ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty('arrayItems') + ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty('props') + ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val, key, parent); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== 'number') return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function l(typ: any) { + return { literal: typ }; +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { AddContextListenerRequest: o( [ { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, @@ -5211,14 +5040,6 @@ const typeMap: any = { ], false ), - Fdc3UserInterfaceChannelSelected: o( - [ - { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelSelectedPayload') }, - { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceChannelSelectedType') }, - ], - false - ), - Fdc3UserInterfaceChannelSelectedPayload: o([{ json: 'selected', js: 'selected', typ: u(null, '') }], false), Fdc3UserInterfaceChannels: o( [ { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelsPayload') }, @@ -5233,6 +5054,14 @@ const typeMap: any = { ], false ), + Fdc3UserInterfaceChannelSelected: o( + [ + { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceChannelSelectedPayload') }, + { json: 'type', js: 'type', typ: r('Fdc3UserInterfaceChannelSelectedType') }, + ], + false + ), + Fdc3UserInterfaceChannelSelectedPayload: o([{ json: 'selected', js: 'selected', typ: u(null, '') }], false), Fdc3UserInterfaceDrag: o( [ { json: 'payload', js: 'payload', typ: r('Fdc3UserInterfaceDragPayload') }, @@ -5313,6 +5142,40 @@ const typeMap: any = { ], false ), + AppMetadata: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'description', js: 'description', typ: u(undefined, '') }, + { json: 'desktopAgent', js: 'desktopAgent', typ: u(undefined, '') }, + { json: 'icons', js: 'icons', typ: u(undefined, a(r('Icon'))) }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + { json: 'instanceMetadata', js: 'instanceMetadata', typ: u(undefined, m('any')) }, + { json: 'name', js: 'name', typ: u(undefined, '') }, + { json: 'resultType', js: 'resultType', typ: u(undefined, u(null, '')) }, + { json: 'screenshots', js: 'screenshots', typ: u(undefined, a(r('Image'))) }, + { json: 'title', js: 'title', typ: u(undefined, '') }, + { json: 'tooltip', js: 'tooltip', typ: u(undefined, '') }, + { json: 'version', js: 'version', typ: u(undefined, '') }, + ], + false + ), + Icon: o( + [ + { json: 'size', js: 'size', typ: u(undefined, '') }, + { json: 'src', js: 'src', typ: '' }, + { json: 'type', js: 'type', typ: u(undefined, '') }, + ], + false + ), + Image: o( + [ + { json: 'label', js: 'label', typ: u(undefined, '') }, + { json: 'size', js: 'size', typ: u(undefined, '') }, + { json: 'src', js: 'src', typ: '' }, + { json: 'type', js: 'type', typ: u(undefined, '') }, + ], + false + ), IntentMetadata: o( [ { json: 'displayName', js: 'displayName', typ: u(undefined, '') }, @@ -5545,6 +5408,24 @@ const typeMap: any = { ], false ), + ImplementationMetadata: o( + [ + { json: 'appMetadata', js: 'appMetadata', typ: r('AppMetadata') }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'optionalFeatures', js: 'optionalFeatures', typ: r('OptionalFeatures') }, + { json: 'provider', js: 'provider', typ: '' }, + { json: 'providerVersion', js: 'providerVersion', typ: u(undefined, '') }, + ], + false + ), + OptionalFeatures: o( + [ + { json: 'DesktopAgentBridging', js: 'DesktopAgentBridging', typ: true }, + { json: 'OriginatingAppMetadata', js: 'OriginatingAppMetadata', typ: true }, + { json: 'UserChannelMembershipAPIs', js: 'UserChannelMembershipAPIs', typ: true }, + ], + false + ), GetOrCreateChannelRequest: o( [ { json: 'meta', js: 'meta', typ: r('AddContextListenerRequestMeta') }, @@ -5922,37 +5803,140 @@ const typeMap: any = { ], false ), - RaiseIntentResultResponse: o( + RaiseIntentResultResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, + { json: 'payload', js: 'payload', typ: r('RaiseIntentResultResponsePayload') }, + { json: 'type', js: 'type', typ: r('RaiseIntentResultResponseType') }, + ], + false + ), + RaiseIntentResultResponsePayload: o( + [ + { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, + { json: 'intentResult', js: 'intentResult', typ: u(undefined, r('IntentResult')) }, + ], + false + ), + WebConnectionProtocol1Hello: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol1HelloPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol1HelloType') }, + ], + false + ), + WebConnectionProtocol1HelloMeta: o( + [ + { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: '' }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + ], + false + ), + WebConnectionProtocol1HelloPayload: o( + [ + { json: 'actualUrl', js: 'actualUrl', typ: '' }, + { json: 'channelSelector', js: 'channelSelector', typ: u(undefined, true) }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'identityUrl', js: 'identityUrl', typ: '' }, + { json: 'intentResolver', js: 'intentResolver', typ: u(undefined, true) }, + ], + 'any' + ), + WebConnectionProtocol2LoadURL: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol2LoadURLPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol2LoadURLType') }, + ], + false + ), + WebConnectionProtocol2LoadURLPayload: o([{ json: 'iframeUrl', js: 'iframeUrl', typ: '' }], 'any'), + WebConnectionProtocol3Handshake: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol3HandshakePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol3HandshakeType') }, + ], + false + ), + WebConnectionProtocol3HandshakePayload: o( + [ + { json: 'channelSelectorUrl', js: 'channelSelectorUrl', typ: u(true, '') }, + { json: 'fdc3Version', js: 'fdc3Version', typ: '' }, + { json: 'intentResolverUrl', js: 'intentResolverUrl', typ: u(true, '') }, + ], + false + ), + WebConnectionProtocol4ValidateAppIdentity: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol4ValidateAppIdentityPayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol4ValidateAppIdentityType') }, + ], + false + ), + WebConnectionProtocol4ValidateAppIdentityPayload: o( + [ + { json: 'actualUrl', js: 'actualUrl', typ: '' }, + { json: 'identityUrl', js: 'identityUrl', typ: '' }, + { json: 'instanceId', js: 'instanceId', typ: u(undefined, '') }, + { json: 'instanceUuid', js: 'instanceUuid', typ: u(undefined, '') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentityFailedResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentityFailedResponseType') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentityFailedResponsePayload: o( + [{ json: 'message', js: 'message', typ: u(undefined, '') }], + false + ), + WebConnectionProtocol5ValidateAppIdentitySuccessResponse: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol1HelloMeta') }, + { json: 'payload', js: 'payload', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol5ValidateAppIdentitySuccessResponseType') }, + ], + false + ), + WebConnectionProtocol5ValidateAppIdentitySuccessResponsePayload: o( + [ + { json: 'appId', js: 'appId', typ: '' }, + { json: 'implementationMetadata', js: 'implementationMetadata', typ: r('ImplementationMetadata') }, + { json: 'instanceId', js: 'instanceId', typ: '' }, + { json: 'instanceUuid', js: 'instanceUuid', typ: '' }, + ], + false + ), + WebConnectionProtocol6Goodbye: o( + [ + { json: 'meta', js: 'meta', typ: r('WebConnectionProtocol6GoodbyeMeta') }, + { json: 'type', js: 'type', typ: r('WebConnectionProtocol6GoodbyeType') }, + ], + false + ), + WebConnectionProtocol6GoodbyeMeta: o([{ json: 'timestamp', js: 'timestamp', typ: Date }], false), + WebConnectionProtocolMessage: o( [ - { json: 'meta', js: 'meta', typ: r('AddContextListenerResponseMeta') }, - { json: 'payload', js: 'payload', typ: r('RaiseIntentResultResponsePayload') }, - { json: 'type', js: 'type', typ: r('RaiseIntentResultResponseType') }, + { json: 'meta', js: 'meta', typ: r('ConnectionStepMetadata') }, + { json: 'payload', js: 'payload', typ: u(undefined, m('any')) }, + { json: 'type', js: 'type', typ: r('ConnectionStepMessageType') }, ], false ), - RaiseIntentResultResponsePayload: o( + ConnectionStepMetadata: o( [ - { json: 'error', js: 'error', typ: u(undefined, r('ResponsePayloadError')) }, - { json: 'intentResult', js: 'intentResult', typ: u(undefined, r('IntentResult')) }, + { json: 'timestamp', js: 'timestamp', typ: Date }, + { json: 'connectionAttemptUuid', js: 'connectionAttemptUuid', typ: u(undefined, '') }, ], false ), - WebConnectionProtocol1HelloType: ['WCP1Hello'], - WebConnectionProtocol2LoadURLType: ['WCP2LoadUrl'], - WebConnectionProtocol3HandshakeType: ['WCP3Handshake'], - WebConnectionProtocol4ValidateAppIdentityType: ['WCP4ValidateAppIdentity'], - WebConnectionProtocol5ValidateAppIdentityFailedResponseType: ['WCP5ValidateAppIdentityFailedResponse'], - WebConnectionProtocol5ValidateAppIdentitySuccessResponseType: ['WCP5ValidateAppIdentityResponse'], - WebConnectionProtocol6GoodbyeType: ['WCP6Goodbye'], - ConnectionStepMessageType: [ - 'WCP1Hello', - 'WCP2LoadUrl', - 'WCP3Handshake', - 'WCP4ValidateAppIdentity', - 'WCP5ValidateAppIdentityFailedResponse', - 'WCP5ValidateAppIdentityResponse', - 'WCP6Goodbye', - ], AddContextListenerRequestType: ['addContextListenerRequest'], PurpleError: ['AccessDenied', 'CreationFailed', 'MalformedContext', 'NoChannelFound'], AddContextListenerResponseType: ['addContextListenerResponse'], @@ -6074,8 +6058,8 @@ const typeMap: any = { CreatePrivateChannelResponseType: ['createPrivateChannelResponse'], EventListenerUnsubscribeRequestType: ['eventListenerUnsubscribeRequest'], EventListenerUnsubscribeResponseType: ['eventListenerUnsubscribeResponse'], - Fdc3UserInterfaceChannelSelectedType: ['Fdc3UserInterfaceChannelSelected'], Fdc3UserInterfaceChannelsType: ['Fdc3UserInterfaceChannels'], + Fdc3UserInterfaceChannelSelectedType: ['Fdc3UserInterfaceChannelSelected'], Fdc3UserInterfaceDragType: ['Fdc3UserInterfaceDrag'], Fdc3UserInterfaceHandshakeType: ['Fdc3UserInterfaceHandshake'], Fdc3UserInterfaceHelloType: ['Fdc3UserInterfaceHello'], @@ -6166,6 +6150,22 @@ const typeMap: any = { RaiseIntentRequestType: ['raiseIntentRequest'], RaiseIntentResponseType: ['raiseIntentResponse'], RaiseIntentResultResponseType: ['raiseIntentResultResponse'], + WebConnectionProtocol1HelloType: ['WCP1Hello'], + WebConnectionProtocol2LoadURLType: ['WCP2LoadUrl'], + WebConnectionProtocol3HandshakeType: ['WCP3Handshake'], + WebConnectionProtocol4ValidateAppIdentityType: ['WCP4ValidateAppIdentity'], + WebConnectionProtocol5ValidateAppIdentityFailedResponseType: ['WCP5ValidateAppIdentityFailedResponse'], + WebConnectionProtocol5ValidateAppIdentitySuccessResponseType: ['WCP5ValidateAppIdentityResponse'], + WebConnectionProtocol6GoodbyeType: ['WCP6Goodbye'], + ConnectionStepMessageType: [ + 'WCP1Hello', + 'WCP2LoadUrl', + 'WCP3Handshake', + 'WCP4ValidateAppIdentity', + 'WCP5ValidateAppIdentityFailedResponse', + 'WCP5ValidateAppIdentityResponse', + 'WCP6Goodbye', + ], }; export type AppRequestMessage = @@ -6191,224 +6191,49 @@ export type AppRequestMessage = | JoinUserChannelRequest | LeaveCurrentChannelRequest | OpenRequest - | PrivateChannelAddEventListenerRequest - | PrivateChannelDisconnectRequest - | PrivateChannelUnsubscribeEventListenerRequest - | RaiseIntentForContextRequest - | RaiseIntentRequest; - -export type AgentResponseMessage = - | AddContextListenerResponse - | AddEventListenerResponse - | AddIntentListenerResponse - | BroadcastResponse - | ContextListenerUnsubscribeResponse - | CreatePrivateChannelResponse - | EventListenerUnsubscribeResponse - | FindInstancesResponse - | FindIntentResponse - | FindIntentsByContextResponse - | GetAppMetadataResponse - | GetCurrentChannelResponse - | GetCurrentContextResponse - | GetInfoResponse - | GetOrCreateChannelResponse - | GetUserChannelsResponse - | IntentListenerUnsubscribeResponse - | IntentResultResponse - | JoinUserChannelResponse - | LeaveCurrentChannelResponse - | OpenResponse - | PrivateChannelAddEventListenerResponse - | PrivateChannelDisconnectResponse - | PrivateChannelUnsubscribeEventListenerResponse - | RaiseIntentForContextResponse - | RaiseIntentResponse - | RaiseIntentResultResponse; - -export type AgentEventMessage = - | BroadcastEvent - | ChannelChangedEvent - | HeartbeatEvent - | IntentEvent - | PrivateChannelOnAddContextListenerEvent - | PrivateChannelOnDisconnectEvent - | PrivateChannelOnUnsubscribeEvent; - -/** - * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - return value != null && value.type === 'WCP1Hello'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { - try { - Convert.webConnectionProtocol1HelloToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = 'WebConnectionProtocol1Hello'; - -/** - * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - return value != null && value.type === 'WCP2LoadUrl'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { - try { - Convert.webConnectionProtocol2LoadURLToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = 'WebConnectionProtocol2LoadURL'; - -/** - * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - return value != null && value.type === 'WCP3Handshake'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { - try { - Convert.webConnectionProtocol3HandshakeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = 'WebConnectionProtocol3Handshake'; - -/** - * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol4ValidateAppIdentity( - value: any -): value is WebConnectionProtocol4ValidateAppIdentity { - return value != null && value.type === 'WCP4ValidateAppIdentity'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol4ValidateAppIdentity( - value: any -): value is WebConnectionProtocol4ValidateAppIdentity { - try { - Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = 'WebConnectionProtocol4ValidateAppIdentity'; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = - 'WebConnectionProtocol5ValidateAppIdentityFailedResponse'; - -/** - * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse( - value: any -): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { - try { - Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = - 'WebConnectionProtocol5ValidateAppIdentitySuccessResponse'; - -/** - * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message - */ -export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - return value != null && value.type === 'WCP6Goodbye'; -} - -/** - * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { - try { - Convert.webConnectionProtocol6GoodbyeToJson(value); - return true; - } catch (_e: any) { - return false; - } -} - -export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = 'WebConnectionProtocol6Goodbye'; + | PrivateChannelAddEventListenerRequest + | PrivateChannelDisconnectRequest + | PrivateChannelUnsubscribeEventListenerRequest + | RaiseIntentForContextRequest + | RaiseIntentRequest; -/** - * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower - */ -export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { - try { - Convert.webConnectionProtocolMessageToJson(value); - return true; - } catch (_e: any) { - return false; - } -} +export type AgentResponseMessage = + | AddContextListenerResponse + | AddEventListenerResponse + | AddIntentListenerResponse + | BroadcastResponse + | ContextListenerUnsubscribeResponse + | CreatePrivateChannelResponse + | EventListenerUnsubscribeResponse + | FindInstancesResponse + | FindIntentResponse + | FindIntentsByContextResponse + | GetAppMetadataResponse + | GetCurrentChannelResponse + | GetCurrentContextResponse + | GetInfoResponse + | GetOrCreateChannelResponse + | GetUserChannelsResponse + | IntentListenerUnsubscribeResponse + | IntentResultResponse + | JoinUserChannelResponse + | LeaveCurrentChannelResponse + | OpenResponse + | PrivateChannelAddEventListenerResponse + | PrivateChannelDisconnectResponse + | PrivateChannelUnsubscribeEventListenerResponse + | RaiseIntentForContextResponse + | RaiseIntentResponse + | RaiseIntentResultResponse; -export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = 'WebConnectionProtocolMessage'; +export type AgentEventMessage = + | BroadcastEvent + | ChannelChangedEvent + | HeartbeatEvent + | IntentEvent + | PrivateChannelOnAddContextListenerEvent + | PrivateChannelOnDisconnectEvent + | PrivateChannelOnUnsubscribeEvent; /** * Returns true if the value has a type property with value 'addContextListenerRequest'. This is a fast check that does not check the format of the message @@ -6747,46 +6572,46 @@ export function isValidEventListenerUnsubscribeResponse(value: any): value is Ev export const EVENT_LISTENER_UNSUBSCRIBE_RESPONSE_TYPE = 'EventListenerUnsubscribeResponse'; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { - return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; +export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { + return value != null && value.type === 'Fdc3UserInterfaceChannels'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { +export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { try { - Convert.fdc3UserInterfaceChannelSelectedToJson(value); + Convert.fdc3UserInterfaceChannelsToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = 'Fdc3UserInterfaceChannelSelected'; +export const FDC3_USER_INTERFACE_CHANNELS_TYPE = 'Fdc3UserInterfaceChannels'; /** - * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannels'. This is a fast check that does not check the format of the message + * Returns true if the value has a type property with value 'Fdc3UserInterfaceChannelSelected'. This is a fast check that does not check the format of the message */ -export function isFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { - return value != null && value.type === 'Fdc3UserInterfaceChannels'; +export function isFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { + return value != null && value.type === 'Fdc3UserInterfaceChannelSelected'; } /** - * Returns true if value is a valid Fdc3UserInterfaceChannels. This checks the type against the json schema for the message and will be slower + * Returns true if value is a valid Fdc3UserInterfaceChannelSelected. This checks the type against the json schema for the message and will be slower */ -export function isValidFdc3UserInterfaceChannels(value: any): value is Fdc3UserInterfaceChannels { +export function isValidFdc3UserInterfaceChannelSelected(value: any): value is Fdc3UserInterfaceChannelSelected { try { - Convert.fdc3UserInterfaceChannelsToJson(value); + Convert.fdc3UserInterfaceChannelSelectedToJson(value); return true; } catch (_e: any) { return false; } } -export const FDC3_USER_INTERFACE_CHANNELS_TYPE = 'Fdc3UserInterfaceChannels'; +export const FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE = 'Fdc3UserInterfaceChannelSelected'; /** * Returns true if the value has a type property with value 'Fdc3UserInterfaceDrag'. This is a fast check that does not check the format of the message @@ -7889,3 +7714,178 @@ export function isValidRaiseIntentResultResponse(value: any): value is RaiseInte } export const RAISE_INTENT_RESULT_RESPONSE_TYPE = 'RaiseIntentResultResponse'; + +/** + * Returns true if the value has a type property with value 'WCP1Hello'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + return value != null && value.type === 'WCP1Hello'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol1Hello. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol1Hello(value: any): value is WebConnectionProtocol1Hello { + try { + Convert.webConnectionProtocol1HelloToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL1_HELLO_TYPE = 'WebConnectionProtocol1Hello'; + +/** + * Returns true if the value has a type property with value 'WCP2LoadUrl'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + return value != null && value.type === 'WCP2LoadUrl'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol2LoadURL. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol2LoadURL(value: any): value is WebConnectionProtocol2LoadURL { + try { + Convert.webConnectionProtocol2LoadURLToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL2_LOAD_U_R_L_TYPE = 'WebConnectionProtocol2LoadURL'; + +/** + * Returns true if the value has a type property with value 'WCP3Handshake'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + return value != null && value.type === 'WCP3Handshake'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol3Handshake. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol3Handshake(value: any): value is WebConnectionProtocol3Handshake { + try { + Convert.webConnectionProtocol3HandshakeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL3_HANDSHAKE_TYPE = 'WebConnectionProtocol3Handshake'; + +/** + * Returns true if the value has a type property with value 'WCP4ValidateAppIdentity'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol4ValidateAppIdentity( + value: any +): value is WebConnectionProtocol4ValidateAppIdentity { + return value != null && value.type === 'WCP4ValidateAppIdentity'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol4ValidateAppIdentity. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol4ValidateAppIdentity( + value: any +): value is WebConnectionProtocol4ValidateAppIdentity { + try { + Convert.webConnectionProtocol4ValidateAppIdentityToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL4_VALIDATE_APP_IDENTITY_TYPE = 'WebConnectionProtocol4ValidateAppIdentity'; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityFailedResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentityFailedResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityFailedResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentityFailedResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentityFailedResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentityFailedResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentityFailedResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_FAILED_RESPONSE_TYPE = + 'WebConnectionProtocol5ValidateAppIdentityFailedResponse'; + +/** + * Returns true if the value has a type property with value 'WCP5ValidateAppIdentityResponse'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + return value != null && value.type === 'WCP5ValidateAppIdentityResponse'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol5ValidateAppIdentitySuccessResponse. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol5ValidateAppIdentitySuccessResponse( + value: any +): value is WebConnectionProtocol5ValidateAppIdentitySuccessResponse { + try { + Convert.webConnectionProtocol5ValidateAppIdentitySuccessResponseToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL5_VALIDATE_APP_IDENTITY_SUCCESS_RESPONSE_TYPE = + 'WebConnectionProtocol5ValidateAppIdentitySuccessResponse'; + +/** + * Returns true if the value has a type property with value 'WCP6Goodbye'. This is a fast check that does not check the format of the message + */ +export function isWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + return value != null && value.type === 'WCP6Goodbye'; +} + +/** + * Returns true if value is a valid WebConnectionProtocol6Goodbye. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocol6Goodbye(value: any): value is WebConnectionProtocol6Goodbye { + try { + Convert.webConnectionProtocol6GoodbyeToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL6_GOODBYE_TYPE = 'WebConnectionProtocol6Goodbye'; + +/** + * Returns true if value is a valid WebConnectionProtocolMessage. This checks the type against the json schema for the message and will be slower + */ +export function isValidWebConnectionProtocolMessage(value: any): value is WebConnectionProtocolMessage { + try { + Convert.webConnectionProtocolMessageToJson(value); + return true; + } catch (_e: any) { + return false; + } +} + +export const WEB_CONNECTION_PROTOCOL_MESSAGE_TYPE = 'WebConnectionProtocolMessage'; diff --git a/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts b/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts index 18c911c8d..fa06596c6 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/DemoServerContext.ts @@ -1,4 +1,12 @@ -import { AppRegistration, Directory, DirectoryApp, InstanceID, ServerContext, State } from '@kite9/fdc3-web-impl'; +import { + AppRegistration, + Directory, + DirectoryApp, + FDC3Server, + InstanceID, + ServerContext, + State, +} from '@kite9/fdc3-web-impl'; import { Socket } from 'socket.io-client'; import { v4 as uuid } from 'uuid'; import { FDC3_DA_EVENT } from '../../message-types'; @@ -10,63 +18,62 @@ enum Opener { Nested, } -type DemoAppRegistration = AppRegistration & { +type RunningAppRegistration = AppRegistration & { window: Window; url: string; }; -type DemoLaunchRegistration = AppRegistration & { +type LaunchingAppRegistration = AppRegistration & { windowPromise: Promise; url: string; }; -type DemoRegistration = DemoAppRegistration | DemoLaunchRegistration; +type DemoAppRegistration = RunningAppRegistration | LaunchingAppRegistration; //Type guard used to check if application launch details have a URL function isWebAppLaunchDetails(details: object): details is { url: string } { return (details as { url: string }).url !== undefined; } -//Type guard used to check if application has been launched or if we are still waiting on the window reference -function isDemoLaunchRegistration( - details: DemoAppRegistration | DemoLaunchRegistration -): details is DemoLaunchRegistration { - return !!(details as DemoLaunchRegistration).windowPromise; +//Type guard used to check if application is still launching (we are waiting on the window reference) +function isLaunchingAppRegistration( + details: RunningAppRegistration | LaunchingAppRegistration +): details is LaunchingAppRegistration { + return !!(details as LaunchingAppRegistration).windowPromise; } -//Type guard used to check if application has been launched or if we are still waiting on the window reference -function isDemoAppRegistration(details: DemoAppRegistration | DemoLaunchRegistration): details is DemoAppRegistration { - return !!(details as DemoAppRegistration).window; +//Type guard used to check if application has been launched (and we have received the window reference) +function isRunningAppRegistration( + details: RunningAppRegistration | LaunchingAppRegistration +): details is RunningAppRegistration { + return !!(details as RunningAppRegistration).window; } -export class DemoServerContext implements ServerContext { +export class DemoServerContext implements ServerContext { private readonly socket: Socket; private readonly directory: Directory; - private connections: (DemoAppRegistration | DemoLaunchRegistration)[] = []; - private pastConnections: { registration: DemoAppRegistration; timestamp: number }[] = []; - private static PAST_CONNECTIONS_MAX_AGE_MS = 60 * 1000; + private connections: (RunningAppRegistration | LaunchingAppRegistration)[] = []; + private server: FDC3Server | null = null; constructor(socket: Socket, directory: Directory) { this.socket = socket; this.directory = directory; } + setFDC3Server(server: FDC3Server): void { + this.server = server; + } + async narrowIntents(_raiser: AppIdentifier, appIntents: AppIntent[] /*, _context: Context*/): Promise { return appIntents; } - private prunePastConnections = () => { - const threshold = Date.now() - DemoServerContext.PAST_CONNECTIONS_MAX_AGE_MS; - this.pastConnections = this.pastConnections.filter(pc => pc.timestamp > threshold); - }; - /** * Sets the appId, url, state and either the window or a Promise for a given connection UUID. */ - setInstanceDetails(uuid: InstanceID, meta: DemoAppRegistration | DemoLaunchRegistration): void { + setInstanceDetails(uuid: InstanceID, meta: RunningAppRegistration | LaunchingAppRegistration): void { //remove any existing records with this uuid this.connections = this.connections.filter(ca => ca.instanceId !== uuid); - this.pastConnections = this.pastConnections.filter(i => i.registration.instanceId != uuid); const instanceDetails = { ...meta, @@ -74,12 +81,12 @@ export class DemoServerContext implements ServerContext { }; this.connections.push(instanceDetails); - if (isDemoLaunchRegistration(meta)) { + if (isLaunchingAppRegistration(meta)) { //If the window wasn't fully realized yet, monitor the window promise so that it // sets window when resolved. meta.windowPromise.then((window: Window | null) => { if (window) { - const launchedMeta: DemoAppRegistration = { + const launchedMeta: RunningAppRegistration = { window: window, url: meta.url, appId: meta.appId, @@ -101,28 +108,28 @@ export class DemoServerContext implements ServerContext { } } - async getInstanceForWindow(window: Window): Promise { - const registration = this.connections.filter(isDemoAppRegistration).find(i => i.window == window); + async getInstanceForWindow(window: Window): Promise { + const registration = this.connections.filter(isRunningAppRegistration).find(i => i.window == window); if (registration) { return registration; } //check for as yet unrealized windows and then wait on those... - const launchingApps = this.connections.filter(isDemoLaunchRegistration); + const launchingApps = this.connections.filter(isLaunchingAppRegistration); if (launchingApps.length == 0) { console.warn('Could not locate an app registration for a window and there are no window launches in progress!'); return; } else { //we need to wait on all currently launching windows as it could be any one of those - return new Promise(resolve => { + return new Promise(resolve => { const toMonitor = launchingApps.length; let doneCount = 0; launchingApps.forEach(launchingApp => { launchingApp.windowPromise.then(realizedWindow => { doneCount++; if (realizedWindow == window) { - //note that this record will separately be converting itself into a DemoAppRegistration + //note that this record will separately be converting itself into a RunningAppRegistration resolve({ window: realizedWindow, url: launchingApp.url, @@ -140,15 +147,10 @@ export class DemoServerContext implements ServerContext { } } - getInstanceDetails(uuid: InstanceID): DemoRegistration | undefined { + getInstanceDetails(uuid: InstanceID): DemoAppRegistration | undefined { return this.connections.find(i => i.instanceId == uuid); } - getPastInstanceDetails(uuid: InstanceID): DemoAppRegistration | undefined { - this.prunePastConnections(); - return this.pastConnections.find(i => i.registration.instanceId == uuid)?.registration; - } - getOpener(): Opener { const cb = document.getElementById('opener') as HTMLInputElement; const val = cb.value; @@ -167,22 +169,6 @@ export class DemoServerContext implements ServerContext { this.socket.emit(FDC3_DA_EVENT, message, to); } - goodbye(id: string) { - const registration = this.connections.find(i => i.instanceId == id); - this.connections = this.connections.filter(i => i.instanceId !== id); - - //cache the connection details in case the app tries to reconnect - if (registration && isDemoAppRegistration(registration)) { - this.pastConnections.push({ registration, timestamp: Date.now() }); - } - - console.debug(`Closed instance`, id); - console.debug( - `Open apps:`, - this.connections.map(i => i.instanceId) - ); - } - openFrame(url: string): Promise { const iframe = document.createElement('iframe'); iframe.setAttribute('src', url); @@ -242,7 +228,7 @@ export class DemoServerContext implements ServerContext { //const window = await this.openUrl(url); const windowPromise = this.openUrl(url); const instanceId: InstanceID = this.createUUID(); - const metadata: DemoLaunchRegistration = { + const metadata: LaunchingAppRegistration = { appId, instanceId, windowPromise, @@ -270,10 +256,18 @@ export class DemoServerContext implements ServerContext { return found != null; } - async setAppState(app: InstanceID, state: State): Promise { + async setAppState(app: InstanceID, newState: State): Promise { const found = this.connections.find(a => a.instanceId == app); + + //if this is a new termination (which might be due to a heartbeat) then notify the server + // if we were already terminated, don't bother as the server will notify us back and + // create a loop if (found) { - found.state = state; + const currentState = found.state; + if (currentState !== State.Terminated && newState === State.Terminated) { + this.server?.cleanup(app); + } + found.state = newState; } } diff --git a/toolbox/fdc3-for-web/demo/src/client/da/util.ts b/toolbox/fdc3-for-web/demo/src/client/da/util.ts index 6c362a9f6..91338f1bc 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/util.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/util.ts @@ -20,6 +20,7 @@ export const UI_URLS = { }; export function link(socket: Socket, channel: MessageChannel, source: InstanceID) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any socket.on(FDC3_DA_EVENT, (data: any) => { channel.port2.postMessage(data); }); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index 92ac661a4..c9dcdf0d2 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -1,5 +1,5 @@ import { FDC3Server } from './FDC3Server'; -import { AppRegistration, InstanceID, ServerContext } from './ServerContext'; +import { AppRegistration, InstanceID, ServerContext, State } from './ServerContext'; import { BroadcastHandler, ChannelState } from './handlers/BroadcastHandler'; import { IntentHandler } from './handlers/IntentHandler'; import { Directory } from './directory/DirectoryInterface'; @@ -45,7 +45,7 @@ export class BasicFDC3Server implements FDC3Server { cleanup(instanceId: InstanceID): void { this.handlers.forEach(handler => handler.cleanup(instanceId, this.sc)); - this.sc.goodbye(instanceId); + this.sc.setAppState(instanceId, State.Terminated); } receive( diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts index 048df7fb3..d2f2c4a3a 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/ServerContext.ts @@ -1,5 +1,6 @@ import { AppIdentifier, AppIntent } from '@kite9/fdc3-standard'; import { Context } from '@kite9/fdc3-context'; +import { FDC3Server } from './FDC3Server'; export enum State { Pending /* App has started, but not completed FDC3 Handshake */, @@ -36,21 +37,18 @@ export interface ServerContext { */ post(message: object, instanceId: InstanceID): Promise; - /** - * Post an outgoing message to a particular app - */ - post(message: object, instanceId: InstanceID): Promise; - /** * Opens a new instance of an application. * Promise completes once the application window is opened */ open(appId: string): Promise; - /** - * Handle clean-up of state after an app instance disconnects. + /** Set the FDC3Server instance associated with this context. This reference is + * used to notify the server to cleanup state for apps that have been terminated. + * The FDC3Server is passed a ServerContext when created and should call this fn + * in its constructor. */ - goodbye(instanceId: string): void; + setFDC3Server(server: FDC3Server): void; /** * Registers a particular instance id with a given app id @@ -64,13 +62,6 @@ export interface ServerContext { */ getInstanceDetails(uuid: InstanceID): X | undefined; - /** - * Returns the connection details for a particular instance of an app that - * was previously connected to the Desktop Agent. Used when validating an - * app's identity when reconnecting. - */ - getPastInstanceDetails(uuid: InstanceID): X | undefined; - /** * Registers an app as connected to the desktop agent. */ diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts index 266ab669a..2501dd4f6 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts @@ -135,8 +135,7 @@ export class IntentHandler implements MessageHandler { this.timeoutMs = timeoutMs; } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - cleanup(instanceId: InstanceID, _sc: ServerContext): void { + cleanup(instanceId: InstanceID /*, _sc: ServerContext */): void { this.registrations = this.registrations.filter(reg => reg.instanceId != instanceId); //don't clean up pendingIntents as some apps may load @@ -208,6 +207,7 @@ export class IntentHandler implements MessageHandler { const to = this.pendingResolutions.get(requestId); if (to) { // post the result to the app that raised the intent + // if its still connected, otherwise do nothing successResponseId( sc, requestId, @@ -218,13 +218,10 @@ export class IntentHandler implements MessageHandler { 'raiseIntentResultResponse' ); - // respond to the app that handled the intent - successResponse(sc, arg0, from, {}, 'intentResultResponse'); this.pendingResolutions.delete(requestId); - } else { - // no-one waiting for this result - errorResponse(sc, arg0, from, 'No-one waiting for this result', 'intentResultResponse'); } + // respond to the app that handled the intent + successResponse(sc, arg0, from, {}, 'intentResultResponse'); } onUnsubscribe( diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts index 535d57a52..76dc58f8e 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/OpenHandler.ts @@ -324,12 +324,16 @@ export class OpenHandler implements MessageHandler { if (arg0.payload.instanceUuid) { // existing app reconnecting console.log('App attempting to reconnect:', arg0.payload.instanceUuid); - const appIdentity = sc.getPastInstanceDetails(arg0.payload.instanceUuid); + const appIdentity = sc.getInstanceDetails(arg0.payload.instanceUuid); if (appIdentity) { - // in this case, the app is reconnecting, so let's just re-assign the - // identity - console.log(`Reassigned existing identity (appId: ${appIdentity.appId}): `, arg0.payload.instanceUuid); + // in this case, the app is reconnecting, so let's just re-assign the identity + console.log( + `Reassigned existing identity, appId: `, + appIdentity.appId, + ', instanceId', + arg0.payload.instanceUuid + ); sc.setInstanceDetails(from, appIdentity); sc.setAppState(from, State.Connected); return returnSuccess(appIdentity.appId, appIdentity.instanceId); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts index 5bbd41e92..56aa70045 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/support/TestServerContext.ts @@ -1,3 +1,4 @@ +import { FDC3Server } from '../../src/FDC3Server'; import { ServerContext, InstanceID, State, AppRegistration } from '../../src/ServerContext'; import { CustomWorld } from '../world'; import { Context } from '@kite9/fdc3-context'; @@ -19,13 +20,14 @@ export class TestServerContext implements ServerContext { private instances: ConnectionDetails[] = []; private nextInstanceId: number = 0; private nextUUID: number = 0; + private server: FDC3Server | null = null; constructor(cw: CustomWorld) { this.cw = cw; } - goodbye(instanceId: string): void { - this.instances = this.instances.filter(instance => instance.instanceId !== instanceId); + setFDC3Server(server: FDC3Server): void { + this.server = server; } // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -37,11 +39,6 @@ export class TestServerContext implements ServerContext { return this.instances.find(ca => ca.instanceId === uuid); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - getPastInstanceDetails(_uuid: string) { - return undefined; - } - setInstanceDetails(uuid: InstanceID, appId: ConnectionDetails) { if (uuid != appId.instanceId) { throw new Error('UUID mismatch'); @@ -61,10 +58,14 @@ export class TestServerContext implements ServerContext { } } - async setAppState(app: InstanceID, state: State): Promise { + async setAppState(app: InstanceID, newState: State): Promise { const found = this.instances.find(a => a.instanceId == app); if (found) { - found.state = state; + const currentState = found.state; + if (currentState !== State.Terminated && newState === State.Terminated) { + this.server?.cleanup(app); + } + found.state = newState; } } From ec14275630ae302e7ceee99d36d810bb68f3108b Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 9 Jan 2025 18:29:44 +0000 Subject: [PATCH 75/90] Refining fdc3-for-web-impl's findIntent fns, tests and cleanup on disconnection --- .../findIntentsByContextResponse.schema.json | 3 +- .../fdc3-web-impl/src/BasicFDC3Server.ts | 9 +- .../fdc3-web-impl/src/FDC3Server.ts | 2 +- .../src/directory/BasicDirectory.ts | 8 +- .../src/directory/DirectoryInterface.ts | 4 +- .../src/handlers/BroadcastHandler.ts | 2 +- .../src/handlers/HeartbeatHandler.ts | 4 +- .../src/handlers/IntentHandler.ts | 61 +++++++------ .../test/features/disconnect-cleanup.feature | 66 ++++++++++++++ .../test/features/find-intent.feature | 43 +++++++++- .../test/features/user-channels.feature | 2 +- .../step-definitions/app-channel.steps.ts | 2 +- .../test/step-definitions/broadcast.steps.ts | 8 +- .../test/step-definitions/generic.steps.ts | 7 ++ .../test/step-definitions/intents.steps.ts | 85 +++++++------------ .../step-definitions/private-channel.steps.ts | 6 +- .../step-definitions/user-channel.steps.ts | 12 +-- 17 files changed, 210 insertions(+), 114 deletions(-) create mode 100644 toolbox/fdc3-for-web/fdc3-web-impl/test/features/disconnect-cleanup.feature diff --git a/packages/fdc3-schema/schemas/api/findIntentsByContextResponse.schema.json b/packages/fdc3-schema/schemas/api/findIntentsByContextResponse.schema.json index 9ccf5cce1..c74c6bda1 100644 --- a/packages/fdc3-schema/schemas/api/findIntentsByContextResponse.schema.json +++ b/packages/fdc3-schema/schemas/api/findIntentsByContextResponse.schema.json @@ -42,8 +42,7 @@ "type": "array", "items": { "$ref": "api.schema.json#/definitions/AppIntent" - }, - "additionalProperties": false + } } }, "required": [ diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts index c9dcdf0d2..b9b24f33c 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/BasicFDC3Server.ts @@ -21,7 +21,7 @@ export interface MessageHandler { msg: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity | WebConnectionProtocol6Goodbye, sc: ServerContext, from: InstanceID - ): void; + ): Promise; /** * Clean-up any state relating to a instance that has disconnected. @@ -48,11 +48,12 @@ export class BasicFDC3Server implements FDC3Server { this.sc.setAppState(instanceId, State.Terminated); } - receive( + async receive( message: AppRequestMessage | WebConnectionProtocol4ValidateAppIdentity | WebConnectionProtocol6Goodbye, from: InstanceID - ): void { - this.handlers.forEach(h => h.accept(message, this.sc, from)); + ): Promise { + const promises = this.handlers.map(h => h.accept(message, this.sc, from)); + await Promise.allSettled(promises); } shutdown(): void { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts index 02b163bd9..fdd7fb529 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/FDC3Server.ts @@ -7,7 +7,7 @@ export interface FDC3Server { /** * Receive an incoming message */ - receive(message: AppRequestMessage, from: InstanceID): void; + receive(message: AppRequestMessage, from: InstanceID): Promise; /** * Cleanup state relating to an instance that has disconnected diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts index 80053626c..fc007ff39 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/BasicDirectory.ts @@ -69,13 +69,15 @@ export class BasicDirectory implements Directory { retrieveApps( contextType: string | undefined, - intentName: string | undefined, - resultType: string | undefined + intentName?: string | undefined, + resultType?: string | undefined ): DirectoryApp[] { - return this.retrieveAllApps().filter( + const result = this.retrieveAllApps().filter( a => this.retrieveIntentsForApp(a).filter(i => this.intentMatches(i, contextType, intentName, resultType)).length > 0 ); + + return result; } retrieveAppsById(appId: string): DirectoryApp[] { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/DirectoryInterface.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/DirectoryInterface.ts index 93407f0b8..de6ac9c16 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/DirectoryInterface.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/directory/DirectoryInterface.ts @@ -24,8 +24,8 @@ export interface Directory { retrieveIntents( contextType: string | undefined, - intentName: string | undefined, - resultType: string | undefined + intentName?: string | undefined, + resultType?: string ): DirectoryIntent[]; retrieveAppsById(appId: string): DirectoryApp[]; diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts index 75a0d73b9..3b261f4ff 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/BroadcastHandler.ts @@ -144,7 +144,7 @@ export class BroadcastHandler implements MessageHandler { } } - accept(msg: AppRequestMessage, sc: ServerContext, uuid: InstanceID) { + async accept(msg: AppRequestMessage, sc: ServerContext, uuid: InstanceID) { const from = sc.getInstanceDetails(uuid); if (from == null) { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts index bb63d6fa8..e4bdcd751 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/HeartbeatHandler.ts @@ -104,11 +104,11 @@ export class HeartbeatHandler implements MessageHandler { clearInterval(this.timerFunction); } - accept( + async accept( msg: AppRequestMessage | WebConnectionProtocol6Goodbye, sc: ServerContext, from: InstanceID - ): void { + ): Promise { if (!this.contexts.includes(sc)) { this.contexts.push(sc); } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts index 2501dd4f6..a6ebc14e6 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/src/handlers/IntentHandler.ts @@ -171,23 +171,23 @@ export class IntentHandler implements MessageHandler { switch (msg.type as string) { // finding intents case 'findIntentsByContextRequest': - return this.findIntentsByContextRequest(msg as FindIntentsByContextRequest, sc, from); + return await this.findIntentsByContextRequest(msg as FindIntentsByContextRequest, sc, from); case 'findIntentRequest': - return this.findIntentRequest(msg as FindIntentRequest, sc, from); + return await this.findIntentRequest(msg as FindIntentRequest, sc, from); // listeners case 'addIntentListenerRequest': - return this.onAddIntentListener(msg as AddIntentListenerRequest, sc, from); + return await this.onAddIntentListener(msg as AddIntentListenerRequest, sc, from); case 'intentListenerUnsubscribeRequest': - return this.onUnsubscribe(msg as IntentListenerUnsubscribeRequest, sc, from); + return await this.onUnsubscribe(msg as IntentListenerUnsubscribeRequest, sc, from); // raising intents and returning results case 'raiseIntentRequest': - return this.raiseIntentRequest(msg as RaiseIntentRequest, sc, from); + return await this.raiseIntentRequest(msg as RaiseIntentRequest, sc, from); case 'raiseIntentForContextRequest': - return this.raiseIntentForContextRequest(msg as RaiseIntentForContextRequest, sc, from); + return await this.raiseIntentForContextRequest(msg as RaiseIntentForContextRequest, sc, from); case 'intentResultRequest': - return this.intentResultRequest(msg as IntentResultRequest, sc, from); + return await this.intentResultRequest(msg as IntentResultRequest, sc, from); } } catch (e) { const responseType = msg.type.replace(new RegExp('Request$'), 'Response') as AgentResponseMessage['type']; @@ -570,19 +570,22 @@ export class IntentHandler implements MessageHandler { sc: ServerContext, from: FullAppIdentifier ): Promise { - // TODO: Add result type - const { context } = r.payload; + const { context, resultType } = r.payload; - const apps1 = this.directory.retrieveIntents(context?.type, undefined, undefined); + const apps1 = this.directory.retrieveIntents(context?.type, undefined, resultType); // fold apps so same intents aren't duplicated const apps2: AppIntent[] = []; - apps1.forEach(a1 => { + //don't use foreach as the handling function is async and needs to process serially + for (let index = 0; index < apps1.length; index++) { + const a1 = apps1[index]; const existing = apps2.find(a2 => a2.intent.name == a1.intentName); + const runningInstances = await this.retrieveRunningInstances(a1.appId, sc); if (existing) { existing.apps.push({ appId: a1.appId }); + runningInstances.forEach(ri => existing.apps.push({ appId: a1.appId, instanceId: ri.instanceId })); } else { - apps2.push({ + const appIntent: AppIntent = { intent: { name: a1.intentName, displayName: a1.displayName ?? a1.intentName, @@ -592,9 +595,11 @@ export class IntentHandler implements MessageHandler { appId: a1.appId, }, ], - }); + }; + runningInstances.forEach(ri => appIntent.apps.push({ appId: a1.appId, instanceId: ri.instanceId })); + apps2.push(appIntent); } - }); + } successResponse( sc, @@ -623,18 +628,14 @@ export class IntentHandler implements MessageHandler { }) as AppIdentifier[]; // directory entries - const apps1 = this.directory - .retrieveApps(context?.type, intent, resultType) - .map(a => { - return { - appId: a.appId, - }; - }) - .filter(i => { - // remove any directory entries that are already started - const running = apps2.find(i2 => i2.appId == i.appId); - return !running; - }) as AppIdentifier[]; + const apps1 = this.directory.retrieveApps(context?.type, intent, resultType).map(a => { + return { + appId: a.appId, + }; + }); + + //combine the lists, no need to de-duplicate as we should return both a directory record with just appId + any instance with appId/instanceId + const finalApps = [...apps1, ...apps2]; // just need this for the (deprecated) display name const allMatchingIntents = this.directory.retrieveIntents(context?.type, intent, resultType); @@ -650,7 +651,7 @@ export class IntentHandler implements MessageHandler { name: intent, displayName, }, - apps: [...apps1, ...apps2], + apps: finalApps, }, }, 'findIntentResponse' @@ -666,4 +667,10 @@ export class IntentHandler implements MessageHandler { const active = matching.filter(r => activeApps.find(a => a.instanceId == r.instanceId)); return active; } + + async retrieveRunningInstances(appId: string, sc: ServerContext) { + const activeApps = await sc.getConnectedApps(); + const filteredApps = activeApps.filter(a => a.appId === appId); + return filteredApps; + } } diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/disconnect-cleanup.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/disconnect-cleanup.feature new file mode 100644 index 000000000..bdf245e19 --- /dev/null +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/disconnect-cleanup.feature @@ -0,0 +1,66 @@ +Feature: App Disconnection and Cleanup + + Background: + Given schemas loaded + + Scenario: Apps that disconnect and reconnect to the DA should receive one copy of a broadcast message from an app channel as state was cleaned up + Given A newly instantiated FDC3 Server + When "App1/a1" is opened with connection id "a1" + And "App2/a2" is opened with connection id "a2" + And "App2/a2" adds a context listener on "one" with type "fdc3.instrument" + And we wait for a period of "100" ms + And "App1/a1" broadcasts "fdc3.instrument" on "one" + Then messaging will have outgoing posts + | msg.matches_type | to.appId | to.instanceId | msg.payload.channelId | msg.payload.context.type | msg.payload.context.id.ticker | + | addContextListenerResponse | App2 | a2 | {null} | {null} | {null} | + | broadcastEvent | App2 | a2 | one | fdc3.instrument | AAPL | + | broadcastResponse | App1 | a1 | {null} | {null} | {null} | + And "App2/a2" is closed + And "App2/a2" is opened with connection id "a2" + And "App2/a2" adds a context listener on "one" with type "fdc3.instrument" + And we wait for a period of "100" ms + And "App1/a1" broadcasts "fdc3.instrument" on "one" + Then messaging will have outgoing posts + | msg.matches_type | to.appId | to.instanceId | msg.payload.channelId | msg.payload.context.type | msg.payload.context.id.ticker | + | addContextListenerResponse | App2 | a2 | {null} | {null} | {null} | + | broadcastEvent | App2 | a2 | one | fdc3.instrument | AAPL | + | broadcastResponse | App1 | a1 | {null} | {null} | {null} | + + + Scenario: Apps that disconnect and reconnect to the DA should NOT receive intent results from the previous connection as state was cleaned up + Given "libraryApp" is an app with the following intents + | Intent Name | Context Type | Result Type | + | returnBook | fdc3.book | {empty} | + And "App1" is an app with the following intents + | Intent Name | Context Type | Result Type | + | viewNews | fdc3.instrument | {empty} | + And A newly instantiated FDC3 Server + When "LibraryApp/l1" is opened with connection id "l1" + And "App1/a1" is opened with connection id "a1" + And "LibraryApp/l1" registers an intent listener for "returnBook" + And "App1/a1" raises an intent for "returnBook" with contextType "fdc3.book" on app "LibraryApp/l1" with requestUuid "ABC123" + And we wait for a period of "100" ms + And "App1/a1" is closed + And we wait for a period of "100" ms + And "LibraryApp/l1" sends a intentResultRequest with eventUuid "uuid7" and contextType "fdc3.book" and raiseIntentUuid "ABC123" + Then messaging will have outgoing posts + | msg.matches_type | msg.meta.eventUuid | msg.meta.requestUuid | to.appId | to.instanceId | msg.payload.raiseIntentRequestUuid | msg.payload.intentResolution.source.instanceId | msg.payload.intentResult.context.type | + | intentEvent | uuid7 | {null} | LibraryApp | l1 | ABC123 | {null} | {null} | + | raiseIntentResponse | {null} | ABC123 | App1 | a1 | {null} | l1 | {null} | + | intentResultResponse | {null} | uuid10 | LibraryApp | l1 | {null} | {null} | {null} | + +Scenario: Disconnecting from the DA when subscribed to a private channel channel sends unsubscribe and disconnect messages + And A newly instantiated FDC3 Server + And "App1/a1" is opened with connection id "a1" + And "App2/a2" is opened with connection id "a2" + And "App2/a1" creates a private channel + #TODO: have a2 retrieve the private channel by raising an intent - its currently using a1 reference to the channel + And I refer to "uuid3" as "channel1Id" + When "App2/a2" adds an "disconnect" event listener on "{channel1Id}" + And "App1/a1" adds a context listener on "{channel1Id}" with type "fdc3.instrument" + And "App2/a2" adds an "unsubscribe" event listener on "{channel1Id}" + And "App1/a1" is closed + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.privateChannelId | msg.payload.contextType | to.appId | to.instanceId | + | privateChannelOnUnsubscribeEvent | {channel1Id} | fdc3.instrument | App2 | a2 | + | privateChannelOnDisconnectEvent | {channel1Id} | {null} | App2 | a2 | \ No newline at end of file diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/find-intent.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/find-intent.feature index a09d1c77b..0eda1465f 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/find-intent.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/find-intent.feature @@ -8,10 +8,25 @@ Feature: Find Intent API | streamBook | fdc3.book | channel | | returnBook | fdc3.book | {empty} | | streamAny | fdc3.book | channel | + And "bakeryApp" is an app with the following intents + | Intent Name | Context Type | Result Type | + | viewStock | fdc3.product | {empty} | + And "butcherApp" is an app with the following intents + | Intent Name | Context Type | Result Type | + | viewStock | fdc3.product | {empty} | + And "chandlerApp" is an app with the following intents + | Intent Name | Context Type | Result Type | + | viewStock | fdc3.product | {empty} | And A newly instantiated FDC3 Server And "App1/a1" is opened with connection id "a1" And "App1/b1" is opened with connection id "b1" And "App1/b1" registers an intent listener for "returnBook" + And "butcherApp/b2" is opened with connection id "b2" + And "butcherApp/b2" registers an intent listener for "viewStock" + #first app returned by directory must have an instance to cover all branches in findIntentsByContextRequest + And "bakeryApp/b3" is opened with connection id "b3" + And "bakeryApp/b3" registers an intent listener for "viewStock" + And we wait for a period of "100" ms Scenario: Unsuccessful Find Intents Request When "App1/a1" finds intents with intent "loanBook" and contextType "fdc3.instrument" and result type "{empty}" @@ -31,12 +46,36 @@ Feature: Find Intent API | msg.matches_type | msg.payload.appIntent.intent.name | msg.payload.appIntent.apps.length | msg.payload.appIntent.apps[0].appId | to.instanceId | msg.payload.appIntent.intent.displayName | | findIntentResponse | loanBook | 1 | libraryApp | a1 | loan book | + Scenario: Find Intents Requests should include both the app and running instances of it + When "App1/a1" finds intents with intent "viewStock" and contextType "fdc3.product" and result type "{empty}" + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.appIntent.intent.name | msg.payload.appIntent.apps.length | to.instanceId | + | findIntentResponse | viewStock | 5 | a1 | + When "butcherApp/b2" is closed + And "App1/a1" finds intents with intent "viewStock" and contextType "fdc3.product" and result type "{empty}" + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.appIntent.intent.name | msg.payload.appIntent.apps.length | to.instanceId | + | findIntentResponse | viewStock | 4 | a1 | + Scenario: Find Intents by Context Request When "App/a1" finds intents with contextType "fdc3.book" Then messaging will have outgoing posts | msg.matches_type | msg.payload.appIntents[0].intent.name | msg.payload.appIntents.length | to.instanceId | msg.payload.appIntents[0].intent.displayName | | findIntentsByContextResponse | loanBook | 4 | a1 | loan book | + Scenario: Find Intents by Context Request with multiple results + When "App/a1" finds intents with contextType "fdc3.product" + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.appIntents[0].intent.name | msg.payload.appIntents.length | to.instanceId | msg.payload.appIntents[0].apps.length | + | findIntentsByContextResponse | viewStock | 1 | a1 | 5 | + + Scenario: Find Intents by Context Request with multiple results which should not include an instance that has closed + When "butcherApp/b2" is closed + When "App/a1" finds intents with contextType "fdc3.product" + Then messaging will have outgoing posts + | msg.matches_type | msg.payload.appIntents[0].intent.name | msg.payload.appIntents.length | to.instanceId | msg.payload.appIntents[0].apps.length | + | findIntentsByContextResponse | viewStock | 1 | a1 | 4 | + Scenario: Successful Find Intents Request With Channel When "App1/a1" finds intents with intent "streamBook" and contextType "fdc3.book" and result type "channel" Then messaging will have outgoing posts @@ -69,7 +108,7 @@ Feature: Find Intent API Scenario: Disconnecting The Intent Listener When "App1/b1" unsubscribes an intent listener with id "uuid3" - When "App1/a1" finds intents with intent "returnBook" and contextType "fdc3.book" and result type "{empty}" + And "App1/a1" finds intents with intent "returnBook" and contextType "fdc3.book" and result type "{empty}" Then messaging will have outgoing posts | msg.matches_type | msg.payload.appIntent.intent.name | msg.payload.appIntent.apps.length | to.instanceId | msg.payload.appIntent.apps[0].appId | | intentListenerUnsubscribeResponse | {null} | {null} | b1 | {null} | @@ -77,7 +116,7 @@ Feature: Find Intent API Scenario: Find Intent excludes results for a closed app with intent listener When "App1/b1" is closed - When "App1/a1" finds intents with intent "returnBook" and contextType "fdc3.book" and result type "{empty}" + And "App1/a1" finds intents with intent "returnBook" and contextType "fdc3.book" and result type "{empty}" Then messaging will have outgoing posts | msg.matches_type | msg.payload.appIntent.intent.name | msg.payload.appIntent.apps.length | to.instanceId | msg.payload.appIntent.apps[0].appId | | findIntentResponse | returnBook | 1 | a1 | libraryApp | diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/user-channels.feature b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/user-channels.feature index b8ecc57b8..3df2073fa 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/features/user-channels.feature +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/features/user-channels.feature @@ -75,7 +75,7 @@ Feature: Relaying Private Channel Broadcast messages Scenario: I should be able to leave a user channel, and not receive messages on it When "App/a1" joins user channel "one" And "App/a1" adds a context listener on "one" with type "{null}" - And "App/a1" leaves user channel "one" + And "App/a1" leaves the current user channel And "App2/a2" broadcasts "fdc3.instrument" on "one" Then messaging will have outgoing posts | msg.matches_type | diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/app-channel.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/app-channel.steps.ts index 455ed05ab..e5b6beda0 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/app-channel.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/app-channel.steps.ts @@ -9,7 +9,7 @@ When( '{string} creates or gets an app channel called {string}', function (this: CustomWorld, app: string, channel: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/broadcast.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/broadcast.steps.ts index f2d07e903..5d68601ff 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/broadcast.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/broadcast.steps.ts @@ -15,7 +15,7 @@ When( '{string} adds a context listener on {string} with type {string}', function (this: CustomWorld, app: string, channelId: string, contextType: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { @@ -33,7 +33,7 @@ When( '{string} asks for the latest context on {string} with type {string}', function (this: CustomWorld, app: string, channelId: string, contextType: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { @@ -49,7 +49,7 @@ When( When('{string} removes context listener with id {string}', function (this: CustomWorld, app: string, id: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, @@ -66,7 +66,7 @@ When( '{string} broadcasts {string} on {string}', function (this: CustomWorld, app: string, contextType: string, channelId: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts index 630df0256..c70600266 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/generic.steps.ts @@ -45,6 +45,13 @@ export const contextMap: Record = { ISSN: '1234', }, }, + 'fdc3.product': { + type: 'fdc3.product', + title: 'Current bun', + id: { + productId: 'cb1', + }, + }, }; function defaultChannels() { diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts index 97eacea5d..1ff088813 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/intents.steps.ts @@ -67,7 +67,7 @@ Given('{string} is an app with the following intents', function (this: CustomWor When( '{string} finds intents with intent {string} and contextType {string} and result type {string}', - function (this: CustomWorld, appStr: string, intentName: string, contextType: string, resultType: string) { + async function (this: CustomWorld, appStr: string, intentName: string, contextType: string, resultType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { @@ -80,13 +80,13 @@ When( type: 'findIntentRequest', } as FindIntentRequest; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} finds intents with contextType {string}', - function (this: CustomWorld, appStr: string, contextType: string) { + async function (this: CustomWorld, appStr: string, contextType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { @@ -97,13 +97,13 @@ When( type: 'findIntentsByContextRequest', } as FindIntentsByContextRequest; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); Given( '{string} registers an intent listener for {string}', - function (this: CustomWorld, appStr: string, intent: string) { + async function (this: CustomWorld, appStr: string, intent: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; @@ -114,13 +114,13 @@ Given( intent: handleResolve(intent, this), }, } as AddIntentListenerRequest; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); Given( '{string} registers an intent listener for {string} with contextType {string}', - function (this: CustomWorld, appStr: string, intent: string, contextType: string) { + async function (this: CustomWorld, appStr: string, intent: string, contextType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { @@ -131,13 +131,13 @@ Given( contextType: handleResolve(contextType, this), }, } as AddIntentListenerRequest; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); Given( '{string} unsubscribes an intent listener with id {string}', - function (this: CustomWorld, appStr: string, id: string) { + async function (this: CustomWorld, appStr: string, id: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { @@ -147,7 +147,7 @@ Given( listenerUUID: handleResolve(id, this), }, } as IntentListenerUnsubscribeRequest; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); @@ -232,67 +232,67 @@ function raiseWithContextAnInvalidTarget( When( '{string} raises an intent with contextType {string}', - function (this: CustomWorld, appStr: string, contextType: string) { + async function (this: CustomWorld, appStr: string, contextType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raiseWithContext(this, contextType, null, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} raises an intent with contextType {string} on app {string}', - function (this: CustomWorld, appStr: string, contextType: string, dest: string) { + async function (this: CustomWorld, appStr: string, contextType: string, dest: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raiseWithContext(this, contextType, dest, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} raises an intent for {string} with contextType {string}', - function (this: CustomWorld, appStr: string, intentName: string, contextType: string) { + async function (this: CustomWorld, appStr: string, intentName: string, contextType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raise(this, intentName, contextType, null, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} raises an intent for {string} with contextType {string} on app {string}', - function (this: CustomWorld, appStr: string, intentName: string, contextType: string, dest: string) { + async function (this: CustomWorld, appStr: string, intentName: string, contextType: string, dest: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raise(this, intentName, contextType, dest, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} raises an intent for {string} with contextType {string} on an invalid app instance', - function (this: CustomWorld, appStr: string, intentName: string, contextType: string) { + async function (this: CustomWorld, appStr: string, intentName: string, contextType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raiseWithInvalidTarget(this, intentName, contextType, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} raises an intent with contextType {string} on an invalid app instance', - function (this: CustomWorld, appStr: string, contextType: string) { + async function (this: CustomWorld, appStr: string, contextType: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raiseWithContextAnInvalidTarget(contextType, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} raises an intent for {string} with contextType {string} on app {string} with requestUuid {string}', - function ( + async function ( this: CustomWorld, appStr: string, intentName: string, @@ -306,7 +306,7 @@ When( }; const uuid = this.sc.getInstanceUUID(meta.source)!; const message = raise(this, intentName, contextType, dest, meta); - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); @@ -318,7 +318,7 @@ When('we wait for the intent timeout', function (this: CustomWorld) { When( '{string} sends a intentResultRequest with eventUuid {string} and contextType {string} and raiseIntentUuid {string}', - function (this: CustomWorld, appStr: string, eventUuid: string, contextType: string, raiseIntentUuid: string) { + async function (this: CustomWorld, appStr: string, eventUuid: string, contextType: string, raiseIntentUuid: string) { const meta = createMeta(this, appStr); const uuid1 = this.sc.getInstanceUUID(meta.source)!; const message: IntentResultRequest = { @@ -334,13 +334,13 @@ When( raiseIntentRequestUuid: raiseIntentUuid, }, }; - this.server.receive(message, uuid1); + await this.server.receive(message, uuid1); } ); When( '{string} sends a intentResultRequest with eventUuid {string} and void contents and raiseIntentUuid {string}', - function (this: CustomWorld, appStr: string, eventUuid: string, raiseIntentUuid: string) { + async function (this: CustomWorld, appStr: string, eventUuid: string, raiseIntentUuid: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; const message: IntentResultRequest = { @@ -354,13 +354,13 @@ When( raiseIntentRequestUuid: raiseIntentUuid, }, }; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); When( '{string} sends a intentResultRequest with eventUuid {string} and private channel {string} and raiseIntentUuid {string}', - function (this: CustomWorld, appStr: string, eventUuid: string, channelId: string, raiseIntentUuid: string) { + async function (this: CustomWorld, appStr: string, eventUuid: string, channelId: string, raiseIntentUuid: string) { const meta = createMeta(this, appStr); const uuid = this.sc.getInstanceUUID(meta.source)!; @@ -380,31 +380,6 @@ When( raiseIntentRequestUuid: raiseIntentUuid, }, }; - this.server.receive(message, uuid); + await this.server.receive(message, uuid); } ); - -// When('{string} sends a intentResultRequest with eventUuid {string}', function (this: CustomWorld, appStr: string, requestUuid: string) { -// const meta = createMeta(this, appStr) -// const uuid = this.sc.getInstanceUUID(meta.source)!! -// const message = { -// type: 'intentResultRequest', -// meta: { -// requestUuid: meta.requestUuid, -// responseUuid: this.sc.createUUID(), -// timestamp: new Date() -// }, -// payload: { -// intentResult: { -// context: { -// "type": "fdc3.something", -// "name": "Some Name" -// } -// }, -// intentEventUuid: 'event-uuid-1', -// raiseIntentRequestUuid: requestUuid -// } -// } as IntentResultRequest - -// this.server.receive(message, uuid) -// }); diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts index 77df32570..b32d9ad07 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/private-channel.steps.ts @@ -11,7 +11,7 @@ type PrivateChannelDisconnectRequest = BrowserTypes.PrivateChannelDisconnectRequ When('{string} creates a private channel', function (this: CustomWorld, app: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: {}, @@ -23,7 +23,7 @@ When('{string} creates a private channel', function (this: CustomWorld, app: str When('{string} removes event listener {string}', function (this: CustomWorld, app: string, listenerUUID: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { @@ -57,7 +57,7 @@ When( '{string} disconnects from private channel {string}', function (this: CustomWorld, app: string, channelId: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/user-channel.steps.ts b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/user-channel.steps.ts index 5cc8d1307..bec7be436 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/user-channel.steps.ts +++ b/toolbox/fdc3-for-web/fdc3-web-impl/test/step-definitions/user-channel.steps.ts @@ -12,7 +12,7 @@ type GetCurrentContextRequest = BrowserTypes.GetCurrentContextRequest; When('{string} gets the list of user channels', function (this: CustomWorld, app: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: {}, @@ -24,7 +24,7 @@ When('{string} gets the list of user channels', function (this: CustomWorld, app When('{string} gets the current user channel', function (this: CustomWorld, app: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: {}, @@ -34,9 +34,9 @@ When('{string} gets the current user channel', function (this: CustomWorld, app: this.server.receive(message, uuid); }); -When('{string} leaves user channel {string}', function (this: CustomWorld, app: string, _channel: string) { +When('{string} leaves the current user channel', function (this: CustomWorld, app: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: {}, @@ -48,7 +48,7 @@ When('{string} leaves user channel {string}', function (this: CustomWorld, app: When('{string} joins user channel {string}', function (this: CustomWorld, app: string, channel: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { @@ -64,7 +64,7 @@ When( '{string} gets the latest context on {string} with type {string}', function (this: CustomWorld, app: string, channel: string, type: string) { const meta = createMeta(this, app); - const uuid = this.sc.getInstanceUUID(meta.source)!!; + const uuid = this.sc.getInstanceUUID(meta.source)!; const message = { meta, payload: { From 1cb72b9cc69753bcb20f646913066bff1d9b6724 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 9 Jan 2025 18:30:23 +0000 Subject: [PATCH 76/90] rolling package verison numbers --- packages/fdc3-agent-proxy/package.json | 2 +- packages/fdc3-commonjs/package.json | 2 +- packages/fdc3-context/package.json | 2 +- packages/fdc3-get-agent/package.json | 2 +- packages/fdc3-schema/package.json | 2 +- packages/fdc3-standard/package.json | 2 +- packages/fdc3/package.json | 2 +- toolbox/fdc3-for-web/demo/package.json | 2 +- toolbox/fdc3-for-web/fdc3-web-impl/package.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/fdc3-agent-proxy/package.json b/packages/fdc3-agent-proxy/package.json index e910557fe..0e8947e3f 100644 --- a/packages/fdc3-agent-proxy/package.json +++ b/packages/fdc3-agent-proxy/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-agent-proxy", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3-commonjs/package.json b/packages/fdc3-commonjs/package.json index cc819cc27..a068334d1 100644 --- a/packages/fdc3-commonjs/package.json +++ b/packages/fdc3-commonjs/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-commonjs", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3-context/package.json b/packages/fdc3-context/package.json index 4947d6bd1..b0fedaeef 100644 --- a/packages/fdc3-context/package.json +++ b/packages/fdc3-context/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-context", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3-get-agent/package.json b/packages/fdc3-get-agent/package.json index 7ac309ab0..b2a8f7df6 100644 --- a/packages/fdc3-get-agent/package.json +++ b/packages/fdc3-get-agent/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-get-agent", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3-schema/package.json b/packages/fdc3-schema/package.json index 7a30cc8d9..d1f37e6ca 100644 --- a/packages/fdc3-schema/package.json +++ b/packages/fdc3-schema/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-schema", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3-standard/package.json b/packages/fdc3-standard/package.json index 01b620589..2ce128e19 100644 --- a/packages/fdc3-standard/package.json +++ b/packages/fdc3-standard/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-standard", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3/package.json b/packages/fdc3/package.json index 94f7be191..07fec6202 100644 --- a/packages/fdc3/package.json +++ b/packages/fdc3/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/toolbox/fdc3-for-web/demo/package.json b/toolbox/fdc3-for-web/demo/package.json index c6a4a25ec..cdd655f61 100644 --- a/toolbox/fdc3-for-web/demo/package.json +++ b/toolbox/fdc3-for-web/demo/package.json @@ -1,7 +1,7 @@ { "name": "@kite9/demo", "private": true, - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "scripts": { "dev": "nodemon -w src/server src/server/main.ts", "lint": "eslint src/" diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/package.json b/toolbox/fdc3-for-web/fdc3-web-impl/package.json index ae6780e8f..4ca9551a0 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/package.json +++ b/toolbox/fdc3-for-web/fdc3-web-impl/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3-web-impl", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { From b6b04e1249edfe424e25cccad9ab299ed5b26a87 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 9 Jan 2025 18:48:11 +0000 Subject: [PATCH 77/90] Fix getAgent tests after previous change to fdc3-for-web-impl --- packages/fdc3-get-agent/test/support/MockFDC3Server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts index b95dfe52d..642181d60 100644 --- a/packages/fdc3-get-agent/test/support/MockFDC3Server.ts +++ b/packages/fdc3-get-agent/test/support/MockFDC3Server.ts @@ -57,7 +57,7 @@ export class MockFDC3Server implements FDC3Server { this.tsc.setAppState(instanceId, State.Terminated); } - receive(message: AppRequestMessage, from: string): void { + async receive(message: AppRequestMessage, from: string): Promise { this.automaticResponses.forEach(r => { if (r.filter(message.type)) { r.action(message, this.tsc, from); From 525b800c723cbb555905fc569dbd789ea13f5c32 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 9 Jan 2025 19:08:35 +0000 Subject: [PATCH 78/90] syncpack --- package-lock.json | 235 +++++++++++++++--- package.json | 2 +- packages/fdc3-agent-proxy/package.json | 4 +- packages/fdc3-commonjs/package.json | 4 +- packages/fdc3-get-agent/package.json | 12 +- packages/fdc3-standard/package.json | 4 +- packages/fdc3/package.json | 11 +- packages/testing/package.json | 4 +- toolbox/fdc3-for-web/demo/package.json | 2 +- .../fdc3-for-web/fdc3-web-impl/package.json | 4 +- 10 files changed, 228 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2acfa9150..fa1b3eef6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16774,29 +16774,28 @@ }, "packages/fdc3": { "name": "@kite9/fdc3", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-get-agent": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29" - }, - "devDependencies": {} + "@kite9/fdc3-context": "2.2.0-beta.30", + "@kite9/fdc3-get-agent": "2.2.0-beta.30", + "@kite9/fdc3-schema": "2.2.0-beta.30", + "@kite9/fdc3-standard": "2.2.0-beta.30" + } }, "packages/fdc3-agent-proxy": { "name": "@kite9/fdc3-agent-proxy", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29" + "@kite9/fdc3-standard": "2.2.0-beta.30" }, "devDependencies": { "@cucumber/cucumber": "10.3.1", "@cucumber/html-formatter": "11.0.4", "@cucumber/pretty-formatter": "1.0.1", "@eslint/js": "^9.16.0", - "@kite9/testing": "2.2.0-beta.29", + "@kite9/testing": "2.2.0-beta.30", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", "@types/node": "^20.16.11", @@ -17160,10 +17159,10 @@ }, "packages/fdc3-commonjs": { "name": "@kite9/fdc3-commonjs", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29" + "@kite9/fdc3": "2.2.0-beta.30" }, "devDependencies": { "@rollup/plugin-commonjs": "^28.0.1", @@ -17173,9 +17172,44 @@ "rollup": "^4.27.4" } }, + "packages/fdc3-commonjs/node_modules/@kite9/fdc3-agent-proxy": { + "version": "2.2.0-beta.29", + "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", + "dependencies": { + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "packages/fdc3-commonjs/node_modules/@kite9/fdc3-context": { + "version": "2.2.0-beta.29", + "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==" + }, + "packages/fdc3-commonjs/node_modules/@kite9/fdc3-get-agent": { + "version": "2.2.0-beta.29", + "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", + "dependencies": { + "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29", + "@types/uuid": "^10.0.0", + "uuid": "^9.0.1" + } + }, + "packages/fdc3-commonjs/node_modules/@kite9/fdc3-schema": { + "version": "2.2.0-beta.29", + "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==" + }, + "packages/fdc3-commonjs/node_modules/@kite9/fdc3-standard": { + "version": "2.2.0-beta.29", + "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29" + } + }, "packages/fdc3-context": { "name": "@kite9/fdc3-context", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -17542,13 +17576,13 @@ }, "packages/fdc3-get-agent": { "name": "@kite9/fdc3-get-agent", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { - "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29", + "@kite9/fdc3-agent-proxy": "2.2.0-beta.30", + "@kite9/fdc3-context": "2.2.0-beta.30", + "@kite9/fdc3-schema": "2.2.0-beta.30", + "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/uuid": "^10.0.0", "picocolors": "^1.1.1", "uuid": "^9.0.1" @@ -17556,8 +17590,8 @@ "devDependencies": { "@cucumber/cucumber": "10.3.1", "@eslint/js": "^9.16.0", - "@kite9/fdc3-web-impl": "2.2.0-beta.29", - "@kite9/testing": "2.2.0-beta.29", + "@kite9/fdc3-web-impl": "2.2.0-beta.30", + "@kite9/testing": "2.2.0-beta.30", "@types/node": "^20.16.11", "@types/wtfnode": "^0.7.3", "eslint": "^9.16.0", @@ -17714,7 +17748,7 @@ }, "packages/fdc3-schema": { "name": "@kite9/fdc3-schema", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -18083,11 +18117,11 @@ }, "packages/fdc3-standard": { "name": "@kite9/fdc3-standard", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" + "@kite9/fdc3-context": "2.2.0-beta.30", + "@kite9/fdc3-schema": "2.2.0-beta.30" }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -18458,13 +18492,13 @@ }, "packages/testing": { "name": "@kite9/testing", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { "@cucumber/cucumber": "10.3.1", "@cucumber/html-formatter": "11.0.4", "@cucumber/pretty-formatter": "1.0.1", - "@kite9/fdc3-standard": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", "@types/node": "^20.16.11", @@ -18816,7 +18850,7 @@ }, "toolbox/fdc3-for-web/demo": { "name": "@kite9/demo", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "dependencies": { "@kite9/fdc3": "2.2.0-beta.29", "@types/uuid": "^10.0.0", @@ -18854,6 +18888,51 @@ "url": "https://github.com/sponsors/nzakas" } }, + "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3": { + "version": "2.2.0-beta.29", + "integrity": "sha512-rwSLtZCzce9MxD9XeABI/oLRzvKdR1kc34Hn8E4KzfYzEhENuN0Xq4rFM/V9ywehXEX0s2sg7JDMMJHsUaEkuw==", + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-get-agent": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-agent-proxy": { + "version": "2.2.0-beta.29", + "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", + "dependencies": { + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-context": { + "version": "2.2.0-beta.29", + "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==" + }, + "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-get-agent": { + "version": "2.2.0-beta.29", + "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", + "dependencies": { + "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29", + "@types/uuid": "^10.0.0", + "uuid": "^9.0.1" + } + }, + "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-schema": { + "version": "2.2.0-beta.29", + "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==" + }, + "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-standard": { + "version": "2.2.0-beta.29", + "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29" + } + }, "toolbox/fdc3-for-web/demo/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", @@ -18983,10 +19062,10 @@ }, "toolbox/fdc3-for-web/fdc3-web-impl": { "name": "@kite9/fdc3-web-impl", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/uuid": "^10.0.0", "uuid": "^9.0.1" }, @@ -18996,7 +19075,7 @@ "@cucumber/pretty-formatter": "1.0.1", "@eslint/js": "^9.16.0", "@kite9/fdc3-common": "2.2.0-beta.6", - "@kite9/testing": "2.2.0-beta.29", + "@kite9/testing": "2.2.0-beta.30", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", "@types/node": "^20.16.11", @@ -19394,6 +19473,51 @@ "url": "https://github.com/sponsors/nzakas" } }, + "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3": { + "version": "2.2.0-beta.29", + "integrity": "sha512-rwSLtZCzce9MxD9XeABI/oLRzvKdR1kc34Hn8E4KzfYzEhENuN0Xq4rFM/V9ywehXEX0s2sg7JDMMJHsUaEkuw==", + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-get-agent": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-agent-proxy": { + "version": "2.2.0-beta.29", + "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", + "dependencies": { + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-context": { + "version": "2.2.0-beta.29", + "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==" + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-get-agent": { + "version": "2.2.0-beta.29", + "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", + "dependencies": { + "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29", + "@types/uuid": "^10.0.0", + "uuid": "^9.0.1" + } + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-schema": { + "version": "2.2.0-beta.29", + "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==" + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-standard": { + "version": "2.2.0-beta.29", + "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29" + } + }, "toolbox/fdc3-for-web/reference-ui/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", @@ -19579,6 +19703,57 @@ "url": "https://github.com/sponsors/nzakas" } }, + "toolbox/fdc3-workbench/node_modules/@kite9/fdc3": { + "version": "2.2.0-beta.29", + "integrity": "sha512-rwSLtZCzce9MxD9XeABI/oLRzvKdR1kc34Hn8E4KzfYzEhENuN0Xq4rFM/V9ywehXEX0s2sg7JDMMJHsUaEkuw==", + "dev": true, + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-get-agent": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-agent-proxy": { + "version": "2.2.0-beta.29", + "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", + "dev": true, + "dependencies": { + "@kite9/fdc3-standard": "2.2.0-beta.29" + } + }, + "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-context": { + "version": "2.2.0-beta.29", + "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==", + "dev": true + }, + "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-get-agent": { + "version": "2.2.0-beta.29", + "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", + "dev": true, + "dependencies": { + "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.29", + "@types/uuid": "^10.0.0", + "uuid": "^9.0.1" + } + }, + "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-schema": { + "version": "2.2.0-beta.29", + "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==", + "dev": true + }, + "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-standard": { + "version": "2.2.0-beta.29", + "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", + "dev": true, + "dependencies": { + "@kite9/fdc3-context": "2.2.0-beta.29", + "@kite9/fdc3-schema": "2.2.0-beta.29" + } + }, "toolbox/fdc3-workbench/node_modules/@typescript-eslint/eslint-plugin": { "version": "8.18.2", "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", diff --git a/package.json b/package.json index e96efe7bb..2ca903c04 100644 --- a/package.json +++ b/package.json @@ -65,4 +65,4 @@ "lint-staged": { "**/*": "prettier --write --ignore-unknown" } -} \ No newline at end of file +} diff --git a/packages/fdc3-agent-proxy/package.json b/packages/fdc3-agent-proxy/package.json index 0e8947e3f..4da7f5127 100644 --- a/packages/fdc3-agent-proxy/package.json +++ b/packages/fdc3-agent-proxy/package.json @@ -23,14 +23,14 @@ "lint": "eslint src/" }, "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29" + "@kite9/fdc3-standard": "2.2.0-beta.30" }, "devDependencies": { "@cucumber/cucumber": "10.3.1", "@cucumber/html-formatter": "11.0.4", "@cucumber/pretty-formatter": "1.0.1", "@eslint/js": "^9.16.0", - "@kite9/testing": "2.2.0-beta.29", + "@kite9/testing": "2.2.0-beta.30", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", "@types/node": "^20.16.11", diff --git a/packages/fdc3-commonjs/package.json b/packages/fdc3-commonjs/package.json index a068334d1..fcd7451cf 100644 --- a/packages/fdc3-commonjs/package.json +++ b/packages/fdc3-commonjs/package.json @@ -22,7 +22,7 @@ "build": "npx rollup -c rollup.config.mjs" }, "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29" + "@kite9/fdc3": "2.2.0-beta.30" }, "devDependencies": { "@rollup/plugin-commonjs": "^28.0.1", @@ -31,4 +31,4 @@ "@rollup/plugin-typescript": "^12.1.1", "rollup": "^4.27.4" } -} \ No newline at end of file +} diff --git a/packages/fdc3-get-agent/package.json b/packages/fdc3-get-agent/package.json index b2a8f7df6..19fdad474 100644 --- a/packages/fdc3-get-agent/package.json +++ b/packages/fdc3-get-agent/package.json @@ -23,10 +23,10 @@ "lint": "eslint src/" }, "dependencies": { - "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29", + "@kite9/fdc3-agent-proxy": "2.2.0-beta.30", + "@kite9/fdc3-context": "2.2.0-beta.30", + "@kite9/fdc3-schema": "2.2.0-beta.30", + "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/uuid": "^10.0.0", "picocolors": "^1.1.1", "uuid": "^9.0.1" @@ -34,8 +34,8 @@ "devDependencies": { "@cucumber/cucumber": "10.3.1", "@eslint/js": "^9.16.0", - "@kite9/fdc3-web-impl": "2.2.0-beta.29", - "@kite9/testing": "2.2.0-beta.29", + "@kite9/fdc3-web-impl": "2.2.0-beta.30", + "@kite9/testing": "2.2.0-beta.30", "@types/node": "^20.16.11", "@types/wtfnode": "^0.7.3", "eslint": "^9.16.0", diff --git a/packages/fdc3-standard/package.json b/packages/fdc3-standard/package.json index 2ce128e19..f53c026f0 100644 --- a/packages/fdc3-standard/package.json +++ b/packages/fdc3-standard/package.json @@ -34,8 +34,8 @@ "outputName": "test-results.xml" }, "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" + "@kite9/fdc3-context": "2.2.0-beta.30", + "@kite9/fdc3-schema": "2.2.0-beta.30" }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", diff --git a/packages/fdc3/package.json b/packages/fdc3/package.json index 07fec6202..7ef0b04d2 100644 --- a/packages/fdc3/package.json +++ b/packages/fdc3/package.json @@ -21,10 +21,9 @@ "build": "tsc --module es2022" }, "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-get-agent": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29" - }, - "devDependencies": {} + "@kite9/fdc3-context": "2.2.0-beta.30", + "@kite9/fdc3-get-agent": "2.2.0-beta.30", + "@kite9/fdc3-schema": "2.2.0-beta.30", + "@kite9/fdc3-standard": "2.2.0-beta.30" + } } diff --git a/packages/testing/package.json b/packages/testing/package.json index df4362043..86f095c7d 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/testing", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { @@ -26,7 +26,7 @@ "@cucumber/cucumber": "10.3.1", "@cucumber/html-formatter": "11.0.4", "@cucumber/pretty-formatter": "1.0.1", - "@kite9/fdc3-standard": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", "@types/node": "^20.16.11", diff --git a/toolbox/fdc3-for-web/demo/package.json b/toolbox/fdc3-for-web/demo/package.json index cdd655f61..896ce4611 100644 --- a/toolbox/fdc3-for-web/demo/package.json +++ b/toolbox/fdc3-for-web/demo/package.json @@ -30,4 +30,4 @@ "uuid": "^9.0.1", "vite-express": "^0.15.0" } -} \ No newline at end of file +} diff --git a/toolbox/fdc3-for-web/fdc3-web-impl/package.json b/toolbox/fdc3-for-web/fdc3-web-impl/package.json index 4ca9551a0..43ff0a346 100644 --- a/toolbox/fdc3-for-web/fdc3-web-impl/package.json +++ b/toolbox/fdc3-for-web/fdc3-web-impl/package.json @@ -24,7 +24,7 @@ "lint": "eslint src/" }, "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29", + "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/uuid": "^10.0.0", "uuid": "^9.0.1" }, @@ -34,7 +34,7 @@ "@cucumber/pretty-formatter": "1.0.1", "@eslint/js": "^9.16.0", "@kite9/fdc3-common": "2.2.0-beta.6", - "@kite9/testing": "2.2.0-beta.29", + "@kite9/testing": "2.2.0-beta.30", "@types/expect": "24.3.0", "@types/lodash": "4.14.167", "@types/node": "^20.16.11", From a305b932b77864939fd4be4985146cd411791310 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 15:28:57 +0000 Subject: [PATCH 79/90] syncing more package.json version nums --- package-lock.json | 189 +----------------- package.json | 2 +- packages/fdc3-get-agent/package.json | 1 - toolbox/fdc3-for-web/demo/package.json | 2 +- .../fdc3-for-web/reference-ui/package.json | 2 +- toolbox/fdc3-workbench/package.json | 4 +- 6 files changed, 11 insertions(+), 189 deletions(-) diff --git a/package-lock.json b/package-lock.json index fa1b3eef6..816802f7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@kite9/fdc3", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@kite9/fdc3", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "workspaces": [ "packages/fdc3-schema", @@ -17172,41 +17172,6 @@ "rollup": "^4.27.4" } }, - "packages/fdc3-commonjs/node_modules/@kite9/fdc3-agent-proxy": { - "version": "2.2.0-beta.29", - "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", - "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "packages/fdc3-commonjs/node_modules/@kite9/fdc3-context": { - "version": "2.2.0-beta.29", - "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==" - }, - "packages/fdc3-commonjs/node_modules/@kite9/fdc3-get-agent": { - "version": "2.2.0-beta.29", - "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", - "dependencies": { - "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29", - "@types/uuid": "^10.0.0", - "uuid": "^9.0.1" - } - }, - "packages/fdc3-commonjs/node_modules/@kite9/fdc3-schema": { - "version": "2.2.0-beta.29", - "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==" - }, - "packages/fdc3-commonjs/node_modules/@kite9/fdc3-standard": { - "version": "2.2.0-beta.29", - "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" - } - }, "packages/fdc3-context": { "name": "@kite9/fdc3-context", "version": "2.2.0-beta.30", @@ -17584,7 +17549,6 @@ "@kite9/fdc3-schema": "2.2.0-beta.30", "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/uuid": "^10.0.0", - "picocolors": "^1.1.1", "uuid": "^9.0.1" }, "devDependencies": { @@ -18852,7 +18816,7 @@ "name": "@kite9/demo", "version": "2.2.0-beta.30", "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29", + "@kite9/fdc3": "2.2.0-beta.30", "@types/uuid": "^10.0.0", "@types/ws": "^8.5.12", "express": "^4.21.1", @@ -18888,51 +18852,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3": { - "version": "2.2.0-beta.29", - "integrity": "sha512-rwSLtZCzce9MxD9XeABI/oLRzvKdR1kc34Hn8E4KzfYzEhENuN0Xq4rFM/V9ywehXEX0s2sg7JDMMJHsUaEkuw==", - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-get-agent": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-agent-proxy": { - "version": "2.2.0-beta.29", - "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", - "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-context": { - "version": "2.2.0-beta.29", - "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==" - }, - "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-get-agent": { - "version": "2.2.0-beta.29", - "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", - "dependencies": { - "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29", - "@types/uuid": "^10.0.0", - "uuid": "^9.0.1" - } - }, - "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-schema": { - "version": "2.2.0-beta.29", - "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==" - }, - "toolbox/fdc3-for-web/demo/node_modules/@kite9/fdc3-standard": { - "version": "2.2.0-beta.29", - "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" - } - }, "toolbox/fdc3-for-web/demo/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", @@ -19449,7 +19368,7 @@ "name": "fdc3-for-web-reference-ui", "version": "2.1.1", "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29" + "@kite9/fdc3": "2.2.0-beta.30" }, "devDependencies": { "@eslint/js": "^9.16.0", @@ -19473,51 +19392,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3": { - "version": "2.2.0-beta.29", - "integrity": "sha512-rwSLtZCzce9MxD9XeABI/oLRzvKdR1kc34Hn8E4KzfYzEhENuN0Xq4rFM/V9ywehXEX0s2sg7JDMMJHsUaEkuw==", - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-get-agent": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-agent-proxy": { - "version": "2.2.0-beta.29", - "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", - "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-context": { - "version": "2.2.0-beta.29", - "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==" - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-get-agent": { - "version": "2.2.0-beta.29", - "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", - "dependencies": { - "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29", - "@types/uuid": "^10.0.0", - "uuid": "^9.0.1" - } - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-schema": { - "version": "2.2.0-beta.29", - "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==" - }, - "toolbox/fdc3-for-web/reference-ui/node_modules/@kite9/fdc3-standard": { - "version": "2.2.0-beta.29", - "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" - } - }, "toolbox/fdc3-for-web/reference-ui/node_modules/ajv": { "version": "6.12.6", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", @@ -19646,13 +19520,13 @@ "dev": true }, "toolbox/fdc3-workbench": { - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "license": "Apache-2.0", "devDependencies": { "@apidevtools/json-schema-ref-parser": "11.7.2", "@fontsource/roboto": "5.1.0", "@fontsource/source-code-pro": "5.1.0", - "@kite9/fdc3": "2.2.0-beta.29", + "@kite9/fdc3": "2.2.0-beta.30", "@material-ui/core": "4.12.4", "@material-ui/icons": "4.11.3", "@material-ui/lab": "4.0.0-alpha.61", @@ -19703,57 +19577,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "toolbox/fdc3-workbench/node_modules/@kite9/fdc3": { - "version": "2.2.0-beta.29", - "integrity": "sha512-rwSLtZCzce9MxD9XeABI/oLRzvKdR1kc34Hn8E4KzfYzEhENuN0Xq4rFM/V9ywehXEX0s2sg7JDMMJHsUaEkuw==", - "dev": true, - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-get-agent": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-agent-proxy": { - "version": "2.2.0-beta.29", - "integrity": "sha512-M/ijMFSBsVMRlxbK5OSN1xscD8SpoZyT5cVORUE1RFShvvzXJ/YPUdEzVkH5cIeS5o7f7nbe9F0Tg0dM+o9lPw==", - "dev": true, - "dependencies": { - "@kite9/fdc3-standard": "2.2.0-beta.29" - } - }, - "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-context": { - "version": "2.2.0-beta.29", - "integrity": "sha512-4BaUIBqLNTCsC3IOQdbuc3E8wo3efx6SH+F4DsvzAF3eW2Yb+qTf9u2qwg/m5j7T/ZTgk0KN086tCC0Jrk1saA==", - "dev": true - }, - "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-get-agent": { - "version": "2.2.0-beta.29", - "integrity": "sha512-QkoHPW3dCUhUFsOuspPVnCzumEKULh9wqeBq10fpjVUtgosS1/Dgl5J/vWK2LLkedi90agbODGPyUnR0P59UsA==", - "dev": true, - "dependencies": { - "@kite9/fdc3-agent-proxy": "2.2.0-beta.29", - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29", - "@kite9/fdc3-standard": "2.2.0-beta.29", - "@types/uuid": "^10.0.0", - "uuid": "^9.0.1" - } - }, - "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-schema": { - "version": "2.2.0-beta.29", - "integrity": "sha512-n2PinAO7sM9825LARTQld9izc6pVV0v2IM+bxtpnni+qT/8t6FTremovKfuq54T74Wi47pC0TriBH+o/GNpZEA==", - "dev": true - }, - "toolbox/fdc3-workbench/node_modules/@kite9/fdc3-standard": { - "version": "2.2.0-beta.29", - "integrity": "sha512-sxXJNOtZ3yre4+2qOEXPYVf/RRVnrITMKew8G9E0LWN2fgsEiuar0OdIlJzki68Nt3j/CfmrpmF5QEg7Cz/K/w==", - "dev": true, - "dependencies": { - "@kite9/fdc3-context": "2.2.0-beta.29", - "@kite9/fdc3-schema": "2.2.0-beta.29" - } - }, "toolbox/fdc3-workbench/node_modules/@typescript-eslint/eslint-plugin": { "version": "8.18.2", "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", diff --git a/package.json b/package.json index 2ca903c04..0f98a5c66 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kite9/fdc3", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "author": "Fintech Open Source Foundation (FINOS)", "homepage": "https://fdc3.finos.org", "repository": { diff --git a/packages/fdc3-get-agent/package.json b/packages/fdc3-get-agent/package.json index 19fdad474..01e2eb06b 100644 --- a/packages/fdc3-get-agent/package.json +++ b/packages/fdc3-get-agent/package.json @@ -28,7 +28,6 @@ "@kite9/fdc3-schema": "2.2.0-beta.30", "@kite9/fdc3-standard": "2.2.0-beta.30", "@types/uuid": "^10.0.0", - "picocolors": "^1.1.1", "uuid": "^9.0.1" }, "devDependencies": { diff --git a/toolbox/fdc3-for-web/demo/package.json b/toolbox/fdc3-for-web/demo/package.json index 896ce4611..441fdb3f4 100644 --- a/toolbox/fdc3-for-web/demo/package.json +++ b/toolbox/fdc3-for-web/demo/package.json @@ -19,7 +19,7 @@ "vite": "^5.4.9" }, "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29", + "@kite9/fdc3": "2.2.0-beta.30", "@types/uuid": "^10.0.0", "@types/ws": "^8.5.12", "express": "^4.21.1", diff --git a/toolbox/fdc3-for-web/reference-ui/package.json b/toolbox/fdc3-for-web/reference-ui/package.json index 73c3b1fc3..de4819f6d 100644 --- a/toolbox/fdc3-for-web/reference-ui/package.json +++ b/toolbox/fdc3-for-web/reference-ui/package.json @@ -20,6 +20,6 @@ "vite": "^5.4.9" }, "dependencies": { - "@kite9/fdc3": "2.2.0-beta.29" + "@kite9/fdc3": "2.2.0-beta.30" } } diff --git a/toolbox/fdc3-workbench/package.json b/toolbox/fdc3-workbench/package.json index 5d398e850..01fab9da3 100644 --- a/toolbox/fdc3-workbench/package.json +++ b/toolbox/fdc3-workbench/package.json @@ -1,6 +1,6 @@ { "name": "fdc3-workbench", - "version": "2.2.0-beta.29", + "version": "2.2.0-beta.30", "private": true, "homepage": ".", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "@apidevtools/json-schema-ref-parser": "11.7.2", "@fontsource/roboto": "5.1.0", "@fontsource/source-code-pro": "5.1.0", - "@kite9/fdc3": "2.2.0-beta.29", + "@kite9/fdc3": "2.2.0-beta.30", "@material-ui/core": "4.12.4", "@material-ui/icons": "4.11.3", "@material-ui/lab": "4.0.0-alpha.61", From 27ccc55d14c8eb758359dea0a4ad360143b940f6 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 15:30:10 +0000 Subject: [PATCH 80/90] Import picocolors to fix commonjs build n.b. Chalk also runs into issues due to our dual-build - may replace with a custom implementation later. --- packages/fdc3-get-agent/src/util/Logger.ts | 5 +- .../fdc3-get-agent/src/util/Picocolors.ts | 106 ++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 packages/fdc3-get-agent/src/util/Picocolors.ts diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index f20d7d89b..6a6a16f59 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -1,8 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import * as pc from 'picocolors'; - +import { createColors } from './Picocolors'; const GET_AGENT_LOG_PREFIX = 'FDC3 getAgent: '; +const pc = createColors(); + type ColorFn = (aString: string) => string; const debugColor: ColorFn = value => pc.black(pc.dim(value)); const logColor: ColorFn = value => pc.green(pc.dim(value)); diff --git a/packages/fdc3-get-agent/src/util/Picocolors.ts b/packages/fdc3-get-agent/src/util/Picocolors.ts new file mode 100644 index 000000000..2d33ec70c --- /dev/null +++ b/packages/fdc3-get-agent/src/util/Picocolors.ts @@ -0,0 +1,106 @@ +/* +From picocolors (imported due to issues building in both ESM and CommonJS) +https://github.com/alexeyraspopov/picocolors + +ISC License + +Copyright (c) 2021-2024 Oleksii Raspopov, Kostiantyn Denysov, Anton Verinov + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +let isColorSupported; +if (typeof process !== 'undefined') { + const argv = process.argv || [], + env = process.env || {}; + isColorSupported = + !(!!env.NO_COLOR || argv.includes('--no-color')) && + (!!env.FORCE_COLOR || + argv.includes('--color') || + process.platform === 'win32' || + ((process.stdout || {}).isTTY && env.TERM !== 'dumb') || + !!env.CI); +} else { + isColorSupported = false; +} + +const formatter = + (open: string, close: string, replace = open) => + (input: string) => { + const string = '' + input, + index = string.indexOf(close, open.length); + return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close; + }; + +const replaceClose = (string: string, close: string, replace: string, index: number) => { + let result = '', + cursor = 0; + do { + result += string.substring(cursor, index) + replace; + cursor = index + close.length; + index = string.indexOf(close, cursor); + } while (~index); + return result + string.substring(cursor); +}; + +export const createColors = (enabled = isColorSupported) => { + const f = enabled ? formatter : () => String; + return { + isColorSupported: enabled, + reset: f('\x1b[0m', '\x1b[0m'), + bold: f('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m'), + dim: f('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m'), + italic: f('\x1b[3m', '\x1b[23m'), + underline: f('\x1b[4m', '\x1b[24m'), + inverse: f('\x1b[7m', '\x1b[27m'), + hidden: f('\x1b[8m', '\x1b[28m'), + strikethrough: f('\x1b[9m', '\x1b[29m'), + + black: f('\x1b[30m', '\x1b[39m'), + red: f('\x1b[31m', '\x1b[39m'), + green: f('\x1b[32m', '\x1b[39m'), + yellow: f('\x1b[33m', '\x1b[39m'), + blue: f('\x1b[34m', '\x1b[39m'), + magenta: f('\x1b[35m', '\x1b[39m'), + cyan: f('\x1b[36m', '\x1b[39m'), + white: f('\x1b[37m', '\x1b[39m'), + gray: f('\x1b[90m', '\x1b[39m'), + + bgBlack: f('\x1b[40m', '\x1b[49m'), + bgRed: f('\x1b[41m', '\x1b[49m'), + bgGreen: f('\x1b[42m', '\x1b[49m'), + bgYellow: f('\x1b[43m', '\x1b[49m'), + bgBlue: f('\x1b[44m', '\x1b[49m'), + bgMagenta: f('\x1b[45m', '\x1b[49m'), + bgCyan: f('\x1b[46m', '\x1b[49m'), + bgWhite: f('\x1b[47m', '\x1b[49m'), + + blackBright: f('\x1b[90m', '\x1b[39m'), + redBright: f('\x1b[91m', '\x1b[39m'), + greenBright: f('\x1b[92m', '\x1b[39m'), + yellowBright: f('\x1b[93m', '\x1b[39m'), + blueBright: f('\x1b[94m', '\x1b[39m'), + magentaBright: f('\x1b[95m', '\x1b[39m'), + cyanBright: f('\x1b[96m', '\x1b[39m'), + whiteBright: f('\x1b[97m', '\x1b[39m'), + + bgBlackBright: f('\x1b[100m', '\x1b[49m'), + bgRedBright: f('\x1b[101m', '\x1b[49m'), + bgGreenBright: f('\x1b[102m', '\x1b[49m'), + bgYellowBright: f('\x1b[103m', '\x1b[49m'), + bgBlueBright: f('\x1b[104m', '\x1b[49m'), + bgMagentaBright: f('\x1b[105m', '\x1b[49m'), + bgCyanBright: f('\x1b[106m', '\x1b[49m'), + bgWhiteBright: f('\x1b[107m', '\x1b[49m'), + }; +}; From b03197a1482af0edd03a2280d133cfad7f9a4a2c Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 15:31:41 +0000 Subject: [PATCH 81/90] timing improvements to injected UIs --- .../src/ui/AbstractUIComponent.ts | 26 ++++++-- .../ui/DefaultDesktopAgentChannelSelector.ts | 18 +++-- .../ui/DefaultDesktopAgentIntentResolver.ts | 9 +-- .../src/ui/NullChannelSelector.ts | 3 +- .../src/ui/NullIntentResolver.ts | 1 + .../fdc3-standard/src/ui/ChannelSelector.ts | 2 +- .../fdc3-for-web/demo/src/client/da/embed.ts | 4 +- .../demo/src/client/ui/channel-selector.ts | 65 ++++++++++++------- .../demo/src/client/ui/intent-resolver.ts | 22 +++++-- .../reference-ui/src/channel_selector.ts | 20 +++--- .../reference-ui/src/intent_resolver.ts | 7 +- toolbox/fdc3-for-web/reference-ui/src/main.ts | 7 +- 12 files changed, 125 insertions(+), 59 deletions(-) diff --git a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts index 0b8a27f54..4edc49ad1 100644 --- a/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts +++ b/packages/fdc3-get-agent/src/ui/AbstractUIComponent.ts @@ -31,16 +31,22 @@ export const ALLOWED_CSS_ELEMENTS = [ 'display', ]; +/** Abstract implementation of an injected UI, used as the base for communication + * with injected Channel Selector and Intent Resolver UIs. + */ export abstract class AbstractUIComponent implements Connectable { private container: HTMLDivElement | undefined = undefined; private iframe: HTMLIFrameElement | undefined = undefined; private url: string; private name: string; - port: MessagePort | null = null; + protected port: MessagePort | null = null; + protected messagePortIsReady: Promise; + private markMessagePortReady: (() => void) | null = null; constructor(url: string, name: string) { this.url = url; this.name = name; + this.messagePortIsReady = new Promise(resolve => (this.markMessagePortReady = resolve)); } /** @@ -52,6 +58,7 @@ export abstract class AbstractUIComponent implements Connectable { * security policies. I.e. awaiting this will not block. */ connect(): Promise { + Logger.debug(`AbstractUIComponent (${this.name}): Awaiting hello from `, this.name, ', url: ', this.url); const portPromise = this.awaitHello(); this.openFrame(); portPromise.then(port => { @@ -75,11 +82,12 @@ export abstract class AbstractUIComponent implements Connectable { const data = e.data; if (isFdc3UserInterfaceRestyle(data)) { - Logger.debug(`Restyling ${JSON.stringify(data.payload, null, 2)}`); + Logger.debug(`AbstractUIComponent (${this.name}): Restyling: `, data.payload); const css = data.payload.updatedCSS; this.themeContainer(css); } }); + port.start(); } async messagePortReady(port: MessagePort) { @@ -90,26 +98,32 @@ export abstract class AbstractUIComponent implements Connectable { fdc3Version: FDC3_VERSION, }, }; + Logger.debug(`AbstractUIComponent (${this.name}): Sending handshake: `, message); port.postMessage(message); + this.markMessagePortReady!(); } private awaitHello(): Promise { return new Promise(resolve => { const ml = (e: MessageEvent) => { + //only respond to messages from this UI's iframe if (e.source == this.iframe?.contentWindow) { if (isFdc3UserInterfaceHello(e.data)) { const helloData = e.data; this.themeContainer(helloData.payload.initialCSS); const port = e.ports[0]; - port.start(); globalThis.window.removeEventListener('message', ml); resolve(port); } else { - Logger.debug('AbstractUIComponent: ignored UI Message from UI iframe while awaiting hello: ', e.data); + Logger.warn( + `AbstractUIComponent (${this.name}): ignored UI Message from UI iframe while awaiting hello: `, + e.data + ); } } else { + //as there are two UIs, we expect some cross-over between their messages Logger.debug( - "AbstractUIComponent: ignored Message that didn't come from expected UI frame\nmessage: ", + `AbstractUIComponent (${this.name}): ignored Message that didn't come from expected UI frame: `, e.data, 'my URL: ', this.url @@ -140,6 +154,7 @@ export abstract class AbstractUIComponent implements Connectable { } themeContainer(css: UpdatedCSS | InitialCSS) { + Logger.debug(`AbstractUIComponent (${this.name}): Applying styles to container`, css); for (let i = 0; i < ALLOWED_CSS_ELEMENTS.length; i++) { const k = ALLOWED_CSS_ELEMENTS[i]; const value: string | undefined = css[k as string]; @@ -152,6 +167,7 @@ export abstract class AbstractUIComponent implements Connectable { } themeFrame(ifrm: HTMLIFrameElement) { + Logger.debug(`AbstractUIComponent (${this.name}): Applying 100% size style to iframe`); ifrm.style.width = '100%'; ifrm.style.height = '100%'; ifrm.style.border = '0'; diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts index ac77f545a..1ce448978 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentChannelSelector.ts @@ -2,14 +2,12 @@ import { Channel } from '@kite9/fdc3-standard'; import { ChannelSelector } from '@kite9/fdc3-standard'; import { AbstractUIComponent } from './AbstractUIComponent'; import { BrowserTypes } from '@kite9/fdc3-schema'; +import { Logger } from '../util/Logger'; const { isFdc3UserInterfaceChannelSelected } = BrowserTypes; type Fdc3UserInterfaceChannels = BrowserTypes.Fdc3UserInterfaceChannels; /** - * Works with the desktop agent to provide a simple channel selector. - * - * This is the default implementation, but can be overridden by app implementers calling - * the getAgent() method + * Handles communication between an injected Channel Selector UI and the getAgent implementation. */ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent implements ChannelSelector { private callback: ((channelId: string | null) => void) | null = null; @@ -20,20 +18,23 @@ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent impl } async setupMessagePort(port: MessagePort): Promise { - await super.setupMessagePort(port); this.port = port; port.addEventListener('message', e => { if (isFdc3UserInterfaceChannelSelected(e.data)) { + Logger.debug(`DefaultDesktopAgentChannelSelector: Received channel selection message: `, e.data); const choice = e.data; if (this.callback) { this.callback(choice.payload.selected); } } }); + + //This starts the port so do it last + await super.setupMessagePort(port); } - updateChannel(channelId: string | null, availableChannels: Channel[]): void { + async updateChannel(channelId: string | null, availableChannels: Channel[]): Promise { const message: Fdc3UserInterfaceChannels = { type: 'Fdc3UserInterfaceChannels', payload: { @@ -47,7 +48,12 @@ export class DefaultDesktopAgentChannelSelector extends AbstractUIComponent impl }), }, }; + + //don't post until the messageport is ready + await this.messagePortIsReady; + this.port?.postMessage(message); + Logger.debug(`DefaultDesktopAgentChannelSelector: Sent channels data to channel selector: `, message); } setChannelChangeCallback(callback: (channelId: string | null) => void): void { diff --git a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts index 47d76412f..f466a812f 100644 --- a/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/DefaultDesktopAgentIntentResolver.ts @@ -8,9 +8,7 @@ const { isFdc3UserInterfaceResolveAction } = BrowserTypes; type Fdc3UserInterfaceResolve = BrowserTypes.Fdc3UserInterfaceResolve; /** - * Works with the desktop agent to provide a resolution to the intent choices. - * This is the default implementation, but can be overridden by app implementers calling - * the getAgent() method + * Handles communication between an injected Intent Resolver UI and the getAgent implementation. */ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent implements IntentResolver { private pendingResolve: ((x: IntentResolutionChoice | void) => void) | null = null; @@ -21,7 +19,6 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple } async setupMessagePort(port: MessagePort): Promise { - await super.setupMessagePort(port); this.port = port; this.port.addEventListener('message', e => { @@ -41,6 +38,9 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple this.pendingResolve = null; } }); + + //This starts the port so do it last + await super.setupMessagePort(port); } async chooseIntent(appIntents: AppIntent[], context: Context): Promise { @@ -55,6 +55,7 @@ export class DefaultDesktopAgentIntentResolver extends AbstractUIComponent imple }, }; this.port?.postMessage(message); + Logger.debug(`DefaultDesktopAgentIntentResolver: Requested resolution: `, message); return out; } } diff --git a/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts b/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts index 4303a32c6..17b4db67c 100644 --- a/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts +++ b/packages/fdc3-get-agent/src/ui/NullChannelSelector.ts @@ -1,9 +1,10 @@ import { Connectable } from '@kite9/fdc3-standard'; import { ChannelSelector } from '@kite9/fdc3-standard'; +/** Implementation used when an injected Channel selector is not in use. */ export class NullChannelSelector implements ChannelSelector, Connectable { async disconnect(): Promise {} async connect(): Promise {} - updateChannel(): void {} + async updateChannel(): Promise {} setChannelChangeCallback(): void {} } diff --git a/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts b/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts index 3ea918ca8..1e5c65f4f 100644 --- a/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts +++ b/packages/fdc3-get-agent/src/ui/NullIntentResolver.ts @@ -1,5 +1,6 @@ import { IntentResolver, IntentResolutionChoice } from '@kite9/fdc3-standard'; +/** Implementation used when an injected IntentResolver is not in use. */ export class NullIntentResolver implements IntentResolver { async disconnect(): Promise {} async connect(): Promise {} diff --git a/packages/fdc3-standard/src/ui/ChannelSelector.ts b/packages/fdc3-standard/src/ui/ChannelSelector.ts index 07f36626e..d5e95caa0 100644 --- a/packages/fdc3-standard/src/ui/ChannelSelector.ts +++ b/packages/fdc3-standard/src/ui/ChannelSelector.ts @@ -8,7 +8,7 @@ export interface ChannelSelector extends Connectable { /** * Called when the list of user channels is updated, or the selected channel changes. */ - updateChannel(channelId: string | null, availableChannels: Channel[]): void; + updateChannel(channelId: string | null, availableChannels: Channel[]): Promise; /** * Called on initialization. The channel selector will invoke the callback after the diff --git a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts index 7f144f0d9..92176177b 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/embed.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/embed.ts @@ -38,7 +38,7 @@ const helloListener = (e: MessageEvent) => { try { eventSourceName = (eventSource as Window)?.name; } catch (e: unknown) { - eventSourceName = `{a cross-origin window: ${(e as Error).message ?? e}} `; + eventSourceName = `{a cross-origin window} `; } if (!eventSourceName) { eventSourceName = '{no window name set} '; @@ -46,7 +46,7 @@ const helloListener = (e: MessageEvent) => { if (isWebConnectionProtocol1Hello(messageData)) { console.debug( - 'Received hello message from: ', + 'Communication iframe adaptor received hello message from: ', eventSourceName, eventSource == appWindow ? '(parent window): ' : '(NOT parent win): ', messageData diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts index f55512fec..0e7fc2220 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts @@ -1,19 +1,25 @@ -import { BrowserTypes } from '@kite9/fdc3-schema'; import { dragElement } from './drag'; -import { Channel, Fdc3UserInterfaceRestyle } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; +import { + Channel, + Fdc3UserInterfaceChannelSelected, + Fdc3UserInterfaceHello, + Fdc3UserInterfaceRestyle, + isFdc3UserInterfaceChannels, + isFdc3UserInterfaceHandshake, + UpdatedCSS, +} from '@kite9/fdc3-schema/generated/api/BrowserTypes'; -// TODO: Update typings let channels: Channel[] = []; let channelId: string | null = null; -export const DEFAULT_COLLAPSED_CSS = { +export const DEFAULT_COLLAPSED_CSS: UpdatedCSS = { width: '50px', height: '50px', position: 'fixed', zIndex: '1000', }; -const DEFAULT_EXPANDED_CSS = { +const DEFAULT_EXPANDED_CSS: UpdatedCSS = { left: '0', right: '0', top: '0', @@ -36,6 +42,11 @@ const position: Position = { top: '', }; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const debug = (...params: any[]) => { + console.debug('Demo Channel Selector: ', ...params); +}; + window.addEventListener('load', () => { const parent = window.parent; const logo = document.getElementById('logo')!; @@ -49,7 +60,7 @@ window.addEventListener('load', () => { myPort.start(); // ISSUE: 1302 - const helloMessage: BrowserTypes.Fdc3UserInterfaceHello = { + const helloMessage: Fdc3UserInterfaceHello = { type: 'Fdc3UserInterfaceHello', payload: { initialCSS: { @@ -60,14 +71,18 @@ window.addEventListener('load', () => { }, }; parent.postMessage(helloMessage, '*', [mc.port2]); + debug('Sent hello message: ', helloMessage); function changeSize(expanded: boolean) { document.body.setAttribute('data-expanded', 'none'); if (expanded) { - myPort.postMessage({ - type: BrowserTypes.FDC3_USER_INTERFACE_RESTYLE_TYPE, + const message: Fdc3UserInterfaceRestyle = { + type: 'Fdc3UserInterfaceRestyle', payload: { updatedCSS: DEFAULT_EXPANDED_CSS }, - } as Fdc3UserInterfaceRestyle); + }; + myPort.postMessage(message); + debug('Setting expanded styles: ', message); + console.debug(); selector.style.left = position.left; selector.style.top = position.top; selector.style.right = position.right; @@ -76,10 +91,12 @@ window.addEventListener('load', () => { document.body.setAttribute('data-expanded', 'selector'); }, 20); } else { - myPort.postMessage({ - type: BrowserTypes.FDC3_USER_INTERFACE_RESTYLE_TYPE, + const message: Fdc3UserInterfaceRestyle = { + type: 'Fdc3UserInterfaceRestyle', payload: { updatedCSS: { ...DEFAULT_COLLAPSED_CSS, ...position } }, - } as Fdc3UserInterfaceRestyle); + }; + debug('Setting collapsed styles: ', message); + myPort.postMessage(message); setTimeout(() => { document.body.setAttribute('data-expanded', 'logo'); }, 20); @@ -87,17 +104,18 @@ window.addEventListener('load', () => { } myPort.addEventListener('message', e => { - if (e.data.type == BrowserTypes.FDC3_USER_INTERFACE_HANDSHAKE_TYPE) { - // ok, port is ready, send the iframe position detials - myPort.postMessage({ - type: BrowserTypes.FDC3_USER_INTERFACE_RESTYLE_TYPE, + if (isFdc3UserInterfaceHandshake(e.data)) { + // ok, port is ready, send the iframe position details + const message: Fdc3UserInterfaceRestyle = { + type: 'Fdc3UserInterfaceRestyle', payload: { updatedCSS: { ...DEFAULT_COLLAPSED_CSS, ...position } }, - } as Fdc3UserInterfaceRestyle); - } else if (e.data.type == BrowserTypes.FDC3_USER_INTERFACE_CHANNELS_TYPE) { - const details = e.data as BrowserTypes.Fdc3UserInterfaceChannels; - console.log(JSON.stringify('CHANNEL DETAILS: ' + JSON.stringify(details))); - channels = details.payload.userChannels; - channelId = details.payload.selected; + }; + myPort.postMessage(message); + debug('Received handshake, sending initial restyle: ', message); + } else if (isFdc3UserInterfaceChannels(e.data)) { + debug('Received channel details: ', e.data); + channels = e.data.payload.userChannels; + channelId = e.data.payload.selected; const selectedColor = (channelId ? channels.find(c => c.id == channelId)?.displayMetadata?.color : null) ?? 'white'; @@ -123,13 +141,14 @@ window.addEventListener('load', () => { li.onclick = () => { changeSize(false); channelId = channel.id; - const message: BrowserTypes.Fdc3UserInterfaceChannelSelected = { + const message: Fdc3UserInterfaceChannelSelected = { type: 'Fdc3UserInterfaceChannelSelected', payload: { selected: channel.id, }, }; myPort.postMessage(message); + debug('Sending channel selection: ', message); }; }); changeSize(true); diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/intent-resolver.ts b/toolbox/fdc3-for-web/demo/src/client/ui/intent-resolver.ts index 5002b7740..40c349272 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/intent-resolver.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/intent-resolver.ts @@ -3,6 +3,8 @@ import { Fdc3UserInterfaceResolve, Fdc3UserInterfaceResolveAction, Fdc3UserInterfaceRestyle, + isFdc3UserInterfaceHandshake, + isFdc3UserInterfaceResolve, } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; import { AppIdentifier } from '@kite9/fdc3-standard'; @@ -25,6 +27,12 @@ const DEFAULT_EXPANDED_CSS = { right: '10%', bottom: '10%', }; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const debug = (...params: any[]) => { + console.debug('Demo Intent Resolver: ', ...params); +}; + window.addEventListener('load', () => { const parent = window.parent; @@ -32,7 +40,7 @@ window.addEventListener('load', () => { const myPort = mc.port1; myPort.start(); - const list = document.getElementById('intent-list')!!; + const list = document.getElementById('intent-list')!; // ISSUE: 1302 const helloMessage: Fdc3UserInterfaceHello = { @@ -43,6 +51,7 @@ window.addEventListener('load', () => { }, }; parent.postMessage(helloMessage, '*', [mc.port2]); + debug('Sent hello message: ', helloMessage); function callback(intent: string | null, app: AppIdentifier | null) { const restyleMessage: Fdc3UserInterfaceRestyle = { @@ -50,6 +59,7 @@ window.addEventListener('load', () => { payload: { updatedCSS: DEFAULT_COLLAPSED_CSS }, }; myPort.postMessage(restyleMessage); + debug('Setting collapsed styles: ', restyleMessage); if (intent && app) { const message: Fdc3UserInterfaceResolveAction = { @@ -61,6 +71,7 @@ window.addEventListener('load', () => { }, }; myPort.postMessage(message); + debug('Sent resolution: ', message); } else { const message: Fdc3UserInterfaceResolveAction = { type: 'Fdc3UserInterfaceResolveAction', @@ -69,22 +80,25 @@ window.addEventListener('load', () => { }, }; myPort.postMessage(message); + debug('Sent cancellation: ', message); } } myPort.addEventListener('message', e => { - if (e.data.type == 'iframeHandshake') { + if (isFdc3UserInterfaceHandshake(e.data)) { const message: Fdc3UserInterfaceRestyle = { type: 'Fdc3UserInterfaceRestyle', payload: { updatedCSS: DEFAULT_COLLAPSED_CSS }, }; myPort.postMessage(message); - } else if (e.data.type == 'iframeResolve') { + debug('Received handshake, sending initial restyle: ', message); + } else if (isFdc3UserInterfaceResolve(e.data)) { const message: Fdc3UserInterfaceRestyle = { type: 'Fdc3UserInterfaceRestyle', payload: { updatedCSS: DEFAULT_EXPANDED_CSS }, }; myPort.postMessage(message); + debug('Received request for resolution, setting expanded styles: ', message); Array.from(list.children).forEach(i => i.remove()); const details: Fdc3UserInterfaceResolve['payload'] = e.data.payload; details.appIntents.forEach(intent => { @@ -111,7 +125,7 @@ window.addEventListener('load', () => { } }); - document.getElementById('cancel')!!.addEventListener('click', () => { + document.getElementById('cancel')!.addEventListener('click', () => { callback(null, null); }); }); diff --git a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts index b22a521b5..99e7df886 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts @@ -1,5 +1,6 @@ import { Channel, + Fdc3UserInterfaceChannelSelected, Fdc3UserInterfaceHello, Fdc3UserInterfaceRestyle, isFdc3UserInterfaceChannels, @@ -49,8 +50,8 @@ window.addEventListener('load', () => { const mc = new MessageChannel(); const myPort = mc.port1; - myPort.start(); - myPort.onmessage = ({ data }) => { + + myPort.addEventListener('message', ({ data }) => { console.debug('Received message: ', data); if (isFdc3UserInterfaceHandshake(data)) { @@ -59,26 +60,29 @@ window.addEventListener('load', () => { logo.removeEventListener('click', expand); const { userChannels, selected } = data.payload; fillChannels(userChannels, selected, channelStr => { - myPort.postMessage({ - type: 'fdc3UserInterfaceSelected', + const message: Fdc3UserInterfaceChannelSelected = { + type: 'Fdc3UserInterfaceChannelSelected', payload: { selected: channelStr || null, }, - }); + }; + myPort.postMessage(message); + console.log('Channel Selected: ', message); collapse(); }); const selectedChannel = userChannels.find(c => c.id === selected); logo.style.fill = selectedChannel?.displayMetadata?.color ?? 'white'; - console.log('Adding event listener'); + console.log('Adding click event listener'); logo.addEventListener('click', expand); } - }; + }); + myPort.start(); const helloMessage: Fdc3UserInterfaceHello = { type: 'Fdc3UserInterfaceHello', payload: { - implementationDetails: '', + implementationDetails: 'FDC3 Reference Channel Selector UI', initialCSS: { width: `${8 * 4}px`, height: `${8 * 5}px`, diff --git a/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts b/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts index 9ce69445f..c80e7a671 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/intent_resolver.ts @@ -181,8 +181,8 @@ window.addEventListener('load', () => { const mc = new MessageChannel(); const myPort = mc.port1; - myPort.start(); - myPort.onmessage = ({ data }) => { + + myPort.addEventListener('message', ({ data }) => { console.debug('Received message: ', data); if (isFdc3UserInterfaceResolve(data)) { const restyleMessage: Fdc3UserInterfaceRestyle = { @@ -222,7 +222,8 @@ window.addEventListener('load', () => { myPort.postMessage(restyleMessage); }); } - }; + }); + myPort.start(); const helloMessage: Fdc3UserInterfaceHello = { type: 'Fdc3UserInterfaceHello', diff --git a/toolbox/fdc3-for-web/reference-ui/src/main.ts b/toolbox/fdc3-for-web/reference-ui/src/main.ts index 75343bcdc..4fdf9e64a 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/main.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/main.ts @@ -128,7 +128,7 @@ const openChannelIframe = (e: MouseEvent) => { const channel = new MessageChannel(); // STEP 2B: Receive confirmation over port from iframe - channel.port1.onmessage = ({ data }) => { + channel.port1.addEventListener('message', ({ data }) => { switch (data.type) { // User clicked on one of the channels in the channel selector case FDC3_USER_INTERFACE_CHANNEL_SELECTED_TYPE: { @@ -154,7 +154,8 @@ const openChannelIframe = (e: MouseEvent) => { break; } } - }; + }); + channel.port1.start(); const { target } = e; if (target) (target as HTMLButtonElement).disabled = true; @@ -166,12 +167,14 @@ const openChannelIframe = (e: MouseEvent) => { resizeButton.setAttribute('data-visible', 'true'); resizeButton.addEventListener('click', () => { expanded = !expanded; + //TODO: update this to a Fdc3UserInterfaceRestyle message channel.port1.postMessage({ type: 'Fdc3UserInterfaceChannelResize', expanded }); iframe.setAttribute('data-expanded', `${expanded}`); resizeButton.textContent = expanded ? 'Collapse' : 'Expand'; }); // STEP 1A: Send port to iframe + //TODO: align message with standard iframe.contentWindow?.postMessage({ type: 'Fdc3UserInterfaceHello' }, '*', [channel.port2]); }; From 5117a588fac078b3961e91081237b992a09845c8 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 16:47:46 +0000 Subject: [PATCH 82/90] Ignore untested parts of picocolors for coverage --- packages/fdc3-get-agent/src/util/Picocolors.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/fdc3-get-agent/src/util/Picocolors.ts b/packages/fdc3-get-agent/src/util/Picocolors.ts index 2d33ec70c..9fa7b9c6f 100644 --- a/packages/fdc3-get-agent/src/util/Picocolors.ts +++ b/packages/fdc3-get-agent/src/util/Picocolors.ts @@ -20,6 +20,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ let isColorSupported; +//else only occurs in a browser and can't be tested in node +/* istanbul ignore else */ if (typeof process !== 'undefined') { const argv = process.argv || [], env = process.env || {}; @@ -42,6 +44,8 @@ const formatter = return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close; }; +//Not currently hit in the codebase or tests but included for completeness +/* istanbul ignore next */ const replaceClose = (string: string, close: string, replace: string, index: number) => { let result = '', cursor = 0; From 53bbaba73174b5b5654cd5fd230af953bebb0b89 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 16:48:52 +0000 Subject: [PATCH 83/90] correcting updateChannel in test implementations of channelSelectors --- packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts | 4 ++-- packages/testing/src/agent/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts b/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts index c23e5850a..665f42832 100644 --- a/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts +++ b/packages/fdc3-agent-proxy/test/support/TestChannelSelector.ts @@ -7,7 +7,7 @@ export class TestChannelSelector implements ChannelSelector { constructor() {} - updateChannel(channelId: string | null, availableChannels: Channel[]): void { + async updateChannel(channelId: string | null, availableChannels: Channel[]): Promise { this.channelId = channelId; this.channels = availableChannels; } @@ -21,7 +21,7 @@ export class TestChannelSelector implements ChannelSelector { } async disconnect(): Promise { - console.log('TestChannelSelector was diconnected'); + console.log('TestChannelSelector was disconnected'); } selectChannel(channelId: string | null): void { diff --git a/packages/testing/src/agent/index.ts b/packages/testing/src/agent/index.ts index e61bdf51c..d9f7c50d8 100644 --- a/packages/testing/src/agent/index.ts +++ b/packages/testing/src/agent/index.ts @@ -50,7 +50,7 @@ export class SimpleChannelSelector implements ChannelSelector { this.cw = cw; } - updateChannel(channelId: string | null, availableChannels: Channel[]): void { + async updateChannel(channelId: string | null, availableChannels: Channel[]): Promise { this.cw.props['channelId'] = channelId; this.cw.props['channels'] = availableChannels; } From 5e2fd557e0656911600d300db6c160fdb9e95e1b Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 17:06:30 +0000 Subject: [PATCH 84/90] Picocolors testing exemption --- packages/fdc3-get-agent/src/util/Picocolors.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/fdc3-get-agent/src/util/Picocolors.ts b/packages/fdc3-get-agent/src/util/Picocolors.ts index 9fa7b9c6f..c607f06c0 100644 --- a/packages/fdc3-get-agent/src/util/Picocolors.ts +++ b/packages/fdc3-get-agent/src/util/Picocolors.ts @@ -23,15 +23,15 @@ let isColorSupported; //else only occurs in a browser and can't be tested in node /* istanbul ignore else */ if (typeof process !== 'undefined') { - const argv = process.argv || [], - env = process.env || {}; + const argv = process.argv || /* istanbul ignore next */ [], + env = process.env || /* istanbul ignore next */ {}; isColorSupported = !(!!env.NO_COLOR || argv.includes('--no-color')) && (!!env.FORCE_COLOR || argv.includes('--color') || - process.platform === 'win32' || + process.platform === 'win32' /* istanbul ignore next */ || ((process.stdout || {}).isTTY && env.TERM !== 'dumb') || - !!env.CI); + /* istanbul ignore next */ !!env.CI); } else { isColorSupported = false; } @@ -41,7 +41,9 @@ const formatter = (input: string) => { const string = '' + input, index = string.indexOf(close, open.length); - return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close; + return ~index + ? /* istanbul ignore next */ open + replaceClose(string, close, replace, index) + close + : open + string + close; }; //Not currently hit in the codebase or tests but included for completeness @@ -58,7 +60,9 @@ const replaceClose = (string: string, close: string, replace: string, index: num }; export const createColors = (enabled = isColorSupported) => { - const f = enabled ? formatter : () => String; + //second branch only occurs in a browser and can't be tested in node + /* istanbul ignore next */ + const f = enabled ? formatter : /* istanbul ignore next */ () => String; return { isColorSupported: enabled, reset: f('\x1b[0m', '\x1b[0m'), From 91449c90864f4cc7a273e4e7268c57715dd77636 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 10 Jan 2025 17:06:58 +0000 Subject: [PATCH 85/90] protect messaging in DefaultChannel --- packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index 7ec11f7e2..90d40cb7b 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -10,7 +10,7 @@ import { } from '@kite9/fdc3-schema/generated/api/BrowserTypes'; export class DefaultChannel implements Channel { - readonly messaging: Messaging; + protected readonly messaging: Messaging; readonly id: string; readonly type: 'user' | 'app' | 'private'; readonly displayMetadata?: DisplayMetadata | undefined; From 5babe3c8a943d15813cb4f22fe28e6e9a10209d7 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 13 Jan 2025 11:33:59 +0000 Subject: [PATCH 86/90] Adding notes on non-standard error messages --- packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts | 5 +++-- packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts | 1 + packages/fdc3-agent-proxy/test/features/app-channels.feature | 2 ++ .../fdc3-agent-proxy/test/features/user-channels.feature | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts b/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts index 4b1a39d22..2412c9b55 100644 --- a/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts +++ b/packages/fdc3-agent-proxy/src/DesktopAgentProxy.ts @@ -13,7 +13,7 @@ import { import { ChannelSupport } from './channels/ChannelSupport'; import { AppSupport } from './apps/AppSupport'; import { IntentSupport } from './intents/IntentSupport'; -import { Connectable } from '@kite9/fdc3-standard'; +import { Connectable, Channel } from '@kite9/fdc3-standard'; import { Context } from '@kite9/fdc3-context'; import { HeartbeatSupport } from './heartbeat/HeartbeatSupport'; @@ -84,6 +84,7 @@ export class DesktopAgentProxy implements DesktopAgent, Connectable { theHandler = contextTypeOrHandler as ContextHandler; } else { //invalid call + // TODO: Replace with Standardized error when #1490 is resolved throw new Error('Invalid arguments passed to addContextListener!'); } @@ -118,7 +119,7 @@ export class DesktopAgentProxy implements DesktopAgent, Connectable { return this.channels.joinUserChannel(channelId); } - getCurrentChannel() { + getCurrentChannel(): Promise { return this.channels.getUserChannel(); } diff --git a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts index 90d40cb7b..03ab3535a 100644 --- a/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts +++ b/packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts @@ -68,6 +68,7 @@ export class DefaultChannel implements Channel { theHandler = contextTypeOrHandler as ContextHandler; } else { //invalid call + // TODO: Replace with Standardized error when #1490 is resolved throw new Error('Invalid arguments passed to addContextListener!'); } diff --git a/packages/fdc3-agent-proxy/test/features/app-channels.feature b/packages/fdc3-agent-proxy/test/features/app-channels.feature index ed110e781..ed103e06a 100644 --- a/packages/fdc3-agent-proxy/test/features/app-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/app-channels.feature @@ -73,6 +73,8 @@ Feature: Channel Listeners Support Scenario: Passing invalid arguments to an app channel's addContextListener fn throws an error When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name" And I refer to "{result}" as "channel1" + # Specific error message not tested as its not currently standardized + # TODO: Fix when #1490 is resolved And I call "{channel1}" with "addContextListener" with parameters "{true}" and "{resultHandler}" Then "{result}" is an error And I call "{channel1}" with "addContextListener" with parameters "{null}" and "{true}" diff --git a/packages/fdc3-agent-proxy/test/features/user-channels.feature b/packages/fdc3-agent-proxy/test/features/user-channels.feature index f3584389b..6e208184d 100644 --- a/packages/fdc3-agent-proxy/test/features/user-channels.feature +++ b/packages/fdc3-agent-proxy/test/features/user-channels.feature @@ -164,6 +164,8 @@ Feature: Basic User Channels Support Scenario: Passing invalid arguments to a user channel's addContextListener fn throws an error Given "resultHandler" pipes context to "contexts" When I call "{api}" with "addContextListener" with parameters "{true}" and "{resultHandler}" + # Specific error message not tested as its not currently standardized + # TODO: Fix when #1490 is resolved Then "{result}" is an error And I call "{api}" with "addContextListener" with parameters "{null}" and "{true}" Then "{result}" is an error From 24d0bb28d84ed150db18d6de8b8f01a2c5969dc6 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 13 Jan 2025 11:44:29 +0000 Subject: [PATCH 87/90] Revert dummy-desktop-agent to default directory --- .../fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index 145508e3d..1c13705e9 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -55,8 +55,8 @@ window.addEventListener('load', () => { socket.emit(DA_HELLO, desktopAgentUUID); const directory = new FDC3_2_1_JSONDirectory(); - //await directory.load('/static/da/appd.json'); - await directory.load('/static/da/local-conformance-2_0.v2.json'); + await directory.load('/static/da/appd.json'); + //await directory.load('/static/da/local-conformance-2_0.v2.json'); const sc = new DemoServerContext(socket, directory); const channelDetails: ChannelState[] = [ From ede080339177f9fa25fe5fd472f9005b4267f97b Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 13 Jan 2025 15:49:02 +0000 Subject: [PATCH 88/90] Improving channel selector implementations --- package-lock.json | 81 +++++++++++++++++ toolbox/fdc3-for-web/demo/package.json | 2 + .../demo/src/client/da/dummy-desktop-agent.ts | 88 ++++++++++++++++++- .../demo/src/client/ui/channel-selector.ts | 35 +++++++- .../demo/src/client/ui/contrast.ts | 17 ++++ .../demo/static/da/channel-selector.html | 30 +++---- .../fdc3-for-web/reference-ui/package.json | 2 + .../reference-ui/public/channel_selector.html | 12 ++- .../reference-ui/src/channel_selector.ts | 40 +++++++-- .../fdc3-for-web/reference-ui/src/contrast.ts | 17 ++++ 10 files changed, 288 insertions(+), 36 deletions(-) create mode 100644 toolbox/fdc3-for-web/demo/src/client/ui/contrast.ts create mode 100644 toolbox/fdc3-for-web/reference-ui/src/contrast.ts diff --git a/package-lock.json b/package-lock.json index 816802f7b..eaca1dc27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4136,6 +4136,27 @@ "@types/node": "*" } }, + "node_modules/@types/color": { + "version": "4.2.0", + "integrity": "sha512-6+xrIRImMtGAL2X3qYkd02Mgs+gFGs+WsK0b7VVMaO4mYRISwyTjcqNrO0mNSmYEoq++rSLDB2F5HDNmqfOe+A==", + "dev": true, + "dependencies": { + "@types/color-convert": "*" + } + }, + "node_modules/@types/color-convert": { + "version": "2.0.4", + "integrity": "sha512-Ub1MmDdyZ7mX//g25uBAoH/mWGd9swVbt8BseymnaE18SU4po/PjmCrHxqIIRjBo3hV/vh1KGr0eMxUhp+t+dQ==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.0" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.5", + "integrity": "sha512-j2K5UJqGTxeesj6oQuGpMgifpT5k9HprgQd8D1Y0lOFqKHl3PJu5GMeS4Y5EgjS55AE6OQxf8mPED9uaGbf4Cg==", + "dev": true + }, "node_modules/@types/connect": { "version": "3.4.38", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", @@ -18829,8 +18850,10 @@ }, "devDependencies": { "@eslint/js": "^9.16.0", + "@types/color": "^4.2.0", "@types/express": "^4.17.21", "@types/node": "^20.16.11", + "color": "^4.2.3", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.13.0", @@ -18867,6 +18890,34 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "toolbox/fdc3-for-web/demo/node_modules/color": { + "version": "4.2.3", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "toolbox/fdc3-for-web/demo/node_modules/color-convert": { + "version": "2.0.1", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "toolbox/fdc3-for-web/demo/node_modules/color-name": { + "version": "1.1.4", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "toolbox/fdc3-for-web/demo/node_modules/eslint": { "version": "9.16.0", "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", @@ -19372,6 +19423,8 @@ }, "devDependencies": { "@eslint/js": "^9.16.0", + "@types/color": "^4.2.0", + "color": "^4.2.3", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.13.0", @@ -19407,6 +19460,34 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "toolbox/fdc3-for-web/reference-ui/node_modules/color": { + "version": "4.2.3", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/color-convert": { + "version": "2.0.1", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "toolbox/fdc3-for-web/reference-ui/node_modules/color-name": { + "version": "1.1.4", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "toolbox/fdc3-for-web/reference-ui/node_modules/eslint": { "version": "9.16.0", "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", diff --git a/toolbox/fdc3-for-web/demo/package.json b/toolbox/fdc3-for-web/demo/package.json index 441fdb3f4..45de467c0 100644 --- a/toolbox/fdc3-for-web/demo/package.json +++ b/toolbox/fdc3-for-web/demo/package.json @@ -8,8 +8,10 @@ }, "devDependencies": { "@eslint/js": "^9.16.0", + "@types/color": "^4.2.0", "@types/express": "^4.17.21", "@types/node": "^20.16.11", + "color": "^4.2.3", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.13.0", diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index 1c13705e9..76635847a 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -60,13 +60,93 @@ window.addEventListener('load', () => { const sc = new DemoServerContext(socket, directory); const channelDetails: ChannelState[] = [ - { id: 'one', type: ChannelType.user, context: [], displayMetadata: { name: 'THE RED CHANNEL', color: 'red' } }, - { id: 'two', type: ChannelType.user, context: [], displayMetadata: { name: 'THE BLUE CHANNEL', color: 'blue' } }, { - id: 'three', + id: 'fdc3.channel.1', type: ChannelType.user, context: [], - displayMetadata: { name: 'THE GREEN CHANNEL', color: 'green' }, + displayMetadata: { + name: 'Channel 1', + color: 'red', + glyph: '1', + glyphColor: 'white', + }, + }, + { + id: 'fdc3.channel.2', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 2', + color: 'orange', + glyph: '2', + glyphColor: 'white', + }, + }, + { + id: 'fdc3.channel.3', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 3', + color: 'yellow', + glyph: '3', + glyphColor: 'black', + }, + }, + { + id: 'fdc3.channel.4', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 4', + color: 'green', + glyph: '4', + glyphColor: 'white', + }, + }, + { + id: 'fdc3.channel.5', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 5', + color: 'cyan', + glyph: '5', + glyphColor: 'black', + }, + }, + { + id: 'fdc3.channel.6', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 6', + color: 'blue', + glyph: '6', + glyphColor: 'white', + }, + }, + { + id: 'fdc3.channel.7', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 7', + color: 'magenta', + glyph: '7', + glyphColor: 'white', + }, + }, + { + id: 'fdc3.channel.8', + type: ChannelType.user, + context: [], + displayMetadata: { + name: 'Channel 8', + color: 'purple', + glyph: '8', + glyphColor: 'white', + }, }, ]; const fdc3Server = new DefaultFDC3Server(sc, directory, channelDetails, true, 20000, 10017); diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts index 0e7fc2220..ca65a74bf 100644 --- a/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts +++ b/toolbox/fdc3-for-web/demo/src/client/ui/channel-selector.ts @@ -1,3 +1,4 @@ +import { selectHighestContrast } from './contrast'; import { dragElement } from './drag'; import { Channel, @@ -129,12 +130,16 @@ window.addEventListener('load', () => { logo.addEventListener('click', () => { list.innerHTML = ''; + + //populate with channels channels.forEach(channel => { const li = document.createElement('div'); - li.style.backgroundColor = channel.displayMetadata!.color!; + const bgColor = channel.displayMetadata?.color ?? 'white'; + li.style.backgroundColor = bgColor; + li.style.color = selectHighestContrast(bgColor, 'white', 'black'); const description = document.createElement('em'); - description.textContent = channel.displayMetadata!.name = channel.id == channelId ? ' CURRENT CHANNEL ' : ''; - li.textContent = channel.id; + description.textContent = channel.id == channelId ? ' SELECTED ' : ''; + li.textContent = channel.displayMetadata?.name ?? channel.id; li.appendChild(description); list.appendChild(li); @@ -148,9 +153,31 @@ window.addEventListener('load', () => { }, }; myPort.postMessage(message); - debug('Sending channel selection: ', message); }; }); + + //add an element for deselecting the channel + const li = document.createElement('div'); + li.style.backgroundColor = 'white'; + li.style.color = 'black'; + const description = document.createElement('em'); + description.textContent = channelId == null ? ' SELECTED ' : ''; + li.textContent = 'NONE'; + + li.appendChild(description); + list.appendChild(li); + li.onclick = () => { + changeSize(false); + channelId = null; + const message: Fdc3UserInterfaceChannelSelected = { + type: 'Fdc3UserInterfaceChannelSelected', + payload: { + selected: null, + }, + }; + myPort.postMessage(message); + }; + changeSize(true); }); diff --git a/toolbox/fdc3-for-web/demo/src/client/ui/contrast.ts b/toolbox/fdc3-for-web/demo/src/client/ui/contrast.ts new file mode 100644 index 000000000..b07f3cfe3 --- /dev/null +++ b/toolbox/fdc3-for-web/demo/src/client/ui/contrast.ts @@ -0,0 +1,17 @@ +import Color from 'color'; + +export function selectHighestContrast(bgColorCSS: string, ...candidates: string[]) { + const bgColor = Color(bgColorCSS); + const contrasts: number[] = candidates.map(candidate => { + return bgColor.contrast(Color(candidate)); + }); + let bestCandidate = candidates[0], + highestContrast = contrasts[0]; + for (let i = 1; i < contrasts.length; i++) { + if (contrasts[i] > highestContrast) { + bestCandidate = candidates[i]; + highestContrast = contrasts[i]; + } + } + return bestCandidate; +} diff --git a/toolbox/fdc3-for-web/demo/static/da/channel-selector.html b/toolbox/fdc3-for-web/demo/static/da/channel-selector.html index e15f4c08f..ff9b0c75f 100644 --- a/toolbox/fdc3-for-web/demo/static/da/channel-selector.html +++ b/toolbox/fdc3-for-web/demo/static/da/channel-selector.html @@ -18,9 +18,18 @@ } .selector { - width: 400px; - height: 300px; - position: fixed; + width: 300px; + height: 300px; + position: fixed; + z-index: 2; + background-color: #fff; + right: 10px; + bottom: 10px; + border-radius: .5rem; + border: 1px solid black; + font-family: Arial, Helvetica, sans-serif; + display: flex; + flex-direction: column; } .background { @@ -30,13 +39,6 @@ background-color: #22222222; } - .selector { - z-index: 2; - background-color: #fff; - right: 10px; - bottom: 10px; - } - .logo { z-index: 3; position: fixed; @@ -44,14 +46,6 @@ top: 0; } - .selector { - border-radius: .5rem; - border: 1px solid black; - font-family: Arial, Helvetica, sans-serif; - display: flex; - flex-direction: column; - } - .header { display: flex; flex-basis: 2rem; diff --git a/toolbox/fdc3-for-web/reference-ui/package.json b/toolbox/fdc3-for-web/reference-ui/package.json index de4819f6d..f3d698257 100644 --- a/toolbox/fdc3-for-web/reference-ui/package.json +++ b/toolbox/fdc3-for-web/reference-ui/package.json @@ -12,6 +12,8 @@ }, "devDependencies": { "@eslint/js": "^9.16.0", + "@types/color": "^4.2.0", + "color": "^4.2.3", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "globals": "^15.13.0", diff --git a/toolbox/fdc3-for-web/reference-ui/public/channel_selector.html b/toolbox/fdc3-for-web/reference-ui/public/channel_selector.html index 0d1687c77..a870fd90a 100644 --- a/toolbox/fdc3-for-web/reference-ui/public/channel_selector.html +++ b/toolbox/fdc3-for-web/reference-ui/public/channel_selector.html @@ -8,8 +8,8 @@ .glyph { font-size: 12px; padding: 2px 6px; - border-radius: 16px; - border-width: 1px; + border-radius: 50%; + border-width: 1.5px; border-style: solid; font-weight: bold; } @@ -58,7 +58,13 @@ } .logo path { - stroke: black; + stroke: white; + stroke-width: 10; + paint-order: fill; + } + + #logo { + filter: drop-shadow(rgba(0, 0, 0, 0.4) 0px 0px 3px) } diff --git a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts index 99e7df886..62a6b4444 100644 --- a/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts +++ b/toolbox/fdc3-for-web/reference-ui/src/channel_selector.ts @@ -6,6 +6,7 @@ import { isFdc3UserInterfaceChannels, isFdc3UserInterfaceHandshake, } from '@kite9/fdc3-schema/dist/generated/api/BrowserTypes'; +import { selectHighestContrast } from './contrast'; const fillChannels = (data: Channel[], selected: string | null, messageClickedChannel: (s: string | null) => void) => { const list = document.getElementById('list')!; @@ -19,7 +20,8 @@ const fillChannels = (data: Channel[], selected: string | null, messageClickedCh span.classList.add('glyph'); if (displayMetadata?.color) { - span.style.color = displayMetadata.color; + span.style.color = selectHighestContrast(displayMetadata.color, 'white', 'black'); + span.style.backgroundColor = displayMetadata.color; span.style.borderColor = displayMetadata.color; } span.textContent = displayMetadata?.glyph ?? ''; @@ -42,6 +44,30 @@ const fillChannels = (data: Channel[], selected: string | null, messageClickedCh node.style.backgroundColor = '#bbb'; } }); + + //add an element for leaving all channels + const node = document.createElement('div'); + node.setAttribute('tabIndex', '0'); + + const span = document.createElement('span'); + span.classList.add('glyph'); + span.textContent = 'X'; + node.appendChild(span); + + const span2 = document.createElement('span'); + span2.classList.add('name'); + span2.textContent = 'none'; + node.appendChild(span2); + + list.appendChild(node); + node.addEventListener('click', () => { + messageClickedChannel(null); + }); + + if (selected === null) { + node.setAttribute('aria-selected', 'true'); + node.style.backgroundColor = '#bbb'; + } }; window.addEventListener('load', () => { @@ -84,10 +110,10 @@ window.addEventListener('load', () => { payload: { implementationDetails: 'FDC3 Reference Channel Selector UI', initialCSS: { - width: `${8 * 4}px`, - height: `${8 * 5}px`, + width: `${8 * 6}px`, + height: `${8 * 8}px`, right: '2px', - bottom: '2px', + bottom: '8px', zIndex: '1000', 'z-index': '1000', position: 'fixed', @@ -120,9 +146,9 @@ window.addEventListener('load', () => { type: 'Fdc3UserInterfaceRestyle', payload: { updatedCSS: { - width: `${8 * 4}px`, - height: `${8 * 5}px`, - right: '2px', + width: `${8 * 6}px`, + height: `${8 * 8}px`, + right: '8px', bottom: '2px', zIndex: '1000', 'z-index': '1000', diff --git a/toolbox/fdc3-for-web/reference-ui/src/contrast.ts b/toolbox/fdc3-for-web/reference-ui/src/contrast.ts new file mode 100644 index 000000000..b07f3cfe3 --- /dev/null +++ b/toolbox/fdc3-for-web/reference-ui/src/contrast.ts @@ -0,0 +1,17 @@ +import Color from 'color'; + +export function selectHighestContrast(bgColorCSS: string, ...candidates: string[]) { + const bgColor = Color(bgColorCSS); + const contrasts: number[] = candidates.map(candidate => { + return bgColor.contrast(Color(candidate)); + }); + let bestCandidate = candidates[0], + highestContrast = contrasts[0]; + for (let i = 1; i < contrasts.length; i++) { + if (contrasts[i] > highestContrast) { + bestCandidate = candidates[i]; + highestContrast = contrasts[i]; + } + } + return bestCandidate; +} From 1bbe6b6418bb70177d1ad9f388ff716183ede894 Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 13 Jan 2025 16:13:28 +0000 Subject: [PATCH 89/90] Remove picocolors --- packages/fdc3-get-agent/src/util/Logger.ts | 28 ++++- .../fdc3-get-agent/src/util/Picocolors.ts | 114 ------------------ 2 files changed, 22 insertions(+), 120 deletions(-) delete mode 100644 packages/fdc3-get-agent/src/util/Picocolors.ts diff --git a/packages/fdc3-get-agent/src/util/Logger.ts b/packages/fdc3-get-agent/src/util/Logger.ts index 6a6a16f59..a207a99b2 100644 --- a/packages/fdc3-get-agent/src/util/Logger.ts +++ b/packages/fdc3-get-agent/src/util/Logger.ts @@ -1,14 +1,30 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { createColors } from './Picocolors'; const GET_AGENT_LOG_PREFIX = 'FDC3 getAgent: '; -const pc = createColors(); +//check if color is supported in console; +let noColor = true; +//else only occurs in a browser and can't be tested in node +/* istanbul ignore if */ +if (typeof process !== 'undefined') { + const argv = process.argv || /* istanbul ignore next */ []; + const env = process.env || /* istanbul ignore next */ {}; + noColor = + (!!env.NO_COLOR || argv.includes('--no-color')) && + !( + !!env.FORCE_COLOR || + argv.includes('--color') || + process.platform === 'win32' /* istanbul ignore next */ || + ((process.stdout || {}).isTTY && env.TERM !== 'dumb') || + /* istanbul ignore next */ !!env.CI + ); +} type ColorFn = (aString: string) => string; -const debugColor: ColorFn = value => pc.black(pc.dim(value)); -const logColor: ColorFn = value => pc.green(pc.dim(value)); -const warnColor: ColorFn = value => pc.yellow(value); -const errorColor: ColorFn = value => pc.red(value); + +const debugColor: ColorFn = value => (noColor ? value : '\x1b[30m\x1b[2m' + value + '\x1b[22m\x1b[39m'); +const logColor: ColorFn = value => (noColor ? value : '\x1b[32m\x1b[2m' + value + '\x1b[22m\x1b[39m'); +const warnColor: ColorFn = value => (noColor ? value : '\x1b[33m' + value + '\x1b[39m'); +const errorColor: ColorFn = value => (noColor ? value : '\x1b[31m' + value + '\x1b[39m'); const prefixAndColorize = (params: any[], colorFn: ColorFn): string[] => { const prefixed = [GET_AGENT_LOG_PREFIX, ...params]; diff --git a/packages/fdc3-get-agent/src/util/Picocolors.ts b/packages/fdc3-get-agent/src/util/Picocolors.ts deleted file mode 100644 index c607f06c0..000000000 --- a/packages/fdc3-get-agent/src/util/Picocolors.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* -From picocolors (imported due to issues building in both ESM and CommonJS) -https://github.com/alexeyraspopov/picocolors - -ISC License - -Copyright (c) 2021-2024 Oleksii Raspopov, Kostiantyn Denysov, Anton Verinov - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -let isColorSupported; -//else only occurs in a browser and can't be tested in node -/* istanbul ignore else */ -if (typeof process !== 'undefined') { - const argv = process.argv || /* istanbul ignore next */ [], - env = process.env || /* istanbul ignore next */ {}; - isColorSupported = - !(!!env.NO_COLOR || argv.includes('--no-color')) && - (!!env.FORCE_COLOR || - argv.includes('--color') || - process.platform === 'win32' /* istanbul ignore next */ || - ((process.stdout || {}).isTTY && env.TERM !== 'dumb') || - /* istanbul ignore next */ !!env.CI); -} else { - isColorSupported = false; -} - -const formatter = - (open: string, close: string, replace = open) => - (input: string) => { - const string = '' + input, - index = string.indexOf(close, open.length); - return ~index - ? /* istanbul ignore next */ open + replaceClose(string, close, replace, index) + close - : open + string + close; - }; - -//Not currently hit in the codebase or tests but included for completeness -/* istanbul ignore next */ -const replaceClose = (string: string, close: string, replace: string, index: number) => { - let result = '', - cursor = 0; - do { - result += string.substring(cursor, index) + replace; - cursor = index + close.length; - index = string.indexOf(close, cursor); - } while (~index); - return result + string.substring(cursor); -}; - -export const createColors = (enabled = isColorSupported) => { - //second branch only occurs in a browser and can't be tested in node - /* istanbul ignore next */ - const f = enabled ? formatter : /* istanbul ignore next */ () => String; - return { - isColorSupported: enabled, - reset: f('\x1b[0m', '\x1b[0m'), - bold: f('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m'), - dim: f('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m'), - italic: f('\x1b[3m', '\x1b[23m'), - underline: f('\x1b[4m', '\x1b[24m'), - inverse: f('\x1b[7m', '\x1b[27m'), - hidden: f('\x1b[8m', '\x1b[28m'), - strikethrough: f('\x1b[9m', '\x1b[29m'), - - black: f('\x1b[30m', '\x1b[39m'), - red: f('\x1b[31m', '\x1b[39m'), - green: f('\x1b[32m', '\x1b[39m'), - yellow: f('\x1b[33m', '\x1b[39m'), - blue: f('\x1b[34m', '\x1b[39m'), - magenta: f('\x1b[35m', '\x1b[39m'), - cyan: f('\x1b[36m', '\x1b[39m'), - white: f('\x1b[37m', '\x1b[39m'), - gray: f('\x1b[90m', '\x1b[39m'), - - bgBlack: f('\x1b[40m', '\x1b[49m'), - bgRed: f('\x1b[41m', '\x1b[49m'), - bgGreen: f('\x1b[42m', '\x1b[49m'), - bgYellow: f('\x1b[43m', '\x1b[49m'), - bgBlue: f('\x1b[44m', '\x1b[49m'), - bgMagenta: f('\x1b[45m', '\x1b[49m'), - bgCyan: f('\x1b[46m', '\x1b[49m'), - bgWhite: f('\x1b[47m', '\x1b[49m'), - - blackBright: f('\x1b[90m', '\x1b[39m'), - redBright: f('\x1b[91m', '\x1b[39m'), - greenBright: f('\x1b[92m', '\x1b[39m'), - yellowBright: f('\x1b[93m', '\x1b[39m'), - blueBright: f('\x1b[94m', '\x1b[39m'), - magentaBright: f('\x1b[95m', '\x1b[39m'), - cyanBright: f('\x1b[96m', '\x1b[39m'), - whiteBright: f('\x1b[97m', '\x1b[39m'), - - bgBlackBright: f('\x1b[100m', '\x1b[49m'), - bgRedBright: f('\x1b[101m', '\x1b[49m'), - bgGreenBright: f('\x1b[102m', '\x1b[49m'), - bgYellowBright: f('\x1b[103m', '\x1b[49m'), - bgBlueBright: f('\x1b[104m', '\x1b[49m'), - bgMagentaBright: f('\x1b[105m', '\x1b[49m'), - bgCyanBright: f('\x1b[106m', '\x1b[49m'), - bgWhiteBright: f('\x1b[107m', '\x1b[49m'), - }; -}; From 6ff39c5f59492af515e584101e099ef08e0ecd1b Mon Sep 17 00:00:00 2001 From: Kris West Date: Mon, 13 Jan 2025 21:58:35 +0000 Subject: [PATCH 90/90] remove unused glyphColor --- .../demo/src/client/da/dummy-desktop-agent.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts index 76635847a..a82b33ce8 100644 --- a/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts +++ b/toolbox/fdc3-for-web/demo/src/client/da/dummy-desktop-agent.ts @@ -68,7 +68,6 @@ window.addEventListener('load', () => { name: 'Channel 1', color: 'red', glyph: '1', - glyphColor: 'white', }, }, { @@ -79,7 +78,6 @@ window.addEventListener('load', () => { name: 'Channel 2', color: 'orange', glyph: '2', - glyphColor: 'white', }, }, { @@ -90,7 +88,6 @@ window.addEventListener('load', () => { name: 'Channel 3', color: 'yellow', glyph: '3', - glyphColor: 'black', }, }, { @@ -101,7 +98,6 @@ window.addEventListener('load', () => { name: 'Channel 4', color: 'green', glyph: '4', - glyphColor: 'white', }, }, { @@ -112,7 +108,6 @@ window.addEventListener('load', () => { name: 'Channel 5', color: 'cyan', glyph: '5', - glyphColor: 'black', }, }, { @@ -123,7 +118,6 @@ window.addEventListener('load', () => { name: 'Channel 6', color: 'blue', glyph: '6', - glyphColor: 'white', }, }, { @@ -134,7 +128,6 @@ window.addEventListener('load', () => { name: 'Channel 7', color: 'magenta', glyph: '7', - glyphColor: 'white', }, }, { @@ -145,7 +138,6 @@ window.addEventListener('load', () => { name: 'Channel 8', color: 'purple', glyph: '8', - glyphColor: 'white', }, }, ];