Compare commits
14 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7928c0ef14 | |||
| b7b313c2e9 | |||
| ffcfe9bbcb | |||
| b61f05b96d | |||
| 9ae01eb90c | |||
| 0e1903f419 | |||
| 3303ae4be0 | |||
| f9582d3c7b | |||
| 90599c2e7c | |||
| ea3aa1413f | |||
| 34152dabc3 | |||
| b159b4c00a | |||
| 97b897a557 | |||
| dfa904042e |
47 changed files with 4500 additions and 12571 deletions
54
.forgejo/workflows/botlib.yaml
Normal file
54
.forgejo/workflows/botlib.yaml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
name: GBCI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# Disabled auto-trigger - enable when needed
|
||||
# push:
|
||||
# branches: ["main"]
|
||||
# pull_request:
|
||||
# branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: gbo
|
||||
|
||||
steps:
|
||||
- name: Disable SSL verification (temporary)
|
||||
run: git config --global http.sslVerify false
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-botlib-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-botlib-
|
||||
|
||||
- name: Install Rust
|
||||
uses: msrd0/rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build library (default features)
|
||||
run: cargo build --locked
|
||||
|
||||
- name: Build library (full features)
|
||||
run: cargo build --locked --features full
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --locked --features full
|
||||
|
||||
- name: Build release
|
||||
run: cargo build --locked --release --features full
|
||||
|
||||
- name: Deploy library
|
||||
run: |
|
||||
sudo mkdir -p /opt/gbo/lib/botlib
|
||||
sudo cp ./target/release/libbotlib.rlib /opt/gbo/lib/botlib/ || true
|
||||
sudo cp ./target/release/libbotlib.a /opt/gbo/lib/botlib/ || true
|
||||
sudo cp ./target/release/libbotlib.so /opt/gbo/lib/botlib/ || true
|
||||
20
.gitignore
vendored
20
.gitignore
vendored
|
|
@ -1,5 +1,15 @@
|
|||
node_modules
|
||||
docs
|
||||
dist
|
||||
xx.xx
|
||||
xx.yy
|
||||
.tmp*
|
||||
.tmp/*
|
||||
*.log
|
||||
target*
|
||||
.env
|
||||
target
|
||||
*.env
|
||||
work
|
||||
*.out
|
||||
bin
|
||||
botserver-stack
|
||||
*logfile*
|
||||
*-log*
|
||||
docs/book
|
||||
*.rdb
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
node_modules
|
||||
docs
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120,
|
||||
"arrowParens": "avoid",
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
2119
Cargo.lock
generated
Normal file
2119
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
38
Cargo.toml
Normal file
38
Cargo.toml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
[package]
|
||||
name = "botlib"
|
||||
version = "6.1.0"
|
||||
edition = "2021"
|
||||
description = "Shared library for General Bots - common types, utilities, and HTTP client"
|
||||
license = "AGPL-3.0"
|
||||
authors = ["Pragmatismo.com.br", "General Bots Community"]
|
||||
repository = "https://github.com/GeneralBots/BotServer"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
full = ["database", "http-client", "validation"]
|
||||
database = ["dep:diesel"]
|
||||
http-client = ["dep:reqwest"]
|
||||
validation = ["dep:validator"]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
anyhow = "1.0"
|
||||
thiserror = "2.0"
|
||||
log = "0.4"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
uuid = { version = "1.11", features = ["serde", "v4"] }
|
||||
toml = "0.8"
|
||||
|
||||
# Optional: Database
|
||||
diesel = { version = "2.1", features = ["postgres", "uuid", "chrono", "serde_json", "r2d2"], optional = true }
|
||||
|
||||
# Optional: HTTP Client
|
||||
reqwest = { version = "0.12", features = ["json"], optional = true }
|
||||
|
||||
# Optional: Validation
|
||||
validator = { version = "0.18", features = ["derive"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.41", features = ["rt", "macros"] }
|
||||
300
PROMPT.md
Normal file
300
PROMPT.md
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
# BotLib Development Prompt Guide
|
||||
|
||||
**Version:** 6.1.0
|
||||
**Purpose:** LLM context for BotLib shared library development
|
||||
|
||||
---
|
||||
|
||||
## Version Management - CRITICAL
|
||||
|
||||
**Current version is 6.1.0 - DO NOT CHANGE without explicit approval!**
|
||||
|
||||
### Rules
|
||||
|
||||
1. **Version is 6.1.0 across ALL workspace crates**
|
||||
2. **NEVER change version without explicit user approval**
|
||||
3. **All workspace crates share version 6.1.0**
|
||||
4. **BotLib does not have migrations - all migrations are in botserver/**
|
||||
|
||||
---
|
||||
|
||||
## Official Icons - Reference
|
||||
|
||||
**BotLib does not contain icons.** Icons are managed in:
|
||||
- `botui/ui/suite/assets/icons/` - Runtime UI icons
|
||||
- `botbook/src/assets/icons/` - Documentation icons
|
||||
|
||||
When documenting or referencing UI elements in BotLib:
|
||||
- Reference icons by name (e.g., `gb-chat.svg`, `gb-drive.svg`)
|
||||
- Never generate or embed icon content
|
||||
- See `botui/PROMPT.md` for the complete icon list
|
||||
|
||||
---
|
||||
|
||||
## Weekly Maintenance - EVERY MONDAY
|
||||
|
||||
### Package Review Checklist
|
||||
|
||||
**Every Monday, review the following:**
|
||||
|
||||
1. **Dependency Updates**
|
||||
```bash
|
||||
cargo outdated
|
||||
cargo audit
|
||||
```
|
||||
|
||||
2. **Package Consolidation Opportunities**
|
||||
- Check if new crates can replace custom code
|
||||
- Look for crates that combine multiple dependencies
|
||||
- Review `Cargo.toml` for redundant dependencies
|
||||
|
||||
3. **Code Reduction Candidates**
|
||||
- Custom implementations that now have crate equivalents
|
||||
- Boilerplate that can be replaced with derive macros
|
||||
- Re-exports that can simplify downstream usage
|
||||
|
||||
4. **Feature Flag Review**
|
||||
- Check if optional features are still needed
|
||||
- Consolidate similar features
|
||||
- Remove unused feature gates
|
||||
|
||||
### Packages to Watch
|
||||
|
||||
| Area | Potential Packages | Purpose |
|
||||
|------|-------------------|---------|
|
||||
| Error Handling | `anyhow`, `thiserror` | Consolidate error types |
|
||||
| Validation | `validator` | Replace manual validation |
|
||||
| Serialization | `serde` derives | Reduce boilerplate |
|
||||
| UUID | `uuid` | Consistent ID generation |
|
||||
|
||||
---
|
||||
|
||||
## Project Overview
|
||||
|
||||
BotLib is the shared foundation library for the General Bots workspace. It provides common types, utilities, error handling, and optional integrations that are consumed by botserver, botui, and botapp.
|
||||
|
||||
### Workspace Position
|
||||
|
||||
```
|
||||
botlib/ # THIS PROJECT - Shared library
|
||||
botserver/ # Main server (depends on botlib)
|
||||
botui/ # Web/Desktop UI (depends on botlib)
|
||||
botapp/ # Desktop app (depends on botlib)
|
||||
botbook/ # Documentation
|
||||
```
|
||||
|
||||
### What BotLib Provides
|
||||
|
||||
- **Error Types**: Common error handling with anyhow/thiserror
|
||||
- **Models**: Shared data structures and types
|
||||
- **HTTP Client**: Optional reqwest wrapper
|
||||
- **Database**: Optional diesel integration
|
||||
- **Validation**: Optional input validation
|
||||
- **Branding**: Version and branding constants
|
||||
|
||||
---
|
||||
|
||||
## Feature Flags
|
||||
|
||||
```toml
|
||||
[features]
|
||||
default = []
|
||||
full = ["database", "http-client", "validation"]
|
||||
database = ["dep:diesel"]
|
||||
http-client = ["dep:reqwest"]
|
||||
validation = ["dep:validator"]
|
||||
```
|
||||
|
||||
### Usage in Dependent Crates
|
||||
|
||||
```toml
|
||||
# botserver/Cargo.toml
|
||||
[dependencies.botlib]
|
||||
path = "../botlib"
|
||||
features = ["database"]
|
||||
|
||||
# botui/Cargo.toml
|
||||
[dependencies.botlib]
|
||||
path = "../botlib"
|
||||
features = ["http-client"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Generation Rules
|
||||
|
||||
### CRITICAL REQUIREMENTS
|
||||
|
||||
```
|
||||
- Library code must be generic and reusable
|
||||
- No hardcoded values or project-specific logic
|
||||
- All public APIs must be well-documented
|
||||
- Feature gates for optional dependencies
|
||||
- Zero warnings - clean compilation required
|
||||
```
|
||||
|
||||
### Module Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── lib.rs # Public exports, feature gates
|
||||
├── error.rs # Error types (thiserror)
|
||||
├── models.rs # Shared data models
|
||||
├── message_types.rs # Message type definitions
|
||||
├── http_client.rs # HTTP client wrapper (feature-gated)
|
||||
├── branding.rs # Version, branding constants
|
||||
└── version.rs # Version information
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Adding New Features
|
||||
|
||||
### Adding a Shared Type
|
||||
|
||||
```rust
|
||||
// src/models.rs
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SharedEntity {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
```
|
||||
|
||||
### Adding a Feature-Gated Module
|
||||
|
||||
```rust
|
||||
// src/lib.rs
|
||||
#[cfg(feature = "my-feature")]
|
||||
pub mod my_module;
|
||||
|
||||
#[cfg(feature = "my-feature")]
|
||||
pub use my_module::MyType;
|
||||
```
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
[features]
|
||||
my-feature = ["dep:some-crate"]
|
||||
|
||||
[dependencies]
|
||||
some-crate = { version = "1.0", optional = true }
|
||||
```
|
||||
|
||||
### Adding Error Types
|
||||
|
||||
```rust
|
||||
// src/error.rs
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum BotLibError {
|
||||
#[error("Configuration error: {0}")]
|
||||
Config(String),
|
||||
|
||||
#[error("HTTP error: {0}")]
|
||||
Http(#[from] reqwest::Error),
|
||||
|
||||
#[error("Database error: {0}")]
|
||||
Database(String),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, BotLibError>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Re-exports Strategy
|
||||
|
||||
BotLib should re-export common dependencies to ensure version consistency:
|
||||
|
||||
```rust
|
||||
// src/lib.rs
|
||||
pub use anyhow;
|
||||
pub use chrono;
|
||||
pub use serde;
|
||||
pub use serde_json;
|
||||
pub use thiserror;
|
||||
pub use uuid;
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
pub use diesel;
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
pub use reqwest;
|
||||
```
|
||||
|
||||
Consumers then use:
|
||||
|
||||
```rust
|
||||
use botlib::uuid::Uuid;
|
||||
use botlib::chrono::Utc;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Library | Version | Purpose | Optional |
|
||||
|---------|---------|---------|----------|
|
||||
| anyhow | 1.0 | Error handling | No |
|
||||
| thiserror | 2.0 | Error derive | No |
|
||||
| log | 0.4 | Logging facade | No |
|
||||
| chrono | 0.4 | Date/time | No |
|
||||
| serde | 1.0 | Serialization | No |
|
||||
| serde_json | 1.0 | JSON | No |
|
||||
| uuid | 1.11 | UUIDs | No |
|
||||
| toml | 0.8 | Config parsing | No |
|
||||
| diesel | 2.1 | Database ORM | Yes |
|
||||
| reqwest | 0.12 | HTTP client | Yes |
|
||||
| validator | 0.18 | Validation | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Test all features
|
||||
cargo test --all-features
|
||||
|
||||
# Test specific feature
|
||||
cargo test --features database
|
||||
|
||||
# Test without optional features
|
||||
cargo test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Final Checks Before Commit
|
||||
|
||||
```bash
|
||||
# Verify version is 6.1.0
|
||||
grep "^version" Cargo.toml | grep "6.1.0"
|
||||
|
||||
# Build with all features
|
||||
cargo build --all-features
|
||||
|
||||
# Check for warnings
|
||||
cargo check --all-features 2>&1 | grep warning
|
||||
|
||||
# Run tests
|
||||
cargo test --all-features
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
- Keep botlib minimal and focused
|
||||
- No business logic - only utilities and types
|
||||
- Feature gate all optional dependencies
|
||||
- Maintain backward compatibility
|
||||
- Document all public APIs
|
||||
- Target zero warnings
|
||||
- **Version**: Always 6.1.0 - do not change without approval
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
General Bots® base library for building Node.js TypeScript Apps packages (.gbapp).
|
||||
|
||||
See: https://github.com/pragmatismo-io/BotServer for main documentation.
|
||||
See: https://github.com/pragmatismo-io/botserver for main documentation.
|
||||
107
VERSION.md
107
VERSION.md
|
|
@ -1,107 +0,0 @@
|
|||
# History
|
||||
|
||||
## Version 0.1.6
|
||||
|
||||
* References and version updated.
|
||||
|
||||
## Version 0.1.5
|
||||
|
||||
* Docs updated.
|
||||
|
||||
## Version 0.1.4
|
||||
|
||||
* New fields to 100% automated development environement setup.
|
||||
|
||||
## Version 0.1.3
|
||||
|
||||
- FIX: Updated dependencies versions.
|
||||
|
||||
## Version 0.1.2
|
||||
|
||||
- NEW: pragmatismo-io-framework updated.
|
||||
|
||||
## Version 0.1.0
|
||||
|
||||
- NEW: Migration to Bot Framework v4.
|
||||
|
||||
## Version 0.0.33
|
||||
|
||||
- FIX: Updated dependencies versions.
|
||||
|
||||
## Version 0.0.32
|
||||
|
||||
- FIX: Updated dependencies versions.
|
||||
|
||||
## Version 0.0.31
|
||||
|
||||
- FIX: Export of Sequelize from sequelize-typescript.
|
||||
|
||||
## Version 0.0.30
|
||||
|
||||
- FIX: Packages updated.
|
||||
- FIX: Missing some 'use strict'.
|
||||
|
||||
## Version 0.0.29
|
||||
|
||||
- FIX: Packages updated.
|
||||
|
||||
## Version 0.0.28
|
||||
|
||||
- FIX: Package compiled.
|
||||
|
||||
## Version 0.0.27
|
||||
|
||||
- FIX: Merged changes.
|
||||
|
||||
## Version 0.0.26
|
||||
|
||||
- NEW: Support for Speech recognition/synthesis.
|
||||
|
||||
## Version 0.0.25
|
||||
|
||||
- FIX: Packages updated.
|
||||
|
||||
## Version 0.0.24
|
||||
|
||||
- FIX: Packages updated.
|
||||
|
||||
## Version 0.0.23
|
||||
|
||||
- FIX: Trying to remove botbuilder dependency on hoek vunerability with no success, MS is promissing update it: https://github.com/Microsoft/BotBuilder/issues/4206.
|
||||
|
||||
## Version 0.0.22
|
||||
|
||||
- FIX: Packages updated.
|
||||
|
||||
## Version 0.0.21
|
||||
|
||||
- FIX: Whatsapp directline client improved.
|
||||
|
||||
## Version 0.0.20
|
||||
|
||||
- NEW: Whatsapp directline client is now working in preview.
|
||||
- NEW: Parameter whatsappServiceWebhookUrl added.
|
||||
|
||||
## Version 0.0.19
|
||||
|
||||
- NEW: Parameter whatsappServiceUrl added to support other whatsapp channels.
|
||||
|
||||
## Version 0.0.18
|
||||
|
||||
- FIX: Missing TS compilation.
|
||||
|
||||
## Version 0.0.17
|
||||
|
||||
- NEW: The bot now has an associated mobile Whatsapp number;
|
||||
|
||||
## Version 0.0.16
|
||||
|
||||
- FIX: Compilation of Typescript into JavaScript.
|
||||
|
||||
## Version 0.0.15
|
||||
|
||||
- NEW: Now each .gbapp has it own set of syspackages loaded.
|
||||
|
||||
## Version 0.0.14
|
||||
|
||||
- NEW: Added support for Whatsapp external service key on bot instance model.
|
||||
|
|
@ -1,865 +0,0 @@
|
|||
/*! normalize.css v1.1.3 | MIT License | git.io/normalize */
|
||||
/* ========================================================================== HTML5 display definitions ========================================================================== */
|
||||
/** Correct `block` display not defined in IE 6/7/8/9 and Firefox 3. */
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; }
|
||||
|
||||
/** Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. */
|
||||
audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; }
|
||||
|
||||
/** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */
|
||||
audio:not([controls]) { display: none; height: 0; }
|
||||
|
||||
/** Address styling not present in IE 7/8/9, Firefox 3, and Safari 4. Known issue: no IE 6 support. */
|
||||
[hidden] { display: none; }
|
||||
|
||||
/* ========================================================================== Base ========================================================================== */
|
||||
/** 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using `em` units. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */
|
||||
html { font-size: 100%; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ font-family: sans-serif; }
|
||||
|
||||
/** Address `font-family` inconsistency between `textarea` and other form elements. */
|
||||
button, input, select, textarea { font-family: sans-serif; }
|
||||
|
||||
/** Address margins handled incorrectly in IE 6/7. */
|
||||
body { margin: 0; }
|
||||
|
||||
/* ========================================================================== Links ========================================================================== */
|
||||
/** Address `outline` inconsistency between Chrome and other browsers. */
|
||||
a:focus { outline: thin dotted; }
|
||||
a:active, a:hover { outline: 0; }
|
||||
|
||||
/** Improve readability when focused and also mouse hovered in all browsers. */
|
||||
/* ========================================================================== Typography ========================================================================== */
|
||||
/** Address font sizes and margins set differently in IE 6/7. Address font sizes within `section` and `article` in Firefox 4+, Safari 5, and Chrome. */
|
||||
h1 { font-size: 2em; margin: 0.67em 0; }
|
||||
|
||||
h2 { font-size: 1.5em; margin: 0.83em 0; }
|
||||
|
||||
h3 { font-size: 1.17em; margin: 1em 0; }
|
||||
|
||||
h4, .tsd-index-panel h3 { font-size: 1em; margin: 1.33em 0; }
|
||||
|
||||
h5 { font-size: 0.83em; margin: 1.67em 0; }
|
||||
|
||||
h6 { font-size: 0.67em; margin: 2.33em 0; }
|
||||
|
||||
/** Address styling not present in IE 7/8/9, Safari 5, and Chrome. */
|
||||
abbr[title] { border-bottom: 1px dotted; }
|
||||
|
||||
/** Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome. */
|
||||
b, strong { font-weight: bold; }
|
||||
|
||||
blockquote { margin: 1em 40px; }
|
||||
|
||||
/** Address styling not present in Safari 5 and Chrome. */
|
||||
dfn { font-style: italic; }
|
||||
|
||||
/** Address differences between Firefox and other browsers. Known issue: no IE 6/7 normalization. */
|
||||
hr { box-sizing: content-box; height: 0; }
|
||||
|
||||
/** Address styling not present in IE 6/7/8/9. */
|
||||
mark { background: #ff0; color: #000; }
|
||||
|
||||
/** Address margins set differently in IE 6/7. */
|
||||
p, pre { margin: 1em 0; }
|
||||
|
||||
/** Correct font family set oddly in IE 6, Safari 4/5, and Chrome. */
|
||||
code, kbd, pre, samp { font-family: monospace, serif; _font-family: "courier new", monospace; font-size: 1em; }
|
||||
|
||||
/** Improve readability of pre-formatted text in all browsers. */
|
||||
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
|
||||
|
||||
/** Address CSS quotes not supported in IE 6/7. */
|
||||
q { quotes: none; }
|
||||
q:before, q:after { content: ""; content: none; }
|
||||
|
||||
/** Address `quotes` property not supported in Safari 4. */
|
||||
/** Address inconsistent and variable font size in all browsers. */
|
||||
small { font-size: 80%; }
|
||||
|
||||
/** Prevent `sub` and `sup` affecting `line-height` in all browsers. */
|
||||
sub { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
|
||||
|
||||
sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; top: -0.5em; }
|
||||
|
||||
sub { bottom: -0.25em; }
|
||||
|
||||
/* ========================================================================== Lists ========================================================================== */
|
||||
/** Address margins set differently in IE 6/7. */
|
||||
dl, menu, ol, ul { margin: 1em 0; }
|
||||
|
||||
dd { margin: 0 0 0 40px; }
|
||||
|
||||
/** Address paddings set differently in IE 6/7. */
|
||||
menu, ol, ul { padding: 0 0 0 40px; }
|
||||
|
||||
/** Correct list images handled incorrectly in IE 7. */
|
||||
nav ul, nav ol { list-style: none; list-style-image: none; }
|
||||
|
||||
/* ========================================================================== Embedded content ========================================================================== */
|
||||
/** 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3. 2. Improve image quality when scaled in IE 7. */
|
||||
img { border: 0; /* 1 */ -ms-interpolation-mode: bicubic; }
|
||||
|
||||
/* 2 */
|
||||
/** Correct overflow displayed oddly in IE 9. */
|
||||
svg:not(:root) { overflow: hidden; }
|
||||
|
||||
/* ========================================================================== Figures ========================================================================== */
|
||||
/** Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11. */
|
||||
figure, form { margin: 0; }
|
||||
|
||||
/* ========================================================================== Forms ========================================================================== */
|
||||
/** Correct margin displayed oddly in IE 6/7. */
|
||||
/** Define consistent border, margin, and padding. */
|
||||
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
|
||||
|
||||
/** 1. Correct color not being inherited in IE 6/7/8/9. 2. Correct text not wrapping in Firefox 3. 3. Correct alignment displayed oddly in IE 6/7. */
|
||||
legend { border: 0; /* 1 */ padding: 0; white-space: normal; /* 2 */ *margin-left: -7px; }
|
||||
|
||||
/* 3 */
|
||||
/** 1. Correct font size not being inherited in all browsers. 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5, and Chrome. 3. Improve appearance and consistency in all browsers. */
|
||||
button, input, select, textarea { font-size: 100%; /* 1 */ margin: 0; /* 2 */ vertical-align: baseline; /* 3 */ *vertical-align: middle; }
|
||||
|
||||
/* 3 */
|
||||
/** Address Firefox 3+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
|
||||
button, input { line-height: normal; }
|
||||
|
||||
/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+. Correct `select` style inheritance in Firefox 4+ and Opera. */
|
||||
button, select { text-transform: none; }
|
||||
|
||||
/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. 4. Remove inner spacing in IE 7 without affecting normal text inputs. Known issue: inner spacing remains in IE 6. */
|
||||
button, html input[type="button"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ *overflow: visible; }
|
||||
|
||||
/* 4 */
|
||||
input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ *overflow: visible; }
|
||||
|
||||
/* 4 */
|
||||
/** Re-set default cursor for disabled elements. */
|
||||
button[disabled], html input[disabled] { cursor: default; }
|
||||
|
||||
/** 1. Address box sizing set to content-box in IE 8/9. 2. Remove excess padding in IE 8/9. 3. Remove excess padding in IE 7. Known issue: excess padding remains in IE 6. */
|
||||
input { /* 3 */ }
|
||||
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ *height: 13px; /* 3 */ *width: 13px; }
|
||||
input[type="search"] { -webkit-appearance: textfield; /* 1 */ /* 2 */ box-sizing: content-box; }
|
||||
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
|
||||
|
||||
/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
|
||||
/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
|
||||
/** Remove inner padding and border in Firefox 3+. */
|
||||
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
|
||||
|
||||
/** 1. Remove default vertical scrollbar in IE 6/7/8/9. 2. Improve readability and alignment in all browsers. */
|
||||
textarea { overflow: auto; /* 1 */ vertical-align: top; }
|
||||
|
||||
/* 2 */
|
||||
/* ========================================================================== Tables ========================================================================== */
|
||||
/** Remove most spacing between table cells. */
|
||||
table { border-collapse: collapse; border-spacing: 0; }
|
||||
|
||||
/* Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name> */
|
||||
.hljs { display: inline-block; padding: 0.5em; background: white; color: black; }
|
||||
|
||||
.hljs-comment, .hljs-annotation, .hljs-template_comment, .diff .hljs-header, .hljs-chunk, .apache .hljs-cbracket { color: #008000; }
|
||||
|
||||
.hljs-keyword, .hljs-id, .hljs-built_in, .css .smalltalk .hljs-class, .hljs-winutils, .bash .hljs-variable, .tex .hljs-command, .hljs-request, .hljs-status, .nginx .hljs-title { color: #00f; }
|
||||
|
||||
.xml .hljs-tag { color: #00f; }
|
||||
.xml .hljs-tag .hljs-value { color: #00f; }
|
||||
|
||||
.hljs-string, .hljs-title, .hljs-parent, .hljs-tag .hljs-value, .hljs-rules .hljs-value { color: #a31515; }
|
||||
|
||||
.ruby .hljs-symbol { color: #a31515; }
|
||||
.ruby .hljs-symbol .hljs-string { color: #a31515; }
|
||||
|
||||
.hljs-template_tag, .django .hljs-variable, .hljs-addition, .hljs-flow, .hljs-stream, .apache .hljs-tag, .hljs-date, .tex .hljs-formula, .coffeescript .hljs-attribute { color: #a31515; }
|
||||
|
||||
.ruby .hljs-string, .hljs-decorator, .hljs-filter .hljs-argument, .hljs-localvars, .hljs-array, .hljs-attr_selector, .hljs-pseudo, .hljs-pi, .hljs-doctype, .hljs-deletion, .hljs-envvar, .hljs-shebang, .hljs-preprocessor, .hljs-pragma, .userType, .apache .hljs-sqbracket, .nginx .hljs-built_in, .tex .hljs-special, .hljs-prompt { color: #2b91af; }
|
||||
|
||||
.hljs-phpdoc, .hljs-javadoc, .hljs-xmlDocTag { color: #808080; }
|
||||
|
||||
.vhdl .hljs-typename { font-weight: bold; }
|
||||
.vhdl .hljs-string { color: #666666; }
|
||||
.vhdl .hljs-literal { color: #a31515; }
|
||||
.vhdl .hljs-attribute { color: #00b0e8; }
|
||||
|
||||
.xml .hljs-attribute { color: #f00; }
|
||||
|
||||
.col > :first-child, .col-1 > :first-child, .col-2 > :first-child, .col-3 > :first-child, .col-4 > :first-child, .col-5 > :first-child, .col-6 > :first-child, .col-7 > :first-child, .col-8 > :first-child, .col-9 > :first-child, .col-10 > :first-child, .col-11 > :first-child, .tsd-panel > :first-child, ul.tsd-descriptions > li > :first-child, .col > :first-child > :first-child, .col-1 > :first-child > :first-child, .col-2 > :first-child > :first-child, .col-3 > :first-child > :first-child, .col-4 > :first-child > :first-child, .col-5 > :first-child > :first-child, .col-6 > :first-child > :first-child, .col-7 > :first-child > :first-child, .col-8 > :first-child > :first-child, .col-9 > :first-child > :first-child, .col-10 > :first-child > :first-child, .col-11 > :first-child > :first-child, .tsd-panel > :first-child > :first-child, ul.tsd-descriptions > li > :first-child > :first-child, .col > :first-child > :first-child > :first-child, .col-1 > :first-child > :first-child > :first-child, .col-2 > :first-child > :first-child > :first-child, .col-3 > :first-child > :first-child > :first-child, .col-4 > :first-child > :first-child > :first-child, .col-5 > :first-child > :first-child > :first-child, .col-6 > :first-child > :first-child > :first-child, .col-7 > :first-child > :first-child > :first-child, .col-8 > :first-child > :first-child > :first-child, .col-9 > :first-child > :first-child > :first-child, .col-10 > :first-child > :first-child > :first-child, .col-11 > :first-child > :first-child > :first-child, .tsd-panel > :first-child > :first-child > :first-child, ul.tsd-descriptions > li > :first-child > :first-child > :first-child { margin-top: 0; }
|
||||
.col > :last-child, .col-1 > :last-child, .col-2 > :last-child, .col-3 > :last-child, .col-4 > :last-child, .col-5 > :last-child, .col-6 > :last-child, .col-7 > :last-child, .col-8 > :last-child, .col-9 > :last-child, .col-10 > :last-child, .col-11 > :last-child, .tsd-panel > :last-child, ul.tsd-descriptions > li > :last-child, .col > :last-child > :last-child, .col-1 > :last-child > :last-child, .col-2 > :last-child > :last-child, .col-3 > :last-child > :last-child, .col-4 > :last-child > :last-child, .col-5 > :last-child > :last-child, .col-6 > :last-child > :last-child, .col-7 > :last-child > :last-child, .col-8 > :last-child > :last-child, .col-9 > :last-child > :last-child, .col-10 > :last-child > :last-child, .col-11 > :last-child > :last-child, .tsd-panel > :last-child > :last-child, ul.tsd-descriptions > li > :last-child > :last-child, .col > :last-child > :last-child > :last-child, .col-1 > :last-child > :last-child > :last-child, .col-2 > :last-child > :last-child > :last-child, .col-3 > :last-child > :last-child > :last-child, .col-4 > :last-child > :last-child > :last-child, .col-5 > :last-child > :last-child > :last-child, .col-6 > :last-child > :last-child > :last-child, .col-7 > :last-child > :last-child > :last-child, .col-8 > :last-child > :last-child > :last-child, .col-9 > :last-child > :last-child > :last-child, .col-10 > :last-child > :last-child > :last-child, .col-11 > :last-child > :last-child > :last-child, .tsd-panel > :last-child > :last-child > :last-child, ul.tsd-descriptions > li > :last-child > :last-child > :last-child { margin-bottom: 0; }
|
||||
|
||||
.container { max-width: 1200px; margin: 0 auto; padding: 0 40px; }
|
||||
@media (max-width: 640px) { .container { padding: 0 20px; } }
|
||||
|
||||
.container-main { padding-bottom: 200px; }
|
||||
|
||||
.row { position: relative; margin: 0 -10px; }
|
||||
.row:after { visibility: hidden; display: block; content: ""; clear: both; height: 0; }
|
||||
|
||||
.col, .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11 { box-sizing: border-box; float: left; padding: 0 10px; }
|
||||
|
||||
.col-1 { width: 8.33333%; }
|
||||
|
||||
.offset-1 { margin-left: 8.33333%; }
|
||||
|
||||
.col-2 { width: 16.66667%; }
|
||||
|
||||
.offset-2 { margin-left: 16.66667%; }
|
||||
|
||||
.col-3 { width: 25%; }
|
||||
|
||||
.offset-3 { margin-left: 25%; }
|
||||
|
||||
.col-4 { width: 33.33333%; }
|
||||
|
||||
.offset-4 { margin-left: 33.33333%; }
|
||||
|
||||
.col-5 { width: 41.66667%; }
|
||||
|
||||
.offset-5 { margin-left: 41.66667%; }
|
||||
|
||||
.col-6 { width: 50%; }
|
||||
|
||||
.offset-6 { margin-left: 50%; }
|
||||
|
||||
.col-7 { width: 58.33333%; }
|
||||
|
||||
.offset-7 { margin-left: 58.33333%; }
|
||||
|
||||
.col-8 { width: 66.66667%; }
|
||||
|
||||
.offset-8 { margin-left: 66.66667%; }
|
||||
|
||||
.col-9 { width: 75%; }
|
||||
|
||||
.offset-9 { margin-left: 75%; }
|
||||
|
||||
.col-10 { width: 83.33333%; }
|
||||
|
||||
.offset-10 { margin-left: 83.33333%; }
|
||||
|
||||
.col-11 { width: 91.66667%; }
|
||||
|
||||
.offset-11 { margin-left: 91.66667%; }
|
||||
|
||||
.tsd-kind-icon { display: block; position: relative; padding-left: 20px; text-indent: -20px; }
|
||||
.tsd-kind-icon:before { content: ''; display: inline-block; vertical-align: middle; width: 17px; height: 17px; margin: 0 3px 2px 0; background-image: url(../images/icons.png); }
|
||||
@media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { .tsd-kind-icon:before { background-image: url(../images/icons@2x.png); background-size: 238px 204px; } }
|
||||
|
||||
.tsd-signature.tsd-kind-icon:before { background-position: 0 -153px; }
|
||||
|
||||
.tsd-kind-object-literal > .tsd-kind-icon:before { background-position: 0px -17px; }
|
||||
.tsd-kind-object-literal.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -17px; }
|
||||
.tsd-kind-object-literal.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -17px; }
|
||||
|
||||
.tsd-kind-class > .tsd-kind-icon:before { background-position: 0px -34px; }
|
||||
.tsd-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -34px; }
|
||||
.tsd-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -34px; }
|
||||
|
||||
.tsd-kind-class.tsd-has-type-parameter > .tsd-kind-icon:before { background-position: 0px -51px; }
|
||||
.tsd-kind-class.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -51px; }
|
||||
.tsd-kind-class.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -51px; }
|
||||
|
||||
.tsd-kind-interface > .tsd-kind-icon:before { background-position: 0px -68px; }
|
||||
.tsd-kind-interface.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -68px; }
|
||||
.tsd-kind-interface.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -68px; }
|
||||
|
||||
.tsd-kind-interface.tsd-has-type-parameter > .tsd-kind-icon:before { background-position: 0px -85px; }
|
||||
.tsd-kind-interface.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -85px; }
|
||||
.tsd-kind-interface.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -85px; }
|
||||
|
||||
.tsd-kind-module > .tsd-kind-icon:before { background-position: 0px -102px; }
|
||||
.tsd-kind-module.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -102px; }
|
||||
.tsd-kind-module.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -102px; }
|
||||
|
||||
.tsd-kind-external-module > .tsd-kind-icon:before { background-position: 0px -102px; }
|
||||
.tsd-kind-external-module.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -102px; }
|
||||
.tsd-kind-external-module.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -102px; }
|
||||
|
||||
.tsd-kind-enum > .tsd-kind-icon:before { background-position: 0px -119px; }
|
||||
.tsd-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -119px; }
|
||||
.tsd-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -119px; }
|
||||
|
||||
.tsd-kind-enum-member > .tsd-kind-icon:before { background-position: 0px -136px; }
|
||||
.tsd-kind-enum-member.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -136px; }
|
||||
.tsd-kind-enum-member.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -136px; }
|
||||
|
||||
.tsd-kind-signature > .tsd-kind-icon:before { background-position: 0px -153px; }
|
||||
.tsd-kind-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -153px; }
|
||||
.tsd-kind-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -153px; }
|
||||
|
||||
.tsd-kind-type-alias > .tsd-kind-icon:before { background-position: 0px -170px; }
|
||||
.tsd-kind-type-alias.tsd-is-protected > .tsd-kind-icon:before { background-position: -17px -170px; }
|
||||
.tsd-kind-type-alias.tsd-is-private > .tsd-kind-icon:before { background-position: -34px -170px; }
|
||||
|
||||
.tsd-kind-variable > .tsd-kind-icon:before { background-position: -136px -0px; }
|
||||
.tsd-kind-variable.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -0px; }
|
||||
.tsd-kind-variable.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -0px; }
|
||||
.tsd-kind-variable.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -0px; }
|
||||
|
||||
.tsd-kind-property > .tsd-kind-icon:before { background-position: -136px -0px; }
|
||||
.tsd-kind-property.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -0px; }
|
||||
.tsd-kind-property.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -0px; }
|
||||
.tsd-kind-property.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -0px; }
|
||||
|
||||
.tsd-kind-get-signature > .tsd-kind-icon:before { background-position: -136px -17px; }
|
||||
.tsd-kind-get-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -17px; }
|
||||
.tsd-kind-get-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -17px; }
|
||||
.tsd-kind-get-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -17px; }
|
||||
|
||||
.tsd-kind-set-signature > .tsd-kind-icon:before { background-position: -136px -34px; }
|
||||
.tsd-kind-set-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -34px; }
|
||||
.tsd-kind-set-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -34px; }
|
||||
.tsd-kind-set-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -34px; }
|
||||
|
||||
.tsd-kind-accessor > .tsd-kind-icon:before { background-position: -136px -51px; }
|
||||
.tsd-kind-accessor.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -51px; }
|
||||
.tsd-kind-accessor.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -51px; }
|
||||
.tsd-kind-accessor.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -51px; }
|
||||
|
||||
.tsd-kind-function > .tsd-kind-icon:before { background-position: -136px -68px; }
|
||||
.tsd-kind-function.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -68px; }
|
||||
.tsd-kind-function.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -68px; }
|
||||
.tsd-kind-function.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -68px; }
|
||||
|
||||
.tsd-kind-method > .tsd-kind-icon:before { background-position: -136px -68px; }
|
||||
.tsd-kind-method.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -68px; }
|
||||
.tsd-kind-method.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -68px; }
|
||||
.tsd-kind-method.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -68px; }
|
||||
|
||||
.tsd-kind-call-signature > .tsd-kind-icon:before { background-position: -136px -68px; }
|
||||
.tsd-kind-call-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -68px; }
|
||||
.tsd-kind-call-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -68px; }
|
||||
.tsd-kind-call-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -68px; }
|
||||
|
||||
.tsd-kind-function.tsd-has-type-parameter > .tsd-kind-icon:before { background-position: -136px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -85px; }
|
||||
.tsd-kind-function.tsd-has-type-parameter.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -85px; }
|
||||
|
||||
.tsd-kind-method.tsd-has-type-parameter > .tsd-kind-icon:before { background-position: -136px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -85px; }
|
||||
.tsd-kind-method.tsd-has-type-parameter.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -85px; }
|
||||
|
||||
.tsd-kind-constructor > .tsd-kind-icon:before { background-position: -136px -102px; }
|
||||
.tsd-kind-constructor.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -102px; }
|
||||
.tsd-kind-constructor.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -102px; }
|
||||
.tsd-kind-constructor.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -102px; }
|
||||
|
||||
.tsd-kind-constructor-signature > .tsd-kind-icon:before { background-position: -136px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -102px; }
|
||||
.tsd-kind-constructor-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -102px; }
|
||||
|
||||
.tsd-kind-index-signature > .tsd-kind-icon:before { background-position: -136px -119px; }
|
||||
.tsd-kind-index-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -119px; }
|
||||
.tsd-kind-index-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -119px; }
|
||||
.tsd-kind-index-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -119px; }
|
||||
|
||||
.tsd-kind-event > .tsd-kind-icon:before { background-position: -136px -136px; }
|
||||
.tsd-kind-event.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -136px; }
|
||||
.tsd-kind-event.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -136px; }
|
||||
.tsd-kind-event.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -136px; }
|
||||
|
||||
.tsd-is-static > .tsd-kind-icon:before { background-position: -136px -153px; }
|
||||
.tsd-is-static.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -153px; }
|
||||
.tsd-is-static.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -153px; }
|
||||
.tsd-is-static.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -153px; }
|
||||
|
||||
.tsd-is-static.tsd-kind-function > .tsd-kind-icon:before { background-position: -136px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -170px; }
|
||||
.tsd-is-static.tsd-kind-function.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -170px; }
|
||||
|
||||
.tsd-is-static.tsd-kind-method > .tsd-kind-icon:before { background-position: -136px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -170px; }
|
||||
.tsd-is-static.tsd-kind-method.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -170px; }
|
||||
|
||||
.tsd-is-static.tsd-kind-call-signature > .tsd-kind-icon:before { background-position: -136px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -170px; }
|
||||
.tsd-is-static.tsd-kind-call-signature.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -170px; }
|
||||
|
||||
.tsd-is-static.tsd-kind-event > .tsd-kind-icon:before { background-position: -136px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-is-protected > .tsd-kind-icon:before { background-position: -153px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-class > .tsd-kind-icon:before { background-position: -51px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-inherited > .tsd-kind-icon:before { background-position: -68px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected > .tsd-kind-icon:before { background-position: -85px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-protected.tsd-is-inherited > .tsd-kind-icon:before { background-position: -102px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-class.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-enum > .tsd-kind-icon:before { background-position: -170px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-enum.tsd-is-protected > .tsd-kind-icon:before { background-position: -187px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-enum.tsd-is-private > .tsd-kind-icon:before { background-position: -119px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-interface > .tsd-kind-icon:before { background-position: -204px -187px; }
|
||||
.tsd-is-static.tsd-kind-event.tsd-parent-kind-interface.tsd-is-inherited > .tsd-kind-icon:before { background-position: -221px -187px; }
|
||||
|
||||
.no-transition { transition: none !important; }
|
||||
|
||||
@-webkit-keyframes fade-in { from { opacity: 0; }
|
||||
to { opacity: 1; } }
|
||||
|
||||
@keyframes fade-in { from { opacity: 0; }
|
||||
to { opacity: 1; } }
|
||||
@-webkit-keyframes fade-out { from { opacity: 1; visibility: visible; }
|
||||
to { opacity: 0; } }
|
||||
@keyframes fade-out { from { opacity: 1; visibility: visible; }
|
||||
to { opacity: 0; } }
|
||||
@-webkit-keyframes fade-in-delayed { 0% { opacity: 0; }
|
||||
33% { opacity: 0; }
|
||||
100% { opacity: 1; } }
|
||||
@keyframes fade-in-delayed { 0% { opacity: 0; }
|
||||
33% { opacity: 0; }
|
||||
100% { opacity: 1; } }
|
||||
@-webkit-keyframes fade-out-delayed { 0% { opacity: 1; visibility: visible; }
|
||||
66% { opacity: 0; }
|
||||
100% { opacity: 0; } }
|
||||
@keyframes fade-out-delayed { 0% { opacity: 1; visibility: visible; }
|
||||
66% { opacity: 0; }
|
||||
100% { opacity: 0; } }
|
||||
@-webkit-keyframes shift-to-left { from { -webkit-transform: translate(0, 0); transform: translate(0, 0); }
|
||||
to { -webkit-transform: translate(-25%, 0); transform: translate(-25%, 0); } }
|
||||
@keyframes shift-to-left { from { -webkit-transform: translate(0, 0); transform: translate(0, 0); }
|
||||
to { -webkit-transform: translate(-25%, 0); transform: translate(-25%, 0); } }
|
||||
@-webkit-keyframes unshift-to-left { from { -webkit-transform: translate(-25%, 0); transform: translate(-25%, 0); }
|
||||
to { -webkit-transform: translate(0, 0); transform: translate(0, 0); } }
|
||||
@keyframes unshift-to-left { from { -webkit-transform: translate(-25%, 0); transform: translate(-25%, 0); }
|
||||
to { -webkit-transform: translate(0, 0); transform: translate(0, 0); } }
|
||||
@-webkit-keyframes pop-in-from-right { from { -webkit-transform: translate(100%, 0); transform: translate(100%, 0); }
|
||||
to { -webkit-transform: translate(0, 0); transform: translate(0, 0); } }
|
||||
@keyframes pop-in-from-right { from { -webkit-transform: translate(100%, 0); transform: translate(100%, 0); }
|
||||
to { -webkit-transform: translate(0, 0); transform: translate(0, 0); } }
|
||||
@-webkit-keyframes pop-out-to-right { from { -webkit-transform: translate(0, 0); transform: translate(0, 0); visibility: visible; }
|
||||
to { -webkit-transform: translate(100%, 0); transform: translate(100%, 0); } }
|
||||
@keyframes pop-out-to-right { from { -webkit-transform: translate(0, 0); transform: translate(0, 0); visibility: visible; }
|
||||
to { -webkit-transform: translate(100%, 0); transform: translate(100%, 0); } }
|
||||
body { background: #fdfdfd; font-family: "Segoe UI", sans-serif; font-size: 16px; color: #222; }
|
||||
|
||||
a { color: #4da6ff; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
code, pre { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; padding: 0.2em; margin: 0; font-size: 14px; background-color: rgba(0, 0, 0, 0.04); }
|
||||
|
||||
pre { padding: 10px; }
|
||||
pre code { padding: 0; font-size: 100%; background-color: transparent; }
|
||||
|
||||
.tsd-typography { line-height: 1.333em; }
|
||||
.tsd-typography ul { list-style: square; padding: 0 0 0 20px; margin: 0; }
|
||||
.tsd-typography h4, .tsd-typography .tsd-index-panel h3, .tsd-index-panel .tsd-typography h3, .tsd-typography h5, .tsd-typography h6 { font-size: 1em; margin: 0; }
|
||||
.tsd-typography h5, .tsd-typography h6 { font-weight: normal; }
|
||||
.tsd-typography p, .tsd-typography ul, .tsd-typography ol { margin: 1em 0; }
|
||||
|
||||
@media (min-width: 901px) and (max-width: 1024px) { html.default .col-content { width: 72%; }
|
||||
html.default .col-menu { width: 28%; }
|
||||
html.default .tsd-navigation { padding-left: 10px; } }
|
||||
@media (max-width: 900px) { html.default .col-content { float: none; width: 100%; }
|
||||
html.default .col-menu { position: fixed !important; overflow: auto; -webkit-overflow-scrolling: touch; overflow-scrolling: touch; z-index: 1024; top: 0 !important; bottom: 0 !important; left: auto !important; right: 0 !important; width: 100%; padding: 20px 20px 0 0; max-width: 450px; visibility: hidden; background-color: #fff; -webkit-transform: translate(100%, 0); transform: translate(100%, 0); }
|
||||
html.default .col-menu > *:last-child { padding-bottom: 20px; }
|
||||
html.default .overlay { content: ""; display: block; position: fixed; z-index: 1023; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.75); visibility: hidden; }
|
||||
html.default.to-has-menu .overlay { -webkit-animation: fade-in 0.4s; animation: fade-in 0.4s; }
|
||||
html.default.to-has-menu header, html.default.to-has-menu footer, html.default.to-has-menu .col-content { -webkit-animation: shift-to-left 0.4s; animation: shift-to-left 0.4s; }
|
||||
html.default.to-has-menu .col-menu { -webkit-animation: pop-in-from-right 0.4s; animation: pop-in-from-right 0.4s; }
|
||||
html.default.from-has-menu .overlay { -webkit-animation: fade-out 0.4s; animation: fade-out 0.4s; }
|
||||
html.default.from-has-menu header, html.default.from-has-menu footer, html.default.from-has-menu .col-content { -webkit-animation: unshift-to-left 0.4s; animation: unshift-to-left 0.4s; }
|
||||
html.default.from-has-menu .col-menu { -webkit-animation: pop-out-to-right 0.4s; animation: pop-out-to-right 0.4s; }
|
||||
html.default.has-menu body { overflow: hidden; }
|
||||
html.default.has-menu .overlay { visibility: visible; }
|
||||
html.default.has-menu header, html.default.has-menu footer, html.default.has-menu .col-content { -webkit-transform: translate(-25%, 0); transform: translate(-25%, 0); }
|
||||
html.default.has-menu .col-menu { visibility: visible; -webkit-transform: translate(0, 0); transform: translate(0, 0); } }
|
||||
|
||||
.tsd-page-title { padding: 70px 0 20px 0; margin: 0 0 40px 0; background: #fff; box-shadow: 0 0 5px rgba(0, 0, 0, 0.35); }
|
||||
.tsd-page-title h1 { margin: 0; }
|
||||
|
||||
.tsd-breadcrumb { margin: 0; padding: 0; color: #808080; }
|
||||
.tsd-breadcrumb a { color: #808080; text-decoration: none; }
|
||||
.tsd-breadcrumb a:hover { text-decoration: underline; }
|
||||
.tsd-breadcrumb li { display: inline; }
|
||||
.tsd-breadcrumb li:after { content: " / "; }
|
||||
|
||||
html.minimal .container { margin: 0; }
|
||||
html.minimal .container-main { padding-top: 50px; padding-bottom: 0; }
|
||||
html.minimal .content-wrap { padding-left: 300px; }
|
||||
html.minimal .tsd-navigation { position: fixed !important; overflow: auto; -webkit-overflow-scrolling: touch; overflow-scrolling: touch; box-sizing: border-box; z-index: 1; left: 0; top: 40px; bottom: 0; width: 300px; padding: 20px; margin: 0; }
|
||||
html.minimal .tsd-member .tsd-member { margin-left: 0; }
|
||||
html.minimal .tsd-page-toolbar { position: fixed; z-index: 2; }
|
||||
html.minimal #tsd-filter .tsd-filter-group { right: 0; -webkit-transform: none; transform: none; }
|
||||
html.minimal footer { background-color: transparent; }
|
||||
html.minimal footer .container { padding: 0; }
|
||||
html.minimal .tsd-generator { padding: 0; }
|
||||
@media (max-width: 900px) { html.minimal .tsd-navigation { display: none; }
|
||||
html.minimal .content-wrap { padding-left: 0; } }
|
||||
|
||||
dl.tsd-comment-tags { overflow: hidden; }
|
||||
dl.tsd-comment-tags dt { clear: both; float: left; padding: 1px 5px; margin: 0 10px 0 0; border-radius: 4px; border: 1px solid #808080; color: #808080; font-size: 0.8em; font-weight: normal; }
|
||||
dl.tsd-comment-tags dd { margin: 0 0 10px 0; }
|
||||
dl.tsd-comment-tags p { margin: 0; }
|
||||
|
||||
.tsd-panel.tsd-comment .lead { font-size: 1.1em; line-height: 1.333em; margin-bottom: 2em; }
|
||||
.tsd-panel.tsd-comment .lead:last-child { margin-bottom: 0; }
|
||||
|
||||
.toggle-protected .tsd-is-private { display: none; }
|
||||
|
||||
.toggle-public .tsd-is-private, .toggle-public .tsd-is-protected, .toggle-public .tsd-is-private-protected { display: none; }
|
||||
|
||||
.toggle-inherited .tsd-is-inherited { display: none; }
|
||||
|
||||
.toggle-only-exported .tsd-is-not-exported { display: none; }
|
||||
|
||||
.toggle-externals .tsd-is-external { display: none; }
|
||||
|
||||
#tsd-filter { position: relative; display: inline-block; height: 40px; vertical-align: bottom; }
|
||||
.no-filter #tsd-filter { display: none; }
|
||||
#tsd-filter .tsd-filter-group { display: inline-block; height: 40px; vertical-align: bottom; white-space: nowrap; }
|
||||
#tsd-filter input { display: none; }
|
||||
@media (max-width: 900px) { #tsd-filter .tsd-filter-group { display: block; position: absolute; top: 40px; right: 20px; height: auto; background-color: #fff; visibility: hidden; -webkit-transform: translate(50%, 0); transform: translate(50%, 0); box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); }
|
||||
.has-options #tsd-filter .tsd-filter-group { visibility: visible; }
|
||||
.to-has-options #tsd-filter .tsd-filter-group { -webkit-animation: fade-in 0.2s; animation: fade-in 0.2s; }
|
||||
.from-has-options #tsd-filter .tsd-filter-group { -webkit-animation: fade-out 0.2s; animation: fade-out 0.2s; }
|
||||
#tsd-filter label, #tsd-filter .tsd-select { display: block; padding-right: 20px; } }
|
||||
|
||||
footer { border-top: 1px solid #eee; background-color: #fff; }
|
||||
footer.with-border-bottom { border-bottom: 1px solid #eee; }
|
||||
footer .tsd-legend-group { font-size: 0; }
|
||||
footer .tsd-legend { display: inline-block; width: 25%; padding: 0; font-size: 16px; list-style: none; line-height: 1.333em; vertical-align: top; }
|
||||
@media (max-width: 900px) { footer .tsd-legend { width: 50%; } }
|
||||
|
||||
.tsd-hierarchy { list-style: square; padding: 0 0 0 20px; margin: 0; }
|
||||
.tsd-hierarchy .target { font-weight: bold; }
|
||||
|
||||
.tsd-index-panel .tsd-index-content { margin-bottom: -30px !important; }
|
||||
.tsd-index-panel .tsd-index-section { margin-bottom: 30px !important; }
|
||||
.tsd-index-panel h3 { margin: 0 -20px 10px -20px; padding: 0 20px 10px 20px; border-bottom: 1px solid #eee; }
|
||||
.tsd-index-panel ul.tsd-index-list { -webkit-column-count: 3; -moz-column-count: 3; -ms-column-count: 3; -o-column-count: 3; column-count: 3; -webkit-column-gap: 20px; -moz-column-gap: 20px; -ms-column-gap: 20px; -o-column-gap: 20px; column-gap: 20px; padding: 0; list-style: none; line-height: 1.333em; }
|
||||
@media (max-width: 900px) { .tsd-index-panel ul.tsd-index-list { -webkit-column-count: 1; -moz-column-count: 1; -ms-column-count: 1; -o-column-count: 1; column-count: 1; } }
|
||||
@media (min-width: 901px) and (max-width: 1024px) { .tsd-index-panel ul.tsd-index-list { -webkit-column-count: 2; -moz-column-count: 2; -ms-column-count: 2; -o-column-count: 2; column-count: 2; } }
|
||||
.tsd-index-panel ul.tsd-index-list li { -webkit-column-break-inside: avoid; -moz-column-break-inside: avoid; -ms-column-break-inside: avoid; -o-column-break-inside: avoid; column-break-inside: avoid; -webkit-page-break-inside: avoid; -moz-page-break-inside: avoid; -ms-page-break-inside: avoid; -o-page-break-inside: avoid; page-break-inside: avoid; }
|
||||
.tsd-index-panel a, .tsd-index-panel .tsd-parent-kind-module a { color: #9600ff; }
|
||||
.tsd-index-panel .tsd-parent-kind-interface a { color: #7da01f; }
|
||||
.tsd-index-panel .tsd-parent-kind-enum a { color: #cc9900; }
|
||||
.tsd-index-panel .tsd-parent-kind-class a { color: #4da6ff; }
|
||||
.tsd-index-panel .tsd-kind-module a { color: #9600ff; }
|
||||
.tsd-index-panel .tsd-kind-interface a { color: #7da01f; }
|
||||
.tsd-index-panel .tsd-kind-enum a { color: #cc9900; }
|
||||
.tsd-index-panel .tsd-kind-class a { color: #4da6ff; }
|
||||
.tsd-index-panel .tsd-is-private a { color: #808080; }
|
||||
|
||||
.tsd-flag { display: inline-block; padding: 1px 5px; border-radius: 4px; color: #fff; background-color: #808080; text-indent: 0; font-size: 14px; font-weight: normal; }
|
||||
|
||||
.tsd-anchor { position: absolute; top: -100px; }
|
||||
|
||||
.tsd-member { position: relative; }
|
||||
.tsd-member .tsd-anchor + h3 { margin-top: 0; margin-bottom: 0; border-bottom: none; }
|
||||
|
||||
.tsd-navigation { padding: 0 0 0 40px; }
|
||||
.tsd-navigation a { display: block; padding-top: 2px; padding-bottom: 2px; border-left: 2px solid transparent; color: #222; text-decoration: none; transition: border-left-color 0.1s; }
|
||||
.tsd-navigation a:hover { text-decoration: underline; }
|
||||
.tsd-navigation ul { margin: 0; padding: 0; list-style: none; }
|
||||
.tsd-navigation li { padding: 0; }
|
||||
|
||||
.tsd-navigation.primary { padding-bottom: 40px; }
|
||||
.tsd-navigation.primary a { display: block; padding-top: 6px; padding-bottom: 6px; }
|
||||
.tsd-navigation.primary ul li a { padding-left: 5px; }
|
||||
.tsd-navigation.primary ul li li a { padding-left: 25px; }
|
||||
.tsd-navigation.primary ul li li li a { padding-left: 45px; }
|
||||
.tsd-navigation.primary ul li li li li a { padding-left: 65px; }
|
||||
.tsd-navigation.primary ul li li li li li a { padding-left: 85px; }
|
||||
.tsd-navigation.primary ul li li li li li li a { padding-left: 105px; }
|
||||
.tsd-navigation.primary > ul { border-bottom: 1px solid #eee; }
|
||||
.tsd-navigation.primary li { border-top: 1px solid #eee; }
|
||||
.tsd-navigation.primary li.current > a { font-weight: bold; }
|
||||
.tsd-navigation.primary li.label span { display: block; padding: 20px 0 6px 5px; color: #808080; }
|
||||
.tsd-navigation.primary li.globals + li > span, .tsd-navigation.primary li.globals + li > a { padding-top: 20px; }
|
||||
|
||||
.tsd-navigation.secondary ul { transition: opacity 0.2s; }
|
||||
.tsd-navigation.secondary ul li a { padding-left: 25px; }
|
||||
.tsd-navigation.secondary ul li li a { padding-left: 45px; }
|
||||
.tsd-navigation.secondary ul li li li a { padding-left: 65px; }
|
||||
.tsd-navigation.secondary ul li li li li a { padding-left: 85px; }
|
||||
.tsd-navigation.secondary ul li li li li li a { padding-left: 105px; }
|
||||
.tsd-navigation.secondary ul li li li li li li a { padding-left: 125px; }
|
||||
.tsd-navigation.secondary ul.current a { border-left-color: #eee; }
|
||||
.tsd-navigation.secondary li.focus > a, .tsd-navigation.secondary ul.current li.focus > a { border-left-color: #000; }
|
||||
.tsd-navigation.secondary li.current { margin-top: 20px; margin-bottom: 20px; border-left-color: #eee; }
|
||||
.tsd-navigation.secondary li.current > a { font-weight: bold; }
|
||||
|
||||
@media (min-width: 901px) { .menu-sticky-wrap { position: static; }
|
||||
.no-csspositionsticky .menu-sticky-wrap.sticky { position: fixed; }
|
||||
.no-csspositionsticky .menu-sticky-wrap.sticky-current { position: fixed; }
|
||||
.no-csspositionsticky .menu-sticky-wrap.sticky-current ul.before-current, .no-csspositionsticky .menu-sticky-wrap.sticky-current ul.after-current { opacity: 0; }
|
||||
.no-csspositionsticky .menu-sticky-wrap.sticky-bottom { position: absolute; top: auto !important; left: auto !important; bottom: 0; right: 0; }
|
||||
.csspositionsticky .menu-sticky-wrap.sticky { position: -webkit-sticky; position: sticky; }
|
||||
.csspositionsticky .menu-sticky-wrap.sticky-current { position: -webkit-sticky; position: sticky; } }
|
||||
|
||||
.tsd-panel { margin: 20px 0; padding: 20px; background-color: #fff; box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); }
|
||||
.tsd-panel:empty { display: none; }
|
||||
.tsd-panel > h1, .tsd-panel > h2, .tsd-panel > h3 { margin: 1.5em -20px 10px -20px; padding: 0 20px 10px 20px; border-bottom: 1px solid #eee; }
|
||||
.tsd-panel > h1.tsd-before-signature, .tsd-panel > h2.tsd-before-signature, .tsd-panel > h3.tsd-before-signature { margin-bottom: 0; border-bottom: 0; }
|
||||
.tsd-panel table { display: block; width: 100%; overflow: auto; margin-top: 10px; word-break: normal; word-break: keep-all; }
|
||||
.tsd-panel table th { font-weight: bold; }
|
||||
.tsd-panel table th, .tsd-panel table td { padding: 6px 13px; border: 1px solid #ddd; }
|
||||
.tsd-panel table tr { background-color: #fff; border-top: 1px solid #ccc; }
|
||||
.tsd-panel table tr:nth-child(2n) { background-color: #f8f8f8; }
|
||||
|
||||
.tsd-panel-group { margin: 60px 0; }
|
||||
.tsd-panel-group > h1, .tsd-panel-group > h2, .tsd-panel-group > h3 { padding-left: 20px; padding-right: 20px; }
|
||||
|
||||
#tsd-search { transition: background-color 0.2s; }
|
||||
#tsd-search .title { position: relative; z-index: 2; }
|
||||
#tsd-search .field { position: absolute; left: 0; top: 0; right: 40px; height: 40px; }
|
||||
#tsd-search .field input { box-sizing: border-box; position: relative; top: -50px; z-index: 1; width: 100%; padding: 0 10px; opacity: 0; outline: 0; border: 0; background: transparent; color: #222; }
|
||||
#tsd-search .field label { position: absolute; overflow: hidden; right: -40px; }
|
||||
#tsd-search .field input, #tsd-search .title { transition: opacity 0.2s; }
|
||||
#tsd-search .results { position: absolute; visibility: hidden; top: 40px; width: 100%; margin: 0; padding: 0; list-style: none; box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); }
|
||||
#tsd-search .results li { padding: 0 10px; background-color: #fdfdfd; }
|
||||
#tsd-search .results li:nth-child(even) { background-color: #fff; }
|
||||
#tsd-search .results li.state { display: none; }
|
||||
#tsd-search .results li.current, #tsd-search .results li:hover { background-color: #eee; }
|
||||
#tsd-search .results a { display: block; }
|
||||
#tsd-search .results a:before { top: 10px; }
|
||||
#tsd-search .results span.parent { color: #808080; font-weight: normal; }
|
||||
#tsd-search.has-focus { background-color: #eee; }
|
||||
#tsd-search.has-focus .field input { top: 0; opacity: 1; }
|
||||
#tsd-search.has-focus .title { z-index: 0; opacity: 0; }
|
||||
#tsd-search.has-focus .results { visibility: visible; }
|
||||
#tsd-search.loading .results li.state.loading { display: block; }
|
||||
#tsd-search.failure .results li.state.failure { display: block; }
|
||||
|
||||
.tsd-signature { margin: 0 0 1em 0; padding: 10px; border: 1px solid #eee; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
|
||||
.tsd-signature.tsd-kind-icon { padding-left: 30px; }
|
||||
.tsd-signature.tsd-kind-icon:before { top: 10px; left: 10px; }
|
||||
.tsd-panel > .tsd-signature { margin-left: -20px; margin-right: -20px; border-width: 1px 0; }
|
||||
.tsd-panel > .tsd-signature.tsd-kind-icon { padding-left: 40px; }
|
||||
.tsd-panel > .tsd-signature.tsd-kind-icon:before { left: 20px; }
|
||||
|
||||
.tsd-signature-symbol { color: #808080; font-weight: normal; }
|
||||
|
||||
.tsd-signature-type { font-style: italic; font-weight: normal; }
|
||||
|
||||
.tsd-signatures { padding: 0; margin: 0 0 1em 0; border: 1px solid #eee; }
|
||||
.tsd-signatures .tsd-signature { margin: 0; border-width: 1px 0 0 0; transition: background-color 0.1s; }
|
||||
.tsd-signatures .tsd-signature:first-child { border-top-width: 0; }
|
||||
.tsd-signatures .tsd-signature.current { background-color: #eee; }
|
||||
.tsd-signatures.active > .tsd-signature { cursor: pointer; }
|
||||
.tsd-panel > .tsd-signatures { margin-left: -20px; margin-right: -20px; border-width: 1px 0; }
|
||||
.tsd-panel > .tsd-signatures .tsd-signature.tsd-kind-icon { padding-left: 40px; }
|
||||
.tsd-panel > .tsd-signatures .tsd-signature.tsd-kind-icon:before { left: 20px; }
|
||||
.tsd-panel > a.anchor + .tsd-signatures { border-top-width: 0; margin-top: -20px; }
|
||||
|
||||
ul.tsd-descriptions { position: relative; overflow: hidden; transition: height 0.3s; padding: 0; list-style: none; }
|
||||
ul.tsd-descriptions.active > .tsd-description { display: none; }
|
||||
ul.tsd-descriptions.active > .tsd-description.current { display: block; }
|
||||
ul.tsd-descriptions.active > .tsd-description.fade-in { -webkit-animation: fade-in-delayed 0.3s; animation: fade-in-delayed 0.3s; }
|
||||
ul.tsd-descriptions.active > .tsd-description.fade-out { -webkit-animation: fade-out-delayed 0.3s; animation: fade-out-delayed 0.3s; position: absolute; display: block; top: 0; left: 0; right: 0; opacity: 0; visibility: hidden; }
|
||||
ul.tsd-descriptions h4, ul.tsd-descriptions .tsd-index-panel h3, .tsd-index-panel ul.tsd-descriptions h3 { font-size: 16px; margin: 1em 0 0.5em 0; }
|
||||
|
||||
ul.tsd-parameters, ul.tsd-type-parameters { list-style: square; margin: 0; padding-left: 20px; }
|
||||
ul.tsd-parameters > li.tsd-parameter-siganture, ul.tsd-type-parameters > li.tsd-parameter-siganture { list-style: none; margin-left: -20px; }
|
||||
ul.tsd-parameters h5, ul.tsd-type-parameters h5 { font-size: 16px; margin: 1em 0 0.5em 0; }
|
||||
ul.tsd-parameters .tsd-comment, ul.tsd-type-parameters .tsd-comment { margin-top: -0.5em; }
|
||||
|
||||
.tsd-sources { font-size: 14px; color: #808080; margin: 0 0 1em 0; }
|
||||
.tsd-sources a { color: #808080; text-decoration: underline; }
|
||||
.tsd-sources ul, .tsd-sources p { margin: 0 !important; }
|
||||
.tsd-sources ul { list-style: none; padding: 0; }
|
||||
|
||||
.tsd-page-toolbar { position: absolute; z-index: 1; top: 0; left: 0; width: 100%; height: 40px; color: #333; background: #fff; border-bottom: 1px solid #eee; }
|
||||
.tsd-page-toolbar a { color: #333; text-decoration: none; }
|
||||
.tsd-page-toolbar a.title { font-weight: bold; }
|
||||
.tsd-page-toolbar a.title:hover { text-decoration: underline; }
|
||||
.tsd-page-toolbar .table-wrap { display: table; width: 100%; height: 40px; }
|
||||
.tsd-page-toolbar .table-cell { display: table-cell; position: relative; white-space: nowrap; line-height: 40px; }
|
||||
.tsd-page-toolbar .table-cell:first-child { width: 100%; }
|
||||
|
||||
.tsd-widget:before, .tsd-select .tsd-select-label:before, .tsd-select .tsd-select-list li:before { content: ""; display: inline-block; width: 40px; height: 40px; margin: 0 -8px 0 0; background-image: url(../images/widgets.png); background-repeat: no-repeat; text-indent: -1024px; vertical-align: bottom; }
|
||||
@media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { .tsd-widget:before, .tsd-select .tsd-select-label:before, .tsd-select .tsd-select-list li:before { background-image: url(../images/widgets@2x.png); background-size: 320px 40px; } }
|
||||
|
||||
.tsd-widget { display: inline-block; overflow: hidden; opacity: 0.6; height: 40px; transition: opacity 0.1s, background-color 0.2s; vertical-align: bottom; cursor: pointer; }
|
||||
.tsd-widget:hover { opacity: 0.8; }
|
||||
.tsd-widget.active { opacity: 1; background-color: #eee; }
|
||||
.tsd-widget.no-caption { width: 40px; }
|
||||
.tsd-widget.no-caption:before { margin: 0; }
|
||||
.tsd-widget.search:before { background-position: 0 0; }
|
||||
.tsd-widget.menu:before { background-position: -40px 0; }
|
||||
.tsd-widget.options:before { background-position: -80px 0; }
|
||||
.tsd-widget.options, .tsd-widget.menu { display: none; }
|
||||
@media (max-width: 900px) { .tsd-widget.options, .tsd-widget.menu { display: inline-block; } }
|
||||
input[type=checkbox] + .tsd-widget:before { background-position: -120px 0; }
|
||||
input[type=checkbox]:checked + .tsd-widget:before { background-position: -160px 0; }
|
||||
|
||||
.tsd-select { position: relative; display: inline-block; height: 40px; transition: opacity 0.1s, background-color 0.2s; vertical-align: bottom; cursor: pointer; }
|
||||
.tsd-select .tsd-select-label { opacity: 0.6; transition: opacity 0.2s; }
|
||||
.tsd-select .tsd-select-label:before { background-position: -240px 0; }
|
||||
.tsd-select.active .tsd-select-label { opacity: 0.8; }
|
||||
.tsd-select.active .tsd-select-list { visibility: visible; opacity: 1; transition-delay: 0s; }
|
||||
.tsd-select .tsd-select-list { position: absolute; visibility: hidden; top: 40px; left: 0; margin: 0; padding: 0; opacity: 0; list-style: none; box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); transition: visibility 0s 0.2s, opacity 0.2s; }
|
||||
.tsd-select .tsd-select-list li { padding: 0 20px 0 0; background-color: #fdfdfd; }
|
||||
.tsd-select .tsd-select-list li:before { background-position: 40px 0; }
|
||||
.tsd-select .tsd-select-list li:nth-child(even) { background-color: #fff; }
|
||||
.tsd-select .tsd-select-list li:hover { background-color: #eee; }
|
||||
.tsd-select .tsd-select-list li.selected:before { background-position: -200px 0; }
|
||||
@media (max-width: 900px) { .tsd-select .tsd-select-list { top: 0; left: auto; right: 100%; margin-right: -5px; }
|
||||
.tsd-select .tsd-select-label:before { background-position: -280px 0; } }
|
||||
|
||||
img { max-width: 100%; }
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 480 B |
Binary file not shown.
|
Before Width: | Height: | Size: 855 B |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,206 +0,0 @@
|
|||
<!doctype html>
|
||||
<html class="default no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>botlib</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="assets/css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="tsd-page-toolbar">
|
||||
<div class="container">
|
||||
<div class="table-wrap">
|
||||
<div class="table-cell" id="tsd-search" data-index="assets/js/search.js" data-base=".">
|
||||
<div class="field">
|
||||
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
|
||||
<input id="tsd-search-field" type="text" />
|
||||
</div>
|
||||
<ul class="results">
|
||||
<li class="state loading">Preparing search index...</li>
|
||||
<li class="state failure">The search index is not available</li>
|
||||
</ul>
|
||||
<a href="index.html" class="title">botlib</a>
|
||||
</div>
|
||||
<div class="table-cell" id="tsd-widgets">
|
||||
<div id="tsd-filter">
|
||||
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
|
||||
<div class="tsd-filter-group">
|
||||
<div class="tsd-select" id="tsd-filter-visibility">
|
||||
<span class="tsd-select-label">All</span>
|
||||
<ul class="tsd-select-list">
|
||||
<li data-value="public">Public</li>
|
||||
<li data-value="protected">Public/Protected</li>
|
||||
<li data-value="private" class="selected">All</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="checkbox" id="tsd-filter-inherited" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
|
||||
<input type="checkbox" id="tsd-filter-externals" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
|
||||
<input type="checkbox" id="tsd-filter-only-exported" />
|
||||
<label class="tsd-widget" for="tsd-filter-only-exported">Only exported</label>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tsd-page-title">
|
||||
<div class="container">
|
||||
<ul class="tsd-breadcrumb">
|
||||
<li>
|
||||
<a href="globals.html">Globals</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h1> botlib</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="container container-main">
|
||||
<div class="row">
|
||||
<div class="col-8 col-content">
|
||||
<section class="tsd-panel-group tsd-index-group">
|
||||
<h2>Index</h2>
|
||||
<section class="tsd-panel tsd-index-panel">
|
||||
<div class="tsd-index-content">
|
||||
<section class="tsd-index-section ">
|
||||
<h3>External modules</h3>
|
||||
<ul class="tsd-index-list">
|
||||
<li class="tsd-kind-external-module"><a href="modules/_gberror_.html" class="tsd-kind-icon">"GBError"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_gbmininstance_.html" class="tsd-kind-icon">"GBMin<wbr>Instance"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_gbservice_.html" class="tsd-kind-icon">"GBService"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_igbadminservice_.html" class="tsd-kind-icon">"IGBAdmin<wbr>Service"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_igbconversationalservice_.html" class="tsd-kind-icon">"IGBConversational<wbr>Service"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_igbcoreservice_.html" class="tsd-kind-icon">"IGBCore<wbr>Service"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_igbdialog_.html" class="tsd-kind-icon">"IGBDialog"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_igbpackage_.html" class="tsd-kind-icon">"IGBPackage"</a></li>
|
||||
<li class="tsd-kind-external-module tsd-is-external"><a href="modules/_igbinstance_.html" class="tsd-kind-icon">"IGBinstance"</a></li>
|
||||
<li class="tsd-kind-external-module"><a href="modules/_index_.html" class="tsd-kind-icon">"index"</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
|
||||
<nav class="tsd-navigation primary">
|
||||
<ul>
|
||||
<li class="globals current ">
|
||||
<a href="globals.html"><em>Globals</em></a>
|
||||
</li>
|
||||
<li class="label tsd-is-external">
|
||||
<span>Internals</span>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_gberror_.html">"GBError"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_gbmininstance_.html">"GBMin<wbr>Instance"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_gbservice_.html">"GBService"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbadminservice_.html">"IGBAdmin<wbr>Service"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbconversationalservice_.html">"IGBConversational<wbr>Service"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbcoreservice_.html">"IGBCore<wbr>Service"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbdialog_.html">"IGBDialog"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbpackage_.html">"IGBPackage"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_index_.html">"index"</a>
|
||||
</li>
|
||||
<li class="label tsd-is-external">
|
||||
<span>Externals</span>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module tsd-is-external">
|
||||
<a href="modules/_igbinstance_.html">"IGBinstance"</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="tsd-navigation secondary menu-sticky">
|
||||
<ul class="before-current">
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="with-border-bottom">
|
||||
<div class="container">
|
||||
<h2>Legend</h2>
|
||||
<div class="tsd-legend-group">
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-module"><span class="tsd-kind-icon">Module</span></li>
|
||||
<li class="tsd-kind-object-literal"><span class="tsd-kind-icon">Object literal</span></li>
|
||||
<li class="tsd-kind-variable"><span class="tsd-kind-icon">Variable</span></li>
|
||||
<li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li>
|
||||
<li class="tsd-kind-function tsd-has-type-parameter"><span class="tsd-kind-icon">Function with type parameter</span></li>
|
||||
<li class="tsd-kind-index-signature"><span class="tsd-kind-icon">Index signature</span></li>
|
||||
<li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li>
|
||||
<li class="tsd-kind-enum-member"><span class="tsd-kind-icon">Enumeration member</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-enum"><span class="tsd-kind-icon">Property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-enum"><span class="tsd-kind-icon">Method</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li>
|
||||
<li class="tsd-kind-interface tsd-has-type-parameter"><span class="tsd-kind-icon">Interface with type parameter</span></li>
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-interface"><span class="tsd-kind-icon">Constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li>
|
||||
<li class="tsd-kind-index-signature tsd-parent-kind-interface"><span class="tsd-kind-icon">Index signature</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li>
|
||||
<li class="tsd-kind-class tsd-has-type-parameter"><span class="tsd-kind-icon">Class with type parameter</span></li>
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class"><span class="tsd-kind-icon">Accessor</span></li>
|
||||
<li class="tsd-kind-index-signature tsd-parent-kind-class"><span class="tsd-kind-icon">Index signature</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited accessor</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected accessor</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private accessor</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li>
|
||||
<li class="tsd-kind-call-signature tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<div class="container tsd-generator">
|
||||
<p>Generated using <a href="http://typedoc.org/" target="_blank">TypeDoc</a></p>
|
||||
</div>
|
||||
<div class="overlay"></div>
|
||||
<script src="assets/js/main.js"></script>
|
||||
<script>if (location.protocol == 'file:') document.write('<script src="assets/js/search.js"><' + '/script>');</script>
|
||||
</body>
|
||||
</html>
|
||||
188
docs/index.html
188
docs/index.html
|
|
@ -1,188 +0,0 @@
|
|||
<!doctype html>
|
||||
<html class="default no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>botlib</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="assets/css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="tsd-page-toolbar">
|
||||
<div class="container">
|
||||
<div class="table-wrap">
|
||||
<div class="table-cell" id="tsd-search" data-index="assets/js/search.js" data-base=".">
|
||||
<div class="field">
|
||||
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
|
||||
<input id="tsd-search-field" type="text" />
|
||||
</div>
|
||||
<ul class="results">
|
||||
<li class="state loading">Preparing search index...</li>
|
||||
<li class="state failure">The search index is not available</li>
|
||||
</ul>
|
||||
<a href="index.html" class="title">botlib</a>
|
||||
</div>
|
||||
<div class="table-cell" id="tsd-widgets">
|
||||
<div id="tsd-filter">
|
||||
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
|
||||
<div class="tsd-filter-group">
|
||||
<div class="tsd-select" id="tsd-filter-visibility">
|
||||
<span class="tsd-select-label">All</span>
|
||||
<ul class="tsd-select-list">
|
||||
<li data-value="public">Public</li>
|
||||
<li data-value="protected">Public/Protected</li>
|
||||
<li data-value="private" class="selected">All</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="checkbox" id="tsd-filter-inherited" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
|
||||
<input type="checkbox" id="tsd-filter-externals" checked />
|
||||
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
|
||||
<input type="checkbox" id="tsd-filter-only-exported" />
|
||||
<label class="tsd-widget" for="tsd-filter-only-exported">Only exported</label>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tsd-page-title">
|
||||
<div class="container">
|
||||
<ul class="tsd-breadcrumb">
|
||||
<li>
|
||||
<a href="globals.html">Globals</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h1> botlib</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="container container-main">
|
||||
<div class="row">
|
||||
<div class="col-8 col-content">
|
||||
<div class="tsd-panel tsd-typography">
|
||||
<p>General Bots base library for building Node.js TypeScript Apps packages (.gbapp).</p>
|
||||
<p>See: <a href="https://github.com/pragmatismo-io/BotServer">https://github.com/pragmatismo-io/BotServer</a> for main documentation.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
|
||||
<nav class="tsd-navigation primary">
|
||||
<ul>
|
||||
<li class="globals ">
|
||||
<a href="globals.html"><em>Globals</em></a>
|
||||
</li>
|
||||
<li class="label tsd-is-external">
|
||||
<span>Internals</span>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_gberror_.html">"GBError"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_gbmininstance_.html">"GBMin<wbr>Instance"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_gbservice_.html">"GBService"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbadminservice_.html">"IGBAdmin<wbr>Service"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbconversationalservice_.html">"IGBConversational<wbr>Service"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbcoreservice_.html">"IGBCore<wbr>Service"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbdialog_.html">"IGBDialog"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_igbpackage_.html">"IGBPackage"</a>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module">
|
||||
<a href="modules/_index_.html">"index"</a>
|
||||
</li>
|
||||
<li class="label tsd-is-external">
|
||||
<span>Externals</span>
|
||||
</li>
|
||||
<li class=" tsd-kind-external-module tsd-is-external">
|
||||
<a href="modules/_igbinstance_.html">"IGBinstance"</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="tsd-navigation secondary menu-sticky">
|
||||
<ul class="before-current">
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="with-border-bottom">
|
||||
<div class="container">
|
||||
<h2>Legend</h2>
|
||||
<div class="tsd-legend-group">
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-module"><span class="tsd-kind-icon">Module</span></li>
|
||||
<li class="tsd-kind-object-literal"><span class="tsd-kind-icon">Object literal</span></li>
|
||||
<li class="tsd-kind-variable"><span class="tsd-kind-icon">Variable</span></li>
|
||||
<li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li>
|
||||
<li class="tsd-kind-function tsd-has-type-parameter"><span class="tsd-kind-icon">Function with type parameter</span></li>
|
||||
<li class="tsd-kind-index-signature"><span class="tsd-kind-icon">Index signature</span></li>
|
||||
<li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li>
|
||||
<li class="tsd-kind-enum-member"><span class="tsd-kind-icon">Enumeration member</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-enum"><span class="tsd-kind-icon">Property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-enum"><span class="tsd-kind-icon">Method</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li>
|
||||
<li class="tsd-kind-interface tsd-has-type-parameter"><span class="tsd-kind-icon">Interface with type parameter</span></li>
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-interface"><span class="tsd-kind-icon">Constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li>
|
||||
<li class="tsd-kind-index-signature tsd-parent-kind-interface"><span class="tsd-kind-icon">Index signature</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li>
|
||||
<li class="tsd-kind-class tsd-has-type-parameter"><span class="tsd-kind-icon">Class with type parameter</span></li>
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class"><span class="tsd-kind-icon">Accessor</span></li>
|
||||
<li class="tsd-kind-index-signature tsd-parent-kind-class"><span class="tsd-kind-icon">Index signature</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited constructor</span></li>
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited accessor</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected accessor</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private property</span></li>
|
||||
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private method</span></li>
|
||||
<li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private accessor</span></li>
|
||||
</ul>
|
||||
<ul class="tsd-legend">
|
||||
<li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li>
|
||||
<li class="tsd-kind-call-signature tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<div class="container tsd-generator">
|
||||
<p>Generated using <a href="http://typedoc.org/" target="_blank">TypeDoc</a></p>
|
||||
</div>
|
||||
<div class="overlay"></div>
|
||||
<script src="assets/js/main.js"></script>
|
||||
<script>if (location.protocol == 'file:') document.write('<script src="assets/js/search.js"><' + '/script>');</script>
|
||||
</body>
|
||||
</html>
|
||||
10229
package-lock.json
generated
10229
package-lock.json
generated
File diff suppressed because it is too large
Load diff
52
package.json
52
package.json
|
|
@ -1,52 +0,0 @@
|
|||
{
|
||||
"name": "botlib",
|
||||
"version": "5.0.0",
|
||||
"description": "General Bot base library for building Node.js TypeScript Apps packages (.gbapp) and Libray packages (.gblib)",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index",
|
||||
"homepage": "http://www.generalbots.ai",
|
||||
"contributors": [
|
||||
"Rodrigo Rodriguez <me@rodrigorodriguez.com>",
|
||||
"João Antonio Ferreira <joao.parana@gmail.com>",
|
||||
"Jorge Ramos <jramos@pobox.com>",
|
||||
"PH <ph.an@outlook.com>",
|
||||
"Dário Vieira <dario.junior3@gmail.com>"
|
||||
],
|
||||
"license": "AGPL-3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GeneralBots/BotLib.git"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf node_modules/ dist/",
|
||||
"build": "npm install && npm run build-lib",
|
||||
"build-lib": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "3.2.6",
|
||||
"botbuilder": "4.23.0",
|
||||
"botbuilder-adapter-facebook": "1.0.12",
|
||||
"botbuilder-ai": "4.23.0",
|
||||
"botbuilder-azure": "4.23.0",
|
||||
"botbuilder-dialogs": "4.23.0",
|
||||
"botframework-connector": "4.23.0",
|
||||
"chrono-node": "2.7.5",
|
||||
"dotenv-extended": "2.9.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
"ms": "2.1.3",
|
||||
"pragmatismo-io-framework": "1.1.1",
|
||||
"reflect-metadata": "0.2.2",
|
||||
"sequelize": "6.37.3",
|
||||
"sequelize-cli": "6.6.2",
|
||||
"sequelize-typescript": "2.1.6",
|
||||
"underscore": "1.13.7",
|
||||
"winston": "3.14.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/sequelize": "4.28.20",
|
||||
"@types/winston": "2.4.4",
|
||||
"ts-node": "10.9.2",
|
||||
"typedoc": "0.26.6",
|
||||
"typescript": "5.5.4"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import { DialogContext } from "botbuilder-dialogs";
|
||||
|
||||
|
||||
export class GBDialogStep extends DialogContext {
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict'
|
||||
|
||||
export enum GBERROR_TYPE {
|
||||
generalError = 2,
|
||||
nlpGeneralError = 3,
|
||||
}
|
||||
|
||||
export class GBError {
|
||||
static createFromCode(GBERROR_TYPE): any { }
|
||||
|
||||
getMessageFromErrorCode(type: GBERROR_TYPE) {
|
||||
if (type === GBERROR_TYPE.nlpGeneralError) {
|
||||
return `Error accessing NLP, check of the service.`
|
||||
}
|
||||
}
|
||||
|
||||
e: Error
|
||||
|
||||
constructor(e: Error, type: GBERROR_TYPE = GBERROR_TYPE.generalError) {
|
||||
this.e = e
|
||||
}
|
||||
|
||||
static create(message) {
|
||||
return new GBError(Error(message))
|
||||
}
|
||||
}
|
||||
30
src/GBLog.ts
30
src/GBLog.ts
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
const loggers = require("./logger");
|
||||
|
||||
export class GBLog {
|
||||
public static getLogger() { return loggers; }
|
||||
public static error(params): void {
|
||||
loggers[0].error(params);
|
||||
loggers[1].error(params);
|
||||
}
|
||||
public static warn(params): void {
|
||||
loggers[0].warn(params);
|
||||
loggers[1].warn(params);
|
||||
}
|
||||
public static info(params): void {
|
||||
loggers[0].info(params);
|
||||
loggers[1].info(params);
|
||||
}
|
||||
public static debug(params): void {
|
||||
loggers[0].debug(params);
|
||||
loggers[1].debug(params);
|
||||
}
|
||||
public static verbose(params): void {
|
||||
loggers[0].verbose(params);
|
||||
loggers[1].verbose(params);
|
||||
}
|
||||
public static silly(params): void {
|
||||
loggers[0].silly(params);
|
||||
loggers[1].silly(params);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import { BotAdapter, UserState } from "botbuilder";
|
||||
import { DialogSet } from "botbuilder-dialogs";
|
||||
import { IGBInstance } from ".";
|
||||
import { IGBCoreService } from "./IGBCoreService";
|
||||
import { IGBConversationalService, IGBPackage } from ".";
|
||||
import { AzureText } from "pragmatismo-io-framework";
|
||||
import { IGBAdminService } from "./IGBAdminService";
|
||||
import { IGBDeployer } from "./IGBDeployer";
|
||||
import { IGBKBService } from "./IGBKBService";
|
||||
|
||||
/** Minimal services for bot. */
|
||||
|
||||
export class GBMinInstance {
|
||||
packages: IGBPackage[];
|
||||
appPackages: IGBPackage[];
|
||||
botId: string;
|
||||
instance: IGBInstance;
|
||||
core: IGBCoreService;
|
||||
conversationalService: IGBConversationalService;
|
||||
kbService: IGBKBService;
|
||||
adminService: IGBAdminService;
|
||||
deployService: IGBDeployer;
|
||||
textServices: AzureText;
|
||||
bot: BotAdapter;
|
||||
dialogs: DialogSet;
|
||||
userState: UserState;
|
||||
userProfile: any;
|
||||
whatsAppDirectLine: any;
|
||||
|
||||
|
||||
cbMap: {};
|
||||
scriptMap: {};
|
||||
sandBoxMap: {};
|
||||
gbappServices: Array<any> = [];
|
||||
|
||||
constructor() {
|
||||
this.packages = [];
|
||||
this.gbappServices = [];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict'
|
||||
|
||||
export class GBService { }
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { IGBInstance } from ".";
|
||||
import { GBMinInstance } from "./GBMinInstance";
|
||||
|
||||
export interface IGBAdminService {
|
||||
acquireElevatedToken(instanceId): Promise<string>;
|
||||
updateSecurityInfo(
|
||||
instanceId: number,
|
||||
authenticatorTenant: string,
|
||||
authenticatorAuthorityHostUrl: string
|
||||
): Promise<IGBInstance>;
|
||||
|
||||
getValue(instanceId: number, key: string): Promise<string>;
|
||||
setValue(instanceId: number, key: string, value: string): Promise<void>;
|
||||
publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void>;
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { GBMinInstance } from './GBMinInstance';
|
||||
import { GBDialogStep } from './GBDialogStep';
|
||||
|
||||
export interface IGBConversationalService {
|
||||
prompt(min: GBMinInstance, step: GBDialogStep, text: string);
|
||||
sendText(min: GBMinInstance, step: GBDialogStep, text: string);
|
||||
sendEvent(min: GBMinInstance, step: GBDialogStep, name: string, value: Object);
|
||||
sendFile(min: GBMinInstance, step: GBDialogStep, mobile: string, url: string, caption: string);
|
||||
sendAudio(min: GBMinInstance, step: GBDialogStep, url: string);
|
||||
prompt(min: GBMinInstance, step: GBDialogStep, text: string);
|
||||
sendSms(min: GBMinInstance, mobile: string, text: string);
|
||||
routeNLP(step: GBDialogStep, min: GBMinInstance, text: string);
|
||||
getCurrentLanguage(step: GBDialogStep);
|
||||
getNewMobileCode();
|
||||
sendMarkdownToMobile(min: GBMinInstance, step: GBDialogStep, mobile: string, text: string);
|
||||
translate(min: GBMinInstance, text: string, language: string): Promise<string>;
|
||||
getLanguage(min: GBMinInstance, text: string): Promise<string>;
|
||||
spellCheck(min: GBMinInstance, text: string): Promise<string>;
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict"
|
||||
|
||||
import { Sequelize } from "sequelize-typescript"
|
||||
import { IGBInstance } from "./IGBInstance"
|
||||
import { IGBInstallationDeployer } from "./IGBInstallationDeployer";
|
||||
import { IGBPackage } from "./IGBPackage";
|
||||
|
||||
/**
|
||||
* This interface defines the core service which is shared among
|
||||
* bot packages so they can have direct access to base services.
|
||||
*/
|
||||
export interface IGBCoreService {
|
||||
sequelize: Sequelize
|
||||
syncDatabaseStructure()
|
||||
loadInstances(): Promise<IGBInstance[]>;
|
||||
deleteInstance(botId: string): Promise<void>;
|
||||
loadInstanceByBotId(botId: string): Promise<IGBInstance>;
|
||||
loadInstanceByActivationCode(activationCode: string): Promise<IGBInstance>;
|
||||
loadInstanceById(instanceId: number): Promise<IGBInstance>;
|
||||
initStorage(): Promise<any>;
|
||||
createBootInstance(core: IGBCoreService, installationDeployer: IGBInstallationDeployer, proxyAddress: string);
|
||||
ensureAdminIsSecured();
|
||||
loadSysPackages(core: IGBCoreService): Promise<IGBPackage[]>;
|
||||
ensureProxy(port): Promise<string>;
|
||||
ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService);
|
||||
checkStorage(azureDeployer: IGBInstallationDeployer);
|
||||
saveInstance(fullInstance: any);
|
||||
loadAllInstances(core: IGBCoreService, azureDeployer: IGBInstallationDeployer, proxyAddress: string);
|
||||
openBrowserInDevelopment();
|
||||
installWebHook(isGet: boolean, url: string, callback: any);
|
||||
setWWWRoot(localPath: string);
|
||||
setEntryPointDialog(dialogName: string);
|
||||
getParam<T>(instance: IGBInstance, name: string, defaultValue?: T): any;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { IGBInstance } from ".";
|
||||
import { GBMinInstance } from "./GBMinInstance";
|
||||
|
||||
export interface IGBDeployer {
|
||||
undeployPackageFromLocalPath(instance: IGBInstance, localPath: string): Promise<void>;
|
||||
deployPackage(min: GBMinInstance, localPath: string): Promise<void>;
|
||||
deployBlankBot(botId: string, mobile: string, email: string): Promise<IGBInstance>;
|
||||
botExists(botId: string): Promise<Boolean>;
|
||||
rebuildIndex(instance: IGBInstance, searchSchema: any): Promise<void>;
|
||||
refreshNLPEntity(instance: IGBInstance, listName, listData): Promise<void>;
|
||||
getBotManifest(instance: IGBInstance): Promise<Buffer>;
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict"
|
||||
|
||||
import { BotAdapter } from "botbuilder"
|
||||
import { GBService } from "./GBService"
|
||||
|
||||
export class IGBDialog {
|
||||
bot: BotAdapter
|
||||
service: GBService
|
||||
constructor(bot: BotAdapter) {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import { IGBInstance } from "./IGBInstance";
|
||||
|
||||
export interface IGBInstallationDeployer {
|
||||
updateBotProxy(botId: string, group: string, endpoint: string);
|
||||
getSubscriptions(credentials);
|
||||
getKBSearchSchema(indexName);
|
||||
openStorageFirewall(groupName, serverName);
|
||||
createApplication(token: string, name: string);
|
||||
deployFarm(
|
||||
proxyAddress: string,
|
||||
instance: IGBInstance,
|
||||
credentials,
|
||||
subscriptionId: string
|
||||
): Promise<IGBInstance>;
|
||||
deployToCloud(
|
||||
title: string,
|
||||
username: string,
|
||||
password: string,
|
||||
cloudLocation: string,
|
||||
authoringKey: string,
|
||||
appId: string,
|
||||
appPassword: string,
|
||||
subscriptionId: string
|
||||
);
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
export interface IGBInstance {
|
||||
botId: string;
|
||||
whoAmIVideo: string;
|
||||
botEndpoint: string;
|
||||
authenticatorTenant: string;
|
||||
authenticatorAuthorityHostUrl: string;
|
||||
cloudSubscriptionId: string;
|
||||
cloudUsername: string;
|
||||
cloudPassword: string;
|
||||
cloudLocation: string;
|
||||
instanceId: number;
|
||||
title: string;
|
||||
activationCode: string;
|
||||
description: string;
|
||||
version: string;
|
||||
enabledAdmin: boolean;
|
||||
engineName: string;
|
||||
marketplaceId: string;
|
||||
textAnalyticsKey: string;
|
||||
textAnalyticsEndpoint: string;
|
||||
marketplacePassword: string;
|
||||
webchatKey: string;
|
||||
googleBotKey: string;
|
||||
googleChatApiKey: string;
|
||||
googleChatSubscriptionName: string;
|
||||
googleClientEmail: string;
|
||||
googlePrivateKey: string;
|
||||
googleProjectId: string;
|
||||
whatsappServiceKey: string;
|
||||
whatsappBotKey: string;
|
||||
whatsappServiceNumber: string;
|
||||
whatsappServiceUrl: string;
|
||||
facebookWorkplaceVerifyToken: string;
|
||||
facebookWorkplaceAppSecret: string;
|
||||
facebookWorkplaceAccessToken: string;
|
||||
smsKey: string;
|
||||
smsSecret: string;
|
||||
smsServiceNumber: string;
|
||||
theme: string;
|
||||
ui: string;
|
||||
kb: string;
|
||||
nlpAppId: string;
|
||||
nlpKey: string;
|
||||
nlpEndpoint: string;
|
||||
nlpAuthoringKey: string;
|
||||
deploymentPaths: string;
|
||||
speechKey: string;
|
||||
speechEndpoint: string;
|
||||
spellcheckerKey: string;
|
||||
spellcheckerEndpoint: string;
|
||||
searchHost: string;
|
||||
searchKey: string;
|
||||
searchIndex: string;
|
||||
searchIndexer: string;
|
||||
searchScore: number;
|
||||
nlpScore: number;
|
||||
storageUsername: string;
|
||||
storagePassword: string;
|
||||
storageName: string;
|
||||
storageServer: string;
|
||||
storageDialect: string;
|
||||
storagePath: string;
|
||||
adminPass: string;
|
||||
translatorKey: string;
|
||||
translatorEndpoint: string;
|
||||
params: string;
|
||||
state: string;
|
||||
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
export interface IGBKBService {
|
||||
getAnswerTextByMediaName(instanceId: number, answerMediaName: string): Promise<string>;
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { IGBCoreService } from './IGBCoreService'
|
||||
import { Sequelize } from 'sequelize-typescript'
|
||||
import { GBMinInstance } from '.'
|
||||
import { GBDialogStep } from './GBDialogStep';
|
||||
|
||||
export interface IGBPackage{
|
||||
|
||||
/**
|
||||
* Each app has its own set of sys packages.
|
||||
*/
|
||||
sysPackages: IGBPackage[]
|
||||
|
||||
/**
|
||||
* Called when a package is being loaded, once per server or at demand.
|
||||
*/
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void>
|
||||
|
||||
/**
|
||||
* Called when a package needs to be unloaded.
|
||||
*/
|
||||
unloadPackage(core: IGBCoreService): Promise<void>
|
||||
|
||||
/**
|
||||
* Called when a new bot instance is loaded.
|
||||
*/
|
||||
getDialogs(min: GBMinInstance)
|
||||
|
||||
/**
|
||||
* Called when a new bot instance is loaded.
|
||||
*/
|
||||
loadBot(min: GBMinInstance): Promise<void>
|
||||
|
||||
/**
|
||||
* Called whenever a bot instance needs to be shutdown.
|
||||
*/
|
||||
unloadBot(min: GBMinInstance): Promise<void>
|
||||
|
||||
/**
|
||||
* Called in each new session.
|
||||
*/
|
||||
onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void>
|
||||
|
||||
/**
|
||||
* Exchange data between BotServer and .gbapp/.gblib
|
||||
* @param kind 'newMessage', 'getBroadcast', 'getKeywords'
|
||||
* @param data
|
||||
*/
|
||||
onExchangeData (min: GBMinInstance, kind: string, data: any);
|
||||
|
||||
}
|
||||
324
src/branding.rs
Normal file
324
src/branding.rs
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
//! White-Label Branding Module
|
||||
//!
|
||||
//! Allows complete customization of platform identity.
|
||||
//! When a .product file exists with name=MyCustomPlatform,
|
||||
//! "General Bots" never appears in logs, display, messages, footer - nothing.
|
||||
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
/// Global branding configuration - loaded once at startup
|
||||
static BRANDING: OnceLock<BrandingConfig> = OnceLock::new();
|
||||
|
||||
/// Default platform name
|
||||
const DEFAULT_PLATFORM_NAME: &str = "General Bots";
|
||||
const DEFAULT_PLATFORM_SHORT: &str = "GB";
|
||||
const DEFAULT_PLATFORM_DOMAIN: &str = "generalbots.com";
|
||||
|
||||
/// Branding configuration loaded from .product file
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BrandingConfig {
|
||||
/// Platform name (e.g., "MyCustomPlatform")
|
||||
pub name: String,
|
||||
/// Short name for logs and compact displays (e.g., "MCP")
|
||||
pub short_name: String,
|
||||
/// Company/organization name
|
||||
pub company: Option<String>,
|
||||
/// Domain for URLs and emails
|
||||
pub domain: Option<String>,
|
||||
/// Support email
|
||||
pub support_email: Option<String>,
|
||||
/// Logo URL (for web UI)
|
||||
pub logo_url: Option<String>,
|
||||
/// Favicon URL
|
||||
pub favicon_url: Option<String>,
|
||||
/// Primary color (hex)
|
||||
pub primary_color: Option<String>,
|
||||
/// Secondary color (hex)
|
||||
pub secondary_color: Option<String>,
|
||||
/// Footer text
|
||||
pub footer_text: Option<String>,
|
||||
/// Copyright text
|
||||
pub copyright: Option<String>,
|
||||
/// Custom CSS URL
|
||||
pub custom_css: Option<String>,
|
||||
/// Terms of service URL
|
||||
pub terms_url: Option<String>,
|
||||
/// Privacy policy URL
|
||||
pub privacy_url: Option<String>,
|
||||
/// Documentation URL
|
||||
pub docs_url: Option<String>,
|
||||
/// Whether this is a white-label deployment
|
||||
pub is_white_label: bool,
|
||||
}
|
||||
|
||||
impl Default for BrandingConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: DEFAULT_PLATFORM_NAME.to_string(),
|
||||
short_name: DEFAULT_PLATFORM_SHORT.to_string(),
|
||||
company: Some("pragmatismo.com.br".to_string()),
|
||||
domain: Some(DEFAULT_PLATFORM_DOMAIN.to_string()),
|
||||
support_email: Some("support@generalbots.com".to_string()),
|
||||
logo_url: None,
|
||||
favicon_url: None,
|
||||
primary_color: Some("#25d366".to_string()),
|
||||
secondary_color: Some("#075e54".to_string()),
|
||||
footer_text: None,
|
||||
copyright: Some(format!(
|
||||
"© {} pragmatismo.com.br. All rights reserved.",
|
||||
chrono::Utc::now().format("%Y")
|
||||
)),
|
||||
custom_css: None,
|
||||
terms_url: None,
|
||||
privacy_url: None,
|
||||
docs_url: Some("https://docs.generalbots.com".to_string()),
|
||||
is_white_label: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BrandingConfig {
|
||||
/// Load branding from .product file if it exists
|
||||
pub fn load() -> Self {
|
||||
let search_paths = [
|
||||
".product",
|
||||
"config/.product",
|
||||
"/etc/botserver/.product",
|
||||
"/opt/gbo/.product",
|
||||
];
|
||||
|
||||
for path in &search_paths {
|
||||
if let Ok(config) = Self::load_from_file(path) {
|
||||
info!("Loaded white-label branding from {}: {}", path, config.name);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
// Check environment variable
|
||||
if let Ok(product_file) = std::env::var("PRODUCT_FILE") {
|
||||
if let Ok(config) = Self::load_from_file(&product_file) {
|
||||
info!(
|
||||
"Loaded white-label branding from PRODUCT_FILE={}: {}",
|
||||
product_file, config.name
|
||||
);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for individual environment overrides
|
||||
let mut config = Self::default();
|
||||
|
||||
if let Ok(name) = std::env::var("PLATFORM_NAME") {
|
||||
config.name = name;
|
||||
config.is_white_label = true;
|
||||
}
|
||||
if let Ok(short) = std::env::var("PLATFORM_SHORT_NAME") {
|
||||
config.short_name = short;
|
||||
}
|
||||
if let Ok(company) = std::env::var("PLATFORM_COMPANY") {
|
||||
config.company = Some(company);
|
||||
}
|
||||
if let Ok(domain) = std::env::var("PLATFORM_DOMAIN") {
|
||||
config.domain = Some(domain);
|
||||
}
|
||||
if let Ok(logo) = std::env::var("PLATFORM_LOGO_URL") {
|
||||
config.logo_url = Some(logo);
|
||||
}
|
||||
if let Ok(color) = std::env::var("PLATFORM_PRIMARY_COLOR") {
|
||||
config.primary_color = Some(color);
|
||||
}
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
/// Load from a specific file path
|
||||
fn load_from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let path = Path::new(path);
|
||||
if !path.exists() {
|
||||
return Err("File not found".into());
|
||||
}
|
||||
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
|
||||
// Try parsing as TOML first
|
||||
if let Ok(config) = toml::from_str::<ProductFile>(&content) {
|
||||
return Ok(config.into());
|
||||
}
|
||||
|
||||
// Try parsing as simple key=value format
|
||||
let mut config = Self::default();
|
||||
config.is_white_label = true;
|
||||
|
||||
for line in content.lines() {
|
||||
let line = line.trim();
|
||||
if line.is_empty() || line.starts_with('#') || line.starts_with(';') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some((key, value)) = line.split_once('=') {
|
||||
let key = key.trim().to_lowercase();
|
||||
let value = value.trim().trim_matches('"').trim_matches('\'');
|
||||
|
||||
match key.as_str() {
|
||||
"name" | "platform_name" => config.name = value.to_string(),
|
||||
"short_name" | "short" => config.short_name = value.to_string(),
|
||||
"company" | "organization" => config.company = Some(value.to_string()),
|
||||
"domain" => config.domain = Some(value.to_string()),
|
||||
"support_email" | "email" => config.support_email = Some(value.to_string()),
|
||||
"logo_url" | "logo" => config.logo_url = Some(value.to_string()),
|
||||
"favicon_url" | "favicon" => config.favicon_url = Some(value.to_string()),
|
||||
"primary_color" | "color" => config.primary_color = Some(value.to_string()),
|
||||
"secondary_color" => config.secondary_color = Some(value.to_string()),
|
||||
"footer_text" | "footer" => config.footer_text = Some(value.to_string()),
|
||||
"copyright" => config.copyright = Some(value.to_string()),
|
||||
"custom_css" | "css" => config.custom_css = Some(value.to_string()),
|
||||
"terms_url" | "terms" => config.terms_url = Some(value.to_string()),
|
||||
"privacy_url" | "privacy" => config.privacy_url = Some(value.to_string()),
|
||||
"docs_url" | "docs" => config.docs_url = Some(value.to_string()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
/// TOML format for .product file
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ProductFile {
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
short_name: Option<String>,
|
||||
#[serde(default)]
|
||||
company: Option<String>,
|
||||
#[serde(default)]
|
||||
domain: Option<String>,
|
||||
#[serde(default)]
|
||||
support_email: Option<String>,
|
||||
#[serde(default)]
|
||||
logo_url: Option<String>,
|
||||
#[serde(default)]
|
||||
favicon_url: Option<String>,
|
||||
#[serde(default)]
|
||||
primary_color: Option<String>,
|
||||
#[serde(default)]
|
||||
secondary_color: Option<String>,
|
||||
#[serde(default)]
|
||||
footer_text: Option<String>,
|
||||
#[serde(default)]
|
||||
copyright: Option<String>,
|
||||
#[serde(default)]
|
||||
custom_css: Option<String>,
|
||||
#[serde(default)]
|
||||
terms_url: Option<String>,
|
||||
#[serde(default)]
|
||||
privacy_url: Option<String>,
|
||||
#[serde(default)]
|
||||
docs_url: Option<String>,
|
||||
}
|
||||
|
||||
impl From<ProductFile> for BrandingConfig {
|
||||
fn from(pf: ProductFile) -> Self {
|
||||
let short_name = pf.short_name.unwrap_or_else(|| {
|
||||
pf.name
|
||||
.split_whitespace()
|
||||
.map(|w| w.chars().next().unwrap_or('X'))
|
||||
.collect::<String>()
|
||||
.to_uppercase()
|
||||
});
|
||||
|
||||
Self {
|
||||
name: pf.name,
|
||||
short_name,
|
||||
company: pf.company,
|
||||
domain: pf.domain,
|
||||
support_email: pf.support_email,
|
||||
logo_url: pf.logo_url,
|
||||
favicon_url: pf.favicon_url,
|
||||
primary_color: pf.primary_color,
|
||||
secondary_color: pf.secondary_color,
|
||||
footer_text: pf.footer_text,
|
||||
copyright: pf.copyright,
|
||||
custom_css: pf.custom_css,
|
||||
terms_url: pf.terms_url,
|
||||
privacy_url: pf.privacy_url,
|
||||
docs_url: pf.docs_url,
|
||||
is_white_label: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Global Access Functions
|
||||
|
||||
/// Initialize branding at application startup
|
||||
pub fn init_branding() {
|
||||
let config = BrandingConfig::load();
|
||||
let _ = BRANDING.set(config);
|
||||
}
|
||||
|
||||
/// Get the current branding configuration
|
||||
pub fn branding() -> &'static BrandingConfig {
|
||||
BRANDING.get_or_init(BrandingConfig::load)
|
||||
}
|
||||
|
||||
/// Get the platform name
|
||||
pub fn platform_name() -> &'static str {
|
||||
&branding().name
|
||||
}
|
||||
|
||||
/// Get the short platform name
|
||||
pub fn platform_short() -> &'static str {
|
||||
&branding().short_name
|
||||
}
|
||||
|
||||
/// Check if this is a white-label deployment
|
||||
pub fn is_white_label() -> bool {
|
||||
branding().is_white_label
|
||||
}
|
||||
|
||||
/// Get formatted copyright text
|
||||
pub fn copyright_text() -> String {
|
||||
branding().copyright.clone().unwrap_or_else(|| {
|
||||
format!(
|
||||
"© {} {}",
|
||||
chrono::Utc::now().format("%Y"),
|
||||
branding().company.as_deref().unwrap_or(&branding().name)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get footer text
|
||||
pub fn footer_text() -> String {
|
||||
branding()
|
||||
.footer_text
|
||||
.clone()
|
||||
.unwrap_or_else(|| format!("Powered by {}", platform_name()))
|
||||
}
|
||||
|
||||
/// Format a log prefix with platform branding
|
||||
pub fn log_prefix() -> String {
|
||||
format!("[{}]", platform_short())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_default_branding() {
|
||||
let config = BrandingConfig::default();
|
||||
assert_eq!(config.name, "General Bots");
|
||||
assert_eq!(config.short_name, "GB");
|
||||
assert!(!config.is_white_label);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_platform_name_function() {
|
||||
let name = platform_name();
|
||||
assert!(!name.is_empty());
|
||||
}
|
||||
}
|
||||
227
src/error.rs
Normal file
227
src/error.rs
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
use thiserror::Error;
|
||||
|
||||
pub type BotResult<T> = Result<T, BotError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum BotError {
|
||||
#[error("Configuration error: {0}")]
|
||||
Config(String),
|
||||
|
||||
#[error("Database error: {0}")]
|
||||
Database(String),
|
||||
|
||||
#[error("HTTP error: {status} - {message}")]
|
||||
Http { status: u16, message: String },
|
||||
|
||||
#[error("Auth error: {0}")]
|
||||
Auth(String),
|
||||
|
||||
#[error("Validation error: {0}")]
|
||||
Validation(String),
|
||||
|
||||
#[error("{entity} not found")]
|
||||
NotFound { entity: String },
|
||||
|
||||
#[error("Conflict: {0}")]
|
||||
Conflict(String),
|
||||
|
||||
#[error("Rate limited: retry after {retry_after_secs}s")]
|
||||
RateLimited { retry_after_secs: u64 },
|
||||
|
||||
#[error("Service unavailable: {0}")]
|
||||
ServiceUnavailable(String),
|
||||
|
||||
#[error("Timeout after {duration_ms}ms")]
|
||||
Timeout { duration_ms: u64 },
|
||||
|
||||
#[error("Internal error: {0}")]
|
||||
Internal(String),
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("JSON error: {0}")]
|
||||
Json(#[from] serde_json::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl BotError {
|
||||
pub fn config(msg: impl Into<String>) -> Self {
|
||||
Self::Config(msg.into())
|
||||
}
|
||||
|
||||
pub fn database(msg: impl Into<String>) -> Self {
|
||||
Self::Database(msg.into())
|
||||
}
|
||||
|
||||
pub fn http(status: u16, msg: impl Into<String>) -> Self {
|
||||
Self::Http {
|
||||
status,
|
||||
message: msg.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn http_msg(msg: impl Into<String>) -> Self {
|
||||
Self::Http {
|
||||
status: 500,
|
||||
message: msg.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auth(msg: impl Into<String>) -> Self {
|
||||
Self::Auth(msg.into())
|
||||
}
|
||||
|
||||
pub fn validation(msg: impl Into<String>) -> Self {
|
||||
Self::Validation(msg.into())
|
||||
}
|
||||
|
||||
pub fn not_found(entity: impl Into<String>) -> Self {
|
||||
Self::NotFound {
|
||||
entity: entity.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn conflict(msg: impl Into<String>) -> Self {
|
||||
Self::Conflict(msg.into())
|
||||
}
|
||||
|
||||
pub fn rate_limited(retry_after_secs: u64) -> Self {
|
||||
Self::RateLimited { retry_after_secs }
|
||||
}
|
||||
|
||||
pub fn service_unavailable(msg: impl Into<String>) -> Self {
|
||||
Self::ServiceUnavailable(msg.into())
|
||||
}
|
||||
|
||||
pub fn timeout(duration_ms: u64) -> Self {
|
||||
Self::Timeout { duration_ms }
|
||||
}
|
||||
|
||||
pub fn internal(msg: impl Into<String>) -> Self {
|
||||
Self::Internal(msg.into())
|
||||
}
|
||||
|
||||
pub fn status_code(&self) -> u16 {
|
||||
match self {
|
||||
Self::Config(_) => 500,
|
||||
Self::Database(_) => 500,
|
||||
Self::Http { status, .. } => *status,
|
||||
Self::Auth(_) => 401,
|
||||
Self::Validation(_) => 400,
|
||||
Self::NotFound { .. } => 404,
|
||||
Self::Conflict(_) => 409,
|
||||
Self::RateLimited { .. } => 429,
|
||||
Self::ServiceUnavailable(_) => 503,
|
||||
Self::Timeout { .. } => 504,
|
||||
Self::Internal(_) => 500,
|
||||
Self::Io(_) => 500,
|
||||
Self::Json(_) => 400,
|
||||
Self::Other(_) => 500,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_retryable(&self) -> bool {
|
||||
match self {
|
||||
Self::RateLimited { .. } | Self::ServiceUnavailable(_) | Self::Timeout { .. } => true,
|
||||
Self::Http { status, .. } => *status >= 500,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_client_error(&self) -> bool {
|
||||
let code = self.status_code();
|
||||
(400..500).contains(&code)
|
||||
}
|
||||
|
||||
pub fn is_server_error(&self) -> bool {
|
||||
self.status_code() >= 500
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for BotError {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
Self::Other(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for BotError {
|
||||
fn from(msg: String) -> Self {
|
||||
Self::Other(msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for BotError {
|
||||
fn from(msg: &str) -> Self {
|
||||
Self::Other(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
impl From<reqwest::Error> for BotError {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
let status = err.status().map(|s| s.as_u16()).unwrap_or(500);
|
||||
Self::Http {
|
||||
status,
|
||||
message: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_error_display() {
|
||||
let err = BotError::config("missing API key");
|
||||
assert_eq!(err.to_string(), "Configuration error: missing API key");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_found_error() {
|
||||
let err = BotError::not_found("User");
|
||||
assert_eq!(err.to_string(), "User not found");
|
||||
assert_eq!(err.status_code(), 404);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_http_error_with_status() {
|
||||
let err = BotError::http(503, "Service down");
|
||||
assert_eq!(err.status_code(), 503);
|
||||
assert!(err.is_server_error());
|
||||
assert!(!err.is_client_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validation_error() {
|
||||
let err = BotError::validation("Invalid email format");
|
||||
assert_eq!(err.status_code(), 400);
|
||||
assert!(err.is_client_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_retryable_errors() {
|
||||
assert!(BotError::rate_limited(60).is_retryable());
|
||||
assert!(BotError::service_unavailable("down").is_retryable());
|
||||
assert!(BotError::timeout(5000).is_retryable());
|
||||
assert!(!BotError::validation("bad input").is_retryable());
|
||||
assert!(!BotError::not_found("User").is_retryable());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limited_display() {
|
||||
let err = BotError::rate_limited(30);
|
||||
assert_eq!(err.to_string(), "Rate limited: retry after 30s");
|
||||
assert_eq!(err.status_code(), 429);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_timeout_display() {
|
||||
let err = BotError::timeout(5000);
|
||||
assert_eq!(err.to_string(), "Timeout after 5000ms");
|
||||
assert_eq!(err.status_code(), 504);
|
||||
}
|
||||
}
|
||||
219
src/http_client.rs
Normal file
219
src/http_client.rs
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
use crate::error::BotError;
|
||||
use log::{debug, error};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
const DEFAULT_BOTSERVER_URL: &str = "https://localhost:8088";
|
||||
const DEFAULT_TIMEOUT_SECS: u64 = 30;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BotServerClient {
|
||||
client: Arc<reqwest::Client>,
|
||||
base_url: String,
|
||||
}
|
||||
|
||||
impl BotServerClient {
|
||||
pub fn new(base_url: Option<String>) -> Self {
|
||||
Self::with_timeout(base_url, Duration::from_secs(DEFAULT_TIMEOUT_SECS))
|
||||
}
|
||||
|
||||
pub fn with_timeout(base_url: Option<String>, timeout: Duration) -> Self {
|
||||
let url = base_url.unwrap_or_else(|| {
|
||||
std::env::var("BOTSERVER_URL").unwrap_or_else(|_| DEFAULT_BOTSERVER_URL.to_string())
|
||||
});
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(timeout)
|
||||
.user_agent(format!("BotLib/{}", env!("CARGO_PKG_VERSION")))
|
||||
.danger_accept_invalid_certs(true)
|
||||
.build()
|
||||
.expect("Failed to create HTTP client");
|
||||
|
||||
Self {
|
||||
client: Arc::new(client),
|
||||
base_url: url,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_url(&self) -> &str {
|
||||
&self.base_url
|
||||
}
|
||||
|
||||
pub async fn get<T: DeserializeOwned>(&self, endpoint: &str) -> Result<T, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("GET {}", url);
|
||||
|
||||
let response = self.client.get(&url).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn post<T: Serialize, R: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
body: &T,
|
||||
) -> Result<R, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("POST {}", url);
|
||||
|
||||
let response = self.client.post(&url).json(body).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn put<T: Serialize, R: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
body: &T,
|
||||
) -> Result<R, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("PUT {}", url);
|
||||
|
||||
let response = self.client.put(&url).json(body).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn patch<T: Serialize, R: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
body: &T,
|
||||
) -> Result<R, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("PATCH {}", url);
|
||||
|
||||
let response = self.client.patch(&url).json(body).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn delete<T: DeserializeOwned>(&self, endpoint: &str) -> Result<T, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("DELETE {}", url);
|
||||
|
||||
let response = self.client.delete(&url).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn get_authorized<T: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
token: &str,
|
||||
) -> Result<T, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("GET {} (authorized)", url);
|
||||
|
||||
let response = self.client.get(&url).bearer_auth(token).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn post_authorized<T: Serialize, R: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
body: &T,
|
||||
token: &str,
|
||||
) -> Result<R, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("POST {} (authorized)", url);
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.post(&url)
|
||||
.bearer_auth(token)
|
||||
.json(body)
|
||||
.send()
|
||||
.await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn delete_authorized<T: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
token: &str,
|
||||
) -> Result<T, BotError> {
|
||||
let url = format!("{}{}", self.base_url, endpoint);
|
||||
debug!("DELETE {} (authorized)", url);
|
||||
|
||||
let response = self.client.delete(&url).bearer_auth(token).send().await?;
|
||||
self.handle_response(response).await
|
||||
}
|
||||
|
||||
pub async fn health_check(&self) -> bool {
|
||||
match self.get::<serde_json::Value>("/health").await {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
error!("Health check failed: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_response<T: DeserializeOwned>(
|
||||
&self,
|
||||
response: reqwest::Response,
|
||||
) -> Result<T, BotError> {
|
||||
let status = response.status();
|
||||
let status_code = status.as_u16();
|
||||
|
||||
if !status.is_success() {
|
||||
let error_text = response
|
||||
.text()
|
||||
.await
|
||||
.unwrap_or_else(|_| "Unknown error".to_string());
|
||||
error!("HTTP {} error: {}", status_code, error_text);
|
||||
return Err(BotError::http(status_code, error_text));
|
||||
}
|
||||
|
||||
response.json().await.map_err(|e| {
|
||||
error!("Failed to parse response: {}", e);
|
||||
BotError::http(status_code, format!("Failed to parse response: {}", e))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BotServerClient {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BotServerClient")
|
||||
.field("base_url", &self.base_url)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_client_creation() {
|
||||
let client = BotServerClient::new(Some("http://localhost:8080".to_string()));
|
||||
assert_eq!(client.base_url(), "http://localhost:8080");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_default_url() {
|
||||
std::env::remove_var("BOTSERVER_URL");
|
||||
let client = BotServerClient::new(None);
|
||||
assert_eq!(client.base_url(), DEFAULT_BOTSERVER_URL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_with_timeout() {
|
||||
let client = BotServerClient::with_timeout(
|
||||
Some("http://test:9000".to_string()),
|
||||
Duration::from_secs(60),
|
||||
);
|
||||
assert_eq!(client.base_url(), "http://test:9000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_with_timeout_default_url() {
|
||||
std::env::remove_var("BOTSERVER_URL");
|
||||
let client = BotServerClient::with_timeout(None, Duration::from_secs(60));
|
||||
assert_eq!(client.base_url(), DEFAULT_BOTSERVER_URL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_debug() {
|
||||
let client = BotServerClient::new(Some("http://debug-test".to_string()));
|
||||
let debug_str = format!("{:?}", client);
|
||||
assert!(debug_str.contains("BotServerClient"));
|
||||
assert!(debug_str.contains("http://debug-test"));
|
||||
}
|
||||
}
|
||||
47
src/index.ts
47
src/index.ts
|
|
@ -1,47 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
export { Sequelize } from "sequelize-typescript";
|
||||
export { IGBConversationalService } from "./IGBConversationalService";
|
||||
export { IGBKBService } from "./IGBKBService";
|
||||
export { IGBCoreService } from "./IGBCoreService";
|
||||
export { IGBDialog } from "./IGBDialog";
|
||||
export { IGBPackage } from "./IGBPackage";
|
||||
export { IGBInstance } from "./IGBInstance";
|
||||
export { GBError, GBERROR_TYPE } from "./GBError";
|
||||
export { GBService } from "./GBService";
|
||||
export { GBMinInstance } from "./GBMinInstance";
|
||||
export { IGBAdminService } from "./IGBAdminService";
|
||||
export { IGBInstallationDeployer } from "./IGBInstallationDeployer";
|
||||
export { IGBDeployer } from "./IGBDeployer";
|
||||
export { GBDialogStep } from "./GBDialogStep";
|
||||
export { GBLog } from "./GBLog";
|
||||
30
src/lib.rs
Normal file
30
src/lib.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
//! BotLib - Shared library for General Bots
|
||||
//!
|
||||
//! This crate provides common types, utilities, and abstractions
|
||||
//! shared between botserver and botui.
|
||||
//!
|
||||
//! # Features
|
||||
//! - `database` - Database connection utilities (diesel)
|
||||
//! - `http-client` - HTTP client for API calls
|
||||
//! - `validation` - Request validation derive macros
|
||||
|
||||
pub mod branding;
|
||||
pub mod error;
|
||||
#[cfg(feature = "http-client")]
|
||||
pub mod http_client;
|
||||
pub mod message_types;
|
||||
pub mod models;
|
||||
pub mod version;
|
||||
|
||||
// Re-exports for convenience
|
||||
pub use branding::{branding, init_branding, is_white_label, platform_name, platform_short, BrandingConfig};
|
||||
pub use error::{BotError, BotResult};
|
||||
pub use message_types::MessageType;
|
||||
pub use models::{ApiResponse, BotResponse, Session, Suggestion, UserMessage};
|
||||
pub use version::{
|
||||
get_botserver_version, init_version_registry, register_component, version_string,
|
||||
ComponentSource, ComponentStatus, ComponentVersion, VersionRegistry, BOTSERVER_VERSION,
|
||||
};
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
pub use http_client::BotServerClient;
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||
| |
|
||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview Logging support.
|
||||
*/
|
||||
|
||||
const { createLogger, format, transports } = require('winston');
|
||||
|
||||
const config = {
|
||||
levels: {
|
||||
error: 0,
|
||||
debug: 1,
|
||||
warn: 2,
|
||||
data: 3,
|
||||
info: 4,
|
||||
verbose: 5,
|
||||
silly: 6,
|
||||
custom: 7
|
||||
},
|
||||
colors: {
|
||||
error: 'red',
|
||||
debug: 'blue',
|
||||
warn: 'yellow',
|
||||
data: 'grey',
|
||||
info: 'green',
|
||||
verbose: 'cyan',
|
||||
silly: 'magenta',
|
||||
custom: 'yellow'
|
||||
}
|
||||
};
|
||||
|
||||
const logger = createLogger({
|
||||
format: format.combine(
|
||||
format.colorize(),
|
||||
format.simple(),
|
||||
format.label({ label: 'GB' }),
|
||||
format.timestamp(),
|
||||
format.printf(nfo => {
|
||||
return `${nfo.timestamp.replace(/\-|\.|\d\d\dZ|\:/gi, '' )} ${nfo.label} ${nfo.level} ${nfo.message}`;
|
||||
})
|
||||
),
|
||||
levels: config.levels,
|
||||
transports: [
|
||||
new transports.Console()]
|
||||
});
|
||||
|
||||
const logger2 = createLogger({
|
||||
levels: config.levels,
|
||||
transports: [new (transports.File)({
|
||||
filename: 'GB.log.json', json: true
|
||||
})]
|
||||
});
|
||||
|
||||
module.exports = [logger, logger2];
|
||||
86
src/message_types.rs
Normal file
86
src/message_types.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//! Message type definitions
|
||||
//!
|
||||
//! Defines the different types of messages in the bot system.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Enum representing different types of messages in the bot system
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct MessageType(pub i32);
|
||||
|
||||
impl MessageType {
|
||||
/// Regular message from external systems (WhatsApp, Instagram, etc.)
|
||||
pub const EXTERNAL: MessageType = MessageType(0);
|
||||
|
||||
/// User message from web interface
|
||||
pub const USER: MessageType = MessageType(1);
|
||||
|
||||
/// Bot response (can be regular content or event)
|
||||
pub const BOT_RESPONSE: MessageType = MessageType(2);
|
||||
|
||||
/// Continue interrupted response
|
||||
pub const CONTINUE: MessageType = MessageType(3);
|
||||
|
||||
/// Suggestion or command message
|
||||
pub const SUGGESTION: MessageType = MessageType(4);
|
||||
|
||||
/// Context change notification
|
||||
pub const CONTEXT_CHANGE: MessageType = MessageType(5);
|
||||
}
|
||||
|
||||
impl From<i32> for MessageType {
|
||||
fn from(value: i32) -> Self {
|
||||
MessageType(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MessageType> for i32 {
|
||||
fn from(value: MessageType) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MessageType {
|
||||
fn default() -> Self {
|
||||
MessageType::USER
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MessageType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let name = match self.0 {
|
||||
0 => "EXTERNAL",
|
||||
1 => "USER",
|
||||
2 => "BOT_RESPONSE",
|
||||
3 => "CONTINUE",
|
||||
4 => "SUGGESTION",
|
||||
5 => "CONTEXT_CHANGE",
|
||||
_ => "UNKNOWN",
|
||||
};
|
||||
write!(f, "{}", name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_message_type_conversion() {
|
||||
assert_eq!(i32::from(MessageType::USER), 1);
|
||||
assert_eq!(MessageType::from(2), MessageType::BOT_RESPONSE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_type_display() {
|
||||
assert_eq!(MessageType::USER.to_string(), "USER");
|
||||
assert_eq!(MessageType::BOT_RESPONSE.to_string(), "BOT_RESPONSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_type_equality() {
|
||||
assert_eq!(MessageType::USER, MessageType(1));
|
||||
assert_ne!(MessageType::USER, MessageType::BOT_RESPONSE);
|
||||
}
|
||||
}
|
||||
540
src/models.rs
Normal file
540
src/models.rs
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
use crate::message_types::MessageType;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ApiResponse<T> {
|
||||
pub success: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<T>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code: Option<String>,
|
||||
}
|
||||
|
||||
impl<T> ApiResponse<T> {
|
||||
pub fn success(data: T) -> Self {
|
||||
Self {
|
||||
success: true,
|
||||
data: Some(data),
|
||||
error: None,
|
||||
message: None,
|
||||
code: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn success_with_message(data: T, message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
success: true,
|
||||
data: Some(data),
|
||||
error: None,
|
||||
message: Some(message.into()),
|
||||
code: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
success: false,
|
||||
data: None,
|
||||
error: Some(message.into()),
|
||||
message: None,
|
||||
code: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_with_code(message: impl Into<String>, code: impl Into<String>) -> Self {
|
||||
Self {
|
||||
success: false,
|
||||
data: None,
|
||||
error: Some(message.into()),
|
||||
message: None,
|
||||
code: Some(code.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> ApiResponse<U> {
|
||||
ApiResponse {
|
||||
success: self.success,
|
||||
data: self.data.map(f),
|
||||
error: self.error,
|
||||
message: self.message,
|
||||
code: self.code,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_success(&self) -> bool {
|
||||
self.success
|
||||
}
|
||||
|
||||
pub fn is_error(&self) -> bool {
|
||||
!self.success
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for ApiResponse<T> {
|
||||
fn default() -> Self {
|
||||
Self::success(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Session {
|
||||
pub id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub bot_id: Uuid,
|
||||
pub title: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub expires_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn new(user_id: Uuid, bot_id: Uuid, title: impl Into<String>) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
user_id,
|
||||
bot_id,
|
||||
title: title.into(),
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
expires_at: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_expiry(mut self, expires_at: DateTime<Utc>) -> Self {
|
||||
self.expires_at = Some(expires_at);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_expired(&self) -> bool {
|
||||
self.expires_at.map(|exp| Utc::now() > exp).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> bool {
|
||||
!self.is_expired()
|
||||
}
|
||||
|
||||
pub fn remaining_time(&self) -> Option<chrono::Duration> {
|
||||
self.expires_at.map(|exp| exp - Utc::now())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserMessage {
|
||||
pub bot_id: String,
|
||||
pub user_id: String,
|
||||
pub session_id: String,
|
||||
pub channel: String,
|
||||
pub content: String,
|
||||
pub message_type: MessageType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub media_url: Option<String>,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context_name: Option<String>,
|
||||
}
|
||||
|
||||
impl UserMessage {
|
||||
pub fn text(
|
||||
bot_id: impl Into<String>,
|
||||
user_id: impl Into<String>,
|
||||
session_id: impl Into<String>,
|
||||
channel: impl Into<String>,
|
||||
content: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bot_id: bot_id.into(),
|
||||
user_id: user_id.into(),
|
||||
session_id: session_id.into(),
|
||||
channel: channel.into(),
|
||||
content: content.into(),
|
||||
message_type: MessageType::USER,
|
||||
media_url: None,
|
||||
timestamp: Utc::now(),
|
||||
context_name: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_media(mut self, url: impl Into<String>) -> Self {
|
||||
self.media_url = Some(url.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_context(mut self, context: impl Into<String>) -> Self {
|
||||
self.context_name = Some(context.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn has_media(&self) -> bool {
|
||||
self.media_url.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Suggestion {
|
||||
pub text: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub action: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub icon: Option<String>,
|
||||
}
|
||||
|
||||
impl Suggestion {
|
||||
pub fn new(text: impl Into<String>) -> Self {
|
||||
Self {
|
||||
text: text.into(),
|
||||
context: None,
|
||||
action: None,
|
||||
icon: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_context(mut self, context: impl Into<String>) -> Self {
|
||||
self.context = Some(context.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_action(mut self, action: impl Into<String>) -> Self {
|
||||
self.action = Some(action.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_icon(mut self, icon: impl Into<String>) -> Self {
|
||||
self.icon = Some(icon.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<String>> From<S> for Suggestion {
|
||||
fn from(text: S) -> Self {
|
||||
Self::new(text)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BotResponse {
|
||||
pub bot_id: String,
|
||||
pub user_id: String,
|
||||
pub session_id: String,
|
||||
pub channel: String,
|
||||
pub content: String,
|
||||
pub message_type: MessageType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stream_token: Option<String>,
|
||||
pub is_complete: bool,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub suggestions: Vec<Suggestion>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub context_length: usize,
|
||||
#[serde(default)]
|
||||
pub context_max_length: usize,
|
||||
}
|
||||
|
||||
impl BotResponse {
|
||||
pub fn new(
|
||||
bot_id: impl Into<String>,
|
||||
session_id: impl Into<String>,
|
||||
user_id: impl Into<String>,
|
||||
content: impl Into<String>,
|
||||
channel: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bot_id: bot_id.into(),
|
||||
user_id: user_id.into(),
|
||||
session_id: session_id.into(),
|
||||
channel: channel.into(),
|
||||
content: content.into(),
|
||||
message_type: MessageType::BOT_RESPONSE,
|
||||
stream_token: None,
|
||||
is_complete: true,
|
||||
suggestions: Vec::new(),
|
||||
context_name: None,
|
||||
context_length: 0,
|
||||
context_max_length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn streaming(
|
||||
bot_id: impl Into<String>,
|
||||
session_id: impl Into<String>,
|
||||
user_id: impl Into<String>,
|
||||
channel: impl Into<String>,
|
||||
stream_token: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bot_id: bot_id.into(),
|
||||
user_id: user_id.into(),
|
||||
session_id: session_id.into(),
|
||||
channel: channel.into(),
|
||||
content: String::new(),
|
||||
message_type: MessageType::BOT_RESPONSE,
|
||||
stream_token: Some(stream_token.into()),
|
||||
is_complete: false,
|
||||
suggestions: Vec::new(),
|
||||
context_name: None,
|
||||
context_length: 0,
|
||||
context_max_length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_suggestions<I, S>(mut self, suggestions: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: Into<Suggestion>,
|
||||
{
|
||||
self.suggestions = suggestions.into_iter().map(Into::into).collect();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_suggestion(mut self, suggestion: impl Into<Suggestion>) -> Self {
|
||||
self.suggestions.push(suggestion.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_context(
|
||||
mut self,
|
||||
name: impl Into<String>,
|
||||
length: usize,
|
||||
max_length: usize,
|
||||
) -> Self {
|
||||
self.context_name = Some(name.into());
|
||||
self.context_length = length;
|
||||
self.context_max_length = max_length;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn append_content(&mut self, chunk: &str) {
|
||||
self.content.push_str(chunk);
|
||||
}
|
||||
|
||||
pub fn complete(mut self) -> Self {
|
||||
self.is_complete = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_streaming(&self) -> bool {
|
||||
self.stream_token.is_some() && !self.is_complete
|
||||
}
|
||||
|
||||
pub fn has_suggestions(&self) -> bool {
|
||||
!self.suggestions.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BotResponse {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bot_id: String::new(),
|
||||
user_id: String::new(),
|
||||
session_id: String::new(),
|
||||
channel: String::new(),
|
||||
content: String::new(),
|
||||
message_type: MessageType::BOT_RESPONSE,
|
||||
stream_token: None,
|
||||
is_complete: true,
|
||||
suggestions: Vec::new(),
|
||||
context_name: None,
|
||||
context_length: 0,
|
||||
context_max_length: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Attachment {
|
||||
pub attachment_type: AttachmentType,
|
||||
pub url: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mime_type: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub filename: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub size: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub thumbnail_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AttachmentType {
|
||||
Image,
|
||||
Audio,
|
||||
Video,
|
||||
Document,
|
||||
File,
|
||||
}
|
||||
|
||||
impl Attachment {
|
||||
pub fn new(attachment_type: AttachmentType, url: impl Into<String>) -> Self {
|
||||
Self {
|
||||
attachment_type,
|
||||
url: url.into(),
|
||||
mime_type: None,
|
||||
filename: None,
|
||||
size: None,
|
||||
thumbnail_url: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image(url: impl Into<String>) -> Self {
|
||||
Self::new(AttachmentType::Image, url)
|
||||
}
|
||||
|
||||
pub fn audio(url: impl Into<String>) -> Self {
|
||||
Self::new(AttachmentType::Audio, url)
|
||||
}
|
||||
|
||||
pub fn video(url: impl Into<String>) -> Self {
|
||||
Self::new(AttachmentType::Video, url)
|
||||
}
|
||||
|
||||
pub fn document(url: impl Into<String>) -> Self {
|
||||
Self::new(AttachmentType::Document, url)
|
||||
}
|
||||
|
||||
pub fn file(url: impl Into<String>) -> Self {
|
||||
Self::new(AttachmentType::File, url)
|
||||
}
|
||||
|
||||
pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
|
||||
self.mime_type = Some(mime_type.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_filename(mut self, filename: impl Into<String>) -> Self {
|
||||
self.filename = Some(filename.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_size(mut self, size: u64) -> Self {
|
||||
self.size = Some(size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_thumbnail(mut self, thumbnail_url: impl Into<String>) -> Self {
|
||||
self.thumbnail_url = Some(thumbnail_url.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_image(&self) -> bool {
|
||||
self.attachment_type == AttachmentType::Image
|
||||
}
|
||||
|
||||
pub fn is_media(&self) -> bool {
|
||||
matches!(
|
||||
self.attachment_type,
|
||||
AttachmentType::Image | AttachmentType::Audio | AttachmentType::Video
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_api_response_success() {
|
||||
let response: ApiResponse<String> = ApiResponse::success("test".to_string());
|
||||
assert!(response.is_success());
|
||||
assert!(!response.is_error());
|
||||
assert_eq!(response.data, Some("test".to_string()));
|
||||
assert!(response.error.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_response_error() {
|
||||
let response: ApiResponse<String> = ApiResponse::error("something went wrong");
|
||||
assert!(!response.is_success());
|
||||
assert!(response.is_error());
|
||||
assert!(response.data.is_none());
|
||||
assert_eq!(response.error, Some("something went wrong".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_response_map() {
|
||||
let response: ApiResponse<i32> = ApiResponse::success(42);
|
||||
let mapped = response.map(|n| n.to_string());
|
||||
assert_eq!(mapped.data, Some("42".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_session_creation() {
|
||||
let user_id = Uuid::new_v4();
|
||||
let bot_id = Uuid::new_v4();
|
||||
let session = Session::new(user_id, bot_id, "Test Session");
|
||||
|
||||
assert_eq!(session.user_id, user_id);
|
||||
assert_eq!(session.bot_id, bot_id);
|
||||
assert_eq!(session.title, "Test Session");
|
||||
assert!(session.is_active());
|
||||
assert!(!session.is_expired());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user_message_creation() {
|
||||
let msg =
|
||||
UserMessage::text("bot1", "user1", "sess1", "web", "Hello!").with_context("greeting");
|
||||
|
||||
assert_eq!(msg.content, "Hello!");
|
||||
assert_eq!(msg.message_type, MessageType::USER);
|
||||
assert_eq!(msg.context_name, Some("greeting".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bot_response_creation() {
|
||||
let response = BotResponse::new("bot1", "sess1", "user1", "Hi there!", "web")
|
||||
.add_suggestion("Option 1")
|
||||
.add_suggestion("Option 2");
|
||||
|
||||
assert!(response.is_complete);
|
||||
assert!(!response.is_streaming());
|
||||
assert!(response.has_suggestions());
|
||||
assert_eq!(response.suggestions.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bot_response_streaming() {
|
||||
let mut response = BotResponse::streaming("bot1", "sess1", "user1", "web", "token123");
|
||||
assert!(response.is_streaming());
|
||||
assert!(!response.is_complete);
|
||||
|
||||
response.append_content("Hello ");
|
||||
response.append_content("World!");
|
||||
assert_eq!(response.content, "Hello World!");
|
||||
|
||||
let response = response.complete();
|
||||
assert!(!response.is_streaming());
|
||||
assert!(response.is_complete);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attachment_creation() {
|
||||
let attachment = Attachment::image("https://example.com/photo.jpg")
|
||||
.with_filename("photo.jpg")
|
||||
.with_size(1024)
|
||||
.with_mime_type("image/jpeg");
|
||||
|
||||
assert!(attachment.is_image());
|
||||
assert!(attachment.is_media());
|
||||
assert_eq!(attachment.filename, Some("photo.jpg".to_string()));
|
||||
assert_eq!(attachment.size, Some(1024));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suggestion_from_string() {
|
||||
let suggestion: Suggestion = "Click here".into();
|
||||
assert_eq!(suggestion.text, "Click here");
|
||||
assert!(suggestion.context.is_none());
|
||||
}
|
||||
}
|
||||
201
src/resilience.rs
Normal file
201
src/resilience.rs
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
//! Resilience Module - Production-grade fault tolerance primitives
|
||||
//!
|
||||
//! This module provides battle-tested resilience patterns:
|
||||
//! - Retry with exponential backoff and jitter
|
||||
//! - Circuit breaker with half-open state
|
||||
//! - Timeout wrappers
|
||||
//! - Bulkhead isolation
|
||||
//! - Fallback chains
|
||||
//!
|
||||
//! # Design Principles
|
||||
//! - Zero-cost abstractions where possible
|
||||
//! - No panics - all errors are recoverable
|
||||
//! - Composable patterns
|
||||
//! - Observable state for metrics
|
||||
|
||||
use std::future::Future;
|
||||
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::{RwLock, Semaphore, SemaphorePermit};
|
||||
use tokio::time::{sleep, timeout};
|
||||
|
||||
/// Errors that can occur during resilient operations
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ResilienceError {
|
||||
/// Operation timed out
|
||||
Timeout { duration: Duration },
|
||||
/// Circuit breaker is open, rejecting requests
|
||||
CircuitOpen { until: Option<Duration> },
|
||||
/// All retry attempts exhausted
|
||||
RetriesExhausted {
|
||||
attempts: u32,
|
||||
last_error: String,
|
||||
},
|
||||
/// Bulkhead rejected request (too many concurrent)
|
||||
BulkheadFull { max_concurrent: usize },
|
||||
/// Wrapped error from the underlying operation
|
||||
Operation(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ResilienceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Timeout { duration } => {
|
||||
write!(f, "Operation timed out after {:?}", duration)
|
||||
}
|
||||
Self::CircuitOpen { until } => {
|
||||
if let Some(d) = until {
|
||||
write!(f, "Circuit breaker open, retry after {:?}", d)
|
||||
} else {
|
||||
write!(f, "Circuit breaker open")
|
||||
}
|
||||
}
|
||||
Self::RetriesExhausted {
|
||||
attempts,
|
||||
last_error,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"All {} retry attempts exhausted. Last error: {}",
|
||||
attempts, last_error
|
||||
)
|
||||
}
|
||||
Self::BulkheadFull { max_concurrent } => {
|
||||
write!(
|
||||
f,
|
||||
"Bulkhead full, max {} concurrent requests",
|
||||
max_concurrent
|
||||
)
|
||||
}
|
||||
Self::Operation(msg) => write!(f, "Operation failed: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ResilienceError {}
|
||||
|
||||
// ============================================================================
|
||||
// Retry Configuration and Execution
|
||||
// ============================================================================
|
||||
|
||||
/// Retry strategy configuration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RetryConfig {
|
||||
/// Maximum number of attempts (including the first one)
|
||||
pub max_attempts: u32,
|
||||
/// Initial delay between retries
|
||||
pub initial_delay: Duration,
|
||||
/// Maximum delay between retries
|
||||
pub max_delay: Duration,
|
||||
/// Multiplier for exponential backoff (typically 2.0)
|
||||
pub backoff_multiplier: f64,
|
||||
/// Add random jitter to prevent thundering herd (0.0 to 1.0)
|
||||
pub jitter_factor: f64,
|
||||
/// Predicate to determine if error is retryable
|
||||
retryable: Option<Arc<dyn Fn(&str) -> bool + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl Default for RetryConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_attempts: 3,
|
||||
initial_delay: Duration::from_millis(100),
|
||||
max_delay: Duration::from_secs(30),
|
||||
backoff_multiplier: 2.0,
|
||||
jitter_factor: 0.2,
|
||||
retryable: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RetryConfig {
|
||||
/// Create a new retry config with custom max attempts
|
||||
pub fn with_max_attempts(mut self, attempts: u32) -> Self {
|
||||
self.max_attempts = attempts.max(1);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set initial delay
|
||||
pub fn with_initial_delay(mut self, delay: Duration) -> Self {
|
||||
self.initial_delay = delay;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set maximum delay cap
|
||||
pub fn with_max_delay(mut self, delay: Duration) -> Self {
|
||||
self.max_delay = delay;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set backoff multiplier
|
||||
pub fn with_backoff_multiplier(mut self, multiplier: f64) -> Self {
|
||||
self.backoff_multiplier = multiplier.max(1.0);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set jitter factor (0.0 to 1.0)
|
||||
pub fn with_jitter(mut self, jitter: f64) -> Self {
|
||||
self.jitter_factor = jitter.clamp(0.0, 1.0);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set custom retryable predicate
|
||||
pub fn with_retryable<F>(mut self, predicate: F) -> Self
|
||||
where
|
||||
F: Fn(&str) -> bool + Send + Sync + 'static,
|
||||
{
|
||||
self.retryable = Some(Arc::new(predicate));
|
||||
self
|
||||
}
|
||||
|
||||
/// Aggressive retry for critical operations
|
||||
pub fn aggressive() -> Self {
|
||||
Self {
|
||||
max_attempts: 5,
|
||||
initial_delay: Duration::from_millis(50),
|
||||
max_delay: Duration::from_secs(10),
|
||||
backoff_multiplier: 1.5,
|
||||
jitter_factor: 0.3,
|
||||
retryable: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Conservative retry for non-critical operations
|
||||
pub fn conservative() -> Self {
|
||||
Self {
|
||||
max_attempts: 2,
|
||||
initial_delay: Duration::from_millis(500),
|
||||
max_delay: Duration::from_secs(5),
|
||||
backoff_multiplier: 2.0,
|
||||
jitter_factor: 0.1,
|
||||
retryable: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate delay for a given attempt number
|
||||
fn calculate_delay(&self, attempt: u32) -> Duration {
|
||||
let base_delay = self.initial_delay.as_secs_f64()
|
||||
* self.backoff_multiplier.powi(attempt.saturating_sub(1) as i32);
|
||||
|
||||
let capped_delay = base_delay.min(self.max_delay.as_secs_f64());
|
||||
|
||||
// Add jitter
|
||||
let jitter = if self.jitter_factor > 0.0 {
|
||||
let jitter_range = capped_delay * self.jitter_factor;
|
||||
// Simple deterministic "random" based on attempt number
|
||||
let pseudo_random = ((attempt as f64 * 1.618033988749895) % 1.0) * 2.0 - 1.0;
|
||||
jitter_range * pseudo_random
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
Duration::from_secs_f64((capped_delay + jitter).max(0.001))
|
||||
}
|
||||
|
||||
/// Check if an error is retryable
|
||||
fn is_retryable(&self, error: &str) -> bool {
|
||||
if let Some(ref predicate) = self.retryable {
|
||||
predicate(error)
|
||||
} else {
|
||||
//
|
||||
346
src/version.rs
Normal file
346
src/version.rs
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
//! Version Tracking Module
|
||||
//!
|
||||
//! Tracks versions of all components and checks for updates.
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::RwLock;
|
||||
|
||||
/// Global version registry
|
||||
static VERSION_REGISTRY: RwLock<Option<VersionRegistry>> = RwLock::new(None);
|
||||
|
||||
/// Current botserver version from Cargo.toml
|
||||
pub const BOTSERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
pub const BOTSERVER_NAME: &str = env!("CARGO_PKG_NAME");
|
||||
|
||||
/// Component version information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ComponentVersion {
|
||||
/// Component name
|
||||
pub name: String,
|
||||
/// Current installed version
|
||||
pub version: String,
|
||||
/// Latest available version (if known)
|
||||
pub latest_version: Option<String>,
|
||||
/// Whether an update is available
|
||||
pub update_available: bool,
|
||||
/// Component status
|
||||
pub status: ComponentStatus,
|
||||
/// Last check time
|
||||
pub last_checked: Option<DateTime<Utc>>,
|
||||
/// Source/origin of the component
|
||||
pub source: ComponentSource,
|
||||
/// Additional metadata
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
/// Component status
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum ComponentStatus {
|
||||
Running,
|
||||
Stopped,
|
||||
Error,
|
||||
Updating,
|
||||
NotInstalled,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ComponentStatus {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ComponentStatus::Running => write!(f, "[OK] Running"),
|
||||
ComponentStatus::Stopped => write!(f, "[STOP] Stopped"),
|
||||
ComponentStatus::Error => write!(f, "[ERR] Error"),
|
||||
ComponentStatus::Updating => write!(f, "[UPD] Updating"),
|
||||
ComponentStatus::NotInstalled => write!(f, "[--] Not Installed"),
|
||||
ComponentStatus::Unknown => write!(f, "[?] Unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Component source type
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum ComponentSource {
|
||||
Builtin,
|
||||
Docker,
|
||||
Lxc,
|
||||
System,
|
||||
Binary,
|
||||
External,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ComponentSource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ComponentSource::Builtin => write!(f, "Built-in"),
|
||||
ComponentSource::Docker => write!(f, "Docker"),
|
||||
ComponentSource::Lxc => write!(f, "LXC"),
|
||||
ComponentSource::System => write!(f, "System"),
|
||||
ComponentSource::Binary => write!(f, "Binary"),
|
||||
ComponentSource::External => write!(f, "External"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Version registry holding all component versions
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VersionRegistry {
|
||||
pub core_version: String,
|
||||
pub components: HashMap<String, ComponentVersion>,
|
||||
pub last_update_check: Option<DateTime<Utc>>,
|
||||
pub update_url: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for VersionRegistry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
core_version: BOTSERVER_VERSION.to_string(),
|
||||
components: HashMap::new(),
|
||||
last_update_check: None,
|
||||
update_url: Some("https://api.generalbots.com/updates".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VersionRegistry {
|
||||
/// Create a new version registry
|
||||
pub fn new() -> Self {
|
||||
let mut registry = Self::default();
|
||||
registry.register_builtin_components();
|
||||
registry
|
||||
}
|
||||
|
||||
/// Register built-in components
|
||||
fn register_builtin_components(&mut self) {
|
||||
self.register_component(ComponentVersion {
|
||||
name: "botserver".to_string(),
|
||||
version: BOTSERVER_VERSION.to_string(),
|
||||
latest_version: None,
|
||||
update_available: false,
|
||||
status: ComponentStatus::Running,
|
||||
last_checked: Some(Utc::now()),
|
||||
source: ComponentSource::Builtin,
|
||||
metadata: HashMap::from([
|
||||
("description".to_string(), "Core bot server".to_string()),
|
||||
(
|
||||
"repo".to_string(),
|
||||
"https://github.com/GeneralBots/botserver".to_string(),
|
||||
),
|
||||
]),
|
||||
});
|
||||
|
||||
self.register_component(ComponentVersion {
|
||||
name: "basic".to_string(),
|
||||
version: BOTSERVER_VERSION.to_string(),
|
||||
latest_version: None,
|
||||
update_available: false,
|
||||
status: ComponentStatus::Running,
|
||||
last_checked: Some(Utc::now()),
|
||||
source: ComponentSource::Builtin,
|
||||
metadata: HashMap::from([(
|
||||
"description".to_string(),
|
||||
"BASIC script interpreter".to_string(),
|
||||
)]),
|
||||
});
|
||||
|
||||
self.register_component(ComponentVersion {
|
||||
name: "llm".to_string(),
|
||||
version: BOTSERVER_VERSION.to_string(),
|
||||
latest_version: None,
|
||||
update_available: false,
|
||||
status: ComponentStatus::Running,
|
||||
last_checked: Some(Utc::now()),
|
||||
source: ComponentSource::Builtin,
|
||||
metadata: HashMap::from([(
|
||||
"description".to_string(),
|
||||
"LLM integration (Claude, GPT, etc.)".to_string(),
|
||||
)]),
|
||||
});
|
||||
}
|
||||
|
||||
/// Register a component
|
||||
pub fn register_component(&mut self, component: ComponentVersion) {
|
||||
debug!(
|
||||
"Registered component: {} v{}",
|
||||
component.name, component.version
|
||||
);
|
||||
self.components.insert(component.name.clone(), component);
|
||||
}
|
||||
|
||||
/// Update component status
|
||||
pub fn update_status(&mut self, name: &str, status: ComponentStatus) {
|
||||
if let Some(component) = self.components.get_mut(name) {
|
||||
component.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
/// Update component version
|
||||
pub fn update_version(&mut self, name: &str, version: String) {
|
||||
if let Some(component) = self.components.get_mut(name) {
|
||||
component.version = version;
|
||||
component.last_checked = Some(Utc::now());
|
||||
}
|
||||
}
|
||||
|
||||
/// Get component by name
|
||||
pub fn get_component(&self, name: &str) -> Option<&ComponentVersion> {
|
||||
self.components.get(name)
|
||||
}
|
||||
|
||||
/// Get all components
|
||||
pub fn get_all_components(&self) -> &HashMap<String, ComponentVersion> {
|
||||
&self.components
|
||||
}
|
||||
|
||||
/// Get components with available updates
|
||||
pub fn get_available_updates(&self) -> Vec<&ComponentVersion> {
|
||||
self.components
|
||||
.values()
|
||||
.filter(|c| c.update_available)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get summary of all components
|
||||
pub fn summary(&self) -> String {
|
||||
let running = self
|
||||
.components
|
||||
.values()
|
||||
.filter(|c| c.status == ComponentStatus::Running)
|
||||
.count();
|
||||
let total = self.components.len();
|
||||
let updates = self.get_available_updates().len();
|
||||
|
||||
format!(
|
||||
"{} v{} | {}/{} components running | {} updates available",
|
||||
BOTSERVER_NAME, self.core_version, running, total, updates
|
||||
)
|
||||
}
|
||||
|
||||
/// Get summary as JSON
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
serde_json::to_string_pretty(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Global Access Functions
|
||||
|
||||
/// Initialize version registry at startup
|
||||
pub fn init_version_registry() {
|
||||
let registry = VersionRegistry::new();
|
||||
if let Ok(mut guard) = VERSION_REGISTRY.write() {
|
||||
*guard = Some(registry);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get version registry (read-only)
|
||||
pub fn version_registry() -> Option<VersionRegistry> {
|
||||
VERSION_REGISTRY.read().ok()?.clone()
|
||||
}
|
||||
|
||||
/// Get mutable version registry
|
||||
pub fn version_registry_mut(
|
||||
) -> Option<std::sync::RwLockWriteGuard<'static, Option<VersionRegistry>>> {
|
||||
VERSION_REGISTRY.write().ok()
|
||||
}
|
||||
|
||||
/// Register a component
|
||||
pub fn register_component(component: ComponentVersion) {
|
||||
if let Ok(mut guard) = VERSION_REGISTRY.write() {
|
||||
if let Some(ref mut registry) = *guard {
|
||||
registry.register_component(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Update component status
|
||||
pub fn update_component_status(name: &str, status: ComponentStatus) {
|
||||
if let Ok(mut guard) = VERSION_REGISTRY.write() {
|
||||
if let Some(ref mut registry) = *guard {
|
||||
registry.update_status(name, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get component version
|
||||
pub fn get_component_version(name: &str) -> Option<ComponentVersion> {
|
||||
VERSION_REGISTRY
|
||||
.read()
|
||||
.ok()?
|
||||
.as_ref()?
|
||||
.get_component(name)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// Get botserver version
|
||||
pub fn get_botserver_version() -> &'static str {
|
||||
BOTSERVER_VERSION
|
||||
}
|
||||
|
||||
/// Get version string for display
|
||||
pub fn version_string() -> String {
|
||||
format!("{} v{}", BOTSERVER_NAME, BOTSERVER_VERSION)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_registry_creation() {
|
||||
let registry = VersionRegistry::new();
|
||||
assert!(!registry.core_version.is_empty());
|
||||
assert!(registry.components.contains_key("botserver"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_component_registration() {
|
||||
let mut registry = VersionRegistry::new();
|
||||
registry.register_component(ComponentVersion {
|
||||
name: "test".to_string(),
|
||||
version: "1.0.0".to_string(),
|
||||
latest_version: None,
|
||||
update_available: false,
|
||||
status: ComponentStatus::Running,
|
||||
last_checked: None,
|
||||
source: ComponentSource::Builtin,
|
||||
metadata: HashMap::new(),
|
||||
});
|
||||
assert!(registry.get_component("test").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_display() {
|
||||
assert_eq!(ComponentStatus::Running.to_string(), "[OK] Running");
|
||||
assert_eq!(ComponentStatus::Error.to_string(), "[ERR] Error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_string() {
|
||||
let vs = version_string();
|
||||
assert!(!vs.is_empty());
|
||||
assert!(vs.contains('v'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_source_display() {
|
||||
assert_eq!(ComponentSource::Builtin.to_string(), "Built-in");
|
||||
assert_eq!(ComponentSource::Docker.to_string(), "Docker");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_status() {
|
||||
let mut registry = VersionRegistry::new();
|
||||
registry.update_status("botserver", ComponentStatus::Stopped);
|
||||
let component = registry.get_component("botserver").unwrap();
|
||||
assert_eq!(component.status, ComponentStatus::Stopped);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_summary() {
|
||||
let registry = VersionRegistry::new();
|
||||
let summary = registry.summary();
|
||||
assert!(summary.contains("components running"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": false,
|
||||
"baseUrl": "./",
|
||||
"declaration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"mapRoot": "./dist/",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"paths": {
|
||||
"pragmatismo-io-framework/*": [
|
||||
"node_modules/pragmatismo-io-framework/*"
|
||||
]
|
||||
},
|
||||
"sourceMap": true,
|
||||
"target": "es6",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"test/**/*",
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
16
typedoc.json
16
typedoc.json
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"mode": "modules",
|
||||
"out": "docs",
|
||||
"name": "General Bots® Open Core",
|
||||
"theme": "default",
|
||||
"ignoreCompilerErrors": "true",
|
||||
"experimentalDecorators": "true",
|
||||
"emitDecoratorMetadata": "true",
|
||||
"target": "ES6",
|
||||
"moduleResolution": "node",
|
||||
"preserveConstEnums": "true",
|
||||
"stripInternal": "true",
|
||||
"suppressExcessPropertyErrors": "true",
|
||||
"suppressImplicitAnyIndexErrors": "true",
|
||||
"module": "commonjs"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue