@get-bb/plugin-sdk 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -0
- package/bundled-types/bb-plugin-sdk-app.d.ts +1519 -0
- package/bundled-types/bb-plugin-sdk-internal-composer-customization-validation.d.ts +30 -0
- package/bundled-types/bb-plugin-sdk-internal-composer-view.d.ts +10 -0
- package/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +141 -0
- package/bundled-types/bb-plugin-sdk-testing-app.d.ts +238 -0
- package/bundled-types/bb-plugin-sdk-testing.d.ts +309 -0
- package/bundled-types/bb-plugin-sdk.d.ts +13635 -0
- package/dist/app.js +36 -0
- package/dist/index.js +11 -0
- package/dist/internal/composer-customization-validation.js +238 -0
- package/dist/internal/composer-view.js +7 -0
- package/dist/internal/host-policy.js +261 -0
- package/dist/testing/app.js +1190 -0
- package/dist/testing/index.js +1625 -0
- package/package.json +137 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Portable type declarations for `@get-bb/plugin-sdk`. Unpublished BB
|
|
2
|
+
// workspace contracts are flattened; public subpaths may reuse the
|
|
3
|
+
// package root without requiring any other @bb/* package.
|
|
4
|
+
//
|
|
5
|
+
// Confused by the API, or need a symbol that isn't here? Clone the BB repo
|
|
6
|
+
// and read the real source: https://github.com/get-bb/bb
|
|
7
|
+
|
|
8
|
+
import { ComposerCustomization, PluginComposerThreadRowStatus } from '@get-bb/plugin-sdk';
|
|
9
|
+
|
|
10
|
+
declare const PLUGIN_SLOT_ID_PATTERN: RegExp;
|
|
11
|
+
type RejectionReporter = (reason: string) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Parse the runtime value handed to
|
|
14
|
+
* `PluginContentScriptContext.experimental_setThreadRowStatus`. `undefined`
|
|
15
|
+
* means the value was rejected; `null` remains the explicit clear operation.
|
|
16
|
+
*/
|
|
17
|
+
declare function normalizePluginThreadRowStatus(value: unknown, onRejected: RejectionReporter): PluginComposerThreadRowStatus | null | undefined;
|
|
18
|
+
declare function requireSlotId(kind: string, value: unknown): string;
|
|
19
|
+
declare function requireMessageDirectiveId(kind: string, value: unknown): string;
|
|
20
|
+
declare function requireNonEmptyString(kind: string, field: string, value: unknown): string;
|
|
21
|
+
declare function requireOptionalString(kind: string, field: string, value: unknown): string | undefined;
|
|
22
|
+
declare function requireComponent<T>(kind: string, value: unknown): T;
|
|
23
|
+
declare function requireUniqueId(kind: string, seen: Set<string>, id: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Validate one registration while isolating composer customization failures.
|
|
26
|
+
* The host and test harness inject their own rejection reporters.
|
|
27
|
+
*/
|
|
28
|
+
declare function collectComposerCustomization(registration: unknown, seenIds: Set<string>, onRejected: RejectionReporter): ComposerCustomization | null;
|
|
29
|
+
|
|
30
|
+
export { PLUGIN_SLOT_ID_PATTERN, collectComposerCustomization, normalizePluginThreadRowStatus, requireComponent, requireMessageDirectiveId, requireNonEmptyString, requireOptionalString, requireSlotId, requireUniqueId };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Portable type declarations for `@get-bb/plugin-sdk`. Unpublished BB
|
|
2
|
+
// workspace contracts are flattened; public subpaths may reuse the
|
|
3
|
+
// package root without requiring any other @bb/* package.
|
|
4
|
+
//
|
|
5
|
+
// Confused by the API, or need a symbol that isn't here? Clone the BB repo
|
|
6
|
+
// and read the real source: https://github.com/get-bb/bb
|
|
7
|
+
|
|
8
|
+
declare function isComposerDraftEmpty(text: string, attachmentCount: number): boolean;
|
|
9
|
+
|
|
10
|
+
export { isComposerDraftEmpty };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Portable type declarations for `@get-bb/plugin-sdk`. Unpublished BB
|
|
2
|
+
// workspace contracts are flattened; public subpaths may reuse the
|
|
3
|
+
// package root without requiring any other @bb/* package.
|
|
4
|
+
//
|
|
5
|
+
// Confused by the API, or need a symbol that isn't here? Clone the BB repo
|
|
6
|
+
// and read the real source: https://github.com/get-bb/bb
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Core `bb` CLI top-level command names (plus commander's built-in help).
|
|
10
|
+
* Plugin CLI commands may not shadow these. Maintained by hand and checked
|
|
11
|
+
* against the real Commander program by
|
|
12
|
+
* apps/cli/src/__tests__/plugin-cli-proxy.test.ts.
|
|
13
|
+
*
|
|
14
|
+
* "automation" and "connect" are intentionally absent: builtin plugins own
|
|
15
|
+
* those top-level commands and the CLI proxies them.
|
|
16
|
+
*/
|
|
17
|
+
declare const RESERVED_BB_CLI_COMMANDS: readonly string[];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The validator-neutral subset of Standard Schema v1 used by plugin RPC.
|
|
21
|
+
* Zod 4 schemas implement this interface directly; other validators can do
|
|
22
|
+
* the same without becoming part of BB's public protocol.
|
|
23
|
+
*/
|
|
24
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
25
|
+
readonly "~standard": {
|
|
26
|
+
readonly version: 1;
|
|
27
|
+
readonly vendor: string;
|
|
28
|
+
readonly validate: (value: unknown) => StandardSchemaV1Result<Output> | Promise<StandardSchemaV1Result<Output>>;
|
|
29
|
+
readonly types?: {
|
|
30
|
+
readonly input: Input;
|
|
31
|
+
readonly output: Output;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
type StandardSchemaV1Result<Output> = {
|
|
36
|
+
readonly value: Output;
|
|
37
|
+
readonly issues?: undefined;
|
|
38
|
+
} | {
|
|
39
|
+
readonly issues: readonly StandardSchemaV1Issue[];
|
|
40
|
+
};
|
|
41
|
+
interface StandardSchemaV1Issue {
|
|
42
|
+
readonly message: string;
|
|
43
|
+
readonly path?: PropertyKey | readonly (PropertyKey | {
|
|
44
|
+
readonly key: PropertyKey;
|
|
45
|
+
})[];
|
|
46
|
+
}
|
|
47
|
+
interface PluginRpcMethodContract<InputSchema extends StandardSchemaV1 = StandardSchemaV1, OutputSchema extends StandardSchemaV1 = StandardSchemaV1> {
|
|
48
|
+
readonly input: InputSchema;
|
|
49
|
+
readonly output: OutputSchema;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Declarative settings descriptors (`bb.settings.define`). Deliberately plain
|
|
54
|
+
* data — not zod — so the host can render settings forms and the CLI can
|
|
55
|
+
* parse values without executing plugin code.
|
|
56
|
+
*/
|
|
57
|
+
type PluginSettingDescriptor = {
|
|
58
|
+
type: "string";
|
|
59
|
+
label: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
/** Stored in a 0600 file under <dataDir>/plugins/<id>/secrets/, never in the db or sent to the frontend. */
|
|
62
|
+
secret?: true;
|
|
63
|
+
default?: string;
|
|
64
|
+
} | {
|
|
65
|
+
type: "boolean";
|
|
66
|
+
label: string;
|
|
67
|
+
description?: string;
|
|
68
|
+
default?: boolean;
|
|
69
|
+
} | {
|
|
70
|
+
type: "select";
|
|
71
|
+
label: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
options: string[];
|
|
74
|
+
default?: string;
|
|
75
|
+
} | {
|
|
76
|
+
type: "project";
|
|
77
|
+
label: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
default?: string;
|
|
80
|
+
};
|
|
81
|
+
type PluginSettingDescriptors = Record<string, PluginSettingDescriptor>;
|
|
82
|
+
interface PluginCliOutputLimitError {
|
|
83
|
+
code: "plugin_cli_output_too_large";
|
|
84
|
+
message: string;
|
|
85
|
+
maxBytes: number;
|
|
86
|
+
stdoutBytes: number;
|
|
87
|
+
stderrBytes: number;
|
|
88
|
+
totalBytes: number;
|
|
89
|
+
}
|
|
90
|
+
/** Normalized host result returned by the plugin CLI HTTP/testing boundary. */
|
|
91
|
+
interface PluginCliExecutionResult {
|
|
92
|
+
exitCode: number;
|
|
93
|
+
stdout: string;
|
|
94
|
+
stderr: string;
|
|
95
|
+
error?: PluginCliOutputLimitError;
|
|
96
|
+
}
|
|
97
|
+
type PluginMentionTrigger = "@" | "#" | "$" | "!" | "~";
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Built-in dynamic tool names plugins may not shadow. Maintained by hand —
|
|
101
|
+
* kept in sync with the built-in tools in
|
|
102
|
+
* apps/server/src/services/threads/thread-runtime-config.ts by
|
|
103
|
+
* apps/server/test/services/plugins/plugin-agent-tools.test.ts.
|
|
104
|
+
*/
|
|
105
|
+
declare const RESERVED_AGENT_TOOL_NAMES: readonly string[];
|
|
106
|
+
/** JSON values ≤256KB; larger writes are rejected with a clear error. */
|
|
107
|
+
declare const KV_VALUE_MAX_BYTES: number;
|
|
108
|
+
declare const PLUGIN_HTTP_METHODS: ReadonlySet<string>;
|
|
109
|
+
declare const RPC_METHOD_PATTERN: RegExp;
|
|
110
|
+
declare const BACKGROUND_NAME_PATTERN: RegExp;
|
|
111
|
+
declare const CLI_COMMAND_NAME_PATTERN: RegExp;
|
|
112
|
+
declare const AGENT_TOOL_NAME_PATTERN: RegExp;
|
|
113
|
+
declare const PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS = 4096;
|
|
114
|
+
/** Status labels ride on every tool-call event and share one timeline row. */
|
|
115
|
+
declare const PLUGIN_AGENT_STATUS_LABEL_MAX_CHARS = 80;
|
|
116
|
+
declare const PLUGIN_AGENT_SELECTION_MAX_IDS = 256;
|
|
117
|
+
declare const PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS = 4096;
|
|
118
|
+
declare const PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES: number;
|
|
119
|
+
declare const MENTION_PROVIDER_ID_PATTERN: RegExp;
|
|
120
|
+
declare const SETTING_KEY_PATTERN: RegExp;
|
|
121
|
+
/**
|
|
122
|
+
* Validate freeform descriptors from plugin code and merge them into the
|
|
123
|
+
* plugin's registered schema. Plugin source is not type-safe at runtime, so
|
|
124
|
+
* both the production and fake hosts must enforce this boundary identically.
|
|
125
|
+
*/
|
|
126
|
+
declare function registerSettingDescriptors(target: PluginSettingDescriptors, added: Record<string, unknown>): PluginSettingDescriptors;
|
|
127
|
+
/** Validate a settings update. `null` means unset. */
|
|
128
|
+
declare function validateSettingsUpdate(descriptors: PluginSettingDescriptors, values: Record<string, unknown>): string[];
|
|
129
|
+
declare const PLUGIN_MENTION_TRIGGER_VALUES: readonly ["@", "#", "$", "!", "~"];
|
|
130
|
+
declare function isPluginMentionTrigger(value: unknown): value is PluginMentionTrigger;
|
|
131
|
+
declare function normalizeMentionProviderTriggers(providerId: string, triggers: unknown): readonly PluginMentionTrigger[];
|
|
132
|
+
declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
133
|
+
declare function readRpcMethodContract(method: string, value: unknown): PluginRpcMethodContract;
|
|
134
|
+
/** Duck-typed zod detection: plugin sources may carry their own zod copy,
|
|
135
|
+
* so instanceof is useless — anything with safeParse is treated as zod. */
|
|
136
|
+
declare function isZodSchemaLike(value: unknown): boolean;
|
|
137
|
+
/** Compact issue summary from a (possibly foreign-instance) zod error. */
|
|
138
|
+
declare function summarizeParseIssues(error: unknown): string;
|
|
139
|
+
declare function enforcePluginCliOutputLimit(result: Omit<PluginCliExecutionResult, "error">, jsonOutput: boolean): PluginCliExecutionResult;
|
|
140
|
+
|
|
141
|
+
export { AGENT_TOOL_NAME_PATTERN, BACKGROUND_NAME_PATTERN, CLI_COMMAND_NAME_PATTERN, KV_VALUE_MAX_BYTES, MENTION_PROVIDER_ID_PATTERN, PLUGIN_AGENT_DYNAMIC_INSTRUCTIONS_MAX_CHARS, PLUGIN_AGENT_SELECTION_MAX_IDS, PLUGIN_AGENT_STATIC_INSTRUCTIONS_MAX_CHARS, PLUGIN_AGENT_STATUS_LABEL_MAX_CHARS, PLUGIN_AGENT_TOOL_PARAMETERS_MAX_BYTES, PLUGIN_HTTP_METHODS, PLUGIN_MENTION_TRIGGER_VALUES, RESERVED_AGENT_TOOL_NAMES, RESERVED_BB_CLI_COMMANDS, RPC_METHOD_PATTERN, SETTING_KEY_PATTERN, enforcePluginCliOutputLimit, isPluginMentionTrigger, isStandardSchema, isZodSchemaLike, normalizeMentionProviderTriggers, readRpcMethodContract, registerSettingDescriptors, summarizeParseIssues, validateSettingsUpdate };
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Portable type declarations for `@get-bb/plugin-sdk`. Unpublished BB
|
|
2
|
+
// workspace contracts are flattened; public subpaths may reuse the
|
|
3
|
+
// package root without requiring any other @bb/* package.
|
|
4
|
+
//
|
|
5
|
+
// Confused by the API, or need a symbol that isn't here? Clone the BB repo
|
|
6
|
+
// and read the real source: https://github.com/get-bb/bb
|
|
7
|
+
|
|
8
|
+
import { ReactNode, ComponentType } from 'react';
|
|
9
|
+
import { RenderResult } from '@testing-library/react';
|
|
10
|
+
import { PluginHomepageSectionRegistration, PluginSettingsSectionRegistration, PluginNavPanelRegistration, PluginThreadPanelActionRegistration, PluginNewThreadPanelActionRegistration, ComposerCustomization, PluginPendingInteractionRegistration, PluginSidebarFooterActionRegistration, PluginThreadListRegistration, PluginThreadHeaderActionRegistration, PluginFileOpenerRegistration, PluginMessageDirectiveRegistration, PluginMessageActionRegistration, PluginContentScriptRegistration, PluginComposerScope, PluginComposerTextEffect, PluginComposerMention, PluginComposerThreadRowStatus, BbNavigate, PluginAppDefinition, PluginRpcContract, StandardSchemaV1InferInput, PluginRpcResult, PluginRealtimeConnectionState, PluginSidebarThreadsState, PluginSidebarPullRequest, PluginSidebarThreadActions } from '@get-bb/plugin-sdk';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* `@get-bb/plugin-sdk/testing/app` — the frontend plugin test harness. Tests a
|
|
14
|
+
* plugin's `app.tsx` source directly under vitest + jsdom, without the bb
|
|
15
|
+
* host or the esbuild bundle:
|
|
16
|
+
*
|
|
17
|
+
* - {@link installTestPluginRuntime} fills `globalThis.__bbPluginRuntime.
|
|
18
|
+
* pluginSdkApp` with a test implementation of the `@get-bb/plugin-sdk/app`
|
|
19
|
+
* surface (the same seam `bb plugin build` shims to the real app). It must
|
|
20
|
+
* run BEFORE the plugin's `app.tsx` module evaluates, because that module
|
|
21
|
+
* binds the runtime at import time — so import `app.tsx` through
|
|
22
|
+
* {@link loadPluginApp}'s thunk form, or call the installer from a vitest
|
|
23
|
+
* setup file when you prefer static imports.
|
|
24
|
+
* - {@link loadPluginApp} runs the definition's setup against a validating
|
|
25
|
+
* collector (ported from the BB app's interpreter, same error messages)
|
|
26
|
+
* and returns the typed slot registrations.
|
|
27
|
+
* - {@link renderSlot} mounts one registration's component with mock hook
|
|
28
|
+
* backends: rpc as a method→handler map with a call log, realtime as a
|
|
29
|
+
* channel you can push events into, settings/context as plain values, and
|
|
30
|
+
* navigate/composer as recorders. Its `behavior`, `inspection`, and
|
|
31
|
+
* `lifecycle` views separate host inputs, assertions, and mount controls;
|
|
32
|
+
* the existing direct members remain aliases.
|
|
33
|
+
*
|
|
34
|
+
* Add `// @vitest-environment jsdom` to test files using renderSlot.
|
|
35
|
+
*/
|
|
36
|
+
interface RpcCall {
|
|
37
|
+
method: string;
|
|
38
|
+
input: unknown;
|
|
39
|
+
}
|
|
40
|
+
type NavigateCall = {
|
|
41
|
+
method: "toThread";
|
|
42
|
+
threadId: string;
|
|
43
|
+
} | {
|
|
44
|
+
method: "toProject";
|
|
45
|
+
projectId: string;
|
|
46
|
+
} | {
|
|
47
|
+
method: "toPluginPanel";
|
|
48
|
+
path: string;
|
|
49
|
+
options?: {
|
|
50
|
+
subPath?: string;
|
|
51
|
+
replace?: boolean;
|
|
52
|
+
};
|
|
53
|
+
} | {
|
|
54
|
+
method: "toCompose";
|
|
55
|
+
options?: {
|
|
56
|
+
initialPrompt?: string;
|
|
57
|
+
focusPrompt?: boolean;
|
|
58
|
+
};
|
|
59
|
+
} | {
|
|
60
|
+
method: "openThreadPanel";
|
|
61
|
+
options: Parameters<BbNavigate["openThreadPanel"]>[0];
|
|
62
|
+
};
|
|
63
|
+
interface ComposerLog {
|
|
64
|
+
/** Latest plain text in this isolated composer scope. */
|
|
65
|
+
readonly text: string;
|
|
66
|
+
/** Latest host-provided composer scope. */
|
|
67
|
+
readonly scope: PluginComposerScope;
|
|
68
|
+
/** Latest host-provided attachment count exposed through `useComposerView()`. */
|
|
69
|
+
readonly attachmentCount: number;
|
|
70
|
+
/** Latest host-rendered text effect requested by the plugin. */
|
|
71
|
+
textEffect: PluginComposerTextEffect | null;
|
|
72
|
+
textEffectCalls: Array<PluginComposerTextEffect | null>;
|
|
73
|
+
/** Whether this plugin currently holds the composer input lock. */
|
|
74
|
+
inputLocked: boolean;
|
|
75
|
+
inputLockCalls: boolean[];
|
|
76
|
+
quotes: string[];
|
|
77
|
+
mentions: PluginComposerMention[];
|
|
78
|
+
focusCount: number;
|
|
79
|
+
}
|
|
80
|
+
/** One recorded `experimental_useSidebarThreadActions()` call. */
|
|
81
|
+
interface SidebarActionCall {
|
|
82
|
+
method: keyof PluginSidebarThreadActions;
|
|
83
|
+
threadId?: string;
|
|
84
|
+
options?: Record<string, unknown>;
|
|
85
|
+
title?: string;
|
|
86
|
+
pinned?: boolean;
|
|
87
|
+
read?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Install the test runtime at `globalThis.__bbPluginRuntime.pluginSdkApp`.
|
|
91
|
+
* Idempotent per module instance; must run before the plugin's `app.tsx`
|
|
92
|
+
* (and therefore `@get-bb/plugin-sdk/app`) is imported.
|
|
93
|
+
*/
|
|
94
|
+
declare function installTestPluginRuntime(): void;
|
|
95
|
+
interface CapturedPluginApp {
|
|
96
|
+
homepageSections: PluginHomepageSectionRegistration[];
|
|
97
|
+
settingsSections: PluginSettingsSectionRegistration[];
|
|
98
|
+
navPanels: PluginNavPanelRegistration[];
|
|
99
|
+
threadPanelActions: PluginThreadPanelActionRegistration[];
|
|
100
|
+
newThreadPanelActions: PluginNewThreadPanelActionRegistration[];
|
|
101
|
+
composerCustomizations: ComposerCustomization[];
|
|
102
|
+
pendingInteractions: PluginPendingInteractionRegistration[];
|
|
103
|
+
sidebarFooterActions: PluginSidebarFooterActionRegistration[];
|
|
104
|
+
threadLists: PluginThreadListRegistration[];
|
|
105
|
+
threadHeaderActions: PluginThreadHeaderActionRegistration[];
|
|
106
|
+
fileOpeners: PluginFileOpenerRegistration[];
|
|
107
|
+
messageDirectives: PluginMessageDirectiveRegistration[];
|
|
108
|
+
messageActions: PluginMessageActionRegistration[];
|
|
109
|
+
contentScripts: PluginContentScriptRegistration[];
|
|
110
|
+
}
|
|
111
|
+
type PluginAppModule = {
|
|
112
|
+
default: unknown;
|
|
113
|
+
};
|
|
114
|
+
type PluginAppSource = PluginAppDefinition | PluginAppModule | (() => Promise<PluginAppDefinition | PluginAppModule>);
|
|
115
|
+
/**
|
|
116
|
+
* Install the test runtime, resolve the plugin app definition, and capture
|
|
117
|
+
* its slot registrations. Pass a thunk (`() => import("../app.tsx")`) so the
|
|
118
|
+
* plugin module evaluates after the runtime is installed — a static import
|
|
119
|
+
* would bind `definePluginApp` before the installer runs.
|
|
120
|
+
*/
|
|
121
|
+
declare function loadPluginApp(source: PluginAppSource): Promise<CapturedPluginApp>;
|
|
122
|
+
interface ContentScriptTestMountOptions {
|
|
123
|
+
pluginId: string;
|
|
124
|
+
/** Defaults to 1. Pass the host generation you want the plugin to observe. */
|
|
125
|
+
generation?: number;
|
|
126
|
+
/**
|
|
127
|
+
* Simulate an older compatible host that predates the optional experimental
|
|
128
|
+
* thread-row status API. Current-host behavior is enabled by default.
|
|
129
|
+
*/
|
|
130
|
+
omitExperimentalThreadRowStatus?: boolean;
|
|
131
|
+
}
|
|
132
|
+
interface ContentScriptThreadRowStatusCall {
|
|
133
|
+
threadId: string;
|
|
134
|
+
status: PluginComposerThreadRowStatus | null;
|
|
135
|
+
}
|
|
136
|
+
interface MountedPluginContentScripts {
|
|
137
|
+
inspection: {
|
|
138
|
+
readonly mountedIds: readonly string[];
|
|
139
|
+
readonly signal: AbortSignal;
|
|
140
|
+
readonly disposed: boolean;
|
|
141
|
+
readonly threadRowStatusCalls: readonly ContentScriptThreadRowStatusCall[];
|
|
142
|
+
getThreadRowStatus(threadId: string): PluginComposerThreadRowStatus | null;
|
|
143
|
+
};
|
|
144
|
+
lifecycle: {
|
|
145
|
+
/** Abort, then run returned cleanup functions once in reverse order. */
|
|
146
|
+
dispose(): Promise<void>;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Mount captured content scripts with host-faithful ordering and rollback.
|
|
151
|
+
* Call this once per simulated app window; each result owns an independent
|
|
152
|
+
* AbortSignal and cleanup lifecycle.
|
|
153
|
+
*/
|
|
154
|
+
declare function mountPluginContentScripts(app: CapturedPluginApp, options: ContentScriptTestMountOptions): Promise<MountedPluginContentScripts>;
|
|
155
|
+
type PluginRpcTestHandlers<Contract extends PluginRpcContract> = {
|
|
156
|
+
[Method in keyof Contract]: (input: StandardSchemaV1InferInput<Contract[Method]["input"]>) => PluginRpcResult<Contract[Method]> | Promise<PluginRpcResult<Contract[Method]>>;
|
|
157
|
+
};
|
|
158
|
+
interface RenderSlotOptions<Contract extends PluginRpcContract = PluginRpcContract> {
|
|
159
|
+
/**
|
|
160
|
+
* Backing handlers for `useRpc().call`: method name → implementation.
|
|
161
|
+
* Inputs and results are JSON-round-tripped like the wire; a method
|
|
162
|
+
* without a handler rejects, and a throwing handler rejects with its
|
|
163
|
+
* message (what the real rpc client surfaces).
|
|
164
|
+
*/
|
|
165
|
+
rpc?: PluginRpcTestHandlers<Contract>;
|
|
166
|
+
/** `useSettings()` values; omitted → `{ values: undefined, isLoading: false }`. */
|
|
167
|
+
settings?: Record<string, string | boolean>;
|
|
168
|
+
/** `useBbContext()` selection; both default to null. */
|
|
169
|
+
context?: {
|
|
170
|
+
projectId?: string | null;
|
|
171
|
+
threadId?: string | null;
|
|
172
|
+
};
|
|
173
|
+
/** Initial `useRealtimeConnectionState()` value; defaults to `connected`. */
|
|
174
|
+
realtimeConnectionState?: PluginRealtimeConnectionState;
|
|
175
|
+
/** Initial state for this render's isolated composer scope and view. */
|
|
176
|
+
composer?: {
|
|
177
|
+
text?: string;
|
|
178
|
+
scope?: PluginComposerScope;
|
|
179
|
+
attachmentCount?: number;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Threads and projects `experimental_useSidebarThreads()` reports. Omitted →
|
|
183
|
+
* a ready, empty list. Pass `{ status: "loading" }` to test that branch.
|
|
184
|
+
*/
|
|
185
|
+
sidebarThreads?: Partial<PluginSidebarThreadsState>;
|
|
186
|
+
/**
|
|
187
|
+
* Pull requests `experimental_useSidebarThreadPullRequest()` reports, keyed
|
|
188
|
+
* by thread id. Omitted → every thread reports none.
|
|
189
|
+
*/
|
|
190
|
+
sidebarPullRequests?: Record<string, PluginSidebarPullRequest>;
|
|
191
|
+
/** Host acceptance for `useBbNavigate().openThreadPanel`. */
|
|
192
|
+
openThreadPanel?: (options: Parameters<BbNavigate["openThreadPanel"]>[0]) => boolean;
|
|
193
|
+
}
|
|
194
|
+
/** Host-originated inputs a slot test can drive deterministically. */
|
|
195
|
+
interface RenderedSlotBehaviorDrivers {
|
|
196
|
+
/**
|
|
197
|
+
* Push a realtime event to `useRealtime(channel, …)` subscribers, wrapped
|
|
198
|
+
* in act. The payload is JSON-round-tripped like `bb.realtime.publish`.
|
|
199
|
+
*/
|
|
200
|
+
emitRealtime(channel: string, payload: unknown): Promise<void>;
|
|
201
|
+
/** Drive the lifecycle of the same connection used by realtime events. */
|
|
202
|
+
setRealtimeConnectionState(state: PluginRealtimeConnectionState): Promise<void>;
|
|
203
|
+
/** Replace composer text as a host-originated edit, wrapped in act. */
|
|
204
|
+
setComposerText(text: string): Promise<void>;
|
|
205
|
+
/** Replace the scope snapshots returned by composer hooks, wrapped in act. */
|
|
206
|
+
setComposerScope(scope: PluginComposerScope): Promise<void>;
|
|
207
|
+
}
|
|
208
|
+
/** Read-only call/write logs produced while the slot is mounted. */
|
|
209
|
+
interface RenderedSlotInspectionState {
|
|
210
|
+
/** Every `useRpc().call`, in order. */
|
|
211
|
+
readonly rpcCalls: RpcCall[];
|
|
212
|
+
/** Every `useBbNavigate()` call, in order. */
|
|
213
|
+
readonly navigateCalls: NavigateCall[];
|
|
214
|
+
/** Every `experimental_useSidebarThreadActions()` call, in order. */
|
|
215
|
+
readonly sidebarActionCalls: SidebarActionCall[];
|
|
216
|
+
/** Everything written through `useComposer()`. */
|
|
217
|
+
readonly composer: ComposerLog;
|
|
218
|
+
}
|
|
219
|
+
/** Explicit mount controls, separate from behavior inputs and call logs. */
|
|
220
|
+
interface RenderedSlotLifecycleControls {
|
|
221
|
+
rerender(ui: ReactNode): void;
|
|
222
|
+
unmount(): void;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Testing Library result plus BB-specific helpers. Direct members are
|
|
226
|
+
* retained for compatibility; named views make intent explicit in new tests.
|
|
227
|
+
*/
|
|
228
|
+
interface RenderedSlot extends RenderResult, RenderedSlotBehaviorDrivers, RenderedSlotInspectionState {
|
|
229
|
+
readonly behavior: RenderedSlotBehaviorDrivers;
|
|
230
|
+
readonly inspection: RenderedSlotInspectionState;
|
|
231
|
+
readonly lifecycle: RenderedSlotLifecycleControls;
|
|
232
|
+
}
|
|
233
|
+
declare function renderSlot<Props extends object, Contract extends PluginRpcContract = PluginRpcContract>(registration: {
|
|
234
|
+
component: ComponentType<Props>;
|
|
235
|
+
}, props: Props, options?: RenderSlotOptions<Contract>): RenderedSlot;
|
|
236
|
+
|
|
237
|
+
export { installTestPluginRuntime, loadPluginApp, mountPluginContentScripts, renderSlot };
|
|
238
|
+
export type { CapturedPluginApp, ComposerLog, ContentScriptTestMountOptions, ContentScriptThreadRowStatusCall, MountedPluginContentScripts, NavigateCall, PluginAppSource, PluginRpcTestHandlers, RenderSlotOptions, RenderedSlot, RenderedSlotBehaviorDrivers, RenderedSlotInspectionState, RenderedSlotLifecycleControls, RpcCall, SidebarActionCall };
|