Initial project push.

This commit is contained in:
dan612 2026-01-15 09:50:55 -05:00
commit c4312feb95
226 changed files with 32233 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
database/origo.db
scripts/default-content.sh

15
Dockerfile Normal file
View File

@ -0,0 +1,15 @@
FROM php:8.4-fpm
# Install SQLite extension and Node.js
RUN apt-get update && apt-get install -y \
sqlite3 \
libsqlite3-dev \
curl \
&& docker-php-ext-install pdo_sqlite \
&& curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
COPY ./src .

37
TODO.md Normal file
View File

@ -0,0 +1,37 @@
# To Do
- [ ] Need to create an agent to send data
- [ ] Need to create api endpoint to handle request
- [ ] Need a new table for accounts
- Users can belong to accounts
## How will authentication work?
JWT or Oauth based tokens
## Lightweight agent
What data will the agent need to send:
1. Gather user data
2. Account id
3. Site id
The agent should be availableas a simple script.
## API Endpoints
```
/api/webhook
```
This will receive a JSON payload from the agent
It will parse the payload to store the data for later display
```
/api/dataset/{account_id}/{site_id}
```
This will provide all metrics to allow displaying
information about the account.:w
```
/api/site-list/{account_id}
```
This will provide a list of sites for a given account.
Each account can have unlimited sites. Each site has an id.

24
composer.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "dan612/origo",
"type": "project",
"autoload": {
"psr-4": {
"Origo\\": "src/"
}
},
"authors": [
{
"name": "dan612",
"email": "dan@danchadwickdesign.com"
}
],
"require": {
"guzzlehttp/guzzle": "^7.10"
},
"scripts": {
"start": "sh scripts/start.sh",
"rebuild": "sh scripts/rebuild.sh",
"theme": "sh scripts/theme.sh",
"db-reset": "sh scripts/db-setup.sh"
}
}

615
composer.lock generated Normal file
View File

@ -0,0 +1,615 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b80dde420686a2bebce99683c667426c",
"packages": [
{
"name": "guzzlehttp/guzzle",
"version": "7.10.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2025-08-23T22:36:01+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://sagikazarmark.hu"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"time": "2025-08-23T21:21:41+00:00"
},
{
"name": "psr/http-client",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client"
},
"time": "2023-09-23T14:17:50+00:00"
},
{
"name": "psr/http-factory",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
"message",
"psr",
"psr-17",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory"
},
"time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
"version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"time": "2023-04-04T09:54:51+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph Khattar",
"email": "ralph.khattar@gmail.com"
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

90
database/schema.sql Normal file
View File

@ -0,0 +1,90 @@
-- schema.sql
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
password TEXT NOT NULL,
status INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
session_id TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
task TEXT UNIQUE NOT NULL,
description TEXT,
status TEXT,
external_url TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS permissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
permission TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
account_id INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS user_accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
account_id INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE,
UNIQUE (user_id, account_id)
);
CREATE TABLE IF NOT EXISTS pageviews (
id INTEGER PRIMARY KEY AUTOINCREMENT,
account_id INTEGER NOT NULL,
page TEXT NOT NULL,
user_agent TEXT,
referrer TEXT,
ip TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_pageviews_account_id
ON pageviews(account_id);
CREATE INDEX IF NOT EXISTS idx_pageviews_created_at
ON pageviews(created_at);
CREATE INDEX IF NOT EXISTS idx_pageviews_account_time
ON pageviews(account_id, created_at);
INSERT INTO users (username, email, password) VALUES
('bender', 'dan@danchadwickdesign.com', 'aa7101dc6e2fe541ac5a44352c24d15052723b70ceecd5fc6d7fe71d0721c9aa');
INSERT INTO permissions (user_id, permission) VALUES
(1, 'admin');
INSERT INTO accounts (account_id) VALUES ("3116a529b262b9f3cc08a4ba87d5d833");
INSERT INTO user_accounts (user_id, account_id) VALUES (1,"3116a529b262b9f3cc08a4ba87d5d833");
INSERT INTO tasks (user_id, task, description, status, external_url) VALUES
(1, 'Buy milk', 'this task requires you to go to the store and buy milk.', 'pending', 'https://www.google.com');
INSERT INTO tasks (user_id, task, description, status, external_url) VALUES
(1, 'Buy eggs', 'this task requires you to go to the store and buy eggs.', 'pending', 'https://www.google.com');

14
docker-compose.yml Normal file
View File

@ -0,0 +1,14 @@
services:
app:
build: .
ports:
- "127.0.0.1:9000:9000"
volumes:
- .:/app
- ./database:/app/database # Persists your SQLite file
networks:
- app-network
networks:
app-network:
driver: bridge

43
index.php Normal file
View File

@ -0,0 +1,43 @@
<?php
require 'vendor/autoload.php';
use Origo\Services\Template;
use Origo\Entity\User;
use Origo\Services\Router;
use Origo\Services\Renderer;
use Origo\Services\Request;
// Need to handle api routes differently.
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
/* 1|bender|dan@danchadwickdesign.com|2025-12-19 00:51:10|aa7101dc6e2fe541ac5a44352c24d15052723b70ceecd5fc6d7fe71d0721c9aa|0 */
$router = new Router();
$renderer = new Renderer();
// If the route doesn't, render the 403 page.
if (!$router->routeExists($path)) {
echo $renderer->render403();
die();
}
// If the user does not have a session cookie, 403.
// now we dont have to do this in every controller.
// Still allow login on homepage.
$request = new Request();
$allowed_paths = ['/', '/user-login'];
if (
!$request->getCookie('ORIGOSESS') &&
!in_array($path, $allowed_paths)
) {
echo $renderer->render403();
die();
}
$controller = $router->getRouteController($path);
$controller_cl = new $controller();
$response = $controller_cl->getResponse();
echo $response;
?>

1
node_modules/.bin/esbuild generated vendored Symbolic link
View File

@ -0,0 +1 @@
../esbuild/bin/esbuild

522
node_modules/.package-lock.json generated vendored Normal file
View File

@ -0,0 +1,522 @@
{
"name": "origo",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@esbuild/aix-ppc64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
"integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
"cpu": [
"ppc64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
"integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
"cpu": [
"arm"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
"integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
"integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
"integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
"integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
"integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
"integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
"integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
"cpu": [
"arm"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
"integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
"integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
"cpu": [
"ia32"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
"integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
"cpu": [
"loong64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
"integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
"cpu": [
"mips64el"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
"integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
"cpu": [
"ppc64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
"integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
"cpu": [
"riscv64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
"integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
"cpu": [
"s390x"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
"integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
"integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
"integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
"integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
"integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
"integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
"integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
"integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
"cpu": [
"arm64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
"integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
"cpu": [
"ia32"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
"integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
"cpu": [
"x64"
],
"dev": true,
"ideallyInert": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/dcjs": {
"version": "1.0.0",
"resolved": "git+ssh://git@github.com/dan612/dcjs.git#9193af54a2c4de341c458b320a0c6b816e3c0134",
"license": "ISC"
},
"node_modules/esbuild": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.2",
"@esbuild/android-arm": "0.27.2",
"@esbuild/android-arm64": "0.27.2",
"@esbuild/android-x64": "0.27.2",
"@esbuild/darwin-arm64": "0.27.2",
"@esbuild/darwin-x64": "0.27.2",
"@esbuild/freebsd-arm64": "0.27.2",
"@esbuild/freebsd-x64": "0.27.2",
"@esbuild/linux-arm": "0.27.2",
"@esbuild/linux-arm64": "0.27.2",
"@esbuild/linux-ia32": "0.27.2",
"@esbuild/linux-loong64": "0.27.2",
"@esbuild/linux-mips64el": "0.27.2",
"@esbuild/linux-ppc64": "0.27.2",
"@esbuild/linux-riscv64": "0.27.2",
"@esbuild/linux-s390x": "0.27.2",
"@esbuild/linux-x64": "0.27.2",
"@esbuild/netbsd-arm64": "0.27.2",
"@esbuild/netbsd-x64": "0.27.2",
"@esbuild/openbsd-arm64": "0.27.2",
"@esbuild/openbsd-x64": "0.27.2",
"@esbuild/openharmony-arm64": "0.27.2",
"@esbuild/sunos-x64": "0.27.2",
"@esbuild/win32-arm64": "0.27.2",
"@esbuild/win32-ia32": "0.27.2",
"@esbuild/win32-x64": "0.27.2"
}
}
}
}

3
node_modules/@esbuild/darwin-arm64/README.md generated vendored Normal file
View File

@ -0,0 +1,3 @@
# esbuild
This is the macOS ARM 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.

BIN
node_modules/@esbuild/darwin-arm64/bin/esbuild generated vendored Executable file

Binary file not shown.

20
node_modules/@esbuild/darwin-arm64/package.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"name": "@esbuild/darwin-arm64",
"version": "0.27.2",
"description": "The macOS ARM 64-bit binary for esbuild, a JavaScript bundler.",
"repository": {
"type": "git",
"url": "git+https://github.com/evanw/esbuild.git"
},
"license": "MIT",
"preferUnplugged": true,
"engines": {
"node": ">=18"
},
"os": [
"darwin"
],
"cpu": [
"arm64"
]
}

54
node_modules/dcjs/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,54 @@
let headers = new Headers({
"user-agent": "DCJS Fetcher",
});
const dcTriggerMap = {
load: "load",
hover: "mouseover",
}
async function renderContentToTarget(content, target) {
let elementToReplace = document.querySelector("#" + target);
elementToReplace.innerHTML = content;
}
async function handleDcjs() {
// need to add a way to show that this is LOADING :-).
// Look for custom data attributes in DOM.
let elementsUsingGet = document.querySelectorAll('[dc-get]');
if (elementsUsingGet.length > 0) {
const reqUrl = location.protocol + '//' + location.host;
for (let i = 0; i < elementsUsingGet.length; i++) {
let dcTrigger = "click";
let dcjsElem = elementsUsingGet[i];
if (dcjsElem.hasAttribute('dc-trigger')) {
dcTrigger = elementsUsingGet[i].getAttribute('dc-trigger');
dcTrigger = dcTriggerMap[dcTrigger];
}
// Dom is already loaded, so just insert content.
if (dcTrigger == "load") {
let getPath = dcjsElem.getAttribute('dc-get');
let targetElement = dcjsElem.getAttribute('dc-target');
fetch(reqUrl + getPath)
.then(res => res.text())
.then(async swap => await renderContentToTarget(swap, targetElement))
}
else {
elementsUsingGet[i].addEventListener(dcTrigger, (e) => {
let getPath = e.target.getAttribute('dc-get');
let targetElement = e.target.getAttribute('dc-target');
fetch(reqUrl + getPath)
.then(res => res.text())
.then(async swap => await renderContentToTarget(swap, targetElement))
})
}
}
}
}
export default {
handleDcjs,
renderContentToTarget
};

19
node_modules/dcjs/package.json generated vendored Normal file
View File

@ -0,0 +1,19 @@
{
"name": "dcjs",
"version": "1.0.0",
"description": "HTMX type library",
"main": "./lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/dan612/dcjs.git"
},
"author": "Dan Chadwick",
"license": "ISC",
"bugs": {
"url": "https://github.com/dan612/dcjs/issues"
},
"homepage": "https://github.com/dan612/dcjs#readme"
}

21
node_modules/esbuild/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Evan Wallace
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.

3
node_modules/esbuild/README.md generated vendored Normal file
View File

@ -0,0 +1,3 @@
# esbuild
This is a JavaScript bundler and minifier. See https://github.com/evanw/esbuild and the [JavaScript API documentation](https://esbuild.github.io/api/) for details.

BIN
node_modules/esbuild/bin/esbuild generated vendored Executable file

Binary file not shown.

289
node_modules/esbuild/install.js generated vendored Normal file
View File

@ -0,0 +1,289 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// lib/npm/node-platform.ts
var fs = require("fs");
var os = require("os");
var path = require("path");
var ESBUILD_BINARY_PATH = process.env.ESBUILD_BINARY_PATH || ESBUILD_BINARY_PATH;
var isValidBinaryPath = (x) => !!x && x !== "/usr/bin/esbuild";
var knownWindowsPackages = {
"win32 arm64 LE": "@esbuild/win32-arm64",
"win32 ia32 LE": "@esbuild/win32-ia32",
"win32 x64 LE": "@esbuild/win32-x64"
};
var knownUnixlikePackages = {
"aix ppc64 BE": "@esbuild/aix-ppc64",
"android arm64 LE": "@esbuild/android-arm64",
"darwin arm64 LE": "@esbuild/darwin-arm64",
"darwin x64 LE": "@esbuild/darwin-x64",
"freebsd arm64 LE": "@esbuild/freebsd-arm64",
"freebsd x64 LE": "@esbuild/freebsd-x64",
"linux arm LE": "@esbuild/linux-arm",
"linux arm64 LE": "@esbuild/linux-arm64",
"linux ia32 LE": "@esbuild/linux-ia32",
"linux mips64el LE": "@esbuild/linux-mips64el",
"linux ppc64 LE": "@esbuild/linux-ppc64",
"linux riscv64 LE": "@esbuild/linux-riscv64",
"linux s390x BE": "@esbuild/linux-s390x",
"linux x64 LE": "@esbuild/linux-x64",
"linux loong64 LE": "@esbuild/linux-loong64",
"netbsd arm64 LE": "@esbuild/netbsd-arm64",
"netbsd x64 LE": "@esbuild/netbsd-x64",
"openbsd arm64 LE": "@esbuild/openbsd-arm64",
"openbsd x64 LE": "@esbuild/openbsd-x64",
"sunos x64 LE": "@esbuild/sunos-x64"
};
var knownWebAssemblyFallbackPackages = {
"android arm LE": "@esbuild/android-arm",
"android x64 LE": "@esbuild/android-x64",
"openharmony arm64 LE": "@esbuild/openharmony-arm64"
};
function pkgAndSubpathForCurrentPlatform() {
let pkg;
let subpath;
let isWASM = false;
let platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
if (platformKey in knownWindowsPackages) {
pkg = knownWindowsPackages[platformKey];
subpath = "esbuild.exe";
} else if (platformKey in knownUnixlikePackages) {
pkg = knownUnixlikePackages[platformKey];
subpath = "bin/esbuild";
} else if (platformKey in knownWebAssemblyFallbackPackages) {
pkg = knownWebAssemblyFallbackPackages[platformKey];
subpath = "bin/esbuild";
isWASM = true;
} else {
throw new Error(`Unsupported platform: ${platformKey}`);
}
return { pkg, subpath, isWASM };
}
function downloadedBinPath(pkg, subpath) {
const esbuildLibDir = path.dirname(require.resolve("esbuild"));
return path.join(esbuildLibDir, `downloaded-${pkg.replace("/", "-")}-${path.basename(subpath)}`);
}
// lib/npm/node-install.ts
var fs2 = require("fs");
var os2 = require("os");
var path2 = require("path");
var zlib = require("zlib");
var https = require("https");
var child_process = require("child_process");
var versionFromPackageJSON = require(path2.join(__dirname, "package.json")).version;
var toPath = path2.join(__dirname, "bin", "esbuild");
var isToPathJS = true;
function validateBinaryVersion(...command) {
command.push("--version");
let stdout;
try {
stdout = child_process.execFileSync(command.shift(), command, {
// Without this, this install script strangely crashes with the error
// "EACCES: permission denied, write" but only on Ubuntu Linux when node is
// installed from the Snap Store. This is not a problem when you download
// the official version of node. The problem appears to be that stderr
// (i.e. file descriptor 2) isn't writable?
//
// More info:
// - https://snapcraft.io/ (what the Snap Store is)
// - https://nodejs.org/dist/ (download the official version of node)
// - https://github.com/evanw/esbuild/issues/1711#issuecomment-1027554035
//
stdio: "pipe"
}).toString().trim();
} catch (err) {
if (os2.platform() === "darwin" && /_SecTrustEvaluateWithError/.test(err + "")) {
let os3 = "this version of macOS";
try {
os3 = "macOS " + child_process.execFileSync("sw_vers", ["-productVersion"]).toString().trim();
} catch {
}
throw new Error(`The "esbuild" package cannot be installed because ${os3} is too outdated.
The Go compiler (which esbuild relies on) no longer supports ${os3},
which means the "esbuild" binary executable can't be run. You can either:
* Update your version of macOS to one that the Go compiler supports
* Use the "esbuild-wasm" package instead of the "esbuild" package
* Build esbuild yourself using an older version of the Go compiler
`);
}
throw err;
}
if (stdout !== versionFromPackageJSON) {
throw new Error(`Expected ${JSON.stringify(versionFromPackageJSON)} but got ${JSON.stringify(stdout)}`);
}
}
function isYarn() {
const { npm_config_user_agent } = process.env;
if (npm_config_user_agent) {
return /\byarn\//.test(npm_config_user_agent);
}
return false;
}
function fetch(url) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location)
return fetch(res.headers.location).then(resolve, reject);
if (res.statusCode !== 200)
return reject(new Error(`Server responded with ${res.statusCode}`));
let chunks = [];
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => resolve(Buffer.concat(chunks)));
}).on("error", reject);
});
}
function extractFileFromTarGzip(buffer, subpath) {
try {
buffer = zlib.unzipSync(buffer);
} catch (err) {
throw new Error(`Invalid gzip data in archive: ${err && err.message || err}`);
}
let str = (i, n) => String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, "");
let offset = 0;
subpath = `package/${subpath}`;
while (offset < buffer.length) {
let name = str(offset, 100);
let size = parseInt(str(offset + 124, 12), 8);
offset += 512;
if (!isNaN(size)) {
if (name === subpath) return buffer.subarray(offset, offset + size);
offset += size + 511 & ~511;
}
}
throw new Error(`Could not find ${JSON.stringify(subpath)} in archive`);
}
function installUsingNPM(pkg, subpath, binPath) {
const env = { ...process.env, npm_config_global: void 0 };
const esbuildLibDir = path2.dirname(require.resolve("esbuild"));
const installDir = path2.join(esbuildLibDir, "npm-install");
fs2.mkdirSync(installDir);
try {
fs2.writeFileSync(path2.join(installDir, "package.json"), "{}");
child_process.execSync(
`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${versionFromPackageJSON}`,
{ cwd: installDir, stdio: "pipe", env }
);
const installedBinPath = path2.join(installDir, "node_modules", pkg, subpath);
fs2.renameSync(installedBinPath, binPath);
} finally {
try {
removeRecursive(installDir);
} catch {
}
}
}
function removeRecursive(dir) {
for (const entry of fs2.readdirSync(dir)) {
const entryPath = path2.join(dir, entry);
let stats;
try {
stats = fs2.lstatSync(entryPath);
} catch {
continue;
}
if (stats.isDirectory()) removeRecursive(entryPath);
else fs2.unlinkSync(entryPath);
}
fs2.rmdirSync(dir);
}
function applyManualBinaryPathOverride(overridePath) {
const pathString = JSON.stringify(overridePath);
fs2.writeFileSync(toPath, `#!/usr/bin/env node
require('child_process').execFileSync(${pathString}, process.argv.slice(2), { stdio: 'inherit' });
`);
const libMain = path2.join(__dirname, "lib", "main.js");
const code = fs2.readFileSync(libMain, "utf8");
fs2.writeFileSync(libMain, `var ESBUILD_BINARY_PATH = ${pathString};
${code}`);
}
function maybeOptimizePackage(binPath) {
const { isWASM } = pkgAndSubpathForCurrentPlatform();
if (os2.platform() !== "win32" && !isYarn() && !isWASM) {
const tempPath = path2.join(__dirname, "bin-esbuild");
try {
fs2.linkSync(binPath, tempPath);
fs2.renameSync(tempPath, toPath);
isToPathJS = false;
fs2.unlinkSync(tempPath);
} catch {
}
}
}
async function downloadDirectlyFromNPM(pkg, subpath, binPath) {
const url = `https://registry.npmjs.org/${pkg}/-/${pkg.replace("@esbuild/", "")}-${versionFromPackageJSON}.tgz`;
console.error(`[esbuild] Trying to download ${JSON.stringify(url)}`);
try {
fs2.writeFileSync(binPath, extractFileFromTarGzip(await fetch(url), subpath));
fs2.chmodSync(binPath, 493);
} catch (e) {
console.error(`[esbuild] Failed to download ${JSON.stringify(url)}: ${e && e.message || e}`);
throw e;
}
}
async function checkAndPreparePackage() {
if (isValidBinaryPath(ESBUILD_BINARY_PATH)) {
if (!fs2.existsSync(ESBUILD_BINARY_PATH)) {
console.warn(`[esbuild] Ignoring bad configuration: ESBUILD_BINARY_PATH=${ESBUILD_BINARY_PATH}`);
} else {
applyManualBinaryPathOverride(ESBUILD_BINARY_PATH);
return;
}
}
const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
let binPath;
try {
binPath = require.resolve(`${pkg}/${subpath}`);
} catch (e) {
console.error(`[esbuild] Failed to find package "${pkg}" on the file system
This can happen if you use the "--no-optional" flag. The "optionalDependencies"
package.json feature is used by esbuild to install the correct binary executable
for your current platform. This install script will now attempt to work around
this. If that fails, you need to remove the "--no-optional" flag to use esbuild.
`);
binPath = downloadedBinPath(pkg, subpath);
try {
console.error(`[esbuild] Trying to install package "${pkg}" using npm`);
installUsingNPM(pkg, subpath, binPath);
} catch (e2) {
console.error(`[esbuild] Failed to install package "${pkg}" using npm: ${e2 && e2.message || e2}`);
try {
await downloadDirectlyFromNPM(pkg, subpath, binPath);
} catch (e3) {
throw new Error(`Failed to install package "${pkg}"`);
}
}
}
maybeOptimizePackage(binPath);
}
checkAndPreparePackage().then(() => {
if (isToPathJS) {
validateBinaryVersion(process.execPath, toPath);
} else {
validateBinaryVersion(toPath);
}
});

