Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11cbf327f0 |
@@ -93,8 +93,8 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p ~/tmp
|
||||
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar > ~/tmp/openapi-generator-cli-7.19.0.jar
|
||||
java -jar ~/tmp/openapi-generator-cli-7.19.0.jar validate -i swagger/swagger.json
|
||||
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar
|
||||
java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json
|
||||
|
||||
# Bundle audit
|
||||
- run:
|
||||
|
||||
@@ -103,5 +103,4 @@ CLAUDE.local.md
|
||||
.histoire
|
||||
.pnpm-store/*
|
||||
local/
|
||||
sw.js
|
||||
Procfile.worktree
|
||||
|
||||
@@ -268,7 +268,6 @@ group :development, :test do
|
||||
gem 'seed_dump'
|
||||
gem 'shoulda-matchers'
|
||||
gem 'simplecov', '>= 0.21', require: false
|
||||
gem 'skooma'
|
||||
gem 'spring'
|
||||
gem 'spring-watcher-listen'
|
||||
end
|
||||
|
||||
@@ -473,12 +473,6 @@ GEM
|
||||
hana (~> 1.3)
|
||||
regexp_parser (~> 2.0)
|
||||
uri_template (~> 0.7)
|
||||
json_skooma (0.2.5)
|
||||
bigdecimal
|
||||
hana (~> 1.3)
|
||||
regexp_parser (~> 2.0)
|
||||
uri-idna (~> 0.2)
|
||||
zeitwerk (~> 2.6)
|
||||
judoscale-rails (1.8.2)
|
||||
judoscale-ruby (= 1.8.2)
|
||||
railties
|
||||
@@ -916,9 +910,6 @@ GEM
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.13.2)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
skooma (0.3.7)
|
||||
json_skooma (~> 0.2.5)
|
||||
zeitwerk (~> 2.6)
|
||||
slack-ruby-client (2.7.0)
|
||||
faraday (>= 2.0.1)
|
||||
faraday-mashify
|
||||
@@ -979,7 +970,6 @@ GEM
|
||||
unicode-emoji (4.0.4)
|
||||
uniform_notifier (1.17.0)
|
||||
uri (1.1.1)
|
||||
uri-idna (0.3.1)
|
||||
uri_template (0.7.0)
|
||||
valid_email2 (5.2.6)
|
||||
activemodel (>= 3.2)
|
||||
@@ -1153,7 +1143,6 @@ DEPENDENCIES
|
||||
sidekiq_alive
|
||||
simplecov (>= 0.21)
|
||||
simplecov_json_formatter
|
||||
skooma
|
||||
slack-ruby-client (~> 2.7.0)
|
||||
spring
|
||||
spring-watcher-listen
|
||||
|
||||
@@ -104,7 +104,7 @@ class ContactIdentifyAction
|
||||
# blank identifier or email will throw unique index error
|
||||
# TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded
|
||||
@contact.discard_invalid_attrs if discard_invalid_attrs
|
||||
@contact.save! if @contact.changed?
|
||||
@contact.save!
|
||||
enqueue_avatar_job
|
||||
end
|
||||
|
||||
|
||||
@@ -18,18 +18,10 @@ const newMessage = ref('');
|
||||
const isLoading = ref(false);
|
||||
|
||||
const formatMessagesForApi = () => {
|
||||
return messages.value.map(message => {
|
||||
const payload = {
|
||||
role: message.sender,
|
||||
content: message.content,
|
||||
};
|
||||
|
||||
if (message.sender === 'assistant' && message.agentName) {
|
||||
payload.agent_name = message.agentName;
|
||||
}
|
||||
|
||||
return payload;
|
||||
});
|
||||
return messages.value.map(message => ({
|
||||
role: message.sender,
|
||||
content: message.content,
|
||||
}));
|
||||
};
|
||||
|
||||
const resetConversation = () => {
|
||||
@@ -70,7 +62,6 @@ const sendMessage = async () => {
|
||||
messages.value.push({
|
||||
content: data.response,
|
||||
sender: 'assistant',
|
||||
agentName: data.agent_name,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -78,7 +78,7 @@ const onSend = () => {
|
||||
<div
|
||||
v-else-if="isGeneratingContent"
|
||||
key="loading-state"
|
||||
class="bg-n-iris-5 rounded min-h-[4.75rem] w-full mb-4 p-4 flex items-start"
|
||||
class="bg-n-iris-5 rounded min-h-16 w-full mb-4 p-4 flex items-start"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<CaptainLoader class="text-n-iris-10 size-4" />
|
||||
|
||||
@@ -162,8 +162,7 @@ export default {
|
||||
this.inReplyTo?.id &&
|
||||
!this.isPrivate &&
|
||||
this.inboxHasFeature(INBOX_FEATURES.REPLY_TO) &&
|
||||
!this.is360DialogWhatsAppChannel &&
|
||||
!this.copilot.isActive.value
|
||||
!this.is360DialogWhatsAppChannel
|
||||
);
|
||||
},
|
||||
showWhatsappTemplates() {
|
||||
@@ -1465,7 +1464,7 @@ export default {
|
||||
}
|
||||
|
||||
.reply-box__top {
|
||||
@apply relative py-0 px-3 -mt-px;
|
||||
@apply relative py-0 px-4 -mt-px;
|
||||
}
|
||||
|
||||
.emoji-dialog {
|
||||
|
||||
@@ -14,7 +14,7 @@ const emit = defineEmits(['dismiss']);
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="reply-editor bg-n-slate-9/10 rounded-md py-1 pl-2 pr-1 text-xs tracking-wide mt-2 flex items-center gap-1.5"
|
||||
class="reply-editor bg-n-slate-9/10 rounded-md py-1 pl-2 pr-1 text-xs tracking-wide mt-2 flex items-center gap-1.5 -mx-2"
|
||||
>
|
||||
<fluent-icon class="flex-shrink-0 icon" icon="arrow-reply" size="14" />
|
||||
<div class="flex-grow gap-1 mt-px text-xs truncate">
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('useAutomation', () => {
|
||||
});
|
||||
useMapGetter.mockImplementation(getter => {
|
||||
const getterMap = {
|
||||
'agents/getVerifiedAgents': agents,
|
||||
'agents/getAgents': agents,
|
||||
'campaigns/getAllCampaigns': campaigns,
|
||||
'contacts/getContacts': contacts,
|
||||
'inboxes/getInboxes': inboxes,
|
||||
|
||||
@@ -111,7 +111,7 @@ describe('useMacros', () => {
|
||||
useStoreGetters.mockReturnValue({
|
||||
'labels/getLabels': { value: mockLabels },
|
||||
'teams/getTeams': { value: mockTeams },
|
||||
'agents/getVerifiedAgents': { value: mockAgents },
|
||||
'agents/getAgents': { value: mockAgents },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -167,7 +167,7 @@ describe('useMacros', () => {
|
||||
useStoreGetters.mockReturnValue({
|
||||
'labels/getLabels': { value: [] },
|
||||
'teams/getTeams': { value: [] },
|
||||
'agents/getVerifiedAgents': { value: [] },
|
||||
'agents/getAgents': { value: [] },
|
||||
});
|
||||
|
||||
const { getMacroDropdownValues } = useMacros();
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
export default function useAutomationValues() {
|
||||
const getters = useStoreGetters();
|
||||
const { t } = useI18n();
|
||||
const agents = useMapGetter('agents/getVerifiedAgents');
|
||||
const agents = useMapGetter('agents/getAgents');
|
||||
const campaigns = useMapGetter('campaigns/getAllCampaigns');
|
||||
const contacts = useMapGetter('contacts/getContacts');
|
||||
const inboxes = useMapGetter('inboxes/getInboxes');
|
||||
|
||||
@@ -13,7 +13,7 @@ export const useMacros = () => {
|
||||
|
||||
const labels = computed(() => getters['labels/getLabels'].value);
|
||||
const teams = computed(() => getters['teams/getTeams'].value);
|
||||
const agents = computed(() => getters['agents/getVerifiedAgents'].value);
|
||||
const agents = computed(() => getters['agents/getAgents'].value);
|
||||
|
||||
/**
|
||||
* Get dropdown values based on the specified type
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
import NotificationSubscriptions from '../api/notificationSubscription';
|
||||
import auth from '../api/auth';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
@@ -15,26 +16,7 @@ export const verifyServiceWorkerExistence = (callback = () => {}) => {
|
||||
|
||||
navigator.serviceWorker
|
||||
.register('/sw.js')
|
||||
.then(registration => {
|
||||
// Check for updates on load
|
||||
registration.update();
|
||||
|
||||
// Listen for updates
|
||||
registration.addEventListener('updatefound', () => {
|
||||
const newWorker = registration.installing;
|
||||
newWorker.addEventListener('statechange', () => {
|
||||
if (
|
||||
newWorker.state === 'installed' &&
|
||||
navigator.serviceWorker.controller
|
||||
) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('New service worker available');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
callback(registration);
|
||||
})
|
||||
.then(registration => callback(registration))
|
||||
.catch(registrationError => {
|
||||
// eslint-disable-next-line
|
||||
console.log('SW registration failed: ', registrationError);
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { build } = require('vite');
|
||||
|
||||
const ROOT_DIR = process.cwd();
|
||||
const PATHS = {
|
||||
manifest: path.join(ROOT_DIR, 'public/vite/.vite/manifest.json'),
|
||||
swRuntime: path.join(__dirname, 'sw-runtime.js'),
|
||||
swRuntimeBuilt: path.join(ROOT_DIR, 'tmp/sw-build/sw-runtime.js'),
|
||||
pushHandlers: path.join(__dirname, 'push-handlers.js'),
|
||||
buildDir: path.join(ROOT_DIR, 'tmp/sw-build'),
|
||||
output: path.join(ROOT_DIR, 'public/sw.js'),
|
||||
};
|
||||
|
||||
const buildSWContent = (runtimeBundle, pushHandlers, assetCount) => `
|
||||
/* Service Worker for Chatwoot */
|
||||
/* Generated: ${new Date().toISOString()} */
|
||||
/* Precached assets: ${assetCount} */
|
||||
|
||||
${runtimeBundle}
|
||||
|
||||
${pushHandlers}
|
||||
`;
|
||||
|
||||
function generateAssetManifest() {
|
||||
const manifestPath = fs.existsSync(PATHS.manifest) ? PATHS.manifest : null;
|
||||
|
||||
if (!manifestPath) {
|
||||
console.warn(
|
||||
'⚠️ No Vite manifest found, skipping asset manifest generation'
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log(`📋 Reading manifest from: ${manifestPath}`);
|
||||
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
||||
const assets = [];
|
||||
const seen = new Set();
|
||||
|
||||
Object.entries(manifest).forEach(([, entry]) => {
|
||||
const file = entry.file;
|
||||
if (file && !seen.has(file)) {
|
||||
seen.add(file);
|
||||
if (file.endsWith('.js') || file.endsWith('.css')) {
|
||||
assets.push({ url: file, revision: null });
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.css) {
|
||||
entry.css.forEach(cssFile => {
|
||||
if (!seen.has(cssFile)) {
|
||||
seen.add(cssFile);
|
||||
assets.push({ url: cssFile, revision: null });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (entry.assets) {
|
||||
entry.assets.forEach(assetFile => {
|
||||
if (!seen.has(assetFile)) {
|
||||
seen.add(assetFile);
|
||||
assets.push({ url: assetFile, revision: null });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📦 Found ${assets.length} assets to precache`);
|
||||
return assets;
|
||||
}
|
||||
|
||||
async function buildServiceWorker() {
|
||||
console.log('🔨 Building service worker...');
|
||||
|
||||
let assetOrigin = process.env.ASSET_CDN_HOST || '';
|
||||
if (assetOrigin && !assetOrigin.startsWith('http')) {
|
||||
assetOrigin = `https://${assetOrigin}`;
|
||||
}
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const assetPath = '/vite/';
|
||||
|
||||
console.log(`📁 Root dir: ${ROOT_DIR}`);
|
||||
console.log(`🌐 Asset origin: ${assetOrigin || '(local)'}`);
|
||||
console.log(`🏭 Environment: ${isProduction ? 'production' : 'development'}`);
|
||||
|
||||
if (!isProduction) {
|
||||
console.log(
|
||||
'⚠️ Development mode: Using push notifications only (no caching)'
|
||||
);
|
||||
|
||||
const devServiceWorker = fs.readFileSync(PATHS.pushHandlers, 'utf8');
|
||||
|
||||
fs.writeFileSync(PATHS.output, devServiceWorker);
|
||||
|
||||
console.log('✅ Development service worker created at public/sw.js');
|
||||
return;
|
||||
}
|
||||
|
||||
const assetManifest = generateAssetManifest();
|
||||
|
||||
try {
|
||||
console.log('📦 Building service worker runtime...');
|
||||
|
||||
await build({
|
||||
configFile: false,
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: PATHS.swRuntime,
|
||||
formats: ['iife'],
|
||||
name: 'ServiceWorkerRuntime',
|
||||
fileName: () => 'sw-runtime.js',
|
||||
},
|
||||
outDir: PATHS.buildDir,
|
||||
emptyOutDir: true,
|
||||
minify: true,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
inlineDynamicImports: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
define: {
|
||||
__ASSET_ORIGIN__: JSON.stringify(assetOrigin),
|
||||
__ASSET_PATH__: JSON.stringify(assetPath),
|
||||
__ASSET_MANIFEST__: JSON.stringify(assetManifest),
|
||||
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
},
|
||||
logLevel: 'warn',
|
||||
});
|
||||
|
||||
console.log('✅ Service worker runtime built');
|
||||
|
||||
const runtimeBundle = fs.readFileSync(PATHS.swRuntimeBuilt, 'utf8');
|
||||
|
||||
const pushHandlers = fs.readFileSync(PATHS.pushHandlers, 'utf8');
|
||||
|
||||
const finalServiceWorker = buildSWContent(
|
||||
runtimeBundle,
|
||||
pushHandlers,
|
||||
assetManifest.length
|
||||
);
|
||||
|
||||
fs.writeFileSync(PATHS.output, finalServiceWorker);
|
||||
|
||||
console.log('✅ Service worker built successfully at public/sw.js');
|
||||
console.log(` - ${assetManifest.length} assets in precache manifest`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to build service worker:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
buildServiceWorker().catch(err => {
|
||||
console.error('❌ Unhandled error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,142 +0,0 @@
|
||||
/* eslint-disable no-restricted-globals, no-use-before-define, no-undef */
|
||||
|
||||
// Build-time injected values (replaced by Vite define at build time)
|
||||
const ASSET_ORIGIN = __ASSET_ORIGIN__;
|
||||
const ASSET_PATH = __ASSET_PATH__;
|
||||
const ASSET_MANIFEST = __ASSET_MANIFEST__;
|
||||
|
||||
const CACHE_NAME = 'chatwoot-assets-v1';
|
||||
|
||||
const EXCLUDED_PATHS = [
|
||||
'/api/',
|
||||
'/auth/',
|
||||
'/rails/',
|
||||
'/cable',
|
||||
'/sidekiq',
|
||||
'/super_admin',
|
||||
'/swagger',
|
||||
'/webhooks/',
|
||||
'/widget',
|
||||
'/survey/',
|
||||
'/__vite',
|
||||
'/sw.js',
|
||||
];
|
||||
|
||||
const BATCH_SIZE = 5;
|
||||
|
||||
const buildAssetListChunks = (arr, size) => {
|
||||
const result = [];
|
||||
for (let i = 0; i < arr.length; i += size) {
|
||||
result.push(arr.slice(i, i + size));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const prefetchBatch = async (cache, baseUrl, assets) => {
|
||||
const fetchAndCacheAsset = async asset => {
|
||||
const url = `${baseUrl}${asset.url}`;
|
||||
if (await cache.match(url)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (response.ok) {
|
||||
cache.put(url, response);
|
||||
}
|
||||
} catch {
|
||||
// Ignore prefetch failures
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all(assets.map(fetchAndCacheAsset));
|
||||
};
|
||||
|
||||
const cacheFirst = async request => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const cached = await cache.match(request);
|
||||
if (cached) return cached;
|
||||
|
||||
try {
|
||||
const response = await fetch(request);
|
||||
if (response.ok) {
|
||||
cache.put(request, response.clone());
|
||||
}
|
||||
return response;
|
||||
} catch (err) {
|
||||
const stale = await cache.match(request);
|
||||
if (stale) return stale;
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const prefetchAssets = async () => {
|
||||
if (!ASSET_MANIFEST?.length) return;
|
||||
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const baseUrl = ASSET_ORIGIN
|
||||
? `${ASSET_ORIGIN}${ASSET_PATH}`
|
||||
: `${self.location.origin}${ASSET_PATH}`;
|
||||
|
||||
const batches = buildAssetListChunks(ASSET_MANIFEST, BATCH_SIZE);
|
||||
await batches.reduce(
|
||||
(promise, batch) =>
|
||||
promise.then(() => prefetchBatch(cache, baseUrl, batch)),
|
||||
Promise.resolve()
|
||||
);
|
||||
};
|
||||
const cleanupStaleAssets = async () => {
|
||||
if (!ASSET_MANIFEST?.length) return;
|
||||
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const cachedRequests = await cache.keys();
|
||||
|
||||
const baseUrl = ASSET_ORIGIN
|
||||
? `${ASSET_ORIGIN}${ASSET_PATH}`
|
||||
: `${self.location.origin}${ASSET_PATH}`;
|
||||
|
||||
const validUrls = new Set(
|
||||
ASSET_MANIFEST.map(asset => `${baseUrl}${asset.url}`)
|
||||
);
|
||||
|
||||
const deletions = cachedRequests
|
||||
.filter(request => {
|
||||
const url = new URL(request.url);
|
||||
const isAssetPath = url.pathname.startsWith('/vite/assets/');
|
||||
return isAssetPath && !validUrls.has(request.url);
|
||||
})
|
||||
.map(request => cache.delete(request));
|
||||
|
||||
await Promise.all(deletions);
|
||||
};
|
||||
|
||||
self.addEventListener('install', () => self.skipWaiting());
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
Promise.all([cleanupStaleAssets(), prefetchAssets(), self.clients.claim()])
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
const { request } = event;
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (EXCLUDED_PATHS.some(path => url.pathname.startsWith(path))) return;
|
||||
|
||||
if (request.method !== 'GET') return;
|
||||
|
||||
const isAChatwootRequest =
|
||||
url.origin === self.location.origin ||
|
||||
(ASSET_ORIGIN && url.origin === ASSET_ORIGIN);
|
||||
|
||||
if (!isAChatwootRequest) return;
|
||||
|
||||
const isAnAsset =
|
||||
url.pathname.startsWith('/vite/') ||
|
||||
url.origin === ASSET_ORIGIN ||
|
||||
/\.(js|css|woff2?|ttf|otf|eot|svg|png)$/i.test(url.pathname);
|
||||
|
||||
if (isAnAsset) {
|
||||
event.respondWith(cacheFirst(request));
|
||||
}
|
||||
});
|
||||
@@ -143,7 +143,7 @@ class Conversation < ApplicationRecord
|
||||
end
|
||||
|
||||
def last_incoming_message
|
||||
messages.where(account_id: account_id)&.incoming&.last
|
||||
messages&.incoming&.last
|
||||
end
|
||||
|
||||
def toggle_status
|
||||
|
||||
@@ -125,7 +125,7 @@ class Message < ApplicationRecord
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :inbox
|
||||
belongs_to :conversation
|
||||
belongs_to :conversation, touch: true
|
||||
belongs_to :sender, polymorphic: true, optional: true
|
||||
|
||||
has_many :attachments, dependent: :destroy, autosave: true, before_add: :validate_attachments_limit
|
||||
@@ -429,7 +429,7 @@ class Message < ApplicationRecord
|
||||
|
||||
def set_conversation_activity
|
||||
# rubocop:disable Rails/SkipsModelValidations
|
||||
conversation.update_columns(last_activity_at: created_at, updated_at: Time.current)
|
||||
conversation.update_columns(last_activity_at: created_at)
|
||||
# rubocop:enable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
|
||||
@@ -47,9 +47,7 @@ class ActionService
|
||||
|
||||
@agent = @account.users.find_by(id: agent_ids)
|
||||
|
||||
return unless @agent.present? && @agent.confirmed?
|
||||
|
||||
@conversation.update!(assignee_id: @agent.id)
|
||||
@conversation.update!(assignee_id: @agent.id) if @agent.present?
|
||||
end
|
||||
|
||||
def remove_label(labels)
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
- name: assignment_v2
|
||||
display_name: Assignment V2
|
||||
enabled: false
|
||||
chatwoot_internal: true
|
||||
- name: twilio_content_templates
|
||||
display_name: Twilio Content Templates
|
||||
enabled: false
|
||||
|
||||
@@ -24,16 +24,10 @@ class Api::V1::Accounts::Captain::AssistantsController < Api::V1::Accounts::Base
|
||||
end
|
||||
|
||||
def playground
|
||||
response = if captain_v2_enabled?
|
||||
Captain::Assistant::AgentRunnerService.new(assistant: @assistant, source: 'playground').generate_response(
|
||||
message_history: playground_message_history
|
||||
)
|
||||
else
|
||||
Captain::Llm::AssistantChatService.new(assistant: @assistant, source: 'playground').generate_response(
|
||||
additional_message: playground_params[:message_content],
|
||||
message_history: message_history
|
||||
)
|
||||
end
|
||||
response = Captain::Llm::AssistantChatService.new(assistant: @assistant).generate_response(
|
||||
additional_message: params[:message_content],
|
||||
message_history: message_history
|
||||
)
|
||||
|
||||
render json: response
|
||||
end
|
||||
@@ -70,31 +64,10 @@ class Api::V1::Accounts::Captain::AssistantsController < Api::V1::Accounts::Base
|
||||
end
|
||||
|
||||
def playground_params
|
||||
params.require(:assistant).permit(:message_content, message_history: [:role, :content, :agent_name])
|
||||
params.require(:assistant).permit(:message_content, message_history: [:role, :content])
|
||||
end
|
||||
|
||||
def message_history
|
||||
(playground_params[:message_history] || []).map do |message|
|
||||
{
|
||||
role: message[:role],
|
||||
content: message[:content],
|
||||
agent_name: message[:agent_name]
|
||||
}.compact
|
||||
end
|
||||
end
|
||||
|
||||
def playground_message_history
|
||||
history = message_history
|
||||
current_message = playground_params[:message_content]
|
||||
return history if current_message.blank?
|
||||
|
||||
current_user_message = { role: 'user', content: current_message }
|
||||
return history if history.last == current_user_message
|
||||
|
||||
history + [current_user_message]
|
||||
end
|
||||
|
||||
def captain_v2_enabled?
|
||||
@assistant.account.feature_enabled?('captain_integration_v2')
|
||||
(playground_params[:message_history] || []).map { |message| { role: message[:role], content: message[:content] } }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ module Captain::ChatHelper
|
||||
|
||||
def request_chat_completion
|
||||
log_chat_completion_request
|
||||
|
||||
chat = build_chat
|
||||
|
||||
add_messages_to_chat(chat)
|
||||
@@ -85,8 +86,7 @@ module Captain::ChatHelper
|
||||
temperature: temperature,
|
||||
metadata: {
|
||||
assistant_id: @assistant&.id,
|
||||
channel_type: resolved_channel_type,
|
||||
source: @source
|
||||
channel_type: resolved_channel_type
|
||||
}.compact
|
||||
}
|
||||
end
|
||||
@@ -130,6 +130,7 @@ module Captain::ChatHelper
|
||||
end
|
||||
|
||||
def log_chat_completion_request
|
||||
Rails.logger.info("#{self.class.name} Assistant: #{@assistant.id}, requesting completion for #{@messages} with #{@tools&.length || 0} tools")
|
||||
Rails.logger.info("#{self.class.name} Assistant: #{@assistant.id}, Requesting chat completion " \
|
||||
"for messages #{@messages} with #{@tools&.length || 0} tools")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -106,7 +106,7 @@ class Captain::Assistant < ApplicationRecord
|
||||
scenarios: scenarios.enabled.map do |scenario|
|
||||
{
|
||||
title: scenario.title,
|
||||
key: scenario.handoff_key,
|
||||
key: scenario.title.parameterize.underscore,
|
||||
description: scenario.description
|
||||
}
|
||||
end,
|
||||
|
||||
@@ -24,19 +24,6 @@ class Captain::Scenario < ApplicationRecord
|
||||
include Concerns::CaptainToolsHelpers
|
||||
include Concerns::Agentable
|
||||
|
||||
# OpenAI enforces a 64-char limit on function names. The ai-agents gem
|
||||
# prepends "handoff_to_" (11 chars), so we keep a safety margin and cap
|
||||
# the full tool name to MAX_HANDOFF_TOOL_NAME_LENGTH (60 chars).
|
||||
# Format: "scenario_{id}_{slug}_agent" for persisted records (stable + readable),
|
||||
# and "scenario_draft_{slug}_agent" for unsaved records, with slug truncated
|
||||
# based on the available length budget.
|
||||
HANDOFF_TOOL_PREFIX = 'handoff_to_'.freeze
|
||||
HANDOFF_KEY_PREFIX = 'scenario'.freeze
|
||||
HANDOFF_KEY_SUFFIX = 'agent'.freeze
|
||||
MAX_HANDOFF_TOOL_NAME_LENGTH = 60
|
||||
MAX_AGENT_NAME_LENGTH = MAX_HANDOFF_TOOL_NAME_LENGTH - HANDOFF_TOOL_PREFIX.length
|
||||
MAX_HANDOFF_SLUG_LENGTH = 24
|
||||
|
||||
self.table_name = 'captain_scenarios'
|
||||
|
||||
belongs_to :assistant, class_name: 'Captain::Assistant'
|
||||
@@ -55,10 +42,6 @@ class Captain::Scenario < ApplicationRecord
|
||||
|
||||
before_save :resolve_tool_references
|
||||
|
||||
def handoff_key
|
||||
[handoff_id_key, compact_handoff_slug, HANDOFF_KEY_SUFFIX].compact.join('_')
|
||||
end
|
||||
|
||||
def prompt_context
|
||||
{
|
||||
title: title,
|
||||
@@ -73,28 +56,7 @@ class Captain::Scenario < ApplicationRecord
|
||||
private
|
||||
|
||||
def agent_name
|
||||
handoff_key
|
||||
end
|
||||
|
||||
def handoff_id_key
|
||||
return "#{HANDOFF_KEY_PREFIX}_#{id}" if id.present?
|
||||
|
||||
"#{HANDOFF_KEY_PREFIX}_draft"
|
||||
end
|
||||
|
||||
def compact_handoff_slug
|
||||
slug = title.to_s.parameterize(separator: '_').presence
|
||||
return nil if slug.blank?
|
||||
|
||||
max_slug_length = [MAX_HANDOFF_SLUG_LENGTH, dynamic_slug_max_length].min
|
||||
return nil if max_slug_length <= 0
|
||||
|
||||
slug.first(max_slug_length).sub(/_+\z/, '').presence
|
||||
end
|
||||
|
||||
def dynamic_slug_max_length
|
||||
# handoff_to_#{scenario_<id>_<slug>_agent}
|
||||
MAX_AGENT_NAME_LENGTH - handoff_id_key.length - HANDOFF_KEY_SUFFIX.length - 2
|
||||
"#{title} Agent".parameterize(separator: '_')
|
||||
end
|
||||
|
||||
def agent_tools
|
||||
|
||||
@@ -19,11 +19,11 @@ class Captain::Assistant::AgentRunnerService
|
||||
CONTACT_INBOX_STATE_ATTRIBUTES = %i[id hmac_verified].freeze
|
||||
|
||||
CAMPAIGN_STATE_ATTRIBUTES = %i[id title message campaign_type description].freeze
|
||||
def initialize(assistant:, conversation: nil, callbacks: {}, source: nil)
|
||||
|
||||
def initialize(assistant:, conversation: nil, callbacks: {})
|
||||
@assistant = assistant
|
||||
@conversation = conversation
|
||||
@callbacks = callbacks
|
||||
@source = source
|
||||
end
|
||||
|
||||
def generate_response(message_history: [])
|
||||
@@ -32,7 +32,8 @@ class Captain::Assistant::AgentRunnerService
|
||||
|
||||
process_agent_result(result)
|
||||
rescue StandardError => e
|
||||
# In rake/local runs, conversation may not be present, so account is optional here.
|
||||
# when running the agent runner service in a rake task, the conversation might not have an account associated
|
||||
# for regular production usage, it will run just fine
|
||||
ChatwootExceptionTracker.new(e, account: @conversation&.account).capture_exception
|
||||
Rails.logger.error "[Captain V2] AgentRunnerService error: #{e.message}"
|
||||
Rails.logger.error e.backtrace.join("\n")
|
||||
@@ -127,7 +128,6 @@ class Captain::Assistant::AgentRunnerService
|
||||
assistant_id: @assistant.id,
|
||||
assistant_config: @assistant.config
|
||||
}
|
||||
state[:source] = @source if @source.present?
|
||||
|
||||
build_conversation_state(state) if @conversation
|
||||
state
|
||||
@@ -140,7 +140,8 @@ class Captain::Assistant::AgentRunnerService
|
||||
state[:campaign] = @conversation.campaign.attributes.symbolize_keys.slice(*CAMPAIGN_STATE_ATTRIBUTES) if @conversation.campaign
|
||||
return unless @conversation.contact_inbox
|
||||
|
||||
state[:contact_inbox] = @conversation.contact_inbox.attributes.symbolize_keys.slice(*CONTACT_INBOX_STATE_ATTRIBUTES)
|
||||
state[:contact_inbox] =
|
||||
@conversation.contact_inbox.attributes.symbolize_keys.slice(*CONTACT_INBOX_STATE_ATTRIBUTES)
|
||||
end
|
||||
|
||||
def build_and_wire_agents
|
||||
@@ -179,7 +180,6 @@ class Captain::Assistant::AgentRunnerService
|
||||
format(ATTR_LANGFUSE_METADATA, 'conversation_id') => conversation[:id],
|
||||
format(ATTR_LANGFUSE_METADATA, 'conversation_display_id') => conversation[:display_id],
|
||||
format(ATTR_LANGFUSE_METADATA, 'channel_type') => state[:channel_type],
|
||||
format(ATTR_LANGFUSE_METADATA, 'source') => state[:source],
|
||||
ATTR_LANGFUSE_TRACE_INPUT => trace_input,
|
||||
ATTR_LANGFUSE_OBSERVATION_INPUT => trace_input
|
||||
}.compact.transform_values(&:to_s)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
class Captain::Llm::AssistantChatService < Llm::BaseAiService
|
||||
include Captain::ChatHelper
|
||||
|
||||
def initialize(assistant: nil, conversation_id: nil, source: nil)
|
||||
def initialize(assistant: nil, conversation_id: nil)
|
||||
super()
|
||||
|
||||
@assistant = assistant
|
||||
@conversation_id = conversation_id
|
||||
@source = source
|
||||
|
||||
@messages = [system_message]
|
||||
@response = ''
|
||||
|
||||
@@ -8,12 +8,6 @@ task before_assets_precompile: :environment do
|
||||
system('echo "-------------- Bulding App for Production --------------"')
|
||||
end
|
||||
|
||||
task after_assets_precompile: :environment do
|
||||
# Build service worker after Vite has generated the asset manifest
|
||||
system('echo "-------------- Building Service Worker --------------"')
|
||||
system('NODE_ENV=production pnpm run build:sw')
|
||||
end
|
||||
|
||||
Rake::Task['assets:precompile'].enhance %w[before_assets_precompile] do
|
||||
Rake::Task['after_assets_precompile'].invoke
|
||||
end
|
||||
# every time you execute 'rake assets:precompile'
|
||||
# run 'before_assets_precompile' first
|
||||
Rake::Task['assets:precompile'].enhance %w[before_assets_precompile]
|
||||
|
||||
+9
-12
@@ -13,7 +13,6 @@
|
||||
"dev": "overmind start -f ./Procfile.dev",
|
||||
"ruby:prettier": "bundle exec rubocop -a",
|
||||
"build:sdk": "BUILD_MODE=library vite build",
|
||||
"build:sw": "node app/javascript/service-worker/build.js",
|
||||
"prepare": "husky install",
|
||||
"size": "size-limit",
|
||||
"story:dev": "histoire dev",
|
||||
@@ -37,8 +36,8 @@
|
||||
"@chatwoot/ninja-keys": "1.2.3",
|
||||
"@chatwoot/prosemirror-schema": "1.3.7",
|
||||
"@chatwoot/utils": "^0.0.52",
|
||||
"@formkit/core": "^1.7.2",
|
||||
"@formkit/vue": "^1.7.2",
|
||||
"@formkit/core": "^1.6.7",
|
||||
"@formkit/vue": "^1.6.7",
|
||||
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
||||
"@highlightjs/vue-plugin": "^2.1.0",
|
||||
"@iconify-json/fluent": "^1.2.32",
|
||||
@@ -50,7 +49,7 @@
|
||||
"@scmmishra/pico-search": "0.6.0",
|
||||
"@sentry/vue": "^8.55.0",
|
||||
"@sindresorhus/slugify": "2.2.1",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tanstack/vue-table": "^8.20.5",
|
||||
"@twilio/voice-sdk": "^2.12.4",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
@@ -60,7 +59,7 @@
|
||||
"@vueuse/components": "^12.0.0",
|
||||
"@vueuse/core": "^12.0.0",
|
||||
"activestorage": "^5.2.6",
|
||||
"axios": "^1.13.6",
|
||||
"axios": "^1.13.2",
|
||||
"camelcase-keys": "^9.1.3",
|
||||
"chart.js": "~4.4.4",
|
||||
"color2k": "^2.0.2",
|
||||
@@ -69,7 +68,7 @@
|
||||
"countries-and-timezones": "^3.6.0",
|
||||
"date-fns": "2.21.1",
|
||||
"date-fns-tz": "^1.3.3",
|
||||
"dompurify": "3.3.2",
|
||||
"dompurify": "3.2.4",
|
||||
"flag-icons": "^7.2.3",
|
||||
"floating-vue": "^5.2.2",
|
||||
"highlight.js": "^11.10.0",
|
||||
@@ -100,7 +99,7 @@
|
||||
"vue": "^3.5.12",
|
||||
"vue-chartjs": "5.3.1",
|
||||
"vue-datepicker-next": "^1.0.3",
|
||||
"vue-dompurify-html": "^5.3.0",
|
||||
"vue-dompurify-html": "^5.1.0",
|
||||
"vue-i18n": "9.14.5",
|
||||
"vue-letter": "^0.2.1",
|
||||
"vue-router": "~4.4.5",
|
||||
@@ -112,7 +111,7 @@
|
||||
"wavesurfer.js": "7.8.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@egoist/tailwindcss-icons": "^1.9.2",
|
||||
"@egoist/tailwindcss-icons": "^1.9.0",
|
||||
"@histoire/plugin-vue": "0.17.15",
|
||||
"@iconify-json/logos": "^1.2.10",
|
||||
"@iconify-json/lucide": "^1.2.82",
|
||||
@@ -143,7 +142,7 @@
|
||||
"prettier": "^3.3.3",
|
||||
"prosemirror-model": "^1.22.3",
|
||||
"size-limit": "^8.2.4",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"vite": "^5.4.21",
|
||||
"vite-plugin-ruby": "^5.0.0",
|
||||
"vitest": "3.0.5"
|
||||
@@ -161,9 +160,7 @@
|
||||
"overrides": {
|
||||
"vite-node": "2.0.1",
|
||||
"vite": "5.4.21",
|
||||
"vitest": "3.0.5",
|
||||
"minimatch@<4": "3.1.5",
|
||||
"minimatch@>=9.0.0 <9.0.7": "9.0.9"
|
||||
"vitest": "3.0.5"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
|
||||
Generated
+240
-152
@@ -8,8 +8,6 @@ overrides:
|
||||
vite-node: 2.0.1
|
||||
vite: 5.4.21
|
||||
vitest: 3.0.5
|
||||
minimatch@<4: 3.1.5
|
||||
minimatch@>=9.0.0 <9.0.7: 9.0.9
|
||||
|
||||
importers:
|
||||
|
||||
@@ -31,11 +29,11 @@ importers:
|
||||
specifier: ^0.0.52
|
||||
version: 0.0.52
|
||||
'@formkit/core':
|
||||
specifier: ^1.7.2
|
||||
version: 1.7.2
|
||||
specifier: ^1.6.7
|
||||
version: 1.6.7
|
||||
'@formkit/vue':
|
||||
specifier: ^1.7.2
|
||||
version: 1.7.2(vue@3.5.12(typescript@5.6.2))
|
||||
specifier: ^1.6.7
|
||||
version: 1.6.7(tailwindcss@3.4.13)(vue@3.5.12(typescript@5.6.2))
|
||||
'@hcaptcha/vue3-hcaptcha':
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0(vue@3.5.12(typescript@5.6.2))
|
||||
@@ -70,8 +68,8 @@ importers:
|
||||
specifier: 2.2.1
|
||||
version: 2.2.1
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.19
|
||||
version: 0.5.19(tailwindcss@3.4.19)
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.15(tailwindcss@3.4.13)
|
||||
'@tanstack/vue-table':
|
||||
specifier: ^8.20.5
|
||||
version: 8.20.5(vue@3.5.12(typescript@5.6.2))
|
||||
@@ -100,8 +98,8 @@ importers:
|
||||
specifier: ^5.2.6
|
||||
version: 5.2.8
|
||||
axios:
|
||||
specifier: ^1.13.6
|
||||
version: 1.13.6
|
||||
specifier: ^1.13.2
|
||||
version: 1.13.2
|
||||
camelcase-keys:
|
||||
specifier: ^9.1.3
|
||||
version: 9.1.3
|
||||
@@ -127,8 +125,8 @@ importers:
|
||||
specifier: ^1.3.3
|
||||
version: 1.3.8(date-fns@2.21.1)
|
||||
dompurify:
|
||||
specifier: 3.3.2
|
||||
version: 3.3.2
|
||||
specifier: 3.2.4
|
||||
version: 3.2.4
|
||||
flag-icons:
|
||||
specifier: ^7.2.3
|
||||
version: 7.2.3
|
||||
@@ -220,8 +218,8 @@ importers:
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3(vue@3.5.12(typescript@5.6.2))
|
||||
vue-dompurify-html:
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0(vue@3.5.12(typescript@5.6.2))
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(vue@3.5.12(typescript@5.6.2))
|
||||
vue-i18n:
|
||||
specifier: 9.14.5
|
||||
version: 9.14.5(vue@3.5.12(typescript@5.6.2))
|
||||
@@ -251,8 +249,8 @@ importers:
|
||||
version: 7.8.6
|
||||
devDependencies:
|
||||
'@egoist/tailwindcss-icons':
|
||||
specifier: ^1.9.2
|
||||
version: 1.9.2(tailwindcss@3.4.19)
|
||||
specifier: ^1.9.0
|
||||
version: 1.9.0(tailwindcss@3.4.13)
|
||||
'@histoire/plugin-vue':
|
||||
specifier: 0.17.15
|
||||
version: 0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))
|
||||
@@ -344,8 +342,8 @@ importers:
|
||||
specifier: ^8.2.4
|
||||
version: 8.2.6
|
||||
tailwindcss:
|
||||
specifier: ^3.4.19
|
||||
version: 3.4.19
|
||||
specifier: ^3.4.13
|
||||
version: 3.4.13
|
||||
vite:
|
||||
specifier: 5.4.21
|
||||
version: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
|
||||
@@ -404,6 +402,9 @@ packages:
|
||||
'@antfu/install-pkg@1.1.0':
|
||||
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
|
||||
|
||||
'@antfu/utils@8.1.1':
|
||||
resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==}
|
||||
|
||||
'@asamuzakjp/css-color@4.1.0':
|
||||
resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==}
|
||||
|
||||
@@ -699,8 +700,8 @@ packages:
|
||||
peerDependencies:
|
||||
postcss-selector-parser: ^6.0.10
|
||||
|
||||
'@egoist/tailwindcss-icons@1.9.2':
|
||||
resolution: {integrity: sha512-I6XsSykmhu2cASg5Hp/ICLsJ/K/1aXPaSKjgbWaNp2xYnb4We/arWMmkhhV+9CglOFCUbqx0A3mM2kWV32ZIhw==}
|
||||
'@egoist/tailwindcss-icons@1.9.0':
|
||||
resolution: {integrity: sha512-xWA9cUy6hzlK7Y6TaoRIcwmilSXiTJ8rbXcEdf9uht7yzDgw/yIgF4rThIQMrpD2Y2v4od51+r2y6Z7GStanDQ==}
|
||||
peerDependencies:
|
||||
tailwindcss: '*'
|
||||
|
||||
@@ -873,35 +874,46 @@ packages:
|
||||
'@floating-ui/utils@0.2.7':
|
||||
resolution: {integrity: sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==}
|
||||
|
||||
'@formkit/core@1.7.2':
|
||||
resolution: {integrity: sha512-XDRVqkDtOziU3z44hdvgWEqGpiv6nTNeCmP8cnESKkr24a4keQuEwmfDVvibYV0ywyTMg6ylp2lyklCYeRHykQ==}
|
||||
'@formkit/core@1.6.7':
|
||||
resolution: {integrity: sha512-wEoWK7crcCPRV5KJfEGLjjIS+qwbuD8I5Ur0zTtKRQrdO4oRL6kVoubxQOpgnq1l8sWfcRY8Wpf22Wna2LD20Q==}
|
||||
|
||||
'@formkit/dev@1.7.2':
|
||||
resolution: {integrity: sha512-W38xbbFS4h4LTV22kUC6ZbPHBmlM2lVbAz5PSYU3SPaNc4FeXp4GTe4GzLEmcS82B+5L1zbSOgGB43kWZts7wA==}
|
||||
'@formkit/dev@1.6.7':
|
||||
resolution: {integrity: sha512-mMtkfvfkl1P1v0haizUE4DadalbG9/3m0ZymmMKKb0F3pojQJFtdfohy67ZQKtmzy4bamowHyEUr+XzLbKY2EA==}
|
||||
|
||||
'@formkit/i18n@1.7.2':
|
||||
resolution: {integrity: sha512-Zs6f+rtP2j2Nnt1HkNrL85WU6rtS1l1Q0BAQjCMGQPsbrppiL7/TZ5bNIrVm0DTntLgG3firDS7bNWAxPSwerQ==}
|
||||
'@formkit/i18n@1.6.7':
|
||||
resolution: {integrity: sha512-i9Mnc2XHCm2c10fppEIxdGv+jqOaixO22iFXX3xF+AkJnxtOzV5hP4f3/TeG+BNahGUq8vj+e1y+VMnjS6duxA==}
|
||||
|
||||
'@formkit/inputs@1.7.2':
|
||||
resolution: {integrity: sha512-4xs7RJN8EFGctTCNRXBTvor2O8RvuEEK3q2Hl/RMU5lhhn5tmck90fkkeAr9o+rWRoSNiV8XgbLQArQ/B1IYPw==}
|
||||
'@formkit/inputs@1.6.7':
|
||||
resolution: {integrity: sha512-VLxoAJn5VGOEXkGI499lju5Irnu12cu+spI1HL//46nlVkqnb1XcV0k0MK9K+hogz4fGmyZUvHf0lxU6dh7ZZQ==}
|
||||
|
||||
'@formkit/observer@1.7.2':
|
||||
resolution: {integrity: sha512-KUr5mcu2SAeHOOK1FaMyFigtA8hkHLsUkaPFWpTC81j79o1AUjJppmfPaX6PbtlHLeMs2Zq8Qhp6VAhi7D2WJg==}
|
||||
'@formkit/observer@1.6.7':
|
||||
resolution: {integrity: sha512-ei5z5ernNMKKiBuoRcFgEthhP1i+KKb02hsPsikLA3XehuoJdWIejn9AAq6jOEGbUMZ5XAAgFJcxzO5tnKuPnw==}
|
||||
|
||||
'@formkit/rules@1.7.2':
|
||||
resolution: {integrity: sha512-2e5qKlXzmL9LAetncFp7xkHEX/UAJsU3bo1iL3idloH3HALf5fIdg3lgOKwCNDMdLjbfiKJ6lVwFaeFfFpcDKw==}
|
||||
'@formkit/rules@1.6.7':
|
||||
resolution: {integrity: sha512-adzOuTvf6ghZbV0g0ZH9+MU9jfoF4DojBztAbqzFP/fT4d+WxhSHHlkWq6PU66fHPy3OH4DkWdx9trL1wGHuzQ==}
|
||||
|
||||
'@formkit/themes@1.7.2':
|
||||
resolution: {integrity: sha512-AaZHy7l9D44Ya3cQRqZ8RIpaTTsCjTB1gX13NlpqYSs6yG0yBTmJ7L7kW60bOGdhs/vmIwSel578EBwz98nybQ==}
|
||||
'@formkit/themes@1.6.7':
|
||||
resolution: {integrity: sha512-TIiWr4TMAFUg1pQz2E4GErfAhBv2Q2VbWlk6pqXPWI8UyPTjmcinEnCSIWDCX6FPPqiYShBnh8123nTO7pyvjA==}
|
||||
peerDependencies:
|
||||
tailwindcss: ^3.2.0
|
||||
unocss: 0.x.x
|
||||
windicss: ^3.0.0
|
||||
peerDependenciesMeta:
|
||||
tailwindcss:
|
||||
optional: true
|
||||
unocss:
|
||||
optional: true
|
||||
windicss:
|
||||
optional: true
|
||||
|
||||
'@formkit/utils@1.7.2':
|
||||
resolution: {integrity: sha512-bBF6alUBOqFfJHjVB95Vck0hp36vlw4QfFJxGfTO6BX68AEaFzzzabtpwfy0DbcHtwHh4Yn7l/rOWGxXEve+QQ==}
|
||||
'@formkit/utils@1.6.7':
|
||||
resolution: {integrity: sha512-aU3CDLzCkC5Dnx6iS3swbsIbys7E+2VOaLWFRnS7wk7kFa8EnENi67qc2E2KFE05RT4UCEAIYMAQY6wvek29gA==}
|
||||
|
||||
'@formkit/validation@1.7.2':
|
||||
resolution: {integrity: sha512-JJsLP7AI/++VujdwtBeUcPhCqY3FXSKZ7hajT7Ow5Feab7JLqVPjxVMFbXDgEOLjq0ex1NX/I+EQHfm5sqMRsA==}
|
||||
'@formkit/validation@1.6.7':
|
||||
resolution: {integrity: sha512-4wUUG+Pz3hPeiLccYiXAzsrF7SXk28PYAeHJeBngIv9K82ieljBJpvvuCJDyA6SeSMOvmbI92TG4wx4u5cDLOw==}
|
||||
|
||||
'@formkit/vue@1.7.2':
|
||||
resolution: {integrity: sha512-jrvXl2ZhS6X5klTbP4N5zc0Dg37AjbAf8SCVoz7mfligVkmwrrF4SN3waMBcH+n9gqT+vrkOYb6bQXdvjUdnCQ==}
|
||||
'@formkit/vue@1.6.7':
|
||||
resolution: {integrity: sha512-w3kjQD0lvtImyyTiy+fLaIZM/4r6sLDbpBIwke8ZA/d5orzNE96JPaloVKbH+HwCo6+z/1mclh1pW1S+7RgMcw==}
|
||||
peerDependencies:
|
||||
vue: ^3.4.0
|
||||
|
||||
@@ -973,8 +985,8 @@ packages:
|
||||
'@iconify/types@2.0.0':
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
|
||||
'@iconify/utils@3.1.0':
|
||||
resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==}
|
||||
'@iconify/utils@2.3.0':
|
||||
resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==}
|
||||
|
||||
'@intlify/core-base@9.14.2':
|
||||
resolution: {integrity: sha512-DZyQ4Hk22sC81MP4qiCDuU+LdaYW91A6lCjq8AWPvY3+mGMzhGDfOCzvyR6YBQxtlPjFqMoFk9ylnNYRAQwXtQ==}
|
||||
@@ -1279,10 +1291,10 @@ packages:
|
||||
peerDependencies:
|
||||
size-limit: 8.2.6
|
||||
|
||||
'@tailwindcss/typography@0.5.19':
|
||||
resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
|
||||
'@tailwindcss/typography@0.5.15':
|
||||
resolution: {integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20'
|
||||
|
||||
'@tanstack/table-core@8.20.5':
|
||||
resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==}
|
||||
@@ -1567,8 +1579,8 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
acorn@8.16.0:
|
||||
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
|
||||
acorn@8.15.0:
|
||||
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1700,8 +1712,8 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
axios@1.13.6:
|
||||
resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==}
|
||||
axios@1.13.2:
|
||||
resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
@@ -1733,8 +1745,8 @@ packages:
|
||||
brace-expansion@1.1.11:
|
||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||
|
||||
brace-expansion@2.0.2:
|
||||
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
|
||||
brace-expansion@2.0.1:
|
||||
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
@@ -1910,6 +1922,9 @@ packages:
|
||||
confbox@0.1.8:
|
||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
||||
|
||||
confbox@0.2.2:
|
||||
resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
|
||||
|
||||
config-chain@1.1.13:
|
||||
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
||||
|
||||
@@ -2151,9 +2166,8 @@ packages:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
dompurify@3.3.2:
|
||||
resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==}
|
||||
engines: {node: '>=20'}
|
||||
dompurify@3.2.4:
|
||||
resolution: {integrity: sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==}
|
||||
|
||||
domutils@3.1.0:
|
||||
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
|
||||
@@ -2436,6 +2450,9 @@ packages:
|
||||
resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
exsolve@1.0.8:
|
||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2628,6 +2645,10 @@ packages:
|
||||
resolution: {integrity: sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
globals@15.15.0:
|
||||
resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
globalthis@1.0.3:
|
||||
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2775,8 +2796,8 @@ packages:
|
||||
resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
immutable@4.3.8:
|
||||
resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==}
|
||||
immutable@4.3.7:
|
||||
resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
@@ -2980,10 +3001,6 @@ packages:
|
||||
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
|
||||
hasBin: true
|
||||
|
||||
jiti@1.21.7:
|
||||
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
|
||||
hasBin: true
|
||||
|
||||
js-beautify@1.15.1:
|
||||
resolution: {integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -3060,6 +3077,9 @@ packages:
|
||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
kolorist@1.8.0:
|
||||
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
|
||||
|
||||
launch-editor@2.9.1:
|
||||
resolution: {integrity: sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==}
|
||||
|
||||
@@ -3077,8 +3097,8 @@ packages:
|
||||
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
lilconfig@3.1.3:
|
||||
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
||||
lilconfig@3.1.2:
|
||||
resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
lines-and-columns@1.2.4:
|
||||
@@ -3111,6 +3131,10 @@ packages:
|
||||
lit@2.2.6:
|
||||
resolution: {integrity: sha512-K2vkeGABfSJSfkhqHy86ujchJs3NR9nW1bEEiV+bXDkbiQ60Tv5GUausYN2mXigZn8lC1qXuc46ArQRKYmumZw==}
|
||||
|
||||
local-pkg@1.1.2:
|
||||
resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
locate-path@5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -3123,6 +3147,12 @@ packages:
|
||||
resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
lodash.castarray@4.4.0:
|
||||
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
|
||||
|
||||
lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
@@ -3257,11 +3287,15 @@ packages:
|
||||
min-document@2.19.0:
|
||||
resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
|
||||
|
||||
minimatch@3.1.5:
|
||||
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
|
||||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
minimatch@9.0.9:
|
||||
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
|
||||
minimatch@9.0.1:
|
||||
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minimist@1.2.8:
|
||||
@@ -3274,8 +3308,8 @@ packages:
|
||||
mitt@3.0.1:
|
||||
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||
|
||||
mlly@1.8.1:
|
||||
resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==}
|
||||
mlly@1.8.0:
|
||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||
|
||||
mpd-parser@0.21.0:
|
||||
resolution: {integrity: sha512-NbpMJ57qQzFmfCiP1pbL7cGMbVTD0X1hqNgL0VYP1wLlZXLf/HtmvQpNkOA1AHkPVeGQng+7/jEtSvNUzV7Gdg==}
|
||||
@@ -3572,6 +3606,9 @@ packages:
|
||||
pkg-types@1.3.1:
|
||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
||||
|
||||
pkg-types@2.3.0:
|
||||
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
|
||||
|
||||
pngjs@5.0.0:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@@ -3878,6 +3915,9 @@ packages:
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
|
||||
quansync@0.2.11:
|
||||
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
|
||||
|
||||
querystringify@2.2.0:
|
||||
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
||||
|
||||
@@ -4229,8 +4269,8 @@ packages:
|
||||
resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
tailwindcss@3.4.19:
|
||||
resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==}
|
||||
tailwindcss@3.4.13:
|
||||
resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -4392,8 +4432,8 @@ packages:
|
||||
uc.micro@2.1.0:
|
||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||
|
||||
ufo@1.6.3:
|
||||
resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
|
||||
ufo@1.6.1:
|
||||
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
|
||||
|
||||
unbox-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
||||
@@ -4582,10 +4622,10 @@ packages:
|
||||
'@vue/composition-api':
|
||||
optional: true
|
||||
|
||||
vue-dompurify-html@5.3.0:
|
||||
resolution: {integrity: sha512-HJQGBHbfSPcb6Mu97McdKbX7TqRHZa6Ji8OCpCNyuHca5QvQZ8IiuwghFPSO8OkSQfqXPNPKFMZdCOrnGGmOSQ==}
|
||||
vue-dompurify-html@5.1.0:
|
||||
resolution: {integrity: sha512-616o2/PBdOLM2bwlRWLdzeEC9NerLkwiudqNgaIJ5vBQWXec+u7Kuzh+45DtQQrids67s4pHnTnJZLVfyPMxbA==}
|
||||
peerDependencies:
|
||||
vue: ^3.4.36
|
||||
vue: ^3.0.0
|
||||
|
||||
vue-eslint-parser@9.4.3:
|
||||
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
|
||||
@@ -4904,6 +4944,8 @@ snapshots:
|
||||
package-manager-detector: 1.6.0
|
||||
tinyexec: 1.0.2
|
||||
|
||||
'@antfu/utils@8.1.1': {}
|
||||
|
||||
'@asamuzakjp/css-color@4.1.0':
|
||||
dependencies:
|
||||
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
|
||||
@@ -5220,10 +5262,12 @@ snapshots:
|
||||
dependencies:
|
||||
postcss-selector-parser: 6.1.1
|
||||
|
||||
'@egoist/tailwindcss-icons@1.9.2(tailwindcss@3.4.19)':
|
||||
'@egoist/tailwindcss-icons@1.9.0(tailwindcss@3.4.13)':
|
||||
dependencies:
|
||||
'@iconify/utils': 3.1.0
|
||||
tailwindcss: 3.4.19
|
||||
'@iconify/utils': 2.3.0
|
||||
tailwindcss: 3.4.13
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
optional: true
|
||||
@@ -5310,7 +5354,7 @@ snapshots:
|
||||
ignore: 5.2.4
|
||||
import-fresh: 3.3.0
|
||||
js-yaml: 4.1.0
|
||||
minimatch: 3.1.5
|
||||
minimatch: 3.1.2
|
||||
strip-json-comments: 3.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5324,7 +5368,7 @@ snapshots:
|
||||
ignore: 5.2.4
|
||||
import-fresh: 3.3.0
|
||||
js-yaml: 4.1.0
|
||||
minimatch: 3.1.5
|
||||
minimatch: 3.1.2
|
||||
strip-json-comments: 3.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5341,61 +5385,67 @@ snapshots:
|
||||
|
||||
'@floating-ui/utils@0.2.7': {}
|
||||
|
||||
'@formkit/core@1.7.2':
|
||||
'@formkit/core@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/utils': 1.6.7
|
||||
|
||||
'@formkit/dev@1.7.2':
|
||||
'@formkit/dev@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/utils': 1.6.7
|
||||
|
||||
'@formkit/i18n@1.7.2':
|
||||
'@formkit/i18n@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/validation': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/utils': 1.6.7
|
||||
'@formkit/validation': 1.6.7
|
||||
|
||||
'@formkit/inputs@1.7.2':
|
||||
'@formkit/inputs@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/utils': 1.6.7
|
||||
|
||||
'@formkit/observer@1.7.2':
|
||||
'@formkit/observer@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/utils': 1.6.7
|
||||
|
||||
'@formkit/rules@1.7.2':
|
||||
'@formkit/rules@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/validation': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/utils': 1.6.7
|
||||
'@formkit/validation': 1.6.7
|
||||
|
||||
'@formkit/themes@1.7.2':
|
||||
'@formkit/themes@1.6.7(tailwindcss@3.4.13)':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
optionalDependencies:
|
||||
tailwindcss: 3.4.13
|
||||
|
||||
'@formkit/utils@1.7.2': {}
|
||||
'@formkit/utils@1.6.7': {}
|
||||
|
||||
'@formkit/validation@1.7.2':
|
||||
'@formkit/validation@1.6.7':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/observer': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/observer': 1.6.7
|
||||
'@formkit/utils': 1.6.7
|
||||
|
||||
'@formkit/vue@1.7.2(vue@3.5.12(typescript@5.6.2))':
|
||||
'@formkit/vue@1.6.7(tailwindcss@3.4.13)(vue@3.5.12(typescript@5.6.2))':
|
||||
dependencies:
|
||||
'@formkit/core': 1.7.2
|
||||
'@formkit/dev': 1.7.2
|
||||
'@formkit/i18n': 1.7.2
|
||||
'@formkit/inputs': 1.7.2
|
||||
'@formkit/observer': 1.7.2
|
||||
'@formkit/rules': 1.7.2
|
||||
'@formkit/themes': 1.7.2
|
||||
'@formkit/utils': 1.7.2
|
||||
'@formkit/validation': 1.7.2
|
||||
'@formkit/core': 1.6.7
|
||||
'@formkit/dev': 1.6.7
|
||||
'@formkit/i18n': 1.6.7
|
||||
'@formkit/inputs': 1.6.7
|
||||
'@formkit/observer': 1.6.7
|
||||
'@formkit/rules': 1.6.7
|
||||
'@formkit/themes': 1.6.7(tailwindcss@3.4.13)
|
||||
'@formkit/utils': 1.6.7
|
||||
'@formkit/validation': 1.6.7
|
||||
vue: 3.5.12(typescript@5.6.2)
|
||||
transitivePeerDependencies:
|
||||
- tailwindcss
|
||||
- unocss
|
||||
- windicss
|
||||
|
||||
'@hcaptcha/vue3-hcaptcha@1.3.0(vue@3.5.12(typescript@5.6.2))':
|
||||
dependencies:
|
||||
@@ -5461,7 +5511,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
debug: 4.3.5
|
||||
minimatch: 3.1.5
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -5499,11 +5549,18 @@ snapshots:
|
||||
|
||||
'@iconify/types@2.0.0': {}
|
||||
|
||||
'@iconify/utils@3.1.0':
|
||||
'@iconify/utils@2.3.0':
|
||||
dependencies:
|
||||
'@antfu/install-pkg': 1.1.0
|
||||
'@antfu/utils': 8.1.1
|
||||
'@iconify/types': 2.0.0
|
||||
mlly: 1.8.1
|
||||
debug: 4.4.3
|
||||
globals: 15.15.0
|
||||
kolorist: 1.8.0
|
||||
local-pkg: 1.1.2
|
||||
mlly: 1.8.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@intlify/core-base@9.14.2':
|
||||
dependencies:
|
||||
@@ -5790,10 +5847,13 @@ snapshots:
|
||||
semver: 7.5.3
|
||||
size-limit: 8.2.6
|
||||
|
||||
'@tailwindcss/typography@0.5.19(tailwindcss@3.4.19)':
|
||||
'@tailwindcss/typography@0.5.15(tailwindcss@3.4.13)':
|
||||
dependencies:
|
||||
lodash.castarray: 4.4.0
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 3.4.19
|
||||
tailwindcss: 3.4.13
|
||||
|
||||
'@tanstack/table-core@8.20.5': {}
|
||||
|
||||
@@ -6170,7 +6230,7 @@ snapshots:
|
||||
|
||||
acorn@8.14.0: {}
|
||||
|
||||
acorn@8.16.0: {}
|
||||
acorn@8.15.0: {}
|
||||
|
||||
activestorage@5.2.8:
|
||||
dependencies:
|
||||
@@ -6331,7 +6391,7 @@ snapshots:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.0.0
|
||||
|
||||
axios@1.13.6:
|
||||
axios@1.13.2:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.11
|
||||
form-data: 4.0.5
|
||||
@@ -6371,7 +6431,7 @@ snapshots:
|
||||
balanced-match: 1.0.2
|
||||
concat-map: 0.0.1
|
||||
|
||||
brace-expansion@2.0.2:
|
||||
brace-expansion@2.0.1:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
@@ -6573,6 +6633,8 @@ snapshots:
|
||||
|
||||
confbox@0.1.8: {}
|
||||
|
||||
confbox@0.2.2: {}
|
||||
|
||||
config-chain@1.1.13:
|
||||
dependencies:
|
||||
ini: 1.3.8
|
||||
@@ -6788,7 +6850,7 @@ snapshots:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
|
||||
dompurify@3.3.2:
|
||||
dompurify@3.2.4:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
@@ -6815,7 +6877,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@one-ini/wasm': 0.1.1
|
||||
commander: 10.0.1
|
||||
minimatch: 9.0.9
|
||||
minimatch: 9.0.1
|
||||
semver: 7.6.3
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
@@ -7082,7 +7144,7 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
minimatch: 3.1.5
|
||||
minimatch: 3.1.2
|
||||
object.fromentries: 2.0.8
|
||||
object.groupby: 1.0.3
|
||||
object.values: 1.2.0
|
||||
@@ -7162,7 +7224,7 @@ snapshots:
|
||||
json-stable-stringify-without-jsonify: 1.0.1
|
||||
levn: 0.4.1
|
||||
lodash.merge: 4.6.2
|
||||
minimatch: 3.1.5
|
||||
minimatch: 3.1.2
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.3
|
||||
strip-ansi: 6.0.1
|
||||
@@ -7208,6 +7270,8 @@ snapshots:
|
||||
|
||||
expect-type@1.1.0: {}
|
||||
|
||||
exsolve@1.0.8: {}
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
dependencies:
|
||||
is-extendable: 0.1.1
|
||||
@@ -7392,7 +7456,7 @@ snapshots:
|
||||
dependencies:
|
||||
foreground-child: 3.3.0
|
||||
jackspeak: 3.4.3
|
||||
minimatch: 9.0.9
|
||||
minimatch: 9.0.5
|
||||
minipass: 7.1.2
|
||||
package-json-from-dist: 1.0.0
|
||||
path-scurry: 1.11.1
|
||||
@@ -7402,7 +7466,7 @@ snapshots:
|
||||
fs.realpath: 1.0.0
|
||||
inflight: 1.0.6
|
||||
inherits: 2.0.4
|
||||
minimatch: 3.1.5
|
||||
minimatch: 3.1.2
|
||||
once: 1.4.0
|
||||
path-is-absolute: 1.0.1
|
||||
|
||||
@@ -7423,6 +7487,8 @@ snapshots:
|
||||
|
||||
globals@15.14.0: {}
|
||||
|
||||
globals@15.15.0: {}
|
||||
|
||||
globalthis@1.0.3:
|
||||
dependencies:
|
||||
define-properties: 1.2.0
|
||||
@@ -7618,7 +7684,7 @@ snapshots:
|
||||
|
||||
ignore@6.0.2: {}
|
||||
|
||||
immutable@4.3.8:
|
||||
immutable@4.3.7:
|
||||
optional: true
|
||||
|
||||
import-fresh@3.3.0:
|
||||
@@ -7808,8 +7874,6 @@ snapshots:
|
||||
|
||||
jiti@1.21.6: {}
|
||||
|
||||
jiti@1.21.7: {}
|
||||
|
||||
js-beautify@1.15.1:
|
||||
dependencies:
|
||||
config-chain: 1.1.13
|
||||
@@ -7926,6 +7990,8 @@ snapshots:
|
||||
|
||||
kind-of@6.0.3: {}
|
||||
|
||||
kolorist@1.8.0: {}
|
||||
|
||||
launch-editor@2.9.1:
|
||||
dependencies:
|
||||
picocolors: 1.1.0
|
||||
@@ -7942,7 +8008,7 @@ snapshots:
|
||||
|
||||
lilconfig@2.1.0: {}
|
||||
|
||||
lilconfig@3.1.3: {}
|
||||
lilconfig@3.1.2: {}
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
@@ -7993,6 +8059,12 @@ snapshots:
|
||||
lit-element: 3.3.3
|
||||
lit-html: 2.8.0
|
||||
|
||||
local-pkg@1.1.2:
|
||||
dependencies:
|
||||
mlly: 1.8.0
|
||||
pkg-types: 2.3.0
|
||||
quansync: 0.2.11
|
||||
|
||||
locate-path@5.0.0:
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
@@ -8005,6 +8077,10 @@ snapshots:
|
||||
dependencies:
|
||||
p-locate: 6.0.0
|
||||
|
||||
lodash.castarray@4.4.0: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash.truncate@4.4.2: {}
|
||||
@@ -8141,13 +8217,17 @@ snapshots:
|
||||
dependencies:
|
||||
dom-walk: 0.1.2
|
||||
|
||||
minimatch@3.1.5:
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.11
|
||||
|
||||
minimatch@9.0.9:
|
||||
minimatch@9.0.1:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.2
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
@@ -8155,12 +8235,12 @@ snapshots:
|
||||
|
||||
mitt@3.0.1: {}
|
||||
|
||||
mlly@1.8.1:
|
||||
mlly@1.8.0:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
acorn: 8.15.0
|
||||
pathe: 2.0.3
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.3
|
||||
ufo: 1.6.1
|
||||
|
||||
mpd-parser@0.21.0:
|
||||
dependencies:
|
||||
@@ -8431,7 +8511,13 @@ snapshots:
|
||||
pkg-types@1.3.1:
|
||||
dependencies:
|
||||
confbox: 0.1.8
|
||||
mlly: 1.8.1
|
||||
mlly: 1.8.0
|
||||
pathe: 2.0.3
|
||||
|
||||
pkg-types@2.3.0:
|
||||
dependencies:
|
||||
confbox: 0.2.2
|
||||
exsolve: 1.0.8
|
||||
pathe: 2.0.3
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
@@ -8548,7 +8634,7 @@ snapshots:
|
||||
|
||||
postcss-load-config@4.0.2(postcss@8.4.47):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
lilconfig: 3.1.2
|
||||
yaml: 2.5.1
|
||||
optionalDependencies:
|
||||
postcss: 8.4.47
|
||||
@@ -8803,6 +8889,8 @@ snapshots:
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
|
||||
quansync@0.2.11: {}
|
||||
|
||||
querystringify@2.2.0: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
@@ -8947,7 +9035,7 @@ snapshots:
|
||||
sass@1.79.3:
|
||||
dependencies:
|
||||
chokidar: 4.0.3
|
||||
immutable: 4.3.8
|
||||
immutable: 4.3.7
|
||||
source-map-js: 1.2.1
|
||||
optional: true
|
||||
|
||||
@@ -9201,7 +9289,7 @@ snapshots:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
tailwindcss@3.4.19:
|
||||
tailwindcss@3.4.13:
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
arg: 5.0.2
|
||||
@@ -9211,12 +9299,12 @@ snapshots:
|
||||
fast-glob: 3.3.2
|
||||
glob-parent: 6.0.2
|
||||
is-glob: 4.0.3
|
||||
jiti: 1.21.7
|
||||
lilconfig: 3.1.3
|
||||
jiti: 1.21.6
|
||||
lilconfig: 2.1.0
|
||||
micromatch: 4.0.8
|
||||
normalize-path: 3.0.0
|
||||
object-hash: 3.0.0
|
||||
picocolors: 1.1.1
|
||||
picocolors: 1.1.0
|
||||
postcss: 8.4.47
|
||||
postcss-import: 15.1.0(postcss@8.4.47)
|
||||
postcss-js: 4.0.1(postcss@8.4.47)
|
||||
@@ -9236,7 +9324,7 @@ snapshots:
|
||||
terser@5.33.0:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.11
|
||||
acorn: 8.16.0
|
||||
acorn: 8.15.0
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
optional: true
|
||||
@@ -9245,7 +9333,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@istanbuljs/schema': 0.1.3
|
||||
glob: 10.4.5
|
||||
minimatch: 9.0.9
|
||||
minimatch: 9.0.5
|
||||
|
||||
text-segmentation@1.0.3:
|
||||
dependencies:
|
||||
@@ -9399,7 +9487,7 @@ snapshots:
|
||||
|
||||
uc.micro@2.1.0: {}
|
||||
|
||||
ufo@1.6.3: {}
|
||||
ufo@1.6.1: {}
|
||||
|
||||
unbox-primitive@1.0.2:
|
||||
dependencies:
|
||||
@@ -9584,9 +9672,9 @@ snapshots:
|
||||
dependencies:
|
||||
vue: 3.5.12(typescript@5.6.2)
|
||||
|
||||
vue-dompurify-html@5.3.0(vue@3.5.12(typescript@5.6.2)):
|
||||
vue-dompurify-html@5.1.0(vue@3.5.12(typescript@5.6.2)):
|
||||
dependencies:
|
||||
dompurify: 3.3.2
|
||||
dompurify: 3.2.4
|
||||
vue: 3.5.12(typescript@5.6.2)
|
||||
|
||||
vue-eslint-parser@9.4.3(eslint@8.57.0):
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable no-restricted-globals */
|
||||
/* eslint-disable no-restricted-globals, no-console */
|
||||
/* globals clients */
|
||||
|
||||
self.addEventListener('push', event => {
|
||||
let notification = event.data && event.data.json();
|
||||
|
||||
@@ -145,24 +145,5 @@ describe ContactIdentifyAction do
|
||||
expect(contact.phone_number).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when params have not changed' do
|
||||
it 'skips save and does not issue an UPDATE query' do
|
||||
contact.update!(name: 'test', identifier: 'test_id', custom_attributes: { test: 'test', test1: 'test1' })
|
||||
params = { name: 'test', identifier: 'test_id', custom_attributes: { test: 'test', test1: 'test1' } }
|
||||
|
||||
# any_instance is needed because merge lookup can reassign @contact to a different Ruby object
|
||||
expect_any_instance_of(Contact).not_to receive(:save!) # rubocop:disable RSpec/AnyInstance
|
||||
described_class.new(contact: contact, params: params).perform
|
||||
end
|
||||
|
||||
it 'still enqueues avatar job even when attributes have not changed' do
|
||||
contact.update!(name: 'test')
|
||||
params = { name: 'test', avatar_url: 'https://chatwoot-assets.local/sample.png' }
|
||||
|
||||
expect(Avatar::AvatarFromUrlJob).to receive(:perform_later).with(contact, params[:avatar_url]).once
|
||||
described_class.new(contact: contact, params: params).perform
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,7 +25,6 @@ RSpec.describe 'Agents API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.parsed_body.size).to eq(account.users.count)
|
||||
end
|
||||
|
||||
@@ -123,7 +122,6 @@ RSpec.describe 'Agents API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(other_agent.reload.name).to eq(params[:name])
|
||||
end
|
||||
|
||||
@@ -173,7 +171,6 @@ RSpec.describe 'Agents API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.parsed_body['email']).to eq(params[:email])
|
||||
expect(account.users.last.name).to eq('NewUser')
|
||||
end
|
||||
|
||||
@@ -45,7 +45,6 @@ RSpec.describe 'Contacts API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
response_body = response.parsed_body
|
||||
contact_emails = response_body['payload'].pluck('email')
|
||||
contact_inboxes_source_ids = response_body['payload'].flat_map { |c| c['contact_inboxes'].pluck('source_id') }
|
||||
@@ -332,7 +331,6 @@ RSpec.describe 'Contacts API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.body).to include(contact2.email)
|
||||
expect(response.body).not_to include(contact1.email)
|
||||
end
|
||||
@@ -445,7 +443,6 @@ RSpec.describe 'Contacts API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.body).to include(contact2.email)
|
||||
expect(response.body).to include(contact1.email)
|
||||
end
|
||||
@@ -500,7 +497,6 @@ RSpec.describe 'Contacts API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.body).to include(contact.name)
|
||||
end
|
||||
end
|
||||
@@ -624,7 +620,6 @@ RSpec.describe 'Contacts API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(contact.reload.name).to eq('Test Blub')
|
||||
# custom attributes are merged properly without overwriting existing ones
|
||||
expect(contact.custom_attributes).to eq({ 'test' => 'new test', 'test1' => 'test1', 'test2' => 'test2' })
|
||||
|
||||
@@ -31,7 +31,6 @@ RSpec.describe 'Conversation Messages API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(conversation.messages.count).to eq(1)
|
||||
expect(conversation.messages.first.content).to eq(params[:content])
|
||||
end
|
||||
@@ -183,7 +182,6 @@ RSpec.describe 'Conversation Messages API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:meta][:contact][:id]).to eq(conversation.contact_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,7 +27,6 @@ RSpec.describe 'Conversations API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
body = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(body[:data][:meta][:all_count]).to eq(1)
|
||||
expect(body[:data][:meta].keys).to include(:all_count, :mine_count, :assigned_count, :unassigned_count)
|
||||
@@ -166,7 +165,6 @@ RSpec.describe 'Conversations API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data.count).to eq(2)
|
||||
end
|
||||
@@ -236,7 +234,6 @@ RSpec.describe 'Conversations API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(conversation.display_id)
|
||||
end
|
||||
|
||||
@@ -285,7 +282,6 @@ RSpec.describe 'Conversations API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:priority]).to eq('high')
|
||||
end
|
||||
|
||||
@@ -346,7 +342,6 @@ RSpec.describe 'Conversations API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:additional_attributes]).to eq(additional_attributes)
|
||||
end
|
||||
@@ -454,11 +449,9 @@ RSpec.describe 'Conversations API', type: :request do
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/conversations/#{conversation.display_id}/toggle_status",
|
||||
headers: agent.create_new_auth_token,
|
||||
params: { status: 'open' },
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(conversation.reload.status).to eq('open')
|
||||
end
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ RSpec.describe 'Inboxes API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:payload].size).to eq(2)
|
||||
end
|
||||
|
||||
@@ -96,7 +95,6 @@ RSpec.describe 'Inboxes API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:id]).to eq(inbox.id)
|
||||
end
|
||||
|
||||
@@ -385,7 +383,6 @@ RSpec.describe 'Inboxes API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.body).to include('test.com')
|
||||
end
|
||||
|
||||
@@ -481,7 +478,6 @@ RSpec.describe 'Inboxes API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(inbox.reload.enable_auto_assignment).to be_falsey
|
||||
expect(inbox.reload.portal_id).to eq(portal.id)
|
||||
expect(response.parsed_body['name']).to eq 'new test inbox'
|
||||
|
||||
@@ -22,7 +22,6 @@ RSpec.describe 'Teams API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.parsed_body.first['id']).to eq(account.teams.first.id)
|
||||
end
|
||||
end
|
||||
@@ -46,7 +45,6 @@ RSpec.describe 'Teams API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.parsed_body['id']).to eq(team.id)
|
||||
end
|
||||
end
|
||||
@@ -85,7 +83,6 @@ RSpec.describe 'Teams API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(Team.count).to eq(2)
|
||||
end
|
||||
end
|
||||
@@ -124,7 +121,6 @@ RSpec.describe 'Teams API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(team.reload.name).to eq('new-team')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -149,7 +149,6 @@ RSpec.describe 'Accounts API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.body).to include(account.name)
|
||||
expect(response.body).to include(account.locale)
|
||||
expect(response.body).to include(account.domain)
|
||||
@@ -185,22 +184,22 @@ RSpec.describe 'Accounts API', type: :request do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH /api/v1/accounts/{account.id}' do
|
||||
describe 'PUT /api/v1/accounts/{account.id}' do
|
||||
let(:account) { create(:account) }
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:admin) { create(:user, account: account, role: :administrator) }
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
patch "/api/v1/accounts/#{account.id}"
|
||||
put "/api/v1/accounts/#{account.id}"
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an unauthorized user' do
|
||||
it 'returns unauthorized' do
|
||||
patch "/api/v1/accounts/#{account.id}",
|
||||
headers: agent.create_new_auth_token
|
||||
put "/api/v1/accounts/#{account.id}",
|
||||
headers: agent.create_new_auth_token
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
@@ -220,20 +219,11 @@ RSpec.describe 'Accounts API', type: :request do
|
||||
company_size: '1-10'
|
||||
}
|
||||
|
||||
it 'returns a valid schema' do
|
||||
patch "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to conform_schema(200)
|
||||
end
|
||||
|
||||
it 'modifies an account' do
|
||||
patch "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
put "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(account.reload.name).to eq(params[:name])
|
||||
@@ -252,19 +242,19 @@ RSpec.describe 'Accounts API', type: :request do
|
||||
|
||||
it 'updates onboarding step to invite_team if onboarding step is present in account custom attributes' do
|
||||
account.update(custom_attributes: { onboarding_step: 'account_update' })
|
||||
patch "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
put "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(account.reload.custom_attributes['onboarding_step']).to eq('invite_team')
|
||||
end
|
||||
|
||||
it 'will not update onboarding step if onboarding step is not present in account custom attributes' do
|
||||
patch "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
put "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(account.reload.custom_attributes['onboarding_step']).to be_nil
|
||||
end
|
||||
@@ -272,10 +262,10 @@ RSpec.describe 'Accounts API', type: :request do
|
||||
it 'Throws error 422' do
|
||||
params[:name] = 'test' * 999
|
||||
|
||||
patch "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
put "/api/v1/accounts/#{account.id}",
|
||||
params: params,
|
||||
headers: admin.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
json_response = response.parsed_body
|
||||
|
||||
@@ -21,7 +21,6 @@ RSpec.describe 'Profile API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
json_response = response.parsed_body
|
||||
expect(json_response['id']).to eq(agent.id)
|
||||
expect(json_response['email']).to eq(agent.email)
|
||||
@@ -51,7 +50,6 @@ RSpec.describe 'Profile API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
json_response = response.parsed_body
|
||||
agent.reload
|
||||
expect(json_response['id']).to eq(agent.id)
|
||||
@@ -66,7 +64,6 @@ RSpec.describe 'Profile API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
agent.reload
|
||||
|
||||
expect(agent.custom_attributes['phone_number']).to eq('+123456789')
|
||||
@@ -94,7 +91,6 @@ RSpec.describe 'Profile API', type: :request do
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(agent.reload.valid_password?('Test1234!')).to be true
|
||||
end
|
||||
|
||||
|
||||
@@ -144,7 +144,6 @@ RSpec.describe 'Platform Accounts API', type: :request do
|
||||
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response).to conform_schema(200)
|
||||
expect(response.body).to include(account.name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -259,12 +259,10 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
|
||||
message_content: 'Hello assistant',
|
||||
message_history: [
|
||||
{ role: 'user', content: 'Previous message' },
|
||||
{ role: 'assistant', content: 'Previous response', agent_name: 'billing_scenario' }
|
||||
{ role: 'assistant', content: 'Previous response' }
|
||||
]
|
||||
}
|
||||
end
|
||||
let(:chat_service) { instance_double(Captain::Llm::AssistantChatService) }
|
||||
let(:agent_runner_service) { instance_double(Captain::Assistant::AgentRunnerService) }
|
||||
|
||||
context 'when it is an un-authenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
@@ -276,14 +274,11 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when captain v2 is disabled' do
|
||||
it 'generates a response with the legacy assistant chat service' do
|
||||
allow(Captain::Llm::AssistantChatService).to receive(:new).with(
|
||||
assistant: assistant,
|
||||
source: 'playground'
|
||||
).and_return(chat_service)
|
||||
context 'when it is an agent' do
|
||||
it 'generates a response' do
|
||||
chat_service = instance_double(Captain::Llm::AssistantChatService)
|
||||
allow(Captain::Llm::AssistantChatService).to receive(:new).with(assistant: assistant).and_return(chat_service)
|
||||
allow(chat_service).to receive(:generate_response).and_return({ content: 'Assistant response' })
|
||||
expect(Captain::Assistant::AgentRunnerService).not_to receive(:new)
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
|
||||
params: valid_params,
|
||||
@@ -297,15 +292,14 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
|
||||
)
|
||||
expect(json_response[:content]).to eq('Assistant response')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when message_history is not provided' do
|
||||
it 'uses empty array as default' do
|
||||
params_without_history = { message_content: 'Hello assistant' }
|
||||
allow(Captain::Llm::AssistantChatService).to receive(:new).with(
|
||||
assistant: assistant,
|
||||
source: 'playground'
|
||||
).and_return(chat_service)
|
||||
chat_service = instance_double(Captain::Llm::AssistantChatService)
|
||||
allow(Captain::Llm::AssistantChatService).to receive(:new).with(assistant: assistant).and_return(chat_service)
|
||||
allow(chat_service).to receive(:generate_response).and_return({ content: 'Assistant response' })
|
||||
expect(Captain::Assistant::AgentRunnerService).not_to receive(:new)
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
|
||||
params: params_without_history,
|
||||
@@ -319,53 +313,5 @@ RSpec.describe 'Api::V1::Accounts::Captain::Assistants', type: :request do
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when captain v2 is enabled' do
|
||||
before do
|
||||
account.enable_features('captain_integration_v2')
|
||||
end
|
||||
|
||||
it 'generates a response with the agent runner service' do
|
||||
allow(Captain::Assistant::AgentRunnerService).to receive(:new).with(
|
||||
assistant: assistant,
|
||||
source: 'playground'
|
||||
).and_return(agent_runner_service)
|
||||
allow(agent_runner_service).to receive(:generate_response).and_return({ response: 'Assistant response' })
|
||||
expect(Captain::Llm::AssistantChatService).not_to receive(:new)
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
|
||||
params: valid_params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(agent_runner_service).to have_received(:generate_response).with(
|
||||
message_history: valid_params[:message_history] + [{ role: 'user', content: valid_params[:message_content] }]
|
||||
)
|
||||
expect(json_response[:response]).to eq('Assistant response')
|
||||
end
|
||||
|
||||
it 'does not duplicate the latest user message if it is already in history' do
|
||||
params_with_latest_message = {
|
||||
message_content: 'Hello assistant',
|
||||
message_history: [{ role: 'user', content: 'Hello assistant' }]
|
||||
}
|
||||
allow(Captain::Assistant::AgentRunnerService).to receive(:new).with(
|
||||
assistant: assistant,
|
||||
source: 'playground'
|
||||
).and_return(agent_runner_service)
|
||||
allow(agent_runner_service).to receive(:generate_response).and_return({ response: 'Assistant response' })
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/captain/assistants/#{assistant.id}/playground",
|
||||
params: params_with_latest_message,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(agent_runner_service).to have_received(:generate_response).with(
|
||||
message_history: params_with_latest_message[:message_history]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,45 +42,6 @@ RSpec.describe Captain::Scenario, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#handoff_key' do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
it 'uses id plus readable slug for persisted scenarios' do
|
||||
scenario = create(:captain_scenario, assistant: assistant, account: account,
|
||||
title: 'Handle complex refund requests requiring manager approval steps')
|
||||
|
||||
expect(scenario.handoff_key).to start_with("scenario_#{scenario.id}_")
|
||||
expect(scenario.handoff_key).to end_with('_agent')
|
||||
expect("handoff_to_#{scenario.handoff_key}".length).to be <= 60
|
||||
end
|
||||
|
||||
it 'uses a truncated slug key for unsaved scenarios' do
|
||||
scenario = build(:captain_scenario, assistant: assistant, account: account,
|
||||
title: 'Troubleshoot payment gateway errors for recurring subscription charges')
|
||||
|
||||
expect(scenario.handoff_key).to match(/\Ascenario_draft_[a-z0-9_]+_agent\z/)
|
||||
expect("handoff_to_#{scenario.handoff_key}".length).to be <= 60
|
||||
end
|
||||
|
||||
it 'stays within length budget even for large ids' do
|
||||
scenario = build(:captain_scenario, assistant: assistant, account: account,
|
||||
title: 'A very long scenario title used only for budget verification')
|
||||
allow(scenario).to receive(:id).and_return(1_234_567_890_123_456_789)
|
||||
|
||||
expect("handoff_to_#{scenario.handoff_key}".length).to be <= 60
|
||||
end
|
||||
|
||||
it 'exposes handoff keys in assistant prompt context' do
|
||||
scenario = create(:captain_scenario, assistant: assistant, account: account)
|
||||
|
||||
prompt_context = assistant.send(:prompt_context)
|
||||
scenario_config = prompt_context[:scenarios].find { |entry| entry[:title] == scenario.title }
|
||||
|
||||
expect(scenario_config[:key]).to eq(scenario.handoff_key)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'tool validation and population' do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
+22
-22
@@ -24,7 +24,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'schedules captain response job for incoming messages on pending conversations' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,7 +43,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'schedules captain response job outside business hours (Captain always responds when configured)' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end
|
||||
|
||||
it 'performs captain handoff when quota is exceeded (OOO template will kick in after handoff)' do
|
||||
@@ -52,7 +52,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
custom_attributes: account.custom_attributes.merge('captain_responses_usage' => 100)
|
||||
)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
|
||||
expect(conversation.reload.status).to eq('open')
|
||||
end
|
||||
@@ -62,7 +62,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
|
||||
end
|
||||
@@ -76,7 +76,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'schedules captain response job regardless of time' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,7 +95,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
end
|
||||
|
||||
it 'performs handoff within business hours when quota exceeded' do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
|
||||
expect(conversation.reload.status).to eq('open')
|
||||
end
|
||||
@@ -110,7 +110,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'does not schedule captain response job' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -122,7 +122,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'does not schedule captain response job' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -130,7 +130,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'does not schedule captain response job' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
|
||||
|
||||
create(:message, conversation: conversation, message_type: :outgoing, account: account)
|
||||
create(:message, conversation: conversation, message_type: :outgoing)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -144,7 +144,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.not_to(change { conversation.reload.messages.template.count })
|
||||
end
|
||||
|
||||
@@ -160,7 +160,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.not_to(change { conversation.reload.messages.template.count })
|
||||
end
|
||||
end
|
||||
@@ -174,7 +174,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||
|
||||
greeting_message = conversation.reload.messages.template.last
|
||||
@@ -193,7 +193,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||
|
||||
out_of_office_message = conversation.reload.messages.template.last
|
||||
@@ -211,7 +211,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||
|
||||
greeting_message = conversation.reload.messages.template.last
|
||||
@@ -230,7 +230,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||
|
||||
out_of_office_message = conversation.reload.messages.template.last
|
||||
@@ -245,7 +245,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
it 'schedules captain response job for incoming messages on pending campaign conversations' do
|
||||
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(campaign_conversation, assistant)
|
||||
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming)
|
||||
end
|
||||
|
||||
it 'does not send greeting template on campaign conversations' do
|
||||
@@ -255,7 +255,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
|
||||
allow(greeting_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming)
|
||||
|
||||
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
|
||||
end
|
||||
@@ -271,7 +271,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming)
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
|
||||
end
|
||||
@@ -284,7 +284,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::EmailCollect).to receive(:new).and_return(email_collect_service)
|
||||
allow(email_collect_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming)
|
||||
|
||||
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new)
|
||||
end
|
||||
@@ -304,7 +304,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
)
|
||||
|
||||
expect do
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: campaign_conversation, message_type: :incoming)
|
||||
end.not_to(change { campaign_conversation.messages.template.count })
|
||||
end
|
||||
end
|
||||
@@ -332,7 +332,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
|
||||
it 'sends out of office message after handoff due to quota exceeded' do
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.to change { conversation.messages.template.count }.by(1)
|
||||
|
||||
expect(conversation.reload.status).to eq('open')
|
||||
@@ -356,7 +356,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
|
||||
|
||||
it 'does not send out of office message after handoff' do
|
||||
expect do
|
||||
create(:message, conversation: conversation, message_type: :incoming, account: account)
|
||||
create(:message, conversation: conversation, message_type: :incoming)
|
||||
end.not_to(change { conversation.messages.template.count })
|
||||
|
||||
expect(conversation.reload.status).to eq('open')
|
||||
|
||||
@@ -75,10 +75,6 @@ RSpec.configure do |config|
|
||||
config.include ActiveSupport::Testing::TimeHelpers
|
||||
config.include ActionCable::TestHelper
|
||||
config.include ActiveJob::TestHelper
|
||||
|
||||
# OpenAPI response validation via Skooma
|
||||
path_to_openapi = Rails.root.join('swagger/swagger.json')
|
||||
config.include Skooma::RSpec[path_to_openapi], type: :request
|
||||
end
|
||||
|
||||
Shoulda::Matchers.configure do |config|
|
||||
|
||||
@@ -50,26 +50,6 @@ describe ActionService do
|
||||
action_service.assign_agent(['nil'])
|
||||
expect(conversation.reload.assignee).to be_nil
|
||||
end
|
||||
|
||||
context 'when agent is confirmed' do
|
||||
it 'assigns the agent to the conversation' do
|
||||
inbox_member
|
||||
action_service.assign_agent([agent.id])
|
||||
expect(conversation.reload.assignee).to eq(agent)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when agent is unconfirmed' do
|
||||
let(:unconfirmed_agent) { create(:user, account: account, role: :agent, skip_confirmation: false) }
|
||||
let(:unconfirmed_inbox_member) { create(:inbox_member, inbox: conversation.inbox, user: unconfirmed_agent) }
|
||||
|
||||
it 'does not assign unconfirmed agent to the conversation' do
|
||||
unconfirmed_inbox_member
|
||||
original_assignee = conversation.assignee
|
||||
action_service.assign_agent([unconfirmed_agent.id])
|
||||
expect(conversation.reload.assignee).to eq(original_assignee)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#assign_team' do
|
||||
|
||||
@@ -15,7 +15,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::Greeting).to receive(:new)
|
||||
|
||||
# described class gets called in message after commit
|
||||
create(:message, conversation: conversation, account: conversation.account, message_type: 'activity', content: 'Conversation marked resolved!!')
|
||||
create(:message, conversation: conversation, message_type: 'activity', content: 'Conversation marked resolved!!')
|
||||
|
||||
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
|
||||
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new)
|
||||
@@ -36,7 +36,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::Greeting).to receive(:new)
|
||||
|
||||
# described class gets called in message after commit
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
|
||||
expect(MessageTemplates::Template::EmailCollect).to have_received(:new).with(conversation: message.conversation)
|
||||
@@ -54,7 +54,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
|
||||
allow(greeting_service).to receive(:perform).and_return(true)
|
||||
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
expect(MessageTemplates::Template::Greeting).not_to have_received(:new).with(conversation: message.conversation)
|
||||
end
|
||||
end
|
||||
@@ -75,7 +75,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(greeting_service).to receive(:perform).and_return(true)
|
||||
|
||||
# described class gets called in message after commit
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::Greeting).to have_received(:new).with(conversation: message.conversation)
|
||||
expect(greeting_service).to have_received(:perform)
|
||||
@@ -90,7 +90,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::EmailCollect).to receive(:new).and_return(true)
|
||||
|
||||
# described class gets called in message after commit
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation)
|
||||
end
|
||||
@@ -105,7 +105,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::EmailCollect).to receive(:new).and_return(true)
|
||||
|
||||
# described class gets called in message after commit
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::EmailCollect).not_to have_received(:new).with(conversation: message.conversation)
|
||||
end
|
||||
@@ -123,7 +123,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
|
||||
allow(greeting_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: conversation, account: conversation.account)
|
||||
create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::Greeting).not_to have_received(:new)
|
||||
end
|
||||
@@ -139,7 +139,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: conversation, account: conversation.account)
|
||||
create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
|
||||
end
|
||||
@@ -151,7 +151,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
conversation = create(:conversation, contact: contact)
|
||||
conversation.inbox.update(greeting_enabled: true, enable_email_collect: true, greeting_message: 'Hi, this is a greeting message')
|
||||
|
||||
message = create(:message, conversation: conversation, account: conversation.account, content_type: :incoming_email)
|
||||
message = create(:message, conversation: conversation, content_type: :incoming_email)
|
||||
message.content_attributes = { email: { auto_reply: true } }
|
||||
message.save!
|
||||
|
||||
@@ -188,7 +188,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
# described class gets called in message after commit
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).to have_received(:new).with(conversation: message.conversation)
|
||||
expect(out_of_office_service).to have_received(:perform)
|
||||
@@ -202,13 +202,13 @@ describe MessageTemplates::HookExecutionService do
|
||||
conversation.inbox.update(working_hours_enabled: true, out_of_office_message: 'We are out of office')
|
||||
conversation.inbox.working_hours.today.update!(closed_all_day: true)
|
||||
|
||||
create(:message, conversation: conversation, account: conversation.account, message_type: :outgoing, created_at: 2.minutes.ago)
|
||||
create(:message, conversation: conversation, message_type: :outgoing, created_at: 2.minutes.ago)
|
||||
|
||||
out_of_office_service = double
|
||||
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: conversation, account: conversation.account)
|
||||
create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
|
||||
expect(out_of_office_service).not_to have_received(:perform)
|
||||
@@ -221,13 +221,13 @@ describe MessageTemplates::HookExecutionService do
|
||||
conversation.inbox.update(working_hours_enabled: true, out_of_office_message: 'We are out of office')
|
||||
conversation.inbox.working_hours.today.update!(closed_all_day: true)
|
||||
|
||||
create(:message, conversation: conversation, account: conversation.account, private: true, message_type: :outgoing, created_at: 2.minutes.ago)
|
||||
create(:message, conversation: conversation, private: true, message_type: :outgoing, created_at: 2.minutes.ago)
|
||||
|
||||
out_of_office_service = double
|
||||
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
create(:message, conversation: conversation, account: conversation.account)
|
||||
create(:message, conversation: conversation)
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).to have_received(:new).with(conversation: conversation)
|
||||
expect(out_of_office_service).to have_received(:perform)
|
||||
@@ -247,7 +247,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||
|
||||
# described class gets called in message after commit
|
||||
message = create(:message, conversation: conversation, account: conversation.account, message_type: 'outgoing')
|
||||
message = create(:message, conversation: conversation, message_type: 'outgoing')
|
||||
|
||||
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new).with(conversation: message.conversation)
|
||||
expect(out_of_office_service).not_to have_received(:perform)
|
||||
@@ -265,7 +265,7 @@ describe MessageTemplates::HookExecutionService do
|
||||
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||
allow(out_of_office_service).to receive(:perform).and_return(false)
|
||||
|
||||
message = create(:message, conversation: conversation, account: conversation.account)
|
||||
message = create(:message, conversation: conversation)
|
||||
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new).with(conversation: message.conversation)
|
||||
expect(out_of_office_service).not_to receive(:perform)
|
||||
end
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'OpenAPI document', type: :request do
|
||||
it 'is valid against the OpenAPI 3.1.0 meta-schema' do
|
||||
expect(skooma_openapi_schema).to be_valid_document
|
||||
end
|
||||
end
|
||||
@@ -70,8 +70,6 @@ platform_account:
|
||||
$ref: ./resource/platform_account.yml
|
||||
team:
|
||||
$ref: ./resource/team.yml
|
||||
label:
|
||||
$ref: ./resource/label.yml
|
||||
integrations_app:
|
||||
$ref: ./resource/integrations/app.yml
|
||||
integrations_hook:
|
||||
@@ -144,10 +142,6 @@ inbox_update_payload:
|
||||
team_create_update_payload:
|
||||
$ref: ./request/team/create_update_payload.yml
|
||||
|
||||
# Label
|
||||
label_create_update_payload:
|
||||
$ref: ./request/label/create_update_payload.yml
|
||||
|
||||
# Custom Filter
|
||||
custom_filter_create_update_payload:
|
||||
$ref: ./request/custom_filter/create_update_payload.yml
|
||||
|
||||
@@ -18,23 +18,20 @@ properties:
|
||||
example: 'support@example.com'
|
||||
# Settings parameters (stored in settings JSONB column)
|
||||
auto_resolve_after:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
minimum: 10
|
||||
maximum: 1439856
|
||||
nullable: true
|
||||
description: Auto resolve conversations after specified minutes
|
||||
example: 1440
|
||||
auto_resolve_message:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
nullable: true
|
||||
description: Message to send when auto resolving
|
||||
example: "This conversation has been automatically resolved due to inactivity"
|
||||
auto_resolve_ignore_waiting:
|
||||
type:
|
||||
- boolean
|
||||
- 'null'
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: Whether to ignore waiting conversations for auto resolve
|
||||
example: false
|
||||
# Custom attributes parameters (stored in custom_attributes JSONB column)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
type: object
|
||||
required:
|
||||
- source_id
|
||||
- inbox_id
|
||||
properties:
|
||||
source_id:
|
||||
type: string
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
description: The label title
|
||||
example: support
|
||||
description:
|
||||
type: string
|
||||
description: A short description for the label
|
||||
example: Conversations that need support follow-up
|
||||
color:
|
||||
type: string
|
||||
description: Hex color code for the label
|
||||
example: '#1f93ff'
|
||||
show_on_sidebar:
|
||||
type: boolean
|
||||
description: Whether the label should appear in the sidebar
|
||||
example: true
|
||||
@@ -26,7 +26,9 @@ properties:
|
||||
type: object
|
||||
description: Cache keys for the account
|
||||
features:
|
||||
type: object
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Enabled features for the account
|
||||
settings:
|
||||
type: object
|
||||
@@ -46,24 +48,16 @@ properties:
|
||||
description: Custom attributes of the account
|
||||
properties:
|
||||
plan_name:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Subscription plan name
|
||||
subscribed_quantity:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: Subscribed quantity
|
||||
subscription_status:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Subscription status
|
||||
subscription_ends_on:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
format: date
|
||||
description: Subscription end date
|
||||
industry:
|
||||
|
||||
@@ -3,9 +3,7 @@ allOf:
|
||||
- type: object
|
||||
properties:
|
||||
latest_chatwoot_version:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Latest version of Chatwoot available
|
||||
example: "3.0.0"
|
||||
subscribed_features:
|
||||
|
||||
@@ -31,7 +31,5 @@ properties:
|
||||
type: string
|
||||
description: The thumbnail of the agent
|
||||
custom_role_id:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
description: The custom role id of the agent
|
||||
|
||||
@@ -38,9 +38,8 @@ properties:
|
||||
type: integer
|
||||
description: Version number of the audit log entry
|
||||
comment:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
nullable: true
|
||||
description: Optional comment associated with the audit log entry
|
||||
request_uuid:
|
||||
type: string
|
||||
@@ -49,7 +48,6 @@ properties:
|
||||
type: integer
|
||||
description: Unix timestamp when the audit log entry was created
|
||||
remote_address:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
nullable: true
|
||||
description: IP address from which the action was performed
|
||||
@@ -31,10 +31,9 @@ properties:
|
||||
type: string
|
||||
description: Status of the message
|
||||
source_id:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Source ID of the message
|
||||
nullable: true
|
||||
content_type:
|
||||
type: string
|
||||
description: Type of the content
|
||||
@@ -42,15 +41,13 @@ properties:
|
||||
type: object
|
||||
description: Attributes of the content
|
||||
sender_type:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Type of the sender
|
||||
nullable: true
|
||||
sender_id:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
description: ID of the sender
|
||||
nullable: true
|
||||
external_source_ids:
|
||||
type: object
|
||||
description: External source IDs
|
||||
@@ -58,10 +55,9 @@ properties:
|
||||
type: object
|
||||
description: Additional attributes of the message
|
||||
processed_message_content:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Processed message content
|
||||
nullable: true
|
||||
sentiment:
|
||||
type: object
|
||||
description: Sentiment analysis of the message
|
||||
@@ -70,10 +66,9 @@ properties:
|
||||
description: Conversation details
|
||||
properties:
|
||||
assignee_id:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
description: ID of the assignee
|
||||
nullable: true
|
||||
unread_count:
|
||||
type: integer
|
||||
description: Count of unread messages
|
||||
|
||||
@@ -11,9 +11,7 @@ properties:
|
||||
type: string
|
||||
description: Country of the contact
|
||||
country_code:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Country code of the contact
|
||||
created_at_ip:
|
||||
type: string
|
||||
@@ -28,18 +26,16 @@ properties:
|
||||
type: integer
|
||||
description: The ID of the contact
|
||||
identifier:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The identifier of the contact
|
||||
nullable: true
|
||||
name:
|
||||
type: string
|
||||
description: The name of the contact
|
||||
phone_number:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The phone number of the contact
|
||||
nullable: true
|
||||
thumbnail:
|
||||
type: string
|
||||
description: The thumbnail of the contact
|
||||
|
||||
@@ -22,7 +22,6 @@ properties:
|
||||
type: string
|
||||
description: Type of channel
|
||||
provider:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
description: Provider of the inbox
|
||||
type: string
|
||||
description: Provider of the inbox
|
||||
nullable: true
|
||||
@@ -11,9 +11,7 @@ properties:
|
||||
type: string
|
||||
description: Country of the contact
|
||||
country_code:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Country code of the contact
|
||||
created_at_ip:
|
||||
type: string
|
||||
@@ -23,10 +21,9 @@ properties:
|
||||
description: Availability status of the contact
|
||||
enum: ["online", "offline"]
|
||||
email:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The email address of the contact
|
||||
nullable: true
|
||||
id:
|
||||
type: integer
|
||||
description: The ID of the contact
|
||||
@@ -34,18 +31,16 @@ properties:
|
||||
type: string
|
||||
description: The name of the contact
|
||||
phone_number:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The phone number of the contact
|
||||
nullable: true
|
||||
blocked:
|
||||
type: boolean
|
||||
description: Whether the contact is blocked
|
||||
identifier:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The identifier of the contact
|
||||
nullable: true
|
||||
thumbnail:
|
||||
type: string
|
||||
description: The thumbnail of the contact
|
||||
@@ -53,10 +48,9 @@ properties:
|
||||
type: object
|
||||
description: The custom attributes of the contact
|
||||
last_activity_at:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
description: Timestamp of last activity
|
||||
nullable: true
|
||||
created_at:
|
||||
type: integer
|
||||
description: Timestamp when contact was created
|
||||
|
||||
@@ -4,7 +4,5 @@ properties:
|
||||
type: integer
|
||||
description: Total number of contacts
|
||||
current_page:
|
||||
type:
|
||||
- string
|
||||
- integer
|
||||
description: Current page number
|
||||
type: string
|
||||
description: Current page number
|
||||
@@ -43,9 +43,7 @@ properties:
|
||||
type: boolean
|
||||
description: Whether the conversation is muted
|
||||
snoozed_until:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: The time at which the conversation will be unmuted
|
||||
status:
|
||||
type: string
|
||||
@@ -58,38 +56,29 @@ properties:
|
||||
type: number
|
||||
description: The time at which conversation was updated
|
||||
timestamp:
|
||||
type: number
|
||||
type: string
|
||||
description: The time at which conversation was created
|
||||
first_reply_created_at:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: The time at which the first reply was created
|
||||
unread_count:
|
||||
type: number
|
||||
description: The number of unread messages
|
||||
last_non_activity_message:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/message'
|
||||
- type: 'null'
|
||||
type: object
|
||||
$ref: '#/components/schemas/message'
|
||||
description: The last non activity message
|
||||
last_activity_at:
|
||||
type: number
|
||||
description: The last activity at of the conversation
|
||||
priority:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The priority of the conversation
|
||||
waiting_since:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: The time at which the conversation was waiting
|
||||
sla_policy_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: The ID of the SLA policy
|
||||
applied_sla:
|
||||
type: object
|
||||
|
||||
@@ -51,12 +51,10 @@ properties:
|
||||
description: The agent assigned to the conversation
|
||||
nullable: true
|
||||
agent_last_seen_at:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Timestamp when the agent last saw the conversation
|
||||
nullable: true
|
||||
assignee_last_seen_at:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
description: Timestamp when the assignee last saw the conversation
|
||||
type: string
|
||||
description: Timestamp when the assignee last saw the conversation
|
||||
nullable: true
|
||||
@@ -13,9 +13,7 @@ properties:
|
||||
type: string
|
||||
description: The availability status of the sender
|
||||
email:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The email of the sender
|
||||
id:
|
||||
type: number
|
||||
@@ -24,22 +22,16 @@ properties:
|
||||
type: string
|
||||
description: The name of the sender
|
||||
phone_number:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The phone number of the sender
|
||||
blocked:
|
||||
type: boolean
|
||||
description: Whether the sender is blocked
|
||||
identifier:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The identifier of the sender
|
||||
thumbnail:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Avatar URL of the contact
|
||||
custom_attributes:
|
||||
type: object
|
||||
|
||||
@@ -28,22 +28,16 @@ properties:
|
||||
type: string
|
||||
description: Script used to load the website widget
|
||||
welcome_title:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Welcome title to be displayed on the widget
|
||||
welcome_tagline:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Welcome tagline to be displayed on the widget
|
||||
greeting_enabled:
|
||||
type: boolean
|
||||
description: The flag which shows whether greeting is enabled
|
||||
greeting_message:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: A greeting message when the user starts the conversation
|
||||
channel_id:
|
||||
type: number
|
||||
@@ -61,9 +55,7 @@ properties:
|
||||
type: object
|
||||
description: Configuration settings for auto assignment
|
||||
out_of_office_message:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Message to show when agents are out of office
|
||||
working_hours:
|
||||
type: array
|
||||
@@ -78,24 +70,16 @@ properties:
|
||||
type: boolean
|
||||
description: Whether the inbox is closed for the entire day
|
||||
open_hour:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: Hour when inbox opens (0-23)
|
||||
open_minutes:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: Minutes of the hour when inbox opens (0-59)
|
||||
close_hour:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: Hour when inbox closes (0-23)
|
||||
close_minutes:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: Minutes of the hour when inbox closes (0-59)
|
||||
open_all_day:
|
||||
type: boolean
|
||||
@@ -104,9 +88,7 @@ properties:
|
||||
type: string
|
||||
description: Timezone configuration for the inbox
|
||||
callback_webhook_url:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Webhook URL for callbacks
|
||||
allow_messages_after_resolved:
|
||||
type: boolean
|
||||
@@ -118,38 +100,26 @@ properties:
|
||||
type: string
|
||||
description: Type of sender name to display (e.g., friendly)
|
||||
business_name:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Business name associated with the inbox
|
||||
hmac_mandatory:
|
||||
type: boolean
|
||||
description: Whether HMAC verification is mandatory
|
||||
selected_feature_flags:
|
||||
type:
|
||||
- array
|
||||
- 'null'
|
||||
type: object
|
||||
description: Selected feature flags for the inbox
|
||||
items:
|
||||
type: string
|
||||
reply_time:
|
||||
type: string
|
||||
description: Expected reply time
|
||||
messaging_service_sid:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Messaging service SID for SMS providers
|
||||
phone_number:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Phone number associated with the inbox
|
||||
medium:
|
||||
type: string
|
||||
description: Medium of communication (e.g., sms, email)
|
||||
provider:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: Provider of the channel
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: number
|
||||
description: The ID of the label
|
||||
title:
|
||||
type: string
|
||||
description: The title of the label
|
||||
description:
|
||||
type: string
|
||||
description: The description of the label
|
||||
color:
|
||||
type: string
|
||||
description: Hex color code for the label
|
||||
show_on_sidebar:
|
||||
type: boolean
|
||||
description: Whether the label should appear in the sidebar
|
||||
@@ -17,49 +17,37 @@ properties:
|
||||
description: The ID of the conversation
|
||||
message_type:
|
||||
type: integer
|
||||
enum: [0, 1, 2, 3]
|
||||
enum: [0, 1, 2]
|
||||
description: The type of the message
|
||||
created_at:
|
||||
type: integer
|
||||
description: The time at which message was created
|
||||
updated_at:
|
||||
type:
|
||||
- integer
|
||||
- string
|
||||
type: integer
|
||||
description: The time at which message was updated
|
||||
private:
|
||||
type: boolean
|
||||
description: The flags which shows whether the message is private or not
|
||||
status:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
enum: ["sent", "delivered", "read", "failed", null]
|
||||
type: string
|
||||
enum: ["sent", "delivered", "read", "failed"]
|
||||
description: The status of the message
|
||||
source_id:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The source ID of the message
|
||||
content_type:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
enum: ["text", "input_text", "input_textarea", "input_email", "input_select", "cards", "form", "article", "incoming_email", "input_csat", "integrations", "sticker", "voice_call", null]
|
||||
type: string
|
||||
enum: ["text", "input_select", "cards", "form"]
|
||||
description: The type of the template message
|
||||
content_attributes:
|
||||
type: object
|
||||
description: The content attributes for each content_type
|
||||
sender_type:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
enum: ["Contact", "User", "AgentBot", "Captain::Assistant", null]
|
||||
type: string
|
||||
enum: ["contact", "agent", "agent_bot"]
|
||||
description: The type of the sender
|
||||
sender_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
description: The ID of the sender
|
||||
external_source_ids:
|
||||
type: object
|
||||
@@ -68,24 +56,16 @@ properties:
|
||||
type: object
|
||||
description: The additional attributes of the message
|
||||
processed_message_content:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The processed message content
|
||||
sentiment:
|
||||
type:
|
||||
- object
|
||||
- 'null'
|
||||
type: object
|
||||
description: The sentiment of the message
|
||||
conversation:
|
||||
type:
|
||||
- object
|
||||
- 'null'
|
||||
type: object
|
||||
description: The conversation object
|
||||
attachment:
|
||||
type:
|
||||
- object
|
||||
- 'null'
|
||||
type: object
|
||||
description: The file object attached to the image
|
||||
sender:
|
||||
type: object
|
||||
|
||||
@@ -18,7 +18,7 @@ properties:
|
||||
description: "The type of the message (0: incoming, 1: outgoing, 2: activity, 3: template)"
|
||||
content_type:
|
||||
type: string
|
||||
enum: ["text", "input_text", "input_textarea", "input_email", "input_select", "cards", "form", "article", "incoming_email", "input_csat", "integrations", "sticker", "voice_call"]
|
||||
enum: ["text", "input_select", "cards", "form", "input_csat"]
|
||||
description: The type of the message content
|
||||
status:
|
||||
type: string
|
||||
@@ -29,15 +29,13 @@ properties:
|
||||
description: The content attributes for each content_type
|
||||
properties:
|
||||
in_reply_to:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: ID of the message this is replying to
|
||||
nullable: true
|
||||
echo_id:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The echo ID of the message, used for deduplication
|
||||
nullable: true
|
||||
created_at:
|
||||
type: integer
|
||||
description: The timestamp when message was created
|
||||
@@ -45,10 +43,9 @@ properties:
|
||||
type: boolean
|
||||
description: The flag which shows whether the message is private or not
|
||||
source_id:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The source ID of the message
|
||||
nullable: true
|
||||
sender:
|
||||
$ref: '#/components/schemas/contact_detail'
|
||||
description: The sender of the message (only for incoming messages)
|
||||
@@ -79,4 +76,4 @@ properties:
|
||||
description: The thumbnail URL of the attached file
|
||||
file_size:
|
||||
type: number
|
||||
description: The size of the attached file in bytes
|
||||
description: The size of the attached file in bytes
|
||||
@@ -4,19 +4,16 @@ properties:
|
||||
type: integer
|
||||
description: Total number of articles
|
||||
archived_articles_count:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
nullable: true
|
||||
description: Number of archived articles
|
||||
published_count:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
nullable: true
|
||||
description: Number of published articles
|
||||
draft_articles_count:
|
||||
type:
|
||||
- integer
|
||||
- 'null'
|
||||
type: integer
|
||||
nullable: true
|
||||
description: Number of draft articles
|
||||
categories_count:
|
||||
type: integer
|
||||
|
||||
@@ -26,19 +26,16 @@ properties:
|
||||
type: number
|
||||
description: ID of the account
|
||||
conversation_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: ID of the conversation
|
||||
inbox_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: ID of the inbox
|
||||
user_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: ID of the user/agent
|
||||
created_at:
|
||||
type: string
|
||||
|
||||
@@ -13,19 +13,16 @@ items:
|
||||
type: number
|
||||
description: Number of conversations resolved by the agent during the date range
|
||||
avg_resolution_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) to resolve conversations. Null if no data available.
|
||||
avg_first_response_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) for the first response. Null if no data available.
|
||||
avg_reply_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) between replies. Null if no data available.
|
||||
example:
|
||||
- id: 1
|
||||
|
||||
@@ -13,19 +13,16 @@ items:
|
||||
type: number
|
||||
description: Number of conversations resolved in the inbox during the date range
|
||||
avg_resolution_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) to resolve conversations. Null if no data available.
|
||||
avg_first_response_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) for the first response. Null if no data available.
|
||||
avg_reply_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) between replies. Null if no data available.
|
||||
example:
|
||||
- id: 1
|
||||
|
||||
@@ -13,19 +13,16 @@ items:
|
||||
type: number
|
||||
description: Number of conversations resolved by the team during the date range
|
||||
avg_resolution_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) to resolve conversations. Null if no data available.
|
||||
avg_first_response_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) for the first response. Null if no data available.
|
||||
avg_reply_time:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
description: Average time (in seconds) between replies. Null if no data available.
|
||||
example:
|
||||
- id: 1
|
||||
|
||||
@@ -7,9 +7,7 @@ properties:
|
||||
type: string
|
||||
description: The name of the team
|
||||
description:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
description: The description about the team
|
||||
allow_auto_assign:
|
||||
type: boolean
|
||||
|
||||
@@ -13,21 +13,17 @@ properties:
|
||||
confirmed:
|
||||
type: boolean
|
||||
display_name:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
nullable: true
|
||||
message_signature:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
nullable: true
|
||||
email:
|
||||
type: string
|
||||
hmac_identifier:
|
||||
type: string
|
||||
inviter_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
name:
|
||||
type: string
|
||||
provider:
|
||||
@@ -42,9 +38,8 @@ properties:
|
||||
uid:
|
||||
type: string
|
||||
type:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
nullable: true
|
||||
custom_attributes:
|
||||
type: object
|
||||
description: Available for users who are created through platform APIs and has custom attributes associated.
|
||||
@@ -60,9 +55,7 @@ properties:
|
||||
status:
|
||||
type: string
|
||||
active_at:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
format: date-time
|
||||
role:
|
||||
type: string
|
||||
@@ -78,10 +71,8 @@ properties:
|
||||
auto_offline:
|
||||
type: boolean
|
||||
custom_role_id:
|
||||
type:
|
||||
- number
|
||||
- 'null'
|
||||
type: number
|
||||
nullable: true
|
||||
custom_role:
|
||||
type:
|
||||
- object
|
||||
- 'null'
|
||||
type: object
|
||||
nullable: true
|
||||
|
||||
+1
-4
@@ -1,4 +1,4 @@
|
||||
openapi: '3.1.0'
|
||||
openapi: '3.0.4'
|
||||
info:
|
||||
title: Chatwoot
|
||||
description: This is the API documentation for Chatwoot server.
|
||||
@@ -67,8 +67,6 @@ tags:
|
||||
description: Communication channels setup
|
||||
- name: Integrations
|
||||
description: Third-party integrations
|
||||
- name: Labels
|
||||
description: Account label management APIs
|
||||
- name: Messages
|
||||
description: Message management APIs
|
||||
- name: Profile
|
||||
@@ -114,7 +112,6 @@ x-tagGroups:
|
||||
- Custom Filters
|
||||
- Inboxes
|
||||
- Integrations
|
||||
- Labels
|
||||
- Messages
|
||||
- Profile
|
||||
- Reports
|
||||
|
||||
@@ -38,14 +38,10 @@ responses:
|
||||
assignee:
|
||||
$ref: '#/components/schemas/agent'
|
||||
agent_last_seen_at:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
format: date-time
|
||||
assignee_last_seen_at:
|
||||
type:
|
||||
- string
|
||||
- 'null'
|
||||
type: string
|
||||
format: date-time
|
||||
payload:
|
||||
type: array
|
||||
|
||||
@@ -25,10 +25,6 @@ requestBody:
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/conversation'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
|
||||
@@ -33,38 +33,3 @@ get:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
post:
|
||||
tags:
|
||||
- Inboxes
|
||||
operationId: inboxCreation
|
||||
summary: Create an inbox
|
||||
description: You can create more than one website inbox in each account
|
||||
security:
|
||||
- userApiKey: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/account_id'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/inbox_create_payload'
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/inbox'
|
||||
'404':
|
||||
description: Inbox not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
'403':
|
||||
description: Access denied
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
|
||||
@@ -1,38 +1,3 @@
|
||||
get:
|
||||
tags:
|
||||
- Inboxes
|
||||
operationId: GetInbox
|
||||
summary: Get an inbox
|
||||
security:
|
||||
- userApiKey: []
|
||||
description: Get an inbox available in the current account
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/account_id'
|
||||
- name: id
|
||||
in: path
|
||||
schema:
|
||||
type: number
|
||||
description: ID of the inbox
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/inbox'
|
||||
'404':
|
||||
description: Inbox not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
'403':
|
||||
description: Access denied
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
patch:
|
||||
tags:
|
||||
- Inboxes
|
||||
@@ -61,6 +26,8 @@ patch:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
description: 'Updated inbox object'
|
||||
$ref: '#/components/schemas/inbox'
|
||||
'404':
|
||||
description: Inbox not found
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
tags:
|
||||
- Labels
|
||||
operationId: create-a-label
|
||||
summary: Create a label
|
||||
security:
|
||||
- userApiKey: []
|
||||
description: Create a label in the account
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/label_create_update_payload'
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/label'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
@@ -1,22 +0,0 @@
|
||||
tags:
|
||||
- Labels
|
||||
operationId: delete-a-label
|
||||
summary: Delete a label
|
||||
security:
|
||||
- userApiKey: []
|
||||
description: Delete a label from the account
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
'404':
|
||||
description: The label does not exist in the account
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
@@ -1,26 +0,0 @@
|
||||
tags:
|
||||
- Labels
|
||||
operationId: list-all-labels
|
||||
summary: List all labels
|
||||
security:
|
||||
- userApiKey: []
|
||||
description: List all labels available in the current account
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
payload:
|
||||
type: array
|
||||
description: Array of labels
|
||||
items:
|
||||
$ref: '#/components/schemas/label'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
@@ -1,26 +0,0 @@
|
||||
tags:
|
||||
- Labels
|
||||
operationId: get-details-of-a-single-label
|
||||
summary: Get a label
|
||||
security:
|
||||
- userApiKey: []
|
||||
description: Get the details of a label in the account
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/label'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
'404':
|
||||
description: The given label ID does not exist in the account
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
@@ -1,26 +0,0 @@
|
||||
tags:
|
||||
- Labels
|
||||
operationId: update-a-label
|
||||
summary: Update a label
|
||||
security:
|
||||
- userApiKey: []
|
||||
description: Update a label's attributes
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/label_create_update_payload'
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/label'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
+5
-25
@@ -167,7 +167,7 @@
|
||||
# ------------ Application API routes ------------#
|
||||
|
||||
# Accounts
|
||||
/api/v1/accounts/{account_id}:
|
||||
/api/v1/accounts/{id}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/account_id'
|
||||
get:
|
||||
@@ -413,6 +413,10 @@
|
||||
# Inboxes
|
||||
/api/v1/accounts/{account_id}/inboxes:
|
||||
$ref: ./application/inboxes/index.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}/:
|
||||
$ref: ./application/inboxes/show.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/:
|
||||
$ref: ./application/inboxes/create.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}:
|
||||
$ref: ./application/inboxes/update.yml
|
||||
/api/v1/accounts/{account_id}/inboxes/{id}/agent_bot:
|
||||
@@ -438,30 +442,6 @@
|
||||
delete:
|
||||
$ref: ./application/inboxes/inbox_members/delete.yml
|
||||
|
||||
# Labels
|
||||
/api/v1/accounts/{account_id}/labels:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/account_id'
|
||||
get:
|
||||
$ref: ./application/labels/index.yml
|
||||
post:
|
||||
$ref: ./application/labels/create.yml
|
||||
/api/v1/accounts/{account_id}/labels/{id}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/account_id'
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: number
|
||||
description: ID of the label
|
||||
get:
|
||||
$ref: ./application/labels/show.yml
|
||||
patch:
|
||||
$ref: ./application/labels/update.yml
|
||||
delete:
|
||||
$ref: ./application/labels/delete.yml
|
||||
|
||||
# Messages
|
||||
/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages:
|
||||
parameters:
|
||||
|
||||
@@ -19,80 +19,3 @@ get:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/bad_request_error'
|
||||
put:
|
||||
tags:
|
||||
- Profile
|
||||
operationId: updateProfile
|
||||
summary: Update user profile
|
||||
description: Update the user profile details
|
||||
security:
|
||||
- userApiKey: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- profile
|
||||
properties:
|
||||
profile:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
display_name:
|
||||
type: string
|
||||
message_signature:
|
||||
type: string
|
||||
phone_number:
|
||||
type: string
|
||||
current_password:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
password_confirmation:
|
||||
type: string
|
||||
ui_settings:
|
||||
type: object
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- profile
|
||||
properties:
|
||||
profile:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
display_name:
|
||||
type: string
|
||||
message_signature:
|
||||
type: string
|
||||
phone_number:
|
||||
type: string
|
||||
current_password:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
password_confirmation:
|
||||
type: string
|
||||
avatar:
|
||||
type: string
|
||||
format: binary
|
||||
ui_settings:
|
||||
type: object
|
||||
responses:
|
||||
'200':
|
||||
description: Success
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/user'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
|
||||
+243
-952
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
openapi: '3.1.0'
|
||||
openapi: '3.0.4'
|
||||
info:
|
||||
title: Chatwoot - Application API
|
||||
description: Application API endpoints for Chatwoot
|
||||
@@ -36,8 +36,6 @@ tags:
|
||||
description: Manage inboxes
|
||||
- name: Integrations
|
||||
description: Manage integrations
|
||||
- name: Labels
|
||||
description: Manage account labels
|
||||
- name: Messages
|
||||
description: Manage messages
|
||||
- name: Profile
|
||||
@@ -64,4 +62,4 @@ components:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: api_access_token
|
||||
description: This token can be obtained by visiting the profile page or via rails console. Provides access to endpoints based on the user permissions levels.
|
||||
description: This token can be obtained by visiting the profile page or via rails console. Provides access to endpoints based on the user permissions levels.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
openapi: '3.1.0'
|
||||
openapi: '3.0.4'
|
||||
info:
|
||||
title: Chatwoot - Client API
|
||||
description: Client API endpoints for Chatwoot
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
openapi: '3.1.0'
|
||||
openapi: '3.0.4'
|
||||
info:
|
||||
title: Chatwoot - Other APIs
|
||||
description: Other API endpoints for Chatwoot
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
openapi: '3.1.0'
|
||||
openapi: '3.0.4'
|
||||
info:
|
||||
title: Chatwoot - Platform API
|
||||
description: Platform API endpoints for Chatwoot
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user