@jchat/addon-sdk 1.0.0-alpha.23 → 1.0.0-alpha.25
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 +45 -9
- package/LICENSE +1 -1
- package/README.md +4 -4
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/contracts.d.mts +2 -144
- package/dist/contracts.mjs +23 -1
- package/dist/contracts2.d.mts +270 -0
- package/dist/diagnostics.d.mts +1 -1
- package/dist/diagnostics.mjs +1 -1
- package/dist/i18n-validator.mjs +4 -3
- package/dist/i18n.mjs +1 -23
- package/dist/index.mjs +24 -4
- package/dist/index2.d.mts +68 -25
- package/dist/signing.d.mts +2 -0
- package/dist/signing.mjs +73 -0
- package/dist/signing2.d.mts +13 -0
- package/dist/testing.d.mts +2 -0
- package/dist/testing.mjs +144 -0
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +2 -2
- package/package.json +20 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @jchat/addon-sdk
|
|
2
2
|
|
|
3
|
+
## 1.0.0-alpha.25
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Update package metadata, documentation, and license links
|
|
8
|
+
|
|
9
|
+
- Bumped `@jchat/*` dependencies:
|
|
10
|
+
- [`icon@1.0.0-alpha.23`](https://github.com/jchatcloud/jchat/releases/tag/icon@v1.0.0-alpha.23)
|
|
11
|
+
- [`ui@1.0.0-alpha.25`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.25)
|
|
12
|
+
|
|
13
|
+
## 1.0.0-alpha.24
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- Add required logo property to AddonManifest contract
|
|
18
|
+
|
|
19
|
+
- Add set operations, atomic rate limiter, and mock testing utilities
|
|
20
|
+
|
|
21
|
+
- Add distribution property to AddonManifest for commercial and free classification
|
|
22
|
+
|
|
23
|
+
- Export typed chat message, attachment, runtime log, and signing contracts
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- Export HOST_LOCALES in contracts module
|
|
28
|
+
|
|
29
|
+
- Update default service and documentation domains to jchatcloud.com
|
|
30
|
+
|
|
31
|
+
- Update package repository URLs to jarvistack organization
|
|
32
|
+
|
|
33
|
+
- Improve code formatting and style consistency
|
|
34
|
+
|
|
35
|
+
- Bumped `@jchat/*` dependencies:
|
|
36
|
+
- [`icon@1.0.0-alpha.22`](https://github.com/jchatcloud/jchat/releases/tag/icon@v1.0.0-alpha.22)
|
|
37
|
+
- [`ui@1.0.0-alpha.24`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.24)
|
|
38
|
+
|
|
3
39
|
## 1.0.0-alpha.23
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
|
@@ -7,14 +43,14 @@
|
|
|
7
43
|
- Support newline normalization for addon signing private keys
|
|
8
44
|
|
|
9
45
|
- Bumped `@jchat/*` dependencies:
|
|
10
|
-
- [`ui@1.0.0-alpha.23`](https://github.com/
|
|
46
|
+
- [`ui@1.0.0-alpha.23`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.23)
|
|
11
47
|
|
|
12
48
|
## 1.0.0-alpha.22
|
|
13
49
|
|
|
14
50
|
### Minor Changes
|
|
15
51
|
|
|
16
52
|
- Introduce composer preview slot, active addon coordination, and lifecycle optimizations
|
|
17
|
-
|
|
53
|
+
|
|
18
54
|
- Add CHAT_COMPOSER_PREVIEW mount point for live composer rich card previews
|
|
19
55
|
- Optimize message lifecycle pipeline with active addon caching and AbortSignal cancellation
|
|
20
56
|
- Allow passing verifyEntitlement function directly to verifyAddonEntitlement
|
|
@@ -24,7 +60,7 @@
|
|
|
24
60
|
### Patch Changes
|
|
25
61
|
|
|
26
62
|
- Bumped `@jchat/*` dependencies:
|
|
27
|
-
- [`ui@1.0.0-alpha.22`](https://github.com/
|
|
63
|
+
- [`ui@1.0.0-alpha.22`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.22)
|
|
28
64
|
|
|
29
65
|
## 1.0.0-alpha.21
|
|
30
66
|
|
|
@@ -43,24 +79,24 @@
|
|
|
43
79
|
- Enhance add-on CSS compilation to ensure consistent styling across dialogs and portals
|
|
44
80
|
|
|
45
81
|
- Bumped `@jchat/*` dependencies:
|
|
46
|
-
- [`icon@1.0.0-alpha.21`](https://github.com/
|
|
47
|
-
- [`ui@1.0.0-alpha.21`](https://github.com/
|
|
82
|
+
- [`icon@1.0.0-alpha.21`](https://github.com/jchatcloud/jchat/releases/tag/icon@v1.0.0-alpha.21)
|
|
83
|
+
- [`ui@1.0.0-alpha.21`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.21)
|
|
48
84
|
|
|
49
85
|
## 1.0.0-alpha.20
|
|
50
86
|
|
|
51
87
|
### Patch Changes
|
|
52
88
|
|
|
53
89
|
- Bumped `@jchat/*` dependencies:
|
|
54
|
-
- [`icon@1.0.0-alpha.20`](https://github.com/
|
|
55
|
-
- [`ui@1.0.0-alpha.20`](https://github.com/
|
|
90
|
+
- [`icon@1.0.0-alpha.20`](https://github.com/jchatcloud/jchat/releases/tag/icon@v1.0.0-alpha.20)
|
|
91
|
+
- [`ui@1.0.0-alpha.20`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.20)
|
|
56
92
|
|
|
57
93
|
## 1.0.0-alpha.19
|
|
58
94
|
|
|
59
95
|
### Patch Changes
|
|
60
96
|
|
|
61
97
|
- Bumped `@jchat/*` dependencies:
|
|
62
|
-
- [`icon@1.0.0-alpha.19`](https://github.com/
|
|
63
|
-
- [`ui@1.0.0-alpha.19`](https://github.com/
|
|
98
|
+
- [`icon@1.0.0-alpha.19`](https://github.com/jchatcloud/jchat/releases/tag/icon@v1.0.0-alpha.19)
|
|
99
|
+
- [`ui@1.0.0-alpha.19`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.19)
|
|
64
100
|
|
|
65
101
|
## 1.0.0-alpha.17
|
|
66
102
|
|
package/LICENSE
CHANGED
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://jchatcloud.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://jchatcloud.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://jchatcloud.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://jchatcloud.com/terms) for full details.
|
package/dist/cli.d.mts
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jchatAddon } from "./vite.mjs";
|
|
2
|
-
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
4
|
import tailwindcss from "@tailwindcss/vite";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
import { build, loadConfigFromFile, mergeConfig } from "vite";
|
package/dist/contracts.d.mts
CHANGED
|
@@ -1,144 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export interface AddonPermissionDefinition {
|
|
4
|
-
/** Permission identifier (recommended: `addon.<id>.<action>`) */
|
|
5
|
-
name: string;
|
|
6
|
-
/** Short, human-readable name for the permission */
|
|
7
|
-
label: string;
|
|
8
|
-
/** Detailed description of what the permission grants (shown in Rank editor) */
|
|
9
|
-
description: string;
|
|
10
|
-
}
|
|
11
|
-
/** Valid locations where an addon can be rendered within the Jchat layout. */
|
|
12
|
-
export declare const MOUNT_POINTS: {
|
|
13
|
-
/** Top of the main chat column */
|
|
14
|
-
readonly CHAT_HEADER: "chat-header";
|
|
15
|
-
/** Below the main chat header, above messages */
|
|
16
|
-
readonly CHAT_TOOLBAR: "chat-toolbar";
|
|
17
|
-
/** The persistent right-side sidebar */
|
|
18
|
-
readonly CHAT_SIDEBAR: "chat-sidebar";
|
|
19
|
-
/** Top of the left sidebar (room list) */
|
|
20
|
-
readonly SIDEBAR_TOP: "sidebar-top";
|
|
21
|
-
/** Bottom of the left sidebar */
|
|
22
|
-
readonly SIDEBAR_BOTTOM: "sidebar-bottom";
|
|
23
|
-
/** Action list shown when clicking a user's avatar */
|
|
24
|
-
readonly USER_POPOVER_ACTIONS: "user-popover-actions";
|
|
25
|
-
/** Menu shown when right-clicking a message */
|
|
26
|
-
readonly MESSAGE_CONTEXT_MENU: "message-context-menu";
|
|
27
|
-
/** Floating overlay rendered on top of the message stream */
|
|
28
|
-
readonly MESSAGE_FEED_OVERLAY: "message-feed-overlay";
|
|
29
|
-
/** Main admin dashboard area */
|
|
30
|
-
readonly ADMIN_PANEL: "admin-panel";
|
|
31
|
-
/** User or site settings dashboard area */
|
|
32
|
-
readonly SETTINGS_PANEL: "settings-panel";
|
|
33
|
-
/** The 'plus' (+) menu in the message composer */
|
|
34
|
-
readonly CHAT_PLUS_MENU: "chat-plus-menu";
|
|
35
|
-
/** Custom tab in the emoji/gif selection panel */
|
|
36
|
-
readonly EMOJI_PICKER_GIF_TAB: "emoji-picker-gif-tab";
|
|
37
|
-
/** Custom tab in the emoji/sticker selection panel */
|
|
38
|
-
readonly EMOJI_PICKER_STICKER_TAB: "emoji-picker-sticker-tab";
|
|
39
|
-
/** Dedicated settings panel rendered in the Owner Dashboard */
|
|
40
|
-
readonly OWNER_SETTINGS: "owner-settings";
|
|
41
|
-
/** Dedicated settings panel rendered in the Site Admin Dashboard */
|
|
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";
|
|
49
|
-
};
|
|
50
|
-
/** Union type of all valid addon mount points. */
|
|
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
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* The `manifest.json` schema required for every Jchat addon. This file describes how the addon is
|
|
71
|
-
* identified and mounted.
|
|
72
|
-
*/
|
|
73
|
-
export interface AddonManifest {
|
|
74
|
-
/** Unique kebab-case addon identifier (must match the folder name) */
|
|
75
|
-
id: string;
|
|
76
|
-
/** Human-readable addon name */
|
|
77
|
-
name: string;
|
|
78
|
-
/** Semver version string (e.g. `1.2.0`) */
|
|
79
|
-
version: string;
|
|
80
|
-
/** Brief summary of what the addon does */
|
|
81
|
-
description?: string;
|
|
82
|
-
/** Author name, organization, or GitHub handle */
|
|
83
|
-
author?: string;
|
|
84
|
-
/** Support or documentation URL */
|
|
85
|
-
homepage?: string;
|
|
86
|
-
/** SPDX license identifier (e.g. `MIT`) */
|
|
87
|
-
license?: string;
|
|
88
|
-
/**
|
|
89
|
-
* Supported language codes (e.g. ["ar", "de", "en", "es", "fr", "hi", "kn", "ml", "ta", "te",
|
|
90
|
-
* "ur"])
|
|
91
|
-
*/
|
|
92
|
-
locales?: string[];
|
|
93
|
-
/** Default fallback language code (e.g. "en") */
|
|
94
|
-
defaultLocale?: string;
|
|
95
|
-
/** Host and SDK versions this directly executed plugin was built and tested against */
|
|
96
|
-
compatibility: {
|
|
97
|
-
/** Supported JChat versions as a semantic-version range, for example `^1.0.0` */
|
|
98
|
-
jchat: string;
|
|
99
|
-
/** Supported `@jchat/addon-sdk` versions as a semantic-version range */
|
|
100
|
-
addonSdk: string;
|
|
101
|
-
};
|
|
102
|
-
/** Identity of the trusted publisher that signed this package. Required when migrations exist */
|
|
103
|
-
publisher?: {
|
|
104
|
-
id: string;
|
|
105
|
-
};
|
|
106
|
-
/** Signature over the canonical archive digest. Required when migrations exist */
|
|
107
|
-
signature?: {
|
|
108
|
-
algorithm: "rsa-sha256";
|
|
109
|
-
digest: string;
|
|
110
|
-
value: string;
|
|
111
|
-
};
|
|
112
|
-
/** Configuration for the React-based frontend bundle */
|
|
113
|
-
frontend?: {
|
|
114
|
-
/** Relative path to the pre-compiled ESM bundle (created by Vite) */
|
|
115
|
-
bundle: string;
|
|
116
|
-
/** List of UI locations where this addon should be active */
|
|
117
|
-
mountPoints: MountPoint[];
|
|
118
|
-
/** Optional path to a specific UI for the settings panel */
|
|
119
|
-
settings?: string;
|
|
120
|
-
/** Additional shared packages this addon imports from the host */
|
|
121
|
-
externals?: string[];
|
|
122
|
-
};
|
|
123
|
-
/** Configuration for the server-side API bundle */
|
|
124
|
-
server?: {
|
|
125
|
-
/** Relative path to the pre-compiled server bundle */
|
|
126
|
-
bundle?: string;
|
|
127
|
-
/** List of SQL files to run (in order) to set up the addon's database tables */
|
|
128
|
-
migrations?: string[];
|
|
129
|
-
/** List of declarative JSON master-data files to apply once, in order */
|
|
130
|
-
seeds?: string[];
|
|
131
|
-
};
|
|
132
|
-
/**
|
|
133
|
-
* The minimum permission required to see or use this addon. If provided, the host gates
|
|
134
|
-
* visibility in the UI and access to all server routes.
|
|
135
|
-
*/
|
|
136
|
-
accessPermission?: string;
|
|
137
|
-
/** Full list of all permissions used by this addon for informational purposes */
|
|
138
|
-
permissions?: string[];
|
|
139
|
-
/** Custom permissions that should be registered with the host application on installation */
|
|
140
|
-
permissionDefinitions?: AddonPermissionDefinition[];
|
|
141
|
-
/** Interactive slash commands exposed in the chat composer */
|
|
142
|
-
commands?: AddonCommandDefinition[];
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
1
|
+
import { _ as HOST_LOCALES, a as AddonChatMessage, b as MountPoint, c as AddonDistribution, d as AddonRequestUser, f as AddonRuntimeLog, g as AddonUser, h as AddonRuntimeLogSource, i as AddonAttachment, l as AddonManifest, m as AddonRuntimeLogLevel, n as ActiveAddonFrontend, o as AddonCommandDefinition, p as AddonRuntimeLogFilter, r as AddonArchiveFile, s as AddonCommandParameter, t as ActiveAddon, u as AddonPermissionDefinition, v as HostLocale, y as MOUNT_POINTS } from "./contracts2.mjs";
|
|
2
|
+
export { ActiveAddon, ActiveAddonFrontend, AddonArchiveFile, AddonAttachment, AddonChatMessage, AddonCommandDefinition, AddonCommandParameter, AddonDistribution, AddonManifest, AddonPermissionDefinition, AddonRequestUser, AddonRuntimeLog, AddonRuntimeLogFilter, AddonRuntimeLogLevel, AddonRuntimeLogSource, AddonUser, HOST_LOCALES, HostLocale, MOUNT_POINTS, MountPoint };
|
package/dist/contracts.mjs
CHANGED
|
@@ -38,5 +38,27 @@ const MOUNT_POINTS = {
|
|
|
38
38
|
/** Custom interactive preview card rendered in the message composer */
|
|
39
39
|
CHAT_COMPOSER_PREVIEW: "chat-composer-preview"
|
|
40
40
|
};
|
|
41
|
+
const HOST_LOCALES = [
|
|
42
|
+
"ar",
|
|
43
|
+
"bg",
|
|
44
|
+
"hr",
|
|
45
|
+
"de",
|
|
46
|
+
"el",
|
|
47
|
+
"en",
|
|
48
|
+
"es",
|
|
49
|
+
"fr",
|
|
50
|
+
"he",
|
|
51
|
+
"hi",
|
|
52
|
+
"kn",
|
|
53
|
+
"ml",
|
|
54
|
+
"nl",
|
|
55
|
+
"pt",
|
|
56
|
+
"ro",
|
|
57
|
+
"ru",
|
|
58
|
+
"ta",
|
|
59
|
+
"te",
|
|
60
|
+
"tr",
|
|
61
|
+
"ur"
|
|
62
|
+
];
|
|
41
63
|
//#endregion
|
|
42
|
-
export { MOUNT_POINTS };
|
|
64
|
+
export { HOST_LOCALES, MOUNT_POINTS };
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
//#region src/contracts.d.ts
|
|
2
|
+
/** Definition of a custom permission introduced by an addon. */
|
|
3
|
+
interface AddonPermissionDefinition {
|
|
4
|
+
/** Permission identifier (recommended: `addon.<id>.<action>`) */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Short, human-readable name for the permission */
|
|
7
|
+
label: string;
|
|
8
|
+
/** Detailed description of what the permission grants (shown in Rank editor) */
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
/** Valid locations where an addon can be rendered within the Jchat layout. */
|
|
12
|
+
declare const MOUNT_POINTS: {
|
|
13
|
+
/** Top of the main chat column */
|
|
14
|
+
readonly CHAT_HEADER: "chat-header";
|
|
15
|
+
/** Below the main chat header, above messages */
|
|
16
|
+
readonly CHAT_TOOLBAR: "chat-toolbar";
|
|
17
|
+
/** The persistent right-side sidebar */
|
|
18
|
+
readonly CHAT_SIDEBAR: "chat-sidebar";
|
|
19
|
+
/** Top of the left sidebar (room list) */
|
|
20
|
+
readonly SIDEBAR_TOP: "sidebar-top";
|
|
21
|
+
/** Bottom of the left sidebar */
|
|
22
|
+
readonly SIDEBAR_BOTTOM: "sidebar-bottom";
|
|
23
|
+
/** Action list shown when clicking a user's avatar */
|
|
24
|
+
readonly USER_POPOVER_ACTIONS: "user-popover-actions";
|
|
25
|
+
/** Menu shown when right-clicking a message */
|
|
26
|
+
readonly MESSAGE_CONTEXT_MENU: "message-context-menu";
|
|
27
|
+
/** Floating overlay rendered on top of the message stream */
|
|
28
|
+
readonly MESSAGE_FEED_OVERLAY: "message-feed-overlay";
|
|
29
|
+
/** Main admin dashboard area */
|
|
30
|
+
readonly ADMIN_PANEL: "admin-panel";
|
|
31
|
+
/** User or site settings dashboard area */
|
|
32
|
+
readonly SETTINGS_PANEL: "settings-panel";
|
|
33
|
+
/** The 'plus' (+) menu in the message composer */
|
|
34
|
+
readonly CHAT_PLUS_MENU: "chat-plus-menu";
|
|
35
|
+
/** Custom tab in the emoji/gif selection panel */
|
|
36
|
+
readonly EMOJI_PICKER_GIF_TAB: "emoji-picker-gif-tab";
|
|
37
|
+
/** Custom tab in the emoji/sticker selection panel */
|
|
38
|
+
readonly EMOJI_PICKER_STICKER_TAB: "emoji-picker-sticker-tab";
|
|
39
|
+
/** Dedicated settings panel rendered in the Owner Dashboard */
|
|
40
|
+
readonly OWNER_SETTINGS: "owner-settings";
|
|
41
|
+
/** Dedicated settings panel rendered in the Site Admin Dashboard */
|
|
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";
|
|
49
|
+
};
|
|
50
|
+
/** Union type of all valid addon mount points. */
|
|
51
|
+
type MountPoint = (typeof MOUNT_POINTS)[keyof typeof MOUNT_POINTS];
|
|
52
|
+
/** Parameter specification for an addon slash command. */
|
|
53
|
+
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
|
+
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
|
+
}
|
|
69
|
+
/** Distribution model for an addon package. Defaults to `'free'` if omitted. */
|
|
70
|
+
type AddonDistribution = "free" | "commercial";
|
|
71
|
+
/**
|
|
72
|
+
* The `manifest.json` schema required for every Jchat addon. This file describes how the addon is
|
|
73
|
+
* identified and mounted.
|
|
74
|
+
*/
|
|
75
|
+
interface AddonManifest {
|
|
76
|
+
/** Unique kebab-case addon identifier (must match the folder name) */
|
|
77
|
+
id: string;
|
|
78
|
+
/** Human-readable addon name */
|
|
79
|
+
name: string;
|
|
80
|
+
/** Semver version string (e.g. `1.2.0`) */
|
|
81
|
+
version: string;
|
|
82
|
+
/**
|
|
83
|
+
* Relative path to the addon's logo image asset (e.g. `./assets/logo.svg`, `./assets/logo.png`,
|
|
84
|
+
* or `./assets/logo.webp`). Recommended square 1:1 aspect ratio, max 512 KB.
|
|
85
|
+
*/
|
|
86
|
+
logo: string;
|
|
87
|
+
/** Brief summary of what the addon does */
|
|
88
|
+
description?: string;
|
|
89
|
+
/** Author name, organization, or GitHub handle */
|
|
90
|
+
author?: string;
|
|
91
|
+
/** Support or documentation URL */
|
|
92
|
+
homepage?: string;
|
|
93
|
+
/** SPDX license identifier (e.g. `MIT`) */
|
|
94
|
+
license?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Distribution model: `'free'` (default) for open/free addons, or `'commercial'` for paid addons
|
|
97
|
+
* requiring purchase entitlement verification.
|
|
98
|
+
*/
|
|
99
|
+
distribution?: AddonDistribution;
|
|
100
|
+
/**
|
|
101
|
+
* Supported language codes (e.g. ["ar", "de", "en", "es", "fr", "hi", "kn", "ml", "ta", "te",
|
|
102
|
+
* "ur"])
|
|
103
|
+
*/
|
|
104
|
+
locales?: string[];
|
|
105
|
+
/** Default fallback language code (e.g. "en") */
|
|
106
|
+
defaultLocale?: string;
|
|
107
|
+
/** Host and SDK versions this directly executed plugin was built and tested against */
|
|
108
|
+
compatibility: {
|
|
109
|
+
/** Supported JChat versions as a semantic-version range, for example `^1.0.0` */
|
|
110
|
+
jchat: string;
|
|
111
|
+
/** Supported `@jchat/addon-sdk` versions as a semantic-version range */
|
|
112
|
+
addonSdk: string;
|
|
113
|
+
};
|
|
114
|
+
/** Identity of the trusted publisher that signed this package. Required when migrations exist */
|
|
115
|
+
publisher?: {
|
|
116
|
+
id: string;
|
|
117
|
+
};
|
|
118
|
+
/** Signature over the canonical archive digest. Required when migrations exist */
|
|
119
|
+
signature?: {
|
|
120
|
+
algorithm: "rsa-sha256";
|
|
121
|
+
digest: string;
|
|
122
|
+
value: string;
|
|
123
|
+
};
|
|
124
|
+
/** Configuration for the React-based frontend bundle */
|
|
125
|
+
frontend?: {
|
|
126
|
+
/** Relative path to the pre-compiled ESM bundle (created by Vite) */
|
|
127
|
+
bundle: string;
|
|
128
|
+
/** List of UI locations where this addon should be active */
|
|
129
|
+
mountPoints: MountPoint[];
|
|
130
|
+
/** Optional path to a specific UI for the settings panel */
|
|
131
|
+
settings?: string;
|
|
132
|
+
/** Additional shared packages this addon imports from the host */
|
|
133
|
+
externals?: string[];
|
|
134
|
+
};
|
|
135
|
+
/** Configuration for the server-side API bundle */
|
|
136
|
+
server?: {
|
|
137
|
+
/** Relative path to the pre-compiled server bundle */
|
|
138
|
+
bundle?: string;
|
|
139
|
+
/** List of SQL files to run (in order) to set up the addon's database tables */
|
|
140
|
+
migrations?: string[];
|
|
141
|
+
/** List of declarative JSON master-data files to apply once, in order */
|
|
142
|
+
seeds?: string[];
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* The minimum permission required to see or use this addon. If provided, the host gates
|
|
146
|
+
* visibility in the UI and access to all server routes.
|
|
147
|
+
*/
|
|
148
|
+
accessPermission?: string;
|
|
149
|
+
/** Full list of all permissions used by this addon for informational purposes */
|
|
150
|
+
permissions?: string[];
|
|
151
|
+
/** Custom permissions that should be registered with the host application on installation */
|
|
152
|
+
permissionDefinitions?: AddonPermissionDefinition[];
|
|
153
|
+
/** Interactive slash commands exposed in the chat composer */
|
|
154
|
+
commands?: AddonCommandDefinition[];
|
|
155
|
+
}
|
|
156
|
+
declare const HOST_LOCALES: readonly ["ar", "bg", "hr", "de", "el", "en", "es", "fr", "he", "hi", "kn", "ml", "nl", "pt", "ro", "ru", "ta", "te", "tr", "ur"];
|
|
157
|
+
type HostLocale = (typeof HOST_LOCALES)[number];
|
|
158
|
+
/** Minimal user profile accessible to addon backends and UI slots. */
|
|
159
|
+
interface AddonUser {
|
|
160
|
+
/** Unique user identifier */
|
|
161
|
+
id: string;
|
|
162
|
+
/** Display name */
|
|
163
|
+
name: string;
|
|
164
|
+
/** Full display name */
|
|
165
|
+
displayName: string;
|
|
166
|
+
/** Full URL to the user's avatar image */
|
|
167
|
+
avatar: string;
|
|
168
|
+
/** User's gender identifier */
|
|
169
|
+
gender: string;
|
|
170
|
+
}
|
|
171
|
+
/** Authenticated request user context passed to addon server routes and message pipeline hooks. */
|
|
172
|
+
interface AddonRequestUser {
|
|
173
|
+
id: string;
|
|
174
|
+
permissions?: string[];
|
|
175
|
+
siteId?: string;
|
|
176
|
+
}
|
|
177
|
+
/** Standard attachment contract for chat messages and addon file attachments. */
|
|
178
|
+
interface AddonAttachment {
|
|
179
|
+
url: string;
|
|
180
|
+
name: string;
|
|
181
|
+
type: string;
|
|
182
|
+
id?: string;
|
|
183
|
+
isUploading?: boolean;
|
|
184
|
+
}
|
|
185
|
+
/** Domain-agnostic message contract passed to addon slots (CHAT_MESSAGE_CARD, CHAT_MESSAGE_FLAIR). */
|
|
186
|
+
interface AddonChatMessage {
|
|
187
|
+
id: string;
|
|
188
|
+
roomId?: string;
|
|
189
|
+
senderId?: string;
|
|
190
|
+
sender?: Partial<AddonUser> & {
|
|
191
|
+
id: string;
|
|
192
|
+
name: string;
|
|
193
|
+
isOwner?: boolean;
|
|
194
|
+
isBot?: boolean;
|
|
195
|
+
rankName?: string;
|
|
196
|
+
};
|
|
197
|
+
content?: unknown;
|
|
198
|
+
attachments?: AddonAttachment[] | null;
|
|
199
|
+
metadata?: Record<string, unknown> | null;
|
|
200
|
+
createdAt?: string | Date;
|
|
201
|
+
}
|
|
202
|
+
/** Severity level classification for runtime addon logging. */
|
|
203
|
+
type AddonRuntimeLogLevel = "error" | "info" | "warn";
|
|
204
|
+
/** Operational lifecycle origin of a runtime log entry. */
|
|
205
|
+
type AddonRuntimeLogSource = "request" | "startup";
|
|
206
|
+
/** A diagnostic runtime log entry recorded during addon server startup or HTTP request execution. */
|
|
207
|
+
interface AddonRuntimeLog {
|
|
208
|
+
/** Unique auto-incrementing log entry sequence identifier */
|
|
209
|
+
id: number;
|
|
210
|
+
/** ISO-8601 UTC timestamp when the event was recorded */
|
|
211
|
+
timestamp: string;
|
|
212
|
+
/** Canonical identifier of the emitting addon */
|
|
213
|
+
addonId: string;
|
|
214
|
+
/** Log severity classification */
|
|
215
|
+
level: AddonRuntimeLogLevel;
|
|
216
|
+
/** Lifecycle stage where the log originated */
|
|
217
|
+
source: AddonRuntimeLogSource;
|
|
218
|
+
/** Descriptive log message or error description */
|
|
219
|
+
message: string;
|
|
220
|
+
/** HTTP method if the log was generated during request execution */
|
|
221
|
+
method?: string;
|
|
222
|
+
/** Request pathname if the log was generated during request execution */
|
|
223
|
+
path?: string;
|
|
224
|
+
/** HTTP response status code if the log was generated during request execution */
|
|
225
|
+
status?: number;
|
|
226
|
+
}
|
|
227
|
+
/** Query parameters for filtering and bounding addon developer runtime logs. */
|
|
228
|
+
interface AddonRuntimeLogFilter {
|
|
229
|
+
/** Filter logs by a specific addon identifier */
|
|
230
|
+
addonId?: string;
|
|
231
|
+
/** Filter logs by severity level */
|
|
232
|
+
level?: AddonRuntimeLogLevel;
|
|
233
|
+
/** Maximum number of recent log records to return */
|
|
234
|
+
limit?: number;
|
|
235
|
+
}
|
|
236
|
+
/** Frontend mounting and bundle distribution metadata for an active addon. */
|
|
237
|
+
interface ActiveAddonFrontend extends Pick<NonNullable<AddonManifest["frontend"]>, "mountPoints"> {
|
|
238
|
+
/** Relative web-accessible path to the compiled frontend bundle */
|
|
239
|
+
bundlePath?: string;
|
|
240
|
+
}
|
|
241
|
+
/** Public host runtime representation of an installed, active addon. */
|
|
242
|
+
interface ActiveAddon extends Pick<AddonManifest, "id" | "name" | "version" | "description" | "author" | "homepage" | "license" | "accessPermission" | "permissions" | "commands"> {
|
|
243
|
+
/** Whether the addon is globally activated on the host platform */
|
|
244
|
+
enabled: boolean;
|
|
245
|
+
/** Relative path to the compiled frontend bundle file */
|
|
246
|
+
bundlePath?: string;
|
|
247
|
+
/** Relative path or URL to the addon logo asset */
|
|
248
|
+
logoPath?: string | null;
|
|
249
|
+
/** Frontend mounting points and distribution information */
|
|
250
|
+
frontend?: ActiveAddonFrontend;
|
|
251
|
+
/** Timestamp when the addon was installed */
|
|
252
|
+
createdAt?: string | Date;
|
|
253
|
+
/** Timestamp when the addon configuration or files were last modified */
|
|
254
|
+
updatedAt?: string | Date;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* In-memory representation of an archive file entry used in canonical digest creation and package
|
|
258
|
+
* verification.
|
|
259
|
+
*/
|
|
260
|
+
interface AddonArchiveFile {
|
|
261
|
+
/**
|
|
262
|
+
* Canonical relative path inside the addon archive (e.g., 'manifest.json',
|
|
263
|
+
* 'migrations/001_init.sql')
|
|
264
|
+
*/
|
|
265
|
+
path: string;
|
|
266
|
+
/** Raw binary contents of the archive file */
|
|
267
|
+
contents: Buffer;
|
|
268
|
+
}
|
|
269
|
+
//#endregion
|
|
270
|
+
export { HOST_LOCALES as _, AddonChatMessage as a, MountPoint as b, AddonDistribution as c, AddonRequestUser as d, AddonRuntimeLog as f, AddonUser as g, AddonRuntimeLogSource as h, AddonAttachment as i, AddonManifest as l, AddonRuntimeLogLevel as m, ActiveAddonFrontend as n, AddonCommandDefinition as o, AddonRuntimeLogFilter as p, AddonArchiveFile as r, AddonCommandParameter as s, ActiveAddon as t, AddonPermissionDefinition as u, HostLocale as v, MOUNT_POINTS as y };
|
package/dist/diagnostics.d.mts
CHANGED
package/dist/diagnostics.mjs
CHANGED
package/dist/i18n-validator.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { HOST_LOCALES } from "./contracts.mjs";
|
|
2
|
+
import "./i18n.mjs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
|
+
import * as fs$1 from "node:fs";
|
|
4
5
|
//#region src/i18n-validator.ts
|
|
5
6
|
function extractNestedKeys(obj, prefix = "") {
|
|
6
7
|
if (!obj || typeof obj !== "object") return [];
|
|
@@ -52,7 +53,7 @@ function validateAddonLocales(dirPath, domainName = "Addon") {
|
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
const enKeys = new Set(extractNestedKeys(enContent));
|
|
55
|
-
for (const lang of
|
|
56
|
+
for (const lang of HOST_LOCALES) {
|
|
56
57
|
if (lang === "en") continue;
|
|
57
58
|
const langFileName = `${lang}.json`;
|
|
58
59
|
const langPath = path$1.join(dirPath, langFileName);
|
package/dist/i18n.mjs
CHANGED
|
@@ -15,28 +15,6 @@ function interpolate(text, params) {
|
|
|
15
15
|
return key in params ? String(params[key]) : match;
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
const HOST_LANGUAGES = [
|
|
19
|
-
"ar",
|
|
20
|
-
"bg",
|
|
21
|
-
"hr",
|
|
22
|
-
"de",
|
|
23
|
-
"el",
|
|
24
|
-
"en",
|
|
25
|
-
"es",
|
|
26
|
-
"fr",
|
|
27
|
-
"he",
|
|
28
|
-
"hi",
|
|
29
|
-
"kn",
|
|
30
|
-
"ml",
|
|
31
|
-
"nl",
|
|
32
|
-
"pt",
|
|
33
|
-
"ro",
|
|
34
|
-
"ru",
|
|
35
|
-
"ta",
|
|
36
|
-
"te",
|
|
37
|
-
"tr",
|
|
38
|
-
"ur"
|
|
39
|
-
];
|
|
40
18
|
const LocaleContext = createContext({
|
|
41
19
|
locale: "en",
|
|
42
20
|
dir: "ltr"
|
|
@@ -188,4 +166,4 @@ function useTranslation(resourcesOrLoader = {}, fallbackLocale = "en") {
|
|
|
188
166
|
};
|
|
189
167
|
}
|
|
190
168
|
//#endregion
|
|
191
|
-
export { useTranslation as
|
|
169
|
+
export { useTranslation as i, createTranslator as n, useLocale as r, LocaleContext as t };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { MOUNT_POINTS } from "./contracts.mjs";
|
|
2
|
-
import {
|
|
1
|
+
import { HOST_LOCALES, MOUNT_POINTS } from "./contracts.mjs";
|
|
2
|
+
import { i as useTranslation, n as createTranslator, r as useLocale, t as LocaleContext } from "./i18n.mjs";
|
|
3
|
+
import { ADDON_ID_PATTERN, COMPATIBILITY_RANGE_PATTERN, MAX_ADDON_ARCHIVE_BYTES, assertSafeRelativePath, canonicalManifest, createCanonicalAddonDigest, isCompatibilityRange, sortValue, validateAddonManifest } from "./signing.mjs";
|
|
4
|
+
import { createMockAddonServerContext } from "./testing.mjs";
|
|
3
5
|
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
6
|
//#region package.json
|
|
5
|
-
var version = "1.0.0-alpha.
|
|
7
|
+
var version = "1.0.0-alpha.24";
|
|
6
8
|
//#endregion
|
|
7
9
|
//#region src/query.ts
|
|
8
10
|
/**
|
|
@@ -95,6 +97,24 @@ function useAddonMutation(options) {
|
|
|
95
97
|
}
|
|
96
98
|
//#endregion
|
|
97
99
|
//#region src/index.ts
|
|
100
|
+
/**
|
|
101
|
+
* @jchat/addon-sdk
|
|
102
|
+
*
|
|
103
|
+
* Lightweight SDK for Jchat addon developers. Provides TypeScript types for addon props, manifest
|
|
104
|
+
* schema, and host API access. This package is always EXTERNALISED from addon bundles — the host
|
|
105
|
+
* app provides the runtime implementation.
|
|
106
|
+
*/
|
|
107
|
+
/** Standard error thrown or handled when an addon message pipeline hook aborts sending. */
|
|
108
|
+
var AddonPipelineAbortError = class extends Error {
|
|
109
|
+
code;
|
|
110
|
+
reason;
|
|
111
|
+
constructor(error) {
|
|
112
|
+
super(error.reason || error.code);
|
|
113
|
+
this.name = "AddonPipelineAbortError";
|
|
114
|
+
this.code = error.code;
|
|
115
|
+
this.reason = error.reason;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
98
118
|
/** Define a manifest with full validation-friendly typing while preserving literal values. */
|
|
99
119
|
function defineAddonManifest(manifest) {
|
|
100
120
|
return manifest;
|
|
@@ -173,4 +193,4 @@ function verifyAddonEntitlement(addonId, target) {
|
|
|
173
193
|
return true;
|
|
174
194
|
}
|
|
175
195
|
//#endregion
|
|
176
|
-
export {
|
|
196
|
+
export { ADDON_ID_PATTERN, AddonPipelineAbortError, COMPATIBILITY_RANGE_PATTERN, HOST_LOCALES, LocaleContext, MAX_ADDON_ARCHIVE_BYTES, MOUNT_POINTS, assertSafeRelativePath, canonicalManifest, createCanonicalAddonDigest, createMockAddonServerContext, createTranslator, defineAddonManifest, defineAddonServer, getAddonSdkVersion, isCompatibilityRange, sortValue, useAddonInfiniteQuery, useAddonMutation, useAddonQuery, useAddonSDK, useLocale, useQueryClient, useTranslation, validateAddonManifest, verifyAddonEntitlement };
|
package/dist/index2.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { i as IconPack, n as IconComponent, r as IconName } from "./types.mjs";
|
|
2
|
-
import { AddonCommandDefinition, AddonCommandParameter,
|
|
2
|
+
import { _ as HOST_LOCALES, a as AddonChatMessage, b as MountPoint, c as AddonDistribution, d as AddonRequestUser, f as AddonRuntimeLog, g as AddonUser, h as AddonRuntimeLogSource, i as AddonAttachment, l as AddonManifest, m as AddonRuntimeLogLevel, n as ActiveAddonFrontend, o as AddonCommandDefinition, p as AddonRuntimeLogFilter, r as AddonArchiveFile, s as AddonCommandParameter, t as ActiveAddon, u as AddonPermissionDefinition, v as HostLocale, y as MOUNT_POINTS } from "./contracts2.mjs";
|
|
3
|
+
import { a as canonicalManifest, c as sortValue, i as assertSafeRelativePath, l as validateAddonManifest, n as COMPATIBILITY_RANGE_PATTERN, o as createCanonicalAddonDigest, r as MAX_ADDON_ARCHIVE_BYTES, s as isCompatibilityRange, t as ADDON_ID_PATTERN } from "./signing2.mjs";
|
|
3
4
|
import { InfiniteData, MutationFunction, QueryFunction, QueryFunctionContext, QueryKey, UndefinedInitialDataInfiniteOptions, UndefinedInitialDataOptions, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult, UseQueryResult, useQueryClient } from "@tanstack/react-query";
|
|
4
5
|
import { Elysia, t } from "elysia";
|
|
5
6
|
import { ColumnType, Generated, Insertable, JSONColumnType, Kysely, Selectable, Updateable } from "kysely";
|
|
6
7
|
//#region src/i18n.d.ts
|
|
7
|
-
export
|
|
8
|
-
export type HostLanguage = (typeof HOST_LANGUAGES)[number];
|
|
8
|
+
export type HostLanguage = HostLocale;
|
|
9
9
|
export type AddonTranslationDictionary = Record<string, unknown>;
|
|
10
10
|
export type AddonTranslationResources = Record<string, AddonTranslationDictionary>;
|
|
11
11
|
export type AddonLocaleLoader = (locale: string) => Promise<AddonTranslationDictionary> | AddonTranslationDictionary;
|
|
@@ -151,6 +151,30 @@ export declare function useAddonInfiniteQuery<TData = unknown, TError = Error, T
|
|
|
151
151
|
*/
|
|
152
152
|
export declare function useAddonMutation<TData = unknown, TVariables = unknown, TError = Error, TContext = unknown>(options: UseAddonMutationOptions<TData, TVariables, TError, TContext>): UseMutationResult<TData, TError, TVariables, TContext>;
|
|
153
153
|
//#endregion
|
|
154
|
+
//#region src/testing.d.ts
|
|
155
|
+
export interface MockAddonServerContextOptions {
|
|
156
|
+
siteId?: string;
|
|
157
|
+
config?: Record<string, unknown>;
|
|
158
|
+
user?: Partial<AddonUser>;
|
|
159
|
+
isEntitled?: boolean;
|
|
160
|
+
}
|
|
161
|
+
export interface MockAddonContextResult {
|
|
162
|
+
context: AddonServerContext;
|
|
163
|
+
emittedEvents: Array<{
|
|
164
|
+
event: string;
|
|
165
|
+
payload: unknown;
|
|
166
|
+
target?: AddonServerEmitTarget;
|
|
167
|
+
}>;
|
|
168
|
+
registeredHooks: AddonPipelineHooks[];
|
|
169
|
+
cacheEntries: Map<string, unknown>;
|
|
170
|
+
cacheSets: Map<string, Set<string>>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Creates an in-memory, zero-dependency AddonServerContext mock for testing addon server factories
|
|
174
|
+
* and pipeline hooks offline in CI without requiring live databases or Redis.
|
|
175
|
+
*/
|
|
176
|
+
export declare function createMockAddonServerContext(addonId: string, options?: MockAddonServerContextOptions): MockAddonContextResult;
|
|
177
|
+
//#endregion
|
|
154
178
|
//#region src/index.d.ts
|
|
155
179
|
export type AddonJsonBody = Record<string, unknown> | unknown[] | null;
|
|
156
180
|
/**
|
|
@@ -160,23 +184,14 @@ export type AddonJsonBody = Record<string, unknown> | unknown[] | null;
|
|
|
160
184
|
* schema, and host API access. This package is always EXTERNALISED from addon bundles — the host
|
|
161
185
|
* app provides the runtime implementation.
|
|
162
186
|
*/
|
|
163
|
-
/**
|
|
164
|
-
export
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
/** Full URL to the user's avatar image */
|
|
172
|
-
avatar: string;
|
|
173
|
-
/** User's gender identifier */
|
|
174
|
-
gender: string;
|
|
175
|
-
}
|
|
176
|
-
export interface AddonRequestUser {
|
|
177
|
-
id: string;
|
|
178
|
-
permissions?: string[];
|
|
179
|
-
siteId?: string;
|
|
187
|
+
/** Standard error thrown or handled when an addon message pipeline hook aborts sending. */
|
|
188
|
+
export declare class AddonPipelineAbortError extends Error {
|
|
189
|
+
readonly code: string;
|
|
190
|
+
readonly reason?: string;
|
|
191
|
+
constructor(error: {
|
|
192
|
+
code: string;
|
|
193
|
+
reason?: string;
|
|
194
|
+
});
|
|
180
195
|
}
|
|
181
196
|
/**
|
|
182
197
|
* Typed, schema-scoped database facade for an addon. The host deliberately omits raw execution,
|
|
@@ -200,6 +215,32 @@ export interface AddonCacheClient {
|
|
|
200
215
|
expire: (key: string, ttlSeconds: number) => Promise<boolean>;
|
|
201
216
|
/** Get the remaining time-to-live of a key in seconds (-2 if key does not exist, -1 if no TTL) */
|
|
202
217
|
ttl: (key: string) => Promise<number>;
|
|
218
|
+
/** Add a member to a set stored at key */
|
|
219
|
+
setAdd: (key: string, member: string) => Promise<number>;
|
|
220
|
+
/** Remove a member from a set stored at key */
|
|
221
|
+
setRemove: (key: string, member: string) => Promise<number>;
|
|
222
|
+
/** Retrieve all members of a set stored at key */
|
|
223
|
+
setMembers: (key: string) => Promise<string[]>;
|
|
224
|
+
}
|
|
225
|
+
export interface AddonRateLimitOptions {
|
|
226
|
+
/** Maximum number of allowed requests within the sliding window */
|
|
227
|
+
limit: number;
|
|
228
|
+
/** Time window duration in milliseconds */
|
|
229
|
+
windowMs: number;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* High-performance sliding-window rate limiter scoped to this addon. Keys are automatically
|
|
233
|
+
* prefixed by the host as `addon:<addonId>:ratelimit:<key>`.
|
|
234
|
+
*/
|
|
235
|
+
export interface AddonRateLimiter {
|
|
236
|
+
/**
|
|
237
|
+
* Consume a rate limit token using an atomic sliding window.
|
|
238
|
+
*
|
|
239
|
+
* @param key - Identifier within the addon (e.g. `user:${userId}:audio`, `command:${cmd}`)
|
|
240
|
+
* @param options - Limit and window duration in milliseconds
|
|
241
|
+
* @returns `true` if within the rate limit, `false` if limit exceeded
|
|
242
|
+
*/
|
|
243
|
+
consume: (key: string, options: AddonRateLimitOptions) => Promise<boolean>;
|
|
203
244
|
}
|
|
204
245
|
export interface AddonServerEmitTarget {
|
|
205
246
|
/** Target a specific site (defaults to the request user's siteId) */
|
|
@@ -213,7 +254,7 @@ export interface AddonMessageMutableData {
|
|
|
213
254
|
/** Message content (can be Slate JSON structure or string) */
|
|
214
255
|
content: unknown;
|
|
215
256
|
/** Optional message attachments */
|
|
216
|
-
attachments?: unknown[] | null;
|
|
257
|
+
attachments?: AddonAttachment[] | unknown[] | null;
|
|
217
258
|
/**
|
|
218
259
|
* Namespaced metadata bucket for this addon. Keyed as `metadata["addon:<addonId>"]`. Storing data
|
|
219
260
|
* here automatically attaches it to the message broadcast and database record.
|
|
@@ -252,7 +293,7 @@ export interface AddonMessageAfterSaveContext {
|
|
|
252
293
|
message: {
|
|
253
294
|
id: string;
|
|
254
295
|
content: unknown;
|
|
255
|
-
attachments?: unknown[] | null;
|
|
296
|
+
attachments?: AddonAttachment[] | unknown[] | null;
|
|
256
297
|
metadata?: Record<string, unknown> | null;
|
|
257
298
|
type: string;
|
|
258
299
|
createdAt: Date | string;
|
|
@@ -320,6 +361,8 @@ export interface AddonServerContext<TDatabase = Record<string, Record<string, un
|
|
|
320
361
|
pipeline?: {
|
|
321
362
|
register: (hooks: AddonPipelineHooks) => void;
|
|
322
363
|
};
|
|
364
|
+
/** An atomic sliding-window rate limiter scoped to your addon (`addon:<addonId>:ratelimit:<key>`). */
|
|
365
|
+
rateLimiter?: AddonRateLimiter;
|
|
323
366
|
/**
|
|
324
367
|
* Cryptographically verify that this addon instance holds a valid host license entitlement.
|
|
325
368
|
* Commercial paid addons should invoke this or call `verifyAddonEntitlement(addonId, context)`.
|
|
@@ -389,7 +432,7 @@ export interface AddonProps {
|
|
|
389
432
|
/** Text direction for the current locale */
|
|
390
433
|
dir?: "ltr" | "rtl";
|
|
391
434
|
/** The message object when rendered inside 'chat-message-card' or 'chat-message-flair' */
|
|
392
|
-
message?: unknown;
|
|
435
|
+
message?: AddonChatMessage | unknown;
|
|
393
436
|
/** The addon's specific payload extracted from message.metadata */
|
|
394
437
|
addonData?: unknown;
|
|
395
438
|
/** List of active addon IDs enabled on the current site */
|
|
@@ -467,7 +510,7 @@ export interface AddonEditorApi {
|
|
|
467
510
|
* Upload and attach a file to the current message without inserting it inline. Users will see the
|
|
468
511
|
* file in the attachment bar below the editor.
|
|
469
512
|
*/
|
|
470
|
-
addAttachment: (attachment: {
|
|
513
|
+
addAttachment: (attachment: AddonAttachment | {
|
|
471
514
|
url: string;
|
|
472
515
|
name: string;
|
|
473
516
|
type: string;
|
|
@@ -610,4 +653,4 @@ export declare function verifyAddonEntitlement(addonId: string, target?: ((expec
|
|
|
610
653
|
verifyEntitlement?: (expectedAddonId?: string) => boolean;
|
|
611
654
|
}): boolean;
|
|
612
655
|
//#endregion
|
|
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 };
|
|
656
|
+
export { ADDON_ID_PATTERN, type ActiveAddon, type ActiveAddonFrontend, type AddonArchiveFile, type AddonAttachment, type AddonChatMessage, type AddonCommandDefinition, type AddonCommandParameter, type AddonDistribution, type AddonManifest, type AddonPermissionDefinition, type AddonRequestUser, type AddonRuntimeLog, type AddonRuntimeLogFilter, type AddonRuntimeLogLevel, type AddonRuntimeLogSource, type AddonUser, COMPATIBILITY_RANGE_PATTERN, type ColumnType, type Generated, HOST_LOCALES, type IconComponent, type IconName, type IconPack, type InfiniteData, type Insertable, type JSONColumnType, MAX_ADDON_ARCHIVE_BYTES, MOUNT_POINTS, type MountPoint, type QueryKey, type Selectable, type Updateable, assertSafeRelativePath, canonicalManifest, createCanonicalAddonDigest, isCompatibilityRange, sortValue, useQueryClient, validateAddonManifest };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as canonicalManifest, c as sortValue, i as assertSafeRelativePath, l as validateAddonManifest, n as COMPATIBILITY_RANGE_PATTERN, o as createCanonicalAddonDigest, r as MAX_ADDON_ARCHIVE_BYTES, s as isCompatibilityRange, t as ADDON_ID_PATTERN } from "./signing2.mjs";
|
|
2
|
+
export { ADDON_ID_PATTERN, COMPATIBILITY_RANGE_PATTERN, MAX_ADDON_ARCHIVE_BYTES, assertSafeRelativePath, canonicalManifest, createCanonicalAddonDigest, isCompatibilityRange, sortValue, validateAddonManifest };
|
package/dist/signing.mjs
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import * as path$1 from "node:path";
|
|
3
|
+
//#region src/signing.ts
|
|
4
|
+
const MAX_ADDON_ARCHIVE_BYTES = 26214400;
|
|
5
|
+
const ADDON_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
6
|
+
const COMPATIBILITY_RANGE_PATTERN = /^[0-9A-Za-z*^~<>=|.\-\s]+$/;
|
|
7
|
+
function assertSafeRelativePath(value, label) {
|
|
8
|
+
if (!value || path$1.isAbsolute(value) || value.includes("\\") || value.split("/").includes("..")) throw new Error(`${label} must be a safe relative path`);
|
|
9
|
+
}
|
|
10
|
+
function isCompatibilityRange(value) {
|
|
11
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64 && COMPATIBILITY_RANGE_PATTERN.test(value);
|
|
12
|
+
}
|
|
13
|
+
function sortValue(value) {
|
|
14
|
+
if (Array.isArray(value)) return value.map(sortValue);
|
|
15
|
+
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, sortValue(child)]));
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function canonicalManifest(manifest) {
|
|
19
|
+
const copy = structuredClone(manifest);
|
|
20
|
+
if (copy.signature) {
|
|
21
|
+
copy.signature.digest = "";
|
|
22
|
+
copy.signature.value = "";
|
|
23
|
+
}
|
|
24
|
+
return JSON.stringify(sortValue(copy));
|
|
25
|
+
}
|
|
26
|
+
function createCanonicalAddonDigest(manifest, files) {
|
|
27
|
+
const hash = crypto.createHash("sha256");
|
|
28
|
+
const sortedFiles = [...files].toSorted((left, right) => left.path.localeCompare(right.path));
|
|
29
|
+
for (const file of sortedFiles) {
|
|
30
|
+
hash.update(file.path);
|
|
31
|
+
hash.update("\0");
|
|
32
|
+
hash.update(file.path === "manifest.json" ? canonicalManifest(manifest) : file.contents);
|
|
33
|
+
hash.update("\0");
|
|
34
|
+
}
|
|
35
|
+
return hash.digest("hex");
|
|
36
|
+
}
|
|
37
|
+
function validateAddonManifest(manifest) {
|
|
38
|
+
if (!manifest.id || manifest.id.length > 40 || !ADDON_ID_PATTERN.test(manifest.id)) throw new Error("Manifest id must contain only lowercase letters, numbers, and hyphens");
|
|
39
|
+
if (!manifest.name || manifest.name.length > 120) throw new Error("Manifest name is invalid");
|
|
40
|
+
if (!manifest.version || String(manifest.version).length > 64) throw new Error("Manifest version is invalid");
|
|
41
|
+
if (!isCompatibilityRange(manifest.compatibility?.jchat) || !isCompatibilityRange(manifest.compatibility?.addonSdk)) throw new Error("Manifest must declare valid JChat and addon SDK compatibility ranges");
|
|
42
|
+
if (manifest.distribution !== void 0 && manifest.distribution !== "free" && manifest.distribution !== "commercial") throw new Error("Manifest distribution must be either 'free' or 'commercial'");
|
|
43
|
+
if (!manifest.logo || typeof manifest.logo !== "string" || !manifest.logo.trim()) throw new Error("Manifest logo is required");
|
|
44
|
+
const cleanLogo = manifest.logo.replace(/^\.\//, "");
|
|
45
|
+
assertSafeRelativePath(cleanLogo, "Logo path");
|
|
46
|
+
const logoExt = path$1.extname(cleanLogo).toLowerCase();
|
|
47
|
+
if (![
|
|
48
|
+
".svg",
|
|
49
|
+
".png",
|
|
50
|
+
".webp"
|
|
51
|
+
].includes(logoExt)) throw new Error("Manifest logo must be an SVG, PNG, or WebP image file");
|
|
52
|
+
const references = [manifest.frontend?.bundle, manifest.server?.bundle].filter((value) => Boolean(value));
|
|
53
|
+
for (const reference of references) assertSafeRelativePath(reference, "Bundle path");
|
|
54
|
+
for (const migration of manifest.server?.migrations ?? []) {
|
|
55
|
+
assertSafeRelativePath(migration, "Migration path");
|
|
56
|
+
if (!migration.startsWith("migrations/") || !migration.endsWith(".sql")) throw new Error("Migration paths must point to migrations/*.sql");
|
|
57
|
+
}
|
|
58
|
+
for (const seed of manifest.server?.seeds ?? []) {
|
|
59
|
+
assertSafeRelativePath(seed, "Seed path");
|
|
60
|
+
if (!seed.startsWith("seeds/") || !seed.endsWith(".json")) throw new Error("Seed paths must point to seeds/*.json");
|
|
61
|
+
}
|
|
62
|
+
const databaseFiles = [...manifest.server?.migrations ?? [], ...manifest.server?.seeds ?? []];
|
|
63
|
+
if (new Set(databaseFiles).size !== databaseFiles.length) throw new Error("Manifest database file paths must be unique");
|
|
64
|
+
const addonPermPrefix = `addon.${manifest.id}.`;
|
|
65
|
+
const declaredPerms = [
|
|
66
|
+
...manifest.accessPermission ? [manifest.accessPermission] : [],
|
|
67
|
+
...manifest.permissions ?? [],
|
|
68
|
+
...manifest.permissionDefinitions?.map((d) => d.name) ?? []
|
|
69
|
+
];
|
|
70
|
+
for (const perm of declaredPerms) if (!perm.startsWith(addonPermPrefix)) throw new Error(`Addon permission '${perm}' must start with '${addonPermPrefix}' prefix to prevent permission collisions`);
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { ADDON_ID_PATTERN, COMPATIBILITY_RANGE_PATTERN, MAX_ADDON_ARCHIVE_BYTES, assertSafeRelativePath, canonicalManifest, createCanonicalAddonDigest, isCompatibilityRange, sortValue, validateAddonManifest };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { l as AddonManifest, r as AddonArchiveFile } from "./contracts2.mjs";
|
|
2
|
+
//#region src/signing.d.ts
|
|
3
|
+
declare const MAX_ADDON_ARCHIVE_BYTES: number;
|
|
4
|
+
declare const ADDON_ID_PATTERN: RegExp;
|
|
5
|
+
declare const COMPATIBILITY_RANGE_PATTERN: RegExp;
|
|
6
|
+
declare function assertSafeRelativePath(value: string, label: string): void;
|
|
7
|
+
declare function isCompatibilityRange(value: unknown): value is string;
|
|
8
|
+
declare function sortValue(value: unknown): unknown;
|
|
9
|
+
declare function canonicalManifest(manifest: AddonManifest): string;
|
|
10
|
+
declare function createCanonicalAddonDigest(manifest: AddonManifest, files: readonly AddonArchiveFile[]): string;
|
|
11
|
+
declare function validateAddonManifest(manifest: AddonManifest): void;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { canonicalManifest as a, sortValue as c, assertSafeRelativePath as i, validateAddonManifest as l, COMPATIBILITY_RANGE_PATTERN as n, createCanonicalAddonDigest as o, MAX_ADDON_ARCHIVE_BYTES as r, isCompatibilityRange as s, ADDON_ID_PATTERN as t };
|
package/dist/testing.mjs
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
//#region src/testing.ts
|
|
2
|
+
/**
|
|
3
|
+
* Creates an in-memory, zero-dependency AddonServerContext mock for testing addon server factories
|
|
4
|
+
* and pipeline hooks offline in CI without requiring live databases or Redis.
|
|
5
|
+
*/
|
|
6
|
+
function createMockAddonServerContext(addonId, options = {}) {
|
|
7
|
+
const { config = {}, user = {}, isEntitled = true } = options;
|
|
8
|
+
const emittedEvents = [];
|
|
9
|
+
const registeredHooks = [];
|
|
10
|
+
const cacheEntries = /* @__PURE__ */ new Map();
|
|
11
|
+
const cacheSets = /* @__PURE__ */ new Map();
|
|
12
|
+
const cacheTtld = /* @__PURE__ */ new Map();
|
|
13
|
+
const rateLimitTimestamps = /* @__PURE__ */ new Map();
|
|
14
|
+
const prefix = `addon:${addonId}:`;
|
|
15
|
+
const cache = {
|
|
16
|
+
async get(key) {
|
|
17
|
+
const fullKey = prefix + key;
|
|
18
|
+
const exp = cacheTtld.get(fullKey);
|
|
19
|
+
if (exp && Date.now() > exp) {
|
|
20
|
+
cacheEntries.delete(fullKey);
|
|
21
|
+
cacheTtld.delete(fullKey);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const val = cacheEntries.get(fullKey);
|
|
25
|
+
return val !== void 0 ? val : null;
|
|
26
|
+
},
|
|
27
|
+
async set(key, value, ttlSeconds) {
|
|
28
|
+
const fullKey = prefix + key;
|
|
29
|
+
cacheEntries.set(fullKey, value);
|
|
30
|
+
if (ttlSeconds && ttlSeconds > 0) cacheTtld.set(fullKey, Date.now() + ttlSeconds * 1e3);
|
|
31
|
+
else cacheTtld.delete(fullKey);
|
|
32
|
+
},
|
|
33
|
+
async del(...keys) {
|
|
34
|
+
let count = 0;
|
|
35
|
+
for (const k of keys) {
|
|
36
|
+
const fullKey = prefix + k;
|
|
37
|
+
if (cacheEntries.delete(fullKey)) count++;
|
|
38
|
+
cacheTtld.delete(fullKey);
|
|
39
|
+
cacheSets.delete(fullKey);
|
|
40
|
+
}
|
|
41
|
+
return count;
|
|
42
|
+
},
|
|
43
|
+
async incr(key) {
|
|
44
|
+
const fullKey = prefix + key;
|
|
45
|
+
const next = (Number(cacheEntries.get(fullKey)) || 0) + 1;
|
|
46
|
+
cacheEntries.set(fullKey, next);
|
|
47
|
+
return next;
|
|
48
|
+
},
|
|
49
|
+
async expire(key, ttlSeconds) {
|
|
50
|
+
const fullKey = prefix + key;
|
|
51
|
+
if (!cacheEntries.has(fullKey) && !cacheSets.has(fullKey)) return false;
|
|
52
|
+
cacheTtld.set(fullKey, Date.now() + ttlSeconds * 1e3);
|
|
53
|
+
return true;
|
|
54
|
+
},
|
|
55
|
+
async ttl(key) {
|
|
56
|
+
const fullKey = prefix + key;
|
|
57
|
+
if (!cacheEntries.has(fullKey) && !cacheSets.has(fullKey)) return -2;
|
|
58
|
+
const exp = cacheTtld.get(fullKey);
|
|
59
|
+
if (!exp) return -1;
|
|
60
|
+
const remaining = Math.ceil((exp - Date.now()) / 1e3);
|
|
61
|
+
return remaining > 0 ? remaining : -2;
|
|
62
|
+
},
|
|
63
|
+
async setAdd(key, member) {
|
|
64
|
+
const fullKey = prefix + key;
|
|
65
|
+
let set = cacheSets.get(fullKey);
|
|
66
|
+
if (!set) {
|
|
67
|
+
set = /* @__PURE__ */ new Set();
|
|
68
|
+
cacheSets.set(fullKey, set);
|
|
69
|
+
}
|
|
70
|
+
const initialSize = set.size;
|
|
71
|
+
set.add(member);
|
|
72
|
+
return set.size > initialSize ? 1 : 0;
|
|
73
|
+
},
|
|
74
|
+
async setRemove(key, member) {
|
|
75
|
+
const fullKey = prefix + key;
|
|
76
|
+
const set = cacheSets.get(fullKey);
|
|
77
|
+
if (!set) return 0;
|
|
78
|
+
return set.delete(member) ? 1 : 0;
|
|
79
|
+
},
|
|
80
|
+
async setMembers(key) {
|
|
81
|
+
const fullKey = prefix + key;
|
|
82
|
+
const set = cacheSets.get(fullKey);
|
|
83
|
+
return set ? Array.from(set) : [];
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const rateLimiter = { async consume(key, opts) {
|
|
87
|
+
const fullKey = `addon:${addonId}:ratelimit:${key}`;
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const windowStart = now - opts.windowMs;
|
|
90
|
+
const valid = (rateLimitTimestamps.get(fullKey) ?? []).filter((t) => t > windowStart);
|
|
91
|
+
if (valid.length >= opts.limit) {
|
|
92
|
+
rateLimitTimestamps.set(fullKey, valid);
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
valid.push(now);
|
|
96
|
+
rateLimitTimestamps.set(fullKey, valid);
|
|
97
|
+
return true;
|
|
98
|
+
} };
|
|
99
|
+
const defaultUser = {
|
|
100
|
+
id: user.id ?? "mock-user-1",
|
|
101
|
+
name: user.name ?? "Mock User",
|
|
102
|
+
displayName: user.displayName ?? "Mock User",
|
|
103
|
+
avatar: user.avatar ?? "https://example.com/avatar.png",
|
|
104
|
+
gender: user.gender ?? "neutral"
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
context: {
|
|
108
|
+
t: {},
|
|
109
|
+
db: {},
|
|
110
|
+
cache,
|
|
111
|
+
rateLimiter,
|
|
112
|
+
emit: async (event, payload, target) => {
|
|
113
|
+
emittedEvents.push({
|
|
114
|
+
event: `addon:${addonId}:${event}`,
|
|
115
|
+
payload,
|
|
116
|
+
target
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
pipeline: { register: (hooks) => {
|
|
120
|
+
registeredHooks.push(hooks);
|
|
121
|
+
} },
|
|
122
|
+
getConfig: async (_targetSiteId) => config,
|
|
123
|
+
getUser: async (userId) => userId === defaultUser.id ? defaultUser : null,
|
|
124
|
+
getUsers: async (userIds) => {
|
|
125
|
+
const map = /* @__PURE__ */ new Map();
|
|
126
|
+
for (const id of userIds) if (id === defaultUser.id) map.set(id, defaultUser);
|
|
127
|
+
return map;
|
|
128
|
+
},
|
|
129
|
+
hasPermission: (reqUser, permission) => {
|
|
130
|
+
return (reqUser?.permissions ?? []).includes(permission);
|
|
131
|
+
},
|
|
132
|
+
verifyEntitlement: (expectedAddonId) => {
|
|
133
|
+
if (expectedAddonId && expectedAddonId !== addonId) return false;
|
|
134
|
+
return isEntitled;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
emittedEvents,
|
|
138
|
+
registeredHooks,
|
|
139
|
+
cacheEntries,
|
|
140
|
+
cacheSets
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { createMockAddonServerContext };
|
package/dist/vite.d.mts
CHANGED
package/dist/vite.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jchat/addon-sdk",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.25",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "JChat Addon SDK for building JChat addons.",
|
|
6
6
|
"keywords": [
|
|
@@ -12,12 +12,8 @@
|
|
|
12
12
|
"sdk",
|
|
13
13
|
"vite"
|
|
14
14
|
],
|
|
15
|
+
"homepage": "https://jchatcloud.com",
|
|
15
16
|
"license": "SEE LICENSE IN LICENSE",
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/mjjabarullah/jchat.git",
|
|
19
|
-
"directory": "packages/addon-sdk"
|
|
20
|
-
},
|
|
21
17
|
"bin": {
|
|
22
18
|
"jchat-addon": "./dist/cli.mjs"
|
|
23
19
|
},
|
|
@@ -43,6 +39,11 @@
|
|
|
43
39
|
"import": "./src/contracts.ts",
|
|
44
40
|
"default": "./src/contracts.ts"
|
|
45
41
|
},
|
|
42
|
+
"./signing": {
|
|
43
|
+
"types": "./src/signing.ts",
|
|
44
|
+
"import": "./src/signing.ts",
|
|
45
|
+
"default": "./src/signing.ts"
|
|
46
|
+
},
|
|
46
47
|
"./cli": {
|
|
47
48
|
"types": "./src/cli.ts",
|
|
48
49
|
"import": "./src/cli.ts",
|
|
@@ -53,6 +54,11 @@
|
|
|
53
54
|
"import": "./src/diagnostics.ts",
|
|
54
55
|
"default": "./src/diagnostics.ts"
|
|
55
56
|
},
|
|
57
|
+
"./testing": {
|
|
58
|
+
"types": "./src/testing.ts",
|
|
59
|
+
"import": "./src/testing.ts",
|
|
60
|
+
"default": "./src/testing.ts"
|
|
61
|
+
},
|
|
56
62
|
"./vite": {
|
|
57
63
|
"types": "./src/vite.ts",
|
|
58
64
|
"import": "./src/vite.ts",
|
|
@@ -97,6 +103,10 @@
|
|
|
97
103
|
"types": "./dist/contracts.d.mts",
|
|
98
104
|
"import": "./dist/contracts.mjs"
|
|
99
105
|
},
|
|
106
|
+
"./signing": {
|
|
107
|
+
"types": "./dist/signing.d.mts",
|
|
108
|
+
"import": "./dist/signing.mjs"
|
|
109
|
+
},
|
|
100
110
|
"./cli": {
|
|
101
111
|
"types": "./dist/cli.d.mts",
|
|
102
112
|
"import": "./dist/cli.mjs"
|
|
@@ -105,6 +115,10 @@
|
|
|
105
115
|
"types": "./dist/diagnostics.d.mts",
|
|
106
116
|
"import": "./dist/diagnostics.mjs"
|
|
107
117
|
},
|
|
118
|
+
"./testing": {
|
|
119
|
+
"types": "./dist/testing.d.mts",
|
|
120
|
+
"import": "./dist/testing.mjs"
|
|
121
|
+
},
|
|
108
122
|
"./vite": {
|
|
109
123
|
"types": "./dist/vite.d.mts",
|
|
110
124
|
"import": "./dist/vite.mjs"
|