716
node_modules/esbuild/lib/main.d.ts generated vendored Normal file
View File

@ -0,0 +1,716 @@
export type Platform = 'browser' | 'node' | 'neutral'
export type Format = 'iife' | 'cjs' | 'esm'
export type Loader = 'base64' | 'binary' | 'copy' | 'css' | 'dataurl' | 'default' | 'empty' | 'file' | 'js' | 'json' | 'jsx' | 'local-css' | 'text' | 'ts' | 'tsx'
export type LogLevel = 'verbose' | 'debug' | 'info' | 'warning' | 'error' | 'silent'
export type Charset = 'ascii' | 'utf8'
export type Drop = 'console' | 'debugger'
export type AbsPaths = 'code' | 'log' | 'metafile'
interface CommonOptions {
/** Documentation: https://esbuild.github.io/api/#sourcemap */
sourcemap?: boolean | 'linked' | 'inline' | 'external' | 'both'
/** Documentation: https://esbuild.github.io/api/#legal-comments */
legalComments?: 'none' | 'inline' | 'eof' | 'linked' | 'external'
/** Documentation: https://esbuild.github.io/api/#source-root */
sourceRoot?: string
/** Documentation: https://esbuild.github.io/api/#sources-content */
sourcesContent?: boolean
/** Documentation: https://esbuild.github.io/api/#format */
format?: Format
/** Documentation: https://esbuild.github.io/api/#global-name */
globalName?: string
/** Documentation: https://esbuild.github.io/api/#target */
target?: string | string[]
/** Documentation: https://esbuild.github.io/api/#supported */
supported?: Record<string, boolean>
/** Documentation: https://esbuild.github.io/api/#platform */
platform?: Platform
/** Documentation: https://esbuild.github.io/api/#mangle-props */
mangleProps?: RegExp
/** Documentation: https://esbuild.github.io/api/#mangle-props */
reserveProps?: RegExp
/** Documentation: https://esbuild.github.io/api/#mangle-props */
mangleQuoted?: boolean
/** Documentation: https://esbuild.github.io/api/#mangle-props */
mangleCache?: Record<string, string | false>
/** Documentation: https://esbuild.github.io/api/#drop */
drop?: Drop[]
/** Documentation: https://esbuild.github.io/api/#drop-labels */
dropLabels?: string[]
/** Documentation: https://esbuild.github.io/api/#minify */
minify?: boolean
/** Documentation: https://esbuild.github.io/api/#minify */
minifyWhitespace?: boolean
/** Documentation: https://esbuild.github.io/api/#minify */
minifyIdentifiers?: boolean
/** Documentation: https://esbuild.github.io/api/#minify */
minifySyntax?: boolean
/** Documentation: https://esbuild.github.io/api/#line-limit */
lineLimit?: number
/** Documentation: https://esbuild.github.io/api/#charset */
charset?: Charset
/** Documentation: https://esbuild.github.io/api/#tree-shaking */
treeShaking?: boolean
/** Documentation: https://esbuild.github.io/api/#ignore-annotations */
ignoreAnnotations?: boolean
/** Documentation: https://esbuild.github.io/api/#jsx */
jsx?: 'transform' | 'preserve' | 'automatic'
/** Documentation: https://esbuild.github.io/api/#jsx-factory */
jsxFactory?: string
/** Documentation: https://esbuild.github.io/api/#jsx-fragment */
jsxFragment?: string
/** Documentation: https://esbuild.github.io/api/#jsx-import-source */
jsxImportSource?: string
/** Documentation: https://esbuild.github.io/api/#jsx-development */
jsxDev?: boolean
/** Documentation: https://esbuild.github.io/api/#jsx-side-effects */
jsxSideEffects?: boolean
/** Documentation: https://esbuild.github.io/api/#define */
define?: { [key: string]: string }
/** Documentation: https://esbuild.github.io/api/#pure */
pure?: string[]
/** Documentation: https://esbuild.github.io/api/#keep-names */
keepNames?: boolean
/** Documentation: https://esbuild.github.io/api/#abs-paths */
absPaths?: AbsPaths[]
/** Documentation: https://esbuild.github.io/api/#color */
color?: boolean
/** Documentation: https://esbuild.github.io/api/#log-level */
logLevel?: LogLevel
/** Documentation: https://esbuild.github.io/api/#log-limit */
logLimit?: number
/** Documentation: https://esbuild.github.io/api/#log-override */
logOverride?: Record<string, LogLevel>
/** Documentation: https://esbuild.github.io/api/#tsconfig-raw */
tsconfigRaw?: string | TsconfigRaw
}
export interface TsconfigRaw {
compilerOptions?: {
alwaysStrict?: boolean
baseUrl?: string
experimentalDecorators?: boolean
importsNotUsedAsValues?: 'remove' | 'preserve' | 'error'
jsx?: 'preserve' | 'react-native' | 'react' | 'react-jsx' | 'react-jsxdev'
jsxFactory?: string
jsxFragmentFactory?: string
jsxImportSource?: string
paths?: Record<string, string[]>
preserveValueImports?: boolean
strict?: boolean
target?: string
useDefineForClassFields?: boolean
verbatimModuleSyntax?: boolean
}
}
export interface BuildOptions extends CommonOptions {
/** Documentation: https://esbuild.github.io/api/#bundle */
bundle?: boolean
/** Documentation: https://esbuild.github.io/api/#splitting */
splitting?: boolean
/** Documentation: https://esbuild.github.io/api/#preserve-symlinks */
preserveSymlinks?: boolean
/** Documentation: https://esbuild.github.io/api/#outfile */
outfile?: string
/** Documentation: https://esbuild.github.io/api/#metafile */
metafile?: boolean
/** Documentation: https://esbuild.github.io/api/#outdir */
outdir?: string
/** Documentation: https://esbuild.github.io/api/#outbase */
outbase?: string
/** Documentation: https://esbuild.github.io/api/#external */
external?: string[]
/** Documentation: https://esbuild.github.io/api/#packages */
packages?: 'bundle' | 'external'
/** Documentation: https://esbuild.github.io/api/#alias */
alias?: Record<string, string>
/** Documentation: https://esbuild.github.io/api/#loader */
loader?: { [ext: string]: Loader }
/** Documentation: https://esbuild.github.io/api/#resolve-extensions */
resolveExtensions?: string[]
/** Documentation: https://esbuild.github.io/api/#main-fields */
mainFields?: string[]
/** Documentation: https://esbuild.github.io/api/#conditions */
conditions?: string[]
/** Documentation: https://esbuild.github.io/api/#write */
write?: boolean
/** Documentation: https://esbuild.github.io/api/#allow-overwrite */
allowOverwrite?: boolean
/** Documentation: https://esbuild.github.io/api/#tsconfig */
tsconfig?: string
/** Documentation: https://esbuild.github.io/api/#out-extension */
outExtension?: { [ext: string]: string }
/** Documentation: https://esbuild.github.io/api/#public-path */
publicPath?: string
/** Documentation: https://esbuild.github.io/api/#entry-names */
entryNames?: string
/** Documentation: https://esbuild.github.io/api/#chunk-names */
chunkNames?: string
/** Documentation: https://esbuild.github.io/api/#asset-names */
assetNames?: string
/** Documentation: https://esbuild.github.io/api/#inject */
inject?: string[]
/** Documentation: https://esbuild.github.io/api/#banner */
banner?: { [type: string]: string }
/** Documentation: https://esbuild.github.io/api/#footer */
footer?: { [type: string]: string }
/** Documentation: https://esbuild.github.io/api/#entry-points */
entryPoints?: (string | { in: string, out: string })[] | Record<string, string>
/** Documentation: https://esbuild.github.io/api/#stdin */
stdin?: StdinOptions
/** Documentation: https://esbuild.github.io/plugins/ */
plugins?: Plugin[]
/** Documentation: https://esbuild.github.io/api/#working-directory */
absWorkingDir?: string
/** Documentation: https://esbuild.github.io/api/#node-paths */
nodePaths?: string[]; // The "NODE_PATH" variable from Node.js
}
export interface StdinOptions {
contents: string | Uint8Array
resolveDir?: string
sourcefile?: string
loader?: Loader
}
export interface Message {
id: string
pluginName: string
text: string
location: Location | null
notes: Note[]
/**
* Optional user-specified data that is passed through unmodified. You can
* use this to stash the original error, for example.
*/
detail: any
}
export interface Note {
text: string
location: Location | null
}
export interface Location {
file: string
namespace: string
/** 1-based */
line: number
/** 0-based, in bytes */
column: number
/** in bytes */
length: number
lineText: string
suggestion: string
}
export interface OutputFile {
path: string
contents: Uint8Array
hash: string
/** "contents" as text (changes automatically with "contents") */
readonly text: string
}
export interface BuildResult<ProvidedOptions extends BuildOptions = BuildOptions> {
errors: Message[]
warnings: Message[]
/** Only when "write: false" */
outputFiles: OutputFile[] | (ProvidedOptions['write'] extends false ? never : undefined)
/** Only when "metafile: true" */
metafile: Metafile | (ProvidedOptions['metafile'] extends true ? never : undefined)
/** Only when "mangleCache" is present */
mangleCache: Record<string, string | false> | (ProvidedOptions['mangleCache'] extends Object ? never : undefined)
}
export interface BuildFailure extends Error {
errors: Message[]
warnings: Message[]
}
/** Documentation: https://esbuild.github.io/api/#serve-arguments */
export interface ServeOptions {
port?: number
host?: string
servedir?: string
keyfile?: string
certfile?: string
fallback?: string
cors?: CORSOptions
onRequest?: (args: ServeOnRequestArgs) => void
}
/** Documentation: https://esbuild.github.io/api/#cors */
export interface CORSOptions {
origin?: string | string[]
}
export interface ServeOnRequestArgs {
remoteAddress: string
method: string
path: string
status: number
/** The time to generate the response, not to send it */
timeInMS: number
}
/** Documentation: https://esbuild.github.io/api/#serve-return-values */
export interface ServeResult {
port: number
hosts: string[]
}
export interface TransformOptions extends CommonOptions {
/** Documentation: https://esbuild.github.io/api/#sourcefile */
sourcefile?: string
/** Documentation: https://esbuild.github.io/api/#loader */
loader?: Loader
/** Documentation: https://esbuild.github.io/api/#banner */
banner?: string
/** Documentation: https://esbuild.github.io/api/#footer */
footer?: string
}
export interface TransformResult<ProvidedOptions extends TransformOptions = TransformOptions> {
code: string
map: string
warnings: Message[]
/** Only when "mangleCache" is present */
mangleCache: Record<string, string | false> | (ProvidedOptions['mangleCache'] extends Object ? never : undefined)
/** Only when "legalComments" is "external" */
legalComments: string | (ProvidedOptions['legalComments'] extends 'external' ? never : undefined)
}
export interface TransformFailure extends Error {
errors: Message[]
warnings: Message[]
}
export interface Plugin {
name: string
setup: (build: PluginBuild) => (void | Promise<void>)
}
export interface PluginBuild {
/** Documentation: https://esbuild.github.io/plugins/#build-options */
initialOptions: BuildOptions
/** Documentation: https://esbuild.github.io/plugins/#resolve */
resolve(path: string, options?: ResolveOptions): Promise<ResolveResult>
/** Documentation: https://esbuild.github.io/plugins/#on-start */
onStart(callback: () =>
(OnStartResult | null | void | Promise<OnStartResult | null | void>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-end */
onEnd(callback: (result: BuildResult) =>
(OnEndResult | null | void | Promise<OnEndResult | null | void>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-resolve */
onResolve(options: OnResolveOptions, callback: (args: OnResolveArgs) =>
(OnResolveResult | null | undefined | Promise<OnResolveResult | null | undefined>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-load */
onLoad(options: OnLoadOptions, callback: (args: OnLoadArgs) =>
(OnLoadResult | null | undefined | Promise<OnLoadResult | null | undefined>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-dispose */
onDispose(callback: () => void): void
// This is a full copy of the esbuild library in case you need it
esbuild: {
context: typeof context,
build: typeof build,
buildSync: typeof buildSync,
transform: typeof transform,
transformSync: typeof transformSync,
formatMessages: typeof formatMessages,
formatMessagesSync: typeof formatMessagesSync,
analyzeMetafile: typeof analyzeMetafile,
analyzeMetafileSync: typeof analyzeMetafileSync,
initialize: typeof initialize,
version: typeof version,
}
}
/** Documentation: https://esbuild.github.io/plugins/#resolve-options */
export interface ResolveOptions {
pluginName?: string
importer?: string
namespace?: string
resolveDir?: string
kind?: ImportKind
pluginData?: any
with?: Record<string, string>
}
/** Documentation: https://esbuild.github.io/plugins/#resolve-results */
export interface ResolveResult {
errors: Message[]
warnings: Message[]
path: string
external: boolean
sideEffects: boolean
namespace: string
suffix: string
pluginData: any
}
export interface OnStartResult {
errors?: PartialMessage[]
warnings?: PartialMessage[]
}
export interface OnEndResult {
errors?: PartialMessage[]
warnings?: PartialMessage[]
}
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-options */
export interface OnResolveOptions {
filter: RegExp
namespace?: string
}
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-arguments */
export interface OnResolveArgs {
path: string
importer: string
namespace: string
resolveDir: string
kind: ImportKind
pluginData: any
with: Record<string, string>
}
export type ImportKind =
| 'entry-point'
// JS
| 'import-statement'
| 'require-call'
| 'dynamic-import'
| 'require-resolve'
// CSS
| 'import-rule'
| 'composes-from'
| 'url-token'
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-results */
export interface OnResolveResult {
pluginName?: string
errors?: PartialMessage[]
warnings?: PartialMessage[]
path?: string
external?: boolean
sideEffects?: boolean
namespace?: string
suffix?: string
pluginData?: any
watchFiles?: string[]
watchDirs?: string[]
}
/** Documentation: https://esbuild.github.io/plugins/#on-load-options */
export interface OnLoadOptions {
filter: RegExp
namespace?: string
}
/** Documentation: https://esbuild.github.io/plugins/#on-load-arguments */
export interface OnLoadArgs {
path: string
namespace: string
suffix: string
pluginData: any
with: Record<string, string>
}
/** Documentation: https://esbuild.github.io/plugins/#on-load-results */
export interface OnLoadResult {
pluginName?: string
errors?: PartialMessage[]
warnings?: PartialMessage[]
contents?: string | Uint8Array
resolveDir?: string
loader?: Loader
pluginData?: any
watchFiles?: string[]
watchDirs?: string[]
}
export interface PartialMessage {
id?: string
pluginName?: string
text?: string
location?: Partial<Location> | null
notes?: PartialNote[]
detail?: any
}
export interface PartialNote {
text?: string
location?: Partial<Location> | null
}
/** Documentation: https://esbuild.github.io/api/#metafile */
export interface Metafile {
inputs: {
[path: string]: {
bytes: number
imports: {
path: string
kind: ImportKind
external?: boolean
original?: string
with?: Record<string, string>
}[]
format?: 'cjs' | 'esm'
with?: Record<string, string>
}
}
outputs: {
[path: string]: {
bytes: number
inputs: {
[path: string]: {
bytesInOutput: number
}
}
imports: {
path: string
kind: ImportKind | 'file-loader'
external?: boolean
}[]
exports: string[]
entryPoint?: string
cssBundle?: string
}
}
}
export interface FormatMessagesOptions {
kind: 'error' | 'warning'
color?: boolean
terminalWidth?: number
}
export interface AnalyzeMetafileOptions {
color?: boolean
verbose?: boolean
}
/** Documentation: https://esbuild.github.io/api/#watch-arguments */
export interface WatchOptions {
delay?: number // In milliseconds
}
export interface BuildContext<ProvidedOptions extends BuildOptions = BuildOptions> {
/** Documentation: https://esbuild.github.io/api/#rebuild */
rebuild(): Promise<BuildResult<ProvidedOptions>>
/** Documentation: https://esbuild.github.io/api/#watch */
watch(options?: WatchOptions): Promise<void>
/** Documentation: https://esbuild.github.io/api/#serve */
serve(options?: ServeOptions): Promise<ServeResult>
cancel(): Promise<void>
dispose(): Promise<void>
}
// This is a TypeScript type-level function which replaces any keys in "In"
// that aren't in "Out" with "never". We use this to reject properties with
// typos in object literals. See: https://stackoverflow.com/questions/49580725
type SameShape<Out, In extends Out> = In & { [Key in Exclude<keyof In, keyof Out>]: never }
/**
* This function invokes the "esbuild" command-line tool for you. It returns a
* promise that either resolves with a "BuildResult" object or rejects with a
* "BuildFailure" object.
*
* - Works in node: yes
* - Works in browser: yes
*
* Documentation: https://esbuild.github.io/api/#build
*/
export declare function build<T extends BuildOptions>(options: SameShape<BuildOptions, T>): Promise<BuildResult<T>>
/**
* This is the advanced long-running form of "build" that supports additional
* features such as watch mode and a local development server.
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#build
*/
export declare function context<T extends BuildOptions>(options: SameShape<BuildOptions, T>): Promise<BuildContext<T>>
/**
* This function transforms a single JavaScript file. It can be used to minify
* JavaScript, convert TypeScript/JSX to JavaScript, or convert newer JavaScript
* to older JavaScript. It returns a promise that is either resolved with a
* "TransformResult" object or rejected with a "TransformFailure" object.
*
* - Works in node: yes
* - Works in browser: yes
*
* Documentation: https://esbuild.github.io/api/#transform
*/
export declare function transform<T extends TransformOptions>(input: string | Uint8Array, options?: SameShape<TransformOptions, T>): Promise<TransformResult<T>>
/**
* Converts log messages to formatted message strings suitable for printing in
* the terminal. This allows you to reuse the built-in behavior of esbuild's
* log message formatter. This is a batch-oriented API for efficiency.
*
* - Works in node: yes
* - Works in browser: yes
*/
export declare function formatMessages(messages: PartialMessage[], options: FormatMessagesOptions): Promise<string[]>
/**
* Pretty-prints an analysis of the metafile JSON to a string. This is just for
* convenience to be able to match esbuild's pretty-printing exactly. If you want
* to customize it, you can just inspect the data in the metafile yourself.
*
* - Works in node: yes
* - Works in browser: yes
*
* Documentation: https://esbuild.github.io/api/#analyze
*/
export declare function analyzeMetafile(metafile: Metafile | string, options?: AnalyzeMetafileOptions): Promise<string>
/**
* A synchronous version of "build".
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#build
*/
export declare function buildSync<T extends BuildOptions>(options: SameShape<BuildOptions, T>): BuildResult<T>
/**
* A synchronous version of "transform".
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#transform
*/
export declare function transformSync<T extends TransformOptions>(input: string | Uint8Array, options?: SameShape<TransformOptions, T>): TransformResult<T>
/**
* A synchronous version of "formatMessages".
*
* - Works in node: yes
* - Works in browser: no
*/
export declare function formatMessagesSync(messages: PartialMessage[], options: FormatMessagesOptions): string[]
/**
* A synchronous version of "analyzeMetafile".
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#analyze
*/
export declare function analyzeMetafileSync(metafile: Metafile | string, options?: AnalyzeMetafileOptions): string
/**
* This configures the browser-based version of esbuild. It is necessary to
* call this first and wait for the returned promise to be resolved before
* making other API calls when using esbuild in the browser.
*
* - Works in node: yes
* - Works in browser: yes ("options" is required)
*
* Documentation: https://esbuild.github.io/api/#browser
*/
export declare function initialize(options: InitializeOptions): Promise<void>
export interface InitializeOptions {
/**
* The URL of the "esbuild.wasm" file. This must be provided when running
* esbuild in the browser.
*/
wasmURL?: string | URL
/**
* The result of calling "new WebAssembly.Module(buffer)" where "buffer"
* is a typed array or ArrayBuffer containing the binary code of the
* "esbuild.wasm" file.
*
* You can use this as an alternative to "wasmURL" for environments where it's
* not possible to download the WebAssembly module.
*/
wasmModule?: WebAssembly.Module
/**
* By default esbuild runs the WebAssembly-based browser API in a web worker
* to avoid blocking the UI thread. This can be disabled by setting "worker"
* to false.
*/
worker?: boolean
}
export let version: string
// Call this function to terminate esbuild's child process. The child process
// is not terminated and re-created after each API call because it's more
// efficient to keep it around when there are multiple API calls.
//
// In node this happens automatically before the parent node process exits. So
// you only need to call this if you know you will not make any more esbuild
// API calls and you want to clean up resources.
//
// Unlike node, Deno lacks the necessary APIs to clean up child processes
// automatically. You must manually call stop() in Deno when you're done
// using esbuild or Deno will continue running forever.
//
// Another reason you might want to call this is if you are using esbuild from
// within a Deno test. Deno fails tests that create a child process without
// killing it before the test ends, so you have to call this function (and
// await the returned promise) in every Deno test that uses esbuild.
export declare function stop(): Promise<void>
// Note: These declarations exist to avoid type errors when you omit "dom" from
// "lib" in your "tsconfig.json" file. TypeScript confusingly declares the
// global "WebAssembly" type in "lib.dom.d.ts" even though it has nothing to do
// with the browser DOM and is present in many non-browser JavaScript runtimes
// (e.g. node and deno). Declaring it here allows esbuild's API to be used in
// these scenarios.
//
// There's an open issue about getting this problem corrected (although these
// declarations will need to remain even if this is fixed for backward
// compatibility with older TypeScript versions):
//
// https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/826
//
declare global {
namespace WebAssembly {
interface Module {
}
}
interface URL {
}
}

2242
node_modules/esbuild/lib/main.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

49
node_modules/esbuild/package.json generated vendored Normal file
View File

@ -0,0 +1,49 @@
{
"name": "esbuild",
"version": "0.27.2",
"description": "An extremely fast JavaScript and CSS bundler and minifier.",
"repository": {
"type": "git",
"url": "git+https://github.com/evanw/esbuild.git"
},
"scripts": {
"postinstall": "node install.js"
},
"main": "lib/main.js",
"types": "lib/main.d.ts",
"engines": {
"node": ">=18"
},
"bin": {
"esbuild": "bin/esbuild"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.2",
"@esbuild/android-arm": "0.27.2",
"@esbuild/android-arm64": "0.27.2",
"@esbuild/android-x64": "0.27.2",
"@esbuild/darwin-arm64": "0.27.2",
"@esbuild/darwin-x64": "0.27.2",
"@esbuild/freebsd-arm64": "0.27.2",
"@esbuild/freebsd-x64": "0.27.2",
"@esbuild/linux-arm": "0.27.2",
"@esbuild/linux-arm64": "0.27.2",
"@esbuild/linux-ia32": "0.27.2",
"@esbuild/linux-loong64": "0.27.2",
"@esbuild/linux-mips64el": "0.27.2",
"@esbuild/linux-ppc64": "0.27.2",
"@esbuild/linux-riscv64": "0.27.2",
"@esbuild/linux-s390x": "0.27.2",
"@esbuild/linux-x64": "0.27.2",
"@esbuild/netbsd-arm64": "0.27.2",
"@esbuild/netbsd-x64": "0.27.2",
"@esbuild/openbsd-arm64": "0.27.2",
"@esbuild/openbsd-x64": "0.27.2",
"@esbuild/openharmony-arm64": "0.27.2",
"@esbuild/sunos-x64": "0.27.2",
"@esbuild/win32-arm64": "0.27.2",
"@esbuild/win32-ia32": "0.27.2",
"@esbuild/win32-x64": "0.27.2"
},
"license": "MIT"
}

508
package-lock.json generated Normal file
View File

@ -0,0 +1,508 @@
{
"name": "origo",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "origo",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"dcjs": "github:dan612/dcjs#main"
},
"devDependencies": {
"esbuild": "^0.27.2"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
"integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
"integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
"integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
"integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
"integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
"integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
"integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
"integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
"integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
"integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
"integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
"integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
"integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
"integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
"integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
"integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
"integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
"integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
"integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
"integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
"integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
"integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
"integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
"integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
"integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
"integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/dcjs": {
"version": "1.0.0",
"resolved": "git+ssh://git@github.com/dan612/dcjs.git#9193af54a2c4de341c458b320a0c6b816e3c0134",
"license": "ISC"
},
"node_modules/esbuild": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.2",
"@esbuild/android-arm": "0.27.2",
"@esbuild/android-arm64": "0.27.2",
"@esbuild/android-x64": "0.27.2",
"@esbuild/darwin-arm64": "0.27.2",
"@esbuild/darwin-x64": "0.27.2",
"@esbuild/freebsd-arm64": "0.27.2",
"@esbuild/freebsd-x64": "0.27.2",
"@esbuild/linux-arm": "0.27.2",
"@esbuild/linux-arm64": "0.27.2",
"@esbuild/linux-ia32": "0.27.2",
"@esbuild/linux-loong64": "0.27.2",
"@esbuild/linux-mips64el": "0.27.2",
"@esbuild/linux-ppc64": "0.27.2",
"@esbuild/linux-riscv64": "0.27.2",
"@esbuild/linux-s390x": "0.27.2",
"@esbuild/linux-x64": "0.27.2",
"@esbuild/netbsd-arm64": "0.27.2",
"@esbuild/netbsd-x64": "0.27.2",
"@esbuild/openbsd-arm64": "0.27.2",
"@esbuild/openbsd-x64": "0.27.2",
"@esbuild/openharmony-arm64": "0.27.2",
"@esbuild/sunos-x64": "0.27.2",
"@esbuild/win32-arm64": "0.27.2",
"@esbuild/win32-ia32": "0.27.2",
"@esbuild/win32-x64": "0.27.2"
}
}
}
}

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "origo",
"version": "1.0.0",
"description": "",
"license": "ISC",
"author": "",
"type": "commonjs",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "sass theme/style.scss theme/style.css",
"dash-build": "npx esbuild theme/js/dashboard.js --bundle --outfile=theme/dist/dash-bundle.js"
},
"dependencies": {
"dcjs": "github:dan612/dcjs#main"
},
"devDependencies": {
"esbuild": "^0.27.2"
}
}

1
salt.txt Normal file
View File

@ -0,0 +1 @@
203f9af9b9d25c0aa0e04e022b7c2c9f

View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
openssl rand -hex 16

6
scripts/db-setup.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
# Truncate the existing database.
rm database/origo.db
# Import the schema for the new database.
sqlite3 database/origo.db < database/schema.sql

2
scripts/rebuild.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/bash
docker build -t origo .

2
scripts/start.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/bash
docker run --rm -p 8000:8000 -v $(pwd):/app origo php -S 0.0.0.0:8000

3
scripts/theme.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
cd theme
sass style.scss style.css

View File

@ -0,0 +1,83 @@
<?php
namespace Origo\Controller;
use Origo\Controller\ControllerBase;
use Origo\Controller\ControllerInterface;
use Origo\Services\Database;
class ApiWebhookController extends ControllerBase implements ControllerInterface {
/**
* The database service.
*
* @var Database
*/
protected Database $database;
/**
* Add common services.
*/
public function __construct() {
parent::__construct();
$this->database = new Database();
}
/**
* Get the response.
*
* @return string
* The response.
*/
public function getResponse(): string {
header('Access-Control-Allow-Origin: *'); // Allow all origins.
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit(); // Stop here - don't process the request
}
// Make sure we have a path and account before proceeding.
$path = $this->request->post('path');
$account_id = $this->request->post('account');
if (
!$path ||
!$account_id
) {
header("HTTP/1.1 422 Unprocessable Entity");
die();
}
// @todo: validate the account id.
$entry = [
'page' => $path,
'account_id' => $account_id,
'user_agent' => $this->request->post('user_agent'),
'referrer' => $this->request->post('referrer'),
'ip' => $this->request->ip(),
];
$clean_entry = array_filter($entry);
$keys = array_keys($clean_entry);
$key_string = implode(',', $keys);
$placeholders = ':' . implode(', :', $keys);
$query = $this->database->prepare("INSERT INTO pageviews ($key_string) VALUES ($placeholders)");
foreach ($clean_entry as $key => $value) {
$query->bindValue(":$key", $value);
}
$success = $query->execute();
if ($success) {
$response = [
"SUCCESS" => "Entry has been stored.",
];
header('Content-Type: application/json');
}
else {
header("HTTP/1.1 422 Unprocessable Entity");
die();
}
return json_encode($response);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Origo\Controller;
use Origo\Services\Database;;
use Origo\Services\Renderer;
use Origo\Services\Request;
abstract class ControllerBase {
/**
* The request service.
*
* @var Request
*/
protected Request $request;
/**
* The renderer service.
*
* @var Renderer
*/
protected Renderer $renderer;
/**
* The database service.
*
* @var Database
*/
protected Database $database;
/**
* Add common services.
*/
public function __construct() {
$this->request = new Request();
$this->renderer = new Renderer();
$this->database = new Database();
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Origo\Controller;
use Origo\Services\Request;
interface ControllerInterface {
public function getResponse(): string;
}

View File

@ -0,0 +1,29 @@
<?php
namespace Origo\Controller;
use Origo\Controller\ControllerBase;
use Origo\Controller\ControllerInterface;
use Origo\Services\Template;
class MainController extends ControllerBase implements ControllerInterface {
public function __construct() {
parent::__construct();
}
/**
* Get the response.
*/
public function getResponse(): string {
$session_id = $this->request->getCookie('ORIGOSESS');
if($session_id) {
header("Location: /dashboard");
die();
}
$template = new Template('main.html');
return $template->render();
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace Origo\Controller;
use Origo\Entity\User;
use Origo\Controller\ControllerInterface;
use Origo\Services\Template;
use Origo\Services\Request;
use Origo\Services\Renderer;
class PlannerController extends ControllerBase implements ControllerInterface {
public function getResponse(): string {
// Okie dokie. so here i need to get the users id,
// then load all the tasks for that user.
// I guess sorting by their creation date would be good.
$user = new User();
$user->loadUserFromSession($this->request->getCookie('ORIGOSESS'));
$query = $this->database->query("SELECT * FROM tasks WHERE user_id = (:user_id) ORDER BY created_at DESC");
$user_id = $user->get('id');
$query->bindParam(':user_id', $user_id);
$query->execute();
$results = $query->fetchAll();
$tasks = '<div class="task-container">';
if ($results) {
foreach ($results as $result) {
$title = htmlspecialchars($result['task']);
$status = htmlspecialchars($result['status']);
$description = htmlspecialchars($result['description']);
$url = htmlspecialchars($result['external_url']);
$statusClass = (strtolower($status) === 'completed') ? 'status-completed' : 'status-pending';
$tasks .= '
<div class="task-card">
<div class="task-info">
<h3 class="task-title">' . $title . '</h3>
<div class="task-description">' . $description . '</div>';
if ($url) {
$tasks .= '<a href="' . $url . '" class="btn btn-soft-clay" target="_blank">View Details →</a>';
}
$tasks .= '
</div>
<div class="task-status ' . $statusClass . '">' . $status . '</div>
</div>';
}
} else {
$tasks .= '<p style="text-align:center; color:var(--color-medium-gray);">No tasks yet.</p>';
}
$tasks .= '</div>';
$template = new Template('task-list.html');
return $template->render([
'tasks' => $tasks,
]);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Origo\Controller;
use Origo\Entity\User;
use Origo\Controller\ControllerInterface;
use Origo\Services\Template;
use Origo\Services\Request;
use Origo\Services\Renderer;
class UserDashboardController implements ControllerInterface {
/**
* Get the response for the dashboard.
*/
public function getResponse(): string {
$template = new Template('dashboard.html');
return $template->render();
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Origo\Controller;
use Origo\Controller\ControllerInterface;
use Origo\Services\Request;
use Origo\Services\Renderer;
use Origo\Services\Template;
use Origo\Entity\User;
class UserLoginController implements ControllerInterface {
private $request;
private Renderer $renderer;
public function __construct() {
$this->request = new Request();
$this->renderer = new Renderer();
}
public function getResponse(): string {
$username = $this->request->post('username') ?? FALSE;
$password = $this->request->post('password') ?? FALSE;
$pw_hash = hash('sha256', $password);
// Check if user can login.
$user = new User();
$session_id = $user->login($username, $pw_hash);
if (!$session_id) {
return $this->renderer->render403();
}
else {
header("Location: /dashboard");
die();
}
}
}

22
src/Entity/Task.php Normal file
View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Origo\Entity;
final class Task {
protected int $id;
protected int $user_id;
protected string $task;
protected string $status;
protected string $external_url;
protected string $created_at;
public function load(int $task_id) {
// TODO: Implement load() method.
// Load the task from the database to the object.
}
}

83
src/Entity/User.php Normal file
View File

@ -0,0 +1,83 @@
<?php
namespace Origo\Entity;
use Origo\Services\Database;
class User {
protected $id;
protected $username;
protected $email;
protected $permissions = [];
protected $database;
public function __construct() {
$this->database = new Database();
}
public function get($property) {
return $this->{$property};
}
public function set($property, $value) {
$this->{$property} = $value;
}
public function getPermissions() {
return $this->permissions;
}
public function hasPermission($permission) {
return in_array($permission, $this->permissions);
}
public function login($username, $password) {
$statement = $this->database->prepare("SELECT username, id from users where username = ? AND password = ?");
$statement->execute([
$username,
$password
]);
$result = $statement->fetch();
if (!$result) {
return FALSE;
}
return $this->createSession($result['id']);
}
private function createSession(int $user_id = 0) {
// Bail out early if id is less than 1.
if ($user_id < 1) {
return FALSE;
}
$session_id = 'ORIGO' . bin2hex(random_bytes(16));
$stmt = $this->database->prepare("INSERT INTO sessions (user_id, session_id) VALUES (:user_id, :session_id)");
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':session_id', $session_id);
$success = $stmt->execute();
if ($success) {
setcookie("ORIGOSESS", $session_id, time() + 3600);
return $session_id;
}
}
public function loadUserFromSession(string $session_id) {
$statement = $this->database->prepare("SELECT user_id FROM sessions WHERE session_id = ?");
$statement->execute([$session_id]);
$result = $statement->fetch();
$this->id = $result['user_id'] ?? '';
$this->loadPermissions();
}
private function loadPermissions(): void {
$statement = $this->database->prepare("SELECT permission from permissions WHERE user_id = ?");
$statement->execute([$this->id]);
$result = $statement->fetch();
if ($result) {
foreach ($result as $permission) {
$this->permissions[] = $permission;
}
}
}
}

17
src/Services/Database.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace Origo\Services;
use PDO;
class Database extends PDO {
public $connection;
public function __construct() {
$database = '/app/database/origo.db';
parent::__construct("sqlite:{$database}");
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
}
}

17
src/Services/Renderer.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace Origo\Services;
use Origo\Services\Template;
final class Renderer {
/**
* Render a 403 page.
*/
public function render403() {
$template = new Template('403.html');
return $template->render();
}
}

89
src/Services/Request.php Normal file
View File

@ -0,0 +1,89 @@
<?php
namespace Origo\Services;
class Request {
/**
* Get a POST parameter.
*
* @param string $key
* The key.
* @param mixed $default
* The default value.
* @return mixed
* The value.
*/
public function post(string $key, $default = NULL) {
$input_stream = file_get_contents('php://input');
$input = [];
if ($input_stream) {
$parsed = parse_str($input_stream, $input);
}
else {
$input = $_POST;
}
return $input[$key] ?? $default;
}
/**
* Get a GET parameter.
*
* @param string $key
* The key.
* @param mixed $default
* The default value.
* @return mixed
* The value.
*/
public function get(string $key, $default = NULL) {
return $_GET[$key] ?? $default;
}
/**
* Get the request method.
*
* @return string
* The method.
*/
public function method(): string {
return $_SERVER['REQUEST_METHOD'];
}
/**
* Get the request IP.
*
* @return string
* The IP.
*/
public function ip(): string {
// Check common proxy headers first
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
return trim($ips[0]);
}
if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
return $_SERVER['HTTP_X_REAL_IP'];
}
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
}
// Fallback to REMOTE_ADDR
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
/**
* Get a cookie.
*
* @param string $key
* The key.
* @return string
* The value.
*/
public function getCookie(string $key): string {
return $_COOKIE[$key] ?? '';
}
}

55
src/Services/Router.php Normal file
View File

@ -0,0 +1,55 @@
<?php
namespace Origo\Services;
class Router {
/**
* The routes.
*
* @var array
*/
private $routes;
/**
* Add common services.
*/
public function __construct() {
$this->routes = [
'/' => \Origo\Controller\MainController::class,
'/planner' => \Origo\Controller\PlannerController::class,
'/dashboard' => \Origo\Controller\UserDashboardController::class,
'/user-login' => \Origo\Controller\UserLoginController::class,
'/api/v1/webhook' => \Origo\Controller\ApiWebhookController::class,
];
}
/**
* Get the route controller.
*
* @param string $path
* The path.
* @return string
* The controller.
*/
public function getRouteController(string $path): string {
return $this->routes[$path];
}
/**
* Check that the route exists.
*
* @param string $path
* The path.
* @return bool
*/
public function routeExists(string $path): bool {
$route_exists = FALSE;
if (array_key_exists($path, $this->routes)) {
$route_exists = TRUE;
}
return $route_exists;
}
}

65
src/Services/Template.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace Origo\Services;
class Template {
/**
* The template to render.
*/
protected $template;
/**
* Creates a new Template object.
*/
public function __construct($template_name) {
$this->template = file_get_contents('templates/' . $template_name);
}
/**
* Renders the template and returns the result.
*/
public function render(array $replacements = []) {
$this->swapHtml();
if ($replacements) {
$this->replaceSections($replacements);
}
return $this->template;
}
/**
* Replace dynamic sections.
*
* @param array $swaps
* An array of placeholders and their replacements.
*/
public function replaceSections(array $swaps) {
foreach ($swaps as $placeholder => $contents) {
$placeholder = "{{ " . $placeholder . " }}";
$this->template = str_replace($placeholder, $contents, $this->template);
}
}
/**
* Replaces all sections in the template with the contents of the included file.
*/
public function swapHtml() {
preg_match_all('/\[\[\s*(.+?)\s*\]\]/', $this->template, $matches);
foreach ($matches[0] as $i => $placeholder) {
$filename = $matches[1][$i];
$template_path = rtrim('templates', '/') . '/' . $filename;
if (file_exists($template_path)) {
$contents = file_get_contents($template_path);
}
else {
$contents = "<!-- Missing include: {$filename} -->";
}
$this->template = str_replace($placeholder, $contents, $this->template);
}
}
}

30
templates/403-body.html Normal file
View File

@ -0,0 +1,30 @@
<section role="main" id="denied">
<div class="container">
<div class="lock-container">
<div class="lock">
<div class="lock-shackle"></div>
<div class="lock-body">
<div class="lock-keyhole"></div>
</div>
</div>
</div>
<div class="error-code">403</div>
<h1 class="error-title">Access Denied</h1>
<p class="error-message">
Oops! You don't have permission to access this page. It's like trying to open a door without the right key.
</p>
<div class="button-group">
<a href="/" class="btn btn-primary">Go Home</a>
<a href="/login" class="btn btn-secondary">Sign In</a>
</div>
<div class="fun-fact">
<div class="fun-fact-title">Did you know?</div>
<div class="fun-fact-text">
The HTTP 403 status code was named after "Forbidden City" in Beijing, which was restricted to the imperial family. Just kidding—but it does mean "forbidden"!
</div>
</div>
</div>
</section>

8
templates/403.html Normal file
View File

@ -0,0 +1,8 @@
<html>
[[ head.html ]]
<body>
[[ header.html ]]
[[ 403-body.html ]]
</body>
</html>

13
templates/dash-body.html Normal file
View File

@ -0,0 +1,13 @@
<section role="main" id="dashboard">
<div class="dashboard-container">
<h1 class="page-title">Dashboard</h1>
<div id="dashboard-links">
<h4>Actions</h4>
<ul id="dash-menu">
<li><a href="/planner" class="btn btn-primary"><span class="material-symbols-outlined">edit_calendar</span>Planner</a></li>
<li><a href="/analytics" class="btn btn-primary"><span class="material-symbols-outlined">area_chart</span>Analytics</a></li>
<li><a href="/user-logout" class="btn btn-accent"><span class="material-symbols-outlined"> logout </span>Logout</a></li>
</ul>
</div>
</div>
</section>

8
templates/dashboard.html Normal file
View File

@ -0,0 +1,8 @@
<html>
[[ head.html ]]
<body>
[[ header.html ]]
[[ dash-body.html ]]
<!-- <script src="theme/dist/dash-bundle.js" defer="true"></script> -->
</body>
</html>

10
templates/head.html Normal file
View File

@ -0,0 +1,10 @@
<head>
<title>Origo</title>
<link rel="icon" type="image/png" href="../theme/images/favicon.png">
<link rel="stylesheet" href="../theme/style.css">
<script src="../theme/js/main.js" defer></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
</head>

7
templates/header.html Normal file
View File

@ -0,0 +1,7 @@
<header>
<div id="branding">
<div id="logo">
<a href="/"><img src="../theme/images/logo-leaf.png" alt="Origo"></a>
</div>
</div>
</header>

37
templates/home-body.html Normal file
View File

@ -0,0 +1,37 @@
<section role="main">
<div id="login">
<div class="container">
<div class="login-card">
<div class="login-header">
<h1 class="login-title">Welcome back</h1>
<p class="login-subtitle">Sign in to continue to your account</p>
</div>
<form method="POST" action="/user-login">
<div class="form-group">
<label for="username">Username</label>
<input
type="text"
id="username"
name="username"
placeholder="Enter your username"
required
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
id="password"
name="password"
placeholder="Enter your password"
required
/>
</div>
<button type="submit" class="login-button">Log In</button>
</form>
</div>
</div>
</section>

7
templates/main.html Normal file
View File

@ -0,0 +1,7 @@
<html>
[[ head.html ]]
<body>
[[ header.html ]]
[[ home-body.html ]]
</body>
</html>

11
templates/task-list.html Normal file
View File

@ -0,0 +1,11 @@
<html>
[[ head.html ]]
<body>
[[ header.html ]]
<section role="main" id="task-list">
<div class="container">
{{ tasks }}
</div>
</section>
</body>
</html>

BIN
theme/.DS_Store vendored Normal file

Binary file not shown.

66
theme/dist/dash-bundle.js vendored Normal file
View File

@ -0,0 +1,66 @@
(() => {
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
// theme/js/dashboard.js
var require_dashboard = __commonJS({
"theme/js/dashboard.js"() {
function updateStats(pageviews, sessions) {
document.getElementById("total-pageviews").textContent = pageviews.toLocaleString();
document.getElementById("total-sessions").textContent = sessions.toLocaleString();
}
function updateTable(data) {
const tbody = document.getElementById("table-body");
if (data.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="5" class="empty-state">
<span class="material-symbols-outlines">inbox</span>
<div>No data available</div>
</td>
</tr>
`;
return;
}
tbody.innerHTML = data.map((row) => `
<tr>
<td class="url-cell" title="${row.url}">${row.url}</td>
<td class="number-cell">${row.pageviews.toLocaleString()}</td>
<td class="number-cell">${row.uniquePageviews.toLocaleString()}</td>
<td class="number-cell">${row.sessions.toLocaleString()}</td>
<td class="number-cell">${row.sessionDuration}</td>
</tr>
`).join("");
}
setTimeout(() => {
updateStats(15234, 8456);
updateTable([
{
url: "/home",
pageviews: 5234,
uniquePageviews: 4521,
sessions: 3456,
sessionDuration: "3m 24s"
},
{
url: "/about",
pageviews: 2345,
uniquePageviews: 2100,
sessions: 1876,
sessionDuration: "2m 15s"
},
{
url: "/products",
pageviews: 1876,
uniquePageviews: 1654,
sessions: 1234,
sessionDuration: "4m 02s"
}
]);
}, 1500);
}
});
require_dashboard();
})();

BIN
theme/images/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

BIN
theme/images/logo-leaf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
theme/images/logo-main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

61
theme/js/dashboard.js Normal file
View File

@ -0,0 +1,61 @@
function updateStats(pageviews, sessions) {
document.getElementById('total-pageviews').textContent = pageviews.toLocaleString();
document.getElementById('total-sessions').textContent = sessions.toLocaleString();
}
// Example: How to populate the table
function updateTable(data) {
const tbody = document.getElementById('table-body');
if (data.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="5" class="empty-state">
<span class="material-symbols-outlines">inbox</span>
<div>No data available</div>
</td>
</tr>
`;
return;
}
tbody.innerHTML = data.map(row => `
<tr>
<td class="url-cell" title="${row.url}">${row.url}</td>
<td class="number-cell">${row.pageviews.toLocaleString()}</td>
<td class="number-cell">${row.uniquePageviews.toLocaleString()}</td>
<td class="number-cell">${row.sessions.toLocaleString()}</td>
<td class="number-cell">${row.sessionDuration}</td>
</tr>
`).join('');
}
// Example usage with sample data (you'll replace this with API calls)
setTimeout(() => {
// Update stats
updateStats(15234, 8456);
// Update table
updateTable([
{
url: '/home',
pageviews: 5234,
uniquePageviews: 4521,
sessions: 3456,
sessionDuration: '3m 24s'
},
{
url: '/about',
pageviews: 2345,
uniquePageviews: 2100,
sessions: 1876,
sessionDuration: '2m 15s'
},
{
url: '/products',
pageviews: 1876,
uniquePageviews: 1654,
sessions: 1234,
sessionDuration: '4m 02s'
}
]);
}, 1500);

0
theme/js/main.js Normal file
View File

209
theme/partials/403.scss Normal file
View File

@ -0,0 +1,209 @@
#denied {
background: linear-gradient(135deg, var(--color-soft-cream) 0%, var(--color-light-gray) 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
.container {
text-align: center;
max-width: 600px;
}
.lock-container {
position: relative;
margin-bottom: 2rem;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-20px); }
}
.lock {
width: 120px;
height: 140px;
margin: 0 auto;
position: relative;
}
.lock-body {
width: 120px;
height: 80px;
background: var(--color-primary);
border-radius: 12px;
position: absolute;
bottom: 0;
box-shadow: 0 10px 30px rgba(122, 155, 142, 0.3);
}
.lock-shackle {
width: 60px;
height: 60px;
border: 12px solid var(--color-primary);
border-radius: 50% 50% 0 0;
border-bottom: none;
position: absolute;
top: 0;
left: 30px;
animation: shake 0.5s ease-in-out;
}
@keyframes shake {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-5deg); }
75% { transform: rotate(5deg); }
}
.lock-keyhole {
width: 8px;
height: 20px;
background: var(--color-soft-cream);
border-radius: 4px 4px 0 0;
position: absolute;
bottom: 25px;
left: 56px;
}
.lock-keyhole::after {
content: '';
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 12px solid var(--color-soft-cream);
position: absolute;
top: 20px;
left: -4px;
}
.error-code {
font-size: 6rem;
font-weight: 700;
color: var(--color-primary);
line-height: 1;
margin-bottom: 1rem;
letter-spacing: -0.02em;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.3s;
}
@keyframes fadeIn {
to { opacity: 1; }
}
.error-title {
font-size: 2rem;
color: var(--color-text-primary);
margin-bottom: 1rem;
font-weight: 600;
letter-spacing: -0.02em;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.5s;
}
.error-message {
font-size: 1.1rem;
color: var(--color-text-secondary);
margin-bottom: 2.5rem;
line-height: 1.6;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.7s;
}
.button-group {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.9s;
}
.btn {
padding: 0.875rem 2rem;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
text-decoration: none;
transition: all 0.2s ease;
display: inline-block;
cursor: pointer;
border: none;
}
.btn-primary {
background: var(--color-primary);
color: white;
}
.btn-primary:hover {
background: #6b8a7e;
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(122, 155, 142, 0.3);
}
.btn-secondary {
background: white;
color: var(--color-primary);
border: 2px solid var(--color-primary);
}
.btn-secondary:hover {
background: var(--color-primary);
color: white;
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(122, 155, 142, 0.2);
}
.fun-fact {
margin-top: 3rem;
padding: 1.5rem;
background: white;
border-radius: 16px;
border-left: 4px solid var(--color-accent);
box-shadow: 0 4px 12px rgba(74, 74, 72, 0.08);
opacity: 0;
animation: fadeIn 0.5s ease forwards 1.1s;
}
.fun-fact-title {
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-accent);
margin-bottom: 0.5rem;
font-weight: 600;
}
.fun-fact-text {
color: var(--color-text-secondary);
font-size: 0.95rem;
line-height: 1.5;
}
@media (max-width: 640px) {
.error-code {
font-size: 4rem;
}
.error-title {
font-size: 1.5rem;
}
.error-message {
font-size: 1rem;
}
.button-group {
flex-direction: column;
width: 100%;
}
.btn {
width: 100%;
}
}
}

View File

@ -0,0 +1,23 @@
@keyframes grow-shrink {
0% {
height: 80px;
}
25% {
height: 200px;
}
50% {
height: 250px;
}
66% {
height: 200px;
}
75% {
height: 100px;
}
90% {
height: 300px;
}
100% {
height: 80px;
}
}

82
theme/partials/base.scss Normal file
View File

@ -0,0 +1,82 @@
:root {
/* Primary Colors */
--color-sage-green: #7A9B8E;
--color-warm-stone: #8B7E74;
/* Neutrals */
--color-soft-cream: #F5F3EF;
--color-light-gray: #E8E6E1;
--color-charcoal: #4A4A48;
--color-medium-gray: #878580;
/* Accent */
--color-terracotta: #C77E68;
/* Data Visualization */
--color-dusty-blue: #8A9BA8;
--color-muted-olive: #A8A070;
--color-soft-clay: #B89485;
/* Semantic Variables (optional - map to use cases) */
--color-primary: var(--color-sage-green);
--color-secondary: var(--color-warm-stone);
--color-accent: var(--color-terracotta);
--color-background: var(--color-soft-cream);
--color-surface: var(--color-light-gray);
--color-text-primary: var(--color-charcoal);
--color-text-secondary: var(--color-medium-gray);
/* Font Family */
--font-family: 'Jost', sans-serif;
--font-size: 16px;
/* Font Weights */
--font-weight-light: 300;
--font-weight-regular: 400;
--font-weight-bold: 700;
/* Font Sizes */
--font-size-small: 0.8rem;
--font-size-medium: 1rem;
--font-size-large: 1.2rem;
/* Line Heights */
--line-height-small: 1.2;
--line-height-medium: 1.4;
--line-height-large: 1.6;
}
a.btn {
display: flex;
gap: 3px;
align-items: center;
text-decoration: none;
border-radius: 8px;
padding: 0.5rem 1rem;
transition: all 0.2s ease;
color: var(--color-soft-cream);
&-accent {
background: var(--color-accent);
&:hover {
background: var(--color-secondary);
}
}
&-primary {
background: var(--color-primary);
&:hover {
background: var(--color-secondary);
}
}
&-soft-clay {
background: var(--color-soft-clay);
&:hover {
background: var(--color-secondary);
}
}
}

View File

@ -0,0 +1,25 @@
#dashboard {
.dashboard-container {
max-width: 800px;
margin: auto;
padding-bottom: 100px;
}
h1.page-title {
margin-bottom: 0;
}
ul#dash-menu {
display: flex;
gap: 12px;
justify-content: flex-start;
list-style: none;
padding: 0;
li {
display: flex;
align-items: center;
gap: 1rem;
}
}
}

View File

@ -0,0 +1,17 @@
header {
display: flex;
justify-content: center;
background-color: color(srgb 0.983 0.9683 0.9471)
}
#logo {
a {
padding: 0;
background: none;
color: white;
}
}
img {
max-width: 90px;
}

View File

@ -0,0 +1,147 @@
#login {
.container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.login-card {
background: white;
border-radius: 24px;
padding: 3rem;
width: 100%;
max-width: 440px;
box-shadow: 0 20px 60px rgba(74, 74, 72, 0.08);
border: 1px solid rgba(122, 155, 142, 0.1);
}
.login-header {
text-align: center;
margin-bottom: 2.5rem;
}
.login-title {
font-size: 1.75rem;
color: var(--color-text-primary);
font-weight: 600;
margin-bottom: 0.5rem;
letter-spacing: -0.02em;
}
.login-subtitle {
color: var(--color-text-secondary);
font-size: 0.95rem;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
color: var(--color-text-primary);
font-size: 0.9rem;
font-weight: 500;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 0.875rem 1rem;
border: 2px solid var(--color-light-gray);
border-radius: 12px;
font-size: 1rem;
color: var(--color-text-primary);
background: var(--color-background);
transition: all 0.2s ease;
outline: none;
}
input[type="text"]:focus,
input[type="password"]:focus {
border-color: var(--color-primary);
background: white;
box-shadow: 0 0 0 4px rgba(122, 155, 142, 0.1);
}
input::placeholder {
color: var(--color-medium-gray);
}
.login-button {
width: 100%;
padding: 1rem;
background: var(--color-primary);
color: white;
border: none;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
margin-top: 0.5rem;
}
.login-button:hover {
background: #6b8a7e;
transform: translateY(-1px);
box-shadow: 0 8px 20px rgba(122, 155, 142, 0.3);
}
.login-button:active {
transform: translateY(0);
}
.form-footer {
margin-top: 1.5rem;
text-align: center;
}
.form-footer a {
color: var(--color-primary);
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
transition: color 0.2s ease;
}
.form-footer a:hover {
color: var(--color-accent);
}
.divider {
display: flex;
align-items: center;
gap: 1rem;
margin: 2rem 0;
color: var(--color-medium-gray);
font-size: 0.85rem;
}
.divider::before,
.divider::after {
content: '';
flex: 1;
height: 1px;
background: var(--color-light-gray);
}
@media (max-width: 640px) {
.header {
padding: 1.5rem 1.5rem;
}
.login-card {
padding: 2rem 1.5rem;
border-radius: 20px;
}
.login-title {
font-size: 1.5rem;
}
}
}

54
theme/partials/reset.scss Normal file
View File

@ -0,0 +1,54 @@
/* 1. Use a more-intuitive box-sizing model */
*, *::before, *::after {
box-sizing: border-box;
}
/* 2. Remove default margin */
* {
margin: 0;
}
/* 3. Enable keyword animations */
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords;
}
}
body {
/* 4. Add accessible line-height */
line-height: 1.5;
/* 5. Improve text rendering */
-webkit-font-smoothing: antialiased;
}
/* 6. Improve media defaults */
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
/* 7. Inherit fonts for form controls */
input, button, textarea, select {
font: inherit;
}
/* 8. Avoid text overflows */
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
/* 9. Improve line wrapping */
p {
text-wrap: pretty;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance;
}
/*
10. Create a root stacking context
*/
#root, #__next {
isolation: isolate;
}

View File

@ -0,0 +1,64 @@
#task-list {
.container {
max-width: 800px;
margin: auto;
padding: 24px;
}
}
.task-container {
max-width: 700px;
margin: 0 auto;
display: flex;
flex-direction: row;
gap: 16px;
}
.task-card {
background: #ffffff;
border-radius: 16px;
padding: 24px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.04);
border: 1px solid var(--color-light-gray);
display: flex;
justify-content: space-between;
align-items: flex-start;
}
/* Left side of the card: Title and Link */
.task-info {
display: flex;
flex-direction: column;
gap: 8px;
}
.task-title {
font-size: 1.15rem;
font-weight: 600;
color: var(--color-charcoal);
margin: 0;
}
/* Status Badges */
.task-status {
padding: 6px 14px;
border-radius: 100px;
font-size: 0.75rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Pending: Subtle Terracotta */
.status-pending {
background-color: #FDF2F0; /* Very light version of terracotta */
color: var(--color-terracotta);
border: 1px solid #F5DBD3;
}
/* Completed: Subtle Sage */
.status-completed {
background-color: #F0F5F3; /* Very light version of sage */
color: var(--color-sage-green);
border: 1px solid #D1E0DA;
}

596
theme/style.css Normal file
View File

@ -0,0 +1,596 @@
/* 1. Use a more-intuitive box-sizing model */
*, *::before, *::after {
box-sizing: border-box;
}
/* 2. Remove default margin */
* {
margin: 0;
}
/* 3. Enable keyword animations */
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords;
}
}
body {
/* 4. Add accessible line-height */
line-height: 1.5;
/* 5. Improve text rendering */
-webkit-font-smoothing: antialiased;
}
/* 6. Improve media defaults */
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
/* 7. Inherit fonts for form controls */
input, button, textarea, select {
font: inherit;
}
/* 8. Avoid text overflows */
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
/* 9. Improve line wrapping */
p {
text-wrap: pretty;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance;
}
/*
10. Create a root stacking context
*/
#root, #__next {
isolation: isolate;
}
:root {
/* Primary Colors */
--color-sage-green: #7A9B8E;
--color-warm-stone: #8B7E74;
/* Neutrals */
--color-soft-cream: #F5F3EF;
--color-light-gray: #E8E6E1;
--color-charcoal: #4A4A48;
--color-medium-gray: #878580;
/* Accent */
--color-terracotta: #C77E68;
/* Data Visualization */
--color-dusty-blue: #8A9BA8;
--color-muted-olive: #A8A070;
--color-soft-clay: #B89485;
/* Semantic Variables (optional - map to use cases) */
--color-primary: var(--color-sage-green);
--color-secondary: var(--color-warm-stone);
--color-accent: var(--color-terracotta);
--color-background: var(--color-soft-cream);
--color-surface: var(--color-light-gray);
--color-text-primary: var(--color-charcoal);
--color-text-secondary: var(--color-medium-gray);
/* Font Family */
--font-family: "Jost", sans-serif;
--font-size: 16px;
/* Font Weights */
--font-weight-light: 300;
--font-weight-regular: 400;
--font-weight-bold: 700;
/* Font Sizes */
--font-size-small: 0.8rem;
--font-size-medium: 1rem;
--font-size-large: 1.2rem;
/* Line Heights */
--line-height-small: 1.2;
--line-height-medium: 1.4;
--line-height-large: 1.6;
}
a.btn {
display: flex;
gap: 3px;
align-items: center;
text-decoration: none;
border-radius: 8px;
padding: 0.5rem 1rem;
transition: all 0.2s ease;
color: var(--color-soft-cream);
}
a.btn-accent {
background: var(--color-accent);
}
a.btn-accent:hover {
background: var(--color-secondary);
}
a.btn-primary {
background: var(--color-primary);
}
a.btn-primary:hover {
background: var(--color-secondary);
}
a.btn-soft-clay {
background: var(--color-soft-clay);
}
a.btn-soft-clay:hover {
background: var(--color-secondary);
}
header {
display: flex;
justify-content: center;
background-color: color(srgb 0.983 0.9683 0.9471);
}
#logo a {
padding: 0;
background: none;
color: white;
}
img {
max-width: 90px;
}
@keyframes grow-shrink {
0% {
height: 80px;
}
25% {
height: 200px;
}
50% {
height: 250px;
}
66% {
height: 200px;
}
75% {
height: 100px;
}
90% {
height: 300px;
}
100% {
height: 80px;
}
}
#login .container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
#login .login-card {
background: white;
border-radius: 24px;
padding: 3rem;
width: 100%;
max-width: 440px;
box-shadow: 0 20px 60px rgba(74, 74, 72, 0.08);
border: 1px solid rgba(122, 155, 142, 0.1);
}
#login .login-header {
text-align: center;
margin-bottom: 2.5rem;
}
#login .login-title {
font-size: 1.75rem;
color: var(--color-text-primary);
font-weight: 600;
margin-bottom: 0.5rem;
letter-spacing: -0.02em;
}
#login .login-subtitle {
color: var(--color-text-secondary);
font-size: 0.95rem;
}
#login .form-group {
margin-bottom: 1.5rem;
}
#login label {
display: block;
margin-bottom: 0.5rem;
color: var(--color-text-primary);
font-size: 0.9rem;
font-weight: 500;
}
#login input[type=text],
#login input[type=password] {
width: 100%;
padding: 0.875rem 1rem;
border: 2px solid var(--color-light-gray);
border-radius: 12px;
font-size: 1rem;
color: var(--color-text-primary);
background: var(--color-background);
transition: all 0.2s ease;
outline: none;
}
#login input[type=text]:focus,
#login input[type=password]:focus {
border-color: var(--color-primary);
background: white;
box-shadow: 0 0 0 4px rgba(122, 155, 142, 0.1);
}
#login input::placeholder {
color: var(--color-medium-gray);
}
#login .login-button {
width: 100%;
padding: 1rem;
background: var(--color-primary);
color: white;
border: none;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
margin-top: 0.5rem;
}
#login .login-button:hover {
background: #6b8a7e;
transform: translateY(-1px);
box-shadow: 0 8px 20px rgba(122, 155, 142, 0.3);
}
#login .login-button:active {
transform: translateY(0);
}
#login .form-footer {
margin-top: 1.5rem;
text-align: center;
}
#login .form-footer a {
color: var(--color-primary);
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
transition: color 0.2s ease;
}
#login .form-footer a:hover {
color: var(--color-accent);
}
#login .divider {
display: flex;
align-items: center;
gap: 1rem;
margin: 2rem 0;
color: var(--color-medium-gray);
font-size: 0.85rem;
}
#login .divider::before,
#login .divider::after {
content: "";
flex: 1;
height: 1px;
background: var(--color-light-gray);
}
@media (max-width: 640px) {
#login .header {
padding: 1.5rem 1.5rem;
}
#login .login-card {
padding: 2rem 1.5rem;
border-radius: 20px;
}
#login .login-title {
font-size: 1.5rem;
}
}
#denied {
background: linear-gradient(135deg, var(--color-soft-cream) 0%, var(--color-light-gray) 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
#denied .container {
text-align: center;
max-width: 600px;
}
#denied .lock-container {
position: relative;
margin-bottom: 2rem;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
}
#denied .lock {
width: 120px;
height: 140px;
margin: 0 auto;
position: relative;
}
#denied .lock-body {
width: 120px;
height: 80px;
background: var(--color-primary);
border-radius: 12px;
position: absolute;
bottom: 0;
box-shadow: 0 10px 30px rgba(122, 155, 142, 0.3);
}
#denied .lock-shackle {
width: 60px;
height: 60px;
border: 12px solid var(--color-primary);
border-radius: 50% 50% 0 0;
border-bottom: none;
position: absolute;
top: 0;
left: 30px;
animation: shake 0.5s ease-in-out;
}
@keyframes shake {
0%, 100% {
transform: rotate(0deg);
}
25% {
transform: rotate(-5deg);
}
75% {
transform: rotate(5deg);
}
}
#denied .lock-keyhole {
width: 8px;
height: 20px;
background: var(--color-soft-cream);
border-radius: 4px 4px 0 0;
position: absolute;
bottom: 25px;
left: 56px;
}
#denied .lock-keyhole::after {
content: "";
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 12px solid var(--color-soft-cream);
position: absolute;
top: 20px;
left: -4px;
}
#denied .error-code {
font-size: 6rem;
font-weight: 700;
color: var(--color-primary);
line-height: 1;
margin-bottom: 1rem;
letter-spacing: -0.02em;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.3s;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
#denied .error-title {
font-size: 2rem;
color: var(--color-text-primary);
margin-bottom: 1rem;
font-weight: 600;
letter-spacing: -0.02em;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.5s;
}
#denied .error-message {
font-size: 1.1rem;
color: var(--color-text-secondary);
margin-bottom: 2.5rem;
line-height: 1.6;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.7s;
}
#denied .button-group {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
opacity: 0;
animation: fadeIn 0.5s ease forwards 0.9s;
}
#denied .btn {
padding: 0.875rem 2rem;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
text-decoration: none;
transition: all 0.2s ease;
display: inline-block;
cursor: pointer;
border: none;
}
#denied .btn-primary {
background: var(--color-primary);
color: white;
}
#denied .btn-primary:hover {
background: #6b8a7e;
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(122, 155, 142, 0.3);
}
#denied .btn-secondary {
background: white;
color: var(--color-primary);
border: 2px solid var(--color-primary);
}
#denied .btn-secondary:hover {
background: var(--color-primary);
color: white;
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(122, 155, 142, 0.2);
}
#denied .fun-fact {
margin-top: 3rem;
padding: 1.5rem;
background: white;
border-radius: 16px;
border-left: 4px solid var(--color-accent);
box-shadow: 0 4px 12px rgba(74, 74, 72, 0.08);
opacity: 0;
animation: fadeIn 0.5s ease forwards 1.1s;
}
#denied .fun-fact-title {
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-accent);
margin-bottom: 0.5rem;
font-weight: 600;
}
#denied .fun-fact-text {
color: var(--color-text-secondary);
font-size: 0.95rem;
line-height: 1.5;
}
@media (max-width: 640px) {
#denied .error-code {
font-size: 4rem;
}
#denied .error-title {
font-size: 1.5rem;
}
#denied .error-message {
font-size: 1rem;
}
#denied .button-group {
flex-direction: column;
width: 100%;
}
#denied .btn {
width: 100%;
}
}
#dashboard .dashboard-container {
max-width: 800px;
margin: auto;
padding-bottom: 100px;
}
#dashboard h1.page-title {
margin-bottom: 0;
}
#dashboard ul#dash-menu {
display: flex;
gap: 12px;
justify-content: flex-start;
list-style: none;
padding: 0;
}
#dashboard ul#dash-menu li {
display: flex;
align-items: center;
gap: 1rem;
}
#task-list .container {
max-width: 800px;
margin: auto;
padding: 24px;
}
.task-container {
max-width: 700px;
margin: 0 auto;
display: flex;
flex-direction: row;
gap: 16px;
}
.task-card {
background: #ffffff;
border-radius: 16px;
padding: 24px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.04);
border: 1px solid var(--color-light-gray);
display: flex;
justify-content: space-between;
align-items: flex-start;
}
/* Left side of the card: Title and Link */
.task-info {
display: flex;
flex-direction: column;
gap: 8px;
}
.task-title {
font-size: 1.15rem;
font-weight: 600;
color: var(--color-charcoal);
margin: 0;
}
/* Status Badges */
.task-status {
padding: 6px 14px;
border-radius: 100px;
font-size: 0.75rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Pending: Subtle Terracotta */
.status-pending {
background-color: #FDF2F0; /* Very light version of terracotta */
color: var(--color-terracotta);
border: 1px solid #F5DBD3;
}
/* Completed: Subtle Sage */
.status-completed {
background-color: #F0F5F3; /* Very light version of sage */
color: var(--color-sage-green);
border: 1px solid #D1E0DA;
}
body {
background: var(--color-primary);
font-family: var(--font-family);
color: var(--color-text-primary);
}
section {
background: var(--color-surface);
}
h1, h2, h3, h4, h5, h6 {
color: var(--color-text-primary);
font-family: var(--font-family);
}
a {
color: var(--color-text-secondary);
background: var(--color-accent);
display: block;
text-decoration: 1px transprent solid;
padding: 5px 10px;
}
.animate {
animation-name: grow-shrink;
animation-duration: 4s;
}
/*# sourceMappingURL=style.css.map */

1
theme/style.css.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["partials/reset.scss","partials/base.scss","partials/header.scss","partials/animations.scss","partials/login-form.scss","partials/403.scss","partials/dashboard.scss","partials/task-list.scss","style.scss"],"names":[],"mappings":"AAAA;AACA;EACE;;;AAGF;AACA;EACE;;;AAGF;AACA;EACE;IACE;;;AAIJ;AACE;EACA;AACA;EACA;;;AAGF;AACA;EACE;EACA;;;AAGF;AACA;EACE;;;AAGF;AACA;EACE;;;AAGF;AACA;EACE;;;AAEF;EACE;;;AAGF;AAAA;AAAA;AAGA;EACE;;;ACpDF;AACE;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;AAEA;EACA;AAEA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;EACA;AAEA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;AAEA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;;AAIJ;EACE;;AAEA;EACE;;AAIJ;EACE;;AAEA;EACE;;;AC9EN;EACE;EACA;EACA;;;AAIA;EACE;EACA;EACA;;;AAIJ;EACE;;;ACfF;EACE;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;;ACnBF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;AAAA;EAEE;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;;;AC9IN;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;IAAW;;EACX;IAAM;;;AAGR;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IAAW;;EACX;IAAM;;EACN;IAAM;;;AAGR;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IAAK;;;AAGP;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;IACA;;EAGF;IACE;;;;AC5MJ;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;;ACpBJ;EACE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;AACA;EACE;EACA;EACA;;;ACrDF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA","file":"style.css"}

