diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e00e1664..d290dc436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,10 +45,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * ES6 functions for `getInfo()` and `raiseIntentForContext()` ([#268](https://github.com/finos/FDC3/pull/268), [#324](https://github.com/finos/FDC3/pull/324)) * `fdc3Ready()` utility function that wraps checks for the window.fdc3 global object and new `fdc3Ready` event ([#360](https://github.com/finos/FDC3/pull/360)) * `compareVersionNumbers()` and `versionIsAtLeast()` utility functions to complement `getInfo()` ([#324](https://github.com/finos/FDC3/pull/324)) +* An example application definition ([#437](https://github.com/finos/FDC3/pull/437) +* A test environment for the app directory specification and the example application definition ([#437](https://github.com/finos/FDC3/pull/437) ### Changed * `addContextListener(contextType, handler)` now supports passing `null` as the context type ([#329](https://github.com/finos/FDC3/pull/329)) * All other API type changes and additions from the [FDC3 Standard 1.2](https://github.com/finos/FDC3/releases/tag/v1.2) release +* The Application schema by removing the `manifestType` and `manifest` properties, introducing new `type` (required), `details` and `hostManifests` properties ([#437](https://github.com/finos/FDC3/pull/437) ### Deprecated * `addContextListener(handler)` ([#329](https://github.com/finos/FDC3/pull/329)) diff --git a/src/app-directory/specification/appd.yaml b/src/app-directory/specification/appd.yaml index c0c68356d..18bdda76c 100644 --- a/src/app-directory/specification/appd.yaml +++ b/src/app-directory/specification/appd.yaml @@ -115,17 +115,6 @@ paths: The same appName could occur in other directories. We are not currently specifying app name conventions in the document. - - in: query - name: manifest - schema: - type: string - required: false - description: > - URI or full JSON of the application manifest providing all details related to launch - and use requirements as described by the vendor. - - The format of this manifest is vendor specific, but can be identified by - the manifestType attribute. - in: query name: version schema: @@ -204,7 +193,7 @@ paths: $ref: '#/components/schemas/ErrorDTO' tags: - Application - + servers: - url: /appd components: @@ -227,14 +216,13 @@ components: Defines an application retrieved from an FDC3 App Directory, which can then be launched. - Launching typically means running for a user on a desktop. + Launching typically means running for a user on a desktop. The details around 'launching' including who or what might do it, and how the launch action is initiated are discussed elsewhere in the FDC3 App Directory spec. - required: + required: # details are not required as the host type applications use the hostsManifests mapping instead - appId - name - - manifest - - manifestType + - type properties: appId: type: string @@ -252,19 +240,14 @@ components: The same appName could occur in other directories. We are not currently specifying app name conventions in the document. - manifest: - type: string - description: > - URI or full JSON of the application manifest providing all details related to launch - and use requirements as described by the vendor. - - The format of this manifest is vendor specific, but can be identified by - the manifestType attribute. - manifestType: - type: string - description: > - The manifest type which relates to the format and structure of the manifest content. - The definition is based on the vendor specific format and definition outside of this specification. + type: + $ref: '#/components/schemas/Type' + details: + description: >- + The type specific details of the application. Currently only the "browser" type is standardized. + "host" type applications should use the hostManifest's object for all application details. + oneOf: + - $ref: '#/components/schemas/BrowserDetails' version: type: string description: >- @@ -323,6 +306,8 @@ components: https://github.com/FDC3/Intents/blob/master/src/Intent.yaml items: $ref: '#/components/schemas/Intent' + hostManifests: + $ref: '#/components/schemas/HostManifest' ApplicationSearchResponse: properties: applications: @@ -380,10 +365,37 @@ components: items: type: string description: >- - A comma sepaarted list of the types of contexts the intent offered by the application can process. + A comma separated list of context-types that the application's intent(s) can process. where the first part of the context type is the namespace e.g."fdc3.contact, org.symphony.contact" customConfig: type: object description: >- Custom configuration for the intent that may be required for a particular desktop agent. + Type: + type: string + description: >- + Enumeration describing the supported application types. Currently only the browser application type is officially supported. + The host application type allows for host specific application types (e.g. exe, workspaces, citrix, etc.). + enum: + - browser + - host + BrowserDetails: + description: Properties common to all browser applications. + required: + - url + properties: + url: + type: string + description: Application URL. + additionalProperties: false + HostManifest: + type: object + description: >- + A mapping from host string to a host-specific application manifest object or URI + from which that manifest can be retrieved. The manifest should provide all details required to + launch and use the application within the specified host. + additionalProperties: + oneOf: + - type: string # URI pointing to a JSON containing all host specific properties + - type: object # object containing all host specific properties diff --git a/src/app-directory/specification/examples/application/fdc3-workbench.js b/src/app-directory/specification/examples/application/fdc3-workbench.js new file mode 100644 index 000000000..f512e600a --- /dev/null +++ b/src/app-directory/specification/examples/application/fdc3-workbench.js @@ -0,0 +1,82 @@ +module.exports = { + "appId": "fdc3-workbench", + "name": "fdc3-workbench", + "title": "FDC3 Workbench", + "description": "Development and test tool for FDC3 desktop agents and apps", + "version": "1.0.0", + "tooltip": "FDC3 Workbench", + "icons": [ + { + "url": "http://fdc3.finos.org/toolbox/fdc3-workbench/fdc3-icon-256.png" + } + ], + "images": [ + { + "url": "https://fdc3.finos.org/docs/assets/fdc3-logo.png", + "tooltip": "FDC3 logo" + } + ], + "contactEmail": "fdc3@finos.org", + "supportEmail": "fdc3-maintainers@finos.org", + "publisher": "FDC3", + "intents": [ + { + "name": "ViewChart", + "displayName": "View Chart", + "contexts": ["fdc3.instrument"] + } + ], + "type": "browser", + "details": { + "url": "https://fdc3.finos.org/toolbox/fdc3-workbench/" + }, + "hostManifests": { + "Glue42": { + "type": "window", + "icon": "https://fdc3.finos.org/docs/assets/fdc3-logo.png", + "details": { + "height": 640, + "width": 560, + "left": 120, + "top": 120, + "mode": "tab", + "allowChannels": true, + "loader": { + "enabled": true, + "hideOnLoad": true + } + }, + "customProperties": { + "folder": "FDC3 Toolbox" + } + }, + "Finsemble": { + "window": { + "left": 120, + "top": 120, + "width": 800, + "height": 750, + "options": { + "minWidth": 75 + } + }, + "foreign": { + "components": { + "App Launcher": { + "launchableByUser": true + }, + "Toolbar": { + "iconURL": "http://fdc3.finos.org/toolbox/fdc3-workbench/fdc3-icon-256.png" + }, + "Window Manager": { + "FSBLHeader": true, + "persistWindowState": true + } + } + }, + "interop": { + "autoConnect": true + } + } + } +}; diff --git a/src/app-directory/specification/test/index.js b/src/app-directory/specification/test/index.js new file mode 100644 index 000000000..c103ad0ca --- /dev/null +++ b/src/app-directory/specification/test/index.js @@ -0,0 +1,24 @@ +const SwaggerParser = require('@apidevtools/swagger-parser'); +const { Validator } = require('jsonschema'); +const assert = require('assert'); +const exampleApplication = require('../examples/application/fdc3-workbench'); + +(async () => { + try { + const api = await SwaggerParser.validate('../appd.yaml'); + + console.log(`API name: ${api.info.title}, Version: ${api.info.version}`); + + const applicationSchema = api.components.schemas.Application; + + const v = new Validator(); + + const validatorResult = v.validate(exampleApplication, applicationSchema); + + assert(validatorResult.valid, `The example application definition does not comply with the Application schema: ${validatorResult.errors}`); + + console.log('Successfully validated the specification and the example application definition!'); + } catch (error) { + console.log(error.message || error); + } +})(); diff --git a/src/app-directory/specification/test/package-lock.json b/src/app-directory/specification/test/package-lock.json new file mode 100644 index 000000000..03a7cdec9 --- /dev/null +++ b/src/app-directory/specification/test/package-lock.json @@ -0,0 +1,255 @@ +{ + "name": "app-directory-specification-test", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "app-directory-specification-test", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@apidevtools/swagger-parser": "^10.0.2", + "jsonschema": "^1.4.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz", + "integrity": "sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^4.2.3" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz", + "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonschema": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz", + "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==", + "engines": { + "node": "*" + } + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/openapi-types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.1.0.tgz", + "integrity": "sha512-mhXh8QN8sbErlxfxBeZ/pzgvmDn443p8CXlxwGSi2bWANZAFvjLPI0PoGjqHW+JdBbXg6uvmvM81WXaweh/SVA==", + "peer": true + }, + "node_modules/validator": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", + "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/z-schema": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz", + "integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==", + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.6.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=6.0.0" + }, + "optionalDependencies": { + "commander": "^2.7.1" + } + } + }, + "dependencies": { + "@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "requires": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==" + }, + "@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" + }, + "@apidevtools/swagger-parser": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz", + "integrity": "sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==", + "requires": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^4.2.3" + } + }, + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, + "@types/json-schema": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz", + "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsonschema": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz", + "integrity": "sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "openapi-types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.1.0.tgz", + "integrity": "sha512-mhXh8QN8sbErlxfxBeZ/pzgvmDn443p8CXlxwGSi2bWANZAFvjLPI0PoGjqHW+JdBbXg6uvmvM81WXaweh/SVA==", + "peer": true + }, + "validator": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", + "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==" + }, + "z-schema": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz", + "integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==", + "requires": { + "commander": "^2.7.1", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.6.0" + } + } + } +} diff --git a/src/app-directory/specification/test/package.json b/src/app-directory/specification/test/package.json new file mode 100644 index 000000000..f35cddefe --- /dev/null +++ b/src/app-directory/specification/test/package.json @@ -0,0 +1,29 @@ +{ + "name": "app-directory-specification-test", + "version": "1.0.0", + "author": "Fintech Open Source Foundation (FINOS)", + "homepage": "https://fdc3.finos.org", + "repository": { + "type": "git", + "url": "https://github.com/finos/FDC3.git" + }, + "publishConfig": { + "tag": "latest" + }, + "license": "Apache-2.0", + "main": "index.js", + "files": [ + "index.js", + "src" + ], + "engines": { + "node": ">=10" + }, + "scripts": { + "test": "node index.js" + }, + "dependencies": { + "@apidevtools/swagger-parser": "^10.0.2", + "jsonschema": "^1.4.0" + } +}