@jchat/addon-sdk 1.0.0-alpha.20 → 1.0.0-alpha.22
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/CHANGELOG.md +38 -1
- package/README.md +4 -4
- package/dist/contracts.d.mts +25 -2
- package/dist/contracts.mjs +7 -3
- package/dist/index.mjs +29 -2
- package/dist/index2.d.mts +163 -28
- package/dist/vite.mjs +14 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @jchat/addon-sdk
|
|
2
2
|
|
|
3
|
+
## 1.0.0-alpha.22
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Introduce composer preview slot, active addon coordination, and lifecycle optimizations
|
|
8
|
+
|
|
9
|
+
- Add CHAT_COMPOSER_PREVIEW mount point for live composer rich card previews
|
|
10
|
+
- Optimize message lifecycle pipeline with active addon caching and AbortSignal cancellation
|
|
11
|
+
- Allow passing verifyEntitlement function directly to verifyAddonEntitlement
|
|
12
|
+
- Provide activeAddonIds in AddonProps to enable addon self-coordination
|
|
13
|
+
- Update default service and documentation domains to jchatplatform.com
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Bumped `@jchat/*` dependencies:
|
|
18
|
+
- [`ui@1.0.0-alpha.22`](https://github.com/mjjabarullah/jchat/releases/tag/ui@v1.0.0-alpha.22)
|
|
19
|
+
|
|
20
|
+
## 1.0.0-alpha.21
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- Add message lifecycle interception hooks and chat message card mount point support
|
|
25
|
+
|
|
26
|
+
- Add TypeScript typings for available editor commands in Addon SDK
|
|
27
|
+
|
|
28
|
+
- Add verifyAddonEntitlement runtime helper and AddonServerContext method
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- Remove redundant boilerplate test files
|
|
33
|
+
|
|
34
|
+
- Enhance add-on CSS compilation to ensure consistent styling across dialogs and portals
|
|
35
|
+
|
|
36
|
+
- Bumped `@jchat/*` dependencies:
|
|
37
|
+
- [`icon@1.0.0-alpha.21`](https://github.com/mjjabarullah/jchat/releases/tag/icon@v1.0.0-alpha.21)
|
|
38
|
+
- [`ui@1.0.0-alpha.21`](https://github.com/mjjabarullah/jchat/releases/tag/ui@v1.0.0-alpha.21)
|
|
39
|
+
|
|
3
40
|
## 1.0.0-alpha.20
|
|
4
41
|
|
|
5
42
|
### Patch Changes
|
|
@@ -57,7 +94,7 @@ No changes in this release.
|
|
|
57
94
|
- c5fa55f: Support direct icon imports via `@jchat/addon-sdk/icon` and align icon packs with canonical Lucide icon definitions. Addons can now import `Icons` directly without requiring hook invocation (`useIcons`), while maintaining backward compatibility for existing addons.
|
|
58
95
|
- 27efa80: - Update third-party developer guide in README with complete quick start, architecture specifications, hook references, and mount points
|
|
59
96
|
- Include `LICENSE` file in published npm package distribution
|
|
60
|
-
- Update license badge and terms references to link to official public web address (`https://
|
|
97
|
+
- Update license badge and terms references to link to official public web address (`https://jchatplatform.com/terms`)
|
|
61
98
|
|
|
62
99
|
## 1.0.0-alpha.11
|
|
63
100
|
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# @jchat/addon-sdk
|
|
2
2
|
|
|
3
|
-
Official TypeScript SDK for developing extensions, UI widgets, and server plugins for the [JChat](https://
|
|
3
|
+
Official TypeScript SDK for developing extensions, UI widgets, and server plugins for the [JChat](https://jchatplatform.com) communication platform.
|
|
4
4
|
|
|
5
5
|
Provides typed interfaces, manifest contracts, Vite bundler plugins, and CLI development tooling for building sandboxed JChat addons.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@jchat/addon-sdk)
|
|
8
|
-
[](https://
|
|
8
|
+
[](https://jchatplatform.com/terms)
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -401,10 +401,10 @@ bun run build
|
|
|
401
401
|
1. Build your addon package: `bun run build`.
|
|
402
402
|
2. Ensure all 20 translation files pass validation: `bun test`.
|
|
403
403
|
3. Package your addon distribution archive.
|
|
404
|
-
4. Sign in to the **[JChat Store Developer Portal](https://
|
|
404
|
+
4. Sign in to the **[JChat Store Developer Portal](https://jchatplatform.com/addons)** and submit your addon package for certified distribution.
|
|
405
405
|
|
|
406
406
|
---
|
|
407
407
|
|
|
408
408
|
## License
|
|
409
409
|
|
|
410
|
-
Proprietary — All rights reserved. See the [Commercial EULA & Licensing Terms](https://
|
|
410
|
+
Proprietary — All rights reserved. See the [Commercial EULA & Licensing Terms](https://jchatplatform.com/terms) for full details.
|
package/dist/contracts.d.mts
CHANGED
|
@@ -36,15 +36,36 @@ export declare const MOUNT_POINTS: {
|
|
|
36
36
|
readonly EMOJI_PICKER_GIF_TAB: "emoji-picker-gif-tab";
|
|
37
37
|
/** Custom tab in the emoji/sticker selection panel */
|
|
38
38
|
readonly EMOJI_PICKER_STICKER_TAB: "emoji-picker-sticker-tab";
|
|
39
|
-
/** Full-screen or modal dialog specifically for TubeScan */
|
|
40
|
-
readonly TUBESCAN_DIALOG: "tubescan-dialog";
|
|
41
39
|
/** Dedicated settings panel rendered in the Owner Dashboard */
|
|
42
40
|
readonly OWNER_SETTINGS: "owner-settings";
|
|
43
41
|
/** Dedicated settings panel rendered in the Site Admin Dashboard */
|
|
44
42
|
readonly ADDON_SETTINGS: "addon-settings";
|
|
43
|
+
/** Custom interactive card rendered inside an enriched chat message */
|
|
44
|
+
readonly CHAT_MESSAGE_CARD: "chat-message-card";
|
|
45
|
+
/** Custom badge, audio equalizer, or particle aura rendered on a chat bubble */
|
|
46
|
+
readonly CHAT_MESSAGE_FLAIR: "chat-message-flair";
|
|
47
|
+
/** Custom interactive preview card rendered in the message composer */
|
|
48
|
+
readonly CHAT_COMPOSER_PREVIEW: "chat-composer-preview";
|
|
45
49
|
};
|
|
46
50
|
/** Union type of all valid addon mount points. */
|
|
47
51
|
export type MountPoint = (typeof MOUNT_POINTS)[keyof typeof MOUNT_POINTS];
|
|
52
|
+
/** Parameter specification for an addon slash command. */
|
|
53
|
+
export interface AddonCommandParameter {
|
|
54
|
+
name: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
required?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** Declaration of an addon slash command available in the chat composer. */
|
|
59
|
+
export interface AddonCommandDefinition {
|
|
60
|
+
/** The command keyword without leading slash (e.g. 'yt', 'roll', 'poll') */
|
|
61
|
+
name: string;
|
|
62
|
+
/** Short summary of what the command does, displayed in autocomplete */
|
|
63
|
+
description: string;
|
|
64
|
+
/** Usage syntax displayed as a hint (e.g. '<query | url>') */
|
|
65
|
+
syntax?: string;
|
|
66
|
+
/** Parameters accepted by this command */
|
|
67
|
+
parameters?: AddonCommandParameter[];
|
|
68
|
+
}
|
|
48
69
|
/**
|
|
49
70
|
* The `manifest.json` schema required for every Jchat addon. This file describes how the addon is
|
|
50
71
|
* identified and mounted.
|
|
@@ -117,5 +138,7 @@ export interface AddonManifest {
|
|
|
117
138
|
permissions?: string[];
|
|
118
139
|
/** Custom permissions that should be registered with the host application on installation */
|
|
119
140
|
permissionDefinitions?: AddonPermissionDefinition[];
|
|
141
|
+
/** Interactive slash commands exposed in the chat composer */
|
|
142
|
+
commands?: AddonCommandDefinition[];
|
|
120
143
|
}
|
|
121
144
|
//#endregion
|
package/dist/contracts.mjs
CHANGED
|
@@ -27,12 +27,16 @@ const MOUNT_POINTS = {
|
|
|
27
27
|
EMOJI_PICKER_GIF_TAB: "emoji-picker-gif-tab",
|
|
28
28
|
/** Custom tab in the emoji/sticker selection panel */
|
|
29
29
|
EMOJI_PICKER_STICKER_TAB: "emoji-picker-sticker-tab",
|
|
30
|
-
/** Full-screen or modal dialog specifically for TubeScan */
|
|
31
|
-
TUBESCAN_DIALOG: "tubescan-dialog",
|
|
32
30
|
/** Dedicated settings panel rendered in the Owner Dashboard */
|
|
33
31
|
OWNER_SETTINGS: "owner-settings",
|
|
34
32
|
/** Dedicated settings panel rendered in the Site Admin Dashboard */
|
|
35
|
-
ADDON_SETTINGS: "addon-settings"
|
|
33
|
+
ADDON_SETTINGS: "addon-settings",
|
|
34
|
+
/** Custom interactive card rendered inside an enriched chat message */
|
|
35
|
+
CHAT_MESSAGE_CARD: "chat-message-card",
|
|
36
|
+
/** Custom badge, audio equalizer, or particle aura rendered on a chat bubble */
|
|
37
|
+
CHAT_MESSAGE_FLAIR: "chat-message-flair",
|
|
38
|
+
/** Custom interactive preview card rendered in the message composer */
|
|
39
|
+
CHAT_COMPOSER_PREVIEW: "chat-composer-preview"
|
|
36
40
|
};
|
|
37
41
|
//#endregion
|
|
38
42
|
export { MOUNT_POINTS };
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { MOUNT_POINTS } from "./contracts.mjs";
|
|
|
2
2
|
import { a as useTranslation, i as useLocale, n as LocaleContext, r as createTranslator, t as HOST_LANGUAGES } from "./i18n.mjs";
|
|
3
3
|
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
//#region package.json
|
|
5
|
-
var version = "1.0.0-alpha.
|
|
5
|
+
var version = "1.0.0-alpha.21";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/query.ts
|
|
8
8
|
/**
|
|
@@ -145,5 +145,32 @@ function useAddonSDK() {
|
|
|
145
145
|
function getAddonSdkVersion() {
|
|
146
146
|
return version;
|
|
147
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Verifies purchase entitlement and identity integrity for commercial addons. Throws an error if
|
|
150
|
+
* the addon fails entitlement verification or if its manifest ID has been tampered with to
|
|
151
|
+
* impersonate another addon.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ;```ts
|
|
155
|
+
* export default ({ verifyEntitlement, db, t }: AddonServerContext, app: AddonApp) => {
|
|
156
|
+
* verifyAddonEntitlement("tubescanpro", verifyEntitlement)
|
|
157
|
+
* return app.get("/trending", async () => { ... })
|
|
158
|
+
* }
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @param addonId - The canonical addon ID defined by the publisher (e.g. 'tubescanpro')
|
|
162
|
+
* @param target - Either the `verifyEntitlement` function from context or the `AddonServerContext`
|
|
163
|
+
* object itself
|
|
164
|
+
* @returns True if valid
|
|
165
|
+
* @throws Error if entitlement verification fails
|
|
166
|
+
*/
|
|
167
|
+
function verifyAddonEntitlement(addonId, target) {
|
|
168
|
+
const verifyFn = typeof target === "function" ? target : target?.verifyEntitlement;
|
|
169
|
+
if (verifyFn) {
|
|
170
|
+
if (!verifyFn(addonId)) throw new Error(`addon_entitlement_verification_failed:${addonId}`);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
148
175
|
//#endregion
|
|
149
|
-
export { HOST_LANGUAGES, LocaleContext, MOUNT_POINTS, createTranslator, defineAddonManifest, defineAddonServer, getAddonSdkVersion, useAddonInfiniteQuery, useAddonMutation, useAddonQuery, useAddonSDK, useLocale, useQueryClient, useTranslation };
|
|
176
|
+
export { HOST_LANGUAGES, LocaleContext, MOUNT_POINTS, createTranslator, defineAddonManifest, defineAddonServer, getAddonSdkVersion, useAddonInfiniteQuery, useAddonMutation, useAddonQuery, useAddonSDK, useLocale, useQueryClient, useTranslation, verifyAddonEntitlement };
|
package/dist/index2.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as IconPack, n as IconComponent, r as IconName } from "./types.mjs";
|
|
2
|
-
import { AddonManifest, AddonPermissionDefinition, MOUNT_POINTS, MountPoint } from "./contracts.mjs";
|
|
2
|
+
import { AddonCommandDefinition, AddonCommandParameter, AddonManifest, AddonPermissionDefinition, MOUNT_POINTS, MountPoint } from "./contracts.mjs";
|
|
3
3
|
import { InfiniteData, MutationFunction, QueryFunction, QueryFunctionContext, QueryKey, UndefinedInitialDataInfiniteOptions, UndefinedInitialDataOptions, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult, UseQueryResult, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { Elysia, t } from "elysia";
|
|
5
5
|
import { ColumnType, Generated, Insertable, JSONColumnType, Kysely, Selectable, Updateable } from "kysely";
|
|
@@ -209,6 +209,70 @@ export interface AddonServerEmitTarget {
|
|
|
209
209
|
/** Target a specific user */
|
|
210
210
|
userId?: string;
|
|
211
211
|
}
|
|
212
|
+
export interface AddonMessageMutableData {
|
|
213
|
+
/** Message content (can be Slate JSON structure or string) */
|
|
214
|
+
content: unknown;
|
|
215
|
+
/** Optional message attachments */
|
|
216
|
+
attachments?: unknown[] | null;
|
|
217
|
+
/**
|
|
218
|
+
* Namespaced metadata bucket for this addon. Keyed as `metadata["addon:<addonId>"]`. Storing data
|
|
219
|
+
* here automatically attaches it to the message broadcast and database record.
|
|
220
|
+
*/
|
|
221
|
+
metadata: Record<string, unknown>;
|
|
222
|
+
}
|
|
223
|
+
export interface AddonMessageContext {
|
|
224
|
+
/** The site ID where the message is being sent */
|
|
225
|
+
siteId: string;
|
|
226
|
+
/** The chat room ID */
|
|
227
|
+
roomId: string;
|
|
228
|
+
/** The authenticated user sending the message (read-only) */
|
|
229
|
+
user: AddonRequestUser;
|
|
230
|
+
/** Mutable message payload */
|
|
231
|
+
message: AddonMessageMutableData;
|
|
232
|
+
/** Convenience method to set metadata under this addon's namespace */
|
|
233
|
+
setMetadata: (key: string, value: unknown) => void;
|
|
234
|
+
/**
|
|
235
|
+
* Abort the message sending pipeline with a user-facing error code and reason. Only active during
|
|
236
|
+
* `beforeValidate` and `transformContent`.
|
|
237
|
+
*/
|
|
238
|
+
abort: (error: {
|
|
239
|
+
code: string;
|
|
240
|
+
reason?: string;
|
|
241
|
+
}) => never;
|
|
242
|
+
/**
|
|
243
|
+
* AbortSignal triggered if this interceptor times out or the message pipeline is cancelled. Can
|
|
244
|
+
* be passed to `fetch(url, { signal: context.signal })` or async operations.
|
|
245
|
+
*/
|
|
246
|
+
signal?: AbortSignal;
|
|
247
|
+
}
|
|
248
|
+
export interface AddonMessageAfterSaveContext {
|
|
249
|
+
siteId: string;
|
|
250
|
+
roomId: string;
|
|
251
|
+
user: AddonRequestUser;
|
|
252
|
+
message: {
|
|
253
|
+
id: string;
|
|
254
|
+
content: unknown;
|
|
255
|
+
attachments?: unknown[] | null;
|
|
256
|
+
metadata?: Record<string, unknown> | null;
|
|
257
|
+
type: string;
|
|
258
|
+
createdAt: Date | string;
|
|
259
|
+
};
|
|
260
|
+
/** AbortSignal triggered if the observer times out or is cancelled. */
|
|
261
|
+
signal?: AbortSignal;
|
|
262
|
+
}
|
|
263
|
+
export interface AddonPipelineHooks {
|
|
264
|
+
/** Optional priority ordering. Lower numbers execute first (e.g. 10 runs before 100). Default is 100. */
|
|
265
|
+
priority?: number;
|
|
266
|
+
/**
|
|
267
|
+
* Run before validation to inspect or guard actions (rate-limits, permission gates). Throw or
|
|
268
|
+
* call `context.abort()` to reject the message.
|
|
269
|
+
*/
|
|
270
|
+
beforeValidate?: (context: AddonMessageContext) => Promise<void> | void;
|
|
271
|
+
/** Run before persistence to mutate text, parse slash commands, or enrich metadata. */
|
|
272
|
+
transformContent?: (context: AddonMessageContext) => Promise<void> | void;
|
|
273
|
+
/** Run asynchronously after database save (fire-and-forget observers). */
|
|
274
|
+
afterSave?: (context: AddonMessageAfterSaveContext) => Promise<void> | void;
|
|
275
|
+
}
|
|
212
276
|
/**
|
|
213
277
|
* Context provided to an addon's server-side factory. Parameterize it with the addon's table
|
|
214
278
|
* interface: `AddonServerContext<MyAddonDatabase>`.
|
|
@@ -249,6 +313,21 @@ export interface AddonServerContext<TDatabase = Record<string, Record<string, un
|
|
|
249
313
|
* `sdk.events.on('addon:<addonId>:<event>', callback)` or `sdk.events.on(event, callback)`.
|
|
250
314
|
*/
|
|
251
315
|
emit: (event: string, payload: unknown, target?: AddonServerEmitTarget) => Promise<void>;
|
|
316
|
+
/**
|
|
317
|
+
* Register lifecycle interception hooks for chat messages. Hooks run in the core chat execution
|
|
318
|
+
* path with strict 50ms timeout guards and fail-open fault tolerance.
|
|
319
|
+
*/
|
|
320
|
+
pipeline?: {
|
|
321
|
+
register: (hooks: AddonPipelineHooks) => void;
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* Cryptographically verify that this addon instance holds a valid host license entitlement.
|
|
325
|
+
* Commercial paid addons should invoke this or call `verifyAddonEntitlement(addonId, context)`.
|
|
326
|
+
*
|
|
327
|
+
* @param expectedAddonId - The canonical addon ID defined by the publisher
|
|
328
|
+
* @returns True if valid, or false if entitlement is missing or invalid
|
|
329
|
+
*/
|
|
330
|
+
verifyEntitlement?: (expectedAddonId?: string) => boolean;
|
|
252
331
|
}
|
|
253
332
|
/**
|
|
254
333
|
* Elysia app instance provided to addon server endpoints with Jchat macro metadata (e.g.
|
|
@@ -309,6 +388,12 @@ export interface AddonProps {
|
|
|
309
388
|
locale?: string;
|
|
310
389
|
/** Text direction for the current locale */
|
|
311
390
|
dir?: "ltr" | "rtl";
|
|
391
|
+
/** The message object when rendered inside 'chat-message-card' or 'chat-message-flair' */
|
|
392
|
+
message?: unknown;
|
|
393
|
+
/** The addon's specific payload extracted from message.metadata */
|
|
394
|
+
addonData?: unknown;
|
|
395
|
+
/** List of active addon IDs enabled on the current site */
|
|
396
|
+
activeAddonIds?: string[];
|
|
312
397
|
}
|
|
313
398
|
export interface AddonApi {
|
|
314
399
|
get: <TResponse = unknown>(path: string) => Promise<TResponse>;
|
|
@@ -337,6 +422,59 @@ export interface AddonFont {
|
|
|
337
422
|
/** Relative size multiplier — apply this to base font sizes to match the host's rendering */
|
|
338
423
|
scale: number;
|
|
339
424
|
}
|
|
425
|
+
export interface AddonEditorInsertImagePayload {
|
|
426
|
+
src: string;
|
|
427
|
+
altText: string;
|
|
428
|
+
emoji?: {
|
|
429
|
+
col: number;
|
|
430
|
+
row: number;
|
|
431
|
+
size: number;
|
|
432
|
+
};
|
|
433
|
+
className?: string;
|
|
434
|
+
}
|
|
435
|
+
export interface AddonEditorInsertEmojiPayload {
|
|
436
|
+
col: number;
|
|
437
|
+
row: number;
|
|
438
|
+
unicode: string;
|
|
439
|
+
shortcode?: string;
|
|
440
|
+
}
|
|
441
|
+
export interface AddonEditorCommandMap {
|
|
442
|
+
INSERT_YOUTUBE_COMMAND: string;
|
|
443
|
+
INSERT_TEXT: string;
|
|
444
|
+
INSERT_TEXT_COMMAND: string;
|
|
445
|
+
INSERT_MENTION_COMMAND: string;
|
|
446
|
+
INSERT_IMAGE_COMMAND: AddonEditorInsertImagePayload;
|
|
447
|
+
INSERT_EMOJI_COMMAND: AddonEditorInsertEmojiPayload;
|
|
448
|
+
CLEAR_EDITOR: void;
|
|
449
|
+
CLEAR_EDITOR_COMMAND: void;
|
|
450
|
+
}
|
|
451
|
+
export type AddonEditorCommand = keyof AddonEditorCommandMap;
|
|
452
|
+
export interface AddonEditorApi {
|
|
453
|
+
/**
|
|
454
|
+
* Trigger a specialized editor command defined by the host.
|
|
455
|
+
*
|
|
456
|
+
* @example
|
|
457
|
+
* sdk.editor.dispatchCommand("INSERT_YOUTUBE_COMMAND", "dQw4w9WgXcQ")
|
|
458
|
+
*/
|
|
459
|
+
dispatchCommand: <C extends AddonEditorCommand>(command: C, ...args: AddonEditorCommandMap[C] extends void ? [payload?: undefined] : [payload: AddonEditorCommandMap[C]]) => void;
|
|
460
|
+
/**
|
|
461
|
+
* Insert a low-level Slate node directly at the user's cursor position.
|
|
462
|
+
*
|
|
463
|
+
* @param node - A valid Slate Descendant or Fragment object
|
|
464
|
+
*/
|
|
465
|
+
insertNode: (node: unknown) => void;
|
|
466
|
+
/**
|
|
467
|
+
* Upload and attach a file to the current message without inserting it inline. Users will see the
|
|
468
|
+
* file in the attachment bar below the editor.
|
|
469
|
+
*/
|
|
470
|
+
addAttachment: (attachment: {
|
|
471
|
+
url: string;
|
|
472
|
+
name: string;
|
|
473
|
+
type: string;
|
|
474
|
+
}) => void;
|
|
475
|
+
/** Force the browser focus back to the editor input */
|
|
476
|
+
focus: () => void;
|
|
477
|
+
}
|
|
340
478
|
/**
|
|
341
479
|
* The bridge between your addon and the Jchat host application. Use the `useAddonSDK()` hook to
|
|
342
480
|
* access this interface in your components.
|
|
@@ -370,32 +508,7 @@ export interface AddonSDK {
|
|
|
370
508
|
* Interaction utilities for the active Slate message editor. Only available if your addon is
|
|
371
509
|
* mounted near the chat input.
|
|
372
510
|
*/
|
|
373
|
-
editor:
|
|
374
|
-
/**
|
|
375
|
-
* Trigger a specialized editor command defined by the host.
|
|
376
|
-
*
|
|
377
|
-
* @example
|
|
378
|
-
* sdk.editor.dispatchCommand("INSERT_YOUTUBE_COMMAND", "dQw4w9WgXcQ")
|
|
379
|
-
*/
|
|
380
|
-
dispatchCommand: (command: string, payload?: unknown) => void;
|
|
381
|
-
/**
|
|
382
|
-
* Insert a low-level Slate node directly at the user's cursor position.
|
|
383
|
-
*
|
|
384
|
-
* @param node - A valid Slate Descendant or Fragment object
|
|
385
|
-
*/
|
|
386
|
-
insertNode: (node: unknown) => void;
|
|
387
|
-
/**
|
|
388
|
-
* Upload and attach a file to the current message without inserting it inline. Users will see
|
|
389
|
-
* the file in the attachment bar below the editor.
|
|
390
|
-
*/
|
|
391
|
-
addAttachment: (attachment: {
|
|
392
|
-
url: string;
|
|
393
|
-
name: string;
|
|
394
|
-
type: string;
|
|
395
|
-
}) => void;
|
|
396
|
-
/** Force the browser focus back to the editor input */
|
|
397
|
-
focus: () => void;
|
|
398
|
-
};
|
|
511
|
+
editor: AddonEditorApi;
|
|
399
512
|
/** Event Bus for reacting to real-time application state changes. */
|
|
400
513
|
events: {
|
|
401
514
|
/**
|
|
@@ -474,5 +587,27 @@ export declare function useAddonSDK(): AddonSDK;
|
|
|
474
587
|
* @returns
|
|
475
588
|
*/
|
|
476
589
|
export declare function getAddonSdkVersion(): string;
|
|
590
|
+
/**
|
|
591
|
+
* Verifies purchase entitlement and identity integrity for commercial addons. Throws an error if
|
|
592
|
+
* the addon fails entitlement verification or if its manifest ID has been tampered with to
|
|
593
|
+
* impersonate another addon.
|
|
594
|
+
*
|
|
595
|
+
* @example
|
|
596
|
+
* ;```ts
|
|
597
|
+
* export default ({ verifyEntitlement, db, t }: AddonServerContext, app: AddonApp) => {
|
|
598
|
+
* verifyAddonEntitlement("tubescanpro", verifyEntitlement)
|
|
599
|
+
* return app.get("/trending", async () => { ... })
|
|
600
|
+
* }
|
|
601
|
+
* ```
|
|
602
|
+
*
|
|
603
|
+
* @param addonId - The canonical addon ID defined by the publisher (e.g. 'tubescanpro')
|
|
604
|
+
* @param target - Either the `verifyEntitlement` function from context or the `AddonServerContext`
|
|
605
|
+
* object itself
|
|
606
|
+
* @returns True if valid
|
|
607
|
+
* @throws Error if entitlement verification fails
|
|
608
|
+
*/
|
|
609
|
+
export declare function verifyAddonEntitlement(addonId: string, target?: ((expectedAddonId?: string) => boolean) | {
|
|
610
|
+
verifyEntitlement?: (expectedAddonId?: string) => boolean;
|
|
611
|
+
}): boolean;
|
|
477
612
|
//#endregion
|
|
478
|
-
export { type AddonManifest, type AddonPermissionDefinition, type ColumnType, type Generated, type IconComponent, type IconName, type IconPack, type InfiniteData, type Insertable, type JSONColumnType, MOUNT_POINTS, type MountPoint, type QueryKey, type Selectable, type Updateable, useQueryClient };
|
|
613
|
+
export { type AddonCommandDefinition, type AddonCommandParameter, type AddonManifest, type AddonPermissionDefinition, type ColumnType, type Generated, type IconComponent, type IconName, type IconPack, type InfiniteData, type Insertable, type JSONColumnType, MOUNT_POINTS, type MountPoint, type QueryKey, type Selectable, type Updateable, useQueryClient };
|
package/dist/vite.mjs
CHANGED
|
@@ -82,7 +82,7 @@ function jchatAddon(options) {
|
|
|
82
82
|
if (!fs.existsSync(buildDir)) return;
|
|
83
83
|
const bundleFile = fs.readdirSync(buildDir).find((f) => f.includes("ui") && f.endsWith(".js"));
|
|
84
84
|
if (!bundleFile) return;
|
|
85
|
-
if (options.css !== false) embedCssIntoBundle(buildDir
|
|
85
|
+
if (options.css !== false) embedCssIntoBundle(buildDir);
|
|
86
86
|
let manifest = {
|
|
87
87
|
...manifestData,
|
|
88
88
|
version: pkg.version,
|
|
@@ -243,7 +243,7 @@ function requireAddonSigningKey(signingPrivateKey, developmentBuild) {
|
|
|
243
243
|
if (developmentBuild) return void 0;
|
|
244
244
|
throw new Error("Database-bearing addon builds require JCHAT_ADDON_SIGNING_PRIVATE_KEY");
|
|
245
245
|
}
|
|
246
|
-
function embedCssIntoBundle(buildDir
|
|
246
|
+
function embedCssIntoBundle(buildDir) {
|
|
247
247
|
const files = fs.readdirSync(buildDir);
|
|
248
248
|
const cssFile = files.find((f) => f.endsWith(".css"));
|
|
249
249
|
const jsFile = files.find((f) => f.includes("ui") && f.endsWith(".js"));
|
|
@@ -274,7 +274,7 @@ function embedCssIntoBundle(buildDir, addonId) {
|
|
|
274
274
|
css = css.replace(/\.user-border\s*\{[^}]+\}/g, "");
|
|
275
275
|
css = css.replace(/\.scrollbar-hide[^{]*\{[^}]+\}/g, "");
|
|
276
276
|
css = css.replace(/@layer\s+components(?:\s*\{[^}]*\}|;)/g, "");
|
|
277
|
-
css = minifyCss(
|
|
277
|
+
css = minifyCss(css);
|
|
278
278
|
}
|
|
279
279
|
if (css.trim().length > 0) {
|
|
280
280
|
const injection = `
|
|
@@ -294,12 +294,14 @@ function embedCssIntoBundle(buildDir, addonId) {
|
|
|
294
294
|
} catch {}
|
|
295
295
|
}
|
|
296
296
|
function stripLayer(css, layerName) {
|
|
297
|
-
const
|
|
298
|
-
let
|
|
299
|
-
while (
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
297
|
+
const regex = new RegExp(`@layer\\s+${layerName}\\s*\\{`);
|
|
298
|
+
let match = regex.exec(css);
|
|
299
|
+
while (match) {
|
|
300
|
+
const startIdx = match.index;
|
|
301
|
+
const openBraceIdx = startIdx + match[0].length - 1;
|
|
302
|
+
let braceCount = 1;
|
|
303
|
+
let endIdx = -1;
|
|
304
|
+
for (let i = openBraceIdx + 1; i < css.length; i++) if (css[i] === "{") braceCount++;
|
|
303
305
|
else if (css[i] === "}") {
|
|
304
306
|
braceCount--;
|
|
305
307
|
if (braceCount === 0) {
|
|
@@ -307,8 +309,9 @@ function stripLayer(css, layerName) {
|
|
|
307
309
|
break;
|
|
308
310
|
}
|
|
309
311
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
+
if (endIdx === -1) break;
|
|
313
|
+
css = css.slice(0, startIdx) + css.slice(endIdx + 1);
|
|
314
|
+
match = regex.exec(css);
|
|
312
315
|
}
|
|
313
316
|
return css;
|
|
314
317
|
}
|