36
theme/style.scss Normal file
View File

@ -0,0 +1,36 @@
@import 'partials/reset';
@import 'partials/base';
@import 'partials/header';
@import 'partials/animations';
@import 'partials/login-form';
@import 'partials/403';
@import 'partials/dashboard';
@import 'partials/task-list';
body {
background: var(--color-primary);
font-family: var(--font-family);
color: var(--color-text-primary);
}
section {
background: var(--color-surface);
}
h1, h2, h3, h4, h5, h6 {
color: var(--color-text-primary);
font-family: var(--font-family);
}
a {
color: var(--color-text-secondary);
background: var(--color-accent);
display: block;
text-decoration: 1px transprent solid;
padding: 5px 10px;
}
.animate {
animation-name: grow-shrink;
animation-duration: 4s;
}

22
vendor/autoload.php vendored Normal file
View File

@ -0,0 +1,22 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit67a51eedd840ed6bdd5dac7658eb06ec::getLoader();

579
vendor/composer/ClassLoader.php vendored Normal file
View File

@ -0,0 +1,579 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

396
vendor/composer/InstalledVersions.php vendored Normal file
View File

@ -0,0 +1,396 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}
}

21
vendor/composer/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
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.

10
vendor/composer/autoload_classmap.php vendored Normal file
View File

