From ce2646007eba854cdf4636dc1b30587def1fdd15 Mon Sep 17 00:00:00 2001 From: corb3nik Date: Fri, 28 Nov 2025 20:59:42 -0500 Subject: [PATCH 1/3] Update page document to use vue --- AGENTS.md | 7 + src/guides/page.md | 431 ++++++++++++++++++--------------------------- 2 files changed, 180 insertions(+), 258 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 569caab..4675cd2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -263,6 +263,13 @@ Example structure: This convention ensures consistency across all Vue component examples in the documentation. +#### UI Component Guidelines + +- **Never use `sdk.ui` methods**: Methods like `sdk.ui.button()`, `sdk.ui.card()`, `sdk.ui.well()`, `sdk.ui.httpRequestEditor()`, etc. are deprecated and should not be used in documentation examples +- **Always use PrimeVue components**: Use PrimeVue components (e.g., `Button` from `primevue/button`, `Card` from `primevue/card`) for all UI elements +- **Style with Tailwind CSS**: Use Tailwind CSS utility classes for layout and styling instead of inline styles or custom CSS +- **Vue is the standard**: All page creation examples should use Vue.js components, not DOM manipulation (`document.createElement`, `appendChild`, etc.) + #### For Reference - Be accurate, complete, and concise diff --git a/src/guides/page.md b/src/guides/page.md index 9c6cba8..a52b05c 100644 --- a/src/guides/page.md +++ b/src/guides/page.md @@ -1,6 +1,10 @@ # Create a Page -Plugin pages provide a graphical user interface in the Caido application. There are multiple SDK objects and methods available to assist you in customization. +Plugin pages provide a graphical user interface in the Caido application. Pages are created using Vue.js components with PrimeVue and Tailwind CSS for styling. + +::: info +Vue.js is the standard approach for creating plugin pages in Caido. When you initialize a plugin using `pnpm create @caido-community/plugin`, you can choose the Vue.js template option. This guide shows how to create pages using Vue components. For more information about using PrimeVue components and styling, see [Using the Component Library](/guides/styling.md). +::: ## Creating Pages and Navigating @@ -8,14 +12,38 @@ Used to create pages in the application and navigate to them. ### Adding a Page +Pages are created by setting up a Vue application and mounting it to a root element, which is then passed to `sdk.navigation.addPage()`. The Vue app handles the page's layout, state, and user interactions. + ```ts -sdk.navigation.addPage("/my-plugin-page", { - body: card; - topbar: bar; -}); +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; + +import App from "./views/App.vue"; + +export const init = (sdk: CaidoSDK) => { + const app = createApp(App); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, + }); + + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", + }); + + app.mount(root); + + sdk.navigation.addPage("/my-plugin-page", { + body: root, + }); +}; ``` -This creates a page of which the contents are the [card](#creating-a-card) you will learn how to create below. +This creates a page where the contents are defined in your `App.vue` component. The Vue app is mounted to a root `div` element, which is then passed as the `body` property to `addPage`. The `topbar` property is optional and appears to the right of the Caido logo in the top-left corner. @@ -47,240 +75,124 @@ The `icon` property is optional and adds a [FontAwesome](https://fontawesome.com - The `isExternal` property is optional and takes a boolean value of _true_ if the path points to an external URL. ::: -## Creating UI Components +## Building UI Components with PrimeVue -Used to create visual elements. Content options for each element are also provided. These elements provide a way to sectionalize the user-interface of your plugin. +UI components are built using PrimeVue components styled with Tailwind CSS. PrimeVue provides a comprehensive set of components that match Caido's design system. -### Creating a Button +### Using PrimeVue Components -```ts -const deleteButton = sdk.ui.button({ - variant: "primary", - label: "Delete", - trailingIcon: "fas fa-trash-can", - size: "small", -}); -``` +Import and use PrimeVue components directly in your Vue components. For example, to create a button: -All button properties are optional and include: +```vue + -- `variant` - Specifies the button type and can have a value of `"primary"`, `"secondary"` or `"tertiary"`. -- `label` - Specifies the inner string within the button. -- `leadingIcon` - Adds an icon at the leading side of the button. -- `trailingIcon` - Addsan icon at the trailing side of the button. -- `size` - Specifies the button size and can have a value of `"small"`, `"medium"` or `"large"`. - -### Creating a Card - -```ts -const card = sdk.ui.card({ - header: headerContainer, - body: bodyText, - footer: footerText, -}); + ``` -A **card** is a layout component. Similar to an HTML file, Cards consist of `header`, `body` and `footer` properties. - -All properties are optional. The value of each property is a defined HTML element. +PrimeVue components support various props for customization: + +- `label` - The button text +- `icon` - FontAwesome icon class +- `severity` - Button style (`primary`, `secondary`, `success`, `info`, `warning`, `danger`) +- `size` - Button size (`small`, `medium`, `large`) + +### Creating Layouts with Tailwind CSS + +Use Tailwind CSS utility classes to create layouts. For example, to create a card-like layout: + +```vue + + + +``` ::: tip -To use multiple HTML elements, combine them using `
` tags: +For a complete example of creating a page with Vue components, see the example below. This shows how to set up a Vue app in `index.ts` and create the page layout in `App.vue`: ```ts +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; + import type { Caido } from "@caido/sdk-frontend"; import type { API } from "starterkit-plugin-backend"; -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const headerText = document.createElement("h1"); - headerText.textContent = "Hello world!"; - - const subText = document.createElement("p"); - subText.textContent = "Lorem ipsum."; +import App from "./views/App.vue"; - const bodyText = document.createElement("p"); - bodyText.textContent = "Paragraph."; - - const footerText = document.createElement("p"); - footerText.textContent = "Footer text."; - - const headerContainer = document.createElement("div"); - headerContainer.appendChild(headerText); - headerContainer.appendChild(subText); - - const bar = document.createElement("p"); - bar.textContent = "Topbar."; - - const card = sdk.ui.card({ - header: headerContainer, - body: bodyText, - footer: footerText, - }); - - sdk.navigation.addPage("/my-plugin-page", { - body: card, - topbar: bar, - }); -}; +export type CaidoSDK = Caido; export const init = (sdk: CaidoSDK) => { - // Register commands - // Commands are registered with a unique identifier and a handler function - // The run function is called when the command is executed - // These commands can be registered in various places like command palette, context menu, etc. - - // Register page - createPage(sdk); - - // Register sidebar - sdk.sidebar.registerItem("My Plugin", "/my-plugin-page", { - icon: "fas fa-rocket", + const app = createApp(App); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, }); -}; -``` - -The `init` function contains the `createPage(sdk)` function to register the page and the `.registerItem` method to make it available in the sidebar when the plugin initializes. -::: - -Add page SKD. - -### Creating a Well - -```ts -const well = sdk.ui.well({ - header: title, - body: paragraph, - footer: advisory, -}); -``` - -A **well** is a layout component. Wells are similar to cards in that they consist of `header`, `body` and `footer` properties. - -All properties are optional. The value of each property is a defined HTML element. - -### Creating a Request Editor -```ts -const reqEditor = sdk.ui.httpRequestEditor(); -const reqEditorPane = reqEditor.getElement(); -``` - -### Creating a Response Editor - -```ts -const respEditor = sdk.ui.httpResponseEditor(); -const respEditorPane = respEditor.getElement(); -``` - -::: tip -For an example of a page with request and response editors, expand the following: - -
-Example - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import type { API } from "starterkit-plugin-backend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const headerText = document.createElement("h1"); - headerText.textContent = "Hello world!"; - - const subText = document.createElement("p"); - subText.textContent = "Lorem ipsum."; - - const bodyText = document.createElement("p"); - bodyText.textContent = "Paragraph."; - - const reqEditor = sdk.ui.httpRequestEditor(); - const reqEditorPane = reqEditor.getElement(); - const respEditor = sdk.ui.httpResponseEditor(); - const respEditorPane = respEditor.getElement(); - - const footerText = document.createElement("p"); - footerText.textContent = "Footer text."; - - const headerContainer = document.createElement("div"); - headerContainer.appendChild(headerText); - headerContainer.appendChild(subText); - - const bodyContainer = document.createElement("div"); - bodyContainer.appendChild(bodyText); - - const editorsContainer = document.createElement("div"); - editorsContainer.classList.add("editors-container"); - - reqEditorPane.classList.add("editor-pane"); - respEditorPane.classList.add("editor-pane"); - - editorsContainer.appendChild(reqEditorPane); - editorsContainer.appendChild(respEditorPane); - - bodyContainer.appendChild(editorsContainer); - - const bar = document.createElement("p"); - bar.textContent = "Topbar."; - - const card = sdk.ui.card({ - header: headerContainer, - body: bodyContainer, - footer: footerText, + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", }); + app.mount(root); + sdk.navigation.addPage("/my-plugin-page", { - body: card, - topbar: bar, + body: root, }); -}; -export const init = (sdk: CaidoSDK) => { - createPage(sdk); sdk.sidebar.registerItem("My Plugin", "/my-plugin-page", { icon: "fas fa-rocket", }); }; ``` -
-::: - -::: tip -To view the CSS rules of the editors shown below, expand the following: - -
-Example - -``` css -.editors-container { - display: flex; - flex-direction: row; - justify-content: space-between; - width: 100%; - height: 100%; -} - -.editor-pane { - flex: 1; - min-width: 300px; - min-height: 500px; - margin: 0 10px; -} - -.editor-pane h2 { - margin: 0; - padding: 10px; - border-radius: 4px; -} +The `App.vue` component defines the page layout: + +```vue + + + ``` -
+The `init` function creates the Vue app, mounts it to a root element, and registers the page with `addPage`. The sidebar item is registered to make the page accessible from the navigation menu. ::: -Page with request and response editors. +Add page SKD. ## Interacting with Windows and Editors @@ -318,80 +230,83 @@ All message properties are optional and include: - `variant` - Specifies the message type and can have a value of `"success"`, `"error"`, `"warning"` or `"info"`. - `duration` - Specifies the amount of time a message will be displayed in milliseconds. -::: tip -For an example of how to trigger Toast messages on button clicks, expand the following: +## Examples -
-Example +### Basic Page with Button -```ts -import type { Caido } from "@caido/sdk-frontend"; -import type { API } from "starterkit-plugin-backend"; +This example creates a simple page with a button that displays a toast message when clicked. -export type CaidoSDK = Caido; +```vue + + + +``` - const headerText = document.createElement("h1"); - headerText.textContent = "Hello world!"; - - const subText = document.createElement("p"); - subText.textContent = "Lorem ipsum."; +The corresponding `index.ts` file: - const bodyText = document.createElement("p"); - bodyText.textContent = "Paragraph."; +```ts +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; - const footerText = document.createElement("p"); - footerText.textContent = "Footer text."; +import type { Caido } from "@caido/sdk-frontend"; +import type { API } from "starterkit-plugin-backend"; - const headerContainer = document.createElement("div"); - headerContainer.appendChild(headerText); - headerContainer.appendChild(subText); - headerContainer.appendChild(messageButton); +import App from "./views/App.vue"; - const bar = document.createElement("p"); - bar.textContent = "Topbar."; +export type CaidoSDK = Caido; - const card = sdk.ui.card({ - header: headerContainer, - body: bodyText, - footer: footerText, +export const init = (sdk: CaidoSDK) => { + const app = createApp(App); + + app.provide("sdk", sdk); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, }); - sdk.navigation.addPage("/my-plugin-page", { - body: card, - topbar: bar, + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", }); -}; -export const init = (sdk: CaidoSDK) => { - // Register commands - // Commands are registered with a unique identifier and a handler function - // The run function is called when the command is executed - // These commands can be registered in various places like command palette, context menu, etc. + app.mount(root); - // Register page - createPage(sdk); + sdk.navigation.addPage("/my-plugin-page", { + body: root, + }); - // Register sidebar sdk.sidebar.registerItem("My Plugin", "/my-plugin-page", { icon: "fas fa-rocket", }); }; ``` -
-::: - Toast messages SKD. From e154318feb31d6ec83d443e64bc9db18e5053b29 Mon Sep 17 00:00:00 2001 From: corb3nik Date: Fri, 28 Nov 2025 21:09:57 -0500 Subject: [PATCH 2/3] Update examples --- src/guides/ai.md | 107 ----------- src/guides/application_events.md | 117 ------------ src/guides/assets.md | 133 ------------- src/guides/command_palette_advanced.md | 86 --------- src/guides/dialogs.md | 106 +++++------ src/guides/editor_extensions.md | 65 ------- src/guides/events.md | 67 +++---- src/guides/fetch.md | 75 +++----- src/guides/filters.md | 241 +++++++----------------- src/guides/log.md | 65 +++---- src/guides/match_replace.md | 152 --------------- src/guides/navigation_events.md | 39 ---- src/guides/replay.md | 249 +++++++++++++------------ src/guides/request.md | 83 ++------- src/guides/rpc.md | 200 ++++++++------------ src/guides/runtime.md | 144 +++----------- src/guides/scopes.md | 158 ++++++++-------- src/guides/utf.md | 66 ++----- src/guides/view_modes.md | 90 --------- src/guides/workflows.md | 101 ---------- 20 files changed, 547 insertions(+), 1797 deletions(-) diff --git a/src/guides/ai.md b/src/guides/ai.md index eb78df2..9fe126a 100644 --- a/src/guides/ai.md +++ b/src/guides/ai.md @@ -49,84 +49,6 @@ export const init = async (sdk: CaidoSDK) => { }; ``` -### AI-Powered Request Analysis - -This example creates a page with a button that analyzes HTTP requests using AI. When clicked, it extracts text from the active editor, sends it to the AI provider for security analysis, and displays the results. - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import { generateText } from "ai"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; - - const analyzeButton = sdk.ui.button({ - variant: "primary", - label: "Analyze Request", - }); - - const resultText = document.createElement("div"); - resultText.style.padding = "16px"; - resultText.style.backgroundColor = "#f5f5f5"; - resultText.style.borderRadius = "4px"; - resultText.style.minHeight = "100px"; - - analyzeButton.addEventListener("click", async () => { - const editor = sdk.window.getActiveEditor(); - if (!editor) { - sdk.window.showToast("No active editor", { variant: "warning" }); - return; - } - - const requestText = editor.getSelectedText() || editor.getEditorView().state.doc.toString(); - - if (!requestText) { - sdk.window.showToast("No request text found", { variant: "warning" }); - return; - } - - resultText.textContent = "Analyzing..."; - analyzeButton.disabled = true; - - try { - const provider = sdk.ai.createProvider(); - const { text } = await generateText({ - model: provider, - prompt: `Analyze this HTTP request and identify potential security issues:\n\n${requestText}`, - }); - - resultText.textContent = text; - } catch (error) { - resultText.textContent = `Error: ${error}`; - sdk.log.error("AI analysis failed:", error); - } finally { - analyzeButton.disabled = false; - } - }); - - container.appendChild(analyzeButton); - container.appendChild(resultText); - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/ai-analyzer", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); -}; -``` - ### AI-Powered Code Generation This example registers a command that uses AI to generate Caido plugin code based on a user's description. The command prompts for a description, generates code using AI, and logs the result. @@ -165,35 +87,6 @@ export const init = (sdk: CaidoSDK) => { }; ``` -### Streaming AI Responses - -This example demonstrates how to stream AI responses in real-time. It processes HTTP request text through AI analysis and calls a callback function for each chunk of the response as it arrives. - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import { streamText } from "ai"; - -export type CaidoSDK = Caido; - -const streamAnalysis = async (sdk: CaidoSDK, requestText: string, onChunk: (text: string) => void) => { - const provider = sdk.ai.createProvider(); - - const { textStream } = await streamText({ - model: provider, - prompt: `Analyze this HTTP request:\n\n${requestText}`, - }); - - for await (const chunk of textStream) { - onChunk(chunk); - } -}; - -export const init = (sdk: CaidoSDK) => { - // Use streaming for real-time AI responses - // Implementation depends on your UI needs -}; -``` - ::: tip The AI provider is compatible with all features of the `ai` library, including text generation, streaming, tool calling, and more. Refer to the [ai SDK documentation](https://ai-sdk.dev/) for advanced usage. ::: diff --git a/src/guides/application_events.md b/src/guides/application_events.md index c0f3f97..ebc3c5c 100644 --- a/src/guides/application_events.md +++ b/src/guides/application_events.md @@ -99,88 +99,6 @@ For more details on navigation events, see [How to Listen to Page Navigation Cha ## Examples -### Comprehensive Event Monitor - -This example creates a comprehensive event monitoring page that subscribes to all major application events (projects, workflows, replay sessions, navigation, and backend events). It displays all events in a scrollable log with timestamps and event types. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; - - const eventLog = document.createElement("div"); - eventLog.id = "event-log"; - eventLog.style.maxHeight = "400px"; - eventLog.style.overflowY = "auto"; - eventLog.style.padding = "8px"; - eventLog.style.backgroundColor = "#f5f5f5"; - eventLog.style.borderRadius = "4px"; - eventLog.style.fontFamily = "monospace"; - eventLog.style.fontSize = "12px"; - - const addLogEntry = (type: string, message: string) => { - const entry = document.createElement("div"); - entry.style.marginBottom = "4px"; - entry.style.padding = "4px"; - entry.style.borderLeft = "3px solid #2196f3"; - entry.innerHTML = `[${type}] ${message} (${new Date().toLocaleTimeString()})`; - eventLog.appendChild(entry); - eventLog.scrollTop = eventLog.scrollHeight; - }; - - // Subscribe to all events - sdk.projects.onCurrentProjectChange((event) => { - addLogEntry("Project", `Changed to: ${event.projectId || "None"}`); - }); - - sdk.workflows.onCreatedWorkflow((workflow) => { - addLogEntry("Workflow", `Created: ${workflow.name}`); - }); - - sdk.workflows.onUpdatedWorkflow((workflow) => { - addLogEntry("Workflow", `Updated: ${workflow.name}`); - }); - - sdk.workflows.onDeletedWorkflow((workflowId) => { - addLogEntry("Workflow", `Deleted: ${workflowId}`); - }); - - sdk.replay.onCurrentSessionChange((event) => { - addLogEntry("Replay", `Session changed to: ${event.sessionId || "None"}`); - }); - - sdk.navigation.onPageChange((event) => { - addLogEntry("Navigation", `Page changed to: ${event.routeId}`); - }); - - // Backend events (if your backend sends events) - sdk.backend.onEvent("custom-event", (data) => { - addLogEntry("Backend", `Custom event: ${JSON.stringify(data)}`); - }); - - container.appendChild(eventLog); - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/event-monitor", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); -}; -``` - ### Project-Specific Configuration This example manages project-specific configuration by listening to project change events. When switching projects, it cleans up resources from the previous project and loads configuration for the new project. @@ -246,41 +164,6 @@ export const init = (sdk: CaidoSDK) => { }; ``` -### Real-Time Updates - -This example demonstrates real-time UI updates based on application events. It listens to replay session changes and page navigation events, calling update functions to keep the UI synchronized with the current state. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -export const init = (sdk: CaidoSDK) => { - // Update UI in real-time based on events - sdk.replay.onCurrentSessionChange((event) => { - if (event.sessionId) { - // Update UI to reflect current session - updateSessionUI(event.sessionId); - } - }); - - sdk.navigation.onPageChange((event) => { - // Update UI based on current page - updatePageUI(event.routeId); - }); - - const updateSessionUI = (sessionId: string) => { - // Update UI elements related to the current session - sdk.log.debug("Updating UI for session:", sessionId); - }; - - const updatePageUI = (routeId: string) => { - // Update UI elements based on the current page - sdk.log.debug("Updating UI for page:", routeId); - }; -}; -``` - ::: tip Application events enable reactive programming patterns. Use them to keep your plugin's state synchronized with Caido's state. ::: diff --git a/src/guides/assets.md b/src/guides/assets.md index 4afe752..22ed608 100644 --- a/src/guides/assets.md +++ b/src/guides/assets.md @@ -90,139 +90,6 @@ export const init = async (sdk: CaidoSDK) => { }; ``` -### Loading Text Templates - -This example loads a text template file from the assets directory and displays it in a page. It handles loading errors gracefully by showing an error message if the template file cannot be found or loaded. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const loadTemplate = async (sdk: CaidoSDK, templateName: string): Promise => { - const asset = await sdk.assets.get(`templates/${templateName}.txt`); - return await asset.asString(); -}; - -const createPage = async (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - - try { - const template = await loadTemplate(sdk, "welcome"); - const content = document.createElement("div"); - content.textContent = template; - container.appendChild(content); - } catch (error) { - const errorMsg = document.createElement("div"); - errorMsg.textContent = `Failed to load template: ${error}`; - errorMsg.style.color = "red"; - container.appendChild(errorMsg); - } - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/template-viewer", { - body: card, - }); -}; - -export const init = async (sdk: CaidoSDK) => { - await createPage(sdk); -}; -``` - -### Processing Large Files - -This example demonstrates how to process large asset files efficiently using streams. It reads the file in chunks, processes them incrementally, and logs progress every 100 chunks to avoid loading the entire file into memory at once. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const processLargeFile = async (sdk: CaidoSDK, filename: string) => { - const asset = await sdk.assets.get(filename); - const stream = asset.asReadableStream(); - const reader = stream.getReader(); - const decoder = new TextDecoder(); - - let buffer = ""; - let chunkCount = 0; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - chunkCount++; - buffer += decoder.decode(value, { stream: true }); - - // Process chunks as they arrive - if (chunkCount % 100 === 0) { - sdk.log.info(`Processed ${chunkCount} chunks`); - } - } - - sdk.log.info(`Finished processing. Total chunks: ${chunkCount}`); - return buffer; -}; - -export const init = async (sdk: CaidoSDK) => { - // Process large file in chunks - await processLargeFile(sdk, "large-data.txt"); -}; -``` - -### Loading Binary Data - -This example loads a binary image file from assets, converts it to a Blob, creates an object URL, and displays it in an image element. This demonstrates how to work with binary assets like images. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const loadImage = async (sdk: CaidoSDK, imagePath: string): Promise => { - const asset = await sdk.assets.get(imagePath); - return await asset.asArrayBuffer(); -}; - -const createPage = async (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - - try { - const imageBuffer = await loadImage(sdk, "images/logo.png"); - const blob = new Blob([imageBuffer], { type: "image/png" }); - const url = URL.createObjectURL(blob); - - const img = document.createElement("img"); - img.src = url; - img.style.maxWidth = "100%"; - container.appendChild(img); - } catch (error) { - const errorMsg = document.createElement("div"); - errorMsg.textContent = `Failed to load image: ${error}`; - errorMsg.style.color = "red"; - container.appendChild(errorMsg); - } - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/image-viewer", { - body: card, - }); -}; - -export const init = async (sdk: CaidoSDK) => { - await createPage(sdk); -}; -``` - ### Loading Multiple Assets This example demonstrates loading multiple assets in parallel using Promise.all. It loads a JSON config file, a text template, and a data JSON file simultaneously, converting each to its appropriate format. diff --git a/src/guides/command_palette_advanced.md b/src/guides/command_palette_advanced.md index 604d5b6..ca096f4 100644 --- a/src/guides/command_palette_advanced.md +++ b/src/guides/command_palette_advanced.md @@ -232,89 +232,3 @@ export const init = (sdk: CaidoSDK) => { sdk.commandPalette.register("multi-step"); }; ``` - -### Interactive Form - -This example creates an interactive form within the command palette that collects a name and email address. When submitted, it displays the collected data in a toast notification. - -```vue - - - - -``` - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import FormView from "./FormView.vue"; - -export type CaidoSDK = Caido; - -export const init = (sdk: CaidoSDK) => { - sdk.commands.register("show-form", { - name: "Show Form", - run: () => { - sdk.commandPalette.pushView({ - type: "Custom", - definition: { - component: FormView, - }, - }); - }, - }); - - sdk.commandPalette.register("show-form"); -}; -``` diff --git a/src/guides/dialogs.md b/src/guides/dialogs.md index aa1d04f..a368c89 100644 --- a/src/guides/dialogs.md +++ b/src/guides/dialogs.md @@ -53,43 +53,34 @@ dialog.close(); ### Confirmation Dialog -This example creates a reusable confirmation dialog function that displays a message and returns a promise resolving to `true` if confirmed or `false` if cancelled. It's used in a page with a delete button. +This example creates a reusable confirmation dialog function that displays a message and returns a promise resolving to `true` if confirmed or `false` if cancelled. ```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; +import Button from "primevue/button"; const showConfirmationDialog = (sdk: CaidoSDK, message: string): Promise => { return new Promise((resolve) => { const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; + container.className = "p-5 flex flex-col gap-4"; const messageEl = document.createElement("p"); messageEl.textContent = message; container.appendChild(messageEl); const buttonContainer = document.createElement("div"); - buttonContainer.style.display = "flex"; - buttonContainer.style.gap = "8px"; - buttonContainer.style.justifyContent = "flex-end"; + buttonContainer.className = "flex gap-2 justify-end"; - const confirmButton = sdk.ui.button({ - variant: "primary", - label: "Confirm", - }); + const confirmButton = document.createElement("button"); + confirmButton.textContent = "Confirm"; + confirmButton.className = "px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"; confirmButton.addEventListener("click", () => { dialog.close(); resolve(true); }); - const cancelButton = sdk.ui.button({ - variant: "secondary", - label: "Cancel", - }); + const cancelButton = document.createElement("button"); + cancelButton.textContent = "Cancel"; + cancelButton.className = "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"; cancelButton.addEventListener("click", () => { dialog.close(); resolve(false); @@ -106,40 +97,40 @@ const showConfirmationDialog = (sdk: CaidoSDK, message: string): Promise { - const button = sdk.ui.button({ - variant: "primary", - label: "Delete Item", - }); +To use this dialog in a Vue component, call it from a button click handler: - button.addEventListener("click", async () => { - const confirmed = await showConfirmationDialog( - sdk, - "Are you sure you want to delete this item?" - ); - - if (confirmed) { - sdk.window.showToast("Item deleted", { variant: "success" }); - } else { - sdk.window.showToast("Cancelled", { variant: "info" }); - } - }); +```vue + + + ``` +::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). +::: + ### Form Dialog This example creates a dialog with a text input field that collects user input. The dialog returns the entered value when submitted, or `null` if cancelled. The input is automatically focused when the dialog opens. @@ -148,35 +139,28 @@ This example creates a dialog with a text input field that collects user input. const showFormDialog = (sdk: CaidoSDK): Promise => { return new Promise((resolve) => { const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; + container.className = "p-5 flex flex-col gap-4"; const input = document.createElement("input"); input.type = "text"; input.placeholder = "Enter value"; - input.style.padding = "8px"; + input.className = "px-3 py-2 border border-gray-600 rounded bg-gray-800 text-white"; container.appendChild(input); const buttonContainer = document.createElement("div"); - buttonContainer.style.display = "flex"; - buttonContainer.style.gap = "8px"; - buttonContainer.style.justifyContent = "flex-end"; + buttonContainer.className = "flex gap-2 justify-end"; - const submitButton = sdk.ui.button({ - variant: "primary", - label: "Submit", - }); + const submitButton = document.createElement("button"); + submitButton.textContent = "Submit"; + submitButton.className = "px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"; submitButton.addEventListener("click", () => { dialog.close(); resolve(input.value || null); }); - const cancelButton = sdk.ui.button({ - variant: "secondary", - label: "Cancel", - }); + const cancelButton = document.createElement("button"); + cancelButton.textContent = "Cancel"; + cancelButton.className = "px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"; cancelButton.addEventListener("click", () => { dialog.close(); resolve(null); diff --git a/src/guides/editor_extensions.md b/src/guides/editor_extensions.md index 95c5e8a..0e87f36 100644 --- a/src/guides/editor_extensions.md +++ b/src/guides/editor_extensions.md @@ -130,68 +130,3 @@ export const init = (sdk: CaidoSDK) => { sdk.httpHistory.addRequestEditorExtension(customKeymapExtension); }; ``` - -### Editor Theme - -This example applies a custom dark theme to the request and response editors. It sets background colors, text colors, and cursor colors to create a dark editor appearance. - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import { Extension } from "@codemirror/state"; -import { EditorView } from "@codemirror/view"; - -export type CaidoSDK = Caido; - -const darkThemeExtension: Extension = EditorView.theme({ - "&": { - backgroundColor: "#1e1e1e", - color: "#d4d4d4", - }, - ".cm-content": { - caretColor: "#aeafad", - }, - ".cm-focused .cm-cursor": { - borderLeftColor: "#aeafad", - }, -}); - -export const init = (sdk: CaidoSDK) => { - sdk.httpHistory.addRequestEditorExtension(darkThemeExtension); - sdk.httpHistory.addResponseEditorExtension(darkThemeExtension); -}; -``` - -### Autocomplete - -This example adds autocomplete functionality that suggests HTTP methods (GET, POST, PUT, DELETE) as you type in the editor. The autocomplete appears when you start typing a word. - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import { Extension } from "@codemirror/state"; -import { autocompletion, completionKeymap } from "@codemirror/autocomplete"; - -export type CaidoSDK = Caido; - -const customAutocompleteExtension: Extension = autocompletion({ - override: [ - (context) => { - const word = context.matchBefore(/\w*/); - if (!word) return null; - - return { - from: word.from, - options: [ - { label: "GET", type: "method" }, - { label: "POST", type: "method" }, - { label: "PUT", type: "method" }, - { label: "DELETE", type: "method" }, - ], - }; - }, - ], -}); - -export const init = (sdk: CaidoSDK) => { - sdk.httpHistory.addRequestEditorExtension(customAutocompleteExtension); -}; -``` diff --git a/src/guides/events.md b/src/guides/events.md index ad60c3b..f67f93e 100644 --- a/src/guides/events.md +++ b/src/guides/events.md @@ -108,55 +108,40 @@ sdk.backend.onEvent("request-completed", (data) => { }); ``` -### /frontend/src/index.ts +### Subscribing to Events in Vue -::: tip -To view the entire frontend script, including the UI - expand the following: - -
-Example +To subscribe to backend events in a Vue component: -``` ts -import type { Caido } from "@caido/sdk-frontend"; -import type { BackendAPI, BackendEvents } from "../../backend/src"; +```vue + + + ``` -
+::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). ::: ## The Result diff --git a/src/guides/fetch.md b/src/guides/fetch.md index 3d084a9..26f157c 100644 --- a/src/guides/fetch.md +++ b/src/guides/fetch.md @@ -182,54 +182,33 @@ Fetch Response: ::: -::: tip -To view how the endpoint can be called with a frontend plugin, expand the following: - -
-Full Script - -``` ts -import type { Caido } from "@caido/sdk-frontend"; -import type { API } from "../../backend/src/index.ts"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - - const resultText = document.createElement("p"); - resultText.textContent = "Result will appear here."; - - const calculateButton = sdk.ui.button({ - variant: "primary", - label: "Fetch", - }); - - calculateButton.addEventListener("click", async () => { - const result = await sdk.backend.callApi(); - resultText.textContent = `Result: ${JSON.stringify(result, null, 2)}`; - }); - - const container = document.createElement("div"); - container.appendChild(calculateButton); - container.appendChild(resultText); - - const card = sdk.ui.card({ - body: container - }); - - sdk.navigation.addPage("/fetch-page", { - body: card - }); -} - -export function init(sdk: CaidoSDK) { - createPage(sdk); - - sdk.sidebar.registerItem("Fetch", "/fetch-page", { - icon: "fas fa-paper-plane" - }); -} +### Calling the Endpoint from Frontend + +To call the endpoint from a Vue component, use the backend SDK: + +```vue + + + ``` -
+::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). ::: diff --git a/src/guides/filters.md b/src/guides/filters.md index 6c29a00..afe0607 100644 --- a/src/guides/filters.md +++ b/src/guides/filters.md @@ -107,205 +107,106 @@ Common HTTPQL query patterns: ## Examples -### Filter Management Plugin +### Dynamic Query Building -This example creates a complete filter management interface that displays all saved filters, allows creating new filters, applying filters to HTTP History, and deleting existing filters. Each filter shows its name, alias, and query. +This example creates a query builder interface with input fields for status code, HTTP method, and path. It dynamically constructs HTTPQL queries from the input values and applies them to HTTP History. ```ts +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; + import type { Caido } from "@caido/sdk-frontend"; +import App from "./views/QueryBuilder.vue"; + export type CaidoSDK = Caido; -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; - - // Filter list - const filterList = document.createElement("div"); - filterList.id = "filter-list"; - - const refreshFilterList = async () => { - filterList.innerHTML = ""; - const filters = await sdk.filters.getAll(); - - if (filters.length === 0) { - filterList.textContent = "No filters found"; - return; - } - - filters.forEach((filter) => { - const filterItem = document.createElement("div"); - filterItem.style.padding = "8px"; - filterItem.style.border = "1px solid #ccc"; - filterItem.style.marginBottom = "8px"; - - const name = document.createElement("h3"); - name.textContent = filter.name; - filterItem.appendChild(name); - - const alias = document.createElement("p"); - alias.textContent = `Alias: ${filter.alias}`; - filterItem.appendChild(alias); - - const query = document.createElement("p"); - query.textContent = `Query: ${filter.query}`; - filterItem.appendChild(query); - - const applyButton = sdk.ui.button({ - variant: "primary", - label: "Apply to HTTP History", - size: "small", - }); - applyButton.addEventListener("click", () => { - sdk.httpHistory.setQuery(filter.query); - sdk.navigation.goTo({ id: "http-history" }); - sdk.window.showToast("Filter applied", { variant: "success" }); - }); - filterItem.appendChild(applyButton); - - const deleteButton = sdk.ui.button({ - variant: "secondary", - label: "Delete", - size: "small", - }); - deleteButton.addEventListener("click", async () => { - await sdk.filters.delete(filter.id); - refreshFilterList(); - sdk.window.showToast("Filter deleted", { variant: "success" }); - }); - filterItem.appendChild(deleteButton); - - filterList.appendChild(filterItem); - }); - }; - - // Create filter button - const createButton = sdk.ui.button({ - variant: "primary", - label: "Create New Filter", - }); - createButton.addEventListener("click", async () => { - const filter = await sdk.filters.create({ - name: `Filter ${Date.now()}`, - alias: `filter-${Date.now()}`, - query: "status:200", - }); - if (filter) { - refreshFilterList(); - sdk.window.showToast("Filter created", { variant: "success" }); - } +export const init = (sdk: CaidoSDK) => { + const app = createApp(App); + + app.provide("sdk", sdk); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, }); - container.appendChild(createButton); - container.appendChild(filterList); - - refreshFilterList(); - - const card = sdk.ui.card({ - body: container, + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", }); - sdk.navigation.addPage("/filter-manager", { - body: card, - }); -}; + app.mount(root); -export const init = (sdk: CaidoSDK) => { - createPage(sdk); + sdk.navigation.addPage("/query-builder", { + body: root, + }); }; ``` -### Dynamic Query Building +```vue + + + ``` ### Using Filter Presets diff --git a/src/guides/log.md b/src/guides/log.md index b677725..ba99051 100644 --- a/src/guides/log.md +++ b/src/guides/log.md @@ -70,41 +70,36 @@ try { This example demonstrates logging at different levels during user interactions. It logs info messages when operations start and complete, error messages when operations fail, and shows corresponding toast notifications to the user. -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const button = sdk.ui.button({ - variant: "primary", - label: "Perform Action", - }); - - button.addEventListener("click", async () => { - sdk.log.info("Button clicked, starting operation"); - - try { - const result = await performOperation(); - sdk.log.info("Operation completed successfully:", result); - sdk.window.showToast("Success!", { variant: "success" }); - } catch (err) { - sdk.log.error("Operation failed:", err); - sdk.window.showToast("Error occurred", { variant: "error" }); - } - }); - - const card = sdk.ui.card({ - body: button, - }); - - sdk.navigation.addPage("/logging-example", { - body: card, - }); +```vue + -export const init = (sdk: CaidoSDK) => { - sdk.log.info("Logging example plugin initialized"); - createPage(sdk); -}; + ``` + +::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). +::: diff --git a/src/guides/match_replace.md b/src/guides/match_replace.md index 01fde91..0ec3665 100644 --- a/src/guides/match_replace.md +++ b/src/guides/match_replace.md @@ -124,158 +124,6 @@ sdk.matchReplace.selectRule(undefined); ## Examples -### Rule Manager Plugin - -This example creates a comprehensive interface for managing match and replace rule collections and individual rules. It displays collections with their rule counts, lists all rules with their queries, and provides buttons to toggle rule states, create collections, and delete items. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; - - // Collections list - const collectionsList = document.createElement("div"); - collectionsList.id = "collections-list"; - - const refreshCollections = () => { - collectionsList.innerHTML = ""; - const collections = sdk.matchReplace.getCollections(); - - if (collections.length === 0) { - collectionsList.textContent = "No collections found"; - return; - } - - collections.forEach((collection) => { - const collectionItem = document.createElement("div"); - collectionItem.style.padding = "8px"; - collectionItem.style.border = "1px solid #ccc"; - collectionItem.style.marginBottom = "8px"; - - const name = document.createElement("h3"); - name.textContent = collection.name; - collectionItem.appendChild(name); - - const ruleCount = document.createElement("p"); - ruleCount.textContent = `${collection.ruleIds.length} rules`; - collectionItem.appendChild(ruleCount); - - const deleteButton = sdk.ui.button({ - variant: "secondary", - label: "Delete", - size: "small", - }); - deleteButton.addEventListener("click", async () => { - await sdk.matchReplace.deleteCollection(collection.id); - refreshCollections(); - sdk.window.showToast("Collection deleted", { variant: "success" }); - }); - collectionItem.appendChild(deleteButton); - - collectionsList.appendChild(collectionItem); - }); - }; - - // Rules list - const rulesList = document.createElement("div"); - rulesList.id = "rules-list"; - - const refreshRules = () => { - rulesList.innerHTML = ""; - const rules = sdk.matchReplace.getRules(); - - if (rules.length === 0) { - rulesList.textContent = "No rules found"; - return; - } - - rules.forEach((rule) => { - const ruleItem = document.createElement("div"); - ruleItem.style.padding = "8px"; - ruleItem.style.border = "1px solid #ccc"; - ruleItem.style.marginBottom = "8px"; - - const name = document.createElement("h3"); - name.textContent = rule.name; - ruleItem.appendChild(name); - - const query = document.createElement("p"); - query.textContent = `Query: ${rule.query}`; - ruleItem.appendChild(query); - - const toggleButton = sdk.ui.button({ - variant: rule.enabled ? "primary" : "secondary", - label: rule.enabled ? "Disable" : "Enable", - size: "small", - }); - toggleButton.addEventListener("click", async () => { - await sdk.matchReplace.toggleRule(rule.id, !rule.enabled); - refreshRules(); - sdk.window.showToast(`Rule ${rule.enabled ? "disabled" : "enabled"}`, { - variant: "success", - }); - }); - ruleItem.appendChild(toggleButton); - - const deleteButton = sdk.ui.button({ - variant: "secondary", - label: "Delete", - size: "small", - }); - deleteButton.addEventListener("click", async () => { - await sdk.matchReplace.deleteRule(rule.id); - refreshRules(); - sdk.window.showToast("Rule deleted", { variant: "success" }); - }); - ruleItem.appendChild(deleteButton); - - rulesList.appendChild(ruleItem); - }); - }; - - // Create collection button - const createCollectionButton = sdk.ui.button({ - variant: "primary", - label: "Create Collection", - }); - createCollectionButton.addEventListener("click", async () => { - const collection = await sdk.matchReplace.createCollection({ - name: `Collection ${Date.now()}`, - }); - if (collection) { - refreshCollections(); - sdk.window.showToast("Collection created", { variant: "success" }); - } - }); - - container.appendChild(createCollectionButton); - container.appendChild(collectionsList); - container.appendChild(rulesList); - - refreshCollections(); - refreshRules(); - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/match-replace-manager", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); -}; -``` - ### Auto-Enable Rules This example automatically enables all rules in a specific collection named "Auto Rules" when the plugin initializes. It finds the collection, filters rules belonging to it, and enables any that are currently disabled. diff --git a/src/guides/navigation_events.md b/src/guides/navigation_events.md index e2d6a7f..5b5f1e4 100644 --- a/src/guides/navigation_events.md +++ b/src/guides/navigation_events.md @@ -87,45 +87,6 @@ export const init = (sdk: CaidoSDK) => { }; ``` -### Updating UI Based on Current Page - -This example creates a page that displays the current route ID and updates it in real-time as the user navigates. It subscribes to page change events and updates a status text element with the current page information. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const statusText = document.createElement("p"); - statusText.textContent = "Current page: Unknown"; - - const updateStatus = (routeId: string) => { - statusText.textContent = `Current page: ${routeId}`; - }; - - // Subscribe to page changes - sdk.navigation.onPageChange((event) => { - updateStatus(event.routeId || "unknown"); - }); - - // Get initial page state - // Note: You may need to check the current page on initialization - - const card = sdk.ui.card({ - body: statusText, - }); - - sdk.navigation.addPage("/page-tracker", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); -}; -``` - ### Conditional Feature Activation This example conditionally enables or disables a feature based on the current page. The feature is only active on Replay or HTTP History pages, and is automatically deactivated when navigating to other pages. diff --git a/src/guides/replay.md b/src/guides/replay.md index 7dcdfe3..a1b93ad 100644 --- a/src/guides/replay.md +++ b/src/guides/replay.md @@ -136,147 +136,154 @@ handler.stop(); This example creates a comprehensive session and collection management interface. It displays all replay sessions and collections, allows opening sessions in tabs, creating new collections, and deleting items. It also subscribes to session change events. ```ts +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; + import type { Caido } from "@caido/sdk-frontend"; +import App from "./views/App.vue"; + export type CaidoSDK = Caido; -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; +export const init = (sdk: CaidoSDK) => { + const app = createApp(App); + + app.provide("sdk", sdk); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, + }); - // Sessions list - const sessionsList = document.createElement("div"); - sessionsList.id = "sessions-list"; + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", + }); - const refreshSessions = () => { - sessionsList.innerHTML = ""; - const sessions = sdk.replay.getSessions(); + app.mount(root); - if (sessions.length === 0) { - sessionsList.textContent = "No sessions found"; - return; - } + sdk.navigation.addPage("/replay-manager", { + body: root, + }); - sessions.forEach((session) => { - const sessionItem = document.createElement("div"); - sessionItem.style.padding = "8px"; - sessionItem.style.border = "1px solid #ccc"; - sessionItem.style.marginBottom = "8px"; - - const name = document.createElement("h3"); - name.textContent = session.name || `Session ${session.id}`; - sessionItem.appendChild(name); - - const openButton = sdk.ui.button({ - variant: "primary", - label: "Open", - size: "small", - }); - openButton.addEventListener("click", () => { - sdk.replay.openTab(session.id); - sdk.navigation.goTo({ id: "replay" }); - }); - sessionItem.appendChild(openButton); - - const deleteButton = sdk.ui.button({ - variant: "secondary", - label: "Delete", - size: "small", - }); - deleteButton.addEventListener("click", async () => { - await sdk.replay.deleteSessions([session.id]); - refreshSessions(); - sdk.window.showToast("Session deleted", { variant: "success" }); - }); - sessionItem.appendChild(deleteButton); - - sessionsList.appendChild(sessionItem); - }); - }; + // Listen for session changes + sdk.replay.onCurrentSessionChange((event) => { + sdk.log.info("Current session changed to:", event.sessionId); + }); +}; +``` - // Collections list - const collectionsList = document.createElement("div"); - collectionsList.id = "collections-list"; +```vue + + + ``` ### Auto-Organize Sessions diff --git a/src/guides/request.md b/src/guides/request.md index d223f2b..65e9914 100644 --- a/src/guides/request.md +++ b/src/guides/request.md @@ -132,79 +132,30 @@ export function init(sdk: SDK) { By registering a command in the frontend, defining the command to make a backend call to execute the `sendRequest` function and then registering the function on the frontend - it can be called at the click of a button: -::: tip -
-To view the entire frontend script, expand the following: +### Calling from Frontend -``` ts -import type { Caido } from "@caido/sdk-frontend"; -import type { API } from "../../backend/src/index"; +To call the backend function from a Vue component: -import "./styles/index.css"; +```vue + -const createPage = (sdk: CaidoSDK) => { - const requestButton = sdk.ui.button({ - variant: "primary", - label: "Send Request", - }); - - requestButton.addEventListener("click", async () => { - await sending(sdk); - }); - - const headerText = document.createElement("h1"); - headerText.textContent = "Hello world!"; - - const subText = document.createElement("p"); - subText.textContent = "Lorem ipsum."; - - const bodyText = document.createElement("p"); - bodyText.textContent = "Paragraph."; - - const footerText = document.createElement("p"); - footerText.textContent = "Footer text."; - - const headerContainer = document.createElement("div"); - headerContainer.appendChild(headerText); - headerContainer.appendChild(subText); - headerContainer.appendChild(requestButton); - - const bodyContainer = document.createElement("div"); - bodyContainer.appendChild(bodyText); - - const card = sdk.ui.card({ - header: headerContainer, - body: bodyContainer, - footer: footerText, - }); - - sdk.navigation.addPage("/my-plugin-page", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); - sdk.sidebar.registerItem("My Plugin", "/my-plugin-page", { - icon: "fas fa-rocket", - }); - - sdk.commands.register(Commands.sending, { - name: "Send Request", - run: () => sending(sdk), - }); -}; + ``` -
+::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). ::: diff --git a/src/guides/rpc.md b/src/guides/rpc.md index 4371b8b..6c91b5c 100644 --- a/src/guides/rpc.md +++ b/src/guides/rpc.md @@ -74,148 +74,110 @@ Now that we've created our endpoint in the backend plugin, we can call `multiply ### /packages/frontend/src/index.ts -``` ts +```ts +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; + import type { Caido } from "@caido/sdk-frontend"; import type { API } from "../../backend/src/index.ts"; +import App from "./views/App.vue"; + export type CaidoSDK = Caido; -const createPage = (sdk: CaidoSDK) => { - - const resultText = document.createElement("p"); - resultText.textContent = "Result will appear here."; - - const inputA = document.createElement("input"); - inputA.type = "number"; - inputA.value = "0"; - inputA.style.color = "black"; - - const inputB = document.createElement("input"); - inputB.type = "number"; - inputB.value = "0"; - inputB.style.color = "black"; - - const calculateButton = sdk.ui.button({ - variant: "primary", - label: "Calculate", - }); - - calculateButton.addEventListener("click", async () => { - const a = Number(inputA.value); - const b = Number(inputB.value); - const result = await sdk.backend.multiply(a, b); - resultText.textContent = `Result: ${result}`; - }); - - const container = document.createElement("div"); - container.appendChild(inputA); - container.appendChild(inputB); - container.appendChild(calculateButton); - container.appendChild(resultText); - - const card = sdk.ui.card({ - body: container - }); - - sdk.navigation.addPage("/multiply-page", { - body: card - }); -} +export const init = (sdk: CaidoSDK) => { + const app = createApp(App); + + app.provide("sdk", sdk); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, + }); + + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", + }); + + app.mount(root); + + sdk.navigation.addPage("/multiply-page", { + body: root, + }); + + sdk.sidebar.registerItem("Multiply", "/multiply-page", { + icon: "fas fa-calculator", + }); +}; +``` -export function init(sdk: CaidoSDK) { - createPage(sdk); - - sdk.sidebar.registerItem("Multiply", "/multiply-page", { - icon: "fas fa-calculator" - }); -} +### /packages/frontend/src/views/App.vue + +```vue + + + ``` ### Script Breakdown -Again, we need to import the necessary type aliases: the base `SDK` and the `API` we just defined in the backend. +The frontend setup imports the necessary type aliases and creates a Vue application. The `CaidoSDK` type alias extends the base `Caido` type with the `API` we defined in the backend. -``` ts +```ts import type { Caido } from "@caido/sdk-frontend"; import type { API } from "../../backend/src/index.ts"; + +export type CaidoSDK = Caido; ``` -Next, we add the API to the SDK by creating the `CaidoSDK` type alias. +The Vue app is created with PrimeVue configured using the Classic preset. The SDK is provided to all components using Vue's dependency injection system. -``` ts -export type CaidoSDK = Caido; +```ts +const app = createApp(App); +app.provide("sdk", sdk); +app.use(PrimeVue, { unstyled: true, pt: Classic }); ``` -The page will include two input fields, one for each expected number parameter and a `

