mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-06-07 23:22:47 +02:00
Run oxfmt across repo, add format script and docs
Add .oxfmtignore to skip generated bindings and wasm-pack output. Add npm format script, update DEVELOPMENT.md for Vite+ toolchain, and format all non-generated files with oxfmt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,16 +4,16 @@ export function formatSize(bytes: number): string {
|
||||
|
||||
if (bytes > 1000 * 1000 * 1000) {
|
||||
num = bytes / 1000 / 1000 / 1000;
|
||||
unit = 'GB';
|
||||
unit = "GB";
|
||||
} else if (bytes > 1000 * 1000) {
|
||||
num = bytes / 1000 / 1000;
|
||||
unit = 'MB';
|
||||
unit = "MB";
|
||||
} else if (bytes > 1000) {
|
||||
num = bytes / 1000;
|
||||
unit = 'KB';
|
||||
unit = "KB";
|
||||
} else {
|
||||
num = bytes;
|
||||
unit = 'B';
|
||||
unit = "B";
|
||||
}
|
||||
|
||||
return `${Math.round(num * 10) / 10} ${unit}`;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './debounce';
|
||||
export * from './formatSize';
|
||||
export * from './templateFunction';
|
||||
export * from "./debounce";
|
||||
export * from "./formatSize";
|
||||
export * from "./templateFunction";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@yaakapp-internal/lib",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "index.ts"
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@ import type {
|
||||
CallTemplateFunctionArgs,
|
||||
JsonPrimitive,
|
||||
TemplateFunctionArg,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
} from "@yaakapp-internal/plugins";
|
||||
|
||||
export function validateTemplateFunctionArgs(
|
||||
fnName: string,
|
||||
args: TemplateFunctionArg[],
|
||||
values: CallTemplateFunctionArgs['values'],
|
||||
values: CallTemplateFunctionArgs["values"],
|
||||
): string | null {
|
||||
for (const arg of args) {
|
||||
if ('inputs' in arg && arg.inputs) {
|
||||
if ("inputs" in arg && arg.inputs) {
|
||||
// Recurse down
|
||||
const err = validateTemplateFunctionArgs(fnName, arg.inputs, values);
|
||||
if (err) return err;
|
||||
}
|
||||
if (!('name' in arg)) continue;
|
||||
if (!("name" in arg)) continue;
|
||||
if (arg.optional) continue;
|
||||
if (arg.defaultValue != null) continue;
|
||||
if (arg.hidden) continue;
|
||||
@@ -34,14 +34,14 @@ export function applyFormInputDefaults(
|
||||
) {
|
||||
let newValues: { [p: string]: JsonPrimitive | undefined } = { ...values };
|
||||
for (const input of inputs) {
|
||||
if ('defaultValue' in input && values[input.name] === undefined) {
|
||||
if ("defaultValue" in input && values[input.name] === undefined) {
|
||||
newValues[input.name] = input.defaultValue;
|
||||
}
|
||||
if (input.type === 'checkbox' && values[input.name] === undefined) {
|
||||
if (input.type === "checkbox" && values[input.name] === undefined) {
|
||||
newValues[input.name] = false;
|
||||
}
|
||||
// Recurse down to all child inputs
|
||||
if ('inputs' in input) {
|
||||
if ("inputs" in input) {
|
||||
newValues = applyFormInputDefaults(input.inputs ?? [], newValues);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,23 +3,23 @@
|
||||
"version": "0.8.0",
|
||||
"keywords": [
|
||||
"api-client",
|
||||
"insomnia-alternative",
|
||||
"bruno-alternative",
|
||||
"insomnia-alternative",
|
||||
"postman-alternative"
|
||||
],
|
||||
"homepage": "https://yaak.app",
|
||||
"bugs": {
|
||||
"url": "https://feedback.yaak.app"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mountain-loop/yaak"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://feedback.yaak.app"
|
||||
},
|
||||
"homepage": "https://yaak.app",
|
||||
"main": "lib/index.js",
|
||||
"typings": "./lib/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"typings": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"bootstrap": "npm run build",
|
||||
"build": "run-s build:copy-types build:tsc",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export type * from './plugins';
|
||||
export type * from './themes';
|
||||
export type * from "./plugins";
|
||||
export type * from "./themes";
|
||||
|
||||
export * from './bindings/gen_models';
|
||||
export * from './bindings/gen_events';
|
||||
export * from "./bindings/gen_models";
|
||||
export * from "./bindings/gen_events";
|
||||
|
||||
// Some extras for utility
|
||||
|
||||
export type { PartialImportResources } from './plugins/ImporterPlugin';
|
||||
export type { PartialImportResources } from "./plugins/ImporterPlugin";
|
||||
|
||||
@@ -5,9 +5,9 @@ import type {
|
||||
FormInput,
|
||||
GetHttpAuthenticationSummaryResponse,
|
||||
HttpAuthenticationAction,
|
||||
} from '../bindings/gen_events';
|
||||
import type { MaybePromise } from '../helpers';
|
||||
import type { Context } from './Context';
|
||||
} from "../bindings/gen_events";
|
||||
import type { MaybePromise } from "../helpers";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
type AddDynamicMethod<T> = {
|
||||
dynamic?: (
|
||||
@@ -19,13 +19,13 @@ type AddDynamicMethod<T> = {
|
||||
// oxlint-disable-next-line no-explicit-any -- distributive conditional type pattern
|
||||
type AddDynamic<T> = T extends any
|
||||
? T extends { inputs?: FormInput[] }
|
||||
? Omit<T, 'inputs'> & {
|
||||
? Omit<T, "inputs"> & {
|
||||
inputs: Array<AddDynamic<FormInput>>;
|
||||
dynamic?: (
|
||||
ctx: Context,
|
||||
args: CallHttpAuthenticationActionArgs,
|
||||
) => MaybePromise<
|
||||
Partial<Omit<T, 'inputs'> & { inputs: Array<AddDynamic<FormInput>> }> | null | undefined
|
||||
Partial<Omit<T, "inputs"> & { inputs: Array<AddDynamic<FormInput>> }> | null | undefined
|
||||
>;
|
||||
}
|
||||
: T & AddDynamicMethod<T>
|
||||
|
||||
@@ -26,10 +26,10 @@ import type {
|
||||
ShowToastRequest,
|
||||
TemplateRenderRequest,
|
||||
WorkspaceInfo,
|
||||
} from '../bindings/gen_events.ts';
|
||||
import type { Folder, HttpRequest } from '../bindings/gen_models.ts';
|
||||
import type { JsonValue } from '../bindings/serde_json/JsonValue';
|
||||
import type { MaybePromise } from '../helpers';
|
||||
} from "../bindings/gen_events.ts";
|
||||
import type { Folder, HttpRequest } from "../bindings/gen_models.ts";
|
||||
import type { JsonValue } from "../bindings/serde_json/JsonValue";
|
||||
import type { MaybePromise } from "../helpers";
|
||||
|
||||
export type CallPromptFormDynamicArgs = {
|
||||
values: { [key in string]?: JsonPrimitive };
|
||||
@@ -45,13 +45,13 @@ type AddDynamicMethod<T> = {
|
||||
// oxlint-disable-next-line no-explicit-any -- distributive conditional type pattern
|
||||
type AddDynamic<T> = T extends any
|
||||
? T extends { inputs?: FormInput[] }
|
||||
? Omit<T, 'inputs'> & {
|
||||
? Omit<T, "inputs"> & {
|
||||
inputs: Array<AddDynamic<FormInput>>;
|
||||
dynamic?: (
|
||||
ctx: Context,
|
||||
args: CallPromptFormDynamicArgs,
|
||||
) => MaybePromise<
|
||||
Partial<Omit<T, 'inputs'> & { inputs: Array<AddDynamic<FormInput>> }> | null | undefined
|
||||
Partial<Omit<T, "inputs"> & { inputs: Array<AddDynamic<FormInput>> }> | null | undefined
|
||||
>;
|
||||
}
|
||||
: T & AddDynamicMethod<T>
|
||||
@@ -59,11 +59,11 @@ type AddDynamic<T> = T extends any
|
||||
|
||||
export type DynamicPromptFormArg = AddDynamic<FormInput>;
|
||||
|
||||
type DynamicPromptFormRequest = Omit<PromptFormRequest, 'inputs'> & {
|
||||
type DynamicPromptFormRequest = Omit<PromptFormRequest, "inputs"> & {
|
||||
inputs: DynamicPromptFormArg[];
|
||||
};
|
||||
|
||||
export type WorkspaceHandle = Pick<WorkspaceInfo, 'id' | 'name'>;
|
||||
export type WorkspaceHandle = Pick<WorkspaceInfo, "id" | "name">;
|
||||
|
||||
export interface Context {
|
||||
clipboard: {
|
||||
@@ -73,8 +73,8 @@ export interface Context {
|
||||
show(args: ShowToastRequest): Promise<void>;
|
||||
};
|
||||
prompt: {
|
||||
text(args: PromptTextRequest): Promise<PromptTextResponse['value']>;
|
||||
form(args: DynamicPromptFormRequest): Promise<PromptFormResponse['values']>;
|
||||
text(args: PromptTextRequest): Promise<PromptTextResponse["value"]>;
|
||||
form(args: DynamicPromptFormRequest): Promise<PromptFormResponse["values"]>;
|
||||
};
|
||||
store: {
|
||||
set<T>(key: string, value: T): Promise<void>;
|
||||
@@ -94,41 +94,41 @@ export interface Context {
|
||||
openExternalUrl(url: string): Promise<void>;
|
||||
};
|
||||
cookies: {
|
||||
listNames(): Promise<ListCookieNamesResponse['names']>;
|
||||
getValue(args: GetCookieValueRequest): Promise<GetCookieValueResponse['value']>;
|
||||
listNames(): Promise<ListCookieNamesResponse["names"]>;
|
||||
getValue(args: GetCookieValueRequest): Promise<GetCookieValueResponse["value"]>;
|
||||
};
|
||||
grpcRequest: {
|
||||
render(args: RenderGrpcRequestRequest): Promise<RenderGrpcRequestResponse['grpcRequest']>;
|
||||
render(args: RenderGrpcRequestRequest): Promise<RenderGrpcRequestResponse["grpcRequest"]>;
|
||||
};
|
||||
httpRequest: {
|
||||
send(args: SendHttpRequestRequest): Promise<SendHttpRequestResponse['httpResponse']>;
|
||||
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse['httpRequest']>;
|
||||
render(args: RenderHttpRequestRequest): Promise<RenderHttpRequestResponse['httpRequest']>;
|
||||
list(args?: ListHttpRequestsRequest): Promise<ListHttpRequestsResponse['httpRequests']>;
|
||||
send(args: SendHttpRequestRequest): Promise<SendHttpRequestResponse["httpResponse"]>;
|
||||
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse["httpRequest"]>;
|
||||
render(args: RenderHttpRequestRequest): Promise<RenderHttpRequestResponse["httpRequest"]>;
|
||||
list(args?: ListHttpRequestsRequest): Promise<ListHttpRequestsResponse["httpRequests"]>;
|
||||
create(
|
||||
args: Omit<Partial<HttpRequest>, 'id' | 'model' | 'createdAt' | 'updatedAt'> &
|
||||
Pick<HttpRequest, 'workspaceId' | 'url'>,
|
||||
args: Omit<Partial<HttpRequest>, "id" | "model" | "createdAt" | "updatedAt"> &
|
||||
Pick<HttpRequest, "workspaceId" | "url">,
|
||||
): Promise<HttpRequest>;
|
||||
update(
|
||||
args: Omit<Partial<HttpRequest>, 'model' | 'createdAt' | 'updatedAt'> &
|
||||
Pick<HttpRequest, 'id'>,
|
||||
args: Omit<Partial<HttpRequest>, "model" | "createdAt" | "updatedAt"> &
|
||||
Pick<HttpRequest, "id">,
|
||||
): Promise<HttpRequest>;
|
||||
delete(args: { id: string }): Promise<HttpRequest>;
|
||||
};
|
||||
folder: {
|
||||
list(args?: ListFoldersRequest): Promise<ListFoldersResponse['folders']>;
|
||||
list(args?: ListFoldersRequest): Promise<ListFoldersResponse["folders"]>;
|
||||
getById(args: { id: string }): Promise<Folder | null>;
|
||||
create(
|
||||
args: Omit<Partial<Folder>, 'id' | 'model' | 'createdAt' | 'updatedAt'> &
|
||||
Pick<Folder, 'workspaceId' | 'name'>,
|
||||
args: Omit<Partial<Folder>, "id" | "model" | "createdAt" | "updatedAt"> &
|
||||
Pick<Folder, "workspaceId" | "name">,
|
||||
): Promise<Folder>;
|
||||
update(
|
||||
args: Omit<Partial<Folder>, 'model' | 'createdAt' | 'updatedAt'> & Pick<Folder, 'id'>,
|
||||
args: Omit<Partial<Folder>, "model" | "createdAt" | "updatedAt"> & Pick<Folder, "id">,
|
||||
): Promise<Folder>;
|
||||
delete(args: { id: string }): Promise<Folder>;
|
||||
};
|
||||
httpResponse: {
|
||||
find(args: FindHttpResponsesRequest): Promise<FindHttpResponsesResponse['httpResponses']>;
|
||||
find(args: FindHttpResponsesRequest): Promise<FindHttpResponsesResponse["httpResponses"]>;
|
||||
};
|
||||
templates: {
|
||||
render<T extends JsonValue>(args: TemplateRenderRequest & { data: T }): Promise<T>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { FilterResponse } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
import type { FilterResponse } from "../bindings/gen_events";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
export type FilterPlugin = {
|
||||
name: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CallFolderActionArgs, FolderAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
import type { CallFolderActionArgs, FolderAction } from "../bindings/gen_events";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
export type FolderActionPlugin = FolderAction & {
|
||||
onSelect(ctx: Context, args: CallFolderActionArgs): Promise<void> | void;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CallGrpcRequestActionArgs, GrpcRequestAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
import type { CallGrpcRequestActionArgs, GrpcRequestAction } from "../bindings/gen_events";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
export type GrpcRequestActionPlugin = GrpcRequestAction & {
|
||||
onSelect(ctx: Context, args: CallGrpcRequestActionArgs): Promise<void> | void;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CallHttpRequestActionArgs, HttpRequestAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
import type { CallHttpRequestActionArgs, HttpRequestAction } from "../bindings/gen_events";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
export type HttpRequestActionPlugin = HttpRequestAction & {
|
||||
onSelect(ctx: Context, args: CallHttpRequestActionArgs): Promise<void> | void;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import type { ImportResources } from '../bindings/gen_events';
|
||||
import type { AtLeast, MaybePromise } from '../helpers';
|
||||
import type { Context } from './Context';
|
||||
import type { ImportResources } from "../bindings/gen_events";
|
||||
import type { AtLeast, MaybePromise } from "../helpers";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
type RootFields = 'name' | 'id' | 'model';
|
||||
type CommonFields = RootFields | 'workspaceId';
|
||||
type RootFields = "name" | "id" | "model";
|
||||
type CommonFields = RootFields | "workspaceId";
|
||||
|
||||
export type PartialImportResources = {
|
||||
workspaces: Array<AtLeast<ImportResources['workspaces'][0], RootFields>>;
|
||||
environments: Array<AtLeast<ImportResources['environments'][0], CommonFields>>;
|
||||
folders: Array<AtLeast<ImportResources['folders'][0], CommonFields>>;
|
||||
httpRequests: Array<AtLeast<ImportResources['httpRequests'][0], CommonFields>>;
|
||||
grpcRequests: Array<AtLeast<ImportResources['grpcRequests'][0], CommonFields>>;
|
||||
websocketRequests: Array<AtLeast<ImportResources['websocketRequests'][0], CommonFields>>;
|
||||
workspaces: Array<AtLeast<ImportResources["workspaces"][0], RootFields>>;
|
||||
environments: Array<AtLeast<ImportResources["environments"][0], CommonFields>>;
|
||||
folders: Array<AtLeast<ImportResources["folders"][0], CommonFields>>;
|
||||
httpRequests: Array<AtLeast<ImportResources["httpRequests"][0], CommonFields>>;
|
||||
grpcRequests: Array<AtLeast<ImportResources["grpcRequests"][0], CommonFields>>;
|
||||
websocketRequests: Array<AtLeast<ImportResources["websocketRequests"][0], CommonFields>>;
|
||||
};
|
||||
|
||||
export type ImportPluginResponse = null | {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CallTemplateFunctionArgs, FormInput, TemplateFunction } from '../bindings/gen_events';
|
||||
import type { MaybePromise } from '../helpers';
|
||||
import type { Context } from './Context';
|
||||
import type { CallTemplateFunctionArgs, FormInput, TemplateFunction } from "../bindings/gen_events";
|
||||
import type { MaybePromise } from "../helpers";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
type AddDynamicMethod<T> = {
|
||||
dynamic?: (
|
||||
@@ -12,13 +12,13 @@ type AddDynamicMethod<T> = {
|
||||
// oxlint-disable-next-line no-explicit-any -- distributive conditional type pattern
|
||||
type AddDynamic<T> = T extends any
|
||||
? T extends { inputs?: FormInput[] }
|
||||
? Omit<T, 'inputs'> & {
|
||||
? Omit<T, "inputs"> & {
|
||||
inputs: Array<AddDynamic<FormInput>>;
|
||||
dynamic?: (
|
||||
ctx: Context,
|
||||
args: CallTemplateFunctionArgs,
|
||||
) => MaybePromise<
|
||||
Partial<Omit<T, 'inputs'> & { inputs: Array<AddDynamic<FormInput>> }> | null | undefined
|
||||
Partial<Omit<T, "inputs"> & { inputs: Array<AddDynamic<FormInput>> }> | null | undefined
|
||||
>;
|
||||
}
|
||||
: T & AddDynamicMethod<T>
|
||||
@@ -26,7 +26,7 @@ type AddDynamic<T> = T extends any
|
||||
|
||||
export type DynamicTemplateFunctionArg = AddDynamic<FormInput>;
|
||||
|
||||
export type TemplateFunctionPlugin = Omit<TemplateFunction, 'args'> & {
|
||||
export type TemplateFunctionPlugin = Omit<TemplateFunction, "args"> & {
|
||||
args: DynamicTemplateFunctionArg[];
|
||||
onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise<string | null>;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import type { Theme } from '../bindings/gen_events';
|
||||
import type { Theme } from "../bindings/gen_events";
|
||||
|
||||
export type ThemePlugin = Theme;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type {
|
||||
CallWebsocketRequestActionArgs,
|
||||
WebsocketRequestAction,
|
||||
} from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
} from "../bindings/gen_events";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
export type WebsocketRequestActionPlugin = WebsocketRequestAction & {
|
||||
onSelect(ctx: Context, args: CallWebsocketRequestActionArgs): Promise<void> | void;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CallWorkspaceActionArgs, WorkspaceAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
import type { CallWorkspaceActionArgs, WorkspaceAction } from "../bindings/gen_events";
|
||||
import type { Context } from "./Context";
|
||||
|
||||
export type WorkspaceActionPlugin = WorkspaceAction & {
|
||||
onSelect(ctx: Context, args: CallWorkspaceActionArgs): Promise<void> | void;
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import type { AuthenticationPlugin } from './AuthenticationPlugin';
|
||||
import type { AuthenticationPlugin } from "./AuthenticationPlugin";
|
||||
|
||||
import type { Context } from './Context';
|
||||
import type { FilterPlugin } from './FilterPlugin';
|
||||
import type { FolderActionPlugin } from './FolderActionPlugin';
|
||||
import type { GrpcRequestActionPlugin } from './GrpcRequestActionPlugin';
|
||||
import type { HttpRequestActionPlugin } from './HttpRequestActionPlugin';
|
||||
import type { ImporterPlugin } from './ImporterPlugin';
|
||||
import type { TemplateFunctionPlugin } from './TemplateFunctionPlugin';
|
||||
import type { ThemePlugin } from './ThemePlugin';
|
||||
import type { WebsocketRequestActionPlugin } from './WebsocketRequestActionPlugin';
|
||||
import type { WorkspaceActionPlugin } from './WorkspaceActionPlugin';
|
||||
import type { Context } from "./Context";
|
||||
import type { FilterPlugin } from "./FilterPlugin";
|
||||
import type { FolderActionPlugin } from "./FolderActionPlugin";
|
||||
import type { GrpcRequestActionPlugin } from "./GrpcRequestActionPlugin";
|
||||
import type { HttpRequestActionPlugin } from "./HttpRequestActionPlugin";
|
||||
import type { ImporterPlugin } from "./ImporterPlugin";
|
||||
import type { TemplateFunctionPlugin } from "./TemplateFunctionPlugin";
|
||||
import type { ThemePlugin } from "./ThemePlugin";
|
||||
import type { WebsocketRequestActionPlugin } from "./WebsocketRequestActionPlugin";
|
||||
import type { WorkspaceActionPlugin } from "./WorkspaceActionPlugin";
|
||||
|
||||
export type { Context };
|
||||
export type { DynamicAuthenticationArg } from './AuthenticationPlugin';
|
||||
export type { CallPromptFormDynamicArgs, DynamicPromptFormArg } from './Context';
|
||||
export type { DynamicTemplateFunctionArg } from './TemplateFunctionPlugin';
|
||||
export type { DynamicAuthenticationArg } from "./AuthenticationPlugin";
|
||||
export type { CallPromptFormDynamicArgs, DynamicPromptFormArg } from "./Context";
|
||||
export type { DynamicTemplateFunctionArg } from "./TemplateFunctionPlugin";
|
||||
export type { TemplateFunctionPlugin };
|
||||
export type { FolderActionPlugin } from './FolderActionPlugin';
|
||||
export type { WorkspaceActionPlugin } from './WorkspaceActionPlugin';
|
||||
export type { FolderActionPlugin } from "./FolderActionPlugin";
|
||||
export type { WorkspaceActionPlugin } from "./WorkspaceActionPlugin";
|
||||
|
||||
/**
|
||||
* The global structure of a Yaak plugin
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { InternalEvent } from '@yaakapp/api';
|
||||
import type { InternalEvent } from "@yaakapp/api";
|
||||
|
||||
export class EventChannel {
|
||||
#listeners = new Set<(event: InternalEvent) => void>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { BootRequest, InternalEvent } from '@yaakapp/api';
|
||||
import type { PluginContext } from '@yaakapp-internal/plugins';
|
||||
import type { EventChannel } from './EventChannel';
|
||||
import { PluginInstance, type PluginWorkerData } from './PluginInstance';
|
||||
import type { BootRequest, InternalEvent } from "@yaakapp/api";
|
||||
import type { PluginContext } from "@yaakapp-internal/plugins";
|
||||
import type { EventChannel } from "./EventChannel";
|
||||
import { PluginInstance, type PluginWorkerData } from "./PluginInstance";
|
||||
|
||||
export class PluginHandle {
|
||||
#instance: PluginInstance;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import console from 'node:console';
|
||||
import { type Stats, statSync, watch } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import console from "node:console";
|
||||
import { type Stats, statSync, watch } from "node:fs";
|
||||
import path from "node:path";
|
||||
import type {
|
||||
CallPromptFormDynamicArgs,
|
||||
Context,
|
||||
DynamicPromptFormArg,
|
||||
PluginDefinition,
|
||||
} from '@yaakapp/api';
|
||||
} from "@yaakapp/api";
|
||||
import {
|
||||
applyFormInputDefaults,
|
||||
validateTemplateFunctionArgs,
|
||||
} from '@yaakapp-internal/lib/templateFunction';
|
||||
} from "@yaakapp-internal/lib/templateFunction";
|
||||
import type {
|
||||
BootRequest,
|
||||
DeleteKeyValueResponse,
|
||||
@@ -45,10 +45,10 @@ import type {
|
||||
TemplateRenderResponse,
|
||||
UpsertModelResponse,
|
||||
WindowInfoResponse,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
import { applyDynamicFormInput } from './common';
|
||||
import { EventChannel } from './EventChannel';
|
||||
import { migrateTemplateFunctionSelectOptions } from './migrations';
|
||||
} from "@yaakapp-internal/plugins";
|
||||
import { applyDynamicFormInput } from "./common";
|
||||
import { EventChannel } from "./EventChannel";
|
||||
import { migrateTemplateFunctionSelectOptions } from "./migrations";
|
||||
|
||||
export interface PluginWorkerData {
|
||||
bootRequest: BootRequest;
|
||||
@@ -84,16 +84,16 @@ export class PluginInstance {
|
||||
this.#sendPayload(
|
||||
workerData.context,
|
||||
{
|
||||
type: 'reload_response',
|
||||
type: "reload_response",
|
||||
silent: false,
|
||||
},
|
||||
null,
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
await ctx.toast.show({
|
||||
message: `Failed to initialize plugin ${this.#workerData.bootRequest.dir.split('/').pop()}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
color: 'notice',
|
||||
icon: 'alert_triangle',
|
||||
message: `Failed to initialize plugin ${this.#workerData.bootRequest.dir.split("/").pop()}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
color: "notice",
|
||||
icon: "alert_triangle",
|
||||
timeout: 30000,
|
||||
});
|
||||
}
|
||||
@@ -123,15 +123,15 @@ export class PluginInstance {
|
||||
const { context, payload, id: replyId } = event;
|
||||
|
||||
try {
|
||||
if (payload.type === 'boot_request') {
|
||||
if (payload.type === "boot_request") {
|
||||
await this.#mod?.init?.(ctx);
|
||||
this.#sendPayload(context, { type: 'boot_response' }, replyId);
|
||||
this.#sendPayload(context, { type: "boot_response" }, replyId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'terminate_request') {
|
||||
if (payload.type === "terminate_request") {
|
||||
const payload: InternalEventPayload = {
|
||||
type: 'terminate_response',
|
||||
type: "terminate_response",
|
||||
};
|
||||
await this.terminate();
|
||||
this.#sendPayload(context, payload, replyId);
|
||||
@@ -139,15 +139,15 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'import_request' &&
|
||||
typeof this.#mod?.importer?.onImport === 'function'
|
||||
payload.type === "import_request" &&
|
||||
typeof this.#mod?.importer?.onImport === "function"
|
||||
) {
|
||||
const reply = await this.#mod.importer.onImport(ctx, {
|
||||
text: payload.content,
|
||||
});
|
||||
if (reply != null) {
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'import_response',
|
||||
type: "import_response",
|
||||
resources: reply.resources as ImportResources,
|
||||
};
|
||||
this.#sendPayload(context, replyPayload, replyId);
|
||||
@@ -157,18 +157,18 @@ export class PluginInstance {
|
||||
}
|
||||
}
|
||||
|
||||
if (payload.type === 'filter_request' && typeof this.#mod?.filter?.onFilter === 'function') {
|
||||
if (payload.type === "filter_request" && typeof this.#mod?.filter?.onFilter === "function") {
|
||||
const reply = await this.#mod.filter.onFilter(ctx, {
|
||||
filter: payload.filter,
|
||||
payload: payload.content,
|
||||
mimeType: payload.type,
|
||||
});
|
||||
this.#sendPayload(context, { type: 'filter_response', ...reply }, replyId);
|
||||
this.#sendPayload(context, { type: "filter_response", ...reply }, replyId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_grpc_request_actions_request' &&
|
||||
payload.type === "get_grpc_request_actions_request" &&
|
||||
Array.isArray(this.#mod?.grpcRequestActions)
|
||||
) {
|
||||
const reply: GrpcRequestAction[] = this.#mod.grpcRequestActions.map((a) => ({
|
||||
@@ -177,7 +177,7 @@ export class PluginInstance {
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_grpc_request_actions_response',
|
||||
type: "get_grpc_request_actions_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
@@ -186,7 +186,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_http_request_actions_request' &&
|
||||
payload.type === "get_http_request_actions_request" &&
|
||||
Array.isArray(this.#mod?.httpRequestActions)
|
||||
) {
|
||||
const reply: HttpRequestAction[] = this.#mod.httpRequestActions.map((a) => ({
|
||||
@@ -195,7 +195,7 @@ export class PluginInstance {
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_http_request_actions_response',
|
||||
type: "get_http_request_actions_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
@@ -204,7 +204,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_websocket_request_actions_request' &&
|
||||
payload.type === "get_websocket_request_actions_request" &&
|
||||
Array.isArray(this.#mod?.websocketRequestActions)
|
||||
) {
|
||||
const reply = this.#mod.websocketRequestActions.map((a) => ({
|
||||
@@ -212,7 +212,7 @@ export class PluginInstance {
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_websocket_request_actions_response',
|
||||
type: "get_websocket_request_actions_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
@@ -221,7 +221,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_workspace_actions_request' &&
|
||||
payload.type === "get_workspace_actions_request" &&
|
||||
Array.isArray(this.#mod?.workspaceActions)
|
||||
) {
|
||||
const reply = this.#mod.workspaceActions.map((a) => ({
|
||||
@@ -229,7 +229,7 @@ export class PluginInstance {
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_workspace_actions_response',
|
||||
type: "get_workspace_actions_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
@@ -238,7 +238,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_folder_actions_request' &&
|
||||
payload.type === "get_folder_actions_request" &&
|
||||
Array.isArray(this.#mod?.folderActions)
|
||||
) {
|
||||
const reply = this.#mod.folderActions.map((a) => ({
|
||||
@@ -246,7 +246,7 @@ export class PluginInstance {
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_folder_actions_response',
|
||||
type: "get_folder_actions_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
@@ -254,9 +254,9 @@ export class PluginInstance {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'get_themes_request' && Array.isArray(this.#mod?.themes)) {
|
||||
if (payload.type === "get_themes_request" && Array.isArray(this.#mod?.themes)) {
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_themes_response',
|
||||
type: "get_themes_response",
|
||||
themes: this.#mod.themes,
|
||||
};
|
||||
this.#sendPayload(context, replyPayload, replyId);
|
||||
@@ -264,7 +264,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_template_function_summary_request' &&
|
||||
payload.type === "get_template_function_summary_request" &&
|
||||
Array.isArray(this.#mod?.templateFunctions)
|
||||
) {
|
||||
const functions: TemplateFunction[] = this.#mod.templateFunctions.map(
|
||||
@@ -277,7 +277,7 @@ export class PluginInstance {
|
||||
},
|
||||
);
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_template_function_summary_response',
|
||||
type: "get_template_function_summary_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
functions,
|
||||
};
|
||||
@@ -286,7 +286,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_template_function_config_request' &&
|
||||
payload.type === "get_template_function_config_request" &&
|
||||
Array.isArray(this.#mod?.templateFunctions)
|
||||
) {
|
||||
const templateFunction = this.#mod.templateFunctions.find((f) => f.name === payload.name);
|
||||
@@ -301,11 +301,11 @@ export class PluginInstance {
|
||||
};
|
||||
|
||||
payload.values = applyFormInputDefaults(fn.args, payload.values);
|
||||
const p = { ...payload, purpose: 'preview' } as const;
|
||||
const p = { ...payload, purpose: "preview" } as const;
|
||||
const resolvedArgs = await applyDynamicFormInput(ctx, fn.args, p);
|
||||
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_template_function_config_response',
|
||||
type: "get_template_function_config_response",
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
function: { ...fn, args: stripDynamicCallbacks(resolvedArgs) },
|
||||
};
|
||||
@@ -313,9 +313,9 @@ export class PluginInstance {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'get_http_authentication_summary_request' && this.#mod?.authentication) {
|
||||
if (payload.type === "get_http_authentication_summary_request" && this.#mod?.authentication) {
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_http_authentication_summary_response',
|
||||
type: "get_http_authentication_summary_response",
|
||||
...this.#mod.authentication,
|
||||
};
|
||||
|
||||
@@ -323,7 +323,7 @@ export class PluginInstance {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'get_http_authentication_config_request' && this.#mod?.authentication) {
|
||||
if (payload.type === "get_http_authentication_config_request" && this.#mod?.authentication) {
|
||||
const { args, actions } = this.#mod.authentication;
|
||||
payload.values = applyFormInputDefaults(args, payload.values);
|
||||
const resolvedArgs = await applyDynamicFormInput(ctx, args, payload);
|
||||
@@ -334,7 +334,7 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_http_authentication_config_response',
|
||||
type: "get_http_authentication_config_response",
|
||||
args: stripDynamicCallbacks(resolvedArgs),
|
||||
actions: resolvedActions,
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
@@ -344,15 +344,15 @@ export class PluginInstance {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'call_http_authentication_request' && this.#mod?.authentication) {
|
||||
if (payload.type === "call_http_authentication_request" && this.#mod?.authentication) {
|
||||
const auth = this.#mod.authentication;
|
||||
if (typeof auth?.onApply === 'function') {
|
||||
if (typeof auth?.onApply === "function") {
|
||||
const resolvedArgs = await applyDynamicFormInput(ctx, auth.args, payload);
|
||||
payload.values = applyFormInputDefaults(resolvedArgs, payload.values);
|
||||
this.#sendPayload(
|
||||
context,
|
||||
{
|
||||
type: 'call_http_authentication_response',
|
||||
type: "call_http_authentication_response",
|
||||
...(await auth.onApply(ctx, payload)),
|
||||
},
|
||||
replyId,
|
||||
@@ -362,11 +362,11 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_http_authentication_action_request' &&
|
||||
payload.type === "call_http_authentication_action_request" &&
|
||||
this.#mod.authentication != null
|
||||
) {
|
||||
const action = this.#mod.authentication.actions?.[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
if (typeof action?.onSelect === "function") {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
@@ -374,11 +374,11 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_http_request_action_request' &&
|
||||
payload.type === "call_http_request_action_request" &&
|
||||
Array.isArray(this.#mod.httpRequestActions)
|
||||
) {
|
||||
const action = this.#mod.httpRequestActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
if (typeof action?.onSelect === "function") {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
@@ -386,11 +386,11 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_websocket_request_action_request' &&
|
||||
payload.type === "call_websocket_request_action_request" &&
|
||||
Array.isArray(this.#mod.websocketRequestActions)
|
||||
) {
|
||||
const action = this.#mod.websocketRequestActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
if (typeof action?.onSelect === "function") {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
@@ -398,20 +398,20 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_workspace_action_request' &&
|
||||
payload.type === "call_workspace_action_request" &&
|
||||
Array.isArray(this.#mod.workspaceActions)
|
||||
) {
|
||||
const action = this.#mod.workspaceActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
if (typeof action?.onSelect === "function") {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (payload.type === 'call_folder_action_request' && Array.isArray(this.#mod.folderActions)) {
|
||||
if (payload.type === "call_folder_action_request" && Array.isArray(this.#mod.folderActions)) {
|
||||
const action = this.#mod.folderActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
if (typeof action?.onSelect === "function") {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
@@ -419,11 +419,11 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_grpc_request_action_request' &&
|
||||
payload.type === "call_grpc_request_action_request" &&
|
||||
Array.isArray(this.#mod.grpcRequestActions)
|
||||
) {
|
||||
const action = this.#mod.grpcRequestActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
if (typeof action?.onSelect === "function") {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
@@ -431,32 +431,32 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_template_function_request' &&
|
||||
payload.type === "call_template_function_request" &&
|
||||
Array.isArray(this.#mod?.templateFunctions)
|
||||
) {
|
||||
const fn = this.#mod.templateFunctions.find((a) => a.name === payload.name);
|
||||
if (
|
||||
payload.args.purpose === 'preview' &&
|
||||
(fn?.previewType === 'click' || fn?.previewType === 'none')
|
||||
payload.args.purpose === "preview" &&
|
||||
(fn?.previewType === "click" || fn?.previewType === "none")
|
||||
) {
|
||||
// Send empty render response
|
||||
this.#sendPayload(
|
||||
context,
|
||||
{
|
||||
type: 'call_template_function_response',
|
||||
type: "call_template_function_response",
|
||||
value: null,
|
||||
error: 'Live preview disabled for this function',
|
||||
error: "Live preview disabled for this function",
|
||||
},
|
||||
replyId,
|
||||
);
|
||||
} else if (typeof fn?.onRender === 'function') {
|
||||
} else if (typeof fn?.onRender === "function") {
|
||||
const resolvedArgs = await applyDynamicFormInput(ctx, fn.args, payload.args);
|
||||
const values = applyFormInputDefaults(resolvedArgs, payload.args.values);
|
||||
const error = validateTemplateFunctionArgs(fn.name, resolvedArgs, values);
|
||||
if (error && payload.args.purpose !== 'preview') {
|
||||
if (error && payload.args.purpose !== "preview") {
|
||||
this.#sendPayload(
|
||||
context,
|
||||
{ type: 'call_template_function_response', value: null, error },
|
||||
{ type: "call_template_function_response", value: null, error },
|
||||
replyId,
|
||||
);
|
||||
return;
|
||||
@@ -466,16 +466,19 @@ export class PluginInstance {
|
||||
const result = await fn.onRender(ctx, { ...payload.args, values });
|
||||
this.#sendPayload(
|
||||
context,
|
||||
{ type: 'call_template_function_response', value: result ?? null },
|
||||
{ type: "call_template_function_response", value: result ?? null },
|
||||
replyId,
|
||||
);
|
||||
} catch (err) {
|
||||
this.#sendPayload(
|
||||
context,
|
||||
{
|
||||
type: 'call_template_function_response',
|
||||
type: "call_template_function_response",
|
||||
value: null,
|
||||
error: (err instanceof Error ? err.message : String(err)).replace(/^Error:\s*/g, ''),
|
||||
error: (err instanceof Error ? err.message : String(err)).replace(
|
||||
/^Error:\s*/g,
|
||||
"",
|
||||
),
|
||||
},
|
||||
replyId,
|
||||
);
|
||||
@@ -484,9 +487,9 @@ export class PluginInstance {
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const error = (err instanceof Error ? err.message : String(err)).replace(/^Error:\s*/g, '');
|
||||
console.log('Plugin call threw exception', payload.type, '→', error);
|
||||
this.#sendPayload(context, { type: 'error_response', error }, replyId);
|
||||
const error = (err instanceof Error ? err.message : String(err)).replace(/^Error:\s*/g, "");
|
||||
console.log("Plugin call threw exception", payload.type, "→", error);
|
||||
this.#sendPayload(context, { type: "error_response", error }, replyId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -495,11 +498,11 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
#pathMod() {
|
||||
return path.posix.join(this.#workerData.bootRequest.dir, 'build', 'index.js');
|
||||
return path.posix.join(this.#workerData.bootRequest.dir, "build", "index.js");
|
||||
}
|
||||
|
||||
#pathPkg() {
|
||||
return path.join(this.#workerData.bootRequest.dir, 'package.json');
|
||||
return path.join(this.#workerData.bootRequest.dir, "package.json");
|
||||
}
|
||||
|
||||
#unimportModule() {
|
||||
@@ -546,10 +549,10 @@ export class PluginInstance {
|
||||
}
|
||||
|
||||
#sendEmpty(context: PluginContext, replyId: string | null = null): string {
|
||||
return this.#sendPayload(context, { type: 'empty_response' }, replyId);
|
||||
return this.#sendPayload(context, { type: "empty_response" }, replyId);
|
||||
}
|
||||
|
||||
#sendForReply<T extends Omit<InternalEventPayload, 'type'>>(
|
||||
#sendForReply<T extends Omit<InternalEventPayload, "type">>(
|
||||
context: PluginContext,
|
||||
payload: InternalEventPayload,
|
||||
): Promise<T> {
|
||||
@@ -600,7 +603,7 @@ export class PluginInstance {
|
||||
throw new Error("Can't get window context without an active window");
|
||||
}
|
||||
const payload: InternalEventPayload = {
|
||||
type: 'window_info_request',
|
||||
type: "window_info_request",
|
||||
label: context.label,
|
||||
};
|
||||
|
||||
@@ -611,7 +614,7 @@ export class PluginInstance {
|
||||
clipboard: {
|
||||
copyText: async (text) => {
|
||||
await this.#sendForReply(context, {
|
||||
type: 'copy_text_request',
|
||||
type: "copy_text_request",
|
||||
text,
|
||||
});
|
||||
},
|
||||
@@ -619,7 +622,7 @@ export class PluginInstance {
|
||||
toast: {
|
||||
show: async (args) => {
|
||||
await this.#sendForReply(context, {
|
||||
type: 'show_toast_request',
|
||||
type: "show_toast_request",
|
||||
// Handle default here because null/undefined both convert to None in Rust translation
|
||||
timeout: args.timeout === undefined ? 5000 : args.timeout,
|
||||
...args,
|
||||
@@ -638,11 +641,11 @@ export class PluginInstance {
|
||||
},
|
||||
openUrl: async ({ onNavigate, onClose, ...args }) => {
|
||||
args.label = args.label || `${Math.random()}`;
|
||||
const payload: InternalEventPayload = { type: 'open_window_request', ...args };
|
||||
const payload: InternalEventPayload = { type: "open_window_request", ...args };
|
||||
const onEvent = (event: InternalEventPayload) => {
|
||||
if (event.type === 'window_navigate_event') {
|
||||
if (event.type === "window_navigate_event") {
|
||||
onNavigate?.(event);
|
||||
} else if (event.type === 'window_close_event') {
|
||||
} else if (event.type === "window_close_event") {
|
||||
onClose?.();
|
||||
}
|
||||
};
|
||||
@@ -650,7 +653,7 @@ export class PluginInstance {
|
||||
return {
|
||||
close: () => {
|
||||
const closePayload: InternalEventPayload = {
|
||||
type: 'close_window_request',
|
||||
type: "close_window_request",
|
||||
label: args.label,
|
||||
};
|
||||
this.#sendPayload(context, closePayload, null);
|
||||
@@ -659,7 +662,7 @@ export class PluginInstance {
|
||||
},
|
||||
openExternalUrl: async (url) => {
|
||||
await this.#sendForReply(context, {
|
||||
type: 'open_external_url_request',
|
||||
type: "open_external_url_request",
|
||||
url,
|
||||
});
|
||||
},
|
||||
@@ -667,7 +670,7 @@ export class PluginInstance {
|
||||
prompt: {
|
||||
text: async (args) => {
|
||||
const reply: PromptTextResponse = await this.#sendForReply(context, {
|
||||
type: 'prompt_text_request',
|
||||
type: "prompt_text_request",
|
||||
...args,
|
||||
});
|
||||
return reply.value;
|
||||
@@ -686,7 +689,7 @@ export class PluginInstance {
|
||||
// Build the event manually so we can get the event ID for keying
|
||||
const eventToSend = this.#buildEventToSend(
|
||||
context,
|
||||
{ type: 'prompt_form_request', ...args, inputs: strippedInputs },
|
||||
{ type: "prompt_form_request", ...args, inputs: strippedInputs },
|
||||
null,
|
||||
);
|
||||
|
||||
@@ -697,7 +700,7 @@ export class PluginInstance {
|
||||
const cb = (event: InternalEvent) => {
|
||||
if (event.replyId !== eventToSend.id) return;
|
||||
|
||||
if (event.payload.type === 'prompt_form_response') {
|
||||
if (event.payload.type === "prompt_form_response") {
|
||||
const { done, values } = event.payload as PromptFormResponse;
|
||||
if (done) {
|
||||
// Final response — resolve the promise and clean up
|
||||
@@ -716,12 +719,12 @@ export class PluginInstance {
|
||||
const stripped = stripDynamicCallbacks(resolvedInputs);
|
||||
this.#sendPayload(
|
||||
context,
|
||||
{ type: 'prompt_form_request', ...args, inputs: stripped },
|
||||
{ type: "prompt_form_request", ...args, inputs: stripped },
|
||||
eventToSend.id,
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to resolve dynamic form inputs', err);
|
||||
console.error("Failed to resolve dynamic form inputs", err);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -739,7 +742,7 @@ export class PluginInstance {
|
||||
httpResponse: {
|
||||
find: async (args) => {
|
||||
const payload = {
|
||||
type: 'find_http_responses_request',
|
||||
type: "find_http_responses_request",
|
||||
...args,
|
||||
} as const;
|
||||
const { httpResponses } = await this.#sendForReply<FindHttpResponsesResponse>(
|
||||
@@ -752,7 +755,7 @@ export class PluginInstance {
|
||||
grpcRequest: {
|
||||
render: async (args) => {
|
||||
const payload = {
|
||||
type: 'render_grpc_request_request',
|
||||
type: "render_grpc_request_request",
|
||||
...args,
|
||||
} as const;
|
||||
const { grpcRequest } = await this.#sendForReply<RenderGrpcRequestResponse>(
|
||||
@@ -765,7 +768,7 @@ export class PluginInstance {
|
||||
httpRequest: {
|
||||
getById: async (args) => {
|
||||
const payload = {
|
||||
type: 'get_http_request_by_id_request',
|
||||
type: "get_http_request_by_id_request",
|
||||
...args,
|
||||
} as const;
|
||||
const { httpRequest } = await this.#sendForReply<GetHttpRequestByIdResponse>(
|
||||
@@ -776,7 +779,7 @@ export class PluginInstance {
|
||||
},
|
||||
send: async (args) => {
|
||||
const payload = {
|
||||
type: 'send_http_request_request',
|
||||
type: "send_http_request_request",
|
||||
...args,
|
||||
} as const;
|
||||
const { httpResponse } = await this.#sendForReply<SendHttpRequestResponse>(
|
||||
@@ -787,7 +790,7 @@ export class PluginInstance {
|
||||
},
|
||||
render: async (args) => {
|
||||
const payload = {
|
||||
type: 'render_http_request_request',
|
||||
type: "render_http_request_request",
|
||||
...args,
|
||||
} as const;
|
||||
const { httpRequest } = await this.#sendForReply<RenderHttpRequestResponse>(
|
||||
@@ -798,9 +801,9 @@ export class PluginInstance {
|
||||
},
|
||||
list: async (args?: { folderId?: string }) => {
|
||||
const payload: InternalEventPayload = {
|
||||
type: 'list_http_requests_request',
|
||||
type: "list_http_requests_request",
|
||||
folderId: args?.folderId,
|
||||
} satisfies ListHttpRequestsRequest & { type: 'list_http_requests_request' };
|
||||
} satisfies ListHttpRequestsRequest & { type: "list_http_requests_request" };
|
||||
const { httpRequests } = await this.#sendForReply<ListHttpRequestsResponse>(
|
||||
context,
|
||||
payload,
|
||||
@@ -809,13 +812,13 @@ export class PluginInstance {
|
||||
},
|
||||
create: async (args) => {
|
||||
const payload = {
|
||||
type: 'upsert_model_request',
|
||||
type: "upsert_model_request",
|
||||
model: {
|
||||
name: '',
|
||||
method: 'GET',
|
||||
name: "",
|
||||
method: "GET",
|
||||
...args,
|
||||
id: '',
|
||||
model: 'http_request',
|
||||
id: "",
|
||||
model: "http_request",
|
||||
},
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<UpsertModelResponse>(context, payload);
|
||||
@@ -823,9 +826,9 @@ export class PluginInstance {
|
||||
},
|
||||
update: async (args) => {
|
||||
const payload = {
|
||||
type: 'upsert_model_request',
|
||||
type: "upsert_model_request",
|
||||
model: {
|
||||
model: 'http_request',
|
||||
model: "http_request",
|
||||
...args,
|
||||
},
|
||||
} as InternalEventPayload;
|
||||
@@ -834,8 +837,8 @@ export class PluginInstance {
|
||||
},
|
||||
delete: async (args) => {
|
||||
const payload = {
|
||||
type: 'delete_model_request',
|
||||
model: 'http_request',
|
||||
type: "delete_model_request",
|
||||
model: "http_request",
|
||||
id: args.id,
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<DeleteModelResponse>(context, payload);
|
||||
@@ -844,23 +847,23 @@ export class PluginInstance {
|
||||
},
|
||||
folder: {
|
||||
list: async () => {
|
||||
const payload = { type: 'list_folders_request' } as const;
|
||||
const payload = { type: "list_folders_request" } as const;
|
||||
const { folders } = await this.#sendForReply<ListFoldersResponse>(context, payload);
|
||||
return folders;
|
||||
},
|
||||
getById: async (args: { id: string }) => {
|
||||
const payload = { type: 'list_folders_request' } as const;
|
||||
const payload = { type: "list_folders_request" } as const;
|
||||
const { folders } = await this.#sendForReply<ListFoldersResponse>(context, payload);
|
||||
return folders.find((f) => f.id === args.id) ?? null;
|
||||
},
|
||||
create: async ({ name, ...args }) => {
|
||||
const payload = {
|
||||
type: 'upsert_model_request',
|
||||
type: "upsert_model_request",
|
||||
model: {
|
||||
...args,
|
||||
name: name ?? '',
|
||||
id: '',
|
||||
model: 'folder',
|
||||
name: name ?? "",
|
||||
id: "",
|
||||
model: "folder",
|
||||
},
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<UpsertModelResponse>(context, payload);
|
||||
@@ -868,9 +871,9 @@ export class PluginInstance {
|
||||
},
|
||||
update: async (args) => {
|
||||
const payload = {
|
||||
type: 'upsert_model_request',
|
||||
type: "upsert_model_request",
|
||||
model: {
|
||||
model: 'folder',
|
||||
model: "folder",
|
||||
...args,
|
||||
},
|
||||
} as InternalEventPayload;
|
||||
@@ -879,8 +882,8 @@ export class PluginInstance {
|
||||
},
|
||||
delete: async (args: { id: string }) => {
|
||||
const payload = {
|
||||
type: 'delete_model_request',
|
||||
model: 'folder',
|
||||
type: "delete_model_request",
|
||||
model: "folder",
|
||||
id: args.id,
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<DeleteModelResponse>(context, payload);
|
||||
@@ -890,14 +893,14 @@ export class PluginInstance {
|
||||
cookies: {
|
||||
getValue: async (args: GetCookieValueRequest) => {
|
||||
const payload = {
|
||||
type: 'get_cookie_value_request',
|
||||
type: "get_cookie_value_request",
|
||||
...args,
|
||||
} as const;
|
||||
const { value } = await this.#sendForReply<GetCookieValueResponse>(context, payload);
|
||||
return value;
|
||||
},
|
||||
listNames: async () => {
|
||||
const payload = { type: 'list_cookie_names_request' } as const;
|
||||
const payload = { type: "list_cookie_names_request" } as const;
|
||||
const { names } = await this.#sendForReply<ListCookieNamesResponse>(context, payload);
|
||||
return names;
|
||||
},
|
||||
@@ -908,7 +911,7 @@ export class PluginInstance {
|
||||
* (eg. object), it will be recursively rendered.
|
||||
*/
|
||||
render: async (args: TemplateRenderRequest) => {
|
||||
const payload = { type: 'template_render_request', ...args } as const;
|
||||
const payload = { type: "template_render_request", ...args } as const;
|
||||
const result = await this.#sendForReply<TemplateRenderResponse>(context, payload);
|
||||
// oxlint-disable-next-line no-explicit-any -- That's okay
|
||||
return result.data as any;
|
||||
@@ -916,34 +919,34 @@ export class PluginInstance {
|
||||
},
|
||||
store: {
|
||||
get: async <T>(key: string) => {
|
||||
const payload = { type: 'get_key_value_request', key } as const;
|
||||
const payload = { type: "get_key_value_request", key } as const;
|
||||
const result = await this.#sendForReply<GetKeyValueResponse>(context, payload);
|
||||
return result.value ? (JSON.parse(result.value) as T) : undefined;
|
||||
},
|
||||
set: async <T>(key: string, value: T) => {
|
||||
const valueStr = JSON.stringify(value);
|
||||
const payload: InternalEventPayload = {
|
||||
type: 'set_key_value_request',
|
||||
type: "set_key_value_request",
|
||||
key,
|
||||
value: valueStr,
|
||||
};
|
||||
await this.#sendForReply<GetKeyValueResponse>(context, payload);
|
||||
},
|
||||
delete: async (key: string) => {
|
||||
const payload = { type: 'delete_key_value_request', key } as const;
|
||||
const payload = { type: "delete_key_value_request", key } as const;
|
||||
const result = await this.#sendForReply<DeleteKeyValueResponse>(context, payload);
|
||||
return result.deleted;
|
||||
},
|
||||
},
|
||||
plugin: {
|
||||
reload: () => {
|
||||
this.#sendPayload(context, { type: 'reload_response', silent: true }, null);
|
||||
this.#sendPayload(context, { type: "reload_response", silent: true }, null);
|
||||
},
|
||||
},
|
||||
workspace: {
|
||||
list: async () => {
|
||||
const payload = {
|
||||
type: 'list_open_workspaces_request',
|
||||
type: "list_open_workspaces_request",
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<ListOpenWorkspacesResponse>(context, payload);
|
||||
return response.workspaces.map((w) => {
|
||||
@@ -975,7 +978,7 @@ function stripDynamicCallbacks(inputs: { dynamic?: unknown }[]): FormInput[] {
|
||||
return inputs.map((input) => {
|
||||
// oxlint-disable-next-line no-explicit-any -- stripping dynamic from union type
|
||||
const { dynamic: _dynamic, ...rest } = input as any;
|
||||
if ('inputs' in rest && Array.isArray(rest.inputs)) {
|
||||
if ("inputs" in rest && Array.isArray(rest.inputs)) {
|
||||
rest.inputs = stripDynamicCallbacks(rest.inputs);
|
||||
}
|
||||
return rest as FormInput;
|
||||
@@ -983,8 +986,8 @@ function stripDynamicCallbacks(inputs: { dynamic?: unknown }[]): FormInput[] {
|
||||
}
|
||||
|
||||
function genId(len = 5): string {
|
||||
const alphabet = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
let id = '';
|
||||
const alphabet = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
let id = "";
|
||||
for (let i = 0; i < len; i++) {
|
||||
id += alphabet[Math.floor(Math.random() * alphabet.length)];
|
||||
}
|
||||
@@ -1004,7 +1007,7 @@ function watchFile(filepath: string, cb: () => void) {
|
||||
const stat = statSync(filepath, { throwIfNoEntry: false });
|
||||
if (stat == null || stat.mtimeMs !== watchedFiles[filepath]?.mtimeMs) {
|
||||
watchedFiles[filepath] = stat ?? null;
|
||||
console.log('[plugin-runtime] watchFile triggered', filepath);
|
||||
console.log("[plugin-runtime] watchFile triggered", filepath);
|
||||
cb();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@ import type {
|
||||
DynamicAuthenticationArg,
|
||||
DynamicPromptFormArg,
|
||||
DynamicTemplateFunctionArg,
|
||||
} from '@yaakapp/api';
|
||||
} from "@yaakapp/api";
|
||||
import type {
|
||||
CallHttpAuthenticationActionArgs,
|
||||
CallTemplateFunctionArgs,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
} from "@yaakapp-internal/plugins";
|
||||
|
||||
type AnyDynamicArg = DynamicTemplateFunctionArg | DynamicAuthenticationArg | DynamicPromptFormArg;
|
||||
type AnyCallArgs =
|
||||
@@ -42,7 +42,7 @@ export async function applyDynamicFormInput(
|
||||
const resolvedArgs: AnyDynamicArg[] = [];
|
||||
for (const { dynamic, ...arg } of args) {
|
||||
const dynamicResult =
|
||||
typeof dynamic === 'function'
|
||||
typeof dynamic === "function"
|
||||
? await dynamic(
|
||||
ctx,
|
||||
callArgs as CallTemplateFunctionArgs &
|
||||
@@ -56,7 +56,7 @@ export async function applyDynamicFormInput(
|
||||
...dynamicResult,
|
||||
} as AnyDynamicArg;
|
||||
|
||||
if ('inputs' in newArg && Array.isArray(newArg.inputs)) {
|
||||
if ("inputs" in newArg && Array.isArray(newArg.inputs)) {
|
||||
try {
|
||||
newArg.inputs = await applyDynamicFormInput(
|
||||
ctx,
|
||||
@@ -66,7 +66,7 @@ export async function applyDynamicFormInput(
|
||||
CallPromptFormDynamicArgs,
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Failed to apply dynamic form input', e);
|
||||
console.error("Failed to apply dynamic form input", e);
|
||||
}
|
||||
}
|
||||
resolvedArgs.push(newArg);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { InternalEvent } from '@yaakapp/api';
|
||||
import WebSocket from 'ws';
|
||||
import { EventChannel } from './EventChannel';
|
||||
import { PluginHandle } from './PluginHandle';
|
||||
import type { InternalEvent } from "@yaakapp/api";
|
||||
import WebSocket from "ws";
|
||||
import { EventChannel } from "./EventChannel";
|
||||
import { PluginHandle } from "./PluginHandle";
|
||||
|
||||
const port = process.env.PORT;
|
||||
if (!port) {
|
||||
throw new Error('Plugin runtime missing PORT');
|
||||
throw new Error("Plugin runtime missing PORT");
|
||||
}
|
||||
|
||||
const host = process.env.HOST;
|
||||
if (!host) {
|
||||
throw new Error('Plugin runtime missing HOST');
|
||||
throw new Error("Plugin runtime missing HOST");
|
||||
}
|
||||
|
||||
const pluginToAppEvents = new EventChannel();
|
||||
@@ -18,16 +18,16 @@ const plugins: Record<string, PluginHandle> = {};
|
||||
|
||||
const ws = new WebSocket(`ws://${host}:${port}`);
|
||||
|
||||
ws.on('message', async (e: Buffer) => {
|
||||
ws.on("message", async (e: Buffer) => {
|
||||
try {
|
||||
await handleIncoming(e.toString());
|
||||
} catch (err) {
|
||||
console.log('Failed to handle incoming plugin event', err);
|
||||
console.log("Failed to handle incoming plugin event", err);
|
||||
}
|
||||
});
|
||||
ws.on('open', () => console.log('Plugin runtime connected to websocket'));
|
||||
ws.on('error', (err: unknown) => console.error('Plugin runtime websocket error', err));
|
||||
ws.on('close', (code: number) => console.log('Plugin runtime websocket closed', code));
|
||||
ws.on("open", () => console.log("Plugin runtime connected to websocket"));
|
||||
ws.on("error", (err: unknown) => console.error("Plugin runtime websocket error", err));
|
||||
ws.on("close", (code: number) => console.log("Plugin runtime websocket closed", code));
|
||||
|
||||
// Listen for incoming events from plugins
|
||||
pluginToAppEvents.listen((e) => {
|
||||
@@ -38,7 +38,7 @@ pluginToAppEvents.listen((e) => {
|
||||
async function handleIncoming(msg: string) {
|
||||
const pluginEvent: InternalEvent = JSON.parse(msg);
|
||||
// Handle special event to bootstrap plugin
|
||||
if (pluginEvent.payload.type === 'boot_request') {
|
||||
if (pluginEvent.payload.type === "boot_request") {
|
||||
const plugin = new PluginHandle(
|
||||
pluginEvent.pluginRefId,
|
||||
pluginEvent.context,
|
||||
@@ -51,23 +51,23 @@ async function handleIncoming(msg: string) {
|
||||
// Once booted, forward all events to the plugin worker
|
||||
const plugin = plugins[pluginEvent.pluginRefId];
|
||||
if (!plugin) {
|
||||
console.warn('Failed to get plugin for event by', pluginEvent.pluginRefId);
|
||||
console.warn("Failed to get plugin for event by", pluginEvent.pluginRefId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pluginEvent.payload.type === 'terminate_request') {
|
||||
if (pluginEvent.payload.type === "terminate_request") {
|
||||
await plugin.terminate();
|
||||
console.log('Terminated plugin worker', pluginEvent.pluginRefId);
|
||||
console.log("Terminated plugin worker", pluginEvent.pluginRefId);
|
||||
delete plugins[pluginEvent.pluginRefId];
|
||||
}
|
||||
|
||||
plugin.sendToWorker(pluginEvent);
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
console.error("Unhandled Rejection at:", promise, "reason:", reason);
|
||||
});
|
||||
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error('Uncaught Exception:', error);
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.error("Uncaught Exception:", error);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* oxlint-disable unbound-method */
|
||||
import process from 'node:process';
|
||||
import process from "node:process";
|
||||
|
||||
export function interceptStdout(intercept: (text: string) => string) {
|
||||
const old_stdout_write = process.stdout.write;
|
||||
@@ -25,5 +25,5 @@ export function interceptStdout(intercept: (text: string) => string) {
|
||||
}
|
||||
|
||||
function interceptor(text: string, fn: (text: string) => string) {
|
||||
return fn(text).replace(/\n$/, '') + (fn(text) && text.endsWith('\n') ? '\n' : '');
|
||||
return fn(text).replace(/\n$/, "") + (fn(text) && text.endsWith("\n") ? "\n" : "");
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { TemplateFunctionPlugin } from '@yaakapp/api';
|
||||
import type { TemplateFunctionPlugin } from "@yaakapp/api";
|
||||
|
||||
export function migrateTemplateFunctionSelectOptions(
|
||||
f: TemplateFunctionPlugin,
|
||||
): TemplateFunctionPlugin {
|
||||
const migratedArgs = f.args.map((a) => {
|
||||
if (a.type === 'select') {
|
||||
if (a.type === "select") {
|
||||
// Migrate old options that had 'name' instead of 'label'
|
||||
type LegacyOption = { label?: string; value: string; name?: string };
|
||||
a.options = a.options.map((o) => {
|
||||
const legacy = o as LegacyOption;
|
||||
return {
|
||||
label: legacy.label ?? legacy.name ?? '',
|
||||
label: legacy.label ?? legacy.name ?? "",
|
||||
value: legacy.value,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,106 +1,106 @@
|
||||
import { applyFormInputDefaults } from '@yaakapp-internal/lib/templateFunction';
|
||||
import type { CallTemplateFunctionArgs } from '@yaakapp-internal/plugins';
|
||||
import type { Context, DynamicTemplateFunctionArg } from '@yaakapp/api';
|
||||
import { describe, expect, test } from 'vite-plus/test';
|
||||
import { applyDynamicFormInput } from '../src/common';
|
||||
import { applyFormInputDefaults } from "@yaakapp-internal/lib/templateFunction";
|
||||
import type { CallTemplateFunctionArgs } from "@yaakapp-internal/plugins";
|
||||
import type { Context, DynamicTemplateFunctionArg } from "@yaakapp/api";
|
||||
import { describe, expect, test } from "vite-plus/test";
|
||||
import { applyDynamicFormInput } from "../src/common";
|
||||
|
||||
describe('applyFormInputDefaults', () => {
|
||||
test('Works with top-level select', () => {
|
||||
describe("applyFormInputDefaults", () => {
|
||||
test("Works with top-level select", () => {
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{
|
||||
type: 'select',
|
||||
name: 'test',
|
||||
options: [{ label: 'Option 1', value: 'one' }],
|
||||
defaultValue: 'one',
|
||||
type: "select",
|
||||
name: "test",
|
||||
options: [{ label: "Option 1", value: "one" }],
|
||||
defaultValue: "one",
|
||||
},
|
||||
];
|
||||
expect(applyFormInputDefaults(args, {})).toEqual({
|
||||
test: 'one',
|
||||
test: "one",
|
||||
});
|
||||
});
|
||||
|
||||
test('Works with existing value', () => {
|
||||
test("Works with existing value", () => {
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{
|
||||
type: 'select',
|
||||
name: 'test',
|
||||
options: [{ label: 'Option 1', value: 'one' }],
|
||||
defaultValue: 'one',
|
||||
type: "select",
|
||||
name: "test",
|
||||
options: [{ label: "Option 1", value: "one" }],
|
||||
defaultValue: "one",
|
||||
},
|
||||
];
|
||||
expect(applyFormInputDefaults(args, { test: 'explicit' })).toEqual({
|
||||
test: 'explicit',
|
||||
expect(applyFormInputDefaults(args, { test: "explicit" })).toEqual({
|
||||
test: "explicit",
|
||||
});
|
||||
});
|
||||
|
||||
test('Works with recursive select', () => {
|
||||
test("Works with recursive select", () => {
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{ type: 'text', name: 'dummy', defaultValue: 'top' },
|
||||
{ type: "text", name: "dummy", defaultValue: "top" },
|
||||
{
|
||||
type: 'accordion',
|
||||
label: 'Test',
|
||||
type: "accordion",
|
||||
label: "Test",
|
||||
inputs: [
|
||||
{ type: 'text', name: 'name', defaultValue: 'hello' },
|
||||
{ type: "text", name: "name", defaultValue: "hello" },
|
||||
{
|
||||
type: 'select',
|
||||
name: 'test',
|
||||
options: [{ label: 'Option 1', value: 'one' }],
|
||||
defaultValue: 'one',
|
||||
type: "select",
|
||||
name: "test",
|
||||
options: [{ label: "Option 1", value: "one" }],
|
||||
defaultValue: "one",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
expect(applyFormInputDefaults(args, {})).toEqual({
|
||||
dummy: 'top',
|
||||
test: 'one',
|
||||
name: 'hello',
|
||||
dummy: "top",
|
||||
test: "one",
|
||||
name: "hello",
|
||||
});
|
||||
});
|
||||
|
||||
test('Works with dynamic options', () => {
|
||||
test("Works with dynamic options", () => {
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{
|
||||
type: 'select',
|
||||
name: 'test',
|
||||
defaultValue: 'one',
|
||||
type: "select",
|
||||
name: "test",
|
||||
defaultValue: "one",
|
||||
options: [],
|
||||
dynamic() {
|
||||
return { options: [{ label: 'Option 1', value: 'one' }] };
|
||||
return { options: [{ label: "Option 1", value: "one" }] };
|
||||
},
|
||||
},
|
||||
];
|
||||
expect(applyFormInputDefaults(args, {})).toEqual({
|
||||
test: 'one',
|
||||
test: "one",
|
||||
});
|
||||
expect(applyFormInputDefaults(args, {})).toEqual({
|
||||
test: 'one',
|
||||
test: "one",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyDynamicFormInput', () => {
|
||||
test('Works with plain input', async () => {
|
||||
describe("applyDynamicFormInput", () => {
|
||||
test("Works with plain input", async () => {
|
||||
const ctx = {} as Context;
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{ type: 'text', name: 'name' },
|
||||
{ type: 'checkbox', name: 'checked' },
|
||||
{ type: "text", name: "name" },
|
||||
{ type: "checkbox", name: "checked" },
|
||||
];
|
||||
const callArgs: CallTemplateFunctionArgs = {
|
||||
values: {},
|
||||
purpose: 'preview',
|
||||
purpose: "preview",
|
||||
};
|
||||
expect(await applyDynamicFormInput(ctx, args, callArgs)).toEqual([
|
||||
{ type: 'text', name: 'name' },
|
||||
{ type: 'checkbox', name: 'checked' },
|
||||
{ type: "text", name: "name" },
|
||||
{ type: "checkbox", name: "checked" },
|
||||
]);
|
||||
});
|
||||
|
||||
test('Works with dynamic input', async () => {
|
||||
test("Works with dynamic input", async () => {
|
||||
const ctx = {} as Context;
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
type: "text",
|
||||
name: "name",
|
||||
async dynamic(_ctx, _args) {
|
||||
return { hidden: true };
|
||||
},
|
||||
@@ -108,28 +108,28 @@ describe('applyDynamicFormInput', () => {
|
||||
];
|
||||
const callArgs: CallTemplateFunctionArgs = {
|
||||
values: {},
|
||||
purpose: 'preview',
|
||||
purpose: "preview",
|
||||
};
|
||||
expect(await applyDynamicFormInput(ctx, args, callArgs)).toEqual([
|
||||
{ type: 'text', name: 'name', hidden: true },
|
||||
{ type: "text", name: "name", hidden: true },
|
||||
]);
|
||||
});
|
||||
|
||||
test('Works with recursive dynamic input', async () => {
|
||||
test("Works with recursive dynamic input", async () => {
|
||||
const ctx = {} as Context;
|
||||
const callArgs: CallTemplateFunctionArgs = {
|
||||
values: { hello: 'world' },
|
||||
purpose: 'preview',
|
||||
values: { hello: "world" },
|
||||
purpose: "preview",
|
||||
};
|
||||
const args: DynamicTemplateFunctionArg[] = [
|
||||
{
|
||||
type: 'banner',
|
||||
type: "banner",
|
||||
inputs: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
type: "text",
|
||||
name: "name",
|
||||
async dynamic(_ctx, args) {
|
||||
return { hidden: args.values.hello === 'world' };
|
||||
return { hidden: args.values.hello === "world" };
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -137,11 +137,11 @@ describe('applyDynamicFormInput', () => {
|
||||
];
|
||||
expect(await applyDynamicFormInput(ctx, args, callArgs)).toEqual([
|
||||
{
|
||||
type: 'banner',
|
||||
type: "banner",
|
||||
inputs: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
type: "text",
|
||||
name: "name",
|
||||
hidden: true,
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user