cjm-fasthtml-byok
Install
pip install cjm_fasthtml_byok
Project Structure
nbs/
├── components/ (2)
│ ├── alerts.ipynb # FastHTML alert and notification components for user feedback
│ └── forms.ipynb # FastHTML form components for API key input and management
├── core/ (3)
│ ├── security.ipynb # Encryption and security utilities for API key management
│ ├── storage.ipynb # Storage backends for API keys (session and database)
│ └── types.ipynb # Type definitions and protocols for the BYOK system
├── middleware/ (1)
│ └── beforeware.ipynb # FastHTML beforeware for API key management
└── utils/ (1)
└── helpers.ipynb # Helper functions for BYOK system
Total: 7 notebooks across 4 directories
Module Dependencies
graph LR
components_alerts[components.alerts<br/>Alerts]
components_forms[components.forms<br/>Forms]
core_security[core.security<br/>Security]
core_storage[core.storage<br/>Storage]
core_types[core.types<br/>Types]
middleware_beforeware[middleware.beforeware<br/>Beforeware]
utils_helpers[utils.helpers<br/>Helpers]
components_forms --> core_security
components_forms --> utils_helpers
core_security --> core_types
core_storage --> core_types
core_storage --> core_security
middleware_beforeware --> core_security
middleware_beforeware --> core_types
middleware_beforeware --> core_storage
utils_helpers --> core_security
9 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
Alerts (alerts.ipynb)
FastHTML alert and notification components for user feedback
Import
from cjm_fasthtml_byok.components.alerts import (
InfoIcon,
SuccessIcon,
WarningIcon,
ErrorIcon,
Alert,
SecurityAlert,
KeyStatusNotification,
ToastContainer,
Toast,
ValidationMessage,
AlertStack
)
Functions
def InfoIcon(
size: str = "6" # Size of the icon (matches Tailwind h-{size} and w-{size} classes)
) -> FT: # SVG element for the info icon
"Create an info icon SVG."
def SuccessIcon(
size: str = "6" # Size of the icon (matches Tailwind h-{size} and w-{size} classes)
) -> FT: # SVG element for the success icon
"Create a success/check icon SVG."
def WarningIcon(
size: str = "6" # Size of the icon (matches Tailwind h-{size} and w-{size} classes)
) -> FT: # SVG element for the warning icon
"Create a warning/exclamation icon SVG."
def ErrorIcon(
size: str = "6" # Size of the icon (matches Tailwind h-{size} and w-{size} classes)
) -> FT: # SVG element for the error icon
"Create an error/X icon SVG."
def Alert(
message: str, # The alert message
kind: Literal["info", "success", "warning", "error"] = "info",
title: Optional[str] = None, # Optional title for the alert
dismissible: bool = False, # Whether the alert can be dismissed
show_icon: bool = True, # Whether to show an icon
style: Optional[str] = None, # Alert style ("soft", "outline", or None for default)
id: Optional[str] = None # HTML ID for the alert element
) -> FT: # Alert component
"Create an alert component for displaying messages."
def SecurityAlert(
message: str, # Security alert message
severity: Literal["low", "medium", "high", "critical"] = "medium",
action_url: Optional[str] = None, # Optional URL for remediation action
action_text: str = "Fix Now" # Text for the action button
) -> FT: # Security alert component
"Create a security-focused alert with severity levels."
def KeyStatusNotification(
provider: str, # Provider name
status: Literal["added", "updated", "deleted", "expired", "invalid"],
masked_key: Optional[str] = None, # Masked version of the key
auto_dismiss: bool = True, # Whether to auto-dismiss
dismiss_after: int = 5000 # Milliseconds before auto-dismiss
) -> FT: # Key status notification component
"Create a notification for API key status changes."
def ToastContainer(
position: Literal["top", "middle", "bottom"] = "top",
align: Literal["start", "center", "end"] = "end",
id: str = "toast-container" # HTML ID for the container
) -> FT: # Toast container component
"Create a container for toast notifications."
def Toast(
message: str, # Toast message
kind: Literal["info", "success", "warning", "error"] = "info",
duration: int = 3000 # Duration in milliseconds
) -> FT: # Toast notification component
"Create a toast notification."
def ValidationMessage(
message: str, # Validation message
is_valid: bool = False, # Whether the validation passed
show_icon: bool = True # Whether to show an icon
) -> FT: # Validation message component
"Create an inline validation message for form fields."
def AlertStack(
alerts: list, # List of alert components
max_visible: int = 3, # Maximum number of visible alerts
spacing: str = "4" # Gap between alerts
) -> FT: # Alert stack component
"Create a stack of alerts with optional limit."
Beforeware (beforeware.ipynb)
FastHTML beforeware for API key management
Import
from cjm_fasthtml_byok.middleware.beforeware import (
create_byok_beforeware,
require_api_key,
require_any_api_key,
SecurityCheckBeforeware,
CleanupBeforeware,
setup_byok
)
Functions
def create_byok_beforeware(
byok_manager: BYOKManager # The BYOK manager instance
)
"Create a FastHTML beforeware handler for BYOK functionality."
def require_api_key(
provider: str, # The provider name to check for
user_id_func: Optional[Callable] = None # Optional function to get user_id from request Usage: @rt @require_api_key("openai") def chat(request): byok = request.scope['byok'] api_key = byok.get_key(request, "openai") # Use the API key...
)
"Decorator that requires an API key to be present for a route."
def require_any_api_key(
providers: List[str], # List of provider names to check
user_id_func: Optional[Callable] = None # Optional function to get user_id from request Usage: @rt @require_any_api_key(["openai", "anthropic", "google"]) def chat(request): # Use whichever API key is available pass
)
"Decorator that requires at least one of the specified API keys."
def setup_byok(
secret_key: str, # Application secret key
db: Optional[Any] = None, # Optional database for persistent storage
user_id_func: Optional[Callable] = None, # Optional function to get user_id from request
enable_security_checks: bool = True, # Enable HTTPS checking
enable_cleanup: bool = True # Enable automatic cleanup of expired keys
)
"Complete setup helper for BYOK with FastHTML. Returns beforeware functions and the BYOK manager."
Classes
class SecurityCheckBeforeware:
def __init__(
self,
require_https: bool = True, # Whether to require HTTPS in production
is_production: Optional[bool] = None # Whether running in production (auto-detected if None)
)
"Beforeware that performs security checks."
def __init__(
self,
require_https: bool = True, # Whether to require HTTPS in production
is_production: Optional[bool] = None # Whether running in production (auto-detected if None)
)
"Initialize security check beforeware with HTTPS requirements"
class CleanupBeforeware:
def __init__(
self,
byok_manager: BYOKManager, # The BYOK manager instance
user_id_func: Optional[Callable] = None # Optional function to get user_id from request
)
"Beforeware that cleans up expired keys."
def __init__(
self,
byok_manager: BYOKManager, # The BYOK manager instance
user_id_func: Optional[Callable] = None # Optional function to get user_id from request
)
"Initialize cleanup beforeware with BYOK manager"
Forms (forms.ipynb)
FastHTML form components for API key input and management
Import
from cjm_fasthtml_byok.components.forms import (
KeyInputForm,
MultiProviderKeyForm,
KeyManagementCard,
KeyManagerDashboard,
InlineKeyInput
)
Functions
def KeyInputForm(
provider: str, # The API provider identifier
action: Optional[str] = None, # Form action URL (defaults to /api/keys/{provider})
method: str = "post", # HTTP method (default: "post")
show_help: bool = True, # Whether to show help text
custom_placeholder: Optional[str] = None, # Custom placeholder text
extra_fields: Optional[List[tuple]] = None, # Additional form fields as [(name, type, placeholder, required), ...]
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> FT: # FastHTML Form component
"Create a form for inputting an API key with improved design."
def MultiProviderKeyForm(
providers: List[str], # List of provider identifiers
action: str = "/api/keys", # Form action URL
method: str = "post", # HTTP method
default_provider: Optional[str] = None, # Initially selected provider
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> FT: # FastHTML Form component with provider selection
"Create a form that allows selecting from multiple providers with enhanced UX."
def KeyManagementCard(
provider: str, # Provider identifier
has_key: bool, # Whether a key is stored
masked_key: Optional[str] = None, # Masked version of the key for display
created_at: Optional[str] = None, # When the key was stored
expires_at: Optional[str] = None, # When the key expires
delete_action: Optional[str] = None, # URL for delete action
update_action: Optional[str] = None, # URL for update action
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> FT: # Card component for key management
"Create a card component for managing a stored API key with enhanced design."
def KeyManagerDashboard(
request, # FastHTML request object
providers: List[str], # List of provider identifiers to manage
byok_manager = None,
user_id: Optional[str] = None, # Optional user ID for database storage
base_url: str = "/api/keys", # Base URL for API endpoints
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> FT: # Dashboard component with all provider cards
"Create a complete dashboard for managing multiple API keys with improved layout."
def InlineKeyInput(
provider: str, # Provider identifier
input_id: Optional[str] = None, # HTML ID for the input element
on_save: Optional[str] = None, # JavaScript to execute on save (or hx-post URL for HTMX)
compact: bool = True, # Whether to use compact styling
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> FT: # Inline input component
"Create a compact inline key input component with polished design."
Helpers (helpers.ipynb)
Helper functions for BYOK system
Import
from cjm_fasthtml_byok.utils.helpers import (
get_provider_info,
format_provider_name,
format_key_age,
format_expiration,
get_key_summary,
get_env_key,
import_from_env
)
Functions
def get_provider_info(
provider: str, # Provider identifier
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> Dict[str, Any]: # Provider info dict with defaults
"Get provider information from config or generate defaults."
def format_provider_name(
provider: str, # Provider identifier
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> str: # Formatted provider name
"Format provider name for display."
def format_key_age(
created_at: datetime # When the key was created
) -> str: # Human-readable age string
"Format the age of a key for display."
def format_expiration(
expires_at: Optional[datetime] # Expiration datetime
) -> str: # Human-readable expiration string
"Format expiration time for display."
def get_key_summary(
byok_manager, # BYOK manager instance
request, # FastHTML request
user_id: Optional[str] = None, # Optional user ID
provider_config: Optional[Dict[str, Any]] = None # Optional provider configuration
) -> Dict[str, Any]: # Summary dictionary with provider info
"Get a summary of all stored keys."
def get_env_key(
provider: str, # Provider name
env_prefix: str = "API_KEY_" # Environment variable prefix
) -> Optional[str]: # API key from environment or None
"Get an API key from environment variables."
def import_from_env(
byok_manager, # BYOK manager instance
request, # FastHTML request
providers: List[str], # List of providers to check
user_id: Optional[str] = None, # Optional user ID
env_prefix: str = "API_KEY_" # Environment variable prefix
) -> Dict[str, bool]: # Dict of provider: success status
"Import API keys from environment variables."
Security (security.ipynb)
Encryption and security utilities for API key management
Import
from cjm_fasthtml_byok.core.security import (
generate_encryption_key,
get_or_create_app_key,
KeyEncryptor,
check_https,
validate_environment,
mask_key,
get_key_fingerprint
)
Functions
def generate_encryption_key(
password: Optional[str] = None, # Optional password to derive key from
salt: Optional[bytes] = None # Optional salt for key derivation (required if password provided)
) -> bytes: # 32-byte encryption key suitable for Fernet
"Generate or derive an encryption key."
def get_or_create_app_key(
"Get or create an app-specific encryption key derived from the app's secret key."
def check_https(
request # FastHTML/Starlette request object
) -> bool: # True if using HTTPS, False otherwise
"Check if the request is using HTTPS."
def validate_environment(
request, # FastHTML/Starlette request object
require_https: bool = True, # Whether to require HTTPS
is_production: bool = None # Whether running in production (auto-detected if None)
) -> None
"Validate the security environment."
def mask_key(
key: str, # The API key to mask
visible_chars: int = 4 # Number of characters to show at start and end
) -> str: # Masked key like 'sk-a...xyz'
"Mask an API key for display purposes."
def get_key_fingerprint(
key: str # The API key
) -> str: # SHA256 fingerprint of the key (first 16 chars)
"Generate a fingerprint for an API key (for logging/tracking without exposing the key)."
Classes
class KeyEncryptor:
def __init__(
self,
encryption_key: Optional[bytes] = None # Encryption key to use. If None, generates a new one
)
"Handles encryption and decryption of API keys."
def __init__(
self,
encryption_key: Optional[bytes] = None # Encryption key to use. If None, generates a new one
)
"Initialize the encryptor.
Args:
encryption_key: Encryption key to use. If None, generates a new one."
def encrypt(
self,
value: str # Plain text API key to encrypt
) -> bytes: # Encrypted bytes
"Encrypt an API key value.
Args:
value: Plain text API key
Returns:
Encrypted bytes
Raises:
EncryptionError: If encryption fails"
def decrypt(
self,
encrypted_value: bytes # Encrypted bytes to decrypt
) -> str: # Decrypted plain text API key
"Decrypt an API key value.
Args:
encrypted_value: Encrypted bytes
Returns:
Decrypted API key
Raises:
EncryptionError: If decryption fails"
def rotate_key(
self,
new_key: bytes, # New encryption key to use
encrypted_value: bytes # Value encrypted with current key
) -> bytes: # Value re-encrypted with new key
"Re-encrypt a value with a new key.
Args:
new_key: New encryption key
encrypted_value: Value encrypted with current key
Returns:
Value encrypted with new key"
Storage (storage.ipynb)
Storage backends for API keys (session and database)
Import
from cjm_fasthtml_byok.core.storage import (
SessionStorage,
DatabaseStorage,
HybridStorage,
BYOKManager
)
Classes
class SessionStorage:
def __init__(
self,
config: BYOKConfig # BYOK configuration object
)
"""
Session-based storage for API keys.
Keys are stored in the user's session and expire with the session.
"""
def __init__(
self,
config: BYOKConfig # BYOK configuration object
)
"Initialize session storage with configuration"
def store(
self,
request: Any, # FastHTML/Starlette request object with session
key: APIKey # API key object to store
) -> None
"Store an API key in the session"
def retrieve(
self,
request: Any, # FastHTML/Starlette request object with session
provider: str, # Provider name to retrieve key for
user_id: Optional[str] = None # User ID (unused in session storage)
) -> Optional[APIKey]: # API key object if found and valid, None otherwise
"Retrieve an API key from the session"
def delete(
self,
request: Any, # FastHTML/Starlette request object with session
provider: str, # Provider name to delete key for
user_id: Optional[str] = None # User ID (unused in session storage)
) -> None
"Delete an API key from the session"
def list_providers(
self,
request: Any, # FastHTML/Starlette request object with session
user_id: Optional[str] = None # User ID (unused in session storage)
) -> List[str]: # List of provider names with stored keys
"List all providers with stored keys"
def clear_all(
self,
request: Any, # FastHTML/Starlette request object with session
user_id: Optional[str] = None # User ID (unused in session storage)
) -> None
"Clear all API keys from the session"
class DatabaseStorage:
def __init__(
self,
config: BYOKConfig, # BYOK configuration object
db_url: str = "sqlite:///byok_keys.db" # Database URL (defaults to SQLite)
)
"""
Database-backed storage for API keys using SQLAlchemy 2.0+.
Keys persist across sessions and devices.
"""
def __init__(
self,
config: BYOKConfig, # BYOK configuration object
db_url: str = "sqlite:///byok_keys.db" # Database URL (defaults to SQLite)
)
"Initialize database storage with SQLAlchemy."
def store(
self,
request: Any, # FastHTML/Starlette request object (unused but kept for interface consistency)
key: APIKey # API key object to store in database
) -> None
"Store an API key in the database"
def retrieve(
self,
request: Any, # FastHTML/Starlette request object (unused but kept for interface consistency)
provider: str, # Provider name to retrieve key for
user_id: Optional[str] = None # User ID to retrieve key for (required for database)
) -> Optional[APIKey]: # API key object if found and valid, None otherwise
"Retrieve an API key from the database"
def delete(
self,
request: Any, # FastHTML/Starlette request object (unused but kept for interface consistency)
provider: str, # Provider name to delete key for
user_id: Optional[str] = None # User ID to delete key for (required for database)
) -> None
"Delete an API key from the database"
def list_providers(
self,
request: Any, # FastHTML/Starlette request object (unused but kept for interface consistency)
user_id: Optional[str] = None # User ID to list providers for (required for database)
) -> List[str]: # List of provider names with stored keys
"List all providers with stored keys for a user"
def clear_all(
self,
request: Any, # FastHTML/Starlette request object (unused but kept for interface consistency)
user_id: Optional[str] = None # User ID to clear keys for (required for database)
) -> None
"Clear all API keys for a user"
class HybridStorage:
def __init__(
self,
config: BYOKConfig, # BYOK configuration object
db_url: Optional[str] = None # Optional database URL for persistent storage
)
"""
Hybrid storage using both session and database.
Session acts as a cache, database provides persistence.
"""
def __init__(
self,
config: BYOKConfig, # BYOK configuration object
db_url: Optional[str] = None # Optional database URL for persistent storage
)
"Initialize hybrid storage with session and optional database backends"
def store(
self,
request: Any, # FastHTML/Starlette request object with session
key: APIKey # API key object to store
) -> None
"Store in both session and database"
def retrieve(
self,
request: Any, # FastHTML/Starlette request object with session
provider: str, # Provider name to retrieve key for
user_id: Optional[str] = None # User ID for database lookup
) -> Optional[APIKey]: # API key object if found, None otherwise
"Retrieve from session first, then database"
def delete(
self,
request: Any, # FastHTML/Starlette request object with session
provider: str, # Provider name to delete key for
user_id: Optional[str] = None # User ID for database deletion
) -> None
"Delete from both storages"
def list_providers(
self,
request: Any, # FastHTML/Starlette request object with session
user_id: Optional[str] = None # User ID for database lookup
) -> List[str]: # Combined list of providers from both storages
"List providers from both storages"
def clear_all(
self,
request: Any, # FastHTML/Starlette request object with session
user_id: Optional[str] = None # User ID for database clearing
) -> None
"Clear from both storages"
class BYOKManager:
def __init__(
self,
secret_key: str, # Application secret key for encryption
db_url: Optional[str] = None, # Optional database URL for persistent storage (e.g., "sqlite:///keys.db")
config: Optional[BYOKConfig] = None # Optional configuration (uses defaults if not provided)
)
"""
Main manager for the BYOK system.
Handles encryption and storage coordination.
"""
def __init__(
self,
secret_key: str, # Application secret key for encryption
db_url: Optional[str] = None, # Optional database URL for persistent storage (e.g., "sqlite:///keys.db")
config: Optional[BYOKConfig] = None # Optional configuration (uses defaults if not provided)
)
"Initialize the BYOK manager."
def set_key(
self,
request: Any, # FastHTML/Starlette request object
provider: str, # Provider name (e.g., 'openai', 'anthropic')
api_key: str, # The API key to store
user_id: Optional[str] = None, # Optional user ID for database storage
ttl: Optional[timedelta] = None # Optional time-to-live for the key
) -> None
"Store an API key."
def get_key(
self,
request: Any, # FastHTML/Starlette request object
provider: str, # Provider name
user_id: Optional[str] = None # Optional user ID for database lookup
) -> Optional[str]: # Decrypted API key or None if not found
"Retrieve and decrypt an API key."
def delete_key(
self,
request: Any, # FastHTML/Starlette request object
provider: str, # Provider name
user_id: Optional[str] = None # Optional user ID
) -> None
"Delete an API key."
def list_providers(
self,
request: Any, # FastHTML/Starlette request object
user_id: Optional[str] = None # Optional user ID
) -> List[str]: # List of provider names
"List all providers with stored keys."
def clear_keys(
self,
request: Any, # FastHTML/Starlette request object
user_id: Optional[str] = None # Optional user ID
) -> None
"Clear all stored API keys."
def has_key(
self,
request: Any, # FastHTML/Starlette request object
provider: str, # Provider name
user_id: Optional[str] = None # Optional user ID
) -> bool: # True if key exists, False otherwise
"Check if a key exists for a provider."
Types (types.ipynb)
Type definitions and protocols for the BYOK system
Import
from cjm_fasthtml_byok.core.types import (
StorageBackend,
APIKey,
KeyStorage,
BYOKConfig,
UserAPIKey,
BYOKException,
EncryptionError,
StorageError,
KeyNotFoundError,
SecurityWarning
)
Classes
class StorageBackend(Enum):
"Available storage backends for API keys"
@dataclass
class APIKey:
"Represents an encrypted API key with metadata"
provider: str # e.g., 'openai', 'anthropic', 'google'
encrypted_value: bytes # Encrypted key value
created_at: datetime = field(...)
expires_at: Optional[datetime]
user_id: Optional[str] # For database storage
def is_expired(
self
) -> bool: # True if key has expired, False otherwise
"Check if the key has expired"
def to_dict(
self
) -> Dict[str, Any]: # Dictionary representation for serialization
"Convert to dictionary for storage"
def from_dict(
cls, # The APIKey class
data: Dict[str, Any] # Dictionary containing serialized key data
) -> 'APIKey': # Reconstructed APIKey instance
"Create from dictionary"
@runtime_checkable
class KeyStorage(Protocol):
"Protocol for key storage implementations"
def store(
self,
request: Any, # FastHTML/Starlette request object
key: APIKey # API key object to store
) -> None
"Store an API key"
def retrieve(
self,
request: Any, # FastHTML/Starlette request object
provider: str, # Provider name to retrieve key for
user_id: Optional[str] = None # Optional user ID for database lookup
) -> Optional[APIKey]: # API key object if found, None otherwise
"Retrieve an API key for a provider"
def delete(
self,
request: Any, # FastHTML/Starlette request object
provider: str, # Provider name to delete key for
user_id: Optional[str] = None # Optional user ID for database deletion
) -> None
"Delete an API key"
def list_providers(
self,
request: Any, # FastHTML/Starlette request object
user_id: Optional[str] = None # Optional user ID for database lookup
) -> list[str]: # List of provider names with stored keys
"List all stored providers"
def clear_all(
self,
request: Any, # FastHTML/Starlette request object
user_id: Optional[str] = None # Optional user ID for database clearing
) -> None
"Clear all stored keys"
@dataclass
class BYOKConfig:
"Configuration for the BYOK system"
storage_backend: StorageBackend = StorageBackend.SESSION
encryption_key: Optional[bytes] # If None, will be generated
default_ttl: Optional[timedelta] = timedelta(hours=24) # Default key expiration
session_key_prefix: str = 'byok_' # Prefix for session storage keys
db_table_name: str = 'user_api_keys' # Database table name
auto_cleanup: bool = True # Auto-cleanup expired keys
require_https: bool = True # Warn if not using HTTPS in production
class UserAPIKey:
"Database schema for persistent API key storage (for use with fastsql)"
class BYOKException(Exception):
"Base exception for BYOK errors"
class EncryptionError(BYOKException):
"Error during encryption/decryption"
class StorageError(BYOKException):
"Error during storage operations"
class KeyNotFoundError(BYOKException):
"Requested key not found"
class SecurityWarning(BYOKException):
"Security-related warning"
Metadata
Release files for cjm-fasthtml-byok 0.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| cjm_fasthtml_byok-0.0.3.tar.gz | 38.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cjm_fasthtml_byok-0.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 74.4 kB
Release files / cjm_fasthtml_byok-0.0.3.tar.gz
| Download URL | cjm_fasthtml_byok-0.0.3.tar.gz |
|---|---|
| Size | 38.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
55f03ccdb2cac8e65e04b011e5e72a7a399d992e1f113b3bd7998895b1c77781
|
|
BLAKE2b-256 checksum How to use checksums |
fd3ba66d6cd9073533ff1d285febd2e9bdf750cc2237372b690f8c39b7813585
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.13
|
Release files / cjm_fasthtml_byok-0.0.3-py3-none-any.whl
| Download URL | cjm_fasthtml_byok-0.0.3-py3-none-any.whl |
|---|---|
| Size | 36.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6a1d9477e645a9ce1e31d60d9c735edc8863fe31ffb683a86274dc8059899e17
|
|
BLAKE2b-256 checksum How to use checksums |
f82cc08dab4bed11c1ecead1dfab706de0c21510b26a29b7f107627b7f02ece7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.13
|
Security for cjm-fasthtml-byok 0.0.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.