@datum-cloud/portal-plugin-sdk 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Datum Technology, Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @datum-cloud/portal-plugin-sdk
2
+
3
+ The host-contract package for cloud-portal's [Portal Plugin
4
+ System](https://github.com/datum-cloud/cloud-portal/blob/main/docs/enhancements/portal-plugin-system.md).
5
+ A service team's plugin imports this package to reach the three things the
6
+ host provides — never a plugin-declared backend, and never a hand-rolled
7
+ stand-in.
8
+
9
+ ```tsx
10
+ import { useProjectContext, usePluginFetch, useResourceWatch } from '@datum-cloud/portal-plugin-sdk';
11
+
12
+ function InstanceList() {
13
+ const { project } = useProjectContext();
14
+ const pluginFetch = usePluginFetch();
15
+ const { lastEvent } = useResourceWatch({
16
+ resourceType: 'compute.miloapis.com/v1alpha1/workloads',
17
+ });
18
+
19
+ // pluginFetch is pre-scoped to `project`'s control plane and already
20
+ // authenticated — the path below is just the K8s API path.
21
+ // await pluginFetch('/apis/compute.miloapis.com/v1alpha1/namespaces/default/workloads')
22
+
23
+ return <div>{project?.displayName}</div>;
24
+ }
25
+ ```
26
+
27
+ ## Why a singleton, not a normal npm dependency
28
+
29
+ Plugins are loaded via Module Federation, in the host's own JavaScript realm.
30
+ If a plugin bundled its own copy of this package, its `useContext()` calls
31
+ would read from its own private Context — never the host's. The host
32
+ registers `@datum-cloud/portal-plugin-sdk` as an **eager singleton** shared
33
+ module (see cloud-portal's `federation-host.ts`), the same way it shares
34
+ `react` and `react-router`, so every plugin resolves the host's exact module
35
+ instance at runtime regardless of what version it was built against.
36
+
37
+ ## Two entry points, two audiences
38
+
39
+ - `@datum-cloud/portal-plugin-sdk` — the plugin-facing surface: `useProjectContext`,
40
+ `usePluginFetch`, `useResourceWatch`, and their result types. This is the
41
+ package a plugin repository actually calls.
42
+ - `@datum-cloud/portal-plugin-sdk/host` — host-only wiring
43
+ (`PortalPluginHostProvider`), imported by cloud-portal to supply the real
44
+ implementations behind those three hooks. A plugin should never import this.
45
+
46
+ ## Versioning
47
+
48
+ The host advertises its SDK version; a plugin manifest whose `sdk.range`
49
+ doesn't match is not loaded (`Compatible=False`). Per the enhancement doc:
50
+ additive changes (a new optional field, a new hook) are **minor**; removing a
51
+ hook or a required field is **major**, with a deprecation window. Both entry
52
+ points are part of that same contract — a breaking change to either is a
53
+ major bump.
54
+
55
+ ## Development
56
+
57
+ ```bash
58
+ pnpm install
59
+ pnpm build
60
+ pnpm test
61
+ pnpm typecheck
62
+ ```
@@ -0,0 +1,22 @@
1
+ import { createContext } from "react";
2
+ //#region src/context.ts
3
+ /**
4
+ * The single React Context instance shared by both this package's plugin-
5
+ * facing hooks (`.`) and the host-only Provider (`./host`).
6
+ *
7
+ * Why this matters for Module Federation: a Context object is only ever the
8
+ * same Context to `useContext()` if it is literally the same module instance.
9
+ * If the host and a plugin each bundled their own copy of this package, the
10
+ * plugin's `useProjectContext()` would read from the plugin's own empty
11
+ * Context — never the host's Provider. That's why cloud-portal's federation
12
+ * host must register `@datum-cloud/portal-plugin-sdk` itself as a Module
13
+ * Federation shared singleton (`singleton: true, eager: true`), exactly like
14
+ * `react` and `react-router` — see the host's federation-host.ts. As long as
15
+ * that's true, every consumer (host and every plugin) resolves this same
16
+ * module, so this same `createContext` call.
17
+ */
18
+ const PortalPluginHostContext = createContext(null);
19
+ //#endregion
20
+ export { PortalPluginHostContext as t };
21
+
22
+ //# sourceMappingURL=context-Cl6RRw0h.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-Cl6RRw0h.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["/**\n * The single React Context instance shared by both this package's plugin-\n * facing hooks (`.`) and the host-only Provider (`./host`).\n *\n * Why this matters for Module Federation: a Context object is only ever the\n * same Context to `useContext()` if it is literally the same module instance.\n * If the host and a plugin each bundled their own copy of this package, the\n * plugin's `useProjectContext()` would read from the plugin's own empty\n * Context — never the host's Provider. That's why cloud-portal's federation\n * host must register `@datum-cloud/portal-plugin-sdk` itself as a Module\n * Federation shared singleton (`singleton: true, eager: true`), exactly like\n * `react` and `react-router` — see the host's federation-host.ts. As long as\n * that's true, every consumer (host and every plugin) resolves this same\n * module, so this same `createContext` call.\n */\nimport { createContext } from 'react';\nimport type { PortalPluginHostBindings } from './types';\n\nexport const PortalPluginHostContext = createContext<PortalPluginHostBindings | null>(null);\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,MAAa,0BAA0B,cAA+C,IAAI"}
@@ -0,0 +1,10 @@
1
+ import { s as PortalPluginHostBindings } from "../types-CvoOm66Q.js";
2
+ import { ReactElement, ReactNode } from "react";
3
+ //#region src/host/index.d.ts
4
+ declare function PortalPluginHostProvider({ bindings, children }: {
5
+ bindings: PortalPluginHostBindings;
6
+ children: ReactNode;
7
+ }): ReactElement;
8
+ //#endregion
9
+ export { type PortalPluginHostBindings, PortalPluginHostProvider };
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/host/index.tsx"],"mappings":";;;iBAegB,2BACd,UACA;EAEA,UAAU;EACV,UAAU;IACR"}
@@ -0,0 +1,24 @@
1
+ import { t as PortalPluginHostContext } from "../context-Cl6RRw0h.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/host/index.tsx
4
+ /**
5
+ * Host-only wiring — imported by cloud-portal, never by a plugin.
6
+ *
7
+ * Wrap the tree that mounts plugin components (the project layout, or at
8
+ * minimum the plugin catch-all mount) in `<PortalPluginHostProvider>`, and
9
+ * pass real implementations for the three hooks. Because this package is
10
+ * registered as an eager, singleton Module Federation share (see
11
+ * federation-host.ts's `hostShared()`), a plugin's `useProjectContext()` /
12
+ * `usePluginFetch()` / `useResourceWatch()` calls resolve to this exact
13
+ * Provider's value, even though the plugin bundle never imports this module.
14
+ */
15
+ function PortalPluginHostProvider({ bindings, children }) {
16
+ return /* @__PURE__ */ jsx(PortalPluginHostContext.Provider, {
17
+ value: bindings,
18
+ children
19
+ });
20
+ }
21
+ //#endregion
22
+ export { PortalPluginHostProvider };
23
+
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/host/index.tsx"],"sourcesContent":["/**\n * Host-only wiring — imported by cloud-portal, never by a plugin.\n *\n * Wrap the tree that mounts plugin components (the project layout, or at\n * minimum the plugin catch-all mount) in `<PortalPluginHostProvider>`, and\n * pass real implementations for the three hooks. Because this package is\n * registered as an eager, singleton Module Federation share (see\n * federation-host.ts's `hostShared()`), a plugin's `useProjectContext()` /\n * `usePluginFetch()` / `useResourceWatch()` calls resolve to this exact\n * Provider's value, even though the plugin bundle never imports this module.\n */\nimport { PortalPluginHostContext } from '../context';\nimport type { PortalPluginHostBindings } from '../types';\nimport type { ReactElement, ReactNode } from 'react';\n\nexport function PortalPluginHostProvider({\n bindings,\n children,\n}: {\n bindings: PortalPluginHostBindings;\n children: ReactNode;\n}): ReactElement {\n return (\n <PortalPluginHostContext.Provider value={bindings}>{children}</PortalPluginHostContext.Provider>\n );\n}\n\nexport type { PortalPluginHostBindings } from '../types';\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,yBAAyB,EACvC,UACA,YAIe;CACf,OACE,oBAAC,wBAAwB,UAAzB;EAAkC,OAAO;EAAW;CAA2C,CAAA;AAEnG"}
@@ -0,0 +1,43 @@
1
+ import { a as PluginWatchEvent, c as UseResourceWatchOptions, i as PluginProjectContextValue, l as UseResourceWatchResult, n as PluginOrganization, o as PluginWatchEventType, r as PluginProject, t as PluginFetch } from "./types-CvoOm66Q.js";
2
+ //#region src/hooks/use-project-context.d.ts
3
+ /**
4
+ * The current project and organization the plugin is mounted under. Backed
5
+ * by the host's own project-resolution state (session, route params, and the
6
+ * project/org fetch) — a plugin never resolves this itself.
7
+ */
8
+ declare function useProjectContext(): PluginProjectContextValue;
9
+ //#endregion
10
+ //#region src/hooks/use-plugin-fetch.d.ts
11
+ /**
12
+ * A `fetch` pre-scoped to the current project's control plane and mediated
13
+ * through the portal's authenticated Milo proxy. This is the only data path
14
+ * a plugin gets — every API call a plugin issues, including calls to a
15
+ * service's own aggregated apiserver, must go through it. There is no
16
+ * plugin-declared backend.
17
+ */
18
+ declare function usePluginFetch(): PluginFetch;
19
+ //#endregion
20
+ //#region src/hooks/use-resource-watch.d.ts
21
+ /**
22
+ * Live updates for a resource in the current project's control plane,
23
+ * through the portal's existing watch stream (the same multiplexed SSE
24
+ * connection built-in pages use — a plugin never opens its own watch
25
+ * connection to Kubernetes).
26
+ */
27
+ declare function useResourceWatch<T = unknown>(options: UseResourceWatchOptions<T>): UseResourceWatchResult<T>;
28
+ //#endregion
29
+ //#region src/version.d.ts
30
+ /**
31
+ * Identity the host and a plugin's manifest both refer to. `SDK_VERSION`
32
+ * follows the semver discipline from docs/enhancements/portal-plugin-system.md:
33
+ * additive changes (new hook, new optional field) are minor releases;
34
+ * removing an extension point or a hook is major, with a deprecation window.
35
+ * The host compares its own advertised version against a plugin manifest's
36
+ * `sdk.range` and refuses to load on a mismatch (`Compatible=False`) — this
37
+ * constant is that source of truth on the SDK side.
38
+ */
39
+ declare const SDK_NAME = "@datum-cloud/portal-plugin-sdk";
40
+ declare const SDK_VERSION = "1.0.0";
41
+ //#endregion
42
+ export { type PluginFetch, type PluginOrganization, type PluginProject, type PluginProjectContextValue, type PluginWatchEvent, type PluginWatchEventType, SDK_NAME, SDK_VERSION, type UseResourceWatchOptions, type UseResourceWatchResult, usePluginFetch, useProjectContext, useResourceWatch };
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/hooks/use-project-context.ts","../src/hooks/use-plugin-fetch.ts","../src/hooks/use-resource-watch.ts","../src/version.ts"],"mappings":";;;;;;;iBAQgB,qBAAqB;;;;;;;;;;iBCErB,kBAAkB;;;;;;;;;iBCDlB,iBAAiB,aAC/B,SAAS,wBAAwB,KAChC,uBAAuB;;;;;;;;;;;;cCFb;cACA"}
package/dist/index.js ADDED
@@ -0,0 +1,66 @@
1
+ import { t as PortalPluginHostContext } from "./context-Cl6RRw0h.js";
2
+ import { useContext } from "react";
3
+ //#region src/hooks/use-host-bindings.ts
4
+ /**
5
+ * Every plugin-facing hook delegates to the host's real implementation rather
6
+ * than containing any logic itself — the SDK is a contract, not a client
7
+ * library. This throws with a specific, actionable message rather than
8
+ * silently returning defaults, because a missing binding here almost always
9
+ * means the MF shared-singleton wiring is wrong, not that the plugin did
10
+ * something incorrectly.
11
+ */
12
+ function useHostBindings(hookName) {
13
+ const bindings = useContext(PortalPluginHostContext);
14
+ if (!bindings) throw new Error(`${hookName}() was called outside the portal host's PortalPluginHostProvider. This usually means @datum-cloud/portal-plugin-sdk is not registered as a Module Federation shared singleton on the host, so the plugin's import resolved to a separate, unbound copy of this package instead of the host's — see @datum-cloud/portal-plugin-sdk/host.`);
15
+ return bindings;
16
+ }
17
+ //#endregion
18
+ //#region src/hooks/use-project-context.ts
19
+ /**
20
+ * The current project and organization the plugin is mounted under. Backed
21
+ * by the host's own project-resolution state (session, route params, and the
22
+ * project/org fetch) — a plugin never resolves this itself.
23
+ */
24
+ function useProjectContext() {
25
+ return useHostBindings("useProjectContext").useProjectContext();
26
+ }
27
+ //#endregion
28
+ //#region src/hooks/use-plugin-fetch.ts
29
+ /**
30
+ * A `fetch` pre-scoped to the current project's control plane and mediated
31
+ * through the portal's authenticated Milo proxy. This is the only data path
32
+ * a plugin gets — every API call a plugin issues, including calls to a
33
+ * service's own aggregated apiserver, must go through it. There is no
34
+ * plugin-declared backend.
35
+ */
36
+ function usePluginFetch() {
37
+ return useHostBindings("usePluginFetch").usePluginFetch();
38
+ }
39
+ //#endregion
40
+ //#region src/hooks/use-resource-watch.ts
41
+ /**
42
+ * Live updates for a resource in the current project's control plane,
43
+ * through the portal's existing watch stream (the same multiplexed SSE
44
+ * connection built-in pages use — a plugin never opens its own watch
45
+ * connection to Kubernetes).
46
+ */
47
+ function useResourceWatch(options) {
48
+ return useHostBindings("useResourceWatch").useResourceWatch(options);
49
+ }
50
+ //#endregion
51
+ //#region src/version.ts
52
+ /**
53
+ * Identity the host and a plugin's manifest both refer to. `SDK_VERSION`
54
+ * follows the semver discipline from docs/enhancements/portal-plugin-system.md:
55
+ * additive changes (new hook, new optional field) are minor releases;
56
+ * removing an extension point or a hook is major, with a deprecation window.
57
+ * The host compares its own advertised version against a plugin manifest's
58
+ * `sdk.range` and refuses to load on a mismatch (`Compatible=False`) — this
59
+ * constant is that source of truth on the SDK side.
60
+ */
61
+ const SDK_NAME = "@datum-cloud/portal-plugin-sdk";
62
+ const SDK_VERSION = "1.0.0";
63
+ //#endregion
64
+ export { SDK_NAME, SDK_VERSION, usePluginFetch, useProjectContext, useResourceWatch };
65
+
66
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/hooks/use-host-bindings.ts","../src/hooks/use-project-context.ts","../src/hooks/use-plugin-fetch.ts","../src/hooks/use-resource-watch.ts","../src/version.ts"],"sourcesContent":["import { PortalPluginHostContext } from '../context';\nimport type { PortalPluginHostBindings } from '../types';\nimport { useContext } from 'react';\n\n/**\n * Every plugin-facing hook delegates to the host's real implementation rather\n * than containing any logic itself — the SDK is a contract, not a client\n * library. This throws with a specific, actionable message rather than\n * silently returning defaults, because a missing binding here almost always\n * means the MF shared-singleton wiring is wrong, not that the plugin did\n * something incorrectly.\n */\nexport function useHostBindings(hookName: string): PortalPluginHostBindings {\n const bindings = useContext(PortalPluginHostContext);\n if (!bindings) {\n throw new Error(\n `${hookName}() was called outside the portal host's PortalPluginHostProvider. ` +\n 'This usually means @datum-cloud/portal-plugin-sdk is not registered as a Module ' +\n \"Federation shared singleton on the host, so the plugin's import resolved to a \" +\n \"separate, unbound copy of this package instead of the host's — see \" +\n '@datum-cloud/portal-plugin-sdk/host.'\n );\n }\n return bindings;\n}\n","import { useHostBindings } from './use-host-bindings';\nimport type { PluginProjectContextValue } from '../types';\n\n/**\n * The current project and organization the plugin is mounted under. Backed\n * by the host's own project-resolution state (session, route params, and the\n * project/org fetch) — a plugin never resolves this itself.\n */\nexport function useProjectContext(): PluginProjectContextValue {\n return useHostBindings('useProjectContext').useProjectContext();\n}\n","import { useHostBindings } from './use-host-bindings';\nimport type { PluginFetch } from '../types';\n\n/**\n * A `fetch` pre-scoped to the current project's control plane and mediated\n * through the portal's authenticated Milo proxy. This is the only data path\n * a plugin gets — every API call a plugin issues, including calls to a\n * service's own aggregated apiserver, must go through it. There is no\n * plugin-declared backend.\n */\nexport function usePluginFetch(): PluginFetch {\n return useHostBindings('usePluginFetch').usePluginFetch();\n}\n","import { useHostBindings } from './use-host-bindings';\nimport type { UseResourceWatchOptions, UseResourceWatchResult } from '../types';\n\n/**\n * Live updates for a resource in the current project's control plane,\n * through the portal's existing watch stream (the same multiplexed SSE\n * connection built-in pages use — a plugin never opens its own watch\n * connection to Kubernetes).\n */\nexport function useResourceWatch<T = unknown>(\n options: UseResourceWatchOptions<T>\n): UseResourceWatchResult<T> {\n return useHostBindings('useResourceWatch').useResourceWatch(options);\n}\n","/**\n * Identity the host and a plugin's manifest both refer to. `SDK_VERSION`\n * follows the semver discipline from docs/enhancements/portal-plugin-system.md:\n * additive changes (new hook, new optional field) are minor releases;\n * removing an extension point or a hook is major, with a deprecation window.\n * The host compares its own advertised version against a plugin manifest's\n * `sdk.range` and refuses to load on a mismatch (`Compatible=False`) — this\n * constant is that source of truth on the SDK side.\n */\nexport const SDK_NAME = '@datum-cloud/portal-plugin-sdk';\nexport const SDK_VERSION = '1.0.0';\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,gBAAgB,UAA4C;CAC1E,MAAM,WAAW,WAAW,uBAAuB;CACnD,IAAI,CAAC,UACH,MAAM,IAAI,MACR,GAAG,SAAS,wUAKd;CAEF,OAAO;AACT;;;;;;;;AChBA,SAAgB,oBAA+C;CAC7D,OAAO,gBAAgB,mBAAmB,CAAC,CAAC,kBAAkB;AAChE;;;;;;;;;;ACAA,SAAgB,iBAA8B;CAC5C,OAAO,gBAAgB,gBAAgB,CAAC,CAAC,eAAe;AAC1D;;;;;;;;;ACHA,SAAgB,iBACd,SAC2B;CAC3B,OAAO,gBAAgB,kBAAkB,CAAC,CAAC,iBAAiB,OAAO;AACrE;;;;;;;;;;;;ACJA,MAAa,WAAW;AACxB,MAAa,cAAc"}
@@ -0,0 +1,74 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * Plugin-facing contract types. Kept dependency-free (no react-query, no
4
+ * axios, no k8s client) so the SDK's own footprint never forces a version on
5
+ * a plugin's toolchain — the host is free to implement these hooks with
6
+ * whatever internal machinery it likes; only these shapes are the contract.
7
+ */
8
+ interface PluginProject {
9
+ /** Kubernetes resource name for the project; also its control-plane namespace. */
10
+ name: string;
11
+ displayName?: string;
12
+ }
13
+ interface PluginOrganization {
14
+ name: string;
15
+ displayName?: string;
16
+ }
17
+ interface PluginProjectContextValue {
18
+ project: PluginProject | undefined;
19
+ org: PluginOrganization | undefined;
20
+ isLoading: boolean;
21
+ error: Error | null;
22
+ }
23
+ /**
24
+ * A `fetch`-like function pre-scoped to the current project's control plane
25
+ * and already authenticated through the portal's session. `path` is just the
26
+ * Kubernetes API path (e.g. `/apis/compute.miloapis.com/v1alpha1/namespaces/
27
+ * default/workloads`) — the host prepends the project-scoped proxy prefix and
28
+ * injects the session's auth. This is the only data path a plugin gets: there
29
+ * is no plugin-declared backend, and a plugin never picks a base URL or auth
30
+ * strategy itself.
31
+ */
32
+ type PluginFetch = (path: string, init?: RequestInit) => Promise<Response>;
33
+ type PluginWatchEventType = 'ADDED' | 'MODIFIED' | 'DELETED' | 'BOOKMARK' | 'ERROR';
34
+ interface PluginWatchEvent<T = unknown> {
35
+ type: PluginWatchEventType;
36
+ object: T;
37
+ }
38
+ interface UseResourceWatchOptions<T = unknown> {
39
+ /** e.g. `compute.miloapis.com/v1alpha1/workloads`. Scoped to the current project. */
40
+ resourceType: string;
41
+ /** Watch a single named resource instead of a list. */
42
+ name?: string;
43
+ /** K8s namespace within the project's control plane. Defaults to `default`. */
44
+ namespace?: string;
45
+ labelSelector?: string;
46
+ fieldSelector?: string;
47
+ /** Set false to pause the subscription without unmounting. @default true */
48
+ enabled?: boolean;
49
+ /** Transform the raw watched object before it reaches `lastEvent`/`onEvent`. */
50
+ transform?: (raw: unknown) => T;
51
+ /** Imperative event handler, called for every event in addition to the returned state. */
52
+ onEvent?: (event: PluginWatchEvent<T>) => void;
53
+ }
54
+ interface UseResourceWatchResult<T = unknown> {
55
+ /** Most recently received event, or `null` before the first one arrives. */
56
+ lastEvent: PluginWatchEvent<T> | null;
57
+ /** Whether the underlying watch stream is currently connected. */
58
+ isConnected: boolean;
59
+ error: Error | null;
60
+ }
61
+ /**
62
+ * The real implementations the host supplies behind the plugin-facing hooks.
63
+ * Never imported by a plugin — only by cloud-portal, via `./host`. Shaped as
64
+ * a bag of hooks (not a single fetch/watch pair) so the host can freely use
65
+ * its own React Query / watch-manager internals in each implementation.
66
+ */
67
+ interface PortalPluginHostBindings {
68
+ useProjectContext(): PluginProjectContextValue;
69
+ usePluginFetch(): PluginFetch;
70
+ useResourceWatch<T = unknown>(options: UseResourceWatchOptions<T>): UseResourceWatchResult<T>;
71
+ }
72
+ //#endregion
73
+ export { PluginWatchEvent as a, UseResourceWatchOptions as c, PluginProjectContextValue as i, UseResourceWatchResult as l, PluginOrganization as n, PluginWatchEventType as o, PluginProject as r, PortalPluginHostBindings as s, PluginFetch as t };
74
+ //# sourceMappingURL=types-CvoOm66Q.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-CvoOm66Q.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;UAWiB;;EAEf;EACA;;UAGe;EACf;EACA;;UAGe;EACf,SAAS;EACT,KAAK;EACL;EACA,OAAO;;;;;;;;;;;KAgBG,eAAe,cAAc,OAAO,gBAAgB,QAAQ;KAM5D;UAEK,iBAAiB;EAChC,MAAM;EACN,QAAQ;;UAGO,wBAAwB;;EAEvC;;EAEA;;EAEA;EACA;EACA;;EAEA;;EAEA,aAAa,iBAAiB;;EAE9B,WAAW,OAAO,iBAAiB;;UAGpB,uBAAuB;;EAEtC,WAAW,iBAAiB;;EAE5B;EACA,OAAO;;;;;;;;UAaQ;EACf,qBAAqB;EACrB,kBAAkB;EAClB,iBAAiB,aAAa,SAAS,wBAAwB,KAAK,uBAAuB"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@datum-cloud/portal-plugin-sdk",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "description": "Host-contract SDK for cloud-portal's Portal Plugin System: React hooks (useProjectContext, usePluginFetch, useResourceWatch) that give a plugin its project identity, its only data path (the portal's authenticated Milo control-plane proxy), and live resource updates.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/datum-cloud/portal-plugin-sdk"
10
+ },
11
+ "sideEffects": false,
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "./host": {
18
+ "types": "./dist/host/index.d.ts",
19
+ "default": "./dist/host/index.js"
20
+ }
21
+ },
22
+ "main": "./dist/index.js",
23
+ "module": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "files": [
26
+ "LICENSE",
27
+ "README.md",
28
+ "dist"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsdown --config-loader native && node scripts/fix-eof.mjs",
32
+ "dev": "tsdown --config-loader native --watch",
33
+ "lint": "eslint .",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest",
37
+ "clean": "rm -rf dist .turbo node_modules coverage"
38
+ },
39
+ "peerDependencies": {
40
+ "react": ">=19.0.0 <20"
41
+ },
42
+ "devDependencies": {
43
+ "@testing-library/react": "^16.3.2",
44
+ "@types/react": "^19.2.17",
45
+ "@types/react-dom": "^19.2.3",
46
+ "eslint": "^9.19.0",
47
+ "jsdom": "^29.1.1",
48
+ "react": "^19.2.7",
49
+ "react-dom": "^19.2.7",
50
+ "tsdown": "^0.22.3",
51
+ "typescript": "^5.9.3",
52
+ "vitest": "^4.1.9"
53
+ },
54
+ "packageManager": "pnpm@11.8.0",
55
+ "publishConfig": {
56
+ "access": "public"
57
+ }
58
+ }