@ensera/plugin-frontend 1.0.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.
- package/README.md +15 -0
- package/dist/index.d.ts +752 -0
- package/dist/index.js +2021 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
declare function createPluginRuntime(ctx: PluginCtx): {
|
|
5
|
+
ctx: PluginCtx;
|
|
6
|
+
fetch: <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
7
|
+
get: <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
8
|
+
post: <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
9
|
+
put: <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
10
|
+
patch: <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
11
|
+
delete: <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
12
|
+
storage: {
|
|
13
|
+
getItem(key: string): string | null;
|
|
14
|
+
setItem(key: string, value: string): void;
|
|
15
|
+
removeItem(key: string): void;
|
|
16
|
+
clear(): void;
|
|
17
|
+
keys(): string[];
|
|
18
|
+
getJSON<T = unknown>(key: string): T | null;
|
|
19
|
+
setJSON(key: string, value: JsonValue): void;
|
|
20
|
+
info(): {
|
|
21
|
+
namespace: string;
|
|
22
|
+
backend: PluginStorageBackend;
|
|
23
|
+
approxBytesUsed?: number;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
log: {
|
|
27
|
+
debug(message: string, meta?: JsonObject): void;
|
|
28
|
+
info(message: string, meta?: JsonObject): void;
|
|
29
|
+
warn(message: string, meta?: JsonObject): void;
|
|
30
|
+
error(message: string, meta?: JsonObject): void;
|
|
31
|
+
};
|
|
32
|
+
notify: {
|
|
33
|
+
send: (notification: PluginNotification, options?: PluginNotificationOptions) => Promise<PluginNotificationResponse>;
|
|
34
|
+
sendBulk: (notifications: PluginNotification[], options?: PluginNotificationOptions) => Promise<PluginNotificationBulkResponse>;
|
|
35
|
+
sendToSelf: (notification: Omit<PluginNotification, "userId">, options?: PluginNotificationOptions) => Promise<PluginNotificationResponse>;
|
|
36
|
+
requestPermission: () => Promise<NotificationPermission>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
type PluginRuntime = ReturnType<typeof createPluginRuntime>;
|
|
40
|
+
/** ---- dispatcher attach ---- */
|
|
41
|
+
type PluginDispatchFn = (req: Omit<PluginDispatchRequest, "type">) => Promise<JsonValue | void>;
|
|
42
|
+
declare function attachActionDispatcher(args: {
|
|
43
|
+
actions: PluginActionsMap;
|
|
44
|
+
runtime: PluginRuntime;
|
|
45
|
+
}): PluginDispatchFn;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Core context passed to every plugin instance
|
|
49
|
+
*/
|
|
50
|
+
type PluginCtx = {
|
|
51
|
+
userId: string;
|
|
52
|
+
workspaceId: string;
|
|
53
|
+
spaceId: string;
|
|
54
|
+
/**
|
|
55
|
+
* Unique per iframe instance (Core generates).
|
|
56
|
+
* For context-menu actions, Core can create hidden instance(s).
|
|
57
|
+
*/
|
|
58
|
+
instanceId: string;
|
|
59
|
+
featureSlug: string;
|
|
60
|
+
apiBase: string;
|
|
61
|
+
token: string;
|
|
62
|
+
tabViewId?: string;
|
|
63
|
+
taskScopeId?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Optional: Core origin for message validation in iframe host/runtime.
|
|
66
|
+
* Example: "http://localhost:3000"
|
|
67
|
+
*/
|
|
68
|
+
coreOrigin?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Optional: how this instance was launched.
|
|
71
|
+
* Backward compatible: older Core can omit.
|
|
72
|
+
*/
|
|
73
|
+
launch?: PluginLaunch;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Launch modes for plugin instances
|
|
77
|
+
*/
|
|
78
|
+
type PluginLaunch = {
|
|
79
|
+
mode: "panel";
|
|
80
|
+
} | {
|
|
81
|
+
mode: "context";
|
|
82
|
+
trigger: "contextmenu";
|
|
83
|
+
x?: number;
|
|
84
|
+
y?: number;
|
|
85
|
+
selectionText?: string;
|
|
86
|
+
targetType?: string;
|
|
87
|
+
targetId?: string;
|
|
88
|
+
pageUrl?: string;
|
|
89
|
+
} | {
|
|
90
|
+
/** Plugin rendered as a floating overlay on top of a panel feature. */
|
|
91
|
+
mode: "overlay";
|
|
92
|
+
trigger: "contextmenu";
|
|
93
|
+
/** The instanceId of the panel feature this overlay is associated with. */
|
|
94
|
+
targetInstanceId: string;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Message sent from a context plugin to Core to request opening an overlay iframe.
|
|
98
|
+
* Core will create a new iframe with launch.mode = "overlay" for this plugin.
|
|
99
|
+
*/
|
|
100
|
+
type PluginOpenOverlayMessage = {
|
|
101
|
+
type: "ENSERA_OPEN_OVERLAY";
|
|
102
|
+
featureSlug: string;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* JSON-serializable value types
|
|
106
|
+
*/
|
|
107
|
+
type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
108
|
+
[key: string]: JsonValue;
|
|
109
|
+
};
|
|
110
|
+
type JsonObject = Record<string, JsonValue>;
|
|
111
|
+
/**
|
|
112
|
+
* Fetch API - Expected response types
|
|
113
|
+
*/
|
|
114
|
+
type PluginFetchExpect = "json" | "text" | "blob" | "none";
|
|
115
|
+
/**
|
|
116
|
+
* Fetch API - Retry configuration
|
|
117
|
+
*/
|
|
118
|
+
type PluginFetchRetry = {
|
|
119
|
+
count: number;
|
|
120
|
+
backoffMs?: number;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Fetch API - Request options
|
|
124
|
+
*/
|
|
125
|
+
type PluginFetchOptions = Omit<RequestInit, "body"> & {
|
|
126
|
+
json?: JsonValue;
|
|
127
|
+
body?: BodyInit;
|
|
128
|
+
timeoutMs?: number;
|
|
129
|
+
retry?: PluginFetchRetry;
|
|
130
|
+
expect?: PluginFetchExpect;
|
|
131
|
+
requestId?: string;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Fetch API - Response wrapper
|
|
135
|
+
*/
|
|
136
|
+
type PluginFetchResponse<T> = {
|
|
137
|
+
data: T;
|
|
138
|
+
status: number;
|
|
139
|
+
headers: Headers;
|
|
140
|
+
url: string;
|
|
141
|
+
requestId: string;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Storage API - Backend types
|
|
145
|
+
*/
|
|
146
|
+
type PluginStorageBackend = "localStorage" | "indexedDB" | "bridge";
|
|
147
|
+
/**
|
|
148
|
+
* Logger API - Log levels
|
|
149
|
+
*/
|
|
150
|
+
type PluginLogLevel = "debug" | "info" | "warn" | "error";
|
|
151
|
+
/**
|
|
152
|
+
* Action System - Action identifier
|
|
153
|
+
*/
|
|
154
|
+
type PluginActionId = string;
|
|
155
|
+
/**
|
|
156
|
+
* Action System - Dispatch request from Core to Plugin
|
|
157
|
+
*/
|
|
158
|
+
type PluginDispatchRequest = {
|
|
159
|
+
type: "ENSERA_DISPATCH";
|
|
160
|
+
featureSlug?: string;
|
|
161
|
+
instanceId?: string;
|
|
162
|
+
requestId: string;
|
|
163
|
+
actionId: PluginActionId;
|
|
164
|
+
payload?: JsonObject;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Action System - Result sent back to Core
|
|
168
|
+
*/
|
|
169
|
+
type PluginDispatchResult = {
|
|
170
|
+
type: "ENSERA_RESULT";
|
|
171
|
+
instanceId?: string;
|
|
172
|
+
requestId: string;
|
|
173
|
+
ok: true;
|
|
174
|
+
data?: JsonValue;
|
|
175
|
+
} | {
|
|
176
|
+
type: "ENSERA_RESULT";
|
|
177
|
+
instanceId?: string;
|
|
178
|
+
requestId: string;
|
|
179
|
+
ok: false;
|
|
180
|
+
error: {
|
|
181
|
+
message: string;
|
|
182
|
+
name?: string;
|
|
183
|
+
code?: string;
|
|
184
|
+
stack?: string;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Action System - Handler function arguments
|
|
189
|
+
*/
|
|
190
|
+
type PluginActionHandlerArgs = {
|
|
191
|
+
actionId: PluginActionId;
|
|
192
|
+
payload?: JsonObject;
|
|
193
|
+
ctx: PluginCtx;
|
|
194
|
+
runtime: PluginRuntime;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Action System - Handler function signature
|
|
198
|
+
*/
|
|
199
|
+
type PluginActionHandler = (args: PluginActionHandlerArgs) => Promise<JsonValue | void> | (JsonValue | void);
|
|
200
|
+
/**
|
|
201
|
+
* Action System - Map of action IDs to handlers
|
|
202
|
+
*/
|
|
203
|
+
type PluginActionsMap = Record<PluginActionId, PluginActionHandler>;
|
|
204
|
+
/**
|
|
205
|
+
* Notification System - Action attached to a notification
|
|
206
|
+
*/
|
|
207
|
+
interface NotificationAction {
|
|
208
|
+
label: string;
|
|
209
|
+
actionId: string;
|
|
210
|
+
payload?: JsonValue;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Notification System - Notification payload
|
|
214
|
+
*/
|
|
215
|
+
interface PluginNotification {
|
|
216
|
+
userId: string;
|
|
217
|
+
type: string;
|
|
218
|
+
title: string;
|
|
219
|
+
message: string;
|
|
220
|
+
metadata?: JsonValue;
|
|
221
|
+
priority?: "low" | "normal" | "high" | "urgent";
|
|
222
|
+
link?: string;
|
|
223
|
+
actions?: NotificationAction[];
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Notification System - Send options
|
|
227
|
+
*/
|
|
228
|
+
interface PluginNotificationOptions {
|
|
229
|
+
/** Skip if user has disabled notifications for this feature */
|
|
230
|
+
respectPreferences?: boolean;
|
|
231
|
+
/** Only send via specific channels */
|
|
232
|
+
channels?: Array<"email" | "push" | "inApp">;
|
|
233
|
+
/** Schedule for later */
|
|
234
|
+
scheduledAt?: Date | string;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Response from Core after sending
|
|
238
|
+
*/
|
|
239
|
+
interface PluginNotificationResponse {
|
|
240
|
+
success: boolean;
|
|
241
|
+
id?: string;
|
|
242
|
+
sent?: boolean;
|
|
243
|
+
emailSent?: boolean;
|
|
244
|
+
pushSent?: boolean;
|
|
245
|
+
error?: string;
|
|
246
|
+
reason?: string;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Bulk send response
|
|
250
|
+
*/
|
|
251
|
+
interface PluginNotificationBulkResponse {
|
|
252
|
+
success: boolean;
|
|
253
|
+
count?: number;
|
|
254
|
+
errors?: Array<{
|
|
255
|
+
index: number;
|
|
256
|
+
userId: string;
|
|
257
|
+
error: string;
|
|
258
|
+
}>;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Notification System - Request sent to Core via postMessage
|
|
262
|
+
*/
|
|
263
|
+
type PluginNotificationRequest = {
|
|
264
|
+
type: "ENSERA_SEND_NOTIFICATION";
|
|
265
|
+
requestId: string;
|
|
266
|
+
payload: PluginNotification & {
|
|
267
|
+
featureSlug: string;
|
|
268
|
+
options?: PluginNotificationOptions;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* PostMessage response from Core
|
|
273
|
+
*/
|
|
274
|
+
type PluginNotificationResultMessage = {
|
|
275
|
+
type: "ENSERA_NOTIFICATION_RESPONSE";
|
|
276
|
+
requestId: string;
|
|
277
|
+
ok: true;
|
|
278
|
+
id: string;
|
|
279
|
+
sent: boolean;
|
|
280
|
+
emailSent: boolean;
|
|
281
|
+
pushSent: boolean;
|
|
282
|
+
} | {
|
|
283
|
+
type: "ENSERA_NOTIFICATION_RESPONSE";
|
|
284
|
+
requestId: string;
|
|
285
|
+
ok: false;
|
|
286
|
+
error: string;
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Notification Configuration - Type definition in package.json
|
|
290
|
+
*/
|
|
291
|
+
interface NotificationTypeConfig {
|
|
292
|
+
id: string;
|
|
293
|
+
label: string;
|
|
294
|
+
description?: string;
|
|
295
|
+
defaultEnabled?: boolean;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Notification Configuration - Feature capabilities in package.json
|
|
299
|
+
*/
|
|
300
|
+
interface NotificationCapabilities {
|
|
301
|
+
enabled: boolean;
|
|
302
|
+
types: NotificationTypeConfig[];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
type PluginErrorPayload = unknown;
|
|
306
|
+
declare class PluginFetchError extends Error {
|
|
307
|
+
readonly status?: number;
|
|
308
|
+
readonly url: string;
|
|
309
|
+
readonly requestId: string;
|
|
310
|
+
readonly payload?: PluginErrorPayload;
|
|
311
|
+
readonly code?: string;
|
|
312
|
+
constructor(args: {
|
|
313
|
+
name?: string;
|
|
314
|
+
message: string;
|
|
315
|
+
url: string;
|
|
316
|
+
requestId: string;
|
|
317
|
+
status?: number;
|
|
318
|
+
payload?: PluginErrorPayload;
|
|
319
|
+
code?: string;
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
declare class PluginAuthError extends PluginFetchError {
|
|
323
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
324
|
+
}
|
|
325
|
+
declare class PluginForbiddenError extends PluginFetchError {
|
|
326
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
327
|
+
}
|
|
328
|
+
declare class PluginNotFoundError extends PluginFetchError {
|
|
329
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
330
|
+
}
|
|
331
|
+
declare class PluginValidationError extends PluginFetchError {
|
|
332
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
333
|
+
}
|
|
334
|
+
declare class PluginRateLimitError extends PluginFetchError {
|
|
335
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
336
|
+
}
|
|
337
|
+
declare class PluginServerError extends PluginFetchError {
|
|
338
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
339
|
+
}
|
|
340
|
+
declare class PluginNetworkError extends PluginFetchError {
|
|
341
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
342
|
+
}
|
|
343
|
+
declare class PluginResponseError extends PluginFetchError {
|
|
344
|
+
constructor(args: ConstructorParameters<typeof PluginFetchError>[0]);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Base storage error
|
|
348
|
+
*/
|
|
349
|
+
declare class PluginStorageError extends Error {
|
|
350
|
+
constructor(message: string);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Quota error (best-effort normalization)
|
|
354
|
+
*/
|
|
355
|
+
declare class PluginStorageQuotaError extends PluginStorageError {
|
|
356
|
+
constructor(message?: string);
|
|
357
|
+
}
|
|
358
|
+
declare class PluginFetchInputError extends Error {
|
|
359
|
+
constructor(message: string);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
declare function createPluginFetch(ctx: PluginCtx): <T = unknown>(path: string, options?: PluginFetchOptions) => Promise<PluginFetchResponse<T>>;
|
|
363
|
+
|
|
364
|
+
declare function makeStorageNamespace(ctx: PluginCtx, version?: number): string;
|
|
365
|
+
declare function createPluginStorage(ctx: PluginCtx): {
|
|
366
|
+
getItem(key: string): string | null;
|
|
367
|
+
setItem(key: string, value: string): void;
|
|
368
|
+
removeItem(key: string): void;
|
|
369
|
+
clear(): void;
|
|
370
|
+
keys(): string[];
|
|
371
|
+
getJSON<T = unknown>(key: string): T | null;
|
|
372
|
+
setJSON(key: string, value: JsonValue): void;
|
|
373
|
+
info(): {
|
|
374
|
+
namespace: string;
|
|
375
|
+
backend: PluginStorageBackend;
|
|
376
|
+
approxBytesUsed?: number;
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
type PluginStorage = ReturnType<typeof createPluginStorage>;
|
|
380
|
+
|
|
381
|
+
declare function createPluginLogger(ctx: PluginCtx): {
|
|
382
|
+
debug(message: string, meta?: JsonObject): void;
|
|
383
|
+
info(message: string, meta?: JsonObject): void;
|
|
384
|
+
warn(message: string, meta?: JsonObject): void;
|
|
385
|
+
error(message: string, meta?: JsonObject): void;
|
|
386
|
+
};
|
|
387
|
+
type PluginLogger = ReturnType<typeof createPluginLogger>;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Helper to define actions with proper typing.
|
|
391
|
+
* Example:
|
|
392
|
+
* export const actions = defineActions({
|
|
393
|
+
* INC_5: async ({ runtime }) => {...}
|
|
394
|
+
* })
|
|
395
|
+
*/
|
|
396
|
+
declare function defineActions<T extends PluginActionsMap>(actions: T): T;
|
|
397
|
+
/**
|
|
398
|
+
* Helpful error to make "unknown action" explicit.
|
|
399
|
+
*/
|
|
400
|
+
declare class PluginUnknownActionError extends Error {
|
|
401
|
+
readonly actionId: string;
|
|
402
|
+
constructor(actionId: string);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Wrap action handler with safe error surface.
|
|
406
|
+
*/
|
|
407
|
+
declare function runActionSafe(args: {
|
|
408
|
+
actions: PluginActionsMap;
|
|
409
|
+
actionId: string;
|
|
410
|
+
payload: any;
|
|
411
|
+
call: () => ReturnType<PluginActionHandler>;
|
|
412
|
+
}): Promise<void | JsonValue>;
|
|
413
|
+
|
|
414
|
+
declare function ContextMenuShell({ children }: {
|
|
415
|
+
children: React.ReactNode;
|
|
416
|
+
}): react_jsx_runtime.JSX.Element;
|
|
417
|
+
|
|
418
|
+
declare function createPluginStorageIndexedDB(ctx: PluginCtx): {
|
|
419
|
+
getItem(key: string): Promise<string | null>;
|
|
420
|
+
setItem(key: string, value: string): Promise<void>;
|
|
421
|
+
removeItem(key: string): Promise<void>;
|
|
422
|
+
clear(): Promise<void>;
|
|
423
|
+
keys(): Promise<string[]>;
|
|
424
|
+
getJSON<T = unknown>(key: string): Promise<T | null>;
|
|
425
|
+
setJSON(key: string, value: JsonValue): Promise<void>;
|
|
426
|
+
info(): Promise<{
|
|
427
|
+
namespace: string;
|
|
428
|
+
backend: PluginStorageBackend;
|
|
429
|
+
}>;
|
|
430
|
+
};
|
|
431
|
+
type PluginStorageIndexedDB = ReturnType<typeof createPluginStorageIndexedDB>;
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Create notification API for feature frontend
|
|
435
|
+
* Uses postMessage to communicate with Core (since feature is in iframe)
|
|
436
|
+
*/
|
|
437
|
+
declare function createPluginNotify(ctx: PluginCtx): {
|
|
438
|
+
send: (notification: PluginNotification, options?: PluginNotificationOptions) => Promise<PluginNotificationResponse>;
|
|
439
|
+
sendBulk: (notifications: PluginNotification[], options?: PluginNotificationOptions) => Promise<PluginNotificationBulkResponse>;
|
|
440
|
+
sendToSelf: (notification: Omit<PluginNotification, "userId">, options?: PluginNotificationOptions) => Promise<PluginNotificationResponse>;
|
|
441
|
+
requestPermission: () => Promise<NotificationPermission>;
|
|
442
|
+
};
|
|
443
|
+
type PluginNotify = ReturnType<typeof createPluginNotify>;
|
|
444
|
+
|
|
445
|
+
type SyncEventType = "sync:task_created" | "sync:task_updated" | "sync:task_deleted" | "sync:tasks_reordered" | "sync:column_created" | "sync:column_updated" | "sync:column_deleted" | "sync:columns_reordered";
|
|
446
|
+
type SyncPayload = {
|
|
447
|
+
id?: string;
|
|
448
|
+
action?: "create" | "update" | "delete" | "reorder";
|
|
449
|
+
[key: string]: unknown;
|
|
450
|
+
};
|
|
451
|
+
/**
|
|
452
|
+
* Call once during plugin init (PluginRuntime.init) to set context.
|
|
453
|
+
* This is needed so broadcast() knows what instanceId to tag messages with
|
|
454
|
+
* and what origin to target.
|
|
455
|
+
*/
|
|
456
|
+
declare function initBroadcast(opts: {
|
|
457
|
+
instanceId: string;
|
|
458
|
+
coreOrigin?: string;
|
|
459
|
+
}): void;
|
|
460
|
+
/**
|
|
461
|
+
* Emit a sync event to sibling plugins in the same Tab View.
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* import { broadcast } from '@ensera/plugin-frontend';
|
|
466
|
+
*
|
|
467
|
+
* // After a successful task mutation:
|
|
468
|
+
* broadcast('sync:task_updated', { id: taskId, action: 'update' });
|
|
469
|
+
* ```
|
|
470
|
+
*
|
|
471
|
+
* Under the hood this sends a postMessage to the parent window (Core).
|
|
472
|
+
* Core's TabViewRenderer then relays it to all sibling iframes.
|
|
473
|
+
* If the plugin is running standalone (no Tab View), this is a no-op.
|
|
474
|
+
*/
|
|
475
|
+
declare function broadcast(event: SyncEventType, payload?: SyncPayload): void;
|
|
476
|
+
type BroadcastCallback = (payload: SyncPayload) => void;
|
|
477
|
+
/**
|
|
478
|
+
* React hook that listens for a specific sync event relayed by Core.
|
|
479
|
+
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```tsx
|
|
482
|
+
* import { useBroadcastListener } from '@ensera/plugin-frontend';
|
|
483
|
+
* import { useQueryClient } from '@tanstack/react-query';
|
|
484
|
+
*
|
|
485
|
+
* function SyncRoot() {
|
|
486
|
+
* const queryClient = useQueryClient();
|
|
487
|
+
*
|
|
488
|
+
* useBroadcastListener('sync:task_updated', () => {
|
|
489
|
+
* queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
|
490
|
+
* });
|
|
491
|
+
*
|
|
492
|
+
* useBroadcastListener('sync:columns_updated', () => {
|
|
493
|
+
* queryClient.invalidateQueries({ queryKey: ['columns'] });
|
|
494
|
+
* queryClient.invalidateQueries({ queryKey: ['statuses'] });
|
|
495
|
+
* });
|
|
496
|
+
*
|
|
497
|
+
* return <App />;
|
|
498
|
+
* }
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
declare function useBroadcastListener(event: SyncEventType | SyncEventType[], callback: BroadcastCallback): void;
|
|
502
|
+
/**
|
|
503
|
+
* Non-hook version for use outside React components.
|
|
504
|
+
* Returns an unsubscribe function.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```ts
|
|
508
|
+
* const unsub = onBroadcast('sync:task_updated', (payload) => {
|
|
509
|
+
* console.log('Task updated:', payload.id);
|
|
510
|
+
* });
|
|
511
|
+
*
|
|
512
|
+
* // Later:
|
|
513
|
+
* unsub();
|
|
514
|
+
* ```
|
|
515
|
+
*/
|
|
516
|
+
declare function onBroadcast(event: SyncEventType | SyncEventType[], callback: BroadcastCallback): () => void;
|
|
517
|
+
|
|
518
|
+
type SyncMessage<T = JsonValue> = {
|
|
519
|
+
type: "STATE_SYNC";
|
|
520
|
+
featureSlug: string;
|
|
521
|
+
instanceId: string;
|
|
522
|
+
clientId: string;
|
|
523
|
+
state: T;
|
|
524
|
+
timestamp: number;
|
|
525
|
+
};
|
|
526
|
+
type SyncCallback<T = JsonValue> = (state: T, source: string) => void;
|
|
527
|
+
/**
|
|
528
|
+
* Creates a synchronized state manager for a plugin instance.
|
|
529
|
+
* Automatically syncs state between context menu and PiP views.
|
|
530
|
+
*/
|
|
531
|
+
declare function createSyncedState<T extends JsonValue>(args: {
|
|
532
|
+
featureSlug: string;
|
|
533
|
+
instanceId: string;
|
|
534
|
+
initialState: T;
|
|
535
|
+
onSync?: SyncCallback<T>;
|
|
536
|
+
}): {
|
|
537
|
+
setState: (newState: T | ((prev: T) => T)) => T;
|
|
538
|
+
getState: () => T;
|
|
539
|
+
cleanup: () => void;
|
|
540
|
+
};
|
|
541
|
+
type SyncedState<T extends JsonValue> = ReturnType<typeof createSyncedState<T>>;
|
|
542
|
+
/**
|
|
543
|
+
* React hook for synced state (optional convenience wrapper)
|
|
544
|
+
*/
|
|
545
|
+
declare function useSyncedState<T extends JsonValue>(args: {
|
|
546
|
+
featureSlug: string;
|
|
547
|
+
instanceId: string;
|
|
548
|
+
initialState: T;
|
|
549
|
+
}): [T, (state: T | ((prev: T) => T)) => void];
|
|
550
|
+
|
|
551
|
+
declare const tokens: {
|
|
552
|
+
readonly spacing: {
|
|
553
|
+
readonly xs: 4;
|
|
554
|
+
readonly sm: 8;
|
|
555
|
+
readonly md: 12;
|
|
556
|
+
readonly lg: 16;
|
|
557
|
+
readonly xl: 20;
|
|
558
|
+
readonly xxl: 24;
|
|
559
|
+
};
|
|
560
|
+
readonly rowHeight: {
|
|
561
|
+
readonly compact: 32;
|
|
562
|
+
readonly default: 44;
|
|
563
|
+
readonly comfortable: 56;
|
|
564
|
+
readonly large: 72;
|
|
565
|
+
};
|
|
566
|
+
readonly fontSize: {
|
|
567
|
+
readonly xs: 11;
|
|
568
|
+
readonly sm: 12;
|
|
569
|
+
readonly md: 14;
|
|
570
|
+
readonly lg: 16;
|
|
571
|
+
readonly xl: 18;
|
|
572
|
+
};
|
|
573
|
+
readonly fontWeight: {
|
|
574
|
+
readonly normal: 400;
|
|
575
|
+
readonly medium: 500;
|
|
576
|
+
readonly semibold: 600;
|
|
577
|
+
readonly bold: 700;
|
|
578
|
+
};
|
|
579
|
+
readonly radius: {
|
|
580
|
+
readonly sm: 4;
|
|
581
|
+
readonly md: 6;
|
|
582
|
+
readonly lg: 8;
|
|
583
|
+
readonly xl: 12;
|
|
584
|
+
readonly full: 9999;
|
|
585
|
+
};
|
|
586
|
+
readonly colors: {
|
|
587
|
+
readonly bg: {
|
|
588
|
+
readonly primary: "#FFFFFF";
|
|
589
|
+
readonly secondary: "#F9FAFB";
|
|
590
|
+
readonly hover: "#F3F4F6";
|
|
591
|
+
readonly active: "#E5E7EB";
|
|
592
|
+
readonly disabled: "#F9FAFB";
|
|
593
|
+
};
|
|
594
|
+
readonly border: {
|
|
595
|
+
readonly default: "#E5E7EB";
|
|
596
|
+
readonly hover: "#D1D5DB";
|
|
597
|
+
readonly focus: "#3B82F6";
|
|
598
|
+
};
|
|
599
|
+
readonly text: {
|
|
600
|
+
readonly primary: "#111827";
|
|
601
|
+
readonly secondary: "#6B7280";
|
|
602
|
+
readonly tertiary: "#9CA3AF";
|
|
603
|
+
readonly disabled: "#D1D5DB";
|
|
604
|
+
readonly inverse: "#FFFFFF";
|
|
605
|
+
};
|
|
606
|
+
readonly accent: {
|
|
607
|
+
readonly primary: "#3B82F6";
|
|
608
|
+
readonly primaryHover: "#2563EB";
|
|
609
|
+
readonly success: "#10B981";
|
|
610
|
+
readonly warning: "#F59E0B";
|
|
611
|
+
readonly danger: "#EF4444";
|
|
612
|
+
};
|
|
613
|
+
};
|
|
614
|
+
readonly shadow: {
|
|
615
|
+
readonly sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)";
|
|
616
|
+
readonly md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)";
|
|
617
|
+
readonly lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)";
|
|
618
|
+
readonly xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)";
|
|
619
|
+
};
|
|
620
|
+
readonly transition: {
|
|
621
|
+
readonly fast: "150ms cubic-bezier(0.4, 0, 0.2, 1)";
|
|
622
|
+
readonly base: "200ms cubic-bezier(0.4, 0, 0.2, 1)";
|
|
623
|
+
readonly slow: "300ms cubic-bezier(0.4, 0, 0.2, 1)";
|
|
624
|
+
};
|
|
625
|
+
};
|
|
626
|
+
type Tokens = typeof tokens;
|
|
627
|
+
|
|
628
|
+
type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
|
|
629
|
+
type ButtonSize = "sm" | "md" | "lg";
|
|
630
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
631
|
+
variant?: ButtonVariant;
|
|
632
|
+
size?: ButtonSize;
|
|
633
|
+
fullWidth?: boolean;
|
|
634
|
+
icon?: React.ReactNode;
|
|
635
|
+
iconPosition?: "left" | "right";
|
|
636
|
+
}
|
|
637
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
638
|
+
|
|
639
|
+
type InputSize = "sm" | "md" | "lg";
|
|
640
|
+
type InputVariant = "default" | "filled";
|
|
641
|
+
interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
|
|
642
|
+
size?: InputSize;
|
|
643
|
+
variant?: InputVariant;
|
|
644
|
+
error?: boolean;
|
|
645
|
+
fullWidth?: boolean;
|
|
646
|
+
leftIcon?: React.ReactNode;
|
|
647
|
+
rightIcon?: React.ReactNode;
|
|
648
|
+
}
|
|
649
|
+
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
|
650
|
+
|
|
651
|
+
type IconButtonSize = "sm" | "md" | "lg";
|
|
652
|
+
type IconButtonVariant = "default" | "ghost" | "primary" | "danger";
|
|
653
|
+
interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
654
|
+
size?: IconButtonSize;
|
|
655
|
+
variant?: IconButtonVariant;
|
|
656
|
+
/**
|
|
657
|
+
* Icon element to display
|
|
658
|
+
*/
|
|
659
|
+
icon: React.ReactNode;
|
|
660
|
+
}
|
|
661
|
+
declare const IconButton: React.ForwardRefExoticComponent<IconButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
662
|
+
|
|
663
|
+
type RowHeight = "compact" | "default" | "comfortable" | "large";
|
|
664
|
+
type RowAlign = "start" | "center" | "end" | "stretch";
|
|
665
|
+
type RowJustify = "start" | "center" | "end" | "between" | "around" | "evenly";
|
|
666
|
+
interface RowProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
667
|
+
/**
|
|
668
|
+
* Predefined height variants based on design tokens
|
|
669
|
+
*/
|
|
670
|
+
height?: RowHeight;
|
|
671
|
+
/**
|
|
672
|
+
* Custom height (overrides height variant)
|
|
673
|
+
*/
|
|
674
|
+
customHeight?: number | string;
|
|
675
|
+
/**
|
|
676
|
+
* Vertical alignment of children
|
|
677
|
+
*/
|
|
678
|
+
align?: RowAlign;
|
|
679
|
+
/**
|
|
680
|
+
* Horizontal distribution of children
|
|
681
|
+
*/
|
|
682
|
+
justify?: RowJustify;
|
|
683
|
+
/**
|
|
684
|
+
* Gap between children (in pixels)
|
|
685
|
+
*/
|
|
686
|
+
gap?: number;
|
|
687
|
+
/**
|
|
688
|
+
* Padding (uses token spacing values)
|
|
689
|
+
*/
|
|
690
|
+
padding?: number;
|
|
691
|
+
/**
|
|
692
|
+
* Whether to fill full width
|
|
693
|
+
*/
|
|
694
|
+
fullWidth?: boolean;
|
|
695
|
+
/**
|
|
696
|
+
* Add divider between children
|
|
697
|
+
*/
|
|
698
|
+
divider?: boolean;
|
|
699
|
+
}
|
|
700
|
+
declare const Row: React.ForwardRefExoticComponent<RowProps & React.RefAttributes<HTMLDivElement>>;
|
|
701
|
+
/**
|
|
702
|
+
* Container component for context menu plugins.
|
|
703
|
+
* Provides consistent height and spacing for all plugin rows.
|
|
704
|
+
*/
|
|
705
|
+
interface ContextRowProps extends Omit<RowProps, "height"> {
|
|
706
|
+
/**
|
|
707
|
+
* Allow the plugin to expand beyond default height
|
|
708
|
+
* @default false
|
|
709
|
+
*/
|
|
710
|
+
expandable?: boolean;
|
|
711
|
+
/**
|
|
712
|
+
* Minimum height constraint (in pixels)
|
|
713
|
+
* @default 44
|
|
714
|
+
*/
|
|
715
|
+
minHeight?: number;
|
|
716
|
+
/**
|
|
717
|
+
* Maximum height constraint (in pixels)
|
|
718
|
+
* @default 120
|
|
719
|
+
*/
|
|
720
|
+
maxHeight?: number;
|
|
721
|
+
}
|
|
722
|
+
declare const ContextRow: React.ForwardRefExoticComponent<ContextRowProps & React.RefAttributes<HTMLDivElement>>;
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Request Core to open this plugin as a floating overlay on top of the
|
|
726
|
+
* panel feature that was right-clicked.
|
|
727
|
+
*
|
|
728
|
+
* Call this from a context-mode plugin when the user clicks "Add Note" (or
|
|
729
|
+
* similar). Core will create a new iframe for the plugin in "overlay" mode
|
|
730
|
+
* and pass `launch.targetInstanceId` in ENSERA_INIT.
|
|
731
|
+
*/
|
|
732
|
+
declare function openOverlay(featureSlug: string): void;
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Sets up a right-click context menu relay from inside a panel feature iframe to Core.
|
|
736
|
+
* Core (SpaceInstanceRenderer) intercepts this message, translates coordinates to
|
|
737
|
+
* page-space, and fires a `panel-context-menu` CustomEvent with the correct instanceId.
|
|
738
|
+
*
|
|
739
|
+
* Call this once in your panel feature's mount() function and invoke the returned
|
|
740
|
+
* cleanup in unmount().
|
|
741
|
+
*
|
|
742
|
+
* @example
|
|
743
|
+
* function mount(container, ctx) {
|
|
744
|
+
* const cleanupCtxMenu = setupContextMenuRelay(ctx);
|
|
745
|
+
* cleanup = () => { cleanupCtxMenu(); reactRoot?.unmount(); ... };
|
|
746
|
+
* }
|
|
747
|
+
*/
|
|
748
|
+
declare function setupContextMenuRelay(ctx: {
|
|
749
|
+
instanceId: string;
|
|
750
|
+
}): () => void;
|
|
751
|
+
|
|
752
|
+
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, ContextMenuShell, ContextRow, type ContextRowProps, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, Input, type InputProps, type InputSize, type InputVariant, type JsonObject, type JsonValue, type NotificationAction, type NotificationCapabilities, type NotificationTypeConfig, type PluginActionHandler, type PluginActionHandlerArgs, type PluginActionId, type PluginActionsMap, PluginAuthError, type PluginCtx, type PluginDispatchFn, type PluginDispatchRequest, type PluginDispatchResult, type PluginErrorPayload, PluginFetchError, type PluginFetchExpect, PluginFetchInputError, type PluginFetchOptions, type PluginFetchResponse, type PluginFetchRetry, PluginForbiddenError, type PluginLaunch, type PluginLogLevel, type PluginLogger, PluginNetworkError, PluginNotFoundError, type PluginNotification, type PluginNotificationBulkResponse, type PluginNotificationOptions, type PluginNotificationRequest, type PluginNotificationResponse, type PluginNotificationResultMessage, type PluginNotify, type PluginOpenOverlayMessage, PluginRateLimitError, PluginResponseError, type PluginRuntime, PluginServerError, type PluginStorage, type PluginStorageBackend, PluginStorageError, type PluginStorageIndexedDB, PluginStorageQuotaError, PluginUnknownActionError, PluginValidationError, Row, type RowAlign, type RowHeight, type RowJustify, type RowProps, type SyncCallback, type SyncEventType, type SyncMessage, type SyncPayload, type SyncedState, type Tokens, attachActionDispatcher, broadcast, createPluginFetch, createPluginLogger, createPluginNotify, createPluginRuntime, createPluginStorage, createPluginStorageIndexedDB, createSyncedState, defineActions, initBroadcast, makeStorageNamespace, onBroadcast, openOverlay, runActionSafe, setupContextMenuRelay, tokens, useBroadcastListener, useSyncedState };
|