@makinbakin/sdk 0.0.1-rc.2 → 0.0.1-rc.20

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.
Files changed (42) hide show
  1. package/README.md +1 -0
  2. package/_internal/app/components/agent-select.d.ts +7 -2
  3. package/_internal/app/components/confirm-dialog.d.ts +33 -0
  4. package/_internal/app/components/empty-state.d.ts +14 -5
  5. package/_internal/app/components/ui/badge.d.ts +1 -1
  6. package/_internal/app/components/ui/button.d.ts +1 -1
  7. package/_internal/app/hooks/use-content-store.d.ts +0 -9
  8. package/_internal/app/hooks/use-horizontal-resize.d.ts +22 -0
  9. package/_internal/app/hooks/use-json-fetch.d.ts +21 -0
  10. package/_internal/app/hooks/use-nav-badge.d.ts +13 -0
  11. package/_internal/app/hooks/use-plugin-event.d.ts +19 -0
  12. package/_internal/app/hooks/use-resizable-pane.d.ts +35 -0
  13. package/_internal/app/hooks/use-schedule.d.ts +2 -1
  14. package/_internal/app/hooks/use-task-run-history.d.ts +26 -0
  15. package/_internal/app/hooks/use-vertical-resize.d.ts +6 -7
  16. package/_internal/app/types/index.d.ts +1 -105
  17. package/_internal/core/adapters/runtime/concepts.d.ts +141 -67
  18. package/_internal/core/adapters/runtime/errors.d.ts +86 -0
  19. package/_internal/core/adapters/runtime/index.d.ts +3 -1
  20. package/_internal/core/content-dir.d.ts +1 -0
  21. package/_internal/core/format.d.ts +9 -0
  22. package/_internal/core/plugin-types.d.ts +124 -470
  23. package/_internal/plugins/models/hooks/use-available-models.d.ts +5 -0
  24. package/_internal/plugins/team/types.d.ts +14 -4
  25. package/components/index.d.ts +40 -2
  26. package/components/index.js +15897 -1678
  27. package/hooks/index.d.ts +69 -8
  28. package/hooks/index.js +14589 -369
  29. package/index.d.ts +64 -2
  30. package/index.js +228 -7
  31. package/metadata/index.d.ts +14 -1
  32. package/package.json +1 -1
  33. package/register.d.ts +45 -9
  34. package/routing/index.d.ts +6 -1
  35. package/routing/index.js +13 -1
  36. package/slots/index.d.ts +16 -24
  37. package/slots/index.js +196 -30
  38. package/types/index.d.ts +15 -919
  39. package/ui/index.js +2 -1
  40. package/utils/index.d.ts +40 -3
  41. package/utils/index.js +57 -0
  42. package/_internal/app/hooks/use-assets.d.ts +0 -25
package/slots/index.js CHANGED
@@ -1,91 +1,257 @@
1
1
  // @bun
2
2
  // packages/sdk/src/slots/index.tsx
3
- import { useSyncExternalStore } from "react";
3
+ import { Component, useEffect, useSyncExternalStore } from "react";
4
+
5
+ // packages/sdk/src/slots/registry.ts
6
+ function getRegistry() {
7
+ const g = globalThis;
8
+ if (!g.__bakinSlotRegistry) {
9
+ g.__bakinSlotRegistry = new Map;
10
+ }
11
+ return g.__bakinSlotRegistry;
12
+ }
13
+ function registerSlot(name, component, order = 100, owner) {
14
+ const reg = getRegistry();
15
+ const entries = reg.get(name) ?? [];
16
+ entries.push({ component, order, owner });
17
+ entries.sort((a, b) => a.order - b.order);
18
+ reg.set(name, entries);
19
+ }
20
+ function getSlotEntries(name) {
21
+ return getRegistry().get(name) ?? [];
22
+ }
23
+ function getSlotNamesOwnedBy(pluginId) {
24
+ const names = [];
25
+ for (const [name, entries] of getRegistry().entries()) {
26
+ if (entries.some((e) => e.owner === pluginId))
27
+ names.push(name);
28
+ }
29
+ return names;
30
+ }
31
+ function clearSlotsOwnedBy(pluginId) {
32
+ const reg = getRegistry();
33
+ for (const [name, entries] of reg.entries()) {
34
+ const filtered = entries.filter((e) => e.owner !== pluginId);
35
+ if (filtered.length === 0)
36
+ reg.delete(name);
37
+ else
38
+ reg.set(name, filtered);
39
+ }
40
+ }
4
41
 
5
42
  // packages/sdk/src/register.ts
6
43
  "use client";
7
44
  function buildNavItemsSnapshot(registry) {
8
45
  const items = [];
46
+ for (const [pluginId, navItems] of registry.manifestNavByPlugin.entries()) {
47
+ if (registry.navByPlugin.has(pluginId))
48
+ continue;
49
+ items.push(...navItems);
50
+ }
9
51
  for (const navItems of registry.navByPlugin.values()) {
10
52
  items.push(...navItems);
11
53
  }
12
54
  return items.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
13
55
  }
