@rigee/plugin-api 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The plugin contract, shared by main / preload / renderer.
3
+ *
4
+ * Rigee's core is a shell: a window, workspaces, a tab framework, terminals, persistence and the
5
+ * IPC spine. Everything that shows a document or a panel — the text editor, source control, the
6
+ * browser, the PDF viewer — is a plugin. This file is the contract they are written against.
7
+ *
8
+ * A plugin is not one object but up to two halves. Electron leaves no choice: a PDF renders in the
9
+ * sandboxed renderer, and the bytes it renders can only be read in main. So a plugin declares a
10
+ * `main` half and a `renderer` half, sharing an id and talking over one IPC channel.
11
+ *
12
+ * THREE RULES THAT SHAPE EVERYTHING HERE
13
+ *
14
+ * 1. This file holds the declarative part only — the shape read at boot to decide *what exists*.
15
+ * Knowing that some plugin claims `*.pdf` must not cost the 437 kB of pdf.js that renders one.
16
+ * The imperative halves load on demand, through the per-realm registries.
17
+ *
18
+ * 2. A manifest carries NO import thunks. They used to live here, and they cannot: TypeScript
19
+ * resolves the literal specifier of a dynamic `import()` into the program, so one manifest
20
+ * naming both halves drags the main half (node:fs) into the web project and the renderer half
21
+ * (.tsx) into the node project. Both fail `tsc -b`. The thunks live in `registry.main.ts` and
22
+ * `registry.renderer.ts`, each covered by exactly one tsconfig.
23
+ *
24
+ * 3. Contributions name components; they never hold them. cordis service access is between 700x
25
+ * and 2000x the cost of a plain property read (measured: 15.5 us for `ctx.svc.method()` against
26
+ * 8 ns), so the framework stays on the activation path and every render-path lookup goes
27
+ * through the plain Maps in the renderer's `bindings.ts`.
28
+ *
29
+ * This file is the root of `@rigee/plugin-api`, which is the version the two sides agree on. It
30
+ * must stay free of runtime imports: it is read at boot in main AND in the renderer, and anything
31
+ * it reaches lands in both bundles.
32
+ */
33
+ export const ALL_PERMISSIONS = [
34
+ 'files:read',
35
+ 'files:write',
36
+ 'process:spawn',
37
+ 'net'
38
+ ];
39
+ /** One line each, for the install dialog. The user reads these, not the identifiers. */
40
+ export const PERMISSION_LABELS = {
41
+ 'files:read': 'Read files on this computer',
42
+ 'files:write': 'Create and change files on this computer',
43
+ 'process:spawn': 'Run other programs',
44
+ net: 'Send and receive data over the network'
45
+ };
46
+ /**
47
+ * The API generation the shell implements.
48
+ *
49
+ * Bumped when something is REMOVED or changed shape — adding a function does not break a plugin
50
+ * that never calls it. A disk plugin whose `apiVersion` differs is refused at discovery.
51
+ */
52
+ export const PLUGIN_API_VERSION = 1;
53
+ /** Prefix a command must carry to be registerable by `id`. */
54
+ export function commandNamespace(id) {
55
+ return `${id}:`;
56
+ }
57
+ /** Prefix a view type, tab type, view or status bar item must carry to belong to `id`. */
58
+ export function viewNamespace(id) {
59
+ return `${id}.`;
60
+ }
61
+ export function matchesSelector(selector, absolutePath) {
62
+ if ('match' in selector)
63
+ return selector.match(absolutePath);
64
+ const dot = absolutePath.lastIndexOf('.');
65
+ const slash = Math.max(absolutePath.lastIndexOf('/'), absolutePath.lastIndexOf('\\'));
66
+ if (dot < 0 || dot < slash)
67
+ return false;
68
+ const ext = absolutePath.slice(dot + 1).toLowerCase();
69
+ return selector.extensions.some((e) => e.toLowerCase() === ext);
70
+ }
package/dist/ui.d.ts ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * What the shell hands a plugin's components, and what it expects back.
3
+ *
4
+ * Types only — there is no React value import here, and there must not be. This module is read by
5
+ * the main process too (a manifest is validated in both realms), and pulling React into main would
6
+ * cost every launch several milliseconds to load a library it can never render with.
7
+ *
8
+ * These used to live in the shell's `plugins/bindings.ts`, which is also where they are still
9
+ * implemented. The split is deliberate: the SHAPE is public and versioned with this package, the
10
+ * Maps that hold the components are private to the shell and may be rewritten at will.
11
+ */
12
+ import type { ComponentType, ReactNode } from 'react';
13
+ /** What every plugin-contributed editor receives. Kept to the two things a viewer cannot infer. */
14
+ export interface PluginEditorProps {
15
+ /** Absolute path of the file to show. */
16
+ filePath: string;
17
+ /** The tab this instance belongs to; the right key for any per-tab state a viewer keeps. */
18
+ tabId: string;
19
+ readOnly: boolean;
20
+ }
21
+ /** What a plugin-owned tab receives: its own persisted state, and the way to change it. */
22
+ export interface PluginTabProps {
23
+ tabId: string;
24
+ state: Record<string, unknown>;
25
+ /** Merged into the tab's state and persisted with it. */
26
+ patchState: (patch: Record<string, unknown>) => void;
27
+ /**
28
+ * Rename the tab in the strip, and optionally give it a hover tooltip.
29
+ *
30
+ * The tooltip is a second argument rather than a second function because the two always change
31
+ * together: a page navigates and both its title and its URL are new.
32
+ */
33
+ setTitle: (title: string, tooltip?: string) => void;
34
+ }
35
+ /** What a side-bar panel receives. The shell owns the rail and the collapse affordance. */
36
+ export interface PluginViewProps {
37
+ onCollapse: () => void;
38
+ }
39
+ export type PluginEditorComponent = ComponentType<PluginEditorProps>;
40
+ export type PluginTabComponent = ComponentType<PluginTabProps>;
41
+ export type PluginViewComponent = ComponentType<PluginViewProps>;
42
+ /**
43
+ * No props at all. `Record<never, never>` rather than `Record<string, never>`: the latter carries
44
+ * an index signature, and React's JSX check then rejects the `key` the shell has to put on every
45
+ * item it maps over.
46
+ */
47
+ export type PluginStatusItemComponent = ComponentType<Record<never, never>>;
48
+ export type PluginOverlayComponent = ComponentType<Record<never, never>>;
49
+ /** What a plugin returns when the shell asks it for a fresh tab of its own type. */
50
+ export type PluginTabFactory = () => {
51
+ title: string;
52
+ state: Record<string, unknown>;
53
+ key?: string;
54
+ };
55
+ /** Props every icon in `icons` accepts. */
56
+ export interface IconProps {
57
+ size?: number;
58
+ className?: string;
59
+ }
60
+ /**
61
+ * The shell's icon set, so a plugin draws the same chevron the file tree does.
62
+ *
63
+ * An object of components rather than one `<Icon name="…">`, because the file tree renders one per
64
+ * row and an extra component layer per row is a real cost in a 5,000-entry directory. The object
65
+ * is filled in when the shell installs its host (see `host.ts`), so a property read at render time
66
+ * is all it costs.
67
+ */
68
+ export interface IconSet {
69
+ Terminal: ComponentType<IconProps>;
70
+ File: ComponentType<IconProps>;
71
+ Files: ComponentType<IconProps>;
72
+ Diff: ComponentType<IconProps>;
73
+ Globe: ComponentType<IconProps>;
74
+ Folder: ComponentType<IconProps>;
75
+ AddFolder: ComponentType<IconProps>;
76
+ NewFile: ComponentType<IconProps>;
77
+ Plugin: ComponentType<IconProps>;
78
+ Plus: ComponentType<IconProps>;
79
+ Close: ComponentType<IconProps>;
80
+ Gear: ComponentType<IconProps>;
81
+ Split: ComponentType<IconProps>;
82
+ Branch: ComponentType<IconProps>;
83
+ Stage: ComponentType<IconProps>;
84
+ Unstage: ComponentType<IconProps>;
85
+ Discard: ComponentType<IconProps>;
86
+ Back: ComponentType<IconProps>;
87
+ Forward: ComponentType<IconProps>;
88
+ Reload: ComponentType<IconProps>;
89
+ Stop: ComponentType<IconProps>;
90
+ DevTools: ComponentType<IconProps>;
91
+ ExpandAll: ComponentType<IconProps>;
92
+ CollapseAll: ComponentType<IconProps>;
93
+ CollapseLeft: ComponentType<IconProps>;
94
+ CollapseRight: ComponentType<IconProps>;
95
+ Search: ComponentType<IconProps>;
96
+ Image: ComponentType<IconProps>;
97
+ Video: ComponentType<IconProps>;
98
+ /** The one icon with a state: `open` rotates it. */
99
+ Chevron: ComponentType<IconProps & {
100
+ open?: boolean;
101
+ }>;
102
+ }
103
+ export interface NoticeProps {
104
+ children: ReactNode;
105
+ tone?: 'muted' | 'error';
106
+ }
package/dist/ui.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * What the shell hands a plugin's components, and what it expects back.
3
+ *
4
+ * Types only — there is no React value import here, and there must not be. This module is read by
5
+ * the main process too (a manifest is validated in both realms), and pulling React into main would
6
+ * cost every launch several milliseconds to load a library it can never render with.
7
+ *
8
+ * These used to live in the shell's `plugins/bindings.ts`, which is also where they are still
9
+ * implemented. The split is deliberate: the SHAPE is public and versioned with this package, the
10
+ * Maps that hold the components are private to the shell and may be rewritten at will.
11
+ */
12
+ export {};
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@rigee/plugin-api",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "The contract a Rigee plugin is written against.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./manifest": {
15
+ "types": "./dist/manifest.d.ts",
16
+ "default": "./dist/manifest.js"
17
+ },
18
+ "./data": {
19
+ "types": "./dist/data.d.ts",
20
+ "default": "./dist/data.js"
21
+ },
22
+ "./context": {
23
+ "types": "./dist/context.d.ts",
24
+ "default": "./dist/context.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "peerDependencies": {
35
+ "cordis": ">=4.0.0-rc.10",
36
+ "react": ">=19"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "cordis": { "optional": true },
40
+ "react": { "optional": true }
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/Qyuan-Tech/rigee.git",
45
+ "directory": "packages/plugin-api"
46
+ }
47
+ }