@loomweaver/plugin-sdk 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/package.json +45 -0
- package/src/index.d.ts +22 -0
- package/src/index.js +23 -0
- package/src/index.js.map +1 -0
- package/src/lib/auth.d.ts +60 -0
- package/src/lib/auth.js +35 -0
- package/src/lib/auth.js.map +1 -0
- package/src/lib/bar-item.d.ts +67 -0
- package/src/lib/bar-item.js +2 -0
- package/src/lib/bar-item.js.map +1 -0
- package/src/lib/button.d.ts +4 -0
- package/src/lib/button.js +2 -0
- package/src/lib/button.js.map +1 -0
- package/src/lib/capability.d.ts +38 -0
- package/src/lib/capability.js +32 -0
- package/src/lib/capability.js.map +1 -0
- package/src/lib/command.d.ts +199 -0
- package/src/lib/command.js +2 -0
- package/src/lib/command.js.map +1 -0
- package/src/lib/container-handle.d.ts +36 -0
- package/src/lib/container-handle.js +4 -0
- package/src/lib/container-handle.js.map +1 -0
- package/src/lib/content-route.d.ts +254 -0
- package/src/lib/content-route.js +2 -0
- package/src/lib/content-route.js.map +1 -0
- package/src/lib/contribution.d.ts +4 -0
- package/src/lib/contribution.js +2 -0
- package/src/lib/contribution.js.map +1 -0
- package/src/lib/dialog-ref.d.ts +25 -0
- package/src/lib/dialog-ref.js +37 -0
- package/src/lib/dialog-ref.js.map +1 -0
- package/src/lib/dialog.d.ts +105 -0
- package/src/lib/dialog.js +2 -0
- package/src/lib/dialog.js.map +1 -0
- package/src/lib/dirty-surface.d.ts +48 -0
- package/src/lib/dirty-surface.js +2 -0
- package/src/lib/dirty-surface.js.map +1 -0
- package/src/lib/menu.d.ts +48 -0
- package/src/lib/menu.js +2 -0
- package/src/lib/menu.js.map +1 -0
- package/src/lib/notification.d.ts +28 -0
- package/src/lib/notification.js +2 -0
- package/src/lib/notification.js.map +1 -0
- package/src/lib/pane-area.d.ts +29 -0
- package/src/lib/pane-area.js +2 -0
- package/src/lib/pane-area.js.map +1 -0
- package/src/lib/plugin-state.d.ts +52 -0
- package/src/lib/plugin-state.js +2 -0
- package/src/lib/plugin-state.js.map +1 -0
- package/src/lib/plugin.d.ts +259 -0
- package/src/lib/plugin.js +2 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/product-identity.d.ts +25 -0
- package/src/lib/product-identity.js +17 -0
- package/src/lib/product-identity.js.map +1 -0
- package/src/lib/rail-item.d.ts +61 -0
- package/src/lib/rail-item.js +2 -0
- package/src/lib/rail-item.js.map +1 -0
- package/src/lib/settings-model.d.ts +164 -0
- package/src/lib/settings-model.js +2 -0
- package/src/lib/settings-model.js.map +1 -0
- package/src/lib/surface.d.ts +220 -0
- package/src/lib/surface.js +2 -0
- package/src/lib/surface.js.map +1 -0
- package/src/lib/view-state.d.ts +38 -0
- package/src/lib/view-state.js +9 -0
- package/src/lib/view-state.js.map +1 -0
- package/src/lib/view.d.ts +103 -0
- package/src/lib/view.js +2 -0
- package/src/lib/view.js.map +1 -0
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@loomweaver/plugin-sdk",
|
|
3
|
+
"version": "0.7.2",
|
|
4
|
+
"description": "LoomWeaver plugin contract: the public SDK a weaver depends on — ProductIdentity, Command, PluginContext and the host UI vocabulary.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"loomweaver",
|
|
7
|
+
"plugin",
|
|
8
|
+
"sdk",
|
|
9
|
+
"plugin-contract",
|
|
10
|
+
"angular",
|
|
11
|
+
"extensibility",
|
|
12
|
+
"plugin-platform"
|
|
13
|
+
],
|
|
14
|
+
"license": "Apache-2.0",
|
|
15
|
+
"author": "Norbert Rosenwinkel (https://loomweaver.dev)",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./src/index.js",
|
|
18
|
+
"module": "./src/index.js",
|
|
19
|
+
"types": "./src/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./src/index.d.ts",
|
|
23
|
+
"default": "./src/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"tslib": "^2.3.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@angular/core": "^22.0.0"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://loomweaver.dev",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/yesbert/loomweaver/issues"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/yesbert/loomweaver.git",
|
|
43
|
+
"directory": "platform/libs/core/plugin-sdk"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export * from './lib/product-identity.js';
|
|
2
|
+
export * from './lib/contribution.js';
|
|
3
|
+
export * from './lib/capability.js';
|
|
4
|
+
export * from './lib/auth.js';
|
|
5
|
+
export * from './lib/menu.js';
|
|
6
|
+
export * from './lib/command.js';
|
|
7
|
+
export * from './lib/button.js';
|
|
8
|
+
export * from './lib/view.js';
|
|
9
|
+
export * from './lib/view-state.js';
|
|
10
|
+
export * from './lib/plugin-state.js';
|
|
11
|
+
export * from './lib/dirty-surface.js';
|
|
12
|
+
export * from './lib/pane-area.js';
|
|
13
|
+
export * from './lib/container-handle.js';
|
|
14
|
+
export * from './lib/content-route.js';
|
|
15
|
+
export * from './lib/surface.js';
|
|
16
|
+
export * from './lib/bar-item.js';
|
|
17
|
+
export * from './lib/rail-item.js';
|
|
18
|
+
export * from './lib/settings-model.js';
|
|
19
|
+
export * from './lib/dialog-ref.js';
|
|
20
|
+
export * from './lib/dialog.js';
|
|
21
|
+
export * from './lib/notification.js';
|
|
22
|
+
export * from './lib/plugin.js';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export * from './lib/product-identity.js';
|
|
2
|
+
export * from './lib/contribution.js';
|
|
3
|
+
export * from './lib/capability.js';
|
|
4
|
+
export * from './lib/auth.js';
|
|
5
|
+
export * from './lib/menu.js';
|
|
6
|
+
export * from './lib/command.js';
|
|
7
|
+
export * from './lib/button.js';
|
|
8
|
+
export * from './lib/view.js';
|
|
9
|
+
export * from './lib/view-state.js';
|
|
10
|
+
export * from './lib/plugin-state.js';
|
|
11
|
+
export * from './lib/dirty-surface.js';
|
|
12
|
+
export * from './lib/pane-area.js';
|
|
13
|
+
export * from './lib/container-handle.js';
|
|
14
|
+
export * from './lib/content-route.js';
|
|
15
|
+
export * from './lib/surface.js';
|
|
16
|
+
export * from './lib/bar-item.js';
|
|
17
|
+
export * from './lib/rail-item.js';
|
|
18
|
+
export * from './lib/settings-model.js';
|
|
19
|
+
export * from './lib/dialog-ref.js';
|
|
20
|
+
export * from './lib/dialog.js';
|
|
21
|
+
export * from './lib/notification.js';
|
|
22
|
+
export * from './lib/plugin.js';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/core/plugin-sdk/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth-aware, declarative access gating. LoomWeaver owns **none** of authentication —
|
|
3
|
+
* login, session, tokens, IdP integration live in the product. The platform only *reacts* to a
|
|
4
|
+
* session snapshot a distribution supplies, so chrome can hide/disable itself by login state and
|
|
5
|
+
* roles. Roles/claims are **opaque strings**: the platform matches, never interprets.
|
|
6
|
+
*
|
|
7
|
+
* Client-side gating is **presentation, not security** — the real enforcement is server-side (the
|
|
8
|
+
* product BFF rejects unauthorized calls). Never treat a hidden control as a boundary.
|
|
9
|
+
*/
|
|
10
|
+
/** A user/session snapshot the host reacts to. Provider-neutral (OIDC/custom/anything reduces here). */
|
|
11
|
+
export interface AuthSnapshot {
|
|
12
|
+
/** Whether someone is signed in. */
|
|
13
|
+
readonly authenticated: boolean;
|
|
14
|
+
/** Opaque role tokens held by the current principal (empty when anonymous). */
|
|
15
|
+
readonly roles: readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* Free-form claim bag; values are strings or string lists. It stays in the distribution's own
|
|
18
|
+
* code: **no plugin receives it** — a plugin permitted the session is told `authenticated` and
|
|
19
|
+
* `roles`, and nothing else — and **no access requirement evaluates it**, since the host matches
|
|
20
|
+
* on `authenticated` and `roles` only. Read it from your own composition; do not expect it to
|
|
21
|
+
* reach a plugin or to gate anything.
|
|
22
|
+
*/
|
|
23
|
+
readonly claims: Readonly<Record<string, string | readonly string[]>>;
|
|
24
|
+
/**
|
|
25
|
+
* Optional stable subject id — the **identity anchor**: the shell's identity-change
|
|
26
|
+
* policy (`provideAuthSource(..., { onIdentityChange })`) compares it across snapshots, and an
|
|
27
|
+
* identity-scoped settings store namespaces per-user state by it. Set it whenever the product
|
|
28
|
+
* can name the signed-in principal; encode the tenant into it if tenant switches should count
|
|
29
|
+
* as identity changes. Omit it and both features stay inert.
|
|
30
|
+
*/
|
|
31
|
+
readonly subject?: string;
|
|
32
|
+
/** Optional, display-only human name. */
|
|
33
|
+
readonly displayName?: string;
|
|
34
|
+
}
|
|
35
|
+
/** The anonymous baseline — the bare-platform default (nobody signed in). */
|
|
36
|
+
export declare const ANONYMOUS: AuthSnapshot;
|
|
37
|
+
/**
|
|
38
|
+
* How a contribution reacts to the auth state. Intentionally **coarse** — no expression parser
|
|
39
|
+
* (consistent with the `when` filter). Generic claim matching is the documented extension
|
|
40
|
+
* once a real case appears (YAGNI).
|
|
41
|
+
*/
|
|
42
|
+
export interface AccessRequirement {
|
|
43
|
+
/** Require a specific signed-in state (`true` = must be signed in, `false` = only anonymous). */
|
|
44
|
+
readonly authenticated?: boolean;
|
|
45
|
+
/** Require at least one of these roles. */
|
|
46
|
+
readonly anyRole?: readonly string[];
|
|
47
|
+
/** Require all of these roles. */
|
|
48
|
+
readonly allRoles?: readonly string[];
|
|
49
|
+
/**
|
|
50
|
+
* Effect on a chrome item when the requirement is **unmet**: `hide` (default) removes it, `disable`
|
|
51
|
+
* keeps it visible but inert. Routes/commands block on invoke regardless of this flag.
|
|
52
|
+
*/
|
|
53
|
+
readonly mode?: 'hide' | 'disable';
|
|
54
|
+
}
|
|
55
|
+
/** True when `snapshot` satisfies `access`. An undefined requirement is always allowed. */
|
|
56
|
+
export declare function meetsAccess(access: AccessRequirement | undefined, snapshot: AuthSnapshot): boolean;
|
|
57
|
+
/** Whether a chrome item should render at all: unmet + `hide` (the default) → not visible. */
|
|
58
|
+
export declare function isAccessVisible(access: AccessRequirement | undefined, snapshot: AuthSnapshot): boolean;
|
|
59
|
+
/** Whether a rendered chrome item should be disabled: unmet + `disable`. */
|
|
60
|
+
export declare function isAccessDisabled(access: AccessRequirement | undefined, snapshot: AuthSnapshot): boolean;
|
package/src/lib/auth.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth-aware, declarative access gating. LoomWeaver owns **none** of authentication —
|
|
3
|
+
* login, session, tokens, IdP integration live in the product. The platform only *reacts* to a
|
|
4
|
+
* session snapshot a distribution supplies, so chrome can hide/disable itself by login state and
|
|
5
|
+
* roles. Roles/claims are **opaque strings**: the platform matches, never interprets.
|
|
6
|
+
*
|
|
7
|
+
* Client-side gating is **presentation, not security** — the real enforcement is server-side (the
|
|
8
|
+
* product BFF rejects unauthorized calls). Never treat a hidden control as a boundary.
|
|
9
|
+
*/
|
|
10
|
+
/** The anonymous baseline — the bare-platform default (nobody signed in). */
|
|
11
|
+
export const ANONYMOUS = { authenticated: false, roles: [], claims: {} };
|
|
12
|
+
/** True when `snapshot` satisfies `access`. An undefined requirement is always allowed. */
|
|
13
|
+
export function meetsAccess(access, snapshot) {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
if (!access)
|
|
16
|
+
return true;
|
|
17
|
+
if (access.authenticated !== undefined && access.authenticated !== snapshot.authenticated) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const held = new Set(snapshot.roles);
|
|
21
|
+
if (((_a = access.anyRole) === null || _a === void 0 ? void 0 : _a.length) && !access.anyRole.some((role) => held.has(role)))
|
|
22
|
+
return false;
|
|
23
|
+
if (((_b = access.allRoles) === null || _b === void 0 ? void 0 : _b.length) && !access.allRoles.every((role) => held.has(role)))
|
|
24
|
+
return false;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
/** Whether a chrome item should render at all: unmet + `hide` (the default) → not visible. */
|
|
28
|
+
export function isAccessVisible(access, snapshot) {
|
|
29
|
+
return meetsAccess(access, snapshot) || (access === null || access === void 0 ? void 0 : access.mode) === 'disable';
|
|
30
|
+
}
|
|
31
|
+
/** Whether a rendered chrome item should be disabled: unmet + `disable`. */
|
|
32
|
+
export function isAccessDisabled(access, snapshot) {
|
|
33
|
+
return !!access && access.mode === 'disable' && !meetsAccess(access, snapshot);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4BH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,SAAS,GAAiB,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAqBvF,2FAA2F;AAC3F,MAAM,UAAU,WAAW,CACzB,MAAqC,EACrC,QAAsB;;IAEtB,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC,aAAa,EAAE,CAAC;QAC1F,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,CAAA,MAAA,MAAM,CAAC,OAAO,0CAAE,MAAM,KAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3F,IAAI,CAAA,MAAA,MAAM,CAAC,QAAQ,0CAAE,MAAM,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,eAAe,CAC7B,MAAqC,EACrC,QAAsB;IAEtB,OAAO,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,MAAK,SAAS,CAAC;AACrE,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAC9B,MAAqC,EACrC,QAAsB;IAEtB,OAAO,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Type } from '@angular/core';
|
|
2
|
+
import { AccessRequirement } from './auth.js';
|
|
3
|
+
/** Bar slots. */
|
|
4
|
+
export type BarSlot = 'start' | 'center' | 'end';
|
|
5
|
+
interface BarItemBase {
|
|
6
|
+
/** Stable id — same id overrides in place (last wins); used for ordering and removal. */
|
|
7
|
+
readonly id: string;
|
|
8
|
+
/** Target Bar region id (e.g. the top bar or a bottom status bar). */
|
|
9
|
+
readonly bar: string;
|
|
10
|
+
/** Which Bar slot the item renders in. */
|
|
11
|
+
readonly slot: BarSlot;
|
|
12
|
+
/** Lower renders first within a slot (default 0). */
|
|
13
|
+
readonly order?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Declarative auth gating: the host hides (default) or, for a {@link BarButtonItem},
|
|
16
|
+
* disables this item when the current session does not meet the requirement. `disable` mode only
|
|
17
|
+
* applies to the host-drawn button — a {@link BarComponentItem} owns its own cell, so it is only
|
|
18
|
+
* ever hidden. Presentation only; real enforcement is server-side. Omit for an item everyone sees.
|
|
19
|
+
*/
|
|
20
|
+
readonly access?: AccessRequirement;
|
|
21
|
+
}
|
|
22
|
+
/** A bar item that renders a plugin-provided component (full control over the cell). */
|
|
23
|
+
export interface BarComponentItem extends BarItemBase {
|
|
24
|
+
/** Component the host renders in the slot. */
|
|
25
|
+
readonly component: Type<unknown>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A declarative bar button — the host renders the button **and** its tooltip from data
|
|
29
|
+
* (host offering). Lets a plugin add a status-/top-bar button without authoring
|
|
30
|
+
* a component or importing `<lw-tooltip>`.
|
|
31
|
+
*/
|
|
32
|
+
export interface BarButtonItem extends BarItemBase {
|
|
33
|
+
/** Icon name shown in the button (optional if a label is given). */
|
|
34
|
+
readonly icon?: string;
|
|
35
|
+
/** Transloco key/literal for a visible text label (optional). */
|
|
36
|
+
readonly label?: string;
|
|
37
|
+
/** Transloco key/literal for the tooltip; falls back to {@link label}. */
|
|
38
|
+
readonly tooltip?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Id of a menu slot to open as this button's **context menu** on right-click — region-agnostic:
|
|
41
|
+
* the host wires the right-click uniformly and passes a serialisable context (`{ targetKind, id, region }`).
|
|
42
|
+
* Contribute items to the slot with `ctx.registerMenuItem({ menu, … })`. Omit for no context menu.
|
|
43
|
+
*/
|
|
44
|
+
readonly menu?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Id of a registered {@link Command} this button triggers. Provide this **or** {@link run}; when
|
|
47
|
+
* set, the host runs that command (so a keybinding/palette can share the same behaviour).
|
|
48
|
+
*/
|
|
49
|
+
readonly command?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Show the {@link command}'s keyboard shortcut hint next to the label, OS-correct (⌘K on macOS,
|
|
52
|
+
* Ctrl+K elsewhere) — the same affordance a menu entry has. Only takes effect when {@link command}
|
|
53
|
+
* names a command that declares a `shortcut`; ignored otherwise. Opt-in because a bar is tighter
|
|
54
|
+
* than a menu. Default off.
|
|
55
|
+
*/
|
|
56
|
+
readonly showShortcut?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Inline behaviour, for a button that is not backed by a registered command. May be async; the
|
|
59
|
+
* host fires it fire-and-forget. Typed `() => void` so a one-expression arrow whose handler
|
|
60
|
+
* happens to return a value (e.g. `() => ctx.ui.openSettings()`) still assigns — the return is
|
|
61
|
+
* ignored either way.
|
|
62
|
+
*/
|
|
63
|
+
run?(): void;
|
|
64
|
+
}
|
|
65
|
+
/** A control the host renders into a slot of a Bar region. */
|
|
66
|
+
export type BarItem = BarComponentItem | BarButtonItem;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bar-item.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/bar-item.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/button.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every coarse capability, in canonical display order. The single source of truth — {@link Capability}
|
|
3
|
+
* is derived from it so the type and the list can never drift, and a host surface (e.g. the built-in
|
|
4
|
+
* permissions settings) can iterate them.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CAPABILITIES: readonly ["contributions", "ui", "host", "navigation", "session", "theme", "automation"];
|
|
7
|
+
/**
|
|
8
|
+
* Coarse capabilities a plugin can hold — capability injection, **default-deny**: a plugin gets
|
|
9
|
+
* nothing it was not granted. Granularity is intentionally coarse first; a scope
|
|
10
|
+
* can split into finer ones later without changing the model. Each names a slice of the `ctx`:
|
|
11
|
+
*
|
|
12
|
+
* - `contributions` — register contributions (`ctx.registerSurface/Command/BarItem/RailItem/
|
|
13
|
+
* SettingsSection/MenuItem`, `ctx.contributeIcons`).
|
|
14
|
+
* - `ui` — use the host UI services (`ctx.ui.*`: dialogs, toasts, settings, context menus).
|
|
15
|
+
* - `host` — read host facts (`ctx.host`: version, update state).
|
|
16
|
+
* - `navigation` — drive and read the content area (`ctx.navigateContent/openContentTab/
|
|
17
|
+
* closeContentTab/keepContentTab/pinContentTab/unpinContentTab/revealSurface`
|
|
18
|
+
* and the read-side `ctx.activeContent`).
|
|
19
|
+
* - `session` — read session facts (`ctx.session`: login state + roles) for self-gating.
|
|
20
|
+
* - `theme` — contribute design tokens that re-color the whole app (`ctx.contributeTheme`).
|
|
21
|
+
* - `automation` — run actions other plugins contributed (`ctx.invokeCommand`,
|
|
22
|
+
* `ctx.invocableCommands`). A plugin reaches its own commands without it.
|
|
23
|
+
*/
|
|
24
|
+
export type Capability = (typeof CAPABILITIES)[number];
|
|
25
|
+
/**
|
|
26
|
+
* Thrown when a plugin uses a `ctx` surface it was not granted (default-deny). A curated-v1
|
|
27
|
+
* misconfiguration (the distribution forgot to grant a capability the plugin needs) surfaces
|
|
28
|
+
* loudly here rather than as a silent no-op — part of the `ctx`-boundary error taxonomy.
|
|
29
|
+
*/
|
|
30
|
+
export declare class CapabilityError extends Error {
|
|
31
|
+
readonly capability: Capability;
|
|
32
|
+
readonly pluginId: string;
|
|
33
|
+
/** Why this particular call needed the capability, when that is not obvious from the member alone. */
|
|
34
|
+
readonly reason?: string | undefined;
|
|
35
|
+
constructor(capability: Capability, pluginId: string,
|
|
36
|
+
/** Why this particular call needed the capability, when that is not obvious from the member alone. */
|
|
37
|
+
reason?: string | undefined);
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every coarse capability, in canonical display order. The single source of truth — {@link Capability}
|
|
3
|
+
* is derived from it so the type and the list can never drift, and a host surface (e.g. the built-in
|
|
4
|
+
* permissions settings) can iterate them.
|
|
5
|
+
*/
|
|
6
|
+
export const CAPABILITIES = [
|
|
7
|
+
'contributions',
|
|
8
|
+
'ui',
|
|
9
|
+
'host',
|
|
10
|
+
'navigation',
|
|
11
|
+
'session',
|
|
12
|
+
'theme',
|
|
13
|
+
'automation',
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when a plugin uses a `ctx` surface it was not granted (default-deny). A curated-v1
|
|
17
|
+
* misconfiguration (the distribution forgot to grant a capability the plugin needs) surfaces
|
|
18
|
+
* loudly here rather than as a silent no-op — part of the `ctx`-boundary error taxonomy.
|
|
19
|
+
*/
|
|
20
|
+
export class CapabilityError extends Error {
|
|
21
|
+
constructor(capability, pluginId,
|
|
22
|
+
/** Why this particular call needed the capability, when that is not obvious from the member alone. */
|
|
23
|
+
reason) {
|
|
24
|
+
super(`Plugin "${pluginId}" is missing the "${capability}" capability (default-deny).` +
|
|
25
|
+
(reason ? ` ${reason}` : ''));
|
|
26
|
+
this.capability = capability;
|
|
27
|
+
this.pluginId = pluginId;
|
|
28
|
+
this.reason = reason;
|
|
29
|
+
this.name = 'CapabilityError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/capability.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,eAAe;IACf,IAAI;IACJ,MAAM;IACN,YAAY;IACZ,SAAS;IACT,OAAO;IACP,YAAY;CACJ,CAAC;AAqBX;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YACW,UAAsB,EACtB,QAAgB;IACzB,sGAAsG;IAC7F,MAAe;QAExB,KAAK,CACH,WAAW,QAAQ,qBAAqB,UAAU,8BAA8B;YAC9E,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC/B,CAAC;QARO,eAAU,GAAV,UAAU,CAAY;QACtB,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,WAAM,GAAN,MAAM,CAAS;QAMxB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { AccessRequirement } from './auth.js';
|
|
2
|
+
import { MenuContext } from './menu.js';
|
|
3
|
+
/** A single value an argument or an answer can carry across any plugin boundary. */
|
|
4
|
+
export type CommandScalar = string | number | boolean;
|
|
5
|
+
/** What one declared argument may be given: a single value, or a list of them. */
|
|
6
|
+
export type CommandArgumentValue = CommandScalar | readonly CommandScalar[];
|
|
7
|
+
/** The arguments an invocation supplies, keyed by {@link CommandArgumentBase.name}. */
|
|
8
|
+
export type CommandArguments = Readonly<Record<string, CommandArgumentValue>>;
|
|
9
|
+
/**
|
|
10
|
+
* What a command may answer with — plain data, because an answer crosses the same boundary its
|
|
11
|
+
* arguments came from and anything else would arrive stripped of what it was.
|
|
12
|
+
*/
|
|
13
|
+
export type CommandAnswer = CommandScalar | null | readonly CommandAnswer[] | {
|
|
14
|
+
readonly [key: string]: CommandAnswer;
|
|
15
|
+
};
|
|
16
|
+
/** What every declared argument carries, whatever kind of value it takes. */
|
|
17
|
+
export interface CommandArgumentBase {
|
|
18
|
+
/** The name the invocation keys this argument by. */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
/**
|
|
21
|
+
* What this argument means, in prose — a Transloco key or a literal. Written for something
|
|
22
|
+
* *choosing* a value, not for a control labelling one, so say what it selects and what a sensible
|
|
23
|
+
* value looks like.
|
|
24
|
+
*/
|
|
25
|
+
readonly description: string;
|
|
26
|
+
/** Whether an invocation must supply it. Omit for an optional argument. */
|
|
27
|
+
readonly required?: boolean;
|
|
28
|
+
/** Take a list of this kind rather than a single value. Omit for a single value. */
|
|
29
|
+
readonly list?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** An argument taking a free value of one of the three plain kinds. */
|
|
32
|
+
export interface SimpleCommandArgument extends CommandArgumentBase {
|
|
33
|
+
readonly kind: 'text' | 'number' | 'boolean';
|
|
34
|
+
}
|
|
35
|
+
/** An argument taking one of a fixed set of strings. */
|
|
36
|
+
export interface ChoiceCommandArgument extends CommandArgumentBase {
|
|
37
|
+
readonly kind: 'choice';
|
|
38
|
+
/** The values this argument accepts; anything else is refused before the command runs. */
|
|
39
|
+
readonly choices: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* One argument a command accepts. The set of kinds is closed on purpose: a caller has to be able to
|
|
43
|
+
* describe a command to something that has never seen it, and a closed set makes a wrong declaration
|
|
44
|
+
* a compile error instead of a silent no-op. Widening it later is additive; narrowing it would not be.
|
|
45
|
+
*/
|
|
46
|
+
export type CommandArgument = SimpleCommandArgument | ChoiceCommandArgument;
|
|
47
|
+
/**
|
|
48
|
+
* Why an invocation was refused. A refusal is not a failure: the command did not run.
|
|
49
|
+
*
|
|
50
|
+
* `unavailable` is deliberately one answer for several situations — no such command, not open to a
|
|
51
|
+
* foreign caller, the session does not meet its access requirement, the window does not host it, the
|
|
52
|
+
* calling plugin was not granted the capability. Telling them apart would let a caller map what is
|
|
53
|
+
* installed by invoking ids and reading the reason back.
|
|
54
|
+
*/
|
|
55
|
+
export type CommandRefusalReason = 'unavailable' | 'invalid-arguments' | 'too-deep';
|
|
56
|
+
/** The command ran; `value` is present where the command declares {@link Command.answers}. */
|
|
57
|
+
export interface CommandAnswered {
|
|
58
|
+
readonly outcome: 'answered';
|
|
59
|
+
readonly value?: CommandAnswer;
|
|
60
|
+
}
|
|
61
|
+
/** The command did not run. */
|
|
62
|
+
export interface CommandRefused {
|
|
63
|
+
readonly outcome: 'refused';
|
|
64
|
+
readonly reason: CommandRefusalReason;
|
|
65
|
+
/** A developer-facing explanation; never the place to show a user a message. */
|
|
66
|
+
readonly message: string;
|
|
67
|
+
}
|
|
68
|
+
/** The command ran and threw, or its asynchronous work rejected. */
|
|
69
|
+
export interface CommandFailed {
|
|
70
|
+
readonly outcome: 'failed';
|
|
71
|
+
readonly message: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* What an invocation answers with. The three cases are distinct because a caller has to tell
|
|
75
|
+
* "you may not" from "it broke" from "here is your answer", and none of the three may be presented
|
|
76
|
+
* as either of the others.
|
|
77
|
+
*/
|
|
78
|
+
export type CommandOutcome = CommandAnswered | CommandRefused | CommandFailed;
|
|
79
|
+
/**
|
|
80
|
+
* A command as offered to a caller that may invoke it — the workbench's own account of what it can
|
|
81
|
+
* be asked to do. Every text is already resolved to the active language, because a caller outside the
|
|
82
|
+
* application cannot reach the translation bundles and a raw key would be useless to it.
|
|
83
|
+
*/
|
|
84
|
+
export interface InvocableCommand {
|
|
85
|
+
readonly id: string;
|
|
86
|
+
readonly title: string;
|
|
87
|
+
readonly description?: string;
|
|
88
|
+
readonly arguments?: readonly CommandArgument[];
|
|
89
|
+
readonly answers?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A named, invocable action.
|
|
93
|
+
* A command is the stable anchor that a keybinding, a command-palette entry, and a UI item
|
|
94
|
+
* (rail/bar/view-action/menu) all point at by {@link Command.id}: one behaviour, many triggers.
|
|
95
|
+
*
|
|
96
|
+
* Register via `ctx.registerCommand(...)`; a UI item references it with `command: <id>` instead
|
|
97
|
+
* of carrying its own inline `run()`.
|
|
98
|
+
*/
|
|
99
|
+
export interface Command {
|
|
100
|
+
/** Stable, namespaced id (e.g. "testbed.reset") — what triggers reference. */
|
|
101
|
+
readonly id: string;
|
|
102
|
+
/** Transloco key (or literal) for the command's label (command palette, menus). */
|
|
103
|
+
readonly title: string;
|
|
104
|
+
/** Optional icon name — resolved by the host icon registry (a plain string). */
|
|
105
|
+
readonly icon?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Optional default keyboard shortcut — a chord like `"mod+enter"` or `"mod+shift+p"`. Tokens are
|
|
108
|
+
* case-insensitive and `+`-joined: modifiers `mod` (⌘ on macOS, Ctrl elsewhere), `ctrl`, `meta`/
|
|
109
|
+
* `cmd`, `alt`/`option`, `shift`, then one key (`k`, `enter`, `escape`, …). The host binds it; user
|
|
110
|
+
* rebinding is deferred.
|
|
111
|
+
*/
|
|
112
|
+
readonly shortcut?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Declarative auth gating: the host **blocks** this command when the current session
|
|
115
|
+
* does not meet the requirement — every trigger flows through one seam, so the keybinding no-ops,
|
|
116
|
+
* the command palette omits it, and a UI item bound to it does nothing. A command is invocable or
|
|
117
|
+
* not, so `mode` is ignored here. Presentation only — real enforcement is server-side. Omit for a
|
|
118
|
+
* command everyone can run.
|
|
119
|
+
*/
|
|
120
|
+
readonly access?: AccessRequirement;
|
|
121
|
+
/**
|
|
122
|
+
* Hide this command from the command palette. Set it on a **context-only** command — one whose
|
|
123
|
+
* {@link Command.run} needs a {@link MenuContext} (a tab or view id) that only a menu supplies, so
|
|
124
|
+
* the palette (which invokes with no context) could offer nothing but a no-op. Menu items and
|
|
125
|
+
* keybindings still invoke it normally. Omit for a command the palette should list.
|
|
126
|
+
*/
|
|
127
|
+
readonly paletteHidden?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Offer this command in a **pop-out window** as well. Commands are main-window-only by
|
|
130
|
+
* default: a pop-out shows exactly one surface, with no tab strip, rail or sidebar, and is a viewer
|
|
131
|
+
* onto that surface rather than half the application. Without this flag the palette omits the
|
|
132
|
+
* command there, its keybinding no-ops and a UI item bound to it does nothing — the same one seam
|
|
133
|
+
* `access` flows through.
|
|
134
|
+
*
|
|
135
|
+
* The default is the quiet one on purpose: a command *missing* from a pop-out is a small
|
|
136
|
+
* annoyance, while one that does something surprising in a detached window is the larger failure,
|
|
137
|
+
* and the shell cannot tell the two apart for a command it did not write.
|
|
138
|
+
*
|
|
139
|
+
* Set it on what genuinely belongs beside a single surface — an about dialog, a theme toggle, an
|
|
140
|
+
* action on the surface's own data. Leave it off for anything that reaches for chrome a pop-out
|
|
141
|
+
* does not have: navigating the content area (which the shell refuses there anyway, since it would
|
|
142
|
+
* take the window out of its `/popout/…` address), opening or revealing a tab, focusing a docked
|
|
143
|
+
* view, changing the layout.
|
|
144
|
+
*/
|
|
145
|
+
readonly popout?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* What this command *does*, in prose — a Transloco key or a literal. Distinct from
|
|
148
|
+
* {@link Command.title}, which labels a control: a title is read beside an icon by someone who can
|
|
149
|
+
* already see where they are, a description is read by something deciding between actions it has
|
|
150
|
+
* never seen. Omit it and the command has none; the title is never substituted, because a label is
|
|
151
|
+
* not an explanation.
|
|
152
|
+
*
|
|
153
|
+
* A command that sets {@link Command.callable} without one is unusable to the very caller it opened
|
|
154
|
+
* itself to, and the manifest validator says so.
|
|
155
|
+
*/
|
|
156
|
+
readonly description?: string;
|
|
157
|
+
/**
|
|
158
|
+
* The arguments this command accepts. The host checks an invocation against them before the
|
|
159
|
+
* command runs — a missing required argument, a value of the wrong kind, or a choice outside the
|
|
160
|
+
* declared set is refused rather than reaching `run`. That check is for discovery, not for safety:
|
|
161
|
+
* validate your own inputs as you would without it.
|
|
162
|
+
*/
|
|
163
|
+
readonly arguments?: readonly CommandArgument[];
|
|
164
|
+
/**
|
|
165
|
+
* What this command answers with, in prose — a Transloco key or a literal. Declaring it is what
|
|
166
|
+
* makes {@link Command.run}'s return value the invocation's answer; without it an invocation
|
|
167
|
+
* succeeds carrying nothing, whatever `run` happened to return.
|
|
168
|
+
*/
|
|
169
|
+
readonly answers?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Let a caller **other than this plugin** invoke this command by its id. Omitted, it cannot be
|
|
172
|
+
* reached that way by any route and is absent from everything that lists what such a caller may
|
|
173
|
+
* run; the plugin that registered it always reaches its own regardless.
|
|
174
|
+
*
|
|
175
|
+
* The default is the quiet one on purpose, exactly as {@link Command.popout} is: a command
|
|
176
|
+
* *missing* from what an automated caller can reach is a small annoyance, while one that does
|
|
177
|
+
* something surprising because something other than the user triggered it is the larger failure,
|
|
178
|
+
* and the shell cannot tell the two apart for a command it did not write.
|
|
179
|
+
*
|
|
180
|
+
* Opening a command widens nothing else. It still runs only where its {@link Command.access}, its
|
|
181
|
+
* {@link Command.popout} declaration and the caller's own granted capabilities already allow, so a
|
|
182
|
+
* caller can never reach through it to something the user could not have triggered themselves.
|
|
183
|
+
*/
|
|
184
|
+
readonly callable?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* The behaviour. May be async; the host fires it and reports a failure rather than throwing.
|
|
187
|
+
* The return type is `unknown` so that a one-expression arrow handler still assigns whatever it
|
|
188
|
+
* returns; the host passes a value back to a caller only where {@link Command.answers} is declared,
|
|
189
|
+
* and only where the value is plain data.
|
|
190
|
+
*
|
|
191
|
+
* Receives an optional {@link MenuContext} when invoked from a menu — e.g. the tab context
|
|
192
|
+
* menu passes `{ tabId, … }` so `shell.tab.closeOthers` knows which tab. Triggers without a context
|
|
193
|
+
* (keybinding, palette, rail/bar item) call it with none; `run()` and `run(context)` are both valid.
|
|
194
|
+
*
|
|
195
|
+
* `args` holds what an invocation by id supplied, already checked against
|
|
196
|
+
* {@link Command.arguments}. A trigger the user drove supplies none.
|
|
197
|
+
*/
|
|
198
|
+
run(context?: MenuContext, args?: CommandArguments): unknown;
|
|
199
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/command.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* What a container child can ask of the container it sits in. Injected by a child
|
|
4
|
+
* surface, so that a list child can open the item a row stands for in a sibling pane.
|
|
5
|
+
*
|
|
6
|
+
* It is a host operation rather than a navigation on purpose. A container tab may sit in a split
|
|
7
|
+
* pane or in a pop-out, where it holds no browser address at all, and a list whose rows only work
|
|
8
|
+
* while its container happens to hold the URL would not be a list. While the container *does* hold
|
|
9
|
+
* the address, the URL follows and shows the focused child; elsewhere the child opens just the same
|
|
10
|
+
* and the address simply does not express it.
|
|
11
|
+
*
|
|
12
|
+
* Only a **docked** surface mounted inside a container receives one; anywhere else the token resolves
|
|
13
|
+
* to `null`, so a surface that can appear in both places checks before it calls.
|
|
14
|
+
*/
|
|
15
|
+
export interface ContainerHandle {
|
|
16
|
+
/**
|
|
17
|
+
* Open a child at an address inside this container, or focus it where it already is. The path is
|
|
18
|
+
* the child's declared segment with its values filled in — `open('item/42')` for a child declared
|
|
19
|
+
* as `{ surface: 'app.item', segment: 'item/:itemId' }`.
|
|
20
|
+
*
|
|
21
|
+
* It lands in the pane the container declared empty (`{ tabs: [] }`), which is what declaring one
|
|
22
|
+
* says; without such a pane it lands in the pane that currently carries the container's pointer.
|
|
23
|
+
*
|
|
24
|
+
* Give the tab a label, or several open items all read as the child surface's own title.
|
|
25
|
+
*/
|
|
26
|
+
open(path: string, label?: ContainerTabLabel): void;
|
|
27
|
+
}
|
|
28
|
+
/** How an opened child's tab is labelled — the same fields a content tab carries. */
|
|
29
|
+
export interface ContainerTabLabel {
|
|
30
|
+
/** Transloco key, or a literal when {@link titleIsLiteral} is set. */
|
|
31
|
+
readonly title?: string;
|
|
32
|
+
readonly titleIsLiteral?: boolean;
|
|
33
|
+
readonly icon?: string;
|
|
34
|
+
}
|
|
35
|
+
/** DI token for the {@link ContainerHandle}; `null` outside a container. */
|
|
36
|
+
export declare const CONTAINER_HANDLE: InjectionToken<ContainerHandle | null>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/** DI token for the {@link ContainerHandle}; `null` outside a container. */
|
|
3
|
+
export const CONTAINER_HANDLE = new InjectionToken('lw.container-handle', { factory: () => null });
|
|
4
|
+
//# sourceMappingURL=container-handle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-handle.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/container-handle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAqC/C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,cAAc,CAChD,qBAAqB,EACrB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CACxB,CAAC"}
|