esoul-sdk 0.3.0

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.
@@ -0,0 +1,359 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * plugin.json — THE package contract. This file is the source of truth for
4
+ * the schema; the host imports it from here, and
5
+ * `schemas/plugin.schema.json` is generated from it at build time so
6
+ * non-TS tooling (and LLMs) can validate without executing anything.
7
+ *
8
+ * SECRETS NEVER LIVE IN A MANIFEST: oauth2 connections declare provider
9
+ * endpoints + ENV VAR NAMES; apiKey connections declare header NAMES.
10
+ * Value-shaped keys are rejected by `.strict()` and by the validator CLI.
11
+ */
12
+ export declare const PLUGIN_MANIFEST_VERSION: 1;
13
+ /** The plugin-contract version THIS SDK (and the matching host) speak.
14
+ * Manifests may pin `platformApi: {min, max?}`; the host refuses installs
15
+ * outside the range at sync time (fail loud at install, never at runtime).
16
+ * 1.1.0: fileSources consent + fileProviders contributions (additive). */
17
+ export declare const PLATFORM_API_VERSION = "1.1.0";
18
+ export declare const PluginConnectionSchema: z.ZodEffects<z.ZodObject<{
19
+ /** Stable key within the plugin, e.g. "microsoft". */
20
+ key: z.ZodString;
21
+ kind: z.ZodEnum<["oauth2", "apiKey"]>;
22
+ label: z.ZodString;
23
+ description: z.ZodOptional<z.ZodString>;
24
+ /** oauth2: provider endpoints (authorization-code + PKCE). */
25
+ authorizeUrl: z.ZodOptional<z.ZodString>;
26
+ tokenUrl: z.ZodOptional<z.ZodString>;
27
+ oauthScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
28
+ /** oauth2: ENV VAR NAMES holding client credentials. */
29
+ clientIdEnv: z.ZodOptional<z.ZodString>;
30
+ clientSecretEnv: z.ZodOptional<z.ZodString>;
31
+ /** apiKey: header NAMES the plugin will send (never values). */
32
+ headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
33
+ }, "strict", z.ZodTypeAny, {
34
+ key: string;
35
+ kind: "oauth2" | "apiKey";
36
+ label: string;
37
+ description?: string | undefined;
38
+ authorizeUrl?: string | undefined;
39
+ tokenUrl?: string | undefined;
40
+ oauthScopes?: string[] | undefined;
41
+ clientIdEnv?: string | undefined;
42
+ clientSecretEnv?: string | undefined;
43
+ headerNames?: string[] | undefined;
44
+ }, {
45
+ key: string;
46
+ kind: "oauth2" | "apiKey";
47
+ label: string;
48
+ description?: string | undefined;
49
+ authorizeUrl?: string | undefined;
50
+ tokenUrl?: string | undefined;
51
+ oauthScopes?: string[] | undefined;
52
+ clientIdEnv?: string | undefined;
53
+ clientSecretEnv?: string | undefined;
54
+ headerNames?: string[] | undefined;
55
+ }>, {
56
+ key: string;
57
+ kind: "oauth2" | "apiKey";
58
+ label: string;
59
+ description?: string | undefined;
60
+ authorizeUrl?: string | undefined;
61
+ tokenUrl?: string | undefined;
62
+ oauthScopes?: string[] | undefined;
63
+ clientIdEnv?: string | undefined;
64
+ clientSecretEnv?: string | undefined;
65
+ headerNames?: string[] | undefined;
66
+ }, {
67
+ key: string;
68
+ kind: "oauth2" | "apiKey";
69
+ label: string;
70
+ description?: string | undefined;
71
+ authorizeUrl?: string | undefined;
72
+ tokenUrl?: string | undefined;
73
+ oauthScopes?: string[] | undefined;
74
+ clientIdEnv?: string | undefined;
75
+ clientSecretEnv?: string | undefined;
76
+ headerNames?: string[] | undefined;
77
+ }>;
78
+ export declare const PluginManifestSchema: z.ZodObject<{
79
+ manifestVersion: z.ZodLiteral<1>;
80
+ /** Directory name under src/plugins/. Kebab-case. */
81
+ id: z.ZodString;
82
+ name: z.ZodString;
83
+ version: z.ZodString;
84
+ description: z.ZodString;
85
+ /** The ApplicationSchema.applicationType the entry module declares.
86
+ * MUST be plugin_-namespaced: the platform uses the prefix to tell
87
+ * "unknown plugin type — honest card" apart from retired built-ins,
88
+ * and it keeps plugin types out of the built-in namespace forever. */
89
+ applicationType: z.ZodString;
90
+ /** Entry module basename (no extension) exporting `pluginSchema`. */
91
+ entry: z.ZodString;
92
+ /**
93
+ * Launcher icon: a lucide-react component name ("Bird", "Gamepad2") from the
94
+ * platform's curated set (`PLUGIN_ICON_CHOICES` in src/lib/app-icons.ts).
95
+ * Unknown names fall back to the generic glyph — never a broken tile. This is
96
+ * how a plugin gets a real icon in the picker without a platform edit.
97
+ */
98
+ icon: z.ZodOptional<z.ZodString>;
99
+ author: z.ZodOptional<z.ZodObject<{
100
+ name: z.ZodString;
101
+ email: z.ZodOptional<z.ZodString>;
102
+ url: z.ZodOptional<z.ZodString>;
103
+ }, "strip", z.ZodTypeAny, {
104
+ name: string;
105
+ email?: string | undefined;
106
+ url?: string | undefined;
107
+ }, {
108
+ name: string;
109
+ email?: string | undefined;
110
+ url?: string | undefined;
111
+ }>>;
112
+ /** Tasks the BROWSER may kick via /api/inngest/send-event. */
113
+ kickableTasks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
114
+ /** Push-ingress endpoints — POST|GET /api/plugins/<id>/webhook/<name>. */
115
+ webhooks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
116
+ /** Server ops — POST /api/plugins/<id>/op/<name> (platform-gated). */
117
+ ops: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
118
+ /** Poll cadences for durable tasks (the offline-safe pull lane). */
119
+ pollTasks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
120
+ task: z.ZodString;
121
+ everyMinutes: z.ZodNumber;
122
+ }, "strip", z.ZodTypeAny, {
123
+ task: string;
124
+ everyMinutes: number;
125
+ }, {
126
+ task: string;
127
+ everyMinutes: number;
128
+ }>, "many">>>;
129
+ /** Contract-version pin: refuse install outside [min, max]. */
130
+ platformApi: z.ZodOptional<z.ZodObject<{
131
+ min: z.ZodString;
132
+ max: z.ZodOptional<z.ZodString>;
133
+ }, "strip", z.ZodTypeAny, {
134
+ min: string;
135
+ max?: string | undefined;
136
+ }, {
137
+ min: string;
138
+ max?: string | undefined;
139
+ }>>;
140
+ /** Reserved for the review/consent flow. */
141
+ scopes: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
142
+ /**
143
+ * Tools of OTHER apps in the workspace this plugin's UI may invoke through
144
+ * `useWorkspaceTools()` — "<applicationType>:<tool base name>", e.g.
145
+ * "spreadsheet:add_row". This is the grant wall for an INSTALLED plugin:
146
+ * the server refuses a call the manifest does not name (the reviewed PR is
147
+ * the consent — plugins are reviewed code, unlike App-Maker specs, which
148
+ * are data and ask each user). In the Forge's live preview (dev mode) the
149
+ * call rides the board's own tab to the owner's workspace instead.
150
+ */
151
+ workspaceTools: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
152
+ /** Third-party logins surfaced in Account settings → Plugins. */
153
+ connections: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{
154
+ /** Stable key within the plugin, e.g. "microsoft". */
155
+ key: z.ZodString;
156
+ kind: z.ZodEnum<["oauth2", "apiKey"]>;
157
+ label: z.ZodString;
158
+ description: z.ZodOptional<z.ZodString>;
159
+ /** oauth2: provider endpoints (authorization-code + PKCE). */
160
+ authorizeUrl: z.ZodOptional<z.ZodString>;
161
+ tokenUrl: z.ZodOptional<z.ZodString>;
162
+ oauthScopes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
163
+ /** oauth2: ENV VAR NAMES holding client credentials. */
164
+ clientIdEnv: z.ZodOptional<z.ZodString>;
165
+ clientSecretEnv: z.ZodOptional<z.ZodString>;
166
+ /** apiKey: header NAMES the plugin will send (never values). */
167
+ headerNames: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
168
+ }, "strict", z.ZodTypeAny, {
169
+ key: string;
170
+ kind: "oauth2" | "apiKey";
171
+ label: string;
172
+ description?: string | undefined;
173
+ authorizeUrl?: string | undefined;
174
+ tokenUrl?: string | undefined;
175
+ oauthScopes?: string[] | undefined;
176
+ clientIdEnv?: string | undefined;
177
+ clientSecretEnv?: string | undefined;
178
+ headerNames?: string[] | undefined;
179
+ }, {
180
+ key: string;
181
+ kind: "oauth2" | "apiKey";
182
+ label: string;
183
+ description?: string | undefined;
184
+ authorizeUrl?: string | undefined;
185
+ tokenUrl?: string | undefined;
186
+ oauthScopes?: string[] | undefined;
187
+ clientIdEnv?: string | undefined;
188
+ clientSecretEnv?: string | undefined;
189
+ headerNames?: string[] | undefined;
190
+ }>, {
191
+ key: string;
192
+ kind: "oauth2" | "apiKey";
193
+ label: string;
194
+ description?: string | undefined;
195
+ authorizeUrl?: string | undefined;
196
+ tokenUrl?: string | undefined;
197
+ oauthScopes?: string[] | undefined;
198
+ clientIdEnv?: string | undefined;
199
+ clientSecretEnv?: string | undefined;
200
+ headerNames?: string[] | undefined;
201
+ }, {
202
+ key: string;
203
+ kind: "oauth2" | "apiKey";
204
+ label: string;
205
+ description?: string | undefined;
206
+ authorizeUrl?: string | undefined;
207
+ tokenUrl?: string | undefined;
208
+ oauthScopes?: string[] | undefined;
209
+ clientIdEnv?: string | undefined;
210
+ clientSecretEnv?: string | undefined;
211
+ headerNames?: string[] | undefined;
212
+ }>, "many">>>;
213
+ /**
214
+ * File-access consent (plugin-file-sources.md §3). EXPLICIT-ONLY: absent
215
+ * means the plugin's server code gets NO file API at all. `workspace`
216
+ * grants the workspace source (read / readwrite); `providers` names the
217
+ * OTHER mounts it may read ("google-drive", "local", or another plugin's
218
+ * providerKey). A plugin's own contributed providers are implicit.
219
+ * Rendered verbatim in the Settings consent panel.
220
+ */
221
+ fileSources: z.ZodOptional<z.ZodObject<{
222
+ workspace: z.ZodOptional<z.ZodEnum<["read", "readwrite"]>>;
223
+ providers: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
224
+ }, "strict", z.ZodTypeAny, {
225
+ providers: string[];
226
+ workspace?: "read" | "readwrite" | undefined;
227
+ }, {
228
+ workspace?: "read" | "readwrite" | undefined;
229
+ providers?: string[] | undefined;
230
+ }>>;
231
+ /**
232
+ * File providers this plugin CONTRIBUTES (plugin-file-sources.md §2):
233
+ * one mount per ACTIVE connection of `connectionKey`. `key` is globally
234
+ * unique across installed plugins (host keys workspace/google-drive/local
235
+ * reserved — sync refuses collisions); the implementation is
236
+ * `pluginServer.fileProviders[key]` in server.ts.
237
+ */
238
+ fileProviders: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
239
+ key: z.ZodString;
240
+ connectionKey: z.ZodString;
241
+ label: z.ZodString;
242
+ }, "strict", z.ZodTypeAny, {
243
+ key: string;
244
+ label: string;
245
+ connectionKey: string;
246
+ }, {
247
+ key: string;
248
+ label: string;
249
+ connectionKey: string;
250
+ }>, "many">>>;
251
+ }, "strip", z.ZodTypeAny, {
252
+ description: string;
253
+ manifestVersion: 1;
254
+ id: string;
255
+ name: string;
256
+ version: string;
257
+ applicationType: string;
258
+ entry: string;
259
+ kickableTasks: string[];
260
+ webhooks: string[];
261
+ ops: string[];
262
+ pollTasks: {
263
+ task: string;
264
+ everyMinutes: number;
265
+ }[];
266
+ scopes: string[];
267
+ workspaceTools: string[];
268
+ connections: {
269
+ key: string;
270
+ kind: "oauth2" | "apiKey";
271
+ label: string;
272
+ description?: string | undefined;
273
+ authorizeUrl?: string | undefined;
274
+ tokenUrl?: string | undefined;
275
+ oauthScopes?: string[] | undefined;
276
+ clientIdEnv?: string | undefined;
277
+ clientSecretEnv?: string | undefined;
278
+ headerNames?: string[] | undefined;
279
+ }[];
280
+ fileProviders: {
281
+ key: string;
282
+ label: string;
283
+ connectionKey: string;
284
+ }[];
285
+ icon?: string | undefined;
286
+ author?: {
287
+ name: string;
288
+ email?: string | undefined;
289
+ url?: string | undefined;
290
+ } | undefined;
291
+ platformApi?: {
292
+ min: string;
293
+ max?: string | undefined;
294
+ } | undefined;
295
+ fileSources?: {
296
+ providers: string[];
297
+ workspace?: "read" | "readwrite" | undefined;
298
+ } | undefined;
299
+ }, {
300
+ description: string;
301
+ manifestVersion: 1;
302
+ id: string;
303
+ name: string;
304
+ version: string;
305
+ applicationType: string;
306
+ entry: string;
307
+ icon?: string | undefined;
308
+ author?: {
309
+ name: string;
310
+ email?: string | undefined;
311
+ url?: string | undefined;
312
+ } | undefined;
313
+ kickableTasks?: string[] | undefined;
314
+ webhooks?: string[] | undefined;
315
+ ops?: string[] | undefined;
316
+ pollTasks?: {
317
+ task: string;
318
+ everyMinutes: number;
319
+ }[] | undefined;
320
+ platformApi?: {
321
+ min: string;
322
+ max?: string | undefined;
323
+ } | undefined;
324
+ scopes?: string[] | undefined;
325
+ workspaceTools?: string[] | undefined;
326
+ connections?: {
327
+ key: string;
328
+ kind: "oauth2" | "apiKey";
329
+ label: string;
330
+ description?: string | undefined;
331
+ authorizeUrl?: string | undefined;
332
+ tokenUrl?: string | undefined;
333
+ oauthScopes?: string[] | undefined;
334
+ clientIdEnv?: string | undefined;
335
+ clientSecretEnv?: string | undefined;
336
+ headerNames?: string[] | undefined;
337
+ }[] | undefined;
338
+ fileSources?: {
339
+ workspace?: "read" | "readwrite" | undefined;
340
+ providers?: string[] | undefined;
341
+ } | undefined;
342
+ fileProviders?: {
343
+ key: string;
344
+ label: string;
345
+ connectionKey: string;
346
+ }[] | undefined;
347
+ }>;
348
+ export type PluginManifest = z.infer<typeof PluginManifestSchema>;
349
+ export type PluginConnectionDecl = z.infer<typeof PluginConnectionSchema>;
350
+ /** Data-only row the host codegen inlines into registry.gen.ts. */
351
+ export interface InstalledPluginInfo {
352
+ id: string;
353
+ name: string;
354
+ version: string;
355
+ description: string;
356
+ applicationType: string;
357
+ /** Manifest `workspaceTools` — the installed plugin's cross-app grant wall. */
358
+ workspaceTools?: string[];
359
+ }
@@ -0,0 +1,136 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * plugin.json — THE package contract. This file is the source of truth for
4
+ * the schema; the host imports it from here, and
5
+ * `schemas/plugin.schema.json` is generated from it at build time so
6
+ * non-TS tooling (and LLMs) can validate without executing anything.
7
+ *
8
+ * SECRETS NEVER LIVE IN A MANIFEST: oauth2 connections declare provider
9
+ * endpoints + ENV VAR NAMES; apiKey connections declare header NAMES.
10
+ * Value-shaped keys are rejected by `.strict()` and by the validator CLI.
11
+ */
12
+ export const PLUGIN_MANIFEST_VERSION = 1;
13
+ /** The plugin-contract version THIS SDK (and the matching host) speak.
14
+ * Manifests may pin `platformApi: {min, max?}`; the host refuses installs
15
+ * outside the range at sync time (fail loud at install, never at runtime).
16
+ * 1.1.0: fileSources consent + fileProviders contributions (additive). */
17
+ export const PLATFORM_API_VERSION = "1.1.0";
18
+ export const PluginConnectionSchema = z
19
+ .object({
20
+ /** Stable key within the plugin, e.g. "microsoft". */
21
+ key: z.string().regex(/^[a-z][a-z0-9-]*$/),
22
+ kind: z.enum(["oauth2", "apiKey"]),
23
+ label: z.string().min(1).max(60),
24
+ description: z.string().max(300).optional(),
25
+ /** oauth2: provider endpoints (authorization-code + PKCE). */
26
+ authorizeUrl: z.string().url().optional(),
27
+ tokenUrl: z.string().url().optional(),
28
+ oauthScopes: z.array(z.string()).optional(),
29
+ /** oauth2: ENV VAR NAMES holding client credentials. */
30
+ clientIdEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),
31
+ clientSecretEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),
32
+ /** apiKey: header NAMES the plugin will send (never values). */
33
+ headerNames: z.array(z.string()).optional(),
34
+ })
35
+ .strict()
36
+ .refine((c) => c.kind !== "oauth2" ||
37
+ (!!c.authorizeUrl && !!c.tokenUrl && !!c.clientIdEnv), { message: "oauth2 connections require authorizeUrl + tokenUrl + clientIdEnv" });
38
+ export const PluginManifestSchema = z.object({
39
+ manifestVersion: z.literal(PLUGIN_MANIFEST_VERSION),
40
+ /** Directory name under src/plugins/. Kebab-case. */
41
+ id: z.string().regex(/^[a-z][a-z0-9-]*$/),
42
+ name: z.string().min(1).max(80),
43
+ version: z.string().regex(/^\d+\.\d+\.\d+$/),
44
+ description: z.string().min(1).max(500),
45
+ /** The ApplicationSchema.applicationType the entry module declares.
46
+ * MUST be plugin_-namespaced: the platform uses the prefix to tell
47
+ * "unknown plugin type — honest card" apart from retired built-ins,
48
+ * and it keeps plugin types out of the built-in namespace forever. */
49
+ applicationType: z.string().regex(/^plugin_[a-z0-9_]*$/),
50
+ /** Entry module basename (no extension) exporting `pluginSchema`. */
51
+ entry: z.string().regex(/^[a-zA-Z0-9_-]+$/),
52
+ /**
53
+ * Launcher icon: a lucide-react component name ("Bird", "Gamepad2") from the
54
+ * platform's curated set (`PLUGIN_ICON_CHOICES` in src/lib/app-icons.ts).
55
+ * Unknown names fall back to the generic glyph — never a broken tile. This is
56
+ * how a plugin gets a real icon in the picker without a platform edit.
57
+ */
58
+ icon: z.string().regex(/^[A-Z][A-Za-z0-9]*$/).max(40).optional(),
59
+ author: z
60
+ .object({
61
+ name: z.string(),
62
+ email: z.string().optional(),
63
+ url: z.string().optional(),
64
+ })
65
+ .optional(),
66
+ /** Tasks the BROWSER may kick via /api/inngest/send-event. */
67
+ kickableTasks: z.array(z.string()).optional().default([]),
68
+ /** Push-ingress endpoints — POST|GET /api/plugins/<id>/webhook/<name>. */
69
+ webhooks: z.array(z.string().regex(/^[a-z][a-z0-9-]*$/)).optional().default([]),
70
+ /** Server ops — POST /api/plugins/<id>/op/<name> (platform-gated). */
71
+ ops: z.array(z.string().regex(/^[a-z][a-z0-9_-]*$/)).optional().default([]),
72
+ /** Poll cadences for durable tasks (the offline-safe pull lane). */
73
+ pollTasks: z
74
+ .array(z.object({
75
+ task: z.string(),
76
+ everyMinutes: z.number().int().min(5).max(1440),
77
+ }))
78
+ .optional()
79
+ .default([]),
80
+ /** Contract-version pin: refuse install outside [min, max]. */
81
+ platformApi: z
82
+ .object({ min: z.string().regex(/^\d+\.\d+\.\d+$/), max: z.string().regex(/^\d+\.\d+\.\d+$/).optional() })
83
+ .optional(),
84
+ /** Reserved for the review/consent flow. */
85
+ scopes: z.array(z.string()).optional().default([]),
86
+ /**
87
+ * Tools of OTHER apps in the workspace this plugin's UI may invoke through
88
+ * `useWorkspaceTools()` — "<applicationType>:<tool base name>", e.g.
89
+ * "spreadsheet:add_row". This is the grant wall for an INSTALLED plugin:
90
+ * the server refuses a call the manifest does not name (the reviewed PR is
91
+ * the consent — plugins are reviewed code, unlike App-Maker specs, which
92
+ * are data and ask each user). In the Forge's live preview (dev mode) the
93
+ * call rides the board's own tab to the owner's workspace instead.
94
+ */
95
+ workspaceTools: z
96
+ .array(z.string().regex(/^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*$/))
97
+ .optional()
98
+ .default([]),
99
+ /** Third-party logins surfaced in Account settings → Plugins. */
100
+ connections: z.array(PluginConnectionSchema).optional().default([]),
101
+ /**
102
+ * File-access consent (plugin-file-sources.md §3). EXPLICIT-ONLY: absent
103
+ * means the plugin's server code gets NO file API at all. `workspace`
104
+ * grants the workspace source (read / readwrite); `providers` names the
105
+ * OTHER mounts it may read ("google-drive", "local", or another plugin's
106
+ * providerKey). A plugin's own contributed providers are implicit.
107
+ * Rendered verbatim in the Settings consent panel.
108
+ */
109
+ fileSources: z
110
+ .object({
111
+ workspace: z.enum(["read", "readwrite"]).optional(),
112
+ providers: z
113
+ .array(z.string().regex(/^[a-z][a-z0-9-]*$/))
114
+ .optional()
115
+ .default([]),
116
+ })
117
+ .strict()
118
+ .optional(),
119
+ /**
120
+ * File providers this plugin CONTRIBUTES (plugin-file-sources.md §2):
121
+ * one mount per ACTIVE connection of `connectionKey`. `key` is globally
122
+ * unique across installed plugins (host keys workspace/google-drive/local
123
+ * reserved — sync refuses collisions); the implementation is
124
+ * `pluginServer.fileProviders[key]` in server.ts.
125
+ */
126
+ fileProviders: z
127
+ .array(z
128
+ .object({
129
+ key: z.string().regex(/^[a-z][a-z0-9-]*$/),
130
+ connectionKey: z.string().regex(/^[a-z][a-z0-9-]*$/),
131
+ label: z.string().min(1).max(60),
132
+ })
133
+ .strict())
134
+ .optional()
135
+ .default([]),
136
+ });
@@ -0,0 +1,85 @@
1
+ /**
2
+ * React hooks for plugin UIs. HOST-PROVIDED: inside the app,
3
+ * `esoul-sdk/react` is aliased to the real implementations
4
+ * (which read venus state through the injection bridge — never import
5
+ * venus-slice or client-registry yourself: module-init cycle, and a bare
6
+ * require() crashes browser ESM chunks; both were hit live).
7
+ *
8
+ * Outside the host these throw with a clear message; in component tests,
9
+ * mock this module.
10
+ */
11
+ import type { EventData } from "./types.js";
12
+ /** Dispatch a workspace event from your UI — the ONLY sanctioned path.
13
+ * Respects read-only viewers (no-op when the viewer cannot edit). */
14
+ export declare function usePluginEventDispatch(): (evt: EventData<any>) => EventData<any> | null;
15
+ /** Current open chat id, for `chatIdSource` attribution. */
16
+ export declare function usePluginCurrentChatId(): string;
17
+ /** True when the current viewer may mutate this workspace. */
18
+ export declare function useAppCanEdit(): boolean;
19
+ export interface WorkspaceToolCall {
20
+ /** Resolve the target by type: the workspace's oldest non-hidden app of this type. */
21
+ appType?: string;
22
+ /** Or name the exact instance (from `listApps`). */
23
+ targetNodeId?: string;
24
+ /** The tool's BASE name (no instance suffix): "add_row", "read_sheet", "add_event". */
25
+ tool: string;
26
+ args?: Record<string, unknown>;
27
+ }
28
+ export interface WorkspaceToolResult {
29
+ ok: boolean;
30
+ /** The tool's answer, or the refusal — always a sentence a UI can show. */
31
+ text: string;
32
+ }
33
+ export interface WorkspaceAppSummary {
34
+ nodeId: string;
35
+ applicationType: string;
36
+ instanceName: string;
37
+ }
38
+ export interface WorkspaceTools {
39
+ /** False when nothing can answer: a read-only viewer, or a preview outside the Forge. */
40
+ available: boolean;
41
+ /** Where calls land — the workspace's name when known. */
42
+ workspaceName: string | null;
43
+ call: (c: WorkspaceToolCall) => Promise<WorkspaceToolResult>;
44
+ listApps: () => Promise<WorkspaceAppSummary[]>;
45
+ }
46
+ /**
47
+ * Invoke tools of OTHER apps in the workspace (append a spreadsheet row, add a
48
+ * calendar event…). Declare each as "<applicationType>:<tool>" in plugin.json
49
+ * `workspaceTools` — that list is the grant wall once installed. In the
50
+ * Forge's live preview the same call rides the board's tab to the owner's
51
+ * real workspace, so a plugin under construction already talks to its
52
+ * neighbours. Pass the app's identity from its state.
53
+ */
54
+ export declare function useWorkspaceTools(_identity: {
55
+ workspaceId: string;
56
+ nodeId: string;
57
+ }): WorkspaceTools;
58
+ import type { FileEntry, FileSource } from "./files.js";
59
+ export interface PluginWorkspaceFile {
60
+ id: string;
61
+ name: string;
62
+ url: string;
63
+ }
64
+ export interface FileSourcesState {
65
+ sources: FileSource[];
66
+ loading: boolean;
67
+ error: string | null;
68
+ reload: () => void;
69
+ }
70
+ export interface FileEntriesState {
71
+ entries: FileEntry[];
72
+ next: string | null;
73
+ loading: boolean;
74
+ error: string | null;
75
+ errorKind: string | null;
76
+ reload: () => void;
77
+ }
78
+ /** The current workspace's file catalogue, live from the store. */
79
+ export declare function usePluginWorkspaceFiles(): PluginWorkspaceFile[];
80
+ /** Upload a browser File into the workspace (blob → row → live list). */
81
+ export declare function usePluginFileUpload(_workspaceId: string): (file: File) => Promise<PluginWorkspaceFile>;
82
+ /** All mounts the signed-in user can see for this workspace. */
83
+ export declare function useFileSources(_workspaceId: string | null): FileSourcesState;
84
+ /** One mount's listing; a failing source reports error/errorKind, never []. */
85
+ export declare function useFileSourceEntries(_workspaceId: string | null, _sourceId: string | null, _folderRef?: string): FileEntriesState;
package/dist/react.js ADDED
@@ -0,0 +1,43 @@
1
+ const hostOnly = (name) => {
2
+ throw new Error(`${name} runs only inside the ExternalSoul host. In tests, mock esoul-sdk/react.`);
3
+ };
4
+ /** Dispatch a workspace event from your UI — the ONLY sanctioned path.
5
+ * Respects read-only viewers (no-op when the viewer cannot edit). */
6
+ export function usePluginEventDispatch() {
7
+ return hostOnly("usePluginEventDispatch");
8
+ }
9
+ /** Current open chat id, for `chatIdSource` attribution. */
10
+ export function usePluginCurrentChatId() {
11
+ return hostOnly("usePluginCurrentChatId");
12
+ }
13
+ /** True when the current viewer may mutate this workspace. */
14
+ export function useAppCanEdit() {
15
+ return hostOnly("useAppCanEdit");
16
+ }
17
+ /**
18
+ * Invoke tools of OTHER apps in the workspace (append a spreadsheet row, add a
19
+ * calendar event…). Declare each as "<applicationType>:<tool>" in plugin.json
20
+ * `workspaceTools` — that list is the grant wall once installed. In the
21
+ * Forge's live preview the same call rides the board's tab to the owner's
22
+ * real workspace, so a plugin under construction already talks to its
23
+ * neighbours. Pass the app's identity from its state.
24
+ */
25
+ export function useWorkspaceTools(_identity) {
26
+ return hostOnly("useWorkspaceTools");
27
+ }
28
+ /** The current workspace's file catalogue, live from the store. */
29
+ export function usePluginWorkspaceFiles() {
30
+ return hostOnly("usePluginWorkspaceFiles");
31
+ }
32
+ /** Upload a browser File into the workspace (blob → row → live list). */
33
+ export function usePluginFileUpload(_workspaceId) {
34
+ return hostOnly("usePluginFileUpload");
35
+ }
36
+ /** All mounts the signed-in user can see for this workspace. */
37
+ export function useFileSources(_workspaceId) {
38
+ return hostOnly("useFileSources");
39
+ }
40
+ /** One mount's listing; a failing source reports error/errorKind, never []. */
41
+ export function useFileSourceEntries(_workspaceId, _sourceId, _folderRef) {
42
+ return hostOnly("useFileSourceEntries");
43
+ }