@ -0,0 +1,10 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

12
vendor/composer/autoload_files.php vendored Normal file
View File

@ -0,0 +1,12 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
);

View File

@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

15
vendor/composer/autoload_psr4.php vendored Normal file
View File

@ -0,0 +1,15 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
'Origo\\' => array($baseDir . '/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
);

50
vendor/composer/autoload_real.php vendored Normal file
View File

@ -0,0 +1,50 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit67a51eedd840ed6bdd5dac7658eb06ec
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit67a51eedd840ed6bdd5dac7658eb06ec', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit67a51eedd840ed6bdd5dac7658eb06ec', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit67a51eedd840ed6bdd5dac7658eb06ec::getInitializer($loader));
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInit67a51eedd840ed6bdd5dac7658eb06ec::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
return $loader;
}
}

74
vendor/composer/autoload_static.php vendored Normal file
View File

@ -0,0 +1,74 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit67a51eedd840ed6bdd5dac7658eb06ec
{
public static $files = array (
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
);
public static $prefixLengthsPsr4 = array (
'P' =>
array (
'Psr\\Http\\Message\\' => 17,
'Psr\\Http\\Client\\' => 16,
),
'O' =>
array (
'Origo\\' => 6,
),
'G' =>
array (
'GuzzleHttp\\Psr7\\' => 16,
'GuzzleHttp\\Promise\\' => 19,
'GuzzleHttp\\' => 11,
),
);
public static $prefixDirsPsr4 = array (
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-factory/src',
1 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Psr\\Http\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-client/src',
),
'Origo\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
),
'GuzzleHttp\\Psr7\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'GuzzleHttp\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
),
'GuzzleHttp\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit67a51eedd840ed6bdd5dac7658eb06ec::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit67a51eedd840ed6bdd5dac7658eb06ec::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit67a51eedd840ed6bdd5dac7658eb06ec::$classMap;
}, null, ClassLoader::class);
}
}