` tag that will be used to display the result. +The Vue component uses reactive refs for the input values and result. When the button is clicked, it calls `sdk.backend.multiply()` with the input values and updates the result display. ::: tip For additional documentation on creating a page - click [here](/guides/page.md). ::: -``` ts -const createPage = (sdk: CaidoSDK) => { - - const resultText = document.createElement("p"); - resultText.textContent = "Result will appear here."; - - const inputA = document.createElement("input"); - inputA.type = "number"; - inputA.value = "0"; - inputA.style.color = "black"; - - const inputB = document.createElement("input"); - inputB.type = "number"; - inputB.value = "0"; - inputB.style.color = "black"; -``` - -The page also includes a button, that when clicked will take the supplied input and use the values as the parameters for the `multiply` function which is called using `sdk.backend.multiply(a, b);`. To account for processing time, `await` is used. - -``` ts - const calculateButton = sdk.ui.button({ - variant: "primary", - label: "Calculate", - }); - - calculateButton.addEventListener("click", async () => { - const a = Number(inputA.value); - const b = Number(inputB.value); - const result = await sdk.backend.multiply(a, b); - resultText.textContent = `Result: ${result}`; - }); -``` - -The page elements are all grouped together and stored in the `container` variable which is then used as the `body` property value of the `sdk.ui.card({})` method. The page is then added to Caido using the `sdk.navigation.addPage()` method with the path of `"/multiply-page"`. Its content is the `card` we just defined. - -``` ts - const container = document.createElement("div"); - container.appendChild(inputA); - container.appendChild(inputB); - container.appendChild(calculateButton); - container.appendChild(resultText); - - const card = sdk.ui.card({ - body: container - }); - - sdk.navigation.addPage("/multiply-page", { - body: card - }); -} -``` - -Finally, we define an initialization function for the frontend that will generate this page when Caido loads our plugin. The `sdk.sidebar.registerItem()` method will add a tab for our plugin page to the left-hand side menu of Caido named `Multiply` with a calculator icon. - -``` ts -export function init(sdk: CaidoSDK) { - createPage(sdk); - - sdk.sidebar.registerItem("Multiply", "/multiply-page", { - icon: "fas fa-calculator" - }); -} -``` - ## The Result Calling the API. diff --git a/src/guides/runtime.md b/src/guides/runtime.md index b34b5ec..7105a25 100644 --- a/src/guides/runtime.md +++ b/src/guides/runtime.md @@ -43,130 +43,30 @@ export const init = (sdk: CaidoSDK) => { ### Version Display -This example creates a page that displays the current Caido version and plugin compatibility status. It shows the version information in a formatted card with styling. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; - - const versionInfo = document.createElement("div"); - versionInfo.style.padding = "16px"; - versionInfo.style.backgroundColor = "#f5f5f5"; - versionInfo.style.borderRadius = "4px"; - - const version = sdk.runtime.version; - versionInfo.innerHTML = ` -

