@litelens/core 1.7.6 → 1.7.11

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 CHANGED
@@ -16,10 +16,13 @@ This package is a **type/documentation surface only** — every export in `src/i
16
16
 
17
17
  So this package exists to give plugin authors real types, JSDoc, and editor autocomplete during development, while the host controls the actual behavior. If a hook's signature changes on the host side (`frontend/src/expose/hooks/`), update the matching declaration here to keep them in sync — there is no automated check that they match.
18
18
 
19
+ The one exception is `createPluginBridge` (see "Using `createPluginBridge`" below): it is a real, self-contained implementation that lives in this package, not a stub. `frontend/src/expose/index.tsx` still wires it onto `window.__LITELENS_VENDOR__.core` like everything else here, but only as a straight pass-through — there is no separate host-side implementation for it to substitute.
20
+
19
21
  ## Contents
20
22
 
21
- - **`src/clusterWideAPI.ts`** (exported as `clusterWideAPI`) — capabilities scoped to the single-cluster view. See "Using `clusterWideAPI`" below.
22
- - **`src/appWideAPI.ts`** (exported as `appWideAPI`) — capabilities with no single-cluster-view constraint. See "Using `appWideAPI`" below.
23
+ - **`src/api/clusterWideAPI.ts`** (exported as `clusterWideAPI`) — capabilities scoped to the single-cluster view. See "Using `clusterWideAPI`" below.
24
+ - **`src/api/appWideAPI.ts`** (exported as `appWideAPI`) — capabilities with no single-cluster-view constraint. See "Using `appWideAPI`" below.
25
+ - **`src/api/frontendBridgeAPI.ts`** (exported as `createPluginBridge`) — factory for a plugin's HTTP bridge to its own backend. See "Using `createPluginBridge`" below.
23
26
  - **`src/types/`** — shared TypeScript types re-exported alongside the API namespaces above (`api`, `nav`, `resources`, `tray`).
24
27
  - **`src/build/tsupPreset.ts`** (exported as `@litelens/core/tsup-preset`) — shared tsup build config for plugin frontends: Node-only build tooling, kept out of the `.` export above so it never ships in the browser bundle the vendor shim substitutes for. See "Shared plugin build config" below.
25
28
 
@@ -69,6 +72,21 @@ function HelmChartListView() {
69
72
  - **`registerStylesheets(pluginId, stylesheets)`** — registers your plugin's global stylesheet(s) (e.g. compiled Tailwind output), loaded once at the app level regardless of which of your views is active. Call this once at module scope, alongside the `clusterWideAPI` registration calls above — don't use per-view `stylesheet` on `registerViews` for CSS that should apply across all of your views.
70
73
  - **`getQueryClient()`** — returns the host's singleton `QueryClient`. Use this from code that isn't a mounted React component (e.g. the module-scope `registerEvents` handler above) and therefore can't call `useQueryClient()`.
71
74
 
75
+ ## Using `createPluginBridge`
76
+
77
+ Business calls (`listCharts`, `installChart`, etc.) go straight from a plugin's frontend to its own backend over localhost HTTP, bypassing the host — see `litelens-plugins`' architecture notes for the full call-path rationale. `createPluginBridge(pluginID)` builds the fetch machinery for that path: it resolves the plugin's backend address via `window.go.app.App.GetPluginBackendAddr`, caches it, and retries once against a freshly-resolved address if a call fails with a network-level `TypeError` (the address went stale, e.g. the backend process restarted) — a `PluginError` response body from a reachable backend is not retried.
78
+
79
+ Each plugin calls this once and wraps the returned `fetchWithRetry` in its own typed, per-endpoint exports, since payload shapes differ per plugin:
80
+
81
+ ```ts
82
+ const { fetchWithRetry } = createPluginBridge("helm");
83
+
84
+ export const ListHelmCharts = (): Promise<HelmChart[]> =>
85
+ fetchWithRetry<HelmChart[]>("listCharts", {});
86
+ ```
87
+
88
+ `invalidateBackendAddrCache()` is exposed for callers that learn independently that the cached address is stale (e.g. a "plugin restarted" event) and want to force a fresh lookup on the next call.
89
+
72
90
  ## Shared plugin build config
73
91
 
74
92
  `@litelens/core/tsup-preset` exports `createPluginTsupConfig({ pluginRoot })`, the tsup config every plugin frontend needs: externalizes the host-shared runtime deps (`PLUGIN_SHARED_EXTERNALS`), inlines Tailwind-compiled CSS as text via a local Tailwind CLI pass, and optionally emits a bundle-analysis report to `dist/stats/` when `ANALYZE=true`. A plugin's own `tsup.config.ts` becomes:
package/dist/index.d.ts CHANGED
@@ -1084,4 +1084,37 @@ declare const appWideAPI: {
1084
1084
  getQueryClient: typeof getQueryClient;
1085
1085
  };
1086
1086
 
1087
- export { type CRBSubject, type ClusterRole, type ClusterRoleBinding, type ConfigMap, type CronJob, type CronJobSummary, type DaemonSet, type DaemonSetSummary, type Deployment, type DeploymentCondition, type DeploymentSummary, type Endpoint, type EndpointAddress, type EndpointPort, type EndpointSlice, type EndpointSliceEndpoint, type EndpointSlicePort, type EndpointSubset, type Event, type HPA, type HPADetail, type HPAMetric, type Ingress, type IngressClass, type IngressDetail, type IngressPath, type IngressRule, type Job, type JobCondition, type JobSummary, type Lease, type LimitRange, type LimitRangeDetail, type ManagedField, type Namespace, type NavEntry, type NavGroup, type NavItem, type NetworkPolicy, type NetworkPolicyDetail, type NetworkPolicyEgressRule, type NetworkPolicyIngressRule, type NetworkPolicyPeer, type Node, type NodeAddress, type NodeCondition, type PersistentVolume, type PersistentVolumeClaim, type PersistentVolumeClaimDetail, type PersistentVolumeDetail, type Pod, type PodCondition, type PodContainerDetail, type PodContainerLastStatus, type PodContainerMount, type PodContainerPort, type PodDisruptionBudget, type PodDisruptionBudgetDetail, type PodSummary, type PodVolume, type PodVolumeSource, type PolicyRule, type PortForward, type PriorityClass, type RBSubject, type ReplicaSet, type ReplicaSetSummary, type ResourceQuota, type ResourceQuotaDetail, type Role, type RoleBinding, type ScaleTargetRef, type Secret, type SecretDetail, type Service, type ServiceAccount, type ServicePort, type SharedNamespaceContext, type SharedUnifiedTrayContentProps, type SharedUnifiedTrayContext, type SharedUnifiedTrayOpenParams, type SharedUnifiedTrayTab, type StatefulSet, type StatefulSetSummary, type StorageClass, type TolerationDetail, type UnifiedTrayAllFamily, type UnifiedTrayCoreFamily, type UseQueryCallback, type ValidatingWebhookConfig, type ValidatingWebhookConfigDetail, type WebhookDetail, appWideAPI, clusterWideAPI };
1087
+ declare global {
1088
+ interface Window {
1089
+ go: {
1090
+ app: {
1091
+ App: {
1092
+ GetPluginBackendAddr(pluginID: string): Promise<string>;
1093
+ };
1094
+ };
1095
+ };
1096
+ }
1097
+ }
1098
+ type PluginError = {
1099
+ code: string;
1100
+ message: string;
1101
+ };
1102
+ type PluginBridge = {
1103
+ fetchWithRetry: <T>(method: string, payload: unknown) => Promise<T>;
1104
+ invalidateBackendAddrCache: () => void;
1105
+ };
1106
+ /**
1107
+ * Builds the fetch/retry/address-caching machinery for one plugin. Each
1108
+ * plugin's frontend calls this once with its own plugin ID and API path
1109
+ * segment, then wraps the returned `fetchWithRetry` in its own typed,
1110
+ * per-endpoint exports (payload shapes differ per plugin, so those stay in
1111
+ * the plugin's own bridge module).
1112
+ *
1113
+ * Example:
1114
+ * const { fetchWithRetry } = createPluginBridge("helm");
1115
+ * export const ListHelmCharts = (): Promise<HelmChart[]> =>
1116
+ * fetchWithRetry<HelmChart[]>("listCharts", {});
1117
+ */
1118
+ declare function createPluginBridge(pluginID: string): PluginBridge;
1119
+
1120
+ export { type CRBSubject, type ClusterRole, type ClusterRoleBinding, type ConfigMap, type CronJob, type CronJobSummary, type DaemonSet, type DaemonSetSummary, type Deployment, type DeploymentCondition, type DeploymentSummary, type Endpoint, type EndpointAddress, type EndpointPort, type EndpointSlice, type EndpointSliceEndpoint, type EndpointSlicePort, type EndpointSubset, type Event, type HPA, type HPADetail, type HPAMetric, type Ingress, type IngressClass, type IngressDetail, type IngressPath, type IngressRule, type Job, type JobCondition, type JobSummary, type Lease, type LimitRange, type LimitRangeDetail, type ManagedField, type Namespace, type NavEntry, type NavGroup, type NavItem, type NetworkPolicy, type NetworkPolicyDetail, type NetworkPolicyEgressRule, type NetworkPolicyIngressRule, type NetworkPolicyPeer, type Node, type NodeAddress, type NodeCondition, type PersistentVolume, type PersistentVolumeClaim, type PersistentVolumeClaimDetail, type PersistentVolumeDetail, type PluginBridge, type PluginError, type Pod, type PodCondition, type PodContainerDetail, type PodContainerLastStatus, type PodContainerMount, type PodContainerPort, type PodDisruptionBudget, type PodDisruptionBudgetDetail, type PodSummary, type PodVolume, type PodVolumeSource, type PolicyRule, type PortForward, type PriorityClass, type RBSubject, type ReplicaSet, type ReplicaSetSummary, type ResourceQuota, type ResourceQuotaDetail, type Role, type RoleBinding, type ScaleTargetRef, type Secret, type SecretDetail, type Service, type ServiceAccount, type ServicePort, type SharedNamespaceContext, type SharedUnifiedTrayContentProps, type SharedUnifiedTrayContext, type SharedUnifiedTrayOpenParams, type SharedUnifiedTrayTab, type StatefulSet, type StatefulSetSummary, type StorageClass, type TolerationDetail, type UnifiedTrayAllFamily, type UnifiedTrayCoreFamily, type UseQueryCallback, type ValidatingWebhookConfig, type ValidatingWebhookConfigDetail, type WebhookDetail, appWideAPI, clusterWideAPI, createPluginBridge };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // src/clusterWideAPI.ts
1
+ // src/api/clusterWideAPI.ts
2
2
  function useExposeProperties() {
3
3
  throw new Error(
4
4
  "clusterWideAPI.useExposeProperties is not available. This hook must be imported from '@litelens/core' within a plugin bundle loaded by the litelens host."
@@ -38,7 +38,7 @@ var clusterWideAPI = {
38
38
  registerEvents
39
39
  };
40
40
 
41
- // src/appWideAPI.ts
41
+ // src/api/appWideAPI.ts
42
42
  function registerStylesheets(pluginId, stylesheets) {
43
43
  throw new Error(
44
44
  "appWideAPI.registerStylesheets is not available. This function must be imported from '@litelens/core' within a plugin bundle loaded by the litelens host."
@@ -54,4 +54,60 @@ var appWideAPI = {
54
54
  getQueryClient
55
55
  };
56
56
 
57
- export { appWideAPI, clusterWideAPI };
57
+ // src/api/frontendBridgeAPI.ts
58
+ function createPluginBridge(pluginID) {
59
+ let backendAddr = null;
60
+ let addressFetchPromise = null;
61
+ function invalidateBackendAddrCache() {
62
+ backendAddr = null;
63
+ addressFetchPromise = null;
64
+ }
65
+ async function getBackendAddr() {
66
+ if (backendAddr) return backendAddr;
67
+ if (addressFetchPromise) return addressFetchPromise;
68
+ addressFetchPromise = window.go.app.App.GetPluginBackendAddr(pluginID).then((addr) => {
69
+ backendAddr = addr;
70
+ addressFetchPromise = null;
71
+ return addr;
72
+ }).catch((err) => {
73
+ addressFetchPromise = null;
74
+ throw err;
75
+ });
76
+ return addressFetchPromise;
77
+ }
78
+ async function doFetch(method, payload, addr) {
79
+ const response = await fetch(`http://${addr}/api/${pluginID}/${method}`, {
80
+ method: "POST",
81
+ headers: { "Content-Type": "application/json" },
82
+ body: JSON.stringify(payload)
83
+ });
84
+ if (!response.ok) {
85
+ const errBody = await response.json();
86
+ throw errBody;
87
+ }
88
+ return await response.json();
89
+ }
90
+ async function fetchWithRetry(method, payload) {
91
+ const addr = await getBackendAddr();
92
+ try {
93
+ return await doFetch(method, payload, addr);
94
+ } catch (err) {
95
+ if (err instanceof TypeError) {
96
+ invalidateBackendAddrCache();
97
+ try {
98
+ const freshAddr = await getBackendAddr();
99
+ return await doFetch(method, payload, freshAddr);
100
+ } catch {
101
+ throw {
102
+ code: "PLUGIN_UNAVAILABLE",
103
+ message: "Plugin backend unreachable"
104
+ };
105
+ }
106
+ }
107
+ throw err;
108
+ }
109
+ }
110
+ return { fetchWithRetry, invalidateBackendAddrCache };
111
+ }
112
+
113
+ export { appWideAPI, clusterWideAPI, createPluginBridge };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litelens/core",
3
- "version": "1.7.6",
3
+ "version": "1.7.11",
4
4
  "description": "React hooks and utilities for litelens plugin development",
5
5
  "private": false,
6
6
  "repository": {