14
- function getRegistry() {
56
+ function getRegistry2() {
15
57
  const g = globalThis;
16
58
  if (!g.__bakinClientRegistry) {
17
59
  g.__bakinClientRegistry = {
18
60
  navByPlugin: new Map,
61
+ manifestNavByPlugin: new Map,
19
62
  routesByPlugin: new Map,
20
63
  cleanupByPlugin: new Map,
21
64
  navItemsSnapshot: [],
22
65
  version: 0,
23
- listeners: new Set
66
+ listeners: new Set,
67
+ badgesByPlugin: new Map,
68
+ badgesSnapshot: new Map,
69
+ badgeListeners: new Set
24
70
  };
25
71
  }
26
72
  const registry = g.__bakinClientRegistry;
73
+ if (!registry.manifestNavByPlugin)
74
+ registry.manifestNavByPlugin = new Map;
27
75
  if (!Array.isArray(registry.navItemsSnapshot)) {
28
76
  registry.navItemsSnapshot = buildNavItemsSnapshot(registry);
29
77
  }
78
+ if (!registry.badgesByPlugin)
79
+ registry.badgesByPlugin = new Map;
80
+ if (!registry.badgesSnapshot)
81
+ registry.badgesSnapshot = buildBadgesSnapshot(registry);
82
+ if (!registry.badgeListeners)
83
+ registry.badgeListeners = new Set;
30
84
  return registry;
31
85
  }
86
+ function buildBadgesSnapshot(registry) {
87
+ const snapshot = new Map;
88
+ for (const byNavItemId of registry.badgesByPlugin.values()) {
89
+ for (const [navItemId, badge] of byNavItemId) {
90
+ if (!snapshot.has(navItemId))
91
+ snapshot.set(navItemId, badge);
92
+ }
93
+ }
94
+ return snapshot;
95
+ }
32
96
  function getRegistryVersion() {
33
- return getRegistry().version;
97
+ return getRegistry2().version;
34
98
  }
35
99
  function subscribeRegistry(listener) {
36
- const registry = getRegistry();
100
+ const registry = getRegistry2();
37
101
  registry.listeners.add(listener);
38
102
  return () => {
39
103
  registry.listeners.delete(listener);
40
104
  };
41
105
  }
42
106
 
43
- // packages/sdk/src/slots/index.tsx
44
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
107
+ // packages/sdk/src/lazy.ts
45
108
  "use client";
46
- function getRegistry2() {
109
+ function getStore() {
47
110
  const g = globalThis;
48
- if (!g.__bakinSlotRegistry) {
49
- g.__bakinSlotRegistry = new Map;
111
+ if (!g.__bakinLazyPluginStore) {
112
+ g.__bakinLazyPluginStore = {
113
+ ownersBySlot: new Map,
114
+ routeOwners: [],
115
+ states: new Map,
116
+ errors: new Map,
117
+ loader: null,
118
+ version: 0,
119
+ listeners: new Set
120
+ };
50
121
  }
51
- return g.__bakinSlotRegistry;
122
+ return g.__bakinLazyPluginStore;
52
123
  }
53
- function registerSlot(name, component, order = 100, owner) {
54
- const reg = getRegistry2();
55
- const entries = reg.get(name) ?? [];
56
- entries.push({ component, order, owner });
57
- entries.sort((a, b) => a.order - b.order);
58
- reg.set(name, entries);
124
+ function bump() {
125
+ const store = getStore();
126
+ store.version++;
127
+ for (const l of store.listeners) {
128
+ try {
129
+ l();
130
+ } catch (err) {
131
+ console.error("[bakin] lazy-plugin listener threw:", err);
132
+ }
133
+ }
59
134
  }
60
- function getSlotEntries(name) {
61
- return getRegistry2().get(name) ?? [];
135
+ function getPluginLoadState(pluginId) {
136
+ return getStore().states.get(pluginId) ?? "idle";
62
137
  }
63
- function clearSlotsOwnedBy(pluginId) {
64
- const reg = getRegistry2();
65
- for (const [name, entries] of reg.entries()) {
66
- const filtered = entries.filter((e) => e.owner !== pluginId);
67
- if (filtered.length === 0)
68
- reg.delete(name);
69
- else
70
- reg.set(name, filtered);
138
+ function getPluginLoadError(pluginId) {
139
+ return getStore().errors.get(pluginId);
140
+ }
141
+ function getSlotOwners(name) {
142
+ return getStore().ownersBySlot.get(name) ?? [];
143
+ }
144
+ function demand(pluginIds) {
145
+ const store = getStore();
146
+ if (!store.loader)
147
+ return;
148
+ for (const pluginId of pluginIds) {
149
+ if ((store.states.get(pluginId) ?? "idle") !== "idle")
150
+ continue;
151
+ store.loader(pluginId);
152
+ }
153
+ }
154
+ function requestSlotPlugins(name) {
155
+ demand(getSlotOwners(name));
156
+ }
157
+ function retryPluginLoad(pluginId) {
158
+ const store = getStore();
159
+ if (store.states.get(pluginId) !== "error")
160
+ return;
161
+ store.states.set(pluginId, "idle");
162
+ store.errors.delete(pluginId);
163
+ bump();
164
+ demand([pluginId]);
165
+ }
166
+ function getLazyPluginsVersion() {
167
+ return getStore().version;
168
+ }
169
+ function subscribeLazyPlugins(listener) {
170
+ const store = getStore();
171
+ store.listeners.add(listener);
172
+ return () => {
173
+ store.listeners.delete(listener);
174
+ };
175
+ }
176
+ // packages/sdk/src/slots/index.tsx
177
+ import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
178
+ "use client";
179
+
180
+ class SlotEntryBoundary extends Component {
181
+ state = { error: null };
182
+ static getDerivedStateFromError(error) {
183
+ return { error };
184
+ }
185
+ componentDidCatch(error) {
186
+ console.error(`[bakin] slot "${this.props.slotName}" entry${this.props.owner ? ` from plugin "${this.props.owner}"` : ""} crashed:`, error);
187
+ }
188
+ render() {
189
+ if (this.state.error) {
190
+ return /* @__PURE__ */ jsxDEV("div", {
191
+ className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
192
+ role: "alert",
193
+ children: [
194
+ this.props.owner ? `Plugin "${this.props.owner}"` : "A plugin",
195
+ " failed to render this section."
196
+ ]
197
+ }, undefined, true, undefined, this);
198
+ }
199
+ return this.props.children;
71
200
  }
72
201
  }
202
+ function SlotLoadError({ slotName, pluginIds }) {
203
+ return /* @__PURE__ */ jsxDEV("div", {
204
+ className: "flex flex-col items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
205
+ role: "alert",
206
+ children: [
207
+ /* @__PURE__ */ jsxDEV("span", {
208
+ children: [
209
+ pluginIds.length === 1 ? `Plugin "${pluginIds[0]}" failed to load` : `Plugins ${pluginIds.map((id) => `"${id}"`).join(", ")} failed to load`,
210
+ getPluginLoadError(pluginIds[0]) ? ` \u2014 ${getPluginLoadError(pluginIds[0])}` : ""
211
+ ]
212
+ }, undefined, true, undefined, this),
213
+ /* @__PURE__ */ jsxDEV("button", {
214
+ type: "button",
215
+ className: "rounded border border-destructive/40 px-2 py-1 text-xs hover:bg-destructive/20",
216
+ onClick: () => pluginIds.forEach(retryPluginLoad),
217
+ "aria-label": `Retry loading ${slotName}`,
218
+ children: "Retry"
219
+ }, undefined, false, undefined, this)
220
+ ]
221
+ }, undefined, true, undefined, this);
222
+ }
73
223
  function Slot({ name, ...props }) {
74
224
  useSyncExternalStore(subscribeRegistry, getRegistryVersion, getRegistryVersion);
225
+ useSyncExternalStore(subscribeLazyPlugins, getLazyPluginsVersion, getLazyPluginsVersion);
226
+ useEffect(() => {
227
+ requestSlotPlugins(name);
228
+ }, [name]);
75
229
  const entries = getSlotEntries(name);
76
- if (entries.length === 0)
230
+ if (entries.length === 0) {
231
+ const failed = getSlotOwners(name).filter((id) => getPluginLoadState(id) === "error");
232
+ if (failed.length > 0)
233
+ return /* @__PURE__ */ jsxDEV(SlotLoadError, {
234
+ slotName: name,
235
+ pluginIds: [...failed]
236
+ }, undefined, false, undefined, this);
77
237
  return null;
238
+ }
78
239
  return /* @__PURE__ */ jsxDEV(Fragment, {
79
240
  children: entries.map((entry, i) => {
80
241
  const C = entry.component;
81
- return /* @__PURE__ */ jsxDEV(C, {
82
- ...props
242
+ return /* @__PURE__ */ jsxDEV(SlotEntryBoundary, {
243
+ owner: entry.owner,
244
+ slotName: name,
245
+ children: /* @__PURE__ */ jsxDEV(C, {
246
+ ...props
247
+ }, undefined, false, undefined, this)
83
248
  }, `${name}-${i}`, false, undefined, this);
84
249
  })
85
250
  }, undefined, false, undefined, this);
86
251
  }
87
252
  export {
88
253
  registerSlot,
254
+ getSlotNamesOwnedBy,
89
255
  getSlotEntries,
90
256
  clearSlotsOwnedBy,
91
257
  Slot