diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50791ae..510590d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [[v0.2.1](https://github.com/The-FireHub-Project/Foundation/compare/v0.2.1...v0.2.0)] – 2026-11-03
+
+### Added
+* Introduce `Origin`, `InvalidOriginException`, and default port resolution for URI schemes by @dieselxxx
+
## [[v0.2.0](https://github.com/The-FireHub-Project/Foundation/compare/v0.2.0...v0.1.0)] – 2026-11-02
### Added
diff --git a/README.md b/README.md
index 0b6323c..29ff1a5 100644
--- a/README.md
+++ b/README.md
@@ -12,84 +12,124 @@
/>
-[](https://github.com/The-FireHub-Project/Foundation/actions/workflows/PHPStan.yml)
-[](https://github.com/The-FireHub-Project/Foundation/actions/workflows/PHPUnit.yml)
-[](https://app.codecov.io/gh/The-FireHub-Project/Foundation/tree/develop)
-
-
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
-The essential PHP core for building domain-driven, clean architecture applications.
-Standard provides the base classes, kernel, domain layer, and minimal runtime utilities needed to start any FireHub project.
+Provides the high-level foundation layer of the FireHub ecosystem. This repository contains developer-focused APIs and reusable building blocks that simplify common programming tasks while maintaining consistency, type safety, and architectural principles across FireHub applications.
+
+The Foundation layer is built on top of the Runtime layer and transforms low-level execution primitives into expressive object-oriented APIs. It provides commonly used components such as string manipulation, date and time handling, mathematical utilities, and other essential application-level abstractions.
+
+This repository represents the developer-facing layer between the FireHub Runtime and application code, enabling clean, readable, and maintainable PHP development.
---
-##
Development Branch
+##
Repository Purpose
+
+FireHub Foundation is the high-level developer API layer of the FireHub ecosystem.
+
+Built on top of FireHub Runtime, it provides expressive, object-oriented abstractions for common programming tasks. The purpose of this layer is to expose simple, consistent, and powerful APIs while hiding low-level implementation details.
-⚠️ **This is the `develop` branch**
+Foundation contains reusable building blocks such as:
-- Unstable
-- APIs may change without notice
-- Not intended for production use
+- String manipulation APIs
+- Date and time handling
+- Mathematical utilities
+- Common application-level abstractions
+- Developer-oriented helper objects
-##
Branch Purpose
+The Foundation layer follows the FireHub architectural principles by separating responsibilities between definition, execution, and usage:
-The `develop` branch is the **primary integration branch** for all ongoing development.
+##
Security
-It serves as the staging area where:
-- Feature branches are merged
-- Bug fixes are integrated
-- Experimental work is stabilized
-- Code is prepared for upcoming releases
+For security reporting and guidelines, please refer to our [SECURITY.md](https://github.com/The-FireHub-Project/.github/blob/master/.github/SECURITY.md) file.
-All **release branches** are created **from `develop`**.
+##
Community
-## Stability Guarantee
+
+
+
-❌ No backward compatibility guarantee
-❌ APIs may change without notice
-❌ Behavior may be incomplete or inconsistent
-❌ Breaking changes are expected
+- Be sure to review the [Code of Conduct](https://github.com/The-FireHub-Project/.github/blob/master/.github/CODE_OF_CONDUCT.md).
+- Read a [Contributing](https://github.com/The-FireHub-Project/.github/blob/master/.github/CONTRIBUTING.md) file to see how you can contribute to this project.
+- Read our [Security policy](https://github.com/The-FireHub-Project/.github/blob/master/.github/SECURITY.md) file to see how you can report a vulnerability.
+- Review the project [Governance model](https://github.com/The-FireHub-Project/.github/blob/master/.github/GOVERNANCE.md), including roles, decision-making, RFC process, and releases.
-This branch is intended **only for contributors and advanced testers**.
+##
Support
-##
Composer Usage (Not Recommended)
+
+
+
+
+
+
+
+
-For internal testing only:
+For help with FireHub products, please refer to the following resources:
-```json
-{
- "require": {
- "the-firehub-project/foundation": "dev-develop"
- }
-}
-```
-⚠️ Never use dev-develop in production.
+- **General questions & discussions**: [GitHub Discussions](https://github.com/orgs/The-FireHub-Project/discussions)
+- **Bug reports & issues**: [Support](https://github.com/The-FireHub-Project/Foundation/issues)
+- **Documentation & guides**: [FireHub Docs](https://the-firehub-project.github.io)
+- **Commercial support** (Pro/Enterprise): contact your account manager
##
Authors and Contributors
@@ -106,4 +146,4 @@ Architecture guidelines, design principles, and ecosystem documentation are avai
This software is licensed under the Apache-2.0 License.
-For more details, read the full license [here](./LICENSE).
\ No newline at end of file
+For more details, read the full license [here](./LICENSE).
diff --git a/src/Uri/Component/Scheme.php b/src/Uri/Component/Scheme.php
index cc530a6..a7dc23f 100644
--- a/src/Uri/Component/Scheme.php
+++ b/src/Uri/Component/Scheme.php
@@ -14,6 +14,7 @@
namespace FireHub\Foundation\Uri\Component;
use FireHub\Core\Type\ValueObject;
+use FireHub\Foundation\Uri\KnownScheme;
use FireHub\Foundation\Uri\Exception\InvalidSchemeException;
use FireHub\Runtime;
@@ -60,6 +61,22 @@ public function __construct (
}
+ /**
+ * ### Returns the known URI scheme
+ *
+ * Resolves the URI scheme to a known scheme enumeration.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Foundation\Uri\Component\Scheme::normalized() To get the normalized scheme.
+ *
+ * @return null|\FireHub\Foundation\Uri\KnownScheme Known scheme or null.
+ */
+ public function known ():?KnownScheme {
+
+ return KnownScheme::tryFrom($this->normalized());
+
+ }
+
/**
* ### Returns the normalized scheme
* @since 1.0.0
diff --git a/src/Uri/Exception/InvalidOriginException.php b/src/Uri/Exception/InvalidOriginException.php
new file mode 100644
index 0000000..03c82e3
--- /dev/null
+++ b/src/Uri/Exception/InvalidOriginException.php
@@ -0,0 +1,33 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.3
+ * @package Foundation
+ */
+
+namespace FireHub\Foundation\Uri\Exception;
+
+use FireHub\Core\Exception\Runtime\InvalidArgumentException;
+
+/**
+ * ### ### Invalid Origin Exception
+ *
+ * Thrown when a URI cannot be represented as a valid tuple-based origin.
+ * @since 1.0.0
+ */
+final class InvalidOriginException extends InvalidArgumentException {
+
+ /**
+ * @inheritdoc
+ *
+ * @since 1.0.0
+ */
+ protected const string DEFAULT_MESSAGE = 'Invalid URI origin.';
+
+}
\ No newline at end of file
diff --git a/src/Uri/KnownScheme.php b/src/Uri/KnownScheme.php
index dd60a55..cccece6 100644
--- a/src/Uri/KnownScheme.php
+++ b/src/Uri/KnownScheme.php
@@ -150,4 +150,32 @@ enum KnownScheme:string {
*/
case GIT = 'git';
+ /**
+ * ### Returns the default network port
+ *
+ * Returns the conventional network port associated with the URI scheme, or null if no default port is defined.
+ * @since 1.0.0
+ *
+ * @return null|int<0, 65535> Default network port.
+ */
+ public function defaultPort ():?int {
+
+ return match ($this) {
+ self::HTTP, self::WS => 80,
+ self::HTTPS, self::WSS => 443,
+ self::FTP => 21,
+ self::SSH => 22,
+ self::LDAP => 389,
+ self::LDAPS => 636,
+ self::SIP => 5060,
+ self::SIPS => 5061,
+ self::IRC => 6667,
+ self::IRCS => 6697,
+ self::NNTP => 119,
+ self::GIT => 9418,
+ default => null
+ };
+
+ }
+
}
\ No newline at end of file
diff --git a/src/Uri/Origin.php b/src/Uri/Origin.php
new file mode 100644
index 0000000..2732553
--- /dev/null
+++ b/src/Uri/Origin.php
@@ -0,0 +1,257 @@
+
+ * @copyright 2026-present The FireHub Project - All rights reserved
+ * @license https://opensource.org/license/Apache-2-0 Apache License, Version 2.0
+ *
+ * @php-version >=8.2
+ * @package Foundation
+ */
+
+namespace FireHub\Foundation\Uri;
+
+use FireHub\Core\Type\ValueObject;
+use FireHub\Foundation\Uri;
+use FireHub\Foundation\Uri\Component\ {
+ Host, Port, Scheme
+};
+use FireHub\Foundation\Uri\Exception\InvalidOriginException;
+use FireHub\Runtime;
+
+/**
+ * ### URI Origin
+ *
+ * Represents an immutable tuple-based origin.
+ *
+ * An origin is identified by its scheme, host, and effective port.
+ *
+ * Supports HTTP, HTTPS, WS, WSS, and FTP origins.
+ *
+ * Default ports are normalized during serialization and comparison.
+ *
+ * The origin does not include URI user information, path, query, or fragment.
+ * @since 1.0.0
+ *
+ * @extends \FireHub\Core\Type\ValueObject
+ */
+final readonly class Origin extends ValueObject {
+
+ /**
+ * ### Constructor
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Core\Type\ValueObject::guard() As a guard.
+ * @uses \FireHub\Foundation\Uri\Component\Host::value() To get the host value.
+ * @uses \FireHub\Runtime\Str\SB\Casing::toLower() To normalize the scheme.
+ *
+ * @param \FireHub\Foundation\Uri\Component\Scheme $scheme
+ * Origin scheme.
+ *
+ * @param \FireHub\Foundation\Uri\Component\Host $host
+ * Origin host.
+ *
+ * @param null|\FireHub\Foundation\Uri\Component\Port $port [optional]
+ * Explicit origin port or null to use the scheme's default port.
+ *
+ *
+ * @throws \FireHub\Foundation\Uri\Exception\InvalidOriginException If the origin components are invalid.
+ * @throws \FireHub\Core\Exception\FireHubException If the condition is not met.
+ * @throws \FireHub\Core\Type\Exception\ValueObjectException If the exception is not a FireHubException.
+ *
+ * @return void
+ */
+ public function __construct (
+ private Scheme $scheme,
+ private Host $host,
+ private ?Port $port = null
+ ) {
+
+ $scheme_value = Runtime\Str\SB\Casing::toLower($scheme->value());
+
+ $this->guard(
+ fn() => match ($scheme_value) {
+ KnownScheme::HTTP->value, KnownScheme::HTTPS->value, KnownScheme::WS->value, KnownScheme::WSS->value,
+ KnownScheme::FTP->value
+ => true,
+ default => false
+ },
+ fn() => new InvalidOriginException(
+ 'The URI scheme does not support a tuple-based origin.'
+ )
+ );
+
+ $this->guard(
+ fn() => $host->value() !== '',
+ fn() => new InvalidOriginException(
+ 'An origin must contain a host.'
+ )
+ );
+
+ }
+
+ /**
+ * ### Creates an origin from a URI
+ *
+ * Extracts the scheme, host, and port from an existing URI.
+ *
+ * The URI path, query, fragment, and user information do not participate in origin identity.
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Foundation\Uri::scheme() To get the URI scheme.
+ * @uses \FireHub\Foundation\Uri::authority() To get the URI authority.
+ * @uses \FireHub\Foundation\Uri\Component\Host::value() To get the host value.
+ * @uses \FireHub\Foundation\Uri\Component\Authority::value() To get the authority value.
+ * @uses \FireHub\Foundation\Uri\Component\Authority::port() To get the authority port.
+ *
+ * @param \FireHub\Foundation\Uri $uri
+ * URI from which to derive the origin.
+ *
+ *
+ * @throws \FireHub\Foundation\Uri\Exception\InvalidOriginException If the origin components are invalid.
+ * @throws \FireHub\Core\Exception\FireHubException If the condition is not met.
+ * @throws \FireHub\Core\Type\Exception\ValueObjectException If the exception is not a FireHubException.
+ *
+ * @return self Derived origin.
+ */
+ public static function fromUri (Uri $uri):self {
+
+ $scheme = $uri->scheme();
+ $authority = $uri->authority();
+
+ if ($scheme === null || $authority === null)
+ throw new InvalidOriginException(
+ 'The URI must contain a scheme and authority.'
+ );
+
+ $host = $authority->host();
+
+ if ($host->value() === '')
+ throw new InvalidOriginException(
+ 'The URI must contain a host.'
+ );
+
+ return new self(
+ $scheme,
+ $host,
+ $authority->port()
+ );
+
+ }
+
+ /**
+ * ### Gets the origin scheme
+ * @since 1.0.0
+ *
+ * @return \FireHub\Foundation\Uri\Component\Scheme Origin scheme.
+ */
+ public function scheme ():Scheme {
+
+ return $this->scheme;
+
+ }
+
+ /**
+ * ### Gets the origin host
+ * @since 1.0.0
+ *
+ * @return \FireHub\Foundation\Uri\Component\Host Origin host.
+ */
+ public function host ():Host {
+
+ return $this->host;
+
+ }
+
+ /**
+ * ### Gets the origin port
+ * @since 1.0.0
+ *
+ * @return null|\FireHub\Foundation\Uri\Component\Port Explicit origin port.
+ */
+ public function port ():?Port {
+
+ return $this->port;
+
+ }
+
+ /**
+ * ### Gets the effective origin port
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Foundation\Uri\Component\Port::value() To get the port value.
+ * @uses \FireHub\Foundation\Uri\Component\Scheme::known() To get the scheme known information.
+ * @uses \FireHub\Foundation\Uri\KnownScheme::defaultPort() To get the default port.
+ *
+ * @throws \FireHub\Foundation\Uri\Exception\InvalidOriginException If the origin scheme does not define a
+ * default port.
+ *
+ * @return int Effective origin port.
+ */
+ public function effectivePort ():int {
+
+ return $this->port?->value()
+ ?? $this->scheme->known()?->defaultPort()
+ ?? throw new InvalidOriginException(
+ 'The origin scheme does not define a default port.'
+ );
+
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Foundation\Uri\Component\Scheme::normalized() To get the normalized scheme.
+ * @uses \FireHub\Foundation\Uri\Component\Host::normalized() To get the normalized host.
+ * @uses \FireHub\Foundation\Uri\Component\Port::value() To get the port value.
+ * @uses \FireHub\Foundation\Uri\Component\Scheme::known() To get the scheme known information.
+ * @uses \FireHub\Foundation\Uri\KnownScheme::defaultPort() To get the default port.
+ *
+ * @return non-empty-string Serialized origin.
+ */
+ public function value ():string {
+
+ $scheme = $this->scheme->normalized();
+ $host = $this->host->normalized();
+
+ $default_port = $this->scheme->known()?->defaultPort();
+ $port = $this->port?->value();
+
+ return $scheme.'://'.$host
+ .(
+ $port !== null && $port !== $default_port
+ ? ':'.$port
+ : ''
+ );
+
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @since 1.0.0
+ *
+ * @uses \FireHub\Foundation\Uri\Component\Scheme::normalized() To normalize the scheme.
+ * @uses \FireHub\Foundation\Uri\Component\Host::normalized() To normalize the host.
+ * @uses \FireHub\Foundation\Uri\Origin::effectivePort() To get the effective port.
+ *
+ * @throws \FireHub\Foundation\Uri\Exception\InvalidOriginException If the origin scheme does not define a
+ * default port.
+ *
+ * @return non-empty-string Normalized origin identity.
+ */
+ protected function comparisonValue ():string {
+
+ return $this->scheme->normalized()
+ .'://'
+ .$this->host->normalized()
+ .':'
+ .$this->effectivePort();
+
+ }
+
+}
\ No newline at end of file