626
vendor/composer/installed.json vendored Normal file
View File

@ -0,0 +1,626 @@
{
"packages": [
{
"name": "guzzlehttp/guzzle",
"version": "7.10.0",
"version_normalized": "7.10.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"time": "2025-08-23T22:36:01+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"installation-source": "dist",
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"install-path": "../guzzlehttp/guzzle"
},
{
"name": "guzzlehttp/promises",
"version": "2.3.0",
"version_normalized": "2.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"time": "2025-08-22T14:34:08+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"install-path": "../guzzlehttp/promises"
},
{
"name": "guzzlehttp/psr7",
"version": "2.8.0",
"version_normalized": "2.8.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"time": "2025-08-23T21:21:41+00:00",
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://sagikazarmark.hu"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"install-path": "../guzzlehttp/psr7"
},
{
"name": "psr/http-client",
"version": "1.0.3",
"version_normalized": "1.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0 || ^2.0"
},
"time": "2023-09-23T14:17:50+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client"
},
"install-path": "../psr/http-client"
},
{
"name": "psr/http-factory",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"time": "2024-04-15T12:06:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
"message",
"psr",
"psr-17",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory"
},
"install-path": "../psr/http-factory"
},
{
"name": "psr/http-message",
"version": "2.0",
"version_normalized": "2.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"time": "2023-04-04T09:54:51+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"install-path": "../psr/http-message"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"version_normalized": "3.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"time": "2019-03-08T08:55:37+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph Khattar",
"email": "ralph.khattar@gmail.com"
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"install-path": "../ralouphie/getallheaders"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"version_normalized": "3.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"time": "2024-09-25T14:21:43+00:00",
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/deprecation-contracts"
}
],
"dev": true,
"dev-package-names": []
}

