@jchat/addon-sdk 1.0.0-alpha.3 → 1.0.0-alpha.6
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 +19 -0
- package/README.md +24 -0
- package/dist/contracts.d.mts +5 -21
- package/dist/diagnostics.d.mts +47 -0
- package/dist/diagnostics.mjs +65 -0
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +6 -2
- package/dist/ui.d.mts +11977 -0
- package/dist/ui.mjs +2 -0
- package/dist/ui2.d.mts +2 -0
- package/dist/vite.d.mts +57 -2
- package/dist/vite.mjs +56 -10
- package/package.json +12 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @jchat/addon-sdk
|
|
2
2
|
|
|
3
|
+
## 1.0.0-alpha.6
|
|
4
|
+
|
|
5
|
+
## 1.0.0-alpha.5
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
- 9755c28: Export curated UI components, types, and Tailwind styles from `@jchat/addon-sdk/ui` (`@jchat/addon-sdk/ui/tailwind.css`) for sandbox and third-party addon developers.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- ad4b00c: Add `OWNER_SETTINGS` (`"owner-settings"`) and `ADDON_SETTINGS` (`"addon-settings"`) to `MOUNT_POINTS` constant and strictly type `MountPoint` union to official mount points. Remove legacy `ConfigSchemaField` and `configSchema` from `AddonManifest` in favor of mount-point-driven settings.
|
|
14
|
+
- ada430f: Formatted type declarations in the Addon SDK to align with project style guidelines.
|
|
15
|
+
|
|
16
|
+
## 1.0.0-alpha.4
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- ada430f: Formatted type declarations in the Addon SDK to align with project style guidelines.
|
|
21
|
+
|
|
3
22
|
## 1.0.0-alpha.3
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -40,6 +40,30 @@ export default {
|
|
|
40
40
|
}
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
## Database Architecture & Schema Isolation
|
|
44
|
+
|
|
45
|
+
JChat database-bearing addons use **Kysely** for server-side database access:
|
|
46
|
+
|
|
47
|
+
- **0 Bundle Overhead**: Table definitions are pure TypeScript interfaces (`src/db.ts`), resulting in 0 runtime JavaScript bundle footprint.
|
|
48
|
+
- **Shared `addons` Schema**: All addon tables are placed inside the dedicated `"addons"` schema (e.g. `addons.DjDropTracks`, `addons.PollwisePolls`, `addons.GlimpseStories`), keeping them cleanly isolated from core `public` application tables without requiring dynamic PostgreSQL role creation (`CREATE ROLE`).
|
|
49
|
+
- **Mandatory Table Naming**: Table names **must start with a Capital letter** and **must be prefixed with your capitalized `addonId`** (e.g. `addons.MyAddonSettings`). Unprefixed tables are rejected by the host migration validator.
|
|
50
|
+
- **SQL Migrations**: Addon migrations are stored as plain SQL files (`migrations/001_*.sql`) listed in `manifest.ts` under `server.migrations`.
|
|
51
|
+
- **ID Column Convention**: Use `text` / `varchar(36)` for host-referencing IDs (`siteId`, `roomId`, `userId`) to ensure driver-agnostic, cast-free query execution with UUID v7 strings.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import type { AddonDatabase } from "@jchat/addon-sdk"
|
|
55
|
+
|
|
56
|
+
export interface MyAddonDatabase {
|
|
57
|
+
MyAddonSettings: {
|
|
58
|
+
id: string
|
|
59
|
+
siteId: string
|
|
60
|
+
createdAt: Date
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type MyAddonContext = AddonServerContext<MyAddonDatabase>
|
|
65
|
+
```
|
|
66
|
+
|
|
43
67
|
## License
|
|
44
68
|
|
|
45
69
|
Apache-2.0
|
package/dist/contracts.d.mts
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
//#region src/contracts.d.ts
|
|
2
2
|
type AddonPermission = string;
|
|
3
|
-
/**
|
|
4
|
-
* Defines a single configuration field for an addon's settings panel. These are shown to site
|
|
5
|
-
* admins in the Jchat dashboard.
|
|
6
|
-
*/
|
|
7
|
-
interface ConfigSchemaField {
|
|
8
|
-
/** Unique key used to store and retrieve the value in `getConfig` */
|
|
9
|
-
key: string;
|
|
10
|
-
/** Data type for validation and UI rendering */
|
|
11
|
-
type: "string" | "number" | "boolean";
|
|
12
|
-
/** Human-readable label shown in the settings UI */
|
|
13
|
-
label: string;
|
|
14
|
-
/** If true, the admin must provide a value before saving */
|
|
15
|
-
required?: boolean;
|
|
16
|
-
/** Whether the value is sensitive (encrypted at rest and masked in the UI) */
|
|
17
|
-
secret?: boolean;
|
|
18
|
-
/** Default value pre-filled in the settings form for new installations */
|
|
19
|
-
default?: string | number | boolean;
|
|
20
|
-
}
|
|
21
3
|
/** Definition of a custom permission introduced by an addon. */
|
|
22
4
|
interface AddonPermissionDefinition {
|
|
23
5
|
/** Permission identifier (recommended: `addon.<id>.<action>`) */
|
|
@@ -55,6 +37,10 @@ declare const MOUNT_POINTS: {
|
|
|
55
37
|
readonly EMOJI_PICKER_GIF_TAB: "emoji-picker-gif-tab";
|
|
56
38
|
/** Full-screen or modal dialog specifically for TubeScan */
|
|
57
39
|
readonly TUBESCAN_DIALOG: "tubescan-dialog";
|
|
40
|
+
/** Dedicated settings panel rendered in the Owner Dashboard */
|
|
41
|
+
readonly OWNER_SETTINGS: "owner-settings";
|
|
42
|
+
/** Dedicated settings panel rendered in the Site Admin Dashboard */
|
|
43
|
+
readonly ADDON_SETTINGS: "addon-settings";
|
|
58
44
|
};
|
|
59
45
|
/** Union type of all valid addon mount points. */
|
|
60
46
|
type MountPoint = (typeof MOUNT_POINTS)[keyof typeof MOUNT_POINTS];
|
|
@@ -123,8 +109,6 @@ interface AddonManifest {
|
|
|
123
109
|
permissions?: AddonPermission[];
|
|
124
110
|
/** Custom permissions that should be registered with the host application on installation */
|
|
125
111
|
permissionDefinitions?: AddonPermissionDefinition[];
|
|
126
|
-
/** Settings form structure shown to site admins. Values are stored encrypted per site */
|
|
127
|
-
configSchema?: ConfigSchemaField[];
|
|
128
112
|
}
|
|
129
113
|
//#endregion
|
|
130
|
-
export {
|
|
114
|
+
export { MountPoint as a, MOUNT_POINTS as i, AddonPermission as n, AddonPermissionDefinition as r, AddonManifest as t };
|
package/dist/diagnostics.d.mts
CHANGED
|
@@ -1,22 +1,69 @@
|
|
|
1
1
|
import { t as AddonManifest } from "./contracts.mjs";
|
|
2
2
|
//#region src/diagnostics.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Diagnostic result status indicator for addon validation checks. - `"pass"`: The diagnostic check
|
|
5
|
+
* passed successfully. - `"warning"`: Non-critical warning (e.g. source maps present in
|
|
6
|
+
* production). - `"error"`: Critical failure blocking addon installation or distribution.
|
|
7
|
+
*/
|
|
3
8
|
type AddonDiagnosticStatus = "pass" | "warning" | "error";
|
|
9
|
+
/** Represents an individual diagnostic check result for an addon package. */
|
|
4
10
|
interface AddonPackageDiagnostic {
|
|
11
|
+
/** Unique identifier for the diagnostic check (e.g. `"jchat"`, `"package-size"`). */
|
|
5
12
|
id: string;
|
|
13
|
+
/** Human-readable title for the diagnostic check. */
|
|
6
14
|
label: string;
|
|
15
|
+
/** Severity status outcome of the check. */
|
|
7
16
|
status: AddonDiagnosticStatus;
|
|
17
|
+
/** Descriptive message or metric value providing check details. */
|
|
8
18
|
message: string;
|
|
9
19
|
}
|
|
20
|
+
/** Options required to run diagnostic validation on an addon build package. */
|
|
10
21
|
interface AddonPackageDiagnosticOptions {
|
|
22
|
+
/** Absolute path to the compiled addon build output directory (`build/`). */
|
|
11
23
|
buildDir: string;
|
|
24
|
+
/** Parsed addon manifest object (`manifest.json`). */
|
|
12
25
|
manifest: AddonManifest;
|
|
26
|
+
/** Semantic version of the host JChat platform instance. */
|
|
13
27
|
jchatVersion: string;
|
|
28
|
+
/** Semantic version of the `@jchat/addon-sdk` package. */
|
|
14
29
|
addonSdkVersion: string;
|
|
30
|
+
/** Whether the diagnostic target is a production `.zip` package build. Defaults to `false`. */
|
|
15
31
|
productionPackage?: boolean;
|
|
32
|
+
/** Maximum allowable package size in bytes. Defaults to 25MB (`26,214,400` bytes). */
|
|
16
33
|
maxBytes?: number;
|
|
17
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Constructs a semantic version compatibility range covering all minor/patch versions of the
|
|
37
|
+
* current major version.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ;```ts
|
|
41
|
+
* createCompatibleMajorRange("1.4.2") // returns ">=1.4.2 <2.0.0"
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @param version - Valid semver string (e.g. `"1.2.0"`).
|
|
45
|
+
* @returns Semver range string matching the current major series (e.g. `">=1.2.0 <2.0.0"`).
|
|
46
|
+
* @throws {@link Error} If the input is not a valid semantic version string.
|
|
47
|
+
*/
|
|
18
48
|
declare function createCompatibleMajorRange(version: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Performs comprehensive diagnostic validation checks on an addon package build directory.
|
|
51
|
+
*
|
|
52
|
+
* Validates version compatibility ranges, verifies required build files (frontend/server bundles,
|
|
53
|
+
* migrations, seeds), checks total package size limits, flags production source maps, and verifies
|
|
54
|
+
* publisher digital signatures.
|
|
55
|
+
*
|
|
56
|
+
* @param options - Configuration options specifying build directory, manifest, and environment
|
|
57
|
+
* versions.
|
|
58
|
+
* @returns Array of {@link AddonPackageDiagnostic} results.
|
|
59
|
+
*/
|
|
19
60
|
declare function diagnoseAddonPackage(options: AddonPackageDiagnosticOptions): AddonPackageDiagnostic[];
|
|
61
|
+
/**
|
|
62
|
+
* Checks whether any diagnostic check in a diagnostic list returned a critical error.
|
|
63
|
+
*
|
|
64
|
+
* @param diagnostics - Array of diagnostic check results to evaluate.
|
|
65
|
+
* @returns `true` if at least one check has `status === "error"`, otherwise `false`.
|
|
66
|
+
*/
|
|
20
67
|
declare function hasAddonDiagnosticErrors(diagnostics: readonly AddonPackageDiagnostic[]): boolean;
|
|
21
68
|
//#endregion
|
|
22
69
|
export { AddonDiagnosticStatus, AddonPackageDiagnostic, AddonPackageDiagnosticOptions, createCompatibleMajorRange, diagnoseAddonPackage, hasAddonDiagnosticErrors };
|
package/dist/diagnostics.mjs
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import * as fs$1 from "node:fs";
|
|
2
2
|
import * as path$1 from "node:path";
|
|
3
3
|
//#region src/diagnostics.ts
|
|
4
|
+
/**
|
|
5
|
+
* Constructs a semantic version compatibility range covering all minor/patch versions of the
|
|
6
|
+
* current major version.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ;```ts
|
|
10
|
+
* createCompatibleMajorRange("1.4.2") // returns ">=1.4.2 <2.0.0"
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @param version - Valid semver string (e.g. `"1.2.0"`).
|
|
14
|
+
* @returns Semver range string matching the current major series (e.g. `">=1.2.0 <2.0.0"`).
|
|
15
|
+
* @throws {@link Error} If the input is not a valid semantic version string.
|
|
16
|
+
*/
|
|
4
17
|
function createCompatibleMajorRange(version) {
|
|
5
18
|
try {
|
|
6
19
|
Bun.semver.order(version, version);
|
|
@@ -12,6 +25,17 @@ function createCompatibleMajorRange(version) {
|
|
|
12
25
|
if (!Number.isSafeInteger(major)) throw new Error(`Invalid semantic version: ${version}`);
|
|
13
26
|
return `>=${version} <${major + 1}.0.0`;
|
|
14
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Performs comprehensive diagnostic validation checks on an addon package build directory.
|
|
30
|
+
*
|
|
31
|
+
* Validates version compatibility ranges, verifies required build files (frontend/server bundles,
|
|
32
|
+
* migrations, seeds), checks total package size limits, flags production source maps, and verifies
|
|
33
|
+
* publisher digital signatures.
|
|
34
|
+
*
|
|
35
|
+
* @param options - Configuration options specifying build directory, manifest, and environment
|
|
36
|
+
* versions.
|
|
37
|
+
* @returns Array of {@link AddonPackageDiagnostic} results.
|
|
38
|
+
*/
|
|
15
39
|
function diagnoseAddonPackage(options) {
|
|
16
40
|
const { buildDir, manifest } = options;
|
|
17
41
|
const diagnostics = [];
|
|
@@ -59,6 +83,18 @@ function diagnoseAddonPackage(options) {
|
|
|
59
83
|
status: totalBytes <= maxBytes ? "pass" : "error",
|
|
60
84
|
message: `${totalBytes} of ${maxBytes} bytes`
|
|
61
85
|
});
|
|
86
|
+
const addonPermPrefix = `addon.${manifest.id}.`;
|
|
87
|
+
const invalidPerms = Array.from(/* @__PURE__ */ new Set([
|
|
88
|
+
...manifest.accessPermission ? [manifest.accessPermission] : [],
|
|
89
|
+
...manifest.permissions ?? [],
|
|
90
|
+
...manifest.permissionDefinitions?.map((d) => d.name) ?? []
|
|
91
|
+
])).filter((perm) => !perm.startsWith(addonPermPrefix));
|
|
92
|
+
diagnostics.push({
|
|
93
|
+
id: "permission-namespacing",
|
|
94
|
+
label: "Permission namespacing",
|
|
95
|
+
status: invalidPerms.length === 0 ? "pass" : "error",
|
|
96
|
+
message: invalidPerms.length === 0 ? `All declared permissions start with ${addonPermPrefix}` : `Permission(s) do not follow naming convention ${addonPermPrefix}*: ${invalidPerms.join(", ")}`
|
|
97
|
+
});
|
|
62
98
|
const sourceMaps = files.filter((file) => file.endsWith(".map"));
|
|
63
99
|
diagnostics.push({
|
|
64
100
|
id: "source-maps",
|
|
@@ -81,9 +117,24 @@ function diagnoseAddonPackage(options) {
|
|
|
81
117
|
});
|
|
82
118
|
return diagnostics;
|
|
83
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Checks whether any diagnostic check in a diagnostic list returned a critical error.
|
|
122
|
+
*
|
|
123
|
+
* @param diagnostics - Array of diagnostic check results to evaluate.
|
|
124
|
+
* @returns `true` if at least one check has `status === "error"`, otherwise `false`.
|
|
125
|
+
*/
|
|
84
126
|
function hasAddonDiagnosticErrors(diagnostics) {
|
|
85
127
|
return diagnostics.some(({ status }) => status === "error");
|
|
86
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Evaluates semantic version compatibility between a target version and a semver range string.
|
|
131
|
+
*
|
|
132
|
+
* @param id - Diagnostic check identifier.
|
|
133
|
+
* @param label - Diagnostic check label.
|
|
134
|
+
* @param version - Environment component version string.
|
|
135
|
+
* @param range - Expected semver range string from manifest compatibility declarations.
|
|
136
|
+
* @returns An {@link AddonPackageDiagnostic} result object.
|
|
137
|
+
*/
|
|
87
138
|
function compatibilityDiagnostic(id, label, version, range) {
|
|
88
139
|
const compatible = Boolean(range && Bun.semver.satisfies(version, range));
|
|
89
140
|
return {
|
|
@@ -93,12 +144,26 @@ function compatibilityDiagnostic(id, label, version, range) {
|
|
|
93
144
|
message: range ? `${version} ${compatible ? "satisfies" : "does not satisfy"} ${range}` : "Compatibility range is missing"
|
|
94
145
|
};
|
|
95
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Safely resolves a relative build file reference within a target build directory, guarding against
|
|
149
|
+
* directory traversal attacks.
|
|
150
|
+
*
|
|
151
|
+
* @param buildDir - Absolute path to the build directory.
|
|
152
|
+
* @param reference - Relative file path declared in manifest.
|
|
153
|
+
* @returns Resolved absolute file path if safe and inside `buildDir`, or `null` if unsafe.
|
|
154
|
+
*/
|
|
96
155
|
function resolveBuildFile(buildDir, reference) {
|
|
97
156
|
if (path$1.isAbsolute(reference) || reference.includes("\\") || reference.split("/").includes("..")) return null;
|
|
98
157
|
const target = path$1.resolve(buildDir, ...reference.replace(/^\.\//, "").split("/"));
|
|
99
158
|
const relative = path$1.relative(path$1.resolve(buildDir), target);
|
|
100
159
|
return relative && !relative.startsWith("..") && !path$1.isAbsolute(relative) ? target : null;
|
|
101
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Recursively lists all regular files within a root directory.
|
|
163
|
+
*
|
|
164
|
+
* @param root - Path to search.
|
|
165
|
+
* @returns Array of absolute file paths.
|
|
166
|
+
*/
|
|
102
167
|
function listRegularFiles(root) {
|
|
103
168
|
if (!fs$1.existsSync(root)) return [];
|
|
104
169
|
return fs$1.readdirSync(root, {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as MountPoint, i as MOUNT_POINTS, n as AddonPermission, r as AddonPermissionDefinition, t as AddonManifest } from "./contracts.mjs";
|
|
2
2
|
import { ComponentType, SVGProps } from "react";
|
|
3
3
|
import { Elysia } from "elysia";
|
|
4
4
|
import { Kysely } from "kysely";
|
|
5
|
-
//#region ../icon/
|
|
5
|
+
//#region ../icon/dist/index.d.mts
|
|
6
|
+
//#region src/types.d.ts
|
|
6
7
|
type IconComponent = ComponentType<SVGProps<SVGSVGElement>>;
|
|
7
8
|
declare const ICON_NAMES: readonly ["ProfileMen", "ProfileWomen", "Stories", "Search", "AdminPanel", "Investigation", "Logout", "Users", "Settings", "RoomList", "AdminShip", "Announcement", "NewsFeed", "Ranks", "TopPoints", "Like", "DisLike", "Love", "Funny", "Comment", "Chat", "Brush", "Image", "Mic", "More", "Palette", "Smiley", "Send", "Private", "Action", "View", "Female", "Male", "LuSend", "Heart", "Trash", "HorizontalOption", "Menu", "UserGroup", "Globe", "Plus", "Loader", "X", "UserRoundPlus", "Footprints", "Calendar", "Volume", "Youtube", "Upload", "Play", "Pause", "Stop", "Ok", "ImageFill", "MicFill", "YoutubeFill", "PlusFill", "Music", "Gift", "Camera", "Envelope", "Key", "Signature", "UserPen", "Edit", "AddressCard", "Star", "StatusOnline", "StatusAway", "StatusBusy", "StatusEating", "StatusGaming", "StatusSinging", "StatusListening", "StatusStay"];
|
|
8
9
|
type IconName = (typeof ICON_NAMES)[number];
|
|
@@ -268,4 +269,4 @@ declare function useIcons(): {
|
|
|
268
269
|
*/
|
|
269
270
|
declare function getAddonSdkVersion(): string;
|
|
270
271
|
//#endregion
|
|
271
|
-
export { AddonApi, AddonDatabase, AddonEventListener, AddonFont, AddonJsonBody, type AddonManifest, type AddonPermission, type AddonPermissionDefinition, AddonProps, AddonRequestUser, AddonSDK, AddonSeedDocument, AddonServerContext, AddonServerFactory, AddonUser,
|
|
272
|
+
export { AddonApi, AddonDatabase, AddonEventListener, AddonFont, AddonJsonBody, type AddonManifest, type AddonPermission, type AddonPermissionDefinition, AddonProps, AddonRequestUser, AddonSDK, AddonSeedDocument, AddonServerContext, AddonServerFactory, AddonUser, MOUNT_POINTS, type MountPoint, defineAddonManifest, defineAddonServer, getAddonSdkVersion, useAddonSDK, useIcons };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region package.json
|
|
2
|
-
var version = "1.0.0-alpha.
|
|
2
|
+
var version = "1.0.0-alpha.6";
|
|
3
3
|
//#endregion
|
|
4
4
|
//#region src/contracts.ts
|
|
5
5
|
/** Valid locations where an addon can be rendered within the Jchat layout. */
|
|
@@ -29,7 +29,11 @@ const MOUNT_POINTS = {
|
|
|
29
29
|
/** Custom tab in the emoji/gif selection panel */
|
|
30
30
|
EMOJI_PICKER_GIF_TAB: "emoji-picker-gif-tab",
|
|
31
31
|
/** Full-screen or modal dialog specifically for TubeScan */
|
|
32
|
-
TUBESCAN_DIALOG: "tubescan-dialog"
|
|
32
|
+
TUBESCAN_DIALOG: "tubescan-dialog",
|
|
33
|
+
/** Dedicated settings panel rendered in the Owner Dashboard */
|
|
34
|
+
OWNER_SETTINGS: "owner-settings",
|
|
35
|
+
/** Dedicated settings panel rendered in the Site Admin Dashboard */
|
|
36
|
+
ADDON_SETTINGS: "addon-settings"
|
|
33
37
|
};
|
|
34
38
|
//#endregion
|
|
35
39
|
//#region src/index.ts
|