Abstract
Capsium is a modular framework designed to efficiently and securely interchange multi-format information in interoperable portable packages, as well as platform-independent deployment of these packages to serve information consumers.
This document specifies requirements of the Capsium framework and its components:
Capsium packages: standardized unit of information interchange in the Capsium framework.
Capsium reactors: server-side or user-side software that allows deployment of a Capsium package.
Capsium HTTP API: user-facing HTTP API implemented by a Capsium reactor.
Introduction
General
The digital era demands advanced, secure, and efficient methods for deploying and exchanging information. As organizations contend with multi-format data across diverse platforms, the limitations of traditional web packaging solutions become increasingly apparent.
Capsium answers this need with a modular framework designed for the efficient and secure interchange of multi-format information within interoperable and portable packages.
Capsium uniquely supports the packaging and deployment of “non-application websites” or “non-server-side application websites” by delegating those functions to the Capsium reactor, which does not depend on a web server and can be directly implemented by the browser, mimicking the file-serving capabilities of a web server.
Features
Today’s complex digital landscape highlight the necessity for Capsium.
Portability: There is a critical need for data and applications to be easily transferable across different environments without compromising security or functionality. Capsium ensures that packages can be seamlessly moved between platforms.
Data immutability: Ensuring that data remains unchanged and secure from tampering is essential for maintaining integrity and trust. Capsium guarantees data immutability through advanced cryptographic techniques, crucial for compliance and auditing.
Interoperability: Diverse systems and applications must communicate effectively. Capsium supports a wide range of formats and protocols, ensuring seamless integration and data exchange across different platforms.
Single-page applications (SPAs): Modern web applications demand dynamic, responsive user experiences. Capsium supports the development and deployment of SPAs, reducing server dependency and enhancing performance.
Capsium Reactors: To meet varied deployment needs, Capsium introduces reactors that can be installed on user machines or servers, managing and deploying Capsium packages with flexibility and scalability, without the need for a traditional web server.
Comparison with existing solutions
Capsium’s unique approach addresses the deficiencies of existing packaging solutions for non-application websites and web applications, which are all unsuitable for the use case.
The following packaging solutions are listed in order of an decreasing level of virtualization.
Website bundles:
Examples: Safari webarchive (extension .webarchive), WARC (extension: .warc), Mozilla Archive Format (MAFF, .maff), Microsoft Compiled HTML Help (CHM, extension .chm) and MHTML/MHT (MIME Encapsulation of Aggregate HTML Documents, extension: .mhtml, .mht) (defined in RFC 2110 and RFC 2557).
Purpose: Bundle website resources for offline access and archival.
Limitations: Not interoperable and difficult to implement across different browsers. Do not support server-side deployments. Unable to contain single-page applications that require rich HTML API interfaces.
Client-side web application bundles:
Examples: Electron, NW.js.
Purpose: Bundle a browser and a web server along with necessary language interpreters.
Limitations: Resulting bundles are often very large and cumbersome to distribute, requiring significant memory for simple outputs. Introduce non-platform-independent executable code, complicating data management processes.
Server-side web application bundles:
Examples: Webpack, Gulp (JavaScript); Maven (Java); Bundler (Ruby); pip and setuptools (Python).
Purpose: Automate bundling of static assets and dependencies, improving load times and simplifying development workflows.
Limitations: Require a large number of dependencies and permissions for port opening and listening. Necessitate running a server, which can be complex and resource-intensive.
Containers:
Examples: Docker, LXC.
Purpose: Allow entire applications and their dependencies to be packaged into portable containers, enhancing deployment consistency.
Limitations: Require virtualization permissions on the machine, which can be a barrier for some environments. Resource-intensive.
Virtual machines:
Examples: VMWare, Xen.
Purpose: Provide complete isolation and can run different operating systems on a single hardware host.
Limitations: Require permissions at the hardware level and can be resource-intensive.
Benefits
Capsium addresses the shortcomings of previous solutions and offers unique benefits:
Interoperability: Supports a variety of formats and protocols, enabling seamless communication between different systems and platforms.
Portability: Capsium packages are easily transferable, facilitating data migration and deployment without compromising security or functionality.
Efficiency: Optimizes deployment processes for SPAs and static websites, reducing server dependency and improving performance.
Security: Utilizing advanced encryption and key management, Capsium ensures secure storage and transfer of information.
Compliance and auditing: Features for tracking data access and modifications ensure regulatory compliance and robust auditing capabilities.
Capsium reactors: Provide flexible and scalable package management and deployment solutions, eliminating the need for traditional server infrastructure.
Data management impact
Capsium modernizes and transforms data management practices in several key ways:
Enhanced Security: Prioritizes data immutability and advanced encryption, helping organizations mitigate data breach risks.
Improved Interoperability: Facilitates greater integration and communication across different systems, driving innovation and efficiency.
Portability: Simplifies the transfer of data and applications across different environments, reducing the effort and risk associated with migration.
Efficiency: Streamlines deployment processes, particularly for SPAs and static websites, leading to faster load times and reduced server loads.
Compliance and Auditing: Facilitates adherence to regulatory requirements by ensuring data integrity and providing robust tracking of data access and modifications.
Summary
Capsium represents a significant advancement in the realm of data management, addressing critical needs for security, interoperability, portability, efficiency, and compliance. Its innovative approach transforms how organizations handle data, making it a vital tool in the modern digital landscape.
Common architecture for portable secure information interchange and unified management (Capsium)
1. Scope
This document describes Capsium, a modular framework for the secure and efficient interchange of multi-format information within interoperable and portable packages.
This document specifies requirements of the Capsium framework and its components:
Capsium packages: standardized unit of information interchange in the Capsium framework.
Capsium reactors: server-side or user-side software that allows deployment of a Capsium package.
Capsium HTTP API: user-facing HTTP API implemented by a Capsium reactor.
This document also provides:
Guidelines for the utilization of the Capsium framework.
Examples for implementing components of the Capsium framework.
2. Normative references
The following documents are referred to in the text in such a way that some or all of their content constitutes requirements of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.
ISO/IEC 21320-1:2015, International Organization for Standardization (committee). Information technology — Document Container File — Part 1: Core. First edition. 2015. Geneva: International Organization for Standardization and International Electrotechnical Commission. https://www.iso.org/standard/60101.html.
NIST FIPS 180-4 fpd, National Institute of Standards and Technology. Secure Hash Standard (SHS). Edition Revision 4. 2012. Gaithersburg. https://csrc.nist.gov/pubs/fips/180-4/final.
NIST SP 800-38D fpd, DWORKIN, Morris. Recommendation for Block Cipher Modes of Operation — Galois/Counter Mode (GCM) and GMAC. 2007. Gaithersburg. https://csrc.nist.gov/pubs/sp/800/38/d/final.
IETF RFC 8017, KALISKI, B., J. JONSSON and A. RUSCH. PKCS #1: RSA Cryptography Specifications Version 2.2. 2016. RFC Publisher. https://www.rfc-editor.org/info/rfc8017.
IETF RFC 9110, Internet Engineering Task Force (committee). HTTP Semantics. 2022. RFC Publisher. https://www.rfc-editor.org/info/rfc9110.
SemVer 2.0.0, Semantic Versioning 2.0.0. https://semver.org/spec/v2.0.0.html
SPDX License List, SPDX License List. Linux Foundation. https://spdx.org/licenses/
3. Terms and definitions
For the purposes of this document, the following terms and definitions apply.
3.1. Capsium package
A structured bundle of multi-format data and resources that can be securely and efficiently interchanged and deployed across different platforms. Capsium packages are designed to be portable and interoperable, ensuring seamless data transfer and application deployment.
3.2. Capsium reactor
A component responsible for managing and deploying Capsium packages. The Capsium reactor can be implemented directly by a web browser or installed on user machines or servers. It eliminates the need for a traditional web server by mimicking its file-serving capabilities.
3.3. Capsium HTTP API
3.4. Non-application website
A website that does not require server-side logic or dynamic content generation. These websites consist primarily of static resources such as HTML, CSS, and JavaScript files and are deployed using the Capsium framework without the need for a traditional web server.
3.5. Single-page application (SPA)
A web application that loads a single HTML page and dynamically updates the content as the user interacts with the app. SPAs provide a more fluid and responsive user experience by reducing server dependency. Capsium supports the deployment and optimization of SPAs.
3.6. Data immutability
The property of data that ensures it remains unchanged and secure from tampering after it has been created. Capsium guarantees data immutability through the use of advanced cryptographic techniques, ensuring the integrity and trustworthiness of the data.
3.7. Interoperability
The ability of different systems, platforms, and applications to communicate and work together effectively. Capsium supports a wide range of formats and protocols, enabling seamless data exchange and integration across diverse environments.
3.8. Portability
The capability of a system or application to be easily transferred and used across different environments without compromising security or functionality. Capsium packages are designed to be portable, facilitating easy migration and deployment.
3.9. Compliance and auditing
The adherence to regulatory requirements and the ability to track and monitor data access and modifications. Capsium includes features that ensure compliance with relevant standards and provide robust auditing capabilities to maintain data integrity and security.
3.10. Encryption
The process of converting data into a coded format to prevent unauthorized access. Capsium employs advanced encryption techniques to ensure that the data within its packages is securely stored and transferred, protecting sensitive information from breaches.
3.11. Key management
The administration of cryptographic keys, which includes their generation, exchange, storage, use, and replacement. In the context of Capsium, key management is crucial for maintaining the security of encrypted data and ensuring that only authorized entities can access or modify the data.
3.12. Static website
A website consisting of fixed content that does not change unless manually updated. Static websites are composed of HTML, CSS, and JavaScript files and do not require server-side processing. Capsium aids in the deployment of static websites by packaging all necessary resources into a single, portable bundle.
3.13. Virtualization
The creation of a virtual version of something, such as an operating system, a server, a storage device, or network resources. Capsium packages reduce the need for virtualization by allowing applications to run directly in the browser or on the client machine, simplifying deployment and reducing resource requirements.
3.14. Package management
The process of handling software packages, including their installation, upgrade, configuration, and removal. Capsium’s package management capabilities ensure that Capsium packages can be efficiently deployed and maintained, streamlining the application lifecycle.
3.15. Browser-implemented reactor
A Capsium reactor that is directly implemented by the web browser, enabling it to serve Capsium packages without the need for additional server infrastructure. This approach leverages the browser’s native capabilities to handle package deployment and management.
3.16. Serverless architecture
A design pattern where the server management and infrastructure concerns are abstracted away from the developer. Capsium supports serverless architectures by allowing applications to be deployed and run without a traditional server, relying instead on the Capsium reactor.
3.17. Cryptographic techniques
Methods used to secure information and communications through the use of codes, ensuring that only those for whom the information is intended can read and process it. Capsium utilizes cryptographic techniques to maintain data security and integrity within its packages.
3.18. Interchange format
A standardized format used for exchanging data between different systems or platforms. Capsium defines a specific interchange format to ensure that its packages can be seamlessly transferred and utilized across various environments.
3.19. Multi-format information
Data that exists in various formats, such as text, images, video, and structured data. Capsium packages are designed to handle multi-format information, ensuring that diverse types of data can be securely and efficiently bundled together and deployed.
3.20. Deployment
The process of distributing and installing software or data packages in a specific environment. Capsium streamlines deployment by allowing packages to be easily transferred and installed without the need for extensive configuration or server infrastructure.
3.21. Regulatory compliance
Adhering to laws, regulations, and guidelines relevant to the handling and protection of data. Capsium helps organizations maintain regulatory compliance by providing tools and features that ensure data security, integrity, and traceability.
3.22. File-serving capabilities
The ability of a server or system to deliver files to clients upon request. In the context of Capsium, the reactor mimics traditional file-serving capabilities, allowing it to serve packaged resources directly to the browser or client machine.
3.23. Resource bundling
The process of combining multiple files and resources into a single package. Capsium facilitates resource bundling, enabling efficient transfer and deployment of all necessary components of a web application or website.
3.24. Package integrity
The assurance that a package has not been altered or tampered with since its creation. Capsium ensures package integrity through cryptographic signatures and other security measures, guaranteeing that the contents of a package remain unchanged during transfer and deployment.
3.25. Transferability
The ease with which data or applications can be moved from one environment to another. Capsium enhances transferability by providing a standardized package format that can be easily migrated across different platforms and systems.
3.26. Static content
Web content that does not change and is delivered to the user exactly as stored. Capsium supports the deployment of static content by packaging it into a portable format that can be served without the need for dynamic processing.
3.27. Advanced cryptography
The use of sophisticated encryption algorithms and techniques to protect data. Capsium employs advanced cryptography to ensure that the data within its packages is secure from unauthorized access and tampering.
3.28. Data migration
The process of moving data from one system or environment to another. Capsium simplifies data migration by providing a portable package format that facilitates the transfer of data and resources across different platforms.
3.29. Scalable deployment
The ability to efficiently deploy applications and data across a varying number of environments and users. Capsium supports scalable deployment by providing a flexible package format and reactor that can handle deployments of any size.
3.30. Platform independence
The ability of software or data to operate on various hardware and operating systems without requiring modification. Capsium ensures platform independence by using standardized formats and protocols, allowing its packages to be used across different environments seamlessly.
3.31. Dependency management
The process of handling and resolving the dependencies required by software applications or packages. Capsium includes mechanisms for managing dependencies within its packages, ensuring that all necessary components are available and properly configured during deployment.
3.32. Immutable data
Data that cannot be altered once it has been created. Capsium guarantees immutability through cryptographic methods, making sure that data within a package remains unchanged and secure from tampering.
3.33. Data integrity
The accuracy and consistency of data over its lifecycle. Capsium ensures data integrity by using cryptographic techniques to protect data from unauthorized alterations, ensuring reliable and trustworthy information.
3.34. Secure interchange
The safe and protected exchange of data between different systems or platforms. Capsium facilitates secure interchange by using advanced encryption and ensuring that packages are transferred without compromising their integrity or confidentiality.
3.35. Application lifecycle
The entire process of developing, deploying, maintaining, and eventually decommissioning an application. Capsium supports the application lifecycle by providing tools and features that streamline deployment, maintenance, and updates of packaged applications.
3.36. Server dependency
The reliance on a server to provide resources, process requests, and manage data. Capsium reduces server dependency by enabling applications and websites to be deployed and run using the Capsium reactor, which can function without a traditional server.
3.37. Resource optimization
The process of improving the efficiency and performance of resources used by an application or system. Capsium supports resource optimization by packaging resources in a way that reduces load times and minimizes server demands.
3.38. Data traceability
The ability to track the history, usage, and location of data over its lifecycle. Capsium includes features that enhance data traceability, ensuring that data access and modifications can be monitored and audited for compliance and security purposes.
3.39. Data security
The protection of data from unauthorized access, corruption, or theft. Capsium ensures data security through encryption, key management, and other protective measures, maintaining the confidentiality and integrity of packaged data.
3.40. Audit trail
A record of all actions and changes made to data, providing transparency and accountability. Capsium supports the creation of audit trails, helping organizations monitor data access and modifications for compliance and security.
3.41. Browser-native deployment
The ability to deploy applications and resources directly within a web browser without requiring additional plugins or software. Capsium supports browser-native deployment, leveraging the browser’s capabilities to handle and serve packaged data and applications.
3.42. Dynamic content
Web content that changes based on user interactions or other conditions. While Capsium primarily targets static and SPA content, it can support dynamic content through appropriate integration with client-side scripting.
3.43. Lightweight deployment
A deployment method that minimizes resource usage and overhead, making it suitable for environments with limited resources. Capsium supports lightweight deployment by packaging applications and data in an efficient, compact format.
3.44. Multi-platform support
The ability to operate across various operating systems, devices, and environments. Capsium ensures multi-platform support by adhering to standardized formats and protocols, allowing its packages to function seamlessly across different systems.
3.45. Portable package
A self-contained bundle that includes all necessary resources and data, designed to be easily transferred and deployed across different environments. Capsium packages are inherently portable, facilitating straightforward migration and deployment.
3.46. Client-side processing
The execution of operations on the user’s device rather than on a server. Capsium supports client-side processing by enabling web applications to run directly in the browser, reducing the need for server interactions.
3.47. Cross-platform compatibility
The ability of software or data to work on various operating systems and devices without requiring modifications. Capsium ensures cross-platform compatibility by using standardized formats and protocols, making its packages usable across different platforms.
3.48. Version control
A system for managing changes to documents, programs, and other information stored as computer files. Capsium integrates version control mechanisms to help track changes, manage different versions, and ensure consistency of packaged data.
3.49. Secure deployment
The practice of deploying applications and data in a manner that ensures their security throughout the process. Capsium supports secure deployment by using encryption and other security measures to protect packages from tampering and unauthorized access.
3.50. Configuration management
The process of handling changes in software, hardware, documentation, and other components. Capsium includes features for configuration management, ensuring that packages are correctly configured and maintained throughout their lifecycle.
3.51. Integrity check
A method to verify that data has not been altered or tampered with. Capsium performs integrity checks using cryptographic signatures, ensuring the authenticity and consistency of the data within its packages.
3.52. Modular framework
A design approach that divides a system into smaller parts, or modules, that can be independently created and then used in different systems. Capsium is a modular framework, allowing components to be added, removed, or updated without affecting the whole system.
3.53. User authentication
The process of verifying the identity of a user. Capsium supports user authentication to ensure that only authorized individuals can access and interact with the contents of a package.
3.54. Data encapsulation
The bundling of data with the methods that operate on that data, restricting direct access to some of the object’s components. Capsium utilizes data encapsulation to protect the integrity and security of the packaged data.
3.55. Environment abstraction
The separation of application logic from the underlying hardware and software environment. Capsium provides environment abstraction by allowing packages to operate independently of the specific details of the deployment environment.
3.56. Resilience
The ability of a system or application to recover quickly from failures and continue to function. Capsium enhances resilience by packaging applications in a way that minimizes dependencies and facilitates recovery and redeployment.
3.57. Scalability
The capacity to handle increasing amounts of work or to be readily enlarged. Capsium supports scalability by ensuring that its packages can be deployed and managed efficiently, regardless of the scale of the deployment.
3.58. Trusted execution
The assurance that code and data are executed in a secure environment, protected from unauthorized access and tampering. Capsium supports trusted execution through the use of secure packaging and deployment mechanisms.
3.59. Content delivery
The process of distributing digital content to users. Capsium optimizes content delivery by bundling resources into efficient packages that can be served directly by the browser or client machine.
3.60. Content encapsulation
The practice of bundling content with the necessary metadata and resources to ensure it can be used independently of its original environment. Capsium uses content encapsulation to create portable packages that can be deployed and used across different systems.
3.61. Application sandboxing
The technique of running applications in a restricted environment to limit their access to system resources and data. Capsium can support application sandboxing by enabling packages to run in isolated environments, enhancing security and control.
3.62. Metadata management
The process of handling metadata, which is data that describes other data. Capsium includes features for metadata management, ensuring that the necessary information about packaged data and resources is available and properly maintained.
3.63. Data lifecycle management
The process of managing data from its creation to its eventual disposal. Capsium includes features for data lifecycle management, ensuring that data within its packages is properly handled, maintained, and disposed of according to best practices and regulatory requirements.
4. Capsium framework
The Capsium framework provides a comprehensive set of principles, features, and use cases that define its architecture and functionality. This clause outlines the essential components and concepts that make up the framework, ensuring a clear understanding of its capabilities and applications.
4.1. General
Capsium (Common architecture for portable secure information interchange and unified management) is an innovative technology framework designed to facilitate the interoperable and portable deployment of lightweight, web-compatible, interactive data packages. The framework supports the packaging and deployment of static websites, which can be hosted by any cloud file hosting service with minimal web serving functionality, such as AWS S3 or GitHub Pages.
The core concept of Capsium is to enable the packaging of static websites into deployable objects, called Capsium packages. These packages are self-contained, size-efficient, and secure, providing all necessary resources and metadata to be served by a simple web server.
4.2. Principles of the framework
The Capsium framework is based on several key principles that ensure its effectiveness and reliability:
Ease of use
The deployable object can be easily built, inspected, extracted, and deployed.
Cross-platform deployment
The deployable object can be deployed across multiple platforms without modification.
Static nature
The deployable object is static, meaning it does not require server-side processing to function.
Size efficiency
The deployable object is designed to be as small and efficient as possible.
Integrity
The deployable object cannot be corrupted, ensuring data integrity.
Self-containment
The deployable object is self-contained, including all necessary routes and redirects for the static site.
Versioning
The deployable object can be versioned, allowing for efficient updates and rollbacks.
Dependencies
The deployable object can require other deployable objects, enabling modularity and extensibility.
File system support
The deployable object has a file system that supports all types of files and provides immutable, layered versioning.
Deployment API compatibility
The deployment API can be easily implemented by common web servers such as Apache and nginx.
Compliance
The deployment API complies with common expectations and supports fetching of metadata and other introspection features.
4.3. Key features of the framework
The Capsium framework includes several key features that enhance its functionality and usability:
Capsium package
A deployable object that is a compressed, single-file package containing all files necessary for a static site.
Capsium filesystem
A file system within the Capsium package, representing the file/folder hierarchy as it will be served by the package’s external API.
Capsium reactor
A Capsium-enabled web server that activates and deploys the Capsium package.
Activation
The process by which a reactor loads the content of a Capsium package and serves its routes to a web address.
These features enable the efficient creation, deployment, and management of web-compatible, interactive data packages.
4.4. Use cases of the framework
The Capsium framework supports a variety of use cases, demonstrating its versatility and practicality:
Static website deployment
Capsium packages can be used to deploy static websites, including HTML, CSS, JS, and media files, on cloud file hosting services.
Microservices integration
Capsium packages can mount routes from other deployable objects, facilitating the integration of microservices.
Data migration
Capsium packages can be used to securely and efficiently migrate data across different platforms and environments.
Secure interchange
Capsium packages provide a secure method for exchanging data between systems, with support for encryption and digital signatures.
Version control and updates
Capsium packages support versioning, enabling efficient updates and rollbacks of deployed static websites.
These use cases highlight the practical applications of the Capsium framework in various scenarios, emphasizing its ability to enhance the deployment and management of web-compatible data packages.
5. Capsium package
The Capsium package is the fundamental unit of deployment within the Capsium framework. This clause details the structure, contents, and specifications of a Capsium package, ensuring a comprehensive understanding of its components and functionality.
5.1. General
A Capsium package is a compressed, single-file deployable object that contains all the necessary files for a static site. It is designed to be easily built, inspected, extracted, and deployed across various platforms. The package ensures that all resources, metadata, and configurations required for site deployment are self-contained within it.
Description
A Capsium package encapsulates a static website, including HTML, CSS, JS, media files, and potentially a data store.
MIME type
The MIME type for a Capsium package is application/vnd.capsium.package.
File extension
The standard file extension for a Capsium package is .cap.
5.2. Structure
5.2.1. General
The structure of a Capsium package includes several key elements that organize and define the contents and functionality of the package:
Folder hierarchy
The internal file/folder hierarchy represents how files will be served by the package’s external API.
Metadata, versions, package dependencies
Metadata provides information about the package, including versioning details and dependencies on other Capsium packages.
License and copyright file and declaration
The package includes a license and copyright file, typically in SPDX format, to specify the legal terms of use.
5.2.2. Folder hierarchy
The folder hierarchy is:
example-capsium-package/
├── index.html
├── styles.css
├── app.js
├── manifest.json
├── routes.json
├── http-api.json
├── storage.json
├── security.json
├── authentication.json
├── logging-monitoring.json
├── validation.json
├── LICENSE.spdx
└── README.md
5.3. Metadata file
5.3.1. General
{
"name": "example-capsium-package",
"version": "1.0.0",
"description": "A sample Capsium package that demonstrates resource bundling.",
"guid": "example.com/example-capsium-package",
"uuid": "123e4567-e89b-12d3-a456-426614174000",
"author": "Your Name",
"repository": {
"type": "git",
"url": "https://github.com/yourusername/example-capsium-package.git"
},
"dependencies": {
"other-package.capsium": ">=1.0.0"
},
"license": "path/to/LICENSE.spdx",
"readOnly": true,
"modules": ["signatures", "layered-storage"]
}
name
Description
The name of the package.
Requirements
Should be a string.
Must be unique within the ecosystem.
Typically uses kebab-case (lowercase letters with hyphens).
version
Description
The version of the package.
Requirements
Should follow [Semantic Versioning](https://semver.org/) (e.g., 1.0.0).
Consists of three digits separated by dots, representing major, minor, and patch versions.
description
Description
A brief description of the package.
Requirements
Should be a string.
Provides a concise overview of what the package does.
guid
Description
A globally unique identifier for the package.
Requirements
Should be a URI.
URI format
uuid
Description
A universally unique identifier for the package.
Requirements
Should be a string.
Must be a valid UUID (e.g., 123e4567-e89b-12d3-a456-426614174000).
author
Description
The name of the author or maintainer of the package.
Requirements
Should be a string.
Can include the author’s name or organization.
license
Description
The license under which the package is distributed.
Requirements
Should be a string.
Can be a standard license identifier (e.g., MIT) or a path to a license file (e.g., path/to/LICENSE.spdx).
repository
Description
Information about the repository where the package source code is hosted.
Sub-attributes
- type
The type of version control system (e.g., git).
Requirements:
Should be a string.
- url
The URL of the repository.
Requirements:
Should be a string and a valid URL.
dependencies
Description
A list of other packages that this package depends on.
Requirements
Should be an object where keys are package names and values are version requirements.
Version requirements can use semantic versioning ranges (e.g., >=1.0.0).
readOnly:
Type
boolean
Description
Specifies if the package is immutable.
Value Requirements
Must be set to true to activate immutability.
Example
modules (optional)
"modules": ["signatures", "layered-storage"]
NOTE 1 The name, version, guid, and uuid attributes are critical for the unique identification of the package.
NOTE 2 The repository and dependencies attributes help in maintaining and managing the package’s source code and its dependencies, respectively.
5.3.2. Identifier
The GUID (Globally Unique Identifier) for a Capsium package is used for uniquely identifying the package within the ecosystem. It follows a URI (Uniform Resource Identifier) format to ensure global uniqueness and to provide a standardized way of referencing the package.
It ensures global uniqueness, readability, and consistent identification of packages.
The GUID is essential for dependency tracking, providing a reliable reference to specific packages within the ecosystem.
5.3.2.1. Requirements for GUID in URI Format
Structure:
The GUID should be structured in a URI format.
Typically, it follows a reverse domain name notation to ensure uniqueness.
Components:
Scheme
The scheme part of the URI, which could be http, https, or a custom scheme like capsium.
Authority
This usually includes the domain name, ensuring the identifier is unique to an organization or individual.
Path
A path that typically reflects the package name and possibly the version.
Uniqueness:
The GUID must be unique across all packages to avoid conflicts.
Using the domain name owned by the package maintainer helps ensure uniqueness.
Readability:
The GUID should be easy to read and understand, reflecting the package’s origin and name.
Examples:
The GUID should ideally be in lowercase to maintain consistency and avoid case-sensitivity issues.
5.3.2.2. Examples of GUIDs in URI Format
Here are a few examples of GUIDs that comply with the URI format requirements:
Example 1:
"guid": "capsium://example.com/package-name"
Scheme
capsium
Authority
example.com
Path
/package-name
Example 2:
"guid": "https://example.com/packages/sample-package"
Scheme
https
Authority
example.com
Path
/packages/sample-package
Example 3:
"guid": "http://myorganization.org/capsium/my-package"
Scheme
http
Authority
myorganization.org
Path
/capsium/my-package
Example 4:
"guid": "capsium://opensource.org/libs/lib-capsium"
Scheme
capsium
Authority
opensource.org
Path
/libs/lib-capsium
5.3.2.3. Dependency tracking
The GUID is crucial for dependency tracking as it provides a unique and consistent identifier for each package. When defining dependencies in the metadata.json file, the GUID ensures that the correct package is referenced, avoiding confusion with similarly named packages.
In the metadata.json file, dependencies can be listed using the GUID:
{
"dependencies": {
"capsium://example.com/package-name": ">=1.0.0",
"https://example.com/packages/another-package": "^2.1.0"
}
}
- capsium://example.com/package-name
This GUID uniquely identifies the package-name from example.com and specifies that any version >=1.0.0 is acceptable.
- https://example.com/packages/another-package
This GUID uniquely identifies the another-package from example.com and specifies that any version compatible with 2.1.0 (using semantic versioning) is acceptable.
5.3.3. Versions
5.3.3.1. General
Versions in the metadata file use [Semantic Versioning](https://semver.org/), which follows the MAJOR.MINOR.PATCH format.
Here is an example:
{
"version": "1.0.0"
}
The version of a Capsium package is a critical attribute that indicates the state and compatibility of the package over time. It follows the Semantic Versioning (SemVer) convention to ensure clarity and consistency across package versions.
5.3.3.2. Requirements for Version
Format:
The version should follow the Semantic Versioning format: MAJOR.MINOR.PATCH.
Each component (MAJOR, MINOR, PATCH) should be a non-negative integer without leading zeros.
Components:
MAJOR
Incremented for incompatible API changes. When you make changes that break backward compatibility, you increase the major version.
MINOR
Incremented for adding functionality in a backward-compatible manner. When you add new features that do not break existing functionality, you increase the minor version.
PATCH
Incremented for backward-compatible bug fixes. When you make minor changes or fixes that do not affect the API, you increase the patch version.
Pre-release and Build Metadata (Optional):
Pre-release version
Indicated by appending a hyphen and a series of dot-separated identifiers (e.g., 1.0.0-alpha, 1.0.0-beta.1).
Build metadata
Indicated by appending a plus sign and a series of dot-separated identifiers (e.g., 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85).
Incrementing Versions:
Always increment the appropriate part of the version number based on the nature of the changes.
Reset the lower components to zero when incrementing a higher component (e.g., 1.2.3 to 2.0.0).
Uniqueness:
Each release of a package should have a unique version number to distinguish it from other releases.
5.3.3.3. Examples of Version Numbers
Stable Versions:
1.0.0: Initial stable release.
2.1.0: Minor update with new features that are backward-compatible.
3.0.2: Patch update with bug fixes for the third major version.
Pre-release Versions:
1.0.0-alpha: An alpha version, which is an early release not intended for production use.
1.0.0-beta.1: The first beta release, which is more stable than alpha but still not production-ready.
1.0.0-rc.1: The first release candidate, which is a final stage before a stable release.
Versions with Build Metadata:
1.0.0+20130313144700: A stable release with build metadata indicating the build timestamp.
2.0.0-beta+exp.sha.5114f85: A beta release with experimental build metadata.
5.3.4. Dependencies
5.3.4.1. General
Dependencies are specified in the dependencies section of the metadata JSON file. Each dependency is listed with a name and a version requirement.
The dependencies section in the metadata.json file specifies other packages that the Capsium package depends on. This section ensures that all necessary packages are available for the package to function correctly. Dependency resolution and the bundling of dependent packages into composite packages are defined by the composite packages module ([module-composite]).
Here is an example:
{
"dependencies": {
"other-package.capsium": ">=1.0.0",
"another-package.capsium": "^2.3.4"
}
}
5.3.4.2. Requirements for Dependencies
Structure:
The dependencies section should be an object where each key is the GUID of a dependency package and the corresponding value is the version requirement.
GUID:
The key should be the GUID of the dependency package in URI format, ensuring global uniqueness and proper identification.
Version Requirement:
The value should be a string that specifies the version requirement of the dependency.
Version requirements can use semantic versioning ranges, such as:
Exact version: 1.2.3
Greater than or equal to a version: >=1.0.0
Compatible with a version: ^2.1.0
Ranges: >=1.0.0 <2.0.0
Multiple Dependencies:
The dependencies section can list multiple dependencies, each with its GUID and version requirement.
5.3.4.3. Examples of Dependencies
Single Dependency:
"dependencies": {
"capsium://example.com/package-name": ">=1.0.0"
}This specifies that the package depends on package-name from example.com with any version >=1.0.0.
Multiple Dependencies:
"dependencies": {
"https://example.com/packages/first-package": "^2.1.0",
"capsium://another.com/second-package": "1.2.3"
}This specifies that the package depends on:
first-package from example.com with any version compatible with 2.1.0.
second-package from another.com with the exact version 1.2.3.
Range Version Dependency:
"dependencies": {
"capsium://example.org/dependency-package": ">=1.0.0 <2.0.0"
}This specifies that the package depends on dependency-package from example.org with any version between 1.0.0 (inclusive) and 2.0.0 (exclusive).
Pre-release Version Dependency:
"dependencies": {
"capsium://example.net/experimental-package": "1.0.0-beta.1"
}This specifies that the package depends on experimental-package from example.net with the specific pre-release version 1.0.0-beta.1.
Dependency with Build Metadata:
"dependencies": {
"https://example.com/special-package": "1.0.0+20130313144700"
}This specifies that the package depends on special-package from example.com with the exact version 1.0.0 including build metadata 20130313144700.
Multiple Version Ranges:
"dependencies": {
"capsium://example.org/multi-range-package": ">=1.0.0 <1.5.0 || >=2.0.0 <3.0.0"
}This specifies that the package depends on multi-range-package from example.org with versions either between 1.0.0 (inclusive) and 1.5.0 (exclusive) or between 2.0.0 (inclusive) and 3.0.0 (exclusive).
Wildcard Version Dependency:
"dependencies": {
"capsium://example.com/wildcard-package": "*"
}This specifies that the package depends on wildcard-package from example.com with any available version.
Caret (^) and Tilde (~) Ranges:
"dependencies": {
"capsium://example.com/caret-package": "^1.2.3",
"capsium://example.com/tilde-package": "~1.2.3"
}This specifies that the package depends on:
caret-package from example.com with any version compatible with 1.2.3 (meaning >=1.2.3 <2.0.0).
tilde-package from example.com with any version compatible with 1.2.3 (meaning >=1.2.3 <1.3.0).
Each dependency in the dependencies section ensures that the package has access to the required versions of other packages necessary for its proper functionality.
5.3.5. License
5.3.5.1. General
The license key in the metadata.json file specifies the licenses under which the Capsium package is distributed. This key ensures compliance with legal requirements and informs users of their rights and obligations regarding the package.
The license file should be in the SPDX format and referenced from the metadata file.
5.3.5.2. Requirements for License
Format:
The license key should be a string or an array of objects.
Each string should be a valid SPDX (Software Package Data Exchange) license identifier or a path to an SPDX file included in the package.
Single License:
When the package is distributed under a single license, the license key should be a string.
Multiple Licenses:
When the package is distributed under multiple licenses, the license key should be an array of objects.
Each object in the array should specify a type and an optional file field if pointing to an SPDX file.
Each object should also include a condition field that describes when the license applies.
SPDX Identifier or File:
An SPDX identifier should be a valid SPDX license identifier.
An SPDX file should be a path to a file included in the package that contains the SPDX license text.
5.3.5.3. Examples of License
Single SPDX License:
"license": "MIT"
This specifies that the package is distributed under the MIT License.
Single SPDX File License:
"license": "LICENSE.spdx"
This specifies that the package is distributed under the license detailed in the LICENSE.spdx file.
Multiple Licenses with Conditions:
"license": [
{
"type": "MIT",
"condition": "Default license"
},
{
"type": "Apache-2.0",
"condition": "For use in commercial environments"
}
]
This specifies that the package is distributed under the MIT License by default, but under the Apache License 2.0 when used in commercial environments.
Combination of SPDX Identifier and File with Conditions:
"license": [
{
"type": "MIT",
"condition": "Default license"
},
{
"type": "Custom-License",
"file": "custom-license.spdx",
"condition": "For internal use only"
}
]
This specifies that the package is distributed under the MIT License by default, but under a custom license detailed in the custom-license.spdx file for internal use only.
Complex License Conditions:
"license": [
{
"type": "GPL-3.0-only",
"condition": "When redistributed"
},
{
"type": "LGPL-3.0-only",
"condition": "When used as a library"
}
]
This specifies that the package is distributed under the GPL-3.0-only License when redistributed and under the LGPL-3.0-only License when used as a library.
By following these requirements and examples, the license key in the Capsium package’s metadata.json file provides clear information about the applicable licenses and the conditions under which they apply.
Below is an example of a simple SPDX license file (LICENSE.spdx):
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: example-capsium-package
DocumentNamespace: http://spdx.org/spdxdocs/example-capsium-package-abc123
Creator: Person: John Doe
Creator: Organization: Example Organization
Creator: Tool: SPDX-Tools-Version-2.1.0
Created: 2024-05-28T12:00:00Z
LicenseID: MIT
LicenseName: MIT License
LicenseText: |
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Ensure this SPDX license file is referenced in the manifest.json:
{
"license": "path/to/LICENSE.spdx"
}
5.3.6. Read-only
Capsium packages can be configured as immutable, ensuring that their content cannot be modified after creation. Composite packages layer changes on top of immutable base packages ([module-composite]).
This section details the requirements, specifications, and use cases for configuring a package as read-only, including value requirements and enumerations for attributes. The read-only attribute is package-wide and set inside metadata.json.
5.4. Manifest file
5.4.1. General
The manifest file describes how to handle multi-format content within the package.
It includes mappings and configurations for handling different types of files and resources.
When the manifest.json file does not exist, it should be built automatically from the contents of the contents/ directory.
Specification
File name
manifest.json
Location
Root directory of the package
Content
JSON format, specifying the resources, their versions, and configurations.
Example:
{
"resources": {
"index.html": {
"type": "text/html",
"version": "1.0.0"
},
"styles.css": {
"type": "text/css",
"version": "1.0.0"
},
"app.js": {
"type": "application/javascript",
"version": "1.0.0"
},
"dynamic-content.js": {
"type": "application/javascript",
"version": "1.0.0"
},
"mobile.css": {
"type": "text/css",
"version": "1.0.0"
},
"desktop.css": {
"type": "text/css",
"version": "1.0.0"
},
"images/small.jpg": {
"type": "image/jpeg",
"version": "1.0.0"
},
"images/medium.jpg": {
"type": "image/jpeg",
"version": "1.0.0"
},
"images/large.jpg": {
"type": "image/jpeg",
"version": "1.0.0"
},
"content/en/index.html": {
"type": "text/html",
"version": "1.0.0"
},
"content/en/about.html": {
"type": "text/html",
"version": "1.0.0"
},
"content/es/index.html": {
"type": "text/html",
"version": "1.0.0"
},
"content/es/about.html": {
"type": "text/html",
"version": "1.0.0"
}
}
}
5.4.2. Content visibility
Content visibility in the Capsium package is managed through the manifest.json file, where resources can be designated as either exported or private. This designation determines whether the resource can be re-used by other packages or is restricted to the current package. Re-use of exported resources across packages is defined by the composite packages module ([module-composite]).
Requirements and Specifications
Resource Declaration:
Resources must be declared in the manifest.json file.
Each resource entry should include the path to the resource and its visibility status.
Visibility Options:
Exported
Resources marked as exported are available for re-use by other packages that depend on the current package.
Private
Resources marked as private are restricted to the current package and cannot be accessed by other packages.
Example Configuration:
An example manifest.json file demonstrating resource visibility:
{
"resources": [
{
"path": "scripts/main.js",
"visibility": "exported"
},
{
"path": "styles/theme.css",
"visibility": "private"
},
{
"path": "images/logo.png",
"visibility": "exported"
}
]
}
Usage in Dependent Packages:
Packages that depend on another package can access resources marked as exported by including the appropriate references in their own configuration files.
Example usage in a dependent package — a dependency resource reference of the form <guid>/<path> ([module-composite]):
{
"dependencies": {
"capsium://example.com/capsium-core": "1.0.0"
},
"routes": [
{
"path": "/vendor/core/main.js",
"resource": "capsium://example.com/capsium-core/scripts/main.js"
}
]
}Enforcement:
The Capsium system should enforce visibility rules, ensuring that private resources are not accessible to other packages.
Attempts to access private resources from other packages should result in an error, maintaining the integrity of resource boundaries.
By clearly defining and adhering to these visibility rules, the Capsium package ensures that resource bundling is both flexible and secure, allowing for effective re-use of assets while protecting private resources.
5.5. Root file
The root file of a Capsium package serves as the main entry point and must be an HTML file. This file is crucial as it defines the primary structure and content that the system should load or render.
5.5.1. Requirements for Root File
File Type:
The root file must be an HTML file. It should have an .html extension.
File Location:
The root file should be located within the package directory.
The path to the root file should be specified relative to the root directory of the package.
File Naming:
The root file should have a clear and descriptive name, commonly named index.html or main.html.
Entry Point Specification:
The path to the root HTML file should be accurately specified in the index key of the routes.json file.
Ensure the path does not contain typos or incorrect directory names.
Content Requirements:
The HTML file should include the necessary structure (<html>, <head>, and <body> tags).
It must be well-formed and valid HTML to ensure proper rendering and functionality.
5.5.2. Examples of Root File
Basic HTML Entry Point:
{
"index": "public/index.html"
}This specifies that the root file for the package is index.html located in the public directory.
HTML Entry Point in Documentation Directory:
{
"index": "docs/main.html"
}This specifies that the root file for the package is main.html located in the docs directory.
HTML Entry Point in Web Directory:
{
"index": "web/index.html"
}This specifies that the root file for the package is index.html located in the web directory.
HTML Entry Point in Dist Directory:
{
"index": "dist/index.html"
}This specifies that the root file for the package is index.html located in the dist directory.
HTML Entry Point in Root Directory:
{
"index": "index.html"
}This specifies that the root file for the package is index.html located in the root directory of the package.
Example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Capsium Package</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Welcome to the Capsium Package</h1>
<script src="app.js"></script>
</body>
</html>
5.6. Resource bundling
5.6.1. General
Resource bundling involves packaging all necessary static and dynamic content within the Capsium package to ensure that the package is self-contained and can be served efficiently.
The content include:
Static content
Includes HTML, CSS, JS, images, and other media files.
Dynamic content
Although primarily static, the package can include references to dynamic content handled by client-side scripts.
Conditional alternative content
The package can include alternative content that is conditionally loaded based on specific criteria, such as files with alternative image resolutions.
Example directory structure:
example-capsium-package/
├── index.html
├── styles.css
├── app.js
├── dynamic-content.js
├── mobile.css
├── desktop.css
├── images/
│ ├── small.jpg
│ ├── medium.jpg
│ └── large.jpg
├── content/
│ ├── en/
│ │ ├── index.html
│ │ └── about.html
│ ├── es/
│ │ ├── index.html
│ │ └── about.html
├── metadata.json
├── manifest.json
├── routes.json
├── LICENSE.spdx
└── README.md
5.6.2. Static Content
Static content includes files that do not change once the package is created and can be directly served to the client. These files are essential for the visual and functional aspects of the web application.
HTML Files
These files define the structure and layout of web pages. They typically include elements like headers, paragraphs, links, and embedded resources such as images and scripts.
Example:
Figure 36 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example Page</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Welcome to Example Page</h1>
<script src="app.js"></script>
</body>
</html>Figure 37 CSS Files
These files define the styles for HTML elements, specifying colors, fonts, layouts, and other visual aspects.
Example (pass:c,q,a,m,p[`styles.css`]):
Figure 38 body {
font-family: Arial, sans-serif;
background-color: =f0f0f0;
}
h1 {
color: =333;
}Figure 39 JavaScript Files
These files contain client-side scripts that add interactivity and dynamic behavior to the web pages.
Example (pass:c,q,a,m,p[`app.js`]):
Figure 40 document.addEventListener('DOMContentLoaded', () => {
console.log('Page loaded');
});Figure 41 Images and Media Files
These include JPEG, PNG, GIF images, SVG graphics, and other media files like videos and audio clips that are used within the web pages.
Example:
Figure 42 example-capsium-package/
├── images/
│ ├── logo.png
│ └── banner.jpgFigure 43
5.6.3. Dynamic Content
Dynamic content refers to content that can change or be generated on the fly, typically handled by client-side scripts. While the package itself is primarily static, it can include references to dynamic content.
Client-side Scripts
JavaScript files that fetch and display dynamic content from APIs or other sources at runtime.
Example (pass:c,q,a,m,p[`dynamic-content.js`]):
Figure 44 fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
document.getElementById('dynamic-content').innerText = data.message;
});Figure 45 Dynamic References
Links and scripts that point to external resources or APIs that provide dynamic data.
Example (pass:c,q,a,m,p[`index.html`]):
Figure 46 <div id="dynamic-content"></div>
<script src="dynamic-content.js"></script>Figure 47
5.6.4. Conditional Alternative Content
Conditional alternative content allows the package to include multiple versions of a resource, with the appropriate version being loaded based on specific criteria. This can enhance performance and provide a better user experience.
Alternative Image Resolutions
Including images in multiple resolutions and loading the appropriate one based on the device’s screen resolution.
Example (pass:c,q,a,m,p[`index.html`]):
Figure 48 <img srcset="small.jpg 480w, medium.jpg 768w, large.jpg 1024w"
sizes="(max-width: 600px) 480px, (max-width: 900px) 768px, 1024px"
src="small.jpg" alt="Example Image">Figure 49 Content for Different Languages
Providing content in multiple languages and loading the appropriate version based on the user’s language preferences.
Example:
Figure 50 example-capsium-package/
├── content/
│ ├── en/
│ │ ├── index.html
│ │ └── about.html
│ ├── es/
│ │ ├── index.html
│ │ └── about.htmlFigure 51 JavaScript to load language-specific content (pass:c,q,a,m,p[`language-loader.js`]):
Figure 52 const userLang = navigator.language || navigator.userLanguage;
const contentPath = userLang.startsWith('es') ? 'content/es/' : 'content/en/';
fetch(contentPath + 'index.html')
.then(response => response.text())
.then(html => {
document.body.innerHTML = html;
});Figure 53 Device-Specific Content
Serving different versions of content based on the type of device (e.g., mobile vs. desktop).
Example:
Figure 54 <link rel="stylesheet" media="screen and (max-width: 600px)" href="mobile.css">
<link rel="stylesheet" media="screen and (min-width: 601px)" href="desktop.css">Figure 55
5.7. Resource routing
5.7.1. General
Resource routing defines how requests to the Capsium package are handled and routed.
The routes.json file is the central configuration for routing within your package. It maps URL paths to resources, covering static resource routing and the essential configurations for headers and HTTP methods. Dynamic HTTP API routes that map a URL path and method to an executable handler are defined by the handler routes module ([module-handler-routes]).
The routing file routes.json is the single source of truth for routing in the package, simplifying management and ensuring consistency.
When the routes.json file doesn’t exist, automatically generate it based on the contents in the manifest. When it is an HTML file, create 2 routes, one with the file’s base name, one with the full file name. When a file of another type, generate the route relative from the content/ path.
- Example routes.json
{
"index": "index.html",
"routes": [
{
"path": "/",
"resource": "index.html"
},
{
"path": "/styles.css",
"resource": "styles.css"
},
{
"path": "/app.js",
"resource": "app.js"
},
{
"path": "/images/small.jpg",
"resource": "images/small.jpg"
},
{
"path": "/data/users",
"resource": "data/users.json"
},
{
"path": "/data/products",
"resource": "data/products.json"
}
]
}
In this example, the routes.json file includes routes for static resources (like HTML, CSS, images, and data files).
5.7.2. Index route
The index key in the routes.json file designates the entry point or root file of the Capsium package. This key is crucial for defining the primary file that the system should load or execute.
5.7.2.1. Requirements for index Key
File Path:
The index key should be a string representing the relative path to the root file from the root directory of the package.
The path should be valid and point to an existing file within the package.
File Type:
The root file can be of various types depending on the nature of the package (e.g., JavaScript, HTML, JSON). Ensure the file type is appropriate for the package’s purpose.
Uniqueness:
There should be only one index key in the routes.json file, specifying a single root file.
Consistency:
The path specified by the index key should be consistent with the project’s structure and should not include typos or incorrect directory names.
5.7.2.2. Examples of index Key
HTML Entry Point
{
"index": "public/index.html"
}
This specifies that the root file for the package is index.html located in the public directory.
By adhering to these requirements and examples, the index key in the routes.json file ensures that the Capsium package has a clearly defined entry point, facilitating proper loading and execution of the package.
5.7.3. Dataset routes
Mounting routes to data sets involves configuring specific endpoints that provide access to various data sets within the package. This allows for organized and efficient data retrieval, enabling users to access the data they need through well-defined routes. All data route mounts will use the HTTP path mount point /api/v1/data/ as the root.
Route definition
Specifies the URL path that will be used to access the data set, using /api/v1/data/ as the root.
Data source
Defines the source of the data, such as a file path, database query, or external API.
Response format
Specifies the format in which the data will be returned, such as JSON, XML, or CSV.
Access control for dataset routes is an optional capability defined by the authentication module ([module-authentication]).
Dataset routes should be mounted as specified in routes.json, with each route pointing to a key dataset that is provided in storage.json.
Example of storage.json:
{
"storage": {
"dataSets": {
"users": {
"source": "db/users",
},
"products": {
"source": "files/products.json",
},
"sales": {
"source": "api/external/sales",
}
}
}
}
Example of routes.json:
{
"routes": [
{
"route": "/api/v1/data/users",
"dataset": "users"
},
{
"route": "/api/v1/data/products",
"dataset": "products"
},
{
"route": "/api/v1/data/sales",
"dataset": "sales"
}
]
}
In this example, routes.json defines three routes, each pointing to a data set specified in storage.json:
Users data set
Route: /api/v1/data/users
Dataset: users (refers to the users key in storage.json)
Products data set
Route: /api/v1/data/products
Dataset: products (refers to the products key in storage.json)
Sales data set
Route: /api/v1/data/sales
Dataset: sales (refers to the sales key in storage.json)
5.7.4. Attributes summary
| Attribute | Description |
|---|---|
| Storage | The root object for storage configuration. |
| Attribute | Description |
|---|---|
| Source | The source of the data (e.g., database path, file path, external API URL). |
| Response format | The format in which the data will be returned (e.g., json, xml, csv). |
| Attribute | Description |
|---|---|
| Route | The URL path for accessing the data set, starting with /api/v1/data/. |
| Dataset | The key in storage.json that this route points to. |
Access control attributes for dataset routes are defined by the authentication module ([module-authentication]).
By configuring these attributes, Capsium packages can effectively manage data storage and provide structured access to data sets through defined routes.
5.7.5. Header responses
5.7.5.1. General
In the Capsium package, resource routing allows you to map URLs to specific resources and define how they should be handled. One crucial aspect of resource routing is defining header responses, which can be done directly in the routes.json file or via external files.
5.7.5.2. Inline declarations
You can specify header responses directly within the routes.json file. This approach embeds the header definitions within the routing configuration, making it straightforward to manage.
Example:
{
"routes": {
"/api/resource": {
"GET": {
"file": "handlers/getResource.js",
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache",
"Access-Control-Allow-Origin": "*"
}
},
"POST": {
"file": "handlers/postResource.js",
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
}
}
}
}
}
In this example: - The GET method for /api/resource has headers defined directly in the routes.json file. - The POST method for /api/resource also defines its headers directly.
5.7.5.3. Declaring through external files
Alternatively, you can manage header definitions in external files, which can be useful for maintaining cleaner and more modular configurations.
Example:
{
"routes": {
"/api/resource": {
"GET": {
"file": "handlers/getResource.js",
"headersFile": "headers/getResourceHeaders.json"
},
"POST": {
"file": "handlers/postResource.js",
"headersFile": "headers/postResourceHeaders.json"
}
}
}
}
In this example: - The GET method for /api/resource references an external file headers/getResourceHeaders.json for headers. - The POST method for /api/resource references an external file headers/postResourceHeaders.json for headers.
The content of headers/getResourceHeaders.json might look like this:
{
"Content-Type": "application/json",
"Cache-Control": "no-cache",
"Access-Control-Allow-Origin": "*"
}
And headers/postResourceHeaders.json might look like this:
{
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
}
By using these mechanisms, you can effectively manage and define header responses in the Capsium package, either directly within the routes.json file or through external files for better modularity and maintainability.
5.7.6. Route visibility
Route visibility in the Capsium package is managed through the routes.json file, where routes can be designated as either exported or private. This designation determines whether the route can be re-used by other packages or is restricted to the current package. Re-use of exported routes across packages is defined by the composite packages module ([module-composite]).
Requirements and Specifications
Route Declaration:
Routes must be declared in the routes.json file.
Each route entry should include the path to the resource and its visibility status.
Visibility Options:
Exported
Routes marked as exported are available for re-use by other packages that depend on the current package.
Private
Routes marked as private are restricted to the current package and cannot be accessed by other packages.
Example Configuration:
An example routes.json file demonstrating route visibility:
{
"routes": [
{
"path": "/api/public",
"handler": "publicHandler",
"visibility": "exported"
},
{
"path": "/api/private",
"handler": "privateHandler",
"visibility": "private"
}
]
}
Inheriting and processing routes from dependency packages is an optional capability defined by the composite packages module ([module-composite]).
5.8. Storage
The Capsium package includes a comprehensive storage system that supports static data files, databases, and — through the optional layered storage capability ([module-layered-storage]) — a unified merged filesystem view. This section outlines the requirements and specifications for each storage type.
A Capsium package can contain datasets. Each dataset is composed of data items. A dataset can be one of:
Layered storage
Utilizes a unified merged filesystem view, similar to overlay FS, to manage different layers of content ([module-layered-storage]).
Static File with Structured Data
Formats such as CSV, JSON, YAML.
Backed by Schemas
Formats that use JSON Schema or YAML Schema for validation.
Static data files
Contains immutable data files that are part of the package.
Databases
Includes support for embedded databases such as SQLite to store structured data (if supported by the Capsium reactor).
5.8.1. Defining datasets
Datasets are explicitly defined, and are referred by other components, such as Clause 5.7.3.
source
Defines the source of the data, such as a file path, database query, or external API.
Example:
{
"storage": {
"dataSets": {
"users": {
"source": "db/users",
},
"products": {
"source": "files/products.json",
},
"sales": {
"source": "api/external/sales",
}
}
}
}
5.8.2. Static data files
Static data files are immutable files that are served directly by the Capsium package. These files typically include assets such as images, stylesheets, and JavaScript files.
Requirements and Specifications
Storage Location:
Static data files must be stored in a designated directory, such as static or public.
Access Path:
Static files should be accessible via predictable URL paths, typically mirroring their directory structure.
Example: /static/images/logo.png should map to static/images/logo.png in the filesystem.
Caching:
Static files should be served with appropriate caching headers to improve performance.
Example:
Cache-Control: public, max-age=31536000Configuration:
The location of static files should be defined in the routes.json file.
Example:
{
"static": {
"path": "static",
"url": "/static"
}
}5.8.3. Datasets
Datasets in the Capsium package provide structured storage for dynamic data that requires querying and transactional operations.
JSON schema or YAML schema for datasets using static files like JSON or YAML in the storage.json configuration file.
5.8.3.1. Schema-backed file datasets
When working with datasets in static file formats such as JSON or YAML, it’s important to validate the data against a predefined schema. This ensures the data adheres to the expected structure and types. The storage.json configuration file can include references to these schemas.
The storage.json file should be structured to include the following attributes for each dataset:
datasetId
Identifier for the dataset.
dataFile
Path to the static data file (JSON or YAML).
schemaFile
Path to the schema file (JSON Schema or YAML Schema).
schemaType
Type of the schema (e.g., “json-schema” or “yaml-schema”).
Example structure: `json { “datasets”: [ { “datasetId”: “dataset1”, “dataFile”: “/path/to/datafile.json”, “schemaFile”: “/path/to/schemafile.json”, “schemaType”: “json-schema” }, { “datasetId”: “dataset2”, “dataFile”: “/path/to/datafile.yaml”, “schemaFile”: “/path/to/schemafile.yaml”, “schemaType”: “yaml-schema” } ] } `
Here’s an example of a JSON schema for validating a dataset of user information: `json { “$schema”: “http://json-schema.org/draft-07/schema#”, “type”: “object”, “properties”: { “users”: { “type”: “array”, “items”: { “type”: “object”, “properties”: { “id”: { “type”: “string” }, “name”: { “type”: “string” }, “email”: { “type”: “string”, “format”: “email” } }, “required”: [“id”, “name”, “email”] } } }, “required”: [“users”] } `
Here’s an example of a YAML schema for validating a dataset of user information: `yaml %YAML 1.2 —- $schema: “http://json-schema.org/draft-07/schema#” type: “object” properties: users: type: “array” items: type: “object” properties: id: type: “string” name: type: “string” email: type: “string” format: “email” required: — id — name — email required: — users `
5.8.3.2. SQLite database
In addition to static file formats like JSON and YAML, datasets can also be stored in SQLite databases. This section explains how to configure SQLite datasets in the storage.json file.
The storage.json file should include the following attributes for each SQLite dataset:
datasetId
Identifier for the dataset.
databaseFile
Path to the SQLite database file.
schemaFile
Path to the schema file (SQL schema or JSON schema for defining table structures).
schemaType
Type of the schema (e.g., “sql-schema” or “json-schema”).
table
Name of the table in the SQLite database that the dataset corresponds to.
Example structure: `json { “datasets”: [ { “datasetId”: “dataset1”, “databaseFile”: “/path/to/database.sqlite”, “schemaFile”: “/path/to/schemafile.sql”, “schemaType”: “sql-schema”, “table”: “users” }, { “datasetId”: “dataset2”, “databaseFile”: “/path/to/another_database.sqlite”, “schemaFile”: “/path/to/schemafile.json”, “schemaType”: “json-schema”, “table”: “products” } ] } `
Here’s an example of an SQL schema for a table of user information: `sql CREATE TABLE users ( id TEXT PRIMARY KEY, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE ); `
Here’s an example of a JSON schema for validating the structure of a table of user information: `json { “$schema”: “http://json-schema.org/draft-07/schema#”, “type”: “object”, “properties”: { “id”: { “type”: “string” }, “name”: { “type”: “string” }, “email”: { “type”: “string”, “format”: “email” } }, “required”: [“id”, “name”, “email”] } `
5.8.3.3. Validation
To validate the datasets in a YAML, JSON dataset or a SQLite database against their respective schemas, you can use various tools and libraries depending on the programming language.
5.8.4. REST API for data access and modification
This is the HTTP REST API that the Capsium reactor offers for an activated Capsium package to the HTTP user. The following endpoints are supported for all datasets, as defined in storage.json.
NOTE The dataset CRUD API served by a reactor — mount points under /api/v1/data/, item identity, and exact status codes — is defined by the writable packages module ([module-writable-packages]). This section describes the operations abstractly.
5.8.4.1. GET (Fetch Data)
Endpoint
/dataset/{datasetId}/data
Method
GET
Description
Fetches all data items from the specified dataset.
Request Attributes
datasetId
The identifier of the dataset. Must be a string.
Response
status
200 OK on success.
body
An array of data items.
Example: `json { “datasetId”: “dataset1” } `
5.8.4.2. GET (Fetch Single Data Item)
Endpoint
/dataset/{datasetId}/data/{dataId}
Method
GET
Description
Fetches a single data item from the specified dataset.
Request Attributes
datasetId
The identifier of the dataset. Must be a string.
dataId
The identifier of the data item to be fetched. Must be a string.
Response
status
200 OK on success.
body
The requested data item.
Example: `json { “datasetId”: “dataset1”, “dataId”: “dataItem42” } `
5.8.4.3. POST (Create Data Item)
Endpoint
/dataset/{datasetId}/data
Method
POST
Description
Adds a new data item to the specified dataset.
Request Attributes
datasetId
The identifier of the dataset. Must be a string.
data
The data item to be added. Must conform to the dataset’s schema.
Response
status
201 Created on success.
body
The created data item with its new identifier.
Example: `json { “datasetId”: “dataset1”, “data”: { “key1”: “value1”, “key2”: 123 } } `
5.8.4.4. PUT (Update Data Item)
Endpoint
/dataset/{datasetId}/data/{dataId}
Method
PUT
Description
Updates an existing data item in the specified dataset.
Request Attributes
datasetId
The identifier of the dataset. Must be a string.
dataId
The identifier of the data item to be updated. Must be a string.
data
The updated data item. Must conform to the dataset’s schema.
Response
status
200 OK on success.
body
The updated data item.
Example: `json { “datasetId”: “dataset1”, “dataId”: “dataItem42”, “data”: { “key1”: “newValue”, “key2”: 456 } } `
5.8.4.5. DELETE (Delete Data Item)
Endpoint
/dataset/{datasetId}/data/{dataId}
Method
DELETE
Description
Deletes a data item from the specified dataset.
Request Attributes
datasetId
The identifier of the dataset. Must be a string.
dataId
The identifier of the data item to be deleted. Must be a string.
Response
status
204 No Content on success.
Example: `json { “datasetId”: “dataset1”, “dataId”: “dataItem42” } `
5.8.5. Data Persistence
5.8.5.1. General
A Capsium package containing data may allow modification of data inside the included datasets. Configuration needs to be specified in the package on which data files can be modified or updated.
NOTE Reactors claiming the writable packages module implement modification with the reactor-side overlay model — top-layer writes, tombstones, and dataset logs — defined by [module-writable-packages]. The action history mechanism described here is an alternative package-side design for recording the same changes.
Since a Capsium package at its core is immutable, the mechanism for handling modifications is by storing action patches in an “action history” folder. This folder can be external to the Capsium package or inside a composite Capsium package ([module-composite]). Each data change is stored as a separate patch file.
When a Capsium reactor loads a Capsium package with an action history folder, it will replay those actions on top of the dataset so that the changes persist for users who access the activated Capsium package.
5.8.5.2. Action patch
An action patch represents a single change to a dataset. The following attributes are required:
timestamp
The time when the change was made. Must be in ISO 8601 format (e.g., 2024-05-28T12:34:56Z).
user
The identifier of the user who made the change. Should be a string.
action
The type of action performed. Enumerated values: add, update, delete.
datasetId
The identifier of the dataset affected by the action. Should be a string.
dataId
The identifier of the data item affected by the action. Should be a string.
changes
A JSON object detailing the changes made. The format depends on the type of action.
Example: `json { “timestamp”: “2024-05-28T12:34:56Z”, “user”: “user123”, “action”: “update”, “datasetId”: “dataset1”, “dataId”: “dataItem42”, “changes”: { “key1”: “newValue” } } `
5.8.5.3. Action history folder
The action history folder stores all action patches. The folder must have the following structure and attributes:
Location
Can be external to the Capsium package or inside a composite Capsium package.
Structure
Each action patch is stored as a separate file within the folder.
Filename Convention
Each file name should be unique and can be based on the timestamp and user ID (e.g., 20240528T123456Z_user123_update_dataItem42.json).
File Content
Each file must contain a valid action patch JSON object as specified above.
Example: ` action-history/ ├── 20240528T123456Z_user123_update_dataItem42.json ├── 20240529T101112Z_user456_add_dataItem43.json └── … `
Additional requirements for the action history folder:
Access Control
The folder must be secured to prevent unauthorized access. Only designated users or systems should have read/write access.
Backup
Regular backups of the action history folder should be maintained to prevent data loss.
Versioning
Each action patch should include a version attribute to manage changes to the action patch schema.
Example of an action patch with versioning: `json { “version”: “1.0”, “timestamp”: “2024-05-28T12:34:56Z”, “user”: “user123”, “action”: “update”, “datasetId”: “dataset1”, “dataId”: “dataItem42”, “changes”: { “key1”: “newValue” } } `
5.8.5.4. Saving Data Changes in Datasets to a New External Capsium Package
To save data changes in datasets to a new external Capsium package, the following configuration is required:
Configuration File
save-external.json
Attributes
originalPackageId
The identifier of the original Capsium package. Must be a string.
newPackageId
The identifier for the new external Capsium package. Must be a string.
actionHistoryLocation
The location of the action history folder. Must be a valid path.
Example: `json { “originalPackageId”: “capsiumPkg1”, “newPackageId”: “capsiumPkg2”, “actionHistoryLocation”: “/path/to/action-history” } `
The process for saving data changes includes the following steps:
Identify Changes: Collect all action patches related to the dataset modifications.
Create New Package: Generate a new Capsium package structure.
Include Action Patches: Copy the action patches to the new package’s action history folder.
Update Metadata: Modify the storage.json and other relevant configuration files to reflect the new package and its contents.
Validate Package: Ensure that the new package meets all Capsium package requirements and is properly versioned.
Example process: `shell # Collect action patches cp /path/to/action-history/* /new-package/action-history/
6. Create new package structure
mkdir /new-package cp -r /original-package/* /new-package/
7. Update metadata
jq ’.packages += [{”id”: “capsiumPkg2”, “actionHistoryLocation”: “/new-package/action-history”}]’ /new-package/storage.json > /new-package/storage_tmp.json mv /new-package/storage_tmp.json /new-package/storage.json
8. Validate package
capsium-validate /new-package `
Additional considerations for creating a new external Capsium package:
Integrity Checks
Perform integrity checks to ensure that all data items and action patches are correctly included and no data corruption has occurred.
Documentation
Update the package documentation to reflect the changes and new version information.
Notification
Notify users or systems that depend on the package about the update to the new package.
Example of integrity check: `shell capsium-check-integrity /new-package `
Example of updating documentation: `markdown # Capsium Package Documentation
8.1. Package ID: capsiumPkg2
Description
This package includes updated datasets from capsiumPkg1 with action patches applied.
Version
2.0
Action History Location
/new-package/action-history `
8.1.1. Saving Data Changes in Datasets in a Composite Capsium Package That Contains the Current Package
To save data changes in datasets in a composite Capsium package, the following configuration is required:
Configuration File
save-composite.json
Attributes
originalPackageId
The identifier of the original Capsium package. Must be a string.
compositePackageId
The identifier for the composite Capsium package. Must be a string.
internalActionHistoryPath
The path to the action history folder within the composite Capsium package. Must be a valid internal path.
Example: `json { “originalPackageId”: “capsiumPkg1”, “compositePackageId”: “compositeCapsiumPkg1”, “internalActionHistoryPath”: “internal/action-history” } `
The process for saving data changes in a composite Capsium package includes the following steps:
Identify Changes: Collect all action patches related to the dataset modifications.
Create Composite Package Structure: Ensure that the composite package contains the current package and an action history folder.
Include Action Patches: Copy the action patches to the action history folder within the composite package.
Update Metadata: Modify the storage.json and other relevant configuration files to reflect the composite package and its contents.
Validate Package: Ensure that the composite package meets all Capsium package requirements and is properly versioned.
Example process: `shell # Collect action patches cp /path/to/action-history/* /composite-package/internal/action-history/
9. Create composite package structure
mkdir /composite-package/internal cp -r /original-package/* /composite-package/internal/
10. Update metadata
jq ’.packages += [{”id”: “compositeCapsiumPkg1”, “internalActionHistoryPath”: “internal/action-history”}]’ /composite-package/storage.json > /composite-package/storage_tmp.json mv /composite-package/storage_tmp.json /composite-package/storage.json
11. Validate package
capsium-validate /composite-package `
Additional considerations for creating a composite Capsium package:
Dependency Management
Ensure that the composite package correctly references the current package and any other dependencies.
Namespace Handling
Manage namespaces to avoid conflicts between datasets from different packages.
Testing
Thoroughly test the composite package to ensure that the data changes are correctly applied and all functionalities work as expected.
Example of dependency management: `json { “compositePackageId”: “compositeCapsiumPkg1”, “dependencies”: [ { “packageId”: “capsiumPkg1”, “version”: “1.0” } ], “internalActionHistoryPath”: “internal/action-history” } `
Example of namespace handling: `json { “datasetNamespaces”: { “capsiumPkg1”: “namespace1”, “compositeCapsiumPkg1”: “namespace2” } } `
Example of testing script: `shell # Test script for composite package capsium-test /composite-package
Appendix A
(informative)
Ruby packager
The capsium Ruby gem (version 0.6.0, MIT licensed, copyright Ribose) is the reference packager and reactor for Capsium packages. It packages a directory into a .cap file, unpacks, inspects and validates packages, and includes the WEBrick-based reactor described in Annex B. This annex describes the packager side of the gem; it requires Ruby 3.2 or later.
A.1. Architecture
The gem is organized under lib/capsium with autoload-only loading: the top level Capsium module declares autoload for every component (Package, Packager, Reactor, Cli, Converters, ThorExt, VERSION), so no implementation file is loaded until the corresponding constant is first referenced.
Package domain objects are modelled with lutaml-model (Lutaml::Model::Serializable). Each configuration file of Clause 5 has a dedicated model with explicit JSON mappings:
metadata.json — Capsium::Package::MetadataData (with a nested Repository model);
manifest.json — the manifest model, keyed by package-relative resource path;
routes.json — the routes model (index plus a routes array);
storage.json — the storage model (storage.dataSets);
security.json — the security model (security.integrityChecks).
The metadata model carries the field-level format rules of Clause 5 (kebab-case name, semantic version, URI guid, UUID uuid) and reports human-readable format errors; these rules drive the validate command.
The command-line interface is built on Thor. Capsium::Cli exposes the subcommands package, reactor, and convert — implemented as Thor subcommand classes under lib/capsium/cli — plus a top-level install command for registry installs.
Notable dependencies: lutaml-model (domain models), thor (CLI), rubyzip (.cap compression and extraction), marcel (MIME type detection when generating manifests), json-schema (dataset schema validation), sqlite3 (SQLite datasets), listen and webrick (reactor, Annex B).
A.2. Installation
gem install capsiumA.3. Usage
A.3.1. Packing a package
capsium package pack [--force/-f] [--bundle-deps] [--store DIR] [--registry R] path-to-package
pack generates manifest.json and routes.json when absent, writes security.json with a SHA-256 checksum of every package file except security.json itself, and compresses the directory into {name}-{version}.cap, with name and version taken from metadata.json. Without --force, an existing target file aborts the build with Capsium::Packager::FileAlreadyExistsError.
With --bundle-deps, the declared dependencies are resolved from the store or registry and encapsulated under packages/ with a packages/index.json index ([module-composite]), producing a self-contained composite package.
EXAMPLE — Sample pack session
$ capsium package pack -f spec/fixtures/bare-package
Package created: bare-package-0.1.0.cap
A.3.2. Unpacking a package
capsium package unpack bare-package-0.1.0.cap [-o/--output my_bare_package]
When -o is omitted, the package is unpacked into a directory named after the .cap file. Extraction is zip-slip safe: entries whose names would escape the destination (absolute paths, drive letters, .. segments) are rejected with Capsium::Packager::UnsafeEntryError.
A.3.3. Validating a package
capsium package validate path-to-package-or-cap
Validation runs a per-check report and exits with status 1 on any failure:
metadata: required fields present and well-formed (kebab-case name, semver version, URI guid, UUID);
manifest: every resource exists on disk;
routes: route targets exist; dataset routes live under /api/v1/data/; the index resolves to an existing HTML file;
storage: dataset sources (and schemas) exist; dataset data passes JSON-schema validation;
security: checksums match when security.json is present;
content: no external http(s) references in packaged content files.
A.3.4. Inspecting a package
capsium package info path-to-package
capsium package metadata path-to-package
capsium package manifest path-to-package
capsium package routes path-to-package
capsium package storage path-to-package
info prints the package path, routes, and manifest; the other commands pretty-print the corresponding configuration as JSON.
A.4. Canonical and legacy schema support
The gem reads both the canonical configuration forms of Clause 5 and the legacy (pre-0.2) gem forms, normalizing the legacy forms on read; writers emit only the canonical forms. For example, a legacy dependencies array of {name, version} objects in metadata.json is accepted and normalized to the canonical object form mapping each dependency GUID to its version range. The full set of accepted legacy forms and their normalization is given in annex E.
A.5. Registry operations
The gem implements the static registry of [module-registries]: publishing to a filesystem registry, and resolving and installing from a directory or an HTTPS registry (plain HTTP is accepted for loopback addresses only).
capsium package push example-package-1.0.0.cap --registry /srv/registry
capsium install capsium://example.com/hello-world \
--constraint ">=1.0.0" --registry https://registry.example.com \
--store ~/.capsium/store
push validates the package, copies it into the registry, recomputes its SHA-256 checksum and size, and rewrites index.json atomically (temporary file plus rename). A remote registry is read-only. install resolves the newest version satisfying the constraint, verifies the downloaded .cap against the indexed checksum — rejecting it on mismatch — and installs it into the store as <name>-<version>.cap, updating the store index. The --registry and --store options default to the CAPSIUM_REGISTRY and CAPSIUM_STORE environment variables.
A.6. security.json generation
At pack time the gem generates security.json (Clause 5, Security) with checksumAlgorithm SHA-256 and a checksums object holding the SHA-256 hex digest of every file in the package except security.json itself:
{
"security": {
"integrityChecks": {
"checksumAlgorithm": "SHA-256",
"checksums": {
"content/index.html": "d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2",
"metadata.json": "e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3"
}
}
}
}
When security.json is present, loading a package verifies it and raises Capsium::Package::Security::IntegrityError on mismatch.
A.7. Programmatic usage
require 'capsium'
package = Capsium::Package.new('example-package-1.0.0.cap')
puts package.metadata.name
errors = package.verify_integrity # typed errors, empty when valid
packager = Capsium::Packager.new
cap_file = packager.pack(package, force: true)
packager.unpack(cap_file, 'output-directory')
The public API ships with RBS signatures in sig/.
Appendix B
(informative)
Ruby reactor
The capsium Ruby gem (Annex A) ships a built-in reactor, Capsium::Reactor, implemented on WEBrick. It activates one or more packages from local .cap files, package directories, or capsium:// registry references, and serves their routes over HTTP, together with the Monitoring HTTP API of [reactor-clause].
B.1. Starting the reactor
capsium reactor serve my_package.cap [more.cap ...] \
[--mount PATH=SOURCE] [--port 8864] [--store DIR] [--registry R] \
[--workdir DIR] [--do_not_listen]
The default port is 8864. While serving, the reactor watches the package directory with the listen gem and restarts the server when files change, so edits to a package directory are picked up without manual restarts.
A source of the form capsium://<guid> is installed from the configured registry into the package store first and served from there ([module-registries]).
B.2. Multiple mounted packages
Several packages can be served at once, either as multiple source arguments or as repeatable --mount PATH=SOURCE mount maps ({path, source}, [reactor-clause]). When a mount path is not given, the first package is mounted at / and every further package at /<metadata.name>/; duplicate mount paths abort startup with Capsium::Reactor::MountConflictError. Requests are dispatched to the longest matching mount prefix, and the introspection endpoints aggregate all mounted packages.
B.3. Route serving
On startup the reactor mounts every route declared by the package’s routes.json, plus the introspection paths, as WEBrick mount procs, and resolves each incoming request path against the package routes:
an unknown path is answered 404 Not Found;
a resource route serves the referenced file with the MIME type recorded in manifest.json (falling back to content-based detection), and a 404 when the file is missing on disk;
a dataset route ({path, dataset}) serves the dataset from storage.json as application/json under its /api/v1/data/<id> mount — JSON natively, YAML parsed and served as JSON — and a 404 when the dataset is unknown;
any other route kind, including dynamic handler routes ([module-handler-routes]), is answered 501 Not Implemented.
Unless a route declares its own headers, resource responses carry Cache-Control: public, max-age=31536000 (one year), the reactor’s configurable default; a route’s headers replace the default for the headers they declare. Method restrictions are enforced on the introspection, data, and write APIs as specified below.
B.4. Integrity verification on load
Loading a package that contains security.json verifies every listed SHA-256 checksum before anything is served; a mismatch raises Capsium::Package::Security::IntegrityError and the package is rejected (Clause 5, Security).
B.5. Writable packages
The reactor implements the writable packages module ([module-writable-packages]) for mounts whose package is writable. Overlay state lives under the reactor work directory (--workdir) at overlays/<name>/, persists across restarts over the same work directory, and every write is visible on the next request.
Write gate
A package whose metadata declares readOnly: true answers every write with 403 Forbidden.
Dataset CRUD
POST /api/v1/data/<dataset> creates an item (201
Location); GET .../<id>, PUT .../<id>, and DELETE .../<id> read, replace, and delete one item (200 / 200 / 204, 404 when absent). Malformed JSON is answered 400, identifier conflicts 409, schema violations 422 with the validation messages, unsupported methods 405, and writes to SQLite datasets 501. Items are identified by their id field, else by their 1-based index as a string.Content writes
PUT <path> writes content into the overlay (creating the route on demand, lifting any tombstone) and DELETE <path> records a tombstone in .capsium-tombstones; the path resolves 404 thereafter, even when a lower layer holds the file.
GraphQL
A mount with at least one JSON-backed dataset exposes POST|GET <mount>/graphql with a list query field (optional id: argument) and create<Dataset> / update<Dataset> / delete<Dataset> mutations per dataset; item types derive from the dataset’s JSON schema, falling back to a permissive JSON scalar. Request failures are reported in the GraphQL errors array.
Save
POST /package/<name>/save folds base package and overlays into a new <name>-<version>.cap with the patch version incremented: tombstones are applied, dataset logs replayed into the data files, and manifest.json, routes.json, and security.json regenerated. The saved package passes package validation and is unsigned; the response returns its path, sha256, name, and version.
B.6. Introspection endpoints
While serving, the reactor answers the Monitoring HTTP API ([reactor-clause]) as application/json. The endpoints are GET-only; other methods are answered 405 Method Not Allowed.
GET /api/v1/introspect/metadata # => {"packages": [{"name", "version", "author", "description"}]}
GET /api/v1/introspect/routes # => {"routes": [{"package", "routes": [{"method", "path"}]}]}
GET /api/v1/introspect/content-hashes # => {"contentHashes": [{"package", "hash"}]}
GET /api/v1/introspect/content-validity # => {"contentValidity": [{"package", "valid", "lastChecked", "signed", "encrypted", "signatureValid"?, "reason"?}]}- metadata
wraps the served packages’ name, version, author, and description in the packages list shape of [reactor-clause], aggregating all mounted packages.
- routes
lists every served route with its HTTP method (defaulting to GET) and path.
- content-hashes
reports the SHA-256 of the .cap blob when the package was served from one. For a directory source there is no blob, so the hash covers the canonical (sorted-key) JSON serialization of the package content checksums — the same data security.json integrity checks carry.
- content-validity
re-verifies the package against security.json on every request and reports the outcome with a UTC lastChecked timestamp; reason lists the integrity errors when valid is false. Entries also report signed and encrypted, and signatureValid for signed packages.
Example content-validity response for a healthy package:
{
"contentValidity": [
{
"package": "example-package",
"valid": true,
"lastChecked": "2024-05-28T12:34:56Z",
"signed": true,
"encrypted": false,
"signatureValid": true
}
]
}
B.7. Reactor-level and per-package introspection
The reactor also answers the reactor-level and per-package introspection endpoints of [reactor-clause], GET-only and as application/json:
GET /introspect/status # => {"status": "running", "uptime": <seconds>, "packagesLoaded": <n>}
GET /introspect/config # => {"port", "storeDir", "cacheControl", "authEnabled", "registry"}
GET /introspect/metrics # => {"uptime": <seconds>, "requestsTotal": <n>, "requestsByStatus": {"<status>": <n>}}
GET /package/<name>/status # => {"package", "version", "status": "loaded", "valid"}
GET /package/<name>/metadata # => {"name", "version", "description", "author", "guid"}
GET /package/<name>/logs # => {"package", "logs": [...]} (?lines=N, default 100, clamped to 1..1000)/introspect/config redacts secrets: userinfo in configured URLs is stripped and deploy.json secrets never appear. The per-package endpoints resolve <name> against the metadata names of all mounted packages and answer 404 Not Found for unknown names.
Appendix C
(informative)
Apache httpd reactor
No Apache httpd implementation of a Capsium reactor exists at the time of writing. This annex provides guidance for realizing one, mapping the reactor responsibilities of [reactor-clause] onto standard Apache httpd modules. Because a Capsium package is static by design (Clause 4), most of the serving behavior can be expressed in declarative httpd configuration; only integrity verification and the Monitoring HTTP API require external tooling or a dynamic backend.
C.1. Extracting the package to a docroot
A .cap file is a ZIP archive (Clause 5, Packaging options). Deployment starts by extracting it into a directory that becomes (part of) the Apache document root:
mkdir -p /var/www/capsium/example-package-1.0.0
cd /var/www/capsium/example-package-1.0.0
unzip /srv/capsium/packages/example-package-1.0.0.cap
Extraction should reject archive entries whose paths would escape the destination directory (absolute paths, .. segments), as required of packagers in [management-clause]. After extraction, the served content tree is available at the docroot and the configuration files (metadata.json, manifest.json, routes.json, security.json) are available for deriving the site configuration.
C.2. Integrity pre-verification at deploy time
Apache httpd itself does not verify security.json. Integrity verification (Clause 5, Security) should therefore be performed at deploy time by external tooling, before the extracted directory is published: recalculate the SHA-256 of every extracted file and compare it against security.integrityChecks.checksums; refuse to publish the docroot on any mismatch. The capsium package validate command (Annex A) performs exactly this check, as does a short script in any language with a SHA-256 library.
C.3. Mapping routes.json to Alias and mod_rewrite
Each resource route in routes.json maps a URL path to a package-relative file. Static mappings translate directly into Alias directives or, for rule shapes such as the dual HTML routes of Clause 5 (base name and full file name), into mod_rewrite rules:
Alias "/styles.css" "/var/www/capsium/example-package-1.0.0/content/styles.css"
RewriteEngine On
# Dual HTML routes: /page serves content/page.html
RewriteCond "%{DOCUMENT_ROOT}/content/$1.html" -f
RewriteRule "^/([^/]+)$" "/content/$1.html" [PT]
The index route of routes.json maps to DirectoryIndex. Dataset routes under /api/v1/data/ (Clause 5, Dataset routes) map to the JSON rendering of the dataset: for file-backed datasets this can again be an Alias to a pre-generated JSON file; database-backed datasets require a small dynamic backend (see the introspection paragraph below).
C.4. Serving manifest-derived MIME types
manifest.json records the MIME type of every resource (Clause 5, Manifest file). httpd’s own mime.types covers the common types; package-specific or unusual types recorded in the manifest can be added with mod_mime:
AddType application/vnd.capsium.package .cap
AddType text/javascript .js
C.5. Cache-Control via mod_headers
Reactors conforming to [reactor-clause] serve static resources with a long-lived Cache-Control policy by default. With mod_headers:
<Directory "/var/www/capsium/example-package-1.0.0/content">
Header set Cache-Control "public, max-age=31536000"
</Directory>
Per-route header declarations in routes.json (Clause 5, Header responses) translate into more specific Header directives scoped by <Location>.
C.6. Basic authentication
The Apache passwd authentication defined for packages ([module-authentication]) is native httpd functionality. A package that declares .htpasswd basic authentication maps to:
<Directory "/var/www/capsium/example-package-1.0.0/content">
AuthType Basic
AuthName "Restricted Access"
AuthUserFile /etc/httpd/capsium/example-package.htpasswd
Require valid-user
</Directory>
The .htpasswd file is managed with the htpasswd utility, must be stored outside the served docroot, and passwords should be hashed with bcrypt ([module-authentication]). OAuth authentication defined by a package requires a dynamic backend or a module such as mod_auth_openidc, with the client secret kept outside the package as specified in [module-authentication].
C.7. Exposing the introspection API
The Monitoring HTTP API ([reactor-clause]) is dynamic and cannot be served from static files alone, because content-validity re-verifies the package at request time. Options for exposing it behind httpd include:
a CGI or FastCGI script that reads the extracted package’s configuration files and recomputes the verification on demand;
a small application server (for example the Ruby reactor of Annex B running alongside httpd) reverse-proxied with mod_proxy:
ProxyPass "/api/v1/introspect" "http://127.0.0.1:8864/api/v1/introspect"
ProxyPassReverse "/api/v1/introspect" "http://127.0.0.1:8864/api/v1/introspect"
Whichever backend is chosen, the four endpoints of [reactor-clause] — /api/v1/introspect/metadata, /routes, /content-hashes, and /content-validity — should answer GET requests with the JSON shapes defined there, and reject other methods with 405.
Appendix D
(informative)
nginx (OpenResty) reactor
The capsium-lua project (version 0.4.0, MIT licensed) is a Capsium reactor built on OpenResty, the Lua-enabled nginx distribution. It serves Capsium packages (.cap files) directly through nginx with Lua: a .cap file dropped into the packages directory is extracted on demand, verified against security.json, and routed, with optional per-mount configuration for paths, domains, headers, caching, and CORS. Mounts may also reference packages by capsium:// URI, pulling them from a static registry ([module-registries]). Serving is read-only: the reactor has no write API.
D.1. Architecture
The implementation keeps a single framework-agnostic core and a thin nginx glue layer, with no duplicated logic:
lib/capsium/ Framework-agnostic core (the rock)
├── utils.lua Pure helpers (tables, JSON files, paths,
│ URL userinfo redaction)
├── mime.lua MIME type detection (text/javascript per RFC 9239)
├── csv.lua Minimal CSV parser (dataset support)
├── yaml.lua Minimal YAML parser (dataset support)
├── semver.lua Semantic versioning ranges
├── crypto.lua Decryption support (encrypted packages)
├── log_buffer.lua Per-worker ring buffer for request logs
├── reactor.lua Reactor core: package management + introspection
├── registry.lua Static registry client (resolve/install)
├── auth/ Authentication (basic auth, OAuth2)
├── package/
│ ├── package.lua Package model (OOP): load/normalize/resolve
│ ├── extractor.lua Atomic .cap extraction (tmp dir + rename)
│ ├── router.lua Schema normalization + route auto-generation
│ ├── security.lua security.json parsing + SHA-256 verification
│ ├── store.lua Package store (dependency resolution)
│ ├── composite.lua Composite packages (dependency content)
│ └── decrypter.lua Package decryption
└── adapters/
├── nginx.lua fs/zip adapters (LuaFileSystem + lua-zip)
└── hash.lua SHA-256 (resty.sha256 in OpenResty,
pure-Lua fallback elsewhere)
lua/capsium/ nginx glue (only code that touches ngx)
├── init.lua Entry point: wires adapters into the core,
│ request handling, introspection API
└── config.lua config.json loading + mount resolution
The core never references ngx; the glue never implements domain logic. Other platforms can plug in their own filesystem, zip, and hash adapters.
D.2. Configuration
Configuration is read from $CAPSIUM_CONFIG_PATH, else the first existing of /etc/capsium/config.json, /etc/capsium/nginx/config.json, /var/lib/capsium/config.json, ./config.json. Top-level keys:
- package_dir
Directory containing .cap files (default /var/lib/capsium/packages).
- extract_dir
Extraction target (default /var/lib/capsium/extracted).
- cache_enabled
Use the capsium_cache shared dict to cache introspection responses (default true).
- cache_ttl
TTL in seconds for the shared-dict cache (default 3600).
- packages_config_dir
Optional directory with per-package <name>.json mount configs, merged with mounts at startup.
- registry
Default static registry for capsium:// mount sources ([module-registries]); also settable with the CAPSIUM_REGISTRY environment variable.
- store_dir
Package store into which registry-resolved packages are installed; also settable with the CAPSIUM_STORE environment variable.
- mounts
Array of mount entries (below).
Example mount entries:
{
"package_dir": "/var/lib/capsium/packages",
"extract_dir": "/var/lib/capsium/extracted",
"cache_enabled": true,
"cache_ttl": 3600,
"registry": "/var/lib/capsium/registry",
"mounts": [
{
"package": "mn-samples-iso-0.1.0.cap",
"path": "/app",
"domain": "example.com",
"options": {
"cache_ttl": 7200,
"headers": {
"X-Frame-Options": "SAMEORIGIN",
"X-Content-Type-Options": "nosniff"
}
}
},
{
"package": "api-1.0.0.cap",
"path": "/api",
"options": {
"cors": {
"allowed_origins": ["https://example.com"],
"allowed_methods": ["GET"],
"allowed_headers": ["Content-Type"],
"max_age": 600
}
}
},
{
"package": "capsium://example.com/registry-app",
"path": "/registry-app",
"version": ">=1.0.0"
}
]
}
Mount entry keys:
- package
Package filename (.cap extension optional), or a capsium://<guid> registry reference (below).
- path
Mount path prefix (default /capsium/<package-name>).
- domain
Virtual host. Advisory: the mount answers on all hosts, and is preferred for the named host when mounts overlap.
- version
Semantic version range for a capsium:// source (default *).
- registry
Per-mount registry override for a capsium:// source.
- store
Per-mount store override for a capsium:// source.
- options.cache_ttl
Static Cache-Control max-age override for this mount (default 31536000, giving public, max-age=31536000).
- options.headers
Extra response headers applied to every response from this mount; an explicit Cache-Control here wins over cache_ttl.
- options.cors
CORS policy: allowed_origins (array, * supported), allowed_methods, allowed_headers, expose_headers, max_age. Preflight OPTIONS requests are answered with 204 when CORS is configured.
- options.encryption.privateKeyPath
Private key used to serve an encrypted package ([module-encryption]).
Every package in package_dir is always also available at /capsium/<package-name> without configuration; /api/v1/introspect, /introspect, and /package are reserved. Mounts are matched longest-path-first, with the domain preference applied first.
D.3. Registry pull
A mount whose package is a capsium://<guid> URI is resolved through the static registry ([module-registries]): on the first request the reactor resolves the newest indexed version satisfying the mount’s version constraint, downloads the .cap from the registry — HTTPS only, except for loopback addresses, with the scheme re-validated on every redirect — and verifies its SHA-256 against the index entry, rejecting the download on mismatch. The verified file is installed atomically (write-then-rename) into the store as <name>-<version>.cap and served from there; a store file whose checksum already matches the index is reused without download. Composite package dependencies are resolved from the store ([module-composite]).
D.4. Extraction and integrity verification
Packages are extracted lazily, on first request. Extraction is atomic: the archive unpacks into a temporary directory that is renamed into place only after metadata.json parses and, when security.json is present, every listed file’s SHA-256 verifies (Clause 5, Security). A package that fails verification is rejected with a 5xx response carrying the reason, and nothing is left at the final extraction path. Archive entries containing .. path segments are refused (zip-slip protection). Re-extraction happens automatically when the .cap file is newer than the extracted tree.
D.5. Manifest-driven routing
Both the canonical configuration forms of Clause 5 and the legacy gem forms are accepted and normalized on read. When routes.json is absent, routes are auto-generated from manifest.json per the routing rules of Clause 5:
index defaults to content/index.html, also routed at /;
every manifest resource under content/ is routed relative to content/;
HTML files get dual routes, /page and /page.html;
every dataset gets /api/v1/data/<id>.
Package routes are GET-only: other methods receive 405 with Allow: GET, HEAD; HEAD is served like GET without a body. Dynamic handler routes ([module-handler-routes]) are accepted by the parser but answered with 501 Not Implemented. Responses carry the media type derived from the file name extension when known — .js is text/javascript per RFC 9239 — with the manifest.json entry as the fallback. Dataset sources are served as application/json — .json served as-is, .csv converted to JSON objects, .yaml parsed by the bundled YAML parser and served as JSON. SQLite datasets are not supported by this reactor; their routes are answered with an error response naming the unsupported dataset.
D.6. Introspection API
The reactor answers the Monitoring HTTP API ([reactor-clause]), GET only:
- /api/v1/introspect/metadata
{packages: [{name, version, author, description}]}
- /api/v1/introspect/routes
{routes: [{package, routes: [{method, path}]}]}
- /api/v1/introspect/content-hashes
{contentHashes: [{package, hash}]} — SHA-256 of the .cap blob.
- /api/v1/introspect/content-validity
{contentValidity: [{package, valid, lastChecked, reason?, signed?, encrypted, signatureValid?}]} — the actual integrity verification result, with the signature and encryption posture of the package.
All introspection endpoints lazily extract and load packages on demand, so a freshly started reactor reports every .cap in package_dir (cold-start introspection). Responses are cached in the capsium_cache shared dict with the configured cache_ttl. Of these endpoints, only /api/v1/introspect is guarded when a package mounted at / declares authentication ([module-authentication]).
D.7. Reactor-level and per-package introspection
The reactor also answers the reactor-level and per-package endpoints of [reactor-clause], GET only:
- /introspect/status
{status: "running", uptime, packagesLoaded} — packagesLoaded counts the configured mounts.
- /introspect/config
The effective configuration, built from a whitelist: authentication secrets and encryption.privateKeyPath can never appear, and userinfo in the registry URL is redacted.
- /introspect/metrics
{uptime, requestsTotal, requestsByStatus} — per status code counts from the capsium_metrics shared dict.
- /package/<name>/status
{package, version, status: "loaded", valid}.
- /package/<name>/metadata
{name, version, description, author, guid}.
- /package/<name>/logs
{package, logs: [...]} from a per-worker ring buffer; ?lines=N selects the number of lines (default 100, clamped to 1..1000).
The per-package endpoints resolve <name> against the metadata names of all mounted packages — resolving registry mounts lazily first — and answer 404 for unknown names.
D.8. Docker deployment
The project ships a Dockerfile whose base image is pinned: openresty/openresty:1.27.1.2-12-alpine-fat (the BASE_IMAGE build arg). A typical deployment mounts the packages and configuration directories into the container:
docker build -t capsium-nginx .
docker run -d -p 8080:80 \
-v $PWD/packages:/var/lib/capsium/packages \
-v $PWD/config:/etc/capsium \
capsium-nginx
Appendix E
(informative)
Legacy configuration forms
Earlier revisions of this document and early implementations used configuration forms that predate the canonical schemas of Clause 5. This annex collects those legacy forms and defines how a reader normalizes them to the canonical schemas.
A conformant reader shall accept every legacy form in this annex and normalize it on read as specified. A conformant writer shall emit only the canonical forms of Clause 5: the legacy forms exist for backward compatibility on read and shall not be produced.
E.1. Legacy manifest
Legacy form
manifest.json with a content array of file / mime entries:
{
"content": [
{ "file": "content/index.html", "mime": "text/html" },
{ "file": "content/styles.css", "mime": "text/css" }
]
}
Normalization
Each entry becomes a resource of the canonical manifest (Clause 5, Manifest file), keyed by its file path, with mime mapped to type and visibility defaulting to exported:
{
"resources": {
"content/index.html": { "type": "text/html", "visibility": "exported" },
"content/styles.css": { "type": "text/css", "visibility": "exported" }
}
}
E.2. Legacy routes
Legacy form 1
routes.json with route entries whose target is a nested target object carrying file or dataset:
{
"routes": [
{ "path": "/", "target": { "file": "content/index.html" } },
{ "path": "/api/v1/data/animals", "target": { "dataset": "animals" } }
]
}
Normalization
The target object is folded into the route entry: file becomes resource, dataset becomes dataset (Clause 5, Resource routing):
{
"routes": [
{ "path": "/", "resource": "content/index.html" },
{ "path": "/api/v1/data/animals", "dataset": "animals" }
]
}
Legacy form 2
routes.json with routes as an object keyed by path, each value describing the target and options of the route:
{
"routes": {
"/": { "resource": "content/index.html" },
"/api/v1/data/animals": { "dataset": "animals" }
}
}
Normalization
The object is converted to the canonical array form: each key becomes the path of a route entry and the value its remaining attributes.
E.3. Legacy storage
Legacy form
storage.json with a datasets array of name, source, format, and schema entries:
{
"datasets": [
{
"name": "animals",
"source": "data/animals.json",
"format": "json",
"schema": "data/animals.schema.json"
}
]
}
Normalization
Each entry becomes a dataset of the canonical storage.dataSets object (Clause 5, Storage), keyed by name. source is kept; a present schema becomes schemaFile with schemaType json-schema; format is dropped — the dataset format is derived from the source file extension:
{
"storage": {
"dataSets": {
"animals": {
"source": "data/animals.json",
"schemaFile": "data/animals.schema.json",
"schemaType": "json-schema"
}
}
}
}
E.4. Legacy dependencies
Legacy form
metadata.json with dependencies as an array of name / version objects:
{
"dependencies": [
{ "name": "capsium://example.com/other-pkg", "version": ">=1.0.0" }
]
}
Normalization
The array is converted to the canonical object form (Clause 5.3.4): each entry’s name becomes a GUID key and its version the version range:
{
"dependencies": {
"capsium://example.com/other-pkg": ">=1.0.0"
}
}