From fe97adc1c0b4055750169cc6f28f67ba2860c84e Mon Sep 17 00:00:00 2001 From: Jeremy LaCivita Date: Fri, 20 Oct 2023 12:49:44 -0400 Subject: [PATCH] chore: Added Markdown Beautifier and link fixer --- requirements/glossary.md | 116 +- requirements/governance.md | 342 ++++-- .../specifications/lifecycle/index.md | 1059 +++++++++-------- .../specifications/lifecycle/presentation.md | 169 ++- requirements/style-guide-and-template.md | 160 ++- src/js/github.io/markdown.mjs | 193 ++- 6 files changed, 1331 insertions(+), 708 deletions(-) diff --git a/requirements/glossary.md b/requirements/glossary.md index 5f8d7d4c8..03ad1e1cf 100644 --- a/requirements/glossary.md +++ b/requirements/glossary.md @@ -1,17 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Glossary -Document Status: Working Draft +Document Status: Working Draft -| Contributor | Organization | -| -------------- | -------------- | -| Jeremy LaCivita | Comcast | +| Contributor | Organization | +| --------------- | ------------ | +| Jeremy LaCivita | Comcast | ## 1. Overview -This document describes various terms used as part of Firebolt APIs, e.g. method names or parameters, and how they are used by Firebolt, for consistency. +This document describes various terms used as part of Firebolt APIs, e.g. +method names or parameters, and how they are used by Firebolt, for +consistency. -The terms are this document are commonly used across multiple modules. However, new APIs should be deferential to all existing APIs, not just words listed here. +The terms are this document are commonly used across multiple modules. However, + new APIs should be deferential to all existing APIs, not just words listed +here. -The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be interpreted as described in [BCP 14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. +The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL + NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT +RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be +interpreted as described in [BCP +14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and + only when, they appear in all capitals, as shown here. ## 2. Table of Contents - [1. Overview](#1-overview) @@ -35,43 +76,76 @@ The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL ## 3. Firebolt Terms ### 3.1. app -noun. - A Firebolt app. Any component that calls [Firebolt APIs](https://github.com/rdkcentral/firebolt-apis), either directly, or by running inside of a container that calls Firebolt APIs, is a Firebolt app. +noun. - A Firebolt app. Any component that calls [Firebolt +APIs](https://github.com/rdkcentral/firebolt-apis), either directly, or by +running inside of a container that calls Firebolt APIs, is a Firebolt app. ### 3.2. available -adj. - Used in the context of a [capability](#34-capability) to denote that the capability *could* be leveraged now if it is [permitted](#311-permitted) and either [granted](#38-granted) or is not gated by a [user grant](#313-user-grant). Available capabilities are, by definition, [supported](#314-supported). +adj. - Used in the context of a [capability](#34-capability) to denote that the + capability *could* be leveraged now if it is [permitted](#311-permitted) +and either [granted](#38-granted) or is not gated by a [user +grant](#313-user-grant). Available capabilities are, by definition, +[supported](#314-supported). ### 3.3. availability -noun. - Used in the context of [content](#36-content) to denote that the content *could* be consumed if either the device has an [entitlement](#37-entitlement) to the content, or the content does not require any entitlement. +noun. - Used in the context of [content](#36-content) to denote that the +content *could* be consumed if either the device has an +[entitlement](#37-entitlement) to the content, or the content does not +require any entitlement. ### 3.4. capability -noun. - A discrete unit of functionality that a Firebolt device might be able to perform. It is granular enough to enable appropriate access controls across all Firebolt Apps, but useful enough to be a meaningful functional unit that an App might care about. +noun. - A discrete unit of functionality that a Firebolt device might be able +to perform. It is granular enough to enable appropriate access controls +across all Firebolt Apps, but useful enough to be a meaningful functional +unit that an App might care about. ### 3.5. closed captions -noun. - Closed Captions are text tracks rendered over or near [content](#36-content) with the intention of making the audio track of the content more accessible, for example to deaf or hard-of-hearing individuals. +noun. - Closed Captions are text tracks rendered over or near +[content](#36-content) with the intention of making the audio track of the +content more accessible, for example to deaf or hard-of-hearing individuals. ### 3.6. content -noun. - Content consumed on Firebolt platforms, e.g. video, games, music, etc. +noun. - Content consumed on Firebolt platforms, e.g. video, games, music, etc. ### 3.7. entitlement -noun. - Used in the context of [content](#36-content) to denote that the device or user has acquired the *right* to consume the content. Content may also have [availability](#33-availability) requirements for consumption, e.g. a user may have pre-orded a piece of content, and therefor have an entitlement to it, that becomes available in the future. +noun. - Used in the context of [content](#36-content) to denote that the device + or user has acquired the *right* to consume the content. Content may also +have [availability](#33-availability) requirements for consumption, e.g. a +user may have pre-orded a piece of content, and therefor have an entitlement +to it, that becomes available in the future. ### 3.8. granted -adj. - Used in the context of a [capability](#34-capability) to denote that the capability has been granted to an app by the user. Capabilities that are gated by [user grant](#313-user-grant) cannot be leveraged by any app w/out being granted. +adj. - Used in the context of a [capability](#34-capability) to denote that the + capability has been granted to an app by the user. Capabilities that are +gated by [user grant](#313-user-grant) cannot be leveraged by any app w/out +being granted. ### 3.9. lifecycle -noun. - Used to describe the life, from being loaded to unloaded, of a Firebolt [app](#31-app). The app lifecycle has many states that inform the app how it is being percieved and how it should behave. +noun. - Used to describe the life, from being loaded to unloaded, of a Firebolt + [app](#31-app). The app lifecycle has many states that inform the app how +it is being percieved and how it should behave. ### 3.10. media -noun. - [Content](#36-content) that that plays back over time without requiring interaction from the user, e.g. video or music. Media must have a start-time, or a duration, or both. +noun. - [Content](#36-content) that that plays back over time without requiring + interaction from the user, e.g. video or music. Media must have a +start-time, or a duration, or both. ### 3.11. permitted -adj. - Used in the context of a [capability](#34-capability) to denote that the capability has been permitted to an app by the distributor of the device. +adj. - Used in the context of a [capability](#34-capability) to denote that the + capability has been permitted to an app by the distributor of the device. ### 3.12. policy -noun. - A group of user, device, and/or distributor settings that affect a particular domain, e.g. Advertising. +noun. - A group of user, device, and/or distributor settings that affect a +particular domain, e.g. Advertising. ### 3.13. user grant -noun. - A secure process in which a user of a device grants an app on the device access to a capability. +noun. - A secure process in which a user of a device grants an app on the +device access to a capability. ### 3.14. supported -adj. - Used in the context of a [capability](#34-capability) to denote that the capability *could* be leveraged at some point on this device, because the distributor offers it as part of this device's feature set. Leveraging a capability also requires that it is [available](#32-available), [permitted](#311-permitted), and either [granted](#38-granted) or is not gated by a [user grant](#313-user-grant). +adj. - Used in the context of a [capability](#34-capability) to denote that the + capability *could* be leveraged at some point on this device, because the +distributor offers it as part of this device's feature set. Leveraging a +capability also requires that it is [available](#32-available), +[permitted](#311-permitted), and either [granted](#38-granted) or is not +gated by a [user grant](#313-user-grant). diff --git a/requirements/governance.md b/requirements/governance.md index 2f3f2e404..2608b5990 100644 --- a/requirements/governance.md +++ b/requirements/governance.md @@ -1,10 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Requirements Governance -This document outlines the governance model for the Firebolt® Open-Source Project, including the structure of an Advisory Board and Working Groups, as well as the process used to codify Requirements Specifications and Architectural Decision Records. +This document outlines the governance model for the Firebolt® Open-Source +Project, including the structure of an Advisory Board and Working Groups, as +well as the process used to codify Requirements Specifications and +Architectural Decision Records. ## 1. Overview -The Firebolt Open-Source Project is governed by an Advisory Board that creates and delegates work to Working Groups, which then create proposals for Requirements Specifications and Architectural Decision Records. +The Firebolt Open-Source Project is governed by an Advisory Board that creates +and delegates work to Working Groups, which then create proposals for +Requirements Specifications and Architectural Decision Records. -![Governance Structure](./images/governance/structure.png) +![Governance Structure](./images/governance/structure.png) ## 2. Table of Contents - [1. Overview](#1-overview) @@ -31,9 +68,12 @@ The Firebolt Open-Source Project is governed by an Advisory Board that creates a - [4.12. Release Versions](#412-release-versions) ## 3. Goals -The goal of the Firebolt Open-Source Project is to provide a Distributor-configurable set of integration APIs and functional requirements for those APIs so that Apps can integrate with the APIs once and run their app on every Firebolt platform (regardless of distributor) consistently. +The goal of the Firebolt Open-Source Project is to provide a +Distributor-configurable set of integration APIs and functional requirements +for those APIs so that Apps can integrate with the APIs once and run their +app on every Firebolt platform (regardless of distributor) consistently. -Specifically, Firebolt provides: +Specifically, Firebolt provides: - Write Apps once, run on all Firebolt distributors - Discovery and launching of Apps @@ -42,9 +82,9 @@ Specifically, Firebolt provides: - Platform integration APIs, (e.g. captions, media info, etc.) - Device and account management - Integration APIs for broader eco-system integrations -(e.g. user experience, advertising, voice, etc.) +(e.g. user experience, advertising, voice, etc.) -While enabling Distributors to: +While enabling Distributors to: - Provide differentiating Discovery and Settings experiences - Configure Firebolt features to meet their business needs @@ -53,28 +93,38 @@ While enabling Distributors to: - Negotiate access to features and APIs with each app ## 4. Governance -The Firebolt Open-Source Project is governed by an Advisory Board. The purpose of the Advisory Board is to ensure that each major, minor, and patch version of the Firebolt Requirements is aligned with the goals of the Firebolt Open-Source Project. - -The Firebolt Requirements are the collection of all Requirements Specifications and all Architectural Decision Records that are ratified by the Advisory Board (and contained in this repository). +The Firebolt Open-Source Project is governed by an Advisory Board. The purpose +of the Advisory Board is to ensure that each major, minor, and patch version +of the Firebolt Requirements is aligned with the goals of the Firebolt +Open-Source Project. + +The Firebolt Requirements are the collection of all Requirements Specifications + and all Architectural Decision Records that are ratified by the Advisory +Board (and contained in this repository). ### 4.1. Scope -This document describes the governance model for the following components: +This document describes the governance model for the following components: - Firebolt RPC APIs & SDKs - Firebolt Media Pipeline (aka Rialto) - Firebolt API Reference Implementation (Ripple) ### 4.2. Firebolt Version -A Firebolt Version is a snapshot of the Firebolt Requirements that has been ratified as an official release of the requirements. Note that the requirements are decoupled from any implementation of those requirements, and iterations to the requirements will occur with input from any teams implementing them. +A Firebolt Version is a snapshot of the Firebolt Requirements that has been +ratified as an official release of the requirements. Note that the +requirements are decoupled from any implementation of those requirements, and + iterations to the requirements will occur with input from any teams +implementing them. -Firebolt Versions **MUST** follow Semantic Versioning. +Firebolt Versions **MUST** follow Semantic Versioning. ### 4.3. Advisory Board -The Advisory Board oversees all aspects of Firebolt Requirements Governance. +The Advisory Board oversees all aspects of Firebolt Requirements Governance. -Advisory Board decisions should aim to be unanimous whenever possible, but in cases of deadlock, may be decided by simple majority. +Advisory Board decisions should aim to be unanimous whenever possible, but in +cases of deadlock, may be decided by simple majority. -The Advisory Board is responsible for: +The Advisory Board is responsible for: - Prioritization of Working Groups needed - Creation of balanced Working Groups with relevant subject matter experts @@ -85,68 +135,121 @@ The Advisory Board is responsible for: - Determination of when a sanctioned fork is warranted ### 4.4. Advisory Board Members -The Firebolt Advisory Board is currently being formed and will be published soon. +The Firebolt Advisory Board is currently being formed and will be published +soon. -Contact the `rdkcentral/firebolt-apis` maintainer, [Jeremy LaCivita](https://github.com/jlacivita), to submit proposals to the Advisory Board. +Contact the `rdkcentral/firebolt-apis` maintainer, [Jeremy +LaCivita](https://github.com/jlacivita), to submit proposals to the Advisory +Board. ### 4.5. Working Group -Working Groups build consensus on requirements for Firebolt features or architectural solutions. They should ideally be three to five individuals spanning technical and product experts. Further recommendations on working group composition are left to the Advisory Board. +Working Groups build consensus on requirements for Firebolt features or +architectural solutions. They should ideally be three to five individuals +spanning technical and product experts. Further recommendations on working +group composition are left to the Advisory Board. -As new features are prioritized, Working Groups should be formed to gather and document requirements for those features. Working groups may be self-forming or selected by the Advisory Board, but all working groups must have their membership reviewed and approved by the board to ensure that they are well balanced. +As new features are prioritized, Working Groups should be formed to gather and +document requirements for those features. Working groups may be self-forming +or selected by the Advisory Board, but all working groups must have their +membership reviewed and approved by the board to ensure that they are well +balanced. -The Advisory Board **MAY** appoint a Working Group Chair or instruct the Working Group to select a chair amongst themselves. +The Advisory Board **MAY** appoint a Working Group Chair or instruct the +Working Group to select a chair amongst themselves. -The Working Group Chair is responsible for driving consensus and reporting back to the Advisory Board +The Working Group Chair is responsible for driving consensus and reporting back + to the Advisory Board ### 4.6. Requirements Specification -A Requirements Specification includes all details necessary for multiple, disassociated teams to build a consistent implementation of a feature, including API signatures, validation, and functionality, as well as functional and behavioral requirements of the feature that are not directly exposed by an API. - -Requirements and APIs may be targeted towards traditional 3rd party apps, as well as more foundational 1st party apps. - -The level of detail in an acceptable Requirements Specification should be such that any App should run consistently on any implementation of the feature that is based on the Specification. - -Requirements Specifications are written using the [IETF Best Common Practice 14](https://www.rfc-editor.org/rfc/rfc2119.txt) and should include the following at the end of the Overview: - -The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be interpreted as described in [BCP 14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. - -Requirements Specification move through several [stages](#48-approval-stages) from being a draft, to being an official versioned requirements specification. +A Requirements Specification includes all details necessary for multiple, +disassociated teams to build a consistent implementation of a feature, +including API signatures, validation, and functionality, as well as +functional and behavioral requirements of the feature that are not directly +exposed by an API. + +Requirements and APIs may be targeted towards traditional 3rd party apps, as +well as more foundational 1st party apps. + +The level of detail in an acceptable Requirements Specification should be such +that any App should run consistently on any implementation of the feature +that is based on the Specification. + +Requirements Specifications are written using the [IETF Best Common Practice +14](https://www.rfc-editor.org/rfc/rfc2119.txt) and should include the +following at the end of the Overview: + +The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL + NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT +RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be +interpreted as described in [BCP +14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and + only when, they appear in all capitals, as shown here. + +Requirements Specification move through several [stages](#48-approval-stages) +from being a draft, to being an official versioned requirements +specification. ### 4.7. Architectural Decision Record -An Architectural Decision Record includes all details necessary to ensure that Firebolt Requirements are fulfilled with an architecturally sound design. This is often used in cases where listing out explicit requirements, e.g. performance or operational requirements, is not possible or realistic, e.g. Requiring use of a well-known open source component to fulfill some aspect of the platform, or requiring adherence to a high level modular breakdown of concerns to keep platform maintenance manageable. - -Since ADRs included in the Firebolt Requirements **MUST** be adhered to, not every architectural decision made in order to fulfill the Firebolt Requirements needs to have a formal ADR in the Firebolt Requirements repository. It is up to the Advisory Board which ADRs warrent a formal inclusion in the Firebolt Requirements. - -ADRs move through the same [stages](#48-approval-stages) as Requirements Specifications. +An Architectural Decision Record includes all details necessary to ensure that +Firebolt Requirements are fulfilled with an architecturally sound design. +This is often used in cases where listing out explicit requirements, e.g. +performance or operational requirements, is not possible or realistic, e.g. +Requiring use of a well-known open source component to fulfill some aspect of + the platform, or requiring adherence to a high level modular breakdown of +concerns to keep platform maintenance manageable. + +Since ADRs included in the Firebolt Requirements **MUST** be adhered to, not +every architectural decision made in order to fulfill the Firebolt +Requirements needs to have a formal ADR in the Firebolt Requirements +repository. It is up to the Advisory Board which ADRs warrent a formal +inclusion in the Firebolt Requirements. + +ADRs move through the same [stages](#48-approval-stages) as Requirements +Specifications. ### 4.8. Approval Stages -Requirements specifications and ADRs are written by working groups and go through several stages of approval before becoming official requirements documents. +Requirements specifications and ADRs are written by working groups and go +through several stages of approval before becoming official requirements +documents. -![Approval Track](./images/governance/approval-track.png) +![Approval Track](./images/governance/approval-track.png) #### 4.8.1. Draft -This is any first draft of a requirements specification submitted by an individual or individuals to a Working Group. +This is any first draft of a requirements specification submitted by an +individual or individuals to a Working Group. -Artifacts: +Artifacts: - A markdown document, ready to be presented to the Working Group -Note that a Draft **MUST** not be committed to any public location, e.g. the Requirements Repository, because it has not yet been reviewed by the Working Group and could mistakenly contain sensative, private information related to a specific Firebolt distributor. +Note that a Draft **MUST** not be committed to any public location, e.g. the +Requirements Repository, because it has not yet been reviewed by the Working +Group and could mistakenly contain sensative, private information related to +a specific Firebolt distributor. #### 4.8.2. Working Draft -A version of the requirements specification that is approved by the Working Group for feedback and review by individuals not on the Working Group. Individuals are selected for review at the discretion of the Working Group. Working drafts may or may not satisfy all requirements of the feature and should not be used for derivative works. +A version of the requirements specification that is approved by the Working +Group for feedback and review by individuals not on the Working Group. +Individuals are selected for review at the discretion of the Working Group. +Working drafts may or may not satisfy all requirements of the feature and +should not be used for derivative works. -Artifacts: +Artifacts: - Markdown specification in a named feature branch of the Requirements Repository - Working Group members identified - Working Group progress is being tracked via GitHub project in the Requirements Repository #### 4.8.3. Candidate Specification -A version of the requirements specification that is approved by the Working Group for proof-of-concept implementations and peer-review by the larger Community. Candidate Specifications have been through significant review by the Working Group and are ready for feedback from the larger community. +A version of the requirements specification that is approved by the Working +Group for proof-of-concept implementations and peer-review by the larger +Community. Candidate Specifications have been through significant review by +the Working Group and are ready for feedback from the larger community. -Once this is published to the peer group for review, they’ll have two weeks to add their comments, make amendments requests, etc. +Once this is published to the peer group for review, they’ll have two weeks to +add their comments, make amendments requests, etc. -Artifacts: +Artifacts: - Markdown specification in a named feature branch of the Requirements Repository - Domain experts for peer-review identified and notified @@ -154,17 +257,22 @@ Artifacts: - JSON-Schema API changes outlined by the document are in the OpenRPC schemas #### 4.8.4. Candidate Specification Draft -A fork of the current Candidate Specification that has changes requested, but not yet approved, by the Working Group. +A fork of the current Candidate Specification that has changes requested, but +not yet approved, by the Working Group. -Artifacts: +Artifacts: - A Pull Request into the feature branch containing in-progress changes - Previous Candidate Specification does not include changes until approved by W.G. #### 4.8.5. Proposed Specification -A version of the requirements specification that is considered, by the Working Group, to be the final Candidate Specification, and has been submitted to the Advisory Board for final approval. This version may be used for experimental implementations and final peer-review by the larger community. +A version of the requirements specification that is considered, by the Working +Group, to be the final Candidate Specification, and has been submitted to the + Advisory Board for final approval. This version may be used for +experimental implementations and final peer-review by the larger community. + -Artifacts: +Artifacts: - Markdown specification merged into the #proposed branch of the Requirements Repository - A Pull Request into the #next branch of Requirements Repository @@ -172,54 +280,136 @@ Artifacts: - Unit tests for any API changes #### 4.8.6. Specification -An official versioned stage of the requirements specification that is done and will not change until a future version is created. This version may be used for official production implementations. +An official versioned stage of the requirements specification that is done and +will not change until a future version is created. This version may be used +for official production implementations. -Artifacts: +Artifacts: - Markdown specification merged into the #main branch of the Requirements Repository - Spec Review notes and green light from implementation teams of all member organizations with a vested interest in the specification - Status tracking link for any Open Source implementations of the spec, if appropriate ### 4.9. Requirements Repository -A public GitHub repository used to manage the progress of a requirements specification. Requirements Specification **MUST** live in their own repository, and not along side of the code that is implementing them. +A public GitHub repository used to manage the progress of a requirements +specification. Requirements Specification **MUST** live in their own +repository, and not along side of the code that is implementing them. + +The Requirements Repository **MUST** be located at: + + + + + + + + + + -The Requirements Repository **MUST** be located at: -[https://github.com/rdkcentral/firebolt-apis](https://github.com/rdkcentral/firebolt-apis) + + + + + + + + + + + + + + + + + + + + + +[https://github.com/rdkcentral/firebolt-apis](https://github.com/rdkcentral/firebolt-apis) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ### 4.10. Requirements Repository Branching -The Requirements Repository **MUST** have the following branches: +The Requirements Repository **MUST** have the following branches: -| Branch | Purpose | -| ------ | ------- | -| main | For officially approved specifications that have been released under a version. | -| next | For all approved specifications, even those that have not been released under a version. | -| proposed | An experimental branch containing all proposed specifications. | +| Branch | Purpose | +| -------- | ---------------------------------------------------------------------------------------- | +| main | For officially approved specifications that have been released under a version. | +| next | For all approved specifications, even those that have not been released under a version. | +| proposed | An experimental branch containing all proposed specifications. | -Working Drafts and Candidate Specification Drafts **MUST** be housed in a named feature branch in the Requirements Repository (see below). +Working Drafts and Candidate Specification Drafts **MUST** be housed in a named + feature branch in the Requirements Repository (see below). -Branches are merged based on the approval process: +Branches are merged based on the approval process: -![Branching](./images/governance/branching.png) +![Branching](./images/governance/branching.png) ### 4.11. Sanctioned Forks -From time to time an organization with access to the Requirements Repository may want to spearhead a new feature without going through the formal approval process. +From time to time an organization with access to the Requirements Repository +may want to spearhead a new feature without going through the formal approval + process. -In this case the member may submit a request to the Approval Board for a sanctioned fork inside the Requirements Repository, so that research and development can be done on the feature. +In this case the member may submit a request to the Approval Board for a +sanctioned fork inside the Requirements Repository, so that research and +development can be done on the feature. -The Approval Board **MAY** grant or deny the request for a sanctioned fork. +The Approval Board **MAY** grant or deny the request for a sanctioned fork. -After the R&D is complete, the forking organization **MUST** submit the resulting requirements to the formal process and work to have them approved. +After the R&D is complete, the forking organization **MUST** submit the +resulting requirements to the formal process and work to have them approved. -The organization requesting the fork **MUST** be willing to migrate to the approved APIs, which may be different than the API in the fork. +The organization requesting the fork **MUST** be willing to migrate to the +approved APIs, which may be different than the API in the fork. -The Advisory Board, and selected Working Group, **SHOULD** be willing to avoid unnecessary changes to make migration as easy as possible, without sacrificing the integrity of the Firebolt Open-Source Project’s goals. +The Advisory Board, and selected Working Group, **SHOULD** be willing to avoid +unnecessary changes to make migration as easy as possible, without +sacrificing the integrity of the Firebolt Open-Source Project’s goals. ### 4.12. Release Versions -The Advisory Board has ownership of when to do major, minor, and patch releases of the Firebolt Requirements. +The Advisory Board has ownership of when to do major, minor, and patch releases + of the Firebolt Requirements. -Releases **MUST** follow Semantic Versioning. +Releases **MUST** follow Semantic Versioning. -Approved changes are all housed in the next branch until the Advisory Board decides that the next branch warrants an officially released version of the requirements. +Approved changes are all housed in the next branch until the Advisory Board +decides that the next branch warrants an officially released version of the +requirements. -If a feature that requires a major version increment, i.e. a breaking change, is proposed, the Advisory Board may decide to keep it unapproved so that any features requiring a minor version change can be pushed through the process. Management of this is the responsibility of the Advisory Board. +If a feature that requires a major version increment, i.e. a breaking change, +is proposed, the Advisory Board may decide to keep it unapproved so that any +features requiring a minor version change can be pushed through the process. +Management of this is the responsibility of the Advisory Board. diff --git a/requirements/specifications/lifecycle/index.md b/requirements/specifications/lifecycle/index.md index 2447badfe..73e4401f2 100644 --- a/requirements/specifications/lifecycle/index.md +++ b/requirements/specifications/lifecycle/index.md @@ -1,65 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # App Lifecycle Management -Document Status: Working Draft +Document Status: Working Draft -See [Firebolt Requirements Governance](../../governance.md) for more info. +See [Firebolt Requirements Governance](../../governance.md) for more info. -| Contributor | Organization | -| -------------- | -------------- | -| Andrew Bennett | Sky | -| Cody Bonney | Charter | -| Bart Catrysse | Liberty | -| Tim Dibben | Sky | -| Piotr Kobzda | Liberty | -| Jeremy LaCivita | Comcast | -| Ramprasad Lakshminarayana | Sky | -| Kevin Pearson | Comcast | -| Jan Pedersen | Sky | -| Peter Yu | Comcast | +| Contributor | Organization | +| ------------------------- | ------------ | +| Andrew Bennett | Sky | +| Cody Bonney | Charter | +| Bart Catrysse | Liberty | +| Tim Dibben | Sky | +| Piotr Kobzda | Liberty | +| Jeremy LaCivita | Comcast | +| Ramprasad Lakshminarayana | Sky | +| Kevin Pearson | Comcast | +| Jan Pedersen | Sky | +| Peter Yu | Comcast | ## 1. Overview -This document describes the requirements that Firebolt platforms and -Firebolt applications must fulfill when managing App Lifecycles. *App -Lifecycle* refers to the lifecycle of an individual app from the time -it is launched/loaded to the time it is destroyed and all runtime -resources are discarded. +This document describes the requirements that Firebolt platforms and Firebolt +applications must fulfill when managing App Lifecycles. *App Lifecycle* +refers to the lifecycle of an individual app from the time it is +launched/loaded to the time it is destroyed and all runtime resources are +discarded. -*Initializing* an app refers to fetching the initial resources, e.g. the -app-manifest and index.html, and loading them into a container capable -of running the app, e.g. a web browser. +*Initializing* an app refers to fetching the initial resources, e.g. the +app-manifest and index.html, and loading them into a container capable of +running the app, e.g. a web browser. -*Activating* an app refers to the process of getting an app into a state -where it is presented as part of the user-perceptible experience (e.g. -visible, audible, or responding to input). This may include *initializing* -the app first, if needed. For details on presentation, see [App -Presentation](./presentation.md). +*Activating* an app refers to the process of getting an app into a state where +it is presented as part of the user-perceptible experience (e.g. visible, +audible, or responding to input). This may include *initializing* the app +first, if needed. For details on presentation, see [App +Presentation](./presentation.md). -*Closing* an app refers to the process of getting an app out of a state -where it is the primary user experience (e.g not visible, not audible, -and not responding to input). This **does not** involve *destroying* the -app. +*Closing* an app refers to the process of getting an app out of a state where +it is the primary user experience (e.g not visible, not audible, and not +responding to input). This **does not** involve *destroying* the app. -*Suspending* an app refers to reducing the app's memory and CPU usage, -and deallocating its graphics surface so that other apps will have -more resources available. +*Suspending* an app refers to reducing the app's memory and CPU usage, and +deallocating its graphics surface so that other apps will have more resources + available. -*Resuming* an app refers to reallocating its graphics surface and -resuming normal CPU and memory allocations. +*Resuming* an app refers to reallocating its graphics surface and resuming +normal CPU and memory allocations. -*Destroying* an app refers to the process of notifying an app to do any -needed clean up, and then *terminating* it. +*Destroying* an app refers to the process of notifying an app to do any needed +clean up, and then *terminating* it. -*Terminating* an app refers to shutting down the app's container and -reclaiming any memory, CPU, etc. that it was consuming. +*Terminating* an app refers to shutting down the app's container and reclaiming + any memory, CPU, etc. that it was consuming. -*Sleeping* an app refers to putting the app into a state where it does -not use CPU cycles, which allows the platform to optimise memory consumption. +*Sleeping* an app refers to putting the app into a state where it does not use +CPU cycles, which allows the platform to optimise memory consumption. -*Waking* an app refers to copying a Sleeping app back into the -memory space of a compatible process so that it resumes where it left -off. +*Waking* an app refers to copying a Sleeping app back into the memory space of +a compatible process so that it resumes where it left off. - [1. Overview](#1-overview) - [2. Lifecycle States](#2-lifecycle-states) @@ -93,16 +121,46 @@ off. ## 2. Lifecycle States -Firebolt platforms **MUST** support running one or more apps -concurrently. The platform **MUST** manage transition of apps from state -to state. - -A Firebolt app, once running, **MUST** be in one of several states and -**MUST NOT** be in more than one state at a time. - -As an app changes states the platform will invoke specific app-provided transition methods, see [Transitions](#4-lifecycle-state-transitions), for more on this. - -![Lifecycle States](../../images/specifications/lifecycle/lifecycle-states.png) +Firebolt platforms **MUST** support running one or more apps concurrently. The +platform **MUST** manage transition of apps from state to state. + +A Firebolt app, once running, **MUST** be in one of several states and **MUST +NOT** be in more than one state at a time. + +As an app changes states the platform will invoke specific app-provided +transition methods, see [Transitions](#4-lifecycle-state-transitions), for +more on this. + +![Lifecycle States](../../images/specifications/lifecycle/lifecycle-states.png) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | | CPU | RAM | F/S | Net | GFX | SFC | A/V | Description | |--------------|-----|-----|-----|-----|-----|-----|-----|----------------------------------------------------------------------------| @@ -112,152 +170,154 @@ As an app changes states the platform will invoke specific app-provided transiti | Suspended | ↓ | ↓ | ✔ | ✔ | | | | Reduced memory footprint and no access to graphics or A/V. | | Sleeping | | | | | | | | No CPU cycles are given to the app. App may stay in RAM or be stored. | -| | Legend | -| - | ------ | +| | Legend | +| --- | ----------------------- | | CPU | Central Processing Unit | -| RAM | Ramdon Access Memory | -| F/S | File System | -| Net | Network | -| GFX | Graphics rendering | -| SFC | Graphics surface | -| A/V | Audio Video Decoder | -| ↓ | Limited | -| ✔ | Normal access | -| ? | Unknown | +| RAM | Ramdon Access Memory | +| F/S | File System | +| Net | Network | +| GFX | Graphics rendering | +| SFC | Graphics surface | +| A/V | Audio Video Decoder | +| ↓ | Limited | +| ✔ | Normal access | +| ? | Unknown | ### 2.1. Initializing -This is the initial state an app exists from the moment it starts receiving CPU cycles. +This is the initial state an app exists from the moment it starts receiving CPU + cycles. -When an app starts running it **MUST** initialize the Firebolt SDK as quickly as possible -and then wait for the `Application.create()` interface to be called before doing further setup. +When an app starts running it **MUST** initialize the Firebolt SDK as quickly +as possible and then wait for the `Application.create()` interface to be +called before doing further setup. -Apps in this state **MUST NOT** have a graphics surface allocated yet. +Apps in this state **MUST NOT** have a graphics surface allocated yet. -Apps in this state **MUST NOT** be visible. +Apps in this state **MUST NOT** be visible. -Apps in this state **MUST NOT** receive RCU key presses. +Apps in this state **MUST NOT** receive RCU key presses. -Apps in this state **MUST NOT** have access to the audio-video decoder. +Apps in this state **MUST NOT** have access to the audio-video decoder. -Apps in this state **MUST NOT** use the media pipeline. +Apps in this state **MUST NOT** use the media pipeline. -See [Initializing an app](#42-initializing-an-app) for more information. +See [Initializing an app](#42-initializing-an-app) for more information. ### 2.2. Running -This state allows an app to be running and ready to go, but not actively part -of the user-perceptible experience. +This state allows an app to be running and ready to go, but not actively part +of the user-perceptible experience. -Running apps can execute code, but are not [Presented](./presentation.md) to the user, do not receive -any input from RCUs, and cannot use the video decoder. +Running apps can execute code, but are not [Presented](./presentation.md) to +the user, do not receive any input from RCUs, and cannot use the video +decoder. -Apps in this state **MUST** have access to the graphics surface. +Apps in this state **MUST** have access to the graphics surface. -Apps in this state **MAY** have created, allocated a graphics surface -but it will not be made visible by platform compositor. +Apps in this state **MAY** have created, allocated a graphics surface but it +will not be made visible by platform compositor. -Apps in this state **MUST NOT** be visible. +Apps in this state **MUST NOT** be visible. -Apps in this state **MUST NOT** receive RCU key presses. +Apps in this state **MUST NOT** receive RCU key presses. -Apps in this state **MUST NOT** have access to the audio-video decoder. +Apps in this state **MUST NOT** have access to the audio-video decoder. -Apps in this state **MUST NOT** use the media pipeline and the platform -**MUST** tear down any Media Pipeline sessions associated with this app. +Apps in this state **MUST NOT** use the media pipeline and the platform +**MUST** tear down any Media Pipeline sessions associated with this app. ### 2.3. Active -This state allows an app to be presented as part of the user-perceptible -experience. +This state allows an app to be presented as part of the user-perceptible +experience. -To determine if an app is the *primary* experience, e.g. fullscreen, -etc., see [Presentation](./presentation.md). +To determine if an app is the *primary* experience, e.g. fullscreen, etc., see +[Presentation](./presentation.md#3-display). -It is a platform decision as to how many apps may be in this state at -once. +It is a platform decision as to how many apps may be in this state at once. -Apps in this state **MAY** be visible. +Apps in this state **MAY** be visible. -Apps in this state **MAY** receive RCU key presses that they have -permissions for. +Apps in this state **MAY** receive RCU key presses that they have permissions +for. -Apps in this state **MUST** have access to the audio decoder if -they have permission to the `xrn:firebolt:capability:decoder:audio` -capability and the platform has an available software or hardware -decoder. +Apps in this state **MUST** have access to the audio decoder if they have +permission to the `xrn:firebolt:capability:decoder:audio` capability and the +platform has an available software or hardware decoder. -Apps in this state **MUST** have access to the video decoder if -they have permission to the `xrn:firebolt:capability:decoder:video` -capability and the platform has an available software or hardware -decoder. +Apps in this state **MUST** have access to the video decoder if they have +permission to the `xrn:firebolt:capability:decoder:video` capability and the +platform has an available software or hardware decoder. -Apps in this state **MUST** have access to the graphics surface. +Apps in this state **MUST** have access to the graphics surface. -Apps in this state **SHOULD** reduce memory usage, if possible. +Apps in this state **SHOULD** reduce memory usage, if possible. -When an app transitions to this state, the platform **MUST** dispatch -the `Lifecycle.onStateChanged` notification with the current state. +When an app transitions to this state, the platform **MUST** dispatch the +`Lifecycle.onStateChanged` notification with the current state. ### 2.4. Suspended -This state allows an app to remain in memory and consume fewer resources. +This state allows an app to remain in memory and consume fewer resources. -Suspended apps can execute code, but are not [Presented](./presentation.md) to the user, do not receive -any input from RCUs, and cannot use the video decoder. +Suspended apps can execute code, but are not [Presented](./presentation.md) to +the user, do not receive any input from RCUs, and cannot use the video +decoder. -Apps in this state **MUST NOT** have a graphics surface allocated any -longer. It **MUST** have been deallocated in the `suspend()` transition. +Apps in this state **MUST NOT** have a graphics surface allocated any longer. +It **MUST** have been deallocated in the `suspend()` transition. -Apps in this state **MUST NOT** be visible. +Apps in this state **MUST NOT** be visible. -Apps in this state **MUST NOT** receive RCU key presses. +Apps in this state **MUST NOT** receive RCU key presses. -Apps in this state **MUST NOT** have access to the audio-video decoder. +Apps in this state **MUST NOT** have access to the audio-video decoder. -Apps in this state **SHOULD** further reduce memory usage (more so than in the `active` state), if possible. +Apps in this state **SHOULD** further reduce memory usage (more so than in the +`active` state), if possible. -**TODO**:: add all the transition pre-requisites, e.g. Apps **MUST** only enter this state from the `SUSPENDED` state, via the `sleep()` interface. +**TODO**:: add all the transition pre-requisites, e.g. Apps **MUST** only enter + this state from the `SUSPENDED` state, via the `sleep()` interface. ### 2.5. Sleeping -This state allows an app to be copied from memory to local storage and -then terminated to save resources. Subsequently, the app may be copied -back into memory, and resume in the same state. +This state allows an app to be copied from memory to local storage and then +terminated to save resources. Subsequently, the app may be copied back into +memory, and resume in the same state. -*If* a platform does not support the -`xrn:firebolt:capability:lifecycle:sleepable` capability, then the following -requirements **MUST NOT** be fulfilled, even partially. A platform -**MUST NOT** use the APIs documented here to implement an alternate, -non-compliant version of the app sleeping feature. +*If* a platform does not support the +`xrn:firebolt:capability:lifecycle:sleepable` capability, then the following +requirements **MUST NOT** be fulfilled, even partially. A platform **MUST +NOT** use the APIs documented here to implement an alternate, non-compliant +version of the app sleeping feature. -*If* a platform supports the `xrn:firebolt:capability:lifecycle:sleepable` -capability, then the following requirements **MUST** be fulfilled. +*If* a platform supports the `xrn:firebolt:capability:lifecycle:sleepable` +capability, then the following requirements **MUST** be fulfilled. -Apps **MUST** only enter this state from the `SUSPENDED` state, via -the `sleep()` interface. +Apps **MUST** only enter this state from the `SUSPENDED` state, via the +`sleep()` interface. -If a platform supports copying sleeping apps memory out of RAM then: +If a platform supports copying sleeping apps memory out of RAM then: -> The platform **MAY** save the app's memory space at this point, so -> that it may be woken later. -> -> Finally, the app and its container **MAY** be removed from memory -> and have other resources released as well. +> The platform **MAY** save the app's memory space at this point, so that it +> may be woken later. +> +> Finally, the app and its container **MAY** be removed from memory and have +> other resources released as well. ## 3. Getting the current state -The Lifecycle module **MUST** provide a `state` property API that -returns the current lifecycle state of the app. +The Lifecycle module **MUST** provide a `state` property API that returns the +current lifecycle state of the app. -If an app is in a transtition from one state to another, then it -**MUST** be considered in the state *before* the transition until -such time as the app's implementation of the [transition](#4-lifecycle-state-transitions) has returned -and the platfrom has finshed the transition. +If an app is in a transtition from one state to another, then it **MUST** be +considered in the state *before* the transition until such time as the app's +implementation of the [transition](#4-lifecycle-state-transitions) has +returned and the platfrom has finshed the transition. -The `state` API **MUST** have a corresponding `onStateChanged` -notification. +The `state` API **MUST** have a corresponding `onStateChanged` notification. -The `state` API must have one of the following values: +The `state` API must have one of the following values: - `Initializing` - `Running` @@ -265,119 +325,127 @@ The `state` API must have one of the following values: - `Active` - `Sleeping` -Note that the `onStateChanged` notification **MUST** never be dispatched -for the `Sleeping` state since it would not be received anyway. +Note that the `onStateChanged` notification **MUST** never be dispatched for +the `Sleeping` state since it would not be received anyway. ## 4. Lifecycle State Transitions -There are several state transitions where the app and the platform need -to interact to ensure the transition goes smoothly. +There are several state transitions where the app and the platform need to +interact to ensure the transition goes smoothly. -![Lifecycle States](../../images/specifications/lifecycle/lifecycle-transitions.png) +![Lifecycle +States](../../images/specifications/lifecycle/lifecycle-transitions.png) -As an app changes states the platform will invoke specific app-provided transition -methods from the `Application` interface: +As an app changes states the platform will invoke specific app-provided +transition methods from the `Application` interface: -| | Legend | -| - | ------ | -| ↓ | Limited | +| | Legend | +| - | ------------- | +| ↓ | Limited | | ✔ | Normal access | -| | CPU | RAM | Net | GFX | A/V | Description | -|----------------|-----|-----|-----|-----|-----|-------------------------------------------------------------------------------| -| `create()` | ✔ | ✔ | ✔ | ✔ | | Creation of the app, from a Firebolt Lifecycle perspective. | -| `suspend()` | ✔ | ✔ | ✔ | ✔ | | Reduce memory and CPU usage, deallocate graphics surface. | -| `resume()` | ✔ | ✔ | ✔ | ✔ | | graphics surface reallocated, full memory usage and normal CPU cycles. | -| `destroy()` | ✔/↓ | ✔/↓ | ✔ | | | Preprare for the app to be deallocated and removed from execution. CPU & RAM based on previous state. | +| | CPU | RAM | Net | GFX | A/V | Description | +|-------------|-----|-----|-----|-----|-----|-------------------------------------------------------------------------------------------------------| +| `create()` | ✔ | ✔ | ✔ | ✔ | | Creation of the app, from a Firebolt Lifecycle perspective. | +| `suspend()` | ✔ | ✔ | ✔ | ✔ | | Reduce memory and CPU usage, deallocate graphics surface. | +| `resume()` | ✔ | ✔ | ✔ | ✔ | | graphics surface reallocated, full memory usage and normal CPU cycles. | +| `destroy()` | ✔/↓ | ✔/↓ | ✔ | | | Preprare for the app to be deallocated and removed from execution. CPU & RAM based on previous state. | -If an app implements the `Activity` interface, then the following transitions may be invoked: +If an app implements the `Activity` interface, then the following transitions +may be invoked: -| | CPU | RAM | Net | GFX | A/V | Description | -|----------------|-----|-----|-----|-----|-----|-------------------------------------------------------------------------------| -| `activate()` | ✔ | ✔ | ✔ | ✔ | ✔ | App is expected to become a user-perceptible part of the user experience. | -| `deactivate()` | ✔ | ✔ | ✔ | ✔ | ✔ | Must remove any user-perceptible activities and deallocate A/V decoders. | +| | CPU | RAM | Net | GFX | A/V | Description | +|----------------|-----|-----|-----|-----|-----|---------------------------------------------------------------------------| +| `activate()` | ✔ | ✔ | ✔ | ✔ | ✔ | App is expected to become a user-perceptible part of the user experience. | +| `deactivate()` | ✔ | ✔ | ✔ | ✔ | ✔ | Must remove any user-perceptible activities and deallocate A/V decoders. | -Finally, if an app implements the `Sleepable` interface, then the following transistions may be invoked. +Finally, if an app implements the `Sleepable` interface, then the following +transistions may be invoked. -| | CPU | RAM | Net | GFX | A/V | Description | -|----------------|-----|-----|-----|-----|-----|-------------------------------------------------------------------------------| -| `sleep()` | ↓ | ↓ | ✔ | | | Prepare for an extended period with no CPU cycles given to app. | -| `wake()` | ↓ | ↓ | ✔ | | | Cleanup after an extended period with no CPU, e.g. reset timers / network connections. | +| | CPU | RAM | Net | GFX | A/V | Description | +|-----------|-----|-----|-----|-----|-----|----------------------------------------------------------------------------------------| +| `sleep()` | ↓ | ↓ | ✔ | | | Prepare for an extended period with no CPU cycles given to app. | +| `wake()` | ↓ | ↓ | ✔ | | | Cleanup after an extended period with no CPU, e.g. reset timers / network connections. | -All of these transition APIs are blocking, and each one has a platform-configurable timeout that specifies how long the app has to fulfill the method. +All of these transition APIs are blocking, and each one has a +platform-configurable timeout that specifies how long the app has to fulfill +the method. -The platform **MUST** never invoke a transions on an app when that app is already running a transition. +The platform **MUST** never invoke a transions on an app when that app is +already running a transition. -All Firebolt apps **MUST** implement the `Application` interface, `xrn:firebolt:capability:lifecycle:application`. +All Firebolt apps **MUST** implement the `Application` interface, +`xrn:firebolt:capability:lifecycle:application`. -This includes: +This includes: - `Application.create()` - `Application.suspend()` - `Application.resume()` - `Application.destroy()` -By providing an implementation of the -`xrn:firebolt:capability:lifecycle:application` interface, an app can -influence how resources are managed during these state transitions. See [Application Interface](#81-application-interface) for more info. +By providing an implementation of the +`xrn:firebolt:capability:lifecycle:application` interface, an app can +influence how resources are managed during these state transitions. See +[Application Interface](#81-application-interface) for more info. -User-facing apps **MUST** implement the `Activity` interface, `xrn:firebolt:capability:lifecycle:activatible`. +User-facing apps **MUST** implement the `Activity` interface, +`xrn:firebolt:capability:lifecycle:activatible`. -This includes: +This includes: - `Application.activate()` - `Application.deactivate()` - `Application.navigate()` -By providing an implementation of the -`xrn:firebolt:capability:lifecycle:activatible` interface, an app can -influence how resources are managed during these state transitions. See [Activity Interface](#82-activity-interface) for more info. +By providing an implementation of the +`xrn:firebolt:capability:lifecycle:activatible` interface, an app can +influence how resources are managed during these state transitions. See +[Activity Interface](#82-activity-interface) for more info. ### 4.2. Initializing an app -Once an app is loaded it **MUST** be initialized immediately. +Once an app is loaded it **MUST** be initialized immediately. -Initializing consists of three parts: +Initializing consists of three parts: - Registration of the Firebolt Application provider - Any other code that automatically runs within the app executable - Invoking the app's Application.create() method -If an app does not provide the `xrn:firebolt:capability:lifecycle:application` -capability within `initializeTimeout` milliseconds, then the platform **MUST** -terminate the app. +If an app does not provide the `xrn:firebolt:capability:lifecycle:application` +capability within `initializeTimeout` milliseconds, then the platform +**MUST** terminate the app. -Otherwise, the platform **MUST** call the app's implementation of -`Application.create()`: +Otherwise, the platform **MUST** call the app's implementation of +`Application.create()`: -> The platform **MUST** dispatch the `Lifecycle.onRequestCreate` -> notification to the app, and wait for `appCreateTimeout` milliseconds -> for either a `Lifecycle.createResult` or `Lifecycle.createError` call in -> response. -> -> Once the platform receives the `createResult` call, then the app -> is considered to have any important Firebolt notifications set up -> and is ready to be activated and presented to the user. -> -> If the app times out or makes a `createError` call, then the app -> **MUST** be immediately terminated by the platform. +> The platform **MUST** dispatch the `Lifecycle.onRequestCreate` notification +> to the app, and wait for `appCreateTimeout` milliseconds for either a +> `Lifecycle.createResult` or `Lifecycle.createError` call in response. +> +> Once the platform receives the `createResult` call, then the app is +> considered to have any important Firebolt notifications set up and is ready +> to be activated and presented to the user. +> +> If the app times out or makes a `createError` call, then the app **MUST** be +> immediately terminated by the platform. -Apps **SHOULD** set up any Firebolt event listeners either before calling -`Lifecycle.provide` or during `create()`, since the platform will wait until -the app is ready before dispatching many critical events such as Lifecycle -and Presentation events. +Apps **SHOULD** set up any Firebolt event listeners either before calling +`Lifecycle.provide` or during `create()`, since the platform will wait until +the app is ready before dispatching many critical events such as Lifecycle +and Presentation events. -Apps **SHOULD** acquire any important authentication needed for the -app to function during initialization. +Apps **SHOULD** acquire any important authentication needed for the app to +function during initialization. -Apps **MAY** load a limited set of global display resources, e.g. a -global style sheet or a logo used throughout the experience, during -initialization. +Apps **MAY** load a limited set of global display resources, e.g. a global +style sheet or a logo used throughout the experience, during initialization. -During the `create()` transition, apps **MUST** inspect the `params` -parameter for [Parameters](#7-launch-parameters) and prepare to fulfill the -provided launch configuration. +During the `create()` transition, apps **MUST** inspect the `params` parameter +for [Parameters](#7-launch-parameters) and prepare to fulfill the provided +launch configuration. -Example Launch Parameters: +Example Launch Parameters: ```json { @@ -387,315 +455,322 @@ Example Launch Parameters: "limitAdTracking": true } } -``` +``` -**TODO**: discuss this ^^ +**TODO**: discuss this ^^ -Once the `create` method returns the app **MUST** be immediately transitioned to -the `RUNNING` state. +Once the `create` method returns the app **MUST** be immediately transitioned +to the `RUNNING` state. ### 4.3. Activating an app -Activating an app transitions it to the `ACTIVE` state so that it becomes part -of the user's experience. - -Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:activate` capability **MUST** implement `Activity.activate()`. - -The platform may activate apps for any number of reasons that are out of -scope for this document. - -To activate an app, platforms **MUST** use the following process. - -If the app is already in the `ACTIVE` state, then it is already -activated and there is no need to do anything else. The platform **MUST -NOT** dispatch any *additional* lifecycle notifications when attempting -to activate an app that is already in the active state and the -remainder of this section does not apply. - -If the app is not loaded, then the platform **MUST** [load](undefined) it first. - -If the app is not initialized, the platform **MUST** [initialize](#42-initializing-an-app) it first. - -If the app is suspended, then it **MUST** be [resumed](#46-resuming-an-app) first. - -At this point, the app **MUST** be in the `RUNNING` state. - -If an app provides the `xrn:firebolt:capability:lifecycle:activatible` -capability, then the platform **MUST** call the app's implementation of -`Activity.activate()`: - -> The platform **MUST** dispatch the `Lifecycle.onRequestActivate` -> notification to the app, and wait for `appActivateTimeout` milliseconds -> for either a `Lifecycle.activateResult` or `Lifecycle.activateError` -> call in response. -> -> The `onRequestActivate` call **MUST** include a `NavigationIntent`. -> -> If the app sends a `Lifecycle.activateFocus` request and has -> permission to use the `xrn:firebolt:capability:lifecycle:loading-screen` -> capability, then the platform **SHOULD** give the app focus and set -> the [Presentation display](./presentation.md) to one of the visible modes, -> so that the app may display a custom loading screen. -> -> Once the platform receives the `activateResult` call, then the app -> may be moved to the `ACTIVE` state. -> -> If the app times out or makes an `activateError` call, then the app -> **MUST** be terminated. - -During the `activate()` transition, the app **MUST** inspect the `intent` -parameter and prepare to fulfill a specific [Navigation Intent](../intents/navigation.md) for -this activation which may include: +Activating an app transitions it to the `ACTIVE` state so that it becomes part +of the user's experience. + +Firebolt apps that have permission to use the +`xrn:firebolt:capability:lifecycle:activate` capability **MUST** implement +`Activity.activate()`. + +The platform may activate apps for any number of reasons that are out of scope +for this document. + +To activate an app, platforms **MUST** use the following process. + +If the app is already in the `ACTIVE` state, then it is already activated and +there is no need to do anything else. The platform **MUST NOT** dispatch any +*additional* lifecycle notifications when attempting to activate an app that +is already in the active state and the remainder of this section does not +apply. + +If the app is not loaded, then the platform **MUST** [load](undefined) it +first. + +If the app is not initialized, the platform **MUST** +[initialize](#42-initializing-an-app) it first. + +If the app is suspended, then it **MUST** be [resumed](#46-resuming-an-app) +first. + +At this point, the app **MUST** be in the `RUNNING` state. + +If an app provides the `xrn:firebolt:capability:lifecycle:activatible` +capability, then the platform **MUST** call the app's implementation of +`Activity.activate()`: + +> The platform **MUST** dispatch the `Lifecycle.onRequestActivate` notification +> to the app, and wait for `appActivateTimeout` milliseconds for either a +> `Lifecycle.activateResult` or `Lifecycle.activateError` call in response. +> +> The `onRequestActivate` call **MUST** include a `NavigationIntent`. +> +> If the app sends a `Lifecycle.activateFocus` request and has permission to +> use the `xrn:firebolt:capability:lifecycle:loading-screen` capability, then +> the platform **SHOULD** give the app focus and set the [Presentation +> display](./presentation.md) to one of the visible modes, so that the app may +> display a custom loading screen. +> +> Once the platform receives the `activateResult` call, then the app may be +> moved to the `ACTIVE` state. +> +> If the app times out or makes an `activateError` call, then the app **MUST** +> be terminated. + +During the `activate()` transition, the app **MUST** inspect the `intent` +parameter and prepare to fulfill a specific [Navigation +Intent](../intents/navigation.md) for this activation which may include: - Loading any metadata needed to display the user's intended content. - Performing any entitlement checks to decide whether to display a player or a purchase flow - Any other steps necesary to present content to the user quickly -The platform will display a loading screen for the entire duration of -the `activate()` callback, and apps **SHOULD** do whatever is necessary -to present the user with content that fulfills the `intent` without -additional loading screens in the app's UX. +The platform will display a loading screen for the entire duration of the +`activate()` callback, and apps **SHOULD** do whatever is necessary to +present the user with content that fulfills the `intent` without additional +loading screens in the app's UX. -**TODO**: Discuss ^^ +**TODO**: Discuss ^^ ### 4.4. Deactivating an app -Closing an app transitions it to the `RUNNING` state, so that it is no -longer part of the user's experience. +Closing an app transitions it to the `RUNNING` state, so that it is no longer +part of the user's experience. -Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:activate` capability **MUST** implement `Activity.deactivate()`. +Firebolt apps that have permission to use the +`xrn:firebolt:capability:lifecycle:activate` capability **MUST** implement +`Activity.deactivate()`. -The platform may close apps for any number of reasons that are out of -scope for this document. +The platform may close apps for any number of reasons that are out of scope for + this document. -Apps **MAY** request to be closed, via the `Lifecycle.close()` API method. +Apps **MAY** request to be closed, via the `Lifecycle.close()` API method. -To close an app, platforms **MUST** use the following process. +To close an app, platforms **MUST** use the following process. -If an app is already in the `RUNNING`, `SUSPENDED`, or `SLEEPING` state, then it is already closed -and there is no need to do anything else. The platform **MUST NOT** -dispatch any *additional* lifecycle notifications when attempting to -close an app that is already in the `RUNNING` state and the remainder of -this section does not apply. +If an app is already in the `RUNNING`, `SUSPENDED`, or `SLEEPING` state, then +it is already closed and there is no need to do anything else. The platform +**MUST NOT** dispatch any *additional* lifecycle notifications when +attempting to close an app that is already in the `RUNNING` state and the +remainder of this section does not apply. -**TODO**: list out all possible transition "interuptions" and make sure they are described in this doc. +**TODO**: list out all possible transition "interuptions" and make sure they +are described in this doc. -If an app is in the `initializing` state, then it is not +If an app is in the `initializing` state, then it is not -If an app is already performing a `deactivate()` transition, the platform -**MUST** ignore the new attempt to close the app, allow the pending -closure to complete, and the remainder of this section does not apply. +If an app is already performing a `deactivate()` transition, the platform +**MUST** ignore the new attempt to close the app, allow the pending closure +to complete, and the remainder of this section does not apply. -If an app is already performing an `activate()` transition, the platform -**MUST** wait for the activate call to succeed or fail and then skip the -remaining [activation steps](#43-activating-an-app). +If an app is already performing an `activate()` transition, the platform +**MUST** wait for the activate call to succeed or fail and then skip the +remaining [activation steps](#43-activating-an-app). -If an app is currently [initializing](#42-initializing-an-app), the -platform **MUST** wait for initialization to succeed or fail and then skip -any activation that may have been pending. +If an app is currently [initializing](#42-initializing-an-app), the platform +**MUST** wait for initialization to succeed or fail and then skip any +activation that may have been pending. -If an app is currently in a [destroy](#49-destroying-an-app) transition then -the app cannot be closed and the platform **MUST NOT** close it, and the -remainder of this section does not apply. +If an app is currently in a [destroy](#49-destroying-an-app) transition then +the app cannot be closed and the platform **MUST NOT** close it, and the +remainder of this section does not apply. -At this point, the app **MUST** be in the `ACTIVE` state. +At this point, the app **MUST** be in the `ACTIVE` state. -If an app provides the `xrn:firebolt:capability:lifecycle:activatible` -capability, then the platform **MUST** call the app's implementation of -`Activity.deactivate()`: +If an app provides the `xrn:firebolt:capability:lifecycle:activatible` +capability, then the platform **MUST** call the app's implementation of +`Activity.deactivate()`: -> The platform **MUST** dispatch the `Lifecycle.onRequestDeactivate` -> notification to the app, and wait for `appDeactivateTimeout` milliseconds -> for either a `Lifecycle.deactivateResult` or `Lifecycle.deactivateError` -> call in response. -> -> Once the platform receives the `deactivateResult` call, then the app -> may be moved to the `RUNNING` state. -> -> If the app times out or makes a `deactivateError` call, then the app -> **MUST** be terminated. +> The platform **MUST** dispatch the `Lifecycle.onRequestDeactivate` +> notification to the app, and wait for `appDeactivateTimeout` milliseconds for +> either a `Lifecycle.deactivateResult` or `Lifecycle.deactivateError` call in +> response. +> +> Once the platform receives the `deactivateResult` call, then the app may be +> moved to the `RUNNING` state. +> +> If the app times out or makes a `deactivateError` call, then the app +> **MUST** be terminated. -During the `deactivate()` transition, the app **MUST** deallocate any -A/V decoders. +During the `deactivate()` transition, the app **MUST** deallocate any A/V +decoders. -The platform **MAY** begin to transition the app out of view as soon as -`deactivate()` is called. +The platform **MAY** begin to transition the app out of view as soon as +`deactivate()` is called. ### 4.5. Suspending an app -Suspending an app transitions it to the `SUSPENDED` state, where it is -no longer allowed to use graphics composition, and is expected to consume -less CPU and RAM. +Suspending an app transitions it to the `SUSPENDED` state, where it is no +longer allowed to use graphics composition, and is expected to consume less +CPU and RAM. -The platform may suspend apps in order to free up memory, or for any -number of reasons that are out of scope for this document. However, it -is the platform's decision to suspend an app, not the app itself. +The platform may suspend apps in order to free up memory, or for any number of +reasons that are out of scope for this document. However, it is the +platform's decision to suspend an app, not the app itself. -To suspend an app, platforms **MUST** use the following process. +To suspend an app, platforms **MUST** use the following process. -If an app is in the `ACTIVE` state then it cannot yet be suspended, and -**MUST** be deactivated first. +If an app is in the `ACTIVE` state then it cannot yet be suspended, and +**MUST** be deactivated first. -If an app is in the `SLEEPING` state then it cannot be suspended and there -is no need to do anything else. The platform **MUST NOT** dispatch any -*additional* lifecycle notifications when attempting to suspend an app -that is already in the `SLEEPING` state and the remainder of this section -does not apply. +If an app is in the `SLEEPING` state then it cannot be suspended and there is +no need to do anything else. The platform **MUST NOT** dispatch any +*additional* lifecycle notifications when attempting to suspend an app that +is already in the `SLEEPING` state and the remainder of this section does not + apply. -If an app is already in the `SUSPENDED` state, then it is already -suspended and there is no need to do anything else. The platform **MUST -NOT** dispatch any *additional* lifecycle notifications when attempting -to suspend an app that is already in the suspended state and the -remainder of this section does not apply. +If an app is already in the `SUSPENDED` state, then it is already suspended and + there is no need to do anything else. The platform **MUST NOT** dispatch +any *additional* lifecycle notifications when attempting to suspend an app +that is already in the suspended state and the remainder of this section +does not apply. -If the app is not loaded, or is not in the `RUNNING` state, then it -cannot be suspended, and the remainder of this section does not need to -happen. +If the app is not loaded, or is not in the `RUNNING` state, then it cannot be +suspended, and the remainder of this section does not need to happen. -At this point, the app **MUST** be in the `RUNNING` state. +At this point, the app **MUST** be in the `RUNNING` state. -Since every app **MUST** provide the `xrn:firebolt:capability:lifecycle:application` -capability, the platform **MUST** call the app's implementation of -`Application.suspend()`: +Since every app **MUST** provide the +`xrn:firebolt:capability:lifecycle:application` capability, the platform +**MUST** call the app's implementation of `Application.suspend()`: -> The platform **MUST** dispatch the `Lifecycle.onRequestSuspend` -> notification to the app, and wait for `appSuspendTimeout` milliseconds -> for either a `Lifecycle.suspendResult` or `Lifecycle.suspendError` -> call in response. -> -> Once the platform receives the `suspendResult` call, then the app -> may be moved to the `SUSPENDED` state. -> -> If the app times out or makes a `suspendError` call, then the app -> **MUST** be [destroyed](#49-destroying-an-app). +> The platform **MUST** dispatch the `Lifecycle.onRequestSuspend` notification +> to the app, and wait for `appSuspendTimeout` milliseconds for either a +> `Lifecycle.suspendResult` or `Lifecycle.suspendError` call in response. +> +> Once the platform receives the `suspendResult` call, then the app may be +> moved to the `SUSPENDED` state. +> +> If the app times out or makes a `suspendError` call, then the app **MUST** +> be [destroyed](#49-destroying-an-app). -During the `suspend()` transition, the app: +During the `suspend()` transition, the app: -> **MUST** deallocate any graphics surface. -> -> **SHOULD** reduce memory usage, if possible. +> **MUST** deallocate any graphics surface. +> +> **SHOULD** reduce memory usage, if possible. ### 4.6. Resuming an app -Resuming an app allows it to reallocate graphics composition and -reload any resources it might have deallocated during `suspend()`. +Resuming an app allows it to reallocate graphics composition and reload any +resources it might have deallocated during `suspend()`. -The platform may resume apps so they can access more resources or -in preperation to activate them. +The platform may resume apps so they can access more resources or in +preperation to activate them. -To resume an app, platforms **MUST** use the following process. +To resume an app, platforms **MUST** use the following process. -If an app is not in the `SUSPENDED` state, then it cannot be resumed -and there is no need to do anything else. The platform **MUST NOT** -dispatch any *additional* lifecycle notifications when attempting to -resume an app that is not in the `SUSPENDED` state and the remainder of -this section does not apply. +If an app is not in the `SUSPENDED` state, then it cannot be resumed and there +is no need to do anything else. The platform **MUST NOT** dispatch any +*additional* lifecycle notifications when attempting to resume an app that is + not in the `SUSPENDED` state and the remainder of this section does not +apply. -At this point, the app **MUST** be in the `SUSPENDED` state. +At this point, the app **MUST** be in the `SUSPENDED` state. -Next, the platform **MUST** remove any restrictions on access the graphics -compositor. +Next, the platform **MUST** remove any restrictions on access the graphics +compositor. -Suspended apps **MUST** provide the `xrn:firebolt:capability:lifecycle:application` -capability, so the platform **MUST** call the app's implementation of -`Application.resume()`: +Suspended apps **MUST** provide the +`xrn:firebolt:capability:lifecycle:application` capability, so the platform +**MUST** call the app's implementation of `Application.resume()`: -The platform **MUST** dispatch the `Lifecycle.onRequestResume` -notification to the app, and wait for `appResumeTimeout` milliseconds -for either a `Lifecycle.resumeResult` or `Lifecycle.resumeError` -call in response. +The platform **MUST** dispatch the `Lifecycle.onRequestResume` notification to +the app, and wait for `appResumeTimeout` milliseconds for either a +`Lifecycle.resumeResult` or `Lifecycle.resumeError` call in response. -Once the platform receives the `resumeResult` call, then the app -may be moved to the `RUNNING` state. +Once the platform receives the `resumeResult` call, then the app may be moved +to the `RUNNING` state. -If the app times out or makes a `resumeError` call, then the app -**MUST** be terminated. +If the app times out or makes a `resumeError` call, then the app **MUST** be +terminated. -During the `resume()` transition, apps **SHOULD** reallocate graphics -composition and other necessary resources. +During the `resume()` transition, apps **SHOULD** reallocate graphics +composition and other necessary resources. ### 4.7. Putting an app to sleep -TBD +TBD -Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:sleepable` capability **MUST** implement `Sleepable.sleep()`. +Firebolt apps that have permission to use the +`xrn:firebolt:capability:lifecycle:sleepable` capability **MUST** implement +`Sleepable.sleep()`. -TODO: if you don't call provide, we won't do this. +TODO: if you don't call provide, we won't do this. ### 4.8. Waking an app from sleep -TBD +TBD -Firebolt apps that have permission to use the `xrn:firebolt:capability:lifecycle:sleepable` capability **MUST** implement `Sleepable.wake()`. +Firebolt apps that have permission to use the +`xrn:firebolt:capability:lifecycle:sleepable` capability **MUST** implement +`Sleepable.wake()`. ### 4.9. Destroying an app -Destroying an app transitions it out of memory, so that it is no longer -using resources on the device. +Destroying an app transitions it out of memory, so that it is no longer using +resources on the device. -The platform may destroy apps for any number of reasons that are out of -scope for this document. +The platform may destroy apps for any number of reasons that are out of scope +for this document. -To destroy an app, platforms **MUST** use the following process. +To destroy an app, platforms **MUST** use the following process. -If an app is not in the `RUNNING` state, then it cannot be destroyed and -there is no need to do anything else. The platform **MUST NOT** dispatch -any *additional* lifecycle notifications when attempting to destroy an -app that is not in the `RUNNING` state and the remainder of this section -does not need to happen. +If an app is not in the `RUNNING` state, then it cannot be destroyed and there +is no need to do anything else. The platform **MUST NOT** dispatch any +*additional* lifecycle notifications when attempting to destroy an app that +is not in the `RUNNING` state and the remainder of this section does not need + to happen. -At this point, the app **MUST** be in the `RUNNING` state. +At this point, the app **MUST** be in the `RUNNING` state. -Since every app **MUST** provide the `xrn:firebolt:capability:lifecycle:application` -capability, the platform **MUST** call the app's implementation of -`Application.destroy()`: +Since every app **MUST** provide the +`xrn:firebolt:capability:lifecycle:application` capability, the platform +**MUST** call the app's implementation of `Application.destroy()`: -> The platform **MUST** dispatch the `Lifecycle.onRequestDestroy` -> notification to the app, and wait for `appDestroyTimeout` milliseconds -> for either a `Lifecycle.destroyResult` or `Lifecycle.destroyError` -> call in response. -> -> Once the platform receives the `destroyResult` call, then the platform -> may proceed with app destroying. -> -> If the app times out or makes an `destroyError` call, then the app -> **MUST** be terminated. +> The platform **MUST** dispatch the `Lifecycle.onRequestDestroy` notification +> to the app, and wait for `appDestroyTimeout` milliseconds for either a +> `Lifecycle.destroyResult` or `Lifecycle.destroyError` call in response. +> +> Once the platform receives the `destroyResult` call, then the platform may +> proceed with app destroying. +> +> If the app times out or makes an `destroyError` call, then the app **MUST** +> be terminated. ### 4.10. Terminating an app -Terminating an app removes it from memory without dispatching any state -changes. +Terminating an app removes it from memory without dispatching any state +changes. -The platform **SHOULD** terminate apps when one of the transitions outlined -here fails for some reason, or if an app becomes non-responsesive. +The platform **SHOULD** terminate apps when one of the transitions outlined +here fails for some reason, or if an app becomes non-responsesive. -Terminating an app results in removing it from memory and all resources -held by the app and it's container being freed up. +Terminating an app results in removing it from memory and all resources held by + the app and it's container being freed up. -Platforms **MAY** terminate an app when needed but **SHOULD NOT** do -this in place of graceful [destroying](#49-destroying-an-app). +Platforms **MAY** terminate an app when needed but **SHOULD NOT** do this in +place of graceful [destroying](#49-destroying-an-app). ## 6. Activity Navigation -Typically navigation is handled either when the app is activated, via -the `intent` parameter of the `activate` method, or by internal input -within the app. +Typically navigation is handled either when the app is activated, via the +`intent` parameter of the `activate` method, or by internal input within the +app. -There are other times when the platform needs to inform an app of a user's -intent to navigate when the app is already `ACTIVE`, e.g. when a voice -command is executed or a soft remote sends a message while the app is in -focus. +There are other times when the platform needs to inform an app of a user's +intent to navigate when the app is already `ACTIVE`, e.g. when a voice +command is executed or a soft remote sends a message while the app is in +focus. -In these cases, the platform **MUST** call the `Activity.navigate` method -of the App, and pass the `intent`. +In these cases, the platform **MUST** call the `Activity.navigate` method of +the App, and pass the `intent`. -Within the `navigate()` method, the app **MUST** inspect the `intent` -parameter and prepare to fulfill a specific [Navigation Intent](../intents/navigation.md) for -the app, which may include: +Within the `navigate()` method, the app **MUST** inspect the `intent` parameter + and prepare to fulfill a specific [Navigation +Intent](../intents/navigation.md) for the app, which may include: - Loading any metadata needed to display the user's intended content. - Performing any entitlement checks to decide whether to display a player or a purchase flow - Any other steps necesary to present content to the user quickly ## 7. Launch Parameters -The `LaunchParameters` type is an object with the following properties: +The `LaunchParameters` type is an object with the following properties: ```typescript type Parameters = { @@ -705,28 +780,31 @@ type Parameters = { limitAdTracking: boolean } } -``` +``` -// Parameters.initialization() +// Parameters.initialization() - suspended after app restart - suspended after power on - foreground after app start -^^^ need to dicuss what we need in here, and also what to do w/ US-centric stuff like 'limitAdTracking' +^^^ need to dicuss what we need in here, and also what to do w/ US-centric +stuff like 'limitAdTracking' ## 8. Core SDK APIs -The following APIs are exposed by the Firebolt Core SDK. +The following APIs are exposed by the Firebolt Core SDK. ### 8.1. Application Interface -The `Application` interface is implemented by Apps to provide resource management around memory as an Application moves through the core lifecycle states: +The `Application` interface is implemented by Apps to provide resource +management around memory as an Application moves through the core lifecycle +states: - `INITIALIZING` - `RUNNING` - `SUSPENDED` -All apps **MUST** implement the Application interface. +All apps **MUST** implement the Application interface. ```typescript interface Application { @@ -735,19 +813,20 @@ interface Application { function resume(): Promise; function destroy(): Promsie; } -``` +``` -| Method | Description | -| -------- | ----------- | -| `create()` | Called when the platform is ready to create the lifecycle session for the app. Only called only once, during the `INITIALIZING` state. | +| Method | Description | +| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `create()` | Called when the platform is ready to create the lifecycle session for the app. Only called only once, during the `INITIALIZING` state. | | `suspend()` | Called when the platform requires the app to deallocate its graphics surface and reduce memory as much as possible. This may be called anytime the app is in the `RUNNING` state. | -| `resume()` | Called when the platform wants the app to reallocate its graphics surface and prepare to be potentially used. | -| `destroy()` | Called when the platform is ready to end the lifecycle session for the app. Only called once. | +| `resume()` | Called when the platform wants the app to reallocate its graphics surface and prepare to be potentially used. | +| `destroy()` | Called when the platform is ready to end the lifecycle session for the app. Only called once. | ### 8.2. Activity Interface -The `Activity` interface is implemented by Apps that provide user perceptible experiences, e.g. visible, audible, or user input. +The `Activity` interface is implemented by Apps that provide user perceptible +experiences, e.g. visible, audible, or user input. -These types of apps require additional resource management +These types of apps require additional resource management ```typescript interface Activity { @@ -755,7 +834,7 @@ interface Activity { function deactivate(): Promise; function navigate(intent: NavigationIntent): Promise; } -``` +``` | Method | Description | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | @@ -764,25 +843,27 @@ interface Activity { | `navigate()` | Called when an app is already `ACTIVE` and the platform wants the app to navigate to a new [Navigation Intent](../intents/navigation.md) | ### 8.3. Sleepable Interface -The `Sleepable` interface is implemented by Apps that are able to handle being put to sleep and then woken at a later point in time. +The `Sleepable` interface is implemented by Apps that are able to handle being +put to sleep and then woken at a later point in time. -These types of apps require additional resource management to reestablish network connections and may also require additional thread safety checks. +These types of apps require additional resource management to reestablish +network connections and may also require additional thread safety checks. ```typescript interface Sleepable { function sleep(): Promise; function wake(): Promise; } -``` +``` -| Method | Description | -| -------- | ----------- | -| `sleep()` | Called when the platform is ready to move the app into the `SLEEPING` state where it will no longer have access to the CPU. | -| `wake()` | Called when the platform is ready to move the app out of the `SLEEPING` state and into `SUSPENDED`. Network connections should be reestablished here. | +| Method | Description | +| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sleep()` | Called when the platform is ready to move the app into the `SLEEPING` state where it will no longer have access to the CPU. | +| `wake()` | Called when the platform is ready to move the app out of the `SLEEPING` state and into `SUSPENDED`. Network connections should be reestablished here. | ### 8.4. Example App -Example: +Example: ```typescript import { Lifecycle } from '@firebolt-js/sdk' @@ -833,62 +914,62 @@ Lifecycle.provide([ "xrn:firebolt:capability:lifecycle:application", "xrn:firebolt:capability:lifecycle:activatible" ], new ExampleApplication()) -``` +``` -**NOTE**: we need to support passing an array of capabilities for a single class. +**NOTE**: we need to support passing an array of capabilities for a single +class. -See the [Firebolt API -Documentation](https://developer.comcast.com/firebolt/core/sdk/latest/api/) -for details around syntax, etc. +See the [Firebolt API +Documentation](https://developer.comcast.com/firebolt/core/sdk/latest/api/) +for details around syntax, etc. ### 8.5. Ready -The Lifecycle.ready() API allows an app to notify the platform that it -is initialized and ready to be displayed to the end user. This method -**MUST NOT** be called more than once. +The Lifecycle.ready() API allows an app to notify the platform that it is +initialized and ready to be displayed to the end user. This method **MUST +NOT** be called more than once. ### 8.6. Close -The Lifecycle.close() API allows an app to request that it be closed by -the platform. +The Lifecycle.close() API allows an app to request that it be closed by the +platform. -This method requires a reason parameter, which tells the platform why -the app is requesting to be closed: +This method requires a reason parameter, which tells the platform why the app +is requesting to be closed: | Reason | Description | -|------------------------------------|------------------------------------| +|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | CloseReason.REMOTE_BUTTON | The user pressed the back or last button on the RCU and the App has determined it is at the top of it's navigation stack and should go back to the platform home screen. | | CloseReason.USER_EXIT | The user selected an exit control exposed by the app's UI. | -| CloseReason.ERROR | The app is experiencing unrecoverable issues and needs to be closed and destroyed. | +| CloseReason.ERROR | The app is experiencing unrecoverable issues and needs to be closed and destroyed. | -Platforms generally **SHOULD** respect this call and move the app to the -running state, but there may be edge cases where this is not possible, -e.g. the app is considered to be the default experience for the device, -and closing it would leave no other UX present. +Platforms generally **SHOULD** respect this call and move the app to the +running state, but there may be edge cases where this is not possible, e.g. +the app is considered to be the default experience for the device, and +closing it would leave no other UX present. -When the request to close is not respected, the Lifecycle.close() method -**MUST** return an error. +When the request to close is not respected, the Lifecycle.close() method +**MUST** return an error. -Platforms **MAY** prioritize apps to be destroyed based on the reason -provided. For example, apps closed due to the RCU are less likely to be -destroyed since it may be an accidental RCU press, whereas an explicit -user exit is more likely to be intentional. +Platforms **MAY** prioritize apps to be destroyed based on the reason provided. + For example, apps closed due to the RCU are less likely to be destroyed +since it may be an accidental RCU press, whereas an explicit user exit is +more likely to be intentional. ### 8.7. State -The Lifecycle.state() method provides convenient access to the current -state, and is implemented by the Core SDK listening to all state -notifications. This method **MUST NOT** be asynchronous. +The Lifecycle.state() method provides convenient access to the current state, +and is implemented by the Core SDK listening to all state notifications. This + method **MUST NOT** be asynchronous. ## 9. Lifecycle Configuration -In order to enable Firebolt Certification of a device's Lifecycle -Management features, the device **MUST** support the following -configuration options, so that the Firebolt Certification Test Suite -knows which optional conditions to test for, and for how long to wait -for state transitions. +In order to enable Firebolt Certification of a device's Lifecycle Management +features, the device **MUST** support the following configuration options, so + that the Firebolt Certification Test Suite knows which optional conditions +to test for, and for how long to wait for state transitions. -The LifecyclePolicy fields are: +The LifecyclePolicy fields are: | Field | Type | Required | Description | |----------------------|--------|----------|--------------------------------------------------------------------------------------------------------------------------| diff --git a/requirements/specifications/lifecycle/presentation.md b/requirements/specifications/lifecycle/presentation.md index 65c7abfc1..c752f7098 100644 --- a/requirements/specifications/lifecycle/presentation.md +++ b/requirements/specifications/lifecycle/presentation.md @@ -1,24 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # App Presentation -need to write this up... +need to write this up... -Document Status: Working Draft +Document Status: Working Draft -See [Firebolt Requirements Governance](../../governance.md) for more info. +See [Firebolt Requirements Governance](../../governance.md) for more info. -| Contributor | Organization | -| -------------- | -------------- | -| Andrew Bennet | Sky | -| Cody Bonney | Charter | -| Bart Catrysse | Liberty | -| Tim Dibben | Sky | -| Jeremy LaCivita | Comcast | -| Ramprasad Lakshminarayana | Sky | -| Kevin Pearson | Comcast | -| Peter Yu | Comcast | +| Contributor | Organization | +| ------------------------- | ------------ | +| Andrew Bennet | Sky | +| Cody Bonney | Charter | +| Bart Catrysse | Liberty | +| Tim Dibben | Sky | +| Jeremy LaCivita | Comcast | +| Ramprasad Lakshminarayana | Sky | +| Kevin Pearson | Comcast | +| Peter Yu | Comcast | ## 1. Overview -TBD... +TBD... - [1. Overview](#1-overview) - [2. Focus](#2-focus) @@ -32,24 +64,26 @@ TBD... ## 2. Focus -The `Presentation` module **MUST** have a `focus` boolean property that returns whether or not the app has input, e.g. RCU, focus. +The `Presentation` module **MUST** have a `focus` boolean property that returns + whether or not the app has input, e.g. RCU, focus. -As a property, this API also has an `onFocusChanged` notification. +As a property, this API also has an `onFocusChanged` notification. ## 3. Display -The `Presentation` module **MUST** have a `display` string property that returns one of the following values: +The `Presentation` module **MUST** have a `display` string property that +returns one of the following values: -| Value | Description | -|-------|-------------| -| `fullscreen` | The app is displayed such that the dimensions fill the entire screen | +| Value | Description | +|--------------|-------------------------------------------------------------------------------------------------------------------------| +| `fullscreen` | The app is displayed such that the dimensions fill the entire screen | | `offscreen` | The app is has it's graphics surface attached, but not displayed on the screen at the moment, e.g. scrolled out of view | -| `scaled` | The app is displayed at a size smaller than the entire screen but at least 25% of the width or height | -| `thumbnail` | The app is displayed at a size smaller than 25% of the width or height of the entire screen | -| `loading` | The platform is displaying a loading screen while the app prepares to be activated | -| `none` | The app does not have it's graphics surface attached to the screen | +| `scaled` | The app is displayed at a size smaller than the entire screen but at least 25% of the width or height | +| `thumbnail` | The app is displayed at a size smaller than 25% of the width or height of the entire screen | +| `loading` | The platform is displaying a loading screen while the app prepares to be activated | +| `none` | The app does not have it's graphics surface attached to the screen | ### 3.1. Display vs Lifecycle -Each Lifecycle state only supports certain display states: +Each Lifecycle state only supports certain display states: | Lifecycle | Supported Displays | |----------------|--------------------------------------------------| @@ -59,63 +93,74 @@ Each Lifecycle state only supports certain display states: | `suspended` | `none`, `loading` | | `sleeping` | `none`, `loading` | -See [Picture-in-picture](#6-picture-in-picture-video) and [Background Audio](#5-background-audio) for exceptions to this. +See [Picture-in-picture](#6-picture-in-picture-video) and [Background +Audio](#5-background-audio) for exceptions to this. ## 4. Overlay -The `Presentation` module **MUST** have an `overlay` string property that returns one of the following values: +The `Presentation` module **MUST** have an `overlay` string property that +returns one of the following values: -| Value | Description | -|-------|-------------| -| `icon` | There is an informative icon, e.g. volume, on top of the app. | -| `band` | There is a horizontal overlay at the top or bottom of the app. | -| `sidebar` | There is a vertical sidebar covering less than 33% of the app on one side. | -| `blocked` | There is a significantly sized UX covering a majority of the app. | +| Value | Description | +|-----------|----------------------------------------------------------------------------| +| `icon` | There is an informative icon, e.g. volume, on top of the app. | +| `band` | There is a horizontal overlay at the top or bottom of the app. | +| `sidebar` | There is a vertical sidebar covering less than 33% of the app on one side. | +| `blocked` | There is a significantly sized UX covering a majority of the app. | ## 5. Background Audio -If an app has the `xrn:firebolt:capability:media:background-audio`, then it can keep playing audio/video when the app is in the `none` display state and the audio will be played for the user. +If an app has the `xrn:firebolt:capability:media:background-audio`, then it can + keep playing audio/video when the app is in the `none` display state and +the audio will be played for the user. -When an app has this capability, it **MAY** be put into the `none` display state while in the `active` Lifecycle state. +When an app has this capability, it **MAY** be put into the `none` display +state while in the `active` Lifecycle state. ## 6. Picture-in-Picture Video -If an app has the `xrn:firebolt:capability:media:picture-in-picture`, then it can keep playing audio/video when the app is in the `none` display state and the audio & video will be presented to the user in bounding box determined by the platform. Note that this does not include the entire UX of the app, just the active media pipeline. +If an app has the `xrn:firebolt:capability:media:picture-in-picture`, then it +can keep playing audio/video when the app is in the `none` display state and +the audio & video will be presented to the user in bounding box determined by + the platform. Note that this does not include the entire UX of the app, +just the active media pipeline. -When an app has this capability, it **MAY** be put into the `none` display state while in the `active` Lifecycle state. +When an app has this capability, it **MAY** be put into the `none` display +state while in the `active` Lifecycle state. ## 7. Platform-provided Loading Screen -Most apps will leverage a platform-provided loading screen. +Most apps will leverage a platform-provided loading screen. -If an app provides the `xrn:firebolt:capability:presentation:loading-screen` -capability, then the platform **MAY** use the app-provided loading screen, in -which case, the rest of the section does not apply. +If an app provides the `xrn:firebolt:capability:presentation:loading-screen` +capability, then the platform **MAY** use the app-provided loading screen, in + which case, the rest of the section does not apply. -The loading screen **SHOULD** include a loading image referenced in the app's -manifest and cached on the device. +The loading screen **SHOULD** include a loading image referenced in the app's +manifest and cached on the device. -The loading screen **MUST** be displayed when the user attempts to launch the -app. +The loading screen **MUST** be displayed when the user attempts to launch the +app. -The loading screen **MUST** stay displayed until the app becomes active, or -launching is cancelled. +The loading screen **MUST** stay displayed until the app becomes active, or +launching is cancelled. -The presentation state of the app **MUST** be `LOADING` for the entire time -the loading screen is displayed. +The presentation state of the app **MUST** be `LOADING` for the entire time the + loading screen is displayed. -See [Lifecycle](./index.md) for more info on launching. +See [Lifecycle](./index.md) for more info on launching. ## 8. App-provided Loading Screen -If an app provides the `xrn:firebolt:capability:lifecycle:loading-screen` -capability, then the platform **MAY** invoke this capability in some situations. +If an app provides the `xrn:firebolt:capability:lifecycle:loading-screen` +capability, then the platform **MAY** invoke this capability in some +situations. -In order for an app and use an app-provided loading screen, the app **MUST** -provide the `xrn:firebolt:capability:lifecycle:activity` capability. If the app -does not provide this capability, then app-provided loading screens **MUST NOT** -but invoked for the app. +In order for an app and use an app-provided loading screen, the app **MUST** +provide the `xrn:firebolt:capability:lifecycle:activity` capability. If the +app does not provide this capability, then app-provided loading screens +**MUST NOT** but invoked for the app. -Apps that provide the loading screen capability **MUST** be made visible at -the very beginning of the `Activity.activate()` transition, rather -than at the end. +Apps that provide the loading screen capability **MUST** be made visible at the + very beginning of the `Activity.activate()` transition, rather than at the +end. -The presentation state of the app **SHOULD NOT** be `none` at any time during -the `activate()` transition. +The presentation state of the app **SHOULD NOT** be `none` at any time during +the `activate()` transition. -See [Lifecycle](./index.md) for more info on loading and activating apps. +See [Lifecycle](./index.md) for more info on loading and activating apps. diff --git a/requirements/style-guide-and-template.md b/requirements/style-guide-and-template.md index 2a9a1ed1d..1d935d9d3 100644 --- a/requirements/style-guide-and-template.md +++ b/requirements/style-guide-and-template.md @@ -1,27 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Requirements Style Guide -Document Status: Working Draft +Document Status: Working Draft -See [Firebolt Requirements Governance](./governance.md) for more info. +See [Firebolt Requirements Governance](./governance.md) for more info. -**NOTE**: Update this link based on your directory depth ^^ +**NOTE**: Update this link based on your directory depth ^^ -| Contributor | Organization | -| -------------- | -------------- | -| TBD | TBD | +| Contributor | Organization | +| ----------- | ------------ | +| TBD | TBD | ## 1. Overview -This document is both a style guide *and* a template for Firebolt Requirements Specifications. +This document is both a style guide *and* a template for Firebolt Requirements +Specifications. -The Overview section is a non-normative or informative introduction to the contents and subject matter of the document. This is included to introduce the reader to the overall problem, solution, and scope. No formal requirements will be included here, as it will often be skipped by readers that are already familiar with the document. +The Overview section is a non-normative or informative introduction to the +contents and subject matter of the document. This is included to introduce +the reader to the overall problem, solution, and scope. No formal +requirements will be included here, as it will often be skipped by readers +that are already familiar with the document. -Overviews can be as long or short as appropriate for the subject matter, and should have a target audience ranging from technical product managers to engineering teams that may be testing, implementing, or integrating with the functionality described in the document. +Overviews can be as long or short as appropriate for the subject matter, and +should have a target audience ranging from technical product managers to +engineering teams that may be testing, implementing, or integrating with the +functionality described in the document. -The overview must contain the following towards the end: +The overview must contain the following towards the end: -Requirements documents are written using the [IETF Best Common Practice 14](https://www.rfc-editor.org/rfc/rfc2119.txt) and should include the following summary in the Overview section: +Requirements documents are written using the [IETF Best Common Practice +14](https://www.rfc-editor.org/rfc/rfc2119.txt) and should include the +following summary in the Overview section: -The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be interpreted as described in [BCP 14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. +The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL + NOT**", "**SHOULD**", "**SHOULD NOT**", "**RECOMMENDED**", "**NOT +RECOMMENDED**", "**MAY**", and "**OPTIONAL**" in this document are to be +interpreted as described in [BCP +14](https://www.rfc-editor.org/rfc/rfc2119.txt) [RFC2119] [RFC8174] when, and + only when, they appear in all capitals, as shown here. ## 2. Table of Contents - [1. Overview](#1-overview) @@ -33,60 +80,101 @@ The key words "**MUST**", "**MUST NOT**", "**REQUIRED**", "**SHALL**", "**SHALL - [4. Example Section](#4-example-section) - [4.1. Example Feature](#41-example-feature) -**NOTE**: This is a simple table of contents. It should include links to all headers in the document, except for the top-level header (i.e. `# Title`). It is recommended to use a Markdown plugin to generate this based on headers ranging from level two to level six. Delete this note from your actual spec :) +**NOTE**: This is a simple table of contents. It should include links to all +headers in the document, except for the top-level header (i.e. `# Title`). It + is recommended to use a Markdown plugin to generate this based on headers +ranging from level two to level six. Delete this note from your actual spec +:) ## 3. Specification Style Requirements -Firebolt uses method templates in order to code-generate consistent APIs. For example, methods with the `"property"` tag only need to have the `getter` editorially defined. The Firebolt OpenRPC tools will auto-generate the `setter` and `subscriber` as OpenRPC methods with matching types. Additionally, the Firebolt OpenRPC tools wil then code-generate the getter, setter, and subscriber as APIs in various languages using templates. +Firebolt uses method templates in order to code-generate consistent APIs. For +example, methods with the `"property"` tag only need to have the `getter` +editorially defined. The Firebolt OpenRPC tools will auto-generate the +`setter` and `subscriber` as OpenRPC methods with matching types. +Additionally, the Firebolt OpenRPC tools wil then code-generate the getter, +setter, and subscriber as APIs in various languages using templates. -This enables both consistent APIs (all properties have a recongnizable pattern) and consistent SDK implementation, which reduces the code that needs to be tested. +This enables both consistent APIs (all properties have a recongnizable pattern) + and consistent SDK implementation, which reduces the code that needs to be +tested. ### 3.1. General Style Requirements -All headers **MUST** be numbered, and have the parent header as the prefix, separated with '.' +All headers **MUST** be numbered, and have the parent header as the prefix, +separated with '.' -Module and method names, as well as constants **MUST** be in monospace font, e.g. the `Foo` module **MUST** have a `bar` method that returns `true`. Specs should use JavaScript notation for any code examples if the spec is not targeting another specific language binding, e.g. a spec about Event listeners in C++ would use C++ syntax. +Module and method names, as well as constants **MUST** be in monospace font, +e.g. the `Foo` module **MUST** have a `bar` method that returns `true`. Specs + should use JavaScript notation for any code examples if the spec is not +targeting another specific language binding, e.g. a spec about Event +listeners in C++ would use C++ syntax. -String constants and values **MUST** be wrapped in quotes for clarity, e.g. `"Hello World"`. +String constants and values **MUST** be wrapped in quotes for clarity, e.g. +`"Hello World"`. ### 3.2. Firebolt Style Requirements -All Firebolt APIs exposed for building Firebolt Apps **MUST** be exposed as JSON-RPC methods on a WebSocket accessible to the device, typically running locally. +All Firebolt APIs exposed for building Firebolt Apps **MUST** be exposed as +JSON-RPC methods on a WebSocket accessible to the device, typically running +locally. -Parameters and return values for all APIs **MUST** be described using JSON-Schema schemas. +Parameters and return values for all APIs **MUST** be described using +JSON-Schema schemas. -Methods **MUST** be grouped into “modules” or “packages” of functionality. +Methods **MUST** be grouped into “modules” or “packages” of functionality. -The JSON-RPC method name of any method **MUST** follow the template: +The JSON-RPC method name of any method **MUST** follow the template: ``` . -``` +``` -e.g. +e.g. ``` lifecycle.ready -``` +``` -JSON-RPC method names are case sensitive. +JSON-RPC method names are case sensitive. -Methods **MUST** have at least one capability used, managed, or provided by the method. +Methods **MUST** have at least one capability used, managed, or provided by the + method. -Methods **MAY** require the use of more than one capability, but this means that the app must have permission to all of them. In order to enable App permissions to be evaluated in an isolated layer, separate from the method implementation itself, a Firebolt method **MUST NOT** be specified to add or remove fields based on the caller's permissions. +Methods **MAY** require the use of more than one capability, but this means +that the app must have permission to all of them. In order to enable App +permissions to be evaluated in an isolated layer, separate from the method +implementation itself, a Firebolt method **MUST NOT** be specified to add or +remove fields based on the caller's permissions. -The words used in method and parameter names **SHOULD** be used as consistently as possible across the Firebolt API surface. See the [Firebolt API Glossary](./glossary.md) for words that Firebolt uses and how they are used. +The words used in method and parameter names **SHOULD** be used as consistently + as possible across the Firebolt API surface. See the [Firebolt API +Glossary](./glossary.md) for words that Firebolt uses and how they are used. ### 3.3. Firebolt Method Templates -Methods **SHOULD** consider using the existing Firebolt method tags, in order to have a level of consistency across APIs. +Methods **SHOULD** consider using the existing Firebolt method tags, in order +to have a level of consistency across APIs. -If a Firebolt method is specified such that it requires a non-existant template, then a new Requirements Specification **MUST** be written and referenced by the specification that inspired it. Method templates **MUST** be designed with re-use in mind. +If a Firebolt method is specified such that it requires a non-existant +template, then a new Requirements Specification **MUST** be written and +referenced by the specification that inspired it. Method templates **MUST** +be designed with re-use in mind. ## 4. Example Section -A section describes group of closely related features. Many specifications have only one section, however, more complicated specifications may have many. The first paragraph of a section is typically a non-normative introduction to that section, and therefor does not contain any formal requirements. +A section describes group of closely related features. Many specifications have + only one section, however, more complicated specifications may have many. +The first paragraph of a section is typically a non-normative introduction +to that section, and therefor does not contain any formal requirements. ### 4.1. Example Feature -Each feature under a section will have it's own heading. Non-normative introductions to features are not typically needed, as the reader is ready to get into requirements at this point. It is recommended that all Feature headings under each Section contain only sentences or short paragraphs with formal requirements, e.g. MUST, SHOULD, MAY, MUST NOT, SHOULD NOT, etc. These sentences should be separated by blank lines for readability, e.g.: +Each feature under a section will have it's own heading. Non-normative +introductions to features are not typically needed, as the reader is ready to + get into requirements at this point. It is recommended that all Feature +headings under each Section contain only sentences or short paragraphs with +formal requirements, e.g. **MUST**, **SHOULD**, **MAY**, **MUST** NOT, +**SHOULD NOT**, etc. These sentences should be separated by blank lines for +readability, e.g.: -This requirement **MUST** be satisifed. +This requirement **MUST** be satisifed. -This requirement **SHOULD** be satisfied. +This requirement **SHOULD** be satisfied. -This requirement **MUST** be satisfied. The requirement **MUST** be satisifed in this particular way. +This requirement **MUST** be satisfied. The requirement **MUST** be satisifed +in this particular way. diff --git a/src/js/github.io/markdown.mjs b/src/js/github.io/markdown.mjs index 9068792e0..071c83a6a 100644 --- a/src/js/github.io/markdown.mjs +++ b/src/js/github.io/markdown.mjs @@ -24,38 +24,183 @@ const requirements = await readFiles(await readDir(path.join('.', 'requirements' const processFiles = (docs) => { Object.keys(docs).forEach(ref => { - if (ref.endsWith('.md')) { let data = docs[ref] -// console.log(data) - // find all headers - const headers = data.match(/#+[ \t]+(([0-9]+\.)+)[ /t]+(.*?)\n/g) - - // turn to slugs - const slugs = headers.map(h => h.replace(/#/g, '')) - .map(h => h.replace(/\t/g, '')) - .map(h => h.replace(/\./g, '')) - .map(h => h.replace(/^ /g, '')) - .map(h => h.replace(/\n$/g, '')) - .map(h => h.replace(/ /g, '-')) - .map(h => h.toLowerCase()) - .map(h => '#' + h) - - const links = data.match(/\]\(.*?\#.*?\)/g) - - links.map(l => l.slice(2, -1)).forEach(link => { - if (!slugs.find(s => s === link)) { - const best = slugs.find(s => s.match(new RegExp(link.replace(/^\#[0-9]+/, '#[0-9]+')))) || slugs.find(s => s.startsWith(link.split('-')[0] + '-')) - console.log('Fixing broken link: (' + link + ') -> (' + best + ')') - data = data.replace('](' + link + ')', '](' + best + ')') - } - }) + data = fixBrokenLinks(data, ref, docs) + data = wrapText(data) + data = prettyTables(data) + data = bcp14(data) + docs[ref] = data } }) } +function fixBrokenLinks(data, ref, files) { + + const getSlugs = (data) => { + // find all headers + const headers = data.match(/#+[ \t]+(([0-9]+\.)+)[ /t]+(.*?)\n/g) + + // turn to slugs + return headers.map(h => h.replace(/#/g, '')) + .map(h => h.replace(/\t/g, '')) + .map(h => h.replace(/\./g, '')) + .map(h => h.replace(/^ /g, '')) + .map(h => h.replace(/\n$/g, '')) + .map(h => h.replace(/ /g, '-')) + .map(h => h.toLowerCase()) + .map(h => '#' + h) + } + + const slugs = getSlugs(data) + const links = data.match(/\]\([^\)]*?\#[^\)]*?\)/gms) + + links.map(l => l.slice(2, -1)).forEach(link => { + if (!slugs.find(s => s === link)) { + const best = slugs.find(s => s.match(new RegExp(link.replace(/^\#[0-9]+/, '#[0-9]+')))) || slugs.find(s => s.startsWith(link.split('-')[0] + '-')) + if (best) { + console.log('Fixing broken link: (' + link + ') -> (' + best + ')') + data = data.replace('](' + link + ')', '](' + best + ')') + } + // TODO: fix bad slugs in links to other files + else if (link.match(/[^\)]+?\#[^\)]*?/gms)) { + // external + const [file, slug] = link.split('#') + const fileRef = path.join(path.dirname(ref), file) + const fileSlugs = getSlugs(files[fileRef]) + if (!fileSlugs.find(s => s === '#' + slug)) { + const best = fileSlugs.find(s => s.match(new RegExp(('#'+slug).replace(/^\#[0-9]+/, '#[0-9]+')))) || slugs.find(s => s.startsWith(link.split('-')[0] + '-')) + if (best) { + console.log('Fixing broken external link: (' + link + ') -> (' + file + best + ')') + data = data.replace('](' + link + ')', '](' + file + best + ')') + } + } + } + } + }) + + return data +} + +function wrapText(data) { + const lines = data.split('\n') + const maximum = 80 + let buffer = '' + let wrapped = '' + let width = 0 + const block_regex = /^\s*?\>/ + const code_regex = /^\s*?```/ + let code = false + + lines.forEach( (line, index) => { + + if (line.match(code_regex)) { + code = !code + } + + // skip lists, tables, headers, and blanks + if (code || line.match(/^\s*?\-/) || line.match(/^\s*?\|/) || line.match(/^\#+/) || line.match(/^\s*?$/)) { + buffer && (wrapped += '\n' + buffer) + buffer = '' + wrapped += '\n' + line + width = 0 + } + else { + const quote = line.match(block_regex) ? true : false + + if (quote) { + line = line.replace(block_regex, '').trim() + + if (!buffer) { + buffer = '> ' + width = 2 + } + else if (!line.trim()) { + buffer += '\n> \n>' + width = 2 + } + } + + line.split(/\s+/).forEach(word => { + if (word.match(block_regex)) { + throw "Found > in line: " + line + } + let len = word.length + 1 // .replace(/\(.*?\)/g, '') + if (width + len > maximum) { + buffer += '\n' + (quote ? '> ' : '') + word + ' ' + width = len + 2 + } + else { + buffer += word + ' ' + width += len + } + }) + } + }) + + buffer && (wrapped += '\n' + buffer) + + return wrapped +} + +function prettyTables(data) { + const lines = data.split('\n') + const table_regex = /^\s*?\|/ + const column_regex = /(? line.trim().split(column_regex).slice(1, -1).map(c => (' ' + c.trim() + ' ').length) + + for (var i=0; i Math.max(w, widths[index])) + } + // pad each cell to match the max width + for (j=i; lines[j].match(table_regex); j++) { + lines[j] = lines[j].split(column_regex).map((cell, index) => { + // stuff before or after the table row + if (index === 0 || index === widths.length + 1) { + return cell + } + else { + if (cell.match(/^ \-+ $/)) { + return ' ' + '-'.repeat(widths[index-1]-2) + ' ' + } + else if (cell.match(/^\-+$/)) { + return '-'.repeat(widths[index-1]) + } + else { + return (' ' + cell.trim() + ' ').padEnd(widths[index-1]) + } + } + }).join('|') + i++ + } + } + } + + return lines.join('\n') +} + +function bcp14(data) { + return data + .replace(/([^\*])MUST(\s+)NOT([^\*])/gms, '$1**MUST$2NOT**$3') + .replace(/([^\*])SHOULD(\s+)NOT([^\*])/gms, '$1**SHOULD$2NOT**$3') + .replace(/([^\*])SHALL(\s+)NOT([^\*])/gms, '$1**SHALL$2NOT**$3') + .replace(/([^\*])NOT(\s+)RECOMMENDED([^\*])/gms, '$1**NOT$2RECOMMENDED**$3') + .replace(/([^\*])MUST([^\*])/gms, '$1**MUST**$2') + .replace(/([^\*])SHOULD([^\*])/gms, '$1**SHOULD**$2') + .replace(/([^\*])SHALL([^\*])/gms, '$1**SHALL**$2') + .replace(/([^\*])RECOMMENDED([^\*])/gms, '$1**RECOMMENDED**$2') + .replace(/([^\*])MAY([^\*])/gms, '$1**MAY**$2') + .replace(/([^\*])REQUIRED([^\*])/gms, '$1**REQUIRED**$2') + .replace(/([^\*])OPTIONAL([^\*])/gms, '$1**OPTIONAL**$2') +} + processFiles(requirements) writeFiles(requirements)