113
vendor/composer/installed.php vendored Normal file
View File

@ -0,0 +1,113 @@
<?php return array(
'root' => array(
'name' => 'dan612/origo',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'dan612/origo' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '7.10.0',
'version' => '7.10.0.0',
'reference' => 'b51ac707cfa420b7bfd4e4d5e510ba8008e822b4',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '2.3.0',
'version' => '2.3.0.0',
'reference' => '481557b130ef3790cf82b713667b43030dc9c957',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.8.0',
'version' => '2.8.0.0',
'reference' => '21dc724a0583619cd1652f673303492272778051',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-client' => array(
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-client',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-client-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
),
),
'psr/http-factory' => array(
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-factory-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
),
),
'psr/http-message' => array(
'pretty_version' => '2.0',
'version' => '2.0.0.0',
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
'dev_requirement' => false,
),
'psr/http-message-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0',
),
),
'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v3.6.0',
'version' => '3.6.0.0',
'reference' => '63afe740e99a13ba87ec199bb07bbdee937a5b62',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

26
vendor/composer/platform_check.php vendored Normal file
View File

@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 80100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

1683
vendor/guzzlehttp/guzzle/CHANGELOG.md vendored Normal file

File diff suppressed because it is too large Load Diff

27
vendor/guzzlehttp/guzzle/LICENSE vendored Normal file
View File

@ -0,0 +1,27 @@
The MIT License (MIT)
Copyright (c) 2011 Michael Dowling <mtdowling@gmail.com>
Copyright (c) 2012 Jeremy Lindblom <jeremeamia@gmail.com>
Copyright (c) 2014 Graham Campbell <hello@gjcampbell.co.uk>
Copyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>
Copyright (c) 2015 Tobias Schultze <webmaster@tubo-world.de>
Copyright (c) 2016 Tobias Nyholm <tobias.nyholm@gmail.com>
Copyright (c) 2016 George Mponos <gmponos@gmail.com>
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.