Caido Version

-

Version: ${version}

-

Plugin Compatibility: ✓ Compatible

- `; - - container.appendChild(versionInfo); - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/version-info", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); -}; -``` - -### Feature Detection - -This example implements a feature availability checker that determines if specific features are available based on the Caido version. It checks version requirements for features like "advanced-filters" and "ai-integration" and enables or disables features accordingly. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const checkFeatureAvailability = (sdk: CaidoSDK, feature: string): boolean => { - const version = sdk.runtime.version; - const [major, minor] = version.split(".").map(Number); - - // Feature availability based on version - const features: Record = { - "advanced-filters": { minMajor: 1, minMinor: 3 }, - "ai-integration": { minMajor: 1, minMinor: 5 }, - }; - - const requirement = features[feature]; - if (!requirement) { - return true; // Unknown feature, assume available - } - - return ( - major > requirement.minMajor || - (major === requirement.minMajor && minor >= requirement.minMinor) - ); -}; - -export const init = (sdk: CaidoSDK) => { - if (checkFeatureAvailability(sdk, "advanced-filters")) { - sdk.log.info("Advanced filters are available"); - // Enable advanced filter features - } else { - sdk.log.warn("Advanced filters require Caido 1.3.0 or higher"); - // Use fallback features - } -}; +This example displays the current Caido version and plugin compatibility status. + +```vue + + + ``` -### Compatibility Check - -This example performs a comprehensive version compatibility check with a custom version comparison function. If the version is incompatible, it displays an error toast and prevents plugin initialization, otherwise it logs successful initialization. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const MIN_VERSION = "1.2.0"; - -const compareVersions = (v1: string, v2: string): number => { - const parts1 = v1.split(".").map(Number); - const parts2 = v2.split(".").map(Number); - - for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { - const part1 = parts1[i] || 0; - const part2 = parts2[i] || 0; - - if (part1 < part2) return -1; - if (part1 > part2) return 1; - } - - return 0; -}; - -export const init = (sdk: CaidoSDK) => { - const version = sdk.runtime.version; - - if (compareVersions(version, MIN_VERSION) < 0) { - sdk.window.showToast( - `This plugin requires Caido ${MIN_VERSION} or higher. Current version: ${version}`, - { variant: "error", duration: 5000 } - ); - sdk.log.error(`Version mismatch: ${version} < ${MIN_VERSION}`); - return; - } - - sdk.log.info(`Plugin initialized on Caido ${version}`); -}; -``` +::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). +::: ::: tip Use version checks to ensure your plugin works correctly across different Caido versions and to provide helpful error messages when requirements aren't met. diff --git a/src/guides/scopes.md b/src/guides/scopes.md index 92b112e..23f14d2 100644 --- a/src/guides/scopes.md +++ b/src/guides/scopes.md @@ -129,98 +129,104 @@ const scope = await sdk.scopes.createScope({ This example creates a scope management interface that lists all scopes with their allowlists and denylists. It provides buttons to create new scopes and delete existing ones, with automatic list refreshing. ```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; +import { Classic } from "@caido/primevue"; +import PrimeVue from "primevue/config"; +import { createApp } from "vue"; - // Scope list - const scopeList = document.createElement("div"); - scopeList.id = "scope-list"; - - const refreshScopeList = () => { - scopeList.innerHTML = ""; - const scopes = sdk.scopes.getScopes(); - - if (scopes.length === 0) { - scopeList.textContent = "No scopes found"; - return; - } - - scopes.forEach((scope) => { - const scopeItem = document.createElement("div"); - scopeItem.style.padding = "8px"; - scopeItem.style.border = "1px solid #ccc"; - scopeItem.style.marginBottom = "8px"; +import type { Caido } from "@caido/sdk-frontend"; - const name = document.createElement("h3"); - name.textContent = scope.name; - scopeItem.appendChild(name); +import App from "./views/App.vue"; - const allowlist = document.createElement("p"); - allowlist.textContent = `Allowlist: ${scope.allowlist.join(", ")}`; - scopeItem.appendChild(allowlist); +export type CaidoSDK = Caido; - const denylist = document.createElement("p"); - denylist.textContent = `Denylist: ${scope.denylist.join(", ")}`; - scopeItem.appendChild(denylist); +export const init = (sdk: CaidoSDK) => { + const app = createApp(App); + + app.provide("sdk", sdk); + + app.use(PrimeVue, { + unstyled: true, + pt: Classic, + }); - const deleteButton = sdk.ui.button({ - variant: "secondary", - label: "Delete", - size: "small", - }); - deleteButton.addEventListener("click", async () => { - await sdk.scopes.deleteScope(scope.id); - refreshScopeList(); - sdk.window.showToast("Scope deleted", { variant: "success" }); - }); - scopeItem.appendChild(deleteButton); + const root = document.createElement("div"); + Object.assign(root.style, { + height: "100%", + width: "100%", + }); - scopeList.appendChild(scopeItem); - }); - }; + app.mount(root); - // Create scope button - const createButton = sdk.ui.button({ - variant: "primary", - label: "Create New Scope", - }); - createButton.addEventListener("click", async () => { - const scope = await sdk.scopes.createScope({ - name: `Scope ${Date.now()}`, - allowlist: ["*example.com"], - denylist: [], - }); - if (scope) { - refreshScopeList(); - sdk.window.showToast("Scope created", { variant: "success" }); - } + sdk.navigation.addPage("/scope-manager", { + body: root, }); +}; +``` - container.appendChild(createButton); - container.appendChild(scopeList); +```vue + + + ``` ### Setting Scope on Page Navigation diff --git a/src/guides/utf.md b/src/guides/utf.md index 48b886f..2073602 100644 --- a/src/guides/utf.md +++ b/src/guides/utf.md @@ -85,60 +85,30 @@ export function init(sdk: SDK) { } ``` -::: tip -
-To view the entire frontend script, expand the following: +### Calling from Frontend -``` ts -import type { Caido } from "@caido/sdk-frontend"; -import type { API } from "../../backend/src/index"; - -import "./styles/index.css"; +To call the backend function from a Vue component: -export type CaidoSDK = Caido; +```vue + -const createPage = (sdk: CaidoSDK) => { - const requestButton = sdk.ui.button({ - variant: "primary", - label: "Send Request", - }); - - requestButton.addEventListener("click", async () => { - await sending(sdk); - }); - - const bodyContainer = document.createElement("div"); - bodyContainer.appendChild(requestButton); - - const card = sdk.ui.card({ - body: bodyContainer, - - }); - - sdk.navigation.addPage("/my-plugin-page", { - body: card, - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); - sdk.sidebar.registerItem("My Plugin", "/my-plugin-page", { - icon: "fas fa-rocket", - }); - - sdk.commands.register(Commands.sending, { - name: "Send Request", - run: () => sending(sdk), - }); -}; + ``` -
+::: info +For information on creating pages and setting up Vue components, see [Create a Page](/guides/page.md). +::: diff --git a/src/guides/view_modes.md b/src/guides/view_modes.md index 9149fee..607c6c2 100644 --- a/src/guides/view_modes.md +++ b/src/guides/view_modes.md @@ -135,96 +135,6 @@ export const init = (sdk: CaidoSDK) => { }; ``` -### Visual Request Builder - -An interactive form view that displays request method, URL, and headers as editable form fields. - -```vue - - - -``` - -```ts -import type { Caido } from "@caido/sdk-frontend"; -import VisualBuilderView from "./VisualBuilderView.vue"; - -export type CaidoSDK = Caido; - -export const init = (sdk: CaidoSDK) => { - sdk.httpHistory.addRequestViewMode({ - label: "Visual Builder", - view: { - component: VisualBuilderView, - }, - }); -}; -``` - ### Editable Request View A view mode for Intercept or Replay that allows editing the request using the `requestDraft` prop. diff --git a/src/guides/workflows.md b/src/guides/workflows.md index b2b55d6..95115a9 100644 --- a/src/guides/workflows.md +++ b/src/guides/workflows.md @@ -59,107 +59,6 @@ Be mindful of performance when subscribing to workflow events. Avoid performing ## Examples -### Workflow Monitor Plugin - -This example creates a page that displays all workflows and maintains a real-time event log. It subscribes to workflow creation, update, and deletion events, updating both the workflow list and event log whenever changes occur. - -```ts -import type { Caido } from "@caido/sdk-frontend"; - -export type CaidoSDK = Caido; - -const createPage = (sdk: CaidoSDK) => { - const container = document.createElement("div"); - container.style.padding = "20px"; - container.style.display = "flex"; - container.style.flexDirection = "column"; - container.style.gap = "16px"; - - // Workflows list - const workflowsList = document.createElement("div"); - workflowsList.id = "workflows-list"; - - const refreshWorkflows = () => { - workflowsList.innerHTML = ""; - const workflows = sdk.workflows.getWorkflows(); - - if (workflows.length === 0) { - workflowsList.textContent = "No workflows found"; - return; - } - - workflows.forEach((workflow) => { - const workflowItem = document.createElement("div"); - workflowItem.style.padding = "8px"; - workflowItem.style.border = "1px solid #ccc"; - workflowItem.style.marginBottom = "8px"; - - const name = document.createElement("h3"); - name.textContent = workflow.name || `Workflow ${workflow.id}`; - workflowItem.appendChild(name); - - const id = document.createElement("p"); - id.textContent = `ID: ${workflow.id}`; - id.style.fontSize = "12px"; - id.style.color = "#666"; - workflowItem.appendChild(id); - - workflowsList.appendChild(workflowItem); - }); - }; - - // Event log - const eventLog = document.createElement("div"); - eventLog.id = "event-log"; - eventLog.style.maxHeight = "300px"; - eventLog.style.overflowY = "auto"; - eventLog.style.padding = "8px"; - eventLog.style.backgroundColor = "#f5f5f5"; - eventLog.style.borderRadius = "4px"; - - const addLogEntry = (message: string) => { - const entry = document.createElement("div"); - entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; - entry.style.marginBottom = "4px"; - eventLog.appendChild(entry); - eventLog.scrollTop = eventLog.scrollHeight; - }; - - container.appendChild(workflowsList); - container.appendChild(eventLog); - - refreshWorkflows(); - - const card = sdk.ui.card({ - body: container, - }); - - sdk.navigation.addPage("/workflow-monitor", { - body: card, - }); - - // Subscribe to workflow events - sdk.workflows.onCreatedWorkflow((workflow) => { - addLogEntry(`Workflow created: ${workflow.name}`); - refreshWorkflows(); - }); - - sdk.workflows.onUpdatedWorkflow((workflow) => { - addLogEntry(`Workflow updated: ${workflow.name}`); - refreshWorkflows(); - }); - - sdk.workflows.onDeletedWorkflow((workflowId) => { - addLogEntry(`Workflow deleted: ${workflowId}`); - refreshWorkflows(); - }); -}; - -export const init = (sdk: CaidoSDK) => { - createPage(sdk); -}; -``` - ### Workflow Automation This example demonstrates reactive workflow management by subscribing to workflow lifecycle events. It logs workflow changes and can trigger automation, notifications, or UI updates when workflows are created, updated, or deleted. From 569c2e6847496ab2611186eeffbd4d81daf837a4 Mon Sep 17 00:00:00 2001 From: corb3nik Date: Fri, 28 Nov 2025 21:22:46 -0500 Subject: [PATCH 3/3] More tooltip placement fixes --- src/guides/ai.md | 16 ++++++++-------- src/guides/application_events.md | 16 ++++++++-------- src/guides/assets.md | 16 ++++++++-------- src/guides/filters.md | 8 ++++---- src/guides/frontend_storage.md | 8 ++++---- src/guides/match_replace.md | 16 ++++++++-------- src/guides/navigation_events.md | 8 ++++---- src/guides/replay.md | 16 ++++++++-------- src/guides/slots.md | 16 ++++++++-------- src/guides/workflows.md | 16 ++++++++-------- 10 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/guides/ai.md b/src/guides/ai.md index 9fe126a..cd3656a 100644 --- a/src/guides/ai.md +++ b/src/guides/ai.md @@ -12,6 +12,14 @@ const provider = sdk.ai.createProvider(); This returns an `AIProvider` instance that can be used with the `ai` library. +::: tip +The AI provider is compatible with all features of the `ai` library, including text generation, streaming, tool calling, and more. Refer to the [ai SDK documentation](https://ai-sdk.dev/) for advanced usage. +::: + +::: info +The AI provider uses Caido's configured AI settings. Users can configure their AI provider preferences in Caido's settings. +::: + ::: warning AI operations can be resource-intensive and may have rate limits. Consider implementing error handling and user feedback for long-running AI operations. ::: @@ -86,11 +94,3 @@ export const init = (sdk: CaidoSDK) => { sdk.commandPalette.register("ai-generate-code"); }; ``` - -::: tip -The AI provider is compatible with all features of the `ai` library, including text generation, streaming, tool calling, and more. Refer to the [ai SDK documentation](https://ai-sdk.dev/) for advanced usage. -::: - -::: info -The AI provider uses Caido's configured AI settings. Users can configure their AI provider preferences in Caido's settings. -::: diff --git a/src/guides/application_events.md b/src/guides/application_events.md index ebc3c5c..2d35f7c 100644 --- a/src/guides/application_events.md +++ b/src/guides/application_events.md @@ -2,6 +2,10 @@ You can subscribe to various application events to react to state changes in Caido, such as project selection, workflow lifecycle, replay session changes, and backend plugin events. +::: tip +Application events enable reactive programming patterns. Use them to keep your plugin's state synchronized with Caido's state. +::: + ## Subscribing to Backend Plugin Events To listen for events sent from your backend plugin: @@ -35,6 +39,10 @@ const handler = sdk.projects.onCurrentProjectChange((event) => { handler.stop(); ``` +::: info +All event subscription methods return a `ListenerHandle` with a `stop()` method. Call `stop()` when your plugin is unloaded to prevent memory leaks. +::: + ## Subscribing to Workflow Events ### Workflow Created @@ -163,11 +171,3 @@ export const init = (sdk: CaidoSDK) => { }); }; ``` - -::: tip -Application events enable reactive programming patterns. Use them to keep your plugin's state synchronized with Caido's state. -::: - -::: info -All event subscription methods return a `ListenerHandle` with a `stop()` method. Call `stop()` when your plugin is unloaded to prevent memory leaks. -::: diff --git a/src/guides/assets.md b/src/guides/assets.md index 22ed608..c8d5450 100644 --- a/src/guides/assets.md +++ b/src/guides/assets.md @@ -40,6 +40,10 @@ const buffer = await asset.asArrayBuffer(); const stream = asset.asReadableStream(); ``` +::: tip +Use `asReadableStream()` for large files to process them in chunks and avoid loading the entire file into memory. +::: + ## Asset Path Configuration Assets are configured in your `caido.config.ts`: @@ -52,6 +56,10 @@ export default defineConfig({ }); ``` +::: info +Asset paths are relative to your plugin's assets directory. Use glob patterns in your config to include multiple files. +::: + ::: warning Assets are bundled with your plugin, so large files will increase the plugin size. Consider loading external resources at runtime for very large files. ::: @@ -118,11 +126,3 @@ export const init = async (sdk: CaidoSDK) => { } }; ``` - -::: tip -Use `asReadableStream()` for large files to process them in chunks and avoid loading the entire file into memory. -::: - -::: info -Asset paths are relative to your plugin's assets directory. Use glob patterns in your config to include multiple files. -::: diff --git a/src/guides/filters.md b/src/guides/filters.md index afe0607..c3d0b85 100644 --- a/src/guides/filters.md +++ b/src/guides/filters.md @@ -20,6 +20,10 @@ const filter = await sdk.filters.create({ - `alias` - A short identifier used in HTTPQL queries (e.g., `preset:my-filter`) - `query` - The HTTPQL query expression +::: tip +Use saved filters to create reusable query presets that can be referenced with the `preset:` prefix in HTTPQL queries. +::: + ### Getting All Filters To retrieve all saved filters: @@ -224,7 +228,3 @@ const filter = await sdk.filters.create({ // Use the filter in a query sdk.httpHistory.setQuery("preset:success-get"); ``` - -::: tip -Use saved filters to create reusable query presets that can be referenced with the `preset:` prefix in HTTPQL queries. -::: diff --git a/src/guides/frontend_storage.md b/src/guides/frontend_storage.md index a1e94a2..325c6e1 100644 --- a/src/guides/frontend_storage.md +++ b/src/guides/frontend_storage.md @@ -12,6 +12,10 @@ The storage system is defined by the [StorageSDK](/reference/sdks/frontend/#sdk) Stored data needs to be JSON serializable. ::: +::: info +Although frontend storage actually exists in the backend, it is inaccessible by the backend component. To share data with the backend component of a plugin, you will need to [create and call a custom function](/guides/rpc.md). +::: + ## User Preferences To demonstrate its usage, let's create a frontend interface that offers light and dark theme options. @@ -215,7 +219,3 @@ A button for both themes are added to the user interface that will call the `upd ``` - -::: info -Although frontend storage actually exists in the backend, it is inaccessible by the backend component. To share data with the backend component of a plugin, you will need to [create and call a custom function](/guides/rpc.md). -::: diff --git a/src/guides/match_replace.md b/src/guides/match_replace.md index 0ec3665..d5c8ba1 100644 --- a/src/guides/match_replace.md +++ b/src/guides/match_replace.md @@ -22,6 +22,10 @@ To retrieve all collections: const collections = sdk.matchReplace.getCollections(); ``` +::: tip +Use collections to organize related match and replace rules, making it easier to enable/disable groups of rules together. +::: + ### Updating a Collection To update a collection: @@ -79,6 +83,10 @@ const activeRules = sdk.matchReplace.getActiveRules(); Rules are returned in priority order from highest to lowest. +::: info +Active rules are processed in priority order. Higher priority rules are applied first. Use `getActiveRules()` to see the processing order. +::: + ### Updating a Rule To update a rule: @@ -176,11 +184,3 @@ export const init = (sdk: CaidoSDK) => { }); }; ``` - -::: tip -Use collections to organize related match and replace rules, making it easier to enable/disable groups of rules together. -::: - -::: info -Active rules are processed in priority order. Higher priority rules are applied first. Use `getActiveRules()` to see the processing order. -::: diff --git a/src/guides/navigation_events.md b/src/guides/navigation_events.md index 5b5f1e4..39668a6 100644 --- a/src/guides/navigation_events.md +++ b/src/guides/navigation_events.md @@ -18,6 +18,10 @@ The callback receives a `PageChangeEvent` object containing: - `routeId` - The route ID of the new page - `path` - The path of the new page +::: tip +Use page change events to optimize performance by only loading resources when needed for specific pages. +::: + ::: info The `onPageChange` callback is called after the page has changed. To perform actions before navigation, you may need to use other mechanisms depending on your use case. ::: @@ -117,7 +121,3 @@ export const init = (sdk: CaidoSDK) => { }); }; ``` - -::: tip -Use page change events to optimize performance by only loading resources when needed for specific pages. -::: diff --git a/src/guides/replay.md b/src/guides/replay.md index a1b93ad..549e663 100644 --- a/src/guides/replay.md +++ b/src/guides/replay.md @@ -50,6 +50,10 @@ To create a new collection: const collection = await sdk.replay.createCollection("My Collection"); ``` +::: tip +Use collections to organize related replay sessions, making it easier to manage and find specific sessions for testing scenarios. +::: + ### Getting Collections To retrieve all collections: @@ -129,6 +133,10 @@ const handler = sdk.replay.onCurrentSessionChange((event) => { handler.stop(); ``` +::: info +Sessions and collections are persisted across Caido restarts, so programmatically created items will remain available. +::: + ## Examples ### Session Manager Plugin @@ -328,11 +336,3 @@ export const init = (sdk: CaidoSDK) => { initializeCollection(); }; ``` - -::: tip -Use collections to organize related replay sessions, making it easier to manage and find specific sessions for testing scenarios. -::: - -::: info -Sessions and collections are persisted across Caido restarts, so programmatically created items will remain available. -::: diff --git a/src/guides/slots.md b/src/guides/slots.md index 030dcc9..697949b 100644 --- a/src/guides/slots.md +++ b/src/guides/slots.md @@ -124,6 +124,14 @@ import { ReplaySlot } from "@caido/sdk-frontend"; Be mindful of slot space limitations. Too many items in a slot can clutter the interface. Consider grouping related actions or using custom components to organize multiple controls. ::: +::: tip +Slots are a powerful way to extend Caido's UI without creating custom pages. Use them to add plugin-specific functionality that integrates seamlessly with the existing interface. +::: + +::: info +Slot content is rendered when the relevant page is active. For footer slots, content is always visible. For Replay slots, content is only visible on the Replay page. +::: + ## Examples ### Footer Actions @@ -242,11 +250,3 @@ export const init = (sdk: CaidoSDK) => { }); }; ``` - -::: tip -Slots are a powerful way to extend Caido's UI without creating custom pages. Use them to add plugin-specific functionality that integrates seamlessly with the existing interface. -::: - -::: info -Slot content is rendered when the relevant page is active. For footer slots, content is always visible. For Replay slots, content is only visible on the Replay page. -::: diff --git a/src/guides/workflows.md b/src/guides/workflows.md index 95115a9..670871c 100644 --- a/src/guides/workflows.md +++ b/src/guides/workflows.md @@ -14,6 +14,14 @@ const workflows = sdk.workflows.getWorkflows(); You can subscribe to three types of workflow events: +::: tip +Use workflow events to keep your plugin's state synchronized with workflow changes, enabling reactive behavior and automation. +::: + +::: info +Workflow events are fired for all workflow changes, not just those made by your plugin. This allows you to react to user actions and other plugin modifications. +::: + ### Workflow Created To listen for when a workflow is created: @@ -126,11 +134,3 @@ export const init = (sdk: CaidoSDK) => { }); }; ``` - -::: tip -Use workflow events to keep your plugin's state synchronized with workflow changes, enabling reactive behavior and automation. -::: - -::: info -Workflow events are fired for all workflow changes, not just those made by your plugin. This allows you to react to user actions and other plugin modifications. -:::