94
vendor/guzzlehttp/guzzle/README.md vendored Normal file
View File

@ -0,0 +1,94 @@
![Guzzle](.github/logo.png?raw=true)
# Guzzle, PHP HTTP client
[![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
[![Build Status](https://img.shields.io/github/actions/workflow/status/guzzle/guzzle/ci.yml?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)
[![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)
Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
trivial to integrate with web services.
- Simple interface for building query strings, POST requests, streaming large
uploads, streaming large downloads, using HTTP cookies, uploading JSON data,
etc...
- Can send both synchronous and asynchronous requests using the same interface.
- Uses PSR-7 interfaces for requests, responses, and streams. This allows you
to utilize other PSR-7 compatible libraries with Guzzle.
- Supports PSR-18 allowing interoperability between other PSR-18 HTTP Clients.
- Abstracts away the underlying HTTP transport, allowing you to write
environment and transport agnostic code; i.e., no hard dependency on cURL,
PHP streams, sockets, or non-blocking event loops.
- Middleware system allows you to augment and compose client behavior.
```php
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
echo $response->getStatusCode(); // 200
echo $response->getHeaderLine('content-type'); // 'application/json; charset=utf8'
echo $response->getBody(); // '{"id": 1420053, "name": "guzzle", ...}'
// Send an asynchronous request.
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
$promise = $client->sendAsync($request)->then(function ($response) {
echo 'I completed! ' . $response->getBody();
});
$promise->wait();
```
## Help and docs
We use GitHub issues only to discuss bugs and new features. For support please refer to:
- [Documentation](https://docs.guzzlephp.org)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/guzzle)
- [#guzzle](https://app.slack.com/client/T0D2S9JCT/CE6UAAKL4) channel on [PHP-HTTP Slack](https://slack.httplug.io/)
- [Gitter](https://gitter.im/guzzle/guzzle)
## Installing Guzzle
The recommended way to install Guzzle is through
[Composer](https://getcomposer.org/).
```bash
composer require guzzlehttp/guzzle
```
## Version Guidance
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|---------------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
| 3.x | EOL (2016-10-31) | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
| 4.x | EOL (2016-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
| 5.x | EOL (2019-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
| 6.x | EOL (2023-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.5 |
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5
[guzzle-7-repo]: https://github.com/guzzle/guzzle
[guzzle-3-docs]: https://guzzle3.readthedocs.io/
[guzzle-5-docs]: https://docs.guzzlephp.org/en/5.3/
[guzzle-6-docs]: https://docs.guzzlephp.org/en/6.5/
[guzzle-7-docs]: https://docs.guzzlephp.org/en/latest/
## Security
If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/guzzle/security/policy) for more information.
## License
Guzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information.
## For Enterprise
Available as part of the Tidelift Subscription
The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-guzzle?utm_source=packagist-guzzlehttp-guzzle&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)

1253
vendor/guzzlehttp/guzzle/UPGRADING.md vendored Normal file

File diff suppressed because it is too large Load Diff

131
vendor/guzzlehttp/guzzle/composer.json vendored Normal file
View File

@ -0,0 +1,131 @@
{
"name": "guzzlehttp/guzzle",
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"framework",
"http",
"rest",
"web service",
"curl",
"client",
"HTTP client",
"PSR-7",
"PSR-18"
],
"license": "MIT",
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"repositories": [
{
"type": "package",
"package": {
"name": "guzzle/client-integration-tests",
"version": "v3.0.2",
"dist": {
"url": "https://codeload.github.com/guzzle/client-integration-tests/zip/2c025848417c1135031fdf9c728ee53d0a7ceaee",
"type": "zip"
},
"require": {
"php": "^7.2.5 || ^8.0",
"phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.11",
"php-http/message": "^1.0 || ^2.0",
"guzzlehttp/psr7": "^1.7 || ^2.0",
"th3n3rd/cartesian-product": "^0.3"
},
"autoload": {
"psr-4": {
"Http\\Client\\Tests\\": "src/"
}
},
"bin": [
"bin/http_test_server"
]
}
}
],
"require": {
"php": "^7.2.5 || ^8.0",
"ext-json": "*",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"ext-curl": "*",
"bamarni/composer-bin-plugin": "^1.8.2",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"config": {
"allow-plugins": {
"bamarni/composer-bin-plugin": true
},
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"autoload-dev": {
"psr-4": {
"GuzzleHttp\\Tests\\": "tests/"
}
}
}

6
vendor/guzzlehttp/guzzle/package-lock.json generated vendored Normal file
View File

@ -0,0 +1,6 @@
{
"name": "guzzle",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@ -0,0 +1,28 @@
<?php
namespace GuzzleHttp;
use Psr\Http\Message\MessageInterface;
final class BodySummarizer implements BodySummarizerInterface
{
/**
* @var int|null
*/
private $truncateAt;
public function __construct(?int $truncateAt = null)
{
$this->truncateAt = $truncateAt;
}
/**
* Returns a summarized message body.
*/
public function summarize(MessageInterface $message): ?string
{
return $this->truncateAt === null
? Psr7\Message::bodySummary($message)
: Psr7\Message::bodySummary($message, $this->truncateAt);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace GuzzleHttp;
use Psr\Http\Message\MessageInterface;
interface BodySummarizerInterface
{
/**
* Returns a summarized message body.
*/
public function summarize(MessageInterface $message): ?string;
}

483
vendor/guzzlehttp/guzzle/src/Client.php vendored Normal file
View File

@ -0,0 +1,483 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* @final
*/
class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
{
use ClientTrait;
/**
* @var array Default request options
*/
private $config;
/**
* Clients accept an array of constructor parameters.
*
* Here's an example of creating a client using a base_uri and an array of
* default request options to apply to each request:
*
* $client = new Client([
* 'base_uri' => 'http://www.foo.com/1.0/',
* 'timeout' => 0,
* 'allow_redirects' => false,
* 'proxy' => '192.168.16.1:10'
* ]);
*
* Client configuration settings include the following options:
*
* - handler: (callable) Function that transfers HTTP requests over the
* wire. The function is called with a Psr7\Http\Message\RequestInterface
* and array of transfer options, and must return a
* GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
* Psr7\Http\Message\ResponseInterface on success.
* If no handler is provided, a default handler will be created
* that enables all of the request options below by attaching all of the
* default middleware to the handler.
* - base_uri: (string|UriInterface) Base URI of the client that is merged
* into relative URIs. Can be a string or instance of UriInterface.
* - **: any request option
*
* @param array $config Client configuration settings.
*
* @see RequestOptions for a list of available request options.
*/
public function __construct(array $config = [])
{
if (!isset($config['handler'])) {
$config['handler'] = HandlerStack::create();
} elseif (!\is_callable($config['handler'])) {
throw new InvalidArgumentException('handler must be a callable');
}
// Convert the base_uri to a UriInterface
if (isset($config['base_uri'])) {
$config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']);
}
$this->configureDefaults($config);
}
/**
* @param string $method
* @param array $args
*
* @return PromiseInterface|ResponseInterface
*
* @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
*/
public function __call($method, $args)
{
if (\count($args) < 1) {
throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
}
$uri = $args[0];
$opts = $args[1] ?? [];
return \substr($method, -5) === 'Async'
? $this->requestAsync(\substr($method, 0, -5), $uri, $opts)
: $this->request($method, $uri, $opts);
}
/**
* Asynchronously send an HTTP request.
*
* @param array $options Request options to apply to the given
* request and to the transfer. See \GuzzleHttp\RequestOptions.
*/
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
{
// Merge the base URI into the request URI if needed.
$options = $this->prepareDefaults($options);
return $this->transfer(
$request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
$options
);
}
/**
* Send an HTTP request.
*
* @param array $options Request options to apply to the given
* request and to the transfer. See \GuzzleHttp\RequestOptions.
*
* @throws GuzzleException
*/
public function send(RequestInterface $request, array $options = []): ResponseInterface
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->sendAsync($request, $options)->wait();
}
/**
* The HttpClient PSR (PSR-18) specify this method.
*
* {@inheritDoc}
*/
public function sendRequest(RequestInterface $request): ResponseInterface
{
$options[RequestOptions::SYNCHRONOUS] = true;
$options[RequestOptions::ALLOW_REDIRECTS] = false;
$options[RequestOptions::HTTP_ERRORS] = false;
return $this->sendAsync($request, $options)->wait();
}
/**
* Create and send an asynchronous HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string $method HTTP method
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
*/
public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
{
$options = $this->prepareDefaults($options);
// Remove request modifying parameter because it can be done up-front.
$headers = $options['headers'] ?? [];
$body = $options['body'] ?? null;
$version = $options['version'] ?? '1.1';
// Merge the URI into the base URI.
$uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options);
if (\is_array($body)) {
throw $this->invalidBody();
}
$request = new Psr7\Request($method, $uri, $headers, $body, $version);
// Remove the option so that they are not doubly-applied.
unset($options['headers'], $options['body'], $options['version']);
return $this->transfer($request, $options);
}
/**
* Create and send an HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string $method HTTP method.
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
*
* @throws GuzzleException
*/
public function request(string $method, $uri = '', array $options = []): ResponseInterface
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->requestAsync($method, $uri, $options)->wait();
}
/**
* Get a client configuration option.
*
* These options include default request options of the client, a "handler"
* (if utilized by the concrete client), and a "base_uri" if utilized by
* the concrete client.
*
* @param string|null $option The config option to retrieve.
*
* @return mixed
*
* @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
*/
public function getConfig(?string $option = null)
{
return $option === null
? $this->config
: ($this->config[$option] ?? null);
}
private function buildUri(UriInterface $uri, array $config): UriInterface
{
if (isset($config['base_uri'])) {
$uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri);
}
if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
$idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion'];
$uri = Utils::idnUriConvert($uri, $idnOptions);
}
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
}
/**
* Configures the default options for a client.
*/
private function configureDefaults(array $config): void
{
$defaults = [
'allow_redirects' => RedirectMiddleware::$defaultSettings,
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false,
'idn_conversion' => false,
];
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
// We can only trust the HTTP_PROXY environment variable in a CLI
// process due to the fact that PHP has no reliable mechanism to
// get environment variables that start with "HTTP_".
if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
$defaults['proxy']['http'] = $proxy;
}
if ($proxy = Utils::getenv('HTTPS_PROXY')) {
$defaults['proxy']['https'] = $proxy;
}
if ($noProxy = Utils::getenv('NO_PROXY')) {
$cleanedNoProxy = \str_replace(' ', '', $noProxy);
$defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
}
$this->config = $config + $defaults;
if (!empty($config['cookies']) && $config['cookies'] === true) {
$this->config['cookies'] = new CookieJar();
}
// Add the default user-agent header.
if (!isset($this->config['headers'])) {
$this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
} else {
// Add the User-Agent header if one was not already set.
foreach (\array_keys($this->config['headers']) as $name) {
if (\strtolower($name) === 'user-agent') {
return;
}
}
$this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
}
}
/**
* Merges default options into the array.
*
* @param array $options Options to modify by reference
*/
private function prepareDefaults(array $options): array
{
$defaults = $this->config;
if (!empty($defaults['headers'])) {
// Default headers are only added if they are not present.
$defaults['_conditional'] = $defaults['headers'];
unset($defaults['headers']);
}
// Special handling for headers is required as they are added as
// conditional headers and as headers passed to a request ctor.
if (\array_key_exists('headers', $options)) {
// Allows default headers to be unset.
if ($options['headers'] === null) {
$defaults['_conditional'] = [];
unset($options['headers']);
} elseif (!\is_array($options['headers'])) {
throw new InvalidArgumentException('headers must be an array');
}
}
// Shallow merge defaults underneath options.
$result = $options + $defaults;
// Remove null values.
foreach ($result as $k => $v) {
if ($v === null) {
unset($result[$k]);
}
}
return $result;
}
/**
* Transfers the given request and applies request options.
*
* The URI of the request is not modified and the request options are used
* as-is without merging in default options.
*
* @param array $options See \GuzzleHttp\RequestOptions.
*/
private function transfer(RequestInterface $request, array $options): PromiseInterface
{
$request = $this->applyOptions($request, $options);
/** @var HandlerStack $handler */
$handler = $options['handler'];
try {
return P\Create::promiseFor($handler($request, $options));
} catch (\Exception $e) {
return P\Create::rejectionFor($e);
}
}
/**
* Applies the array of request options to a request.
*/
private function applyOptions(RequestInterface $request, array &$options): RequestInterface
{
$modify = [
'set_headers' => [],
];
if (isset($options['headers'])) {
if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) {
throw new InvalidArgumentException('The headers array must have header name as keys.');
}
$modify['set_headers'] = $options['headers'];
unset($options['headers']);
}
if (isset($options['form_params'])) {
if (isset($options['multipart'])) {
throw new InvalidArgumentException('You cannot use '
.'form_params and multipart at the same time. Use the '
.'form_params option if you want to send application/'
.'x-www-form-urlencoded requests, and the multipart '
.'option to send multipart/form-data requests.');
}
$options['body'] = \http_build_query($options['form_params'], '', '&');
unset($options['form_params']);
// Ensure that we don't have the header in different case and set the new value.
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
}
if (isset($options['multipart'])) {
$options['body'] = new Psr7\MultipartStream($options['multipart']);
unset($options['multipart']);
}
if (isset($options['json'])) {
$options['body'] = Utils::jsonEncode($options['json']);
unset($options['json']);
// Ensure that we don't have the header in different case and set the new value.
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'application/json';
}
if (!empty($options['decode_content'])
&& $options['decode_content'] !== true
) {
// Ensure that we don't have the header in different case and set the new value.
$options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
$modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
}
if (isset($options['body'])) {
if (\is_array($options['body'])) {
throw $this->invalidBody();
}
$modify['body'] = Psr7\Utils::streamFor($options['body']);
unset($options['body']);
}
if (!empty($options['auth']) && \is_array($options['auth'])) {
$value = $options['auth'];
$type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
switch ($type) {
case 'basic':
// Ensure that we don't have the header in different case and set the new value.
$modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
$modify['set_headers']['Authorization'] = 'Basic '
.\base64_encode("$value[0]:$value[1]");
break;
case 'digest':
// @todo: Do not rely on curl
$options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
$options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
break;
case 'ntlm':
$options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
$options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
break;
}
}
if (isset($options['query'])) {
$value = $options['query'];
if (\is_array($value)) {
$value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
}
if (!\is_string($value)) {
throw new InvalidArgumentException('query must be a string or array');
}
$modify['query'] = $value;
unset($options['query']);
}
// Ensure that sink is not an invalid value.
if (isset($options['sink'])) {
// TODO: Add more sink validation?
if (\is_bool($options['sink'])) {
throw new InvalidArgumentException('sink must not be a boolean');
}
}
if (isset($options['version'])) {
$modify['version'] = $options['version'];
}
$request = Psr7\Utils::modifyRequest($request, $modify);
if ($request->getBody() instanceof Psr7\MultipartStream) {
// Use a multipart/form-data POST if a Content-Type is not set.
// Ensure that we don't have the header in different case and set the new value.
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
.$request->getBody()->getBoundary();
}
// Merge in conditional headers if they are not present.
if (isset($options['_conditional'])) {
// Build up the changes so it's in a single clone of the message.
$modify = [];
foreach ($options['_conditional'] as $k => $v) {
if (!$request->hasHeader($k)) {
$modify['set_headers'][$k] = $v;
}
}
$request = Psr7\Utils::modifyRequest($request, $modify);
// Don't pass this internal value along to middleware/handlers.
unset($options['_conditional']);
}
return $request;
}
/**
* Return an InvalidArgumentException with pre-set message.
*/
private function invalidBody(): InvalidArgumentException
{
return new InvalidArgumentException('Passing in the "body" request '
.'option as an array to send a request is not supported. '
.'Please use the "form_params" request option to send a '
.'application/x-www-form-urlencoded request, or the "multipart" '
.'request option to send a multipart/form-data request.');
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* Client interface for sending HTTP requests.
*/
interface ClientInterface
{
/**
* The Guzzle major version.
*/
public const MAJOR_VERSION = 7;
/**
* Send an HTTP request.
*
* @param RequestInterface $request Request to send
* @param array $options Request options to apply to the given
* request and to the transfer.
*
* @throws GuzzleException
*/
public function send(RequestInterface $request, array $options = []): ResponseInterface;
/**
* Asynchronously send an HTTP request.
*
* @param RequestInterface $request Request to send
* @param array $options Request options to apply to the given
* request and to the transfer.
*/
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface;
/**
* Create and send an HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string $method HTTP method.
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function request(string $method, $uri, array $options = []): ResponseInterface;
/**
* Create and send an asynchronous HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string $method HTTP method
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;
/**
* Get a client configuration option.
*
* These options include default request options of the client, a "handler"
* (if utilized by the concrete client), and a "base_uri" if utilized by
* the concrete client.
*
* @param string|null $option The config option to retrieve.
*
* @return mixed
*
* @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
*/
public function getConfig(?string $option = null);
}

View File

@ -0,0 +1,241 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* Client interface for sending HTTP requests.
*/
trait ClientTrait
{
/**
* Create and send an HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string $method HTTP method.
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
abstract public function request(string $method, $uri, array $options = []): ResponseInterface;
/**
* Create and send an HTTP GET request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function get($uri, array $options = []): ResponseInterface
{
return $this->request('GET', $uri, $options);
}
/**
* Create and send an HTTP HEAD request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function head($uri, array $options = []): ResponseInterface
{
return $this->request('HEAD', $uri, $options);
}
/**
* Create and send an HTTP PUT request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function put($uri, array $options = []): ResponseInterface
{
return $this->request('PUT', $uri, $options);
}
/**
* Create and send an HTTP POST request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function post($uri, array $options = []): ResponseInterface
{
return $this->request('POST', $uri, $options);
}
/**
* Create and send an HTTP PATCH request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function patch($uri, array $options = []): ResponseInterface
{
return $this->request('PATCH', $uri, $options);
}
/**
* Create and send an HTTP DELETE request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*
* @throws GuzzleException
*/
public function delete($uri, array $options = []): ResponseInterface
{
return $this->request('DELETE', $uri, $options);
}
/**
* Create and send an asynchronous HTTP request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string $method HTTP method
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
abstract public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;
/**
* Create and send an asynchronous HTTP GET request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function getAsync($uri, array $options = []): PromiseInterface
{
return $this->requestAsync('GET', $uri, $options);
}
/**
* Create and send an asynchronous HTTP HEAD request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function headAsync($uri, array $options = []): PromiseInterface
{
return $this->requestAsync('HEAD', $uri, $options);
}
/**
* Create and send an asynchronous HTTP PUT request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function putAsync($uri, array $options = []): PromiseInterface
{
return $this->requestAsync('PUT', $uri, $options);
}
/**
* Create and send an asynchronous HTTP POST request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function postAsync($uri, array $options = []): PromiseInterface
{
return $this->requestAsync('POST', $uri, $options);
}
/**
* Create and send an asynchronous HTTP PATCH request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function patchAsync($uri, array $options = []): PromiseInterface
{
return $this->requestAsync('PATCH', $uri, $options);
}
/**
* Create and send an asynchronous HTTP DELETE request.
*
* Use an absolute path to override the base path of the client, or a
* relative path to append to the base path of the client. The URL can
* contain the query string as well. Use an array to provide a URL
* template and additional variables to use in the URL template expansion.
*
* @param string|UriInterface $uri URI object or string.
* @param array $options Request options to apply.
*/
public function deleteAsync($uri, array $options = []): PromiseInterface
{
return $this->requestAsync('DELETE', $uri, $options);
}
}

View File

@ -0,0 +1,307 @@
<?php
namespace GuzzleHttp\Cookie;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Cookie jar that stores cookies as an array
*/
class CookieJar implements CookieJarInterface
{
/**
* @var SetCookie[] Loaded cookie data
*/
private $cookies = [];
/**
* @var bool
*/
private $strictMode;
/**
* @param bool $strictMode Set to true to throw exceptions when invalid
* cookies are added to the cookie jar.
* @param array $cookieArray Array of SetCookie objects or a hash of
* arrays that can be used with the SetCookie
* constructor
*/
public function __construct(bool $strictMode = false, array $cookieArray = [])
{
$this->strictMode = $strictMode;
foreach ($cookieArray as $cookie) {
if (!($cookie instanceof SetCookie)) {
$cookie = new SetCookie($cookie);
}
$this->setCookie($cookie);
}
}
/**
* Create a new Cookie jar from an associative array and domain.
*
* @param array $cookies Cookies to create the jar from
* @param string $domain Domain to set the cookies to
*/
public static function fromArray(array $cookies, string $domain): self
{
$cookieJar = new self();
foreach ($cookies as $name => $value) {
$cookieJar->setCookie(new SetCookie([
'Domain' => $domain,
'Name' => $name,
'Value' => $value,
'Discard' => true,
]));
}
return $cookieJar;
}
/**
* Evaluate if this cookie should be persisted to storage
* that survives between requests.
*
* @param SetCookie $cookie Being evaluated.
* @param bool $allowSessionCookies If we should persist session cookies
*/
public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
{
if ($cookie->getExpires() || $allowSessionCookies) {
if (!$cookie->getDiscard()) {
return true;
}
}
return false;
}
/**
* Finds and returns the cookie based on the name
*
* @param string $name cookie name to search for
*
* @return SetCookie|null cookie that was found or null if not found
*/
public function getCookieByName(string $name): ?SetCookie
{
foreach ($this->cookies as $cookie) {
if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
return $cookie;
}
}
return null;
}
public function toArray(): array
{
return \array_map(static function (SetCookie $cookie): array {
return $cookie->toArray();
}, $this->getIterator()->getArrayCopy());
}
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
{
if (!$domain) {
$this->cookies = [];
return;
} elseif (!$path) {
$this->cookies = \array_filter(
$this->cookies,
static function (SetCookie $cookie) use ($domain): bool {
return !$cookie->matchesDomain($domain);
}
);
} elseif (!$name) {
$this->cookies = \array_filter(
$this->cookies,
static function (SetCookie $cookie) use ($path, $domain): bool {
return !($cookie->matchesPath($path)
&& $cookie->matchesDomain($domain));
}
);
} else {
$this->cookies = \array_filter(
$this->cookies,
static function (SetCookie $cookie) use ($path, $domain, $name) {
return !($cookie->getName() == $name
&& $cookie->matchesPath($path)
&& $cookie->matchesDomain($domain));
}
);
}
}
public function clearSessionCookies(): void
{
$this->cookies = \array_filter(
$this->cookies,
static function (SetCookie $cookie): bool {
return !$cookie->getDiscard() && $cookie->getExpires();
}
);
}
public function setCookie(SetCookie $cookie): bool
{
// If the name string is empty (but not 0), ignore the set-cookie
// string entirely.
$name = $cookie->getName();
if (!$name && $name !== '0') {
return false;
}
// Only allow cookies with set and valid domain, name, value
$result = $cookie->validate();
if ($result !== true) {
if ($this->strictMode) {
throw new \RuntimeException('Invalid cookie: '.$result);
}
$this->removeCookieIfEmpty($cookie);
return false;
}
// Resolve conflicts with previously set cookies
foreach ($this->cookies as $i => $c) {
// Two cookies are identical, when their path, and domain are
// identical.
if ($c->getPath() != $cookie->getPath()
|| $c->getDomain() != $cookie->getDomain()
|| $c->getName() != $cookie->getName()
) {
continue;
}
// The previously set cookie is a discard cookie and this one is
// not so allow the new cookie to be set
if (!$cookie->getDiscard() && $c->getDiscard()) {
unset($this->cookies[$i]);
continue;
}
// If the new cookie's expiration is further into the future, then
// replace the old cookie
if ($cookie->getExpires() > $c->getExpires()) {
unset($this->cookies[$i]);
continue;
}
// If the value has changed, we better change it
if ($cookie->getValue() !== $c->getValue()) {
unset($this->cookies[$i]);
continue;
}
// The cookie exists, so no need to continue
return false;
}
$this->cookies[] = $cookie;
return true;
}
public function count(): int
{
return \count($this->cookies);
}
/**
* @return \ArrayIterator<int, SetCookie>
*/
public function getIterator(): \ArrayIterator
{
return new \ArrayIterator(\array_values($this->cookies));
}
public function extractCookies(RequestInterface $request, ResponseInterface $response): void
{
if ($cookieHeader = $response->getHeader('Set-Cookie')) {
foreach ($cookieHeader as $cookie) {
$sc = SetCookie::fromString($cookie);
if (!$sc->getDomain()) {
$sc->setDomain($request->getUri()->getHost());
}
if (0 !== \strpos($sc->getPath(), '/')) {
$sc->setPath($this->getCookiePathFromRequest($request));
}
if (!$sc->matchesDomain($request->getUri()->getHost())) {
continue;
}
// Note: At this point `$sc->getDomain()` being a public suffix should
// be rejected, but we don't want to pull in the full PSL dependency.
$this->setCookie($sc);
}
}
}
/**
* Computes cookie path following RFC 6265 section 5.1.4
*
* @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4
*/
private function getCookiePathFromRequest(RequestInterface $request): string
{
$uriPath = $request->getUri()->getPath();
if ('' === $uriPath) {
return '/';
}
if (0 !== \strpos($uriPath, '/')) {
return '/';
}
if ('/' === $uriPath) {
return '/';
}
$lastSlashPos = \strrpos($uriPath, '/');
if (0 === $lastSlashPos || false === $lastSlashPos) {
return '/';
}
return \substr($uriPath, 0, $lastSlashPos);
}
public function withCookieHeader(RequestInterface $request): RequestInterface
{
$values = [];
$uri = $request->getUri();
$scheme = $uri->getScheme();
$host = $uri->getHost();
$path = $uri->getPath() ?: '/';
foreach ($this->cookies as $cookie) {
if ($cookie->matchesPath($path)
&& $cookie->matchesDomain($host)
&& !$cookie->isExpired()
&& (!$cookie->getSecure() || $scheme === 'https')
) {
$values[] = $cookie->getName().'='
.$cookie->getValue();
}
}
return $values
? $request->withHeader('Cookie', \implode('; ', $values))
: $request;
}
/**
* If a cookie already exists and the server asks to set it again with a
* null value, the cookie must be deleted.
*/
private function removeCookieIfEmpty(SetCookie $cookie): void
{
$cookieValue = $cookie->getValue();
if ($cookieValue === null || $cookieValue === '') {
$this->clear(
$cookie->getDomain(),
$cookie->getPath(),
$cookie->getName()
);
}
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace GuzzleHttp\Cookie;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Stores HTTP cookies.
*
* It extracts cookies from HTTP requests, and returns them in HTTP responses.
* CookieJarInterface instances automatically expire contained cookies when
* necessary. Subclasses are also responsible for storing and retrieving
* cookies from a file, database, etc.
*
* @see https://docs.python.org/2/library/cookielib.html Inspiration
*
* @extends \IteratorAggregate<SetCookie>
*/
interface CookieJarInterface extends \Countable, \IteratorAggregate
{
/**
* Create a request with added cookie headers.
*
* If no matching cookies are found in the cookie jar, then no Cookie
* header is added to the request and the same request is returned.
*
* @param RequestInterface $request Request object to modify.
*
* @return RequestInterface returns the modified request.
*/
public function withCookieHeader(RequestInterface $request): RequestInterface;
/**
* Extract cookies from an HTTP response and store them in the CookieJar.
*
* @param RequestInterface $request Request that was sent
* @param ResponseInterface $response Response that was received
*/
public function extractCookies(RequestInterface $request, ResponseInterface $response): void;
/**
* Sets a cookie in the cookie jar.
*
* @param SetCookie $cookie Cookie to set.
*
* @return bool Returns true on success or false on failure
*/
public function setCookie(SetCookie $cookie): bool;
/**
* Remove cookies currently held in the cookie jar.
*
* Invoking this method without arguments will empty the whole cookie jar.
* If given a $domain argument only cookies belonging to that domain will
* be removed. If given a $domain and $path argument, cookies belonging to
* the specified path within that domain are removed. If given all three
* arguments, then the cookie with the specified name, path and domain is
* removed.
*
* @param string|null $domain Clears cookies matching a domain
* @param string|null $path Clears cookies matching a domain and path
* @param string|null $name Clears cookies matching a domain, path, and name
*/
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;
/**
* Discard all sessions cookies.
*
* Removes cookies that don't have an expire field or a have a discard
* field set to true. To be called when the user agent shuts down according
* to RFC 2965.
*/
public function clearSessionCookies(): void;
/**
* Converts the cookie jar to an array.
*/
public function toArray(): array;
}

View File

@ -0,0 +1,101 @@
<?php
namespace GuzzleHttp\Cookie;
use GuzzleHttp\Utils;
/**
* Persists non-session cookies using a JSON formatted file
*/
class FileCookieJar extends CookieJar
{
/**
* @var string filename
*/
private $filename;
/**
* @var bool Control whether to persist session cookies or not.
*/
private $storeSessionCookies;
/**
* Create a new FileCookieJar object
*
* @param string $cookieFile File to store the cookie data
* @param bool $storeSessionCookies Set to true to store session cookies
* in the cookie jar.
*
* @throws \RuntimeException if the file cannot be found or created
*/
public function __construct(string $cookieFile, bool $storeSessionCookies = false)
{
parent::__construct();
$this->filename = $cookieFile;
$this->storeSessionCookies = $storeSessionCookies;
if (\file_exists($cookieFile)) {
$this->load($cookieFile);
}
}
/**
* Saves the file when shutting down
*/
public function __destruct()
{
$this->save($this->filename);
}
/**
* Saves the cookies to a file.
*
* @param string $filename File to save
*
* @throws \RuntimeException if the file cannot be found or created
*/
public function save(string $filename): void
{
$json = [];
/** @var SetCookie $cookie */
foreach ($this as $cookie) {
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
$json[] = $cookie->toArray();
}
}
$jsonStr = Utils::jsonEncode($json);
if (false === \file_put_contents($filename, $jsonStr, \LOCK_EX)) {
throw new \RuntimeException("Unable to save file {$filename}");
}
}
/**
* Load cookies from a JSON formatted file.
*
* Old cookies are kept unless overwritten by newly loaded ones.
*
* @param string $filename Cookie file to load.
*
* @throws \RuntimeException if the file cannot be loaded.
*/
public function load(string $filename): void
{
$json = \file_get_contents($filename);
if (false === $json) {
throw new \RuntimeException("Unable to load file {$filename}");
}
if ($json === '') {
return;
}
$data = Utils::jsonDecode($json, true);
if (\is_array($data)) {
foreach ($data as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (\is_scalar($data) && !empty($data)) {
throw new \RuntimeException("Invalid cookie file: {$filename}");
}
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace GuzzleHttp\Cookie;
/**
* Persists cookies in the client session
*/
class SessionCookieJar extends CookieJar
{
/**
* @var string session key
*/
private $sessionKey;
/**
* @var bool Control whether to persist session cookies or not.
*/
private $storeSessionCookies;
/**
* Create a new SessionCookieJar object
*
* @param string $sessionKey Session key name to store the cookie
* data in session
* @param bool $storeSessionCookies Set to true to store session cookies
* in the cookie jar.
*/
public function __construct(string $sessionKey, bool $storeSessionCookies = false)
{
parent::__construct();
$this->sessionKey = $sessionKey;
$this->storeSessionCookies = $storeSessionCookies;
$this->load();
}
/**
* Saves cookies to session when shutting down
*/
public function __destruct()
{
$this->save();
}
/**
* Save cookies to the client session
*/
public function save(): void
{
$json = [];
/** @var SetCookie $cookie */
foreach ($this as $cookie) {
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
$json[] = $cookie->toArray();
}
}
$_SESSION[$this->sessionKey] = \json_encode($json);
}
/**
* Load the contents of the client session into the data array
*/
protected function load(): void
{
if (!isset($_SESSION[$this->sessionKey])) {
return;
}
$data = \json_decode($_SESSION[$this->sessionKey], true);
if (\is_array($data)) {
foreach ($data as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (\strlen($data)) {
throw new \RuntimeException('Invalid cookie data');
}
}
}

Some files were not shown because too many files have changed in this diff Show More