@lobb-js/studio 0.1.34 → 0.1.36

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 (34) hide show
  1. package/package.json +2 -2
  2. package/src/lib/Lobb.d.ts +30 -0
  3. package/src/lib/Lobb.ts +241 -0
  4. package/src/lib/components/Studio.svelte +5 -5
  5. package/src/lib/components/routes/collections/collection.svelte +46 -0
  6. package/src/lib/components/routes/collections/collections.svelte +43 -0
  7. package/src/lib/components/routes/collections/collections.svelte.d.ts +5 -0
  8. package/src/lib/components/routes/data_model/dataModel.svelte +40 -0
  9. package/src/lib/components/routes/data_model/dataModel.svelte.d.ts +3 -0
  10. package/src/lib/components/routes/data_model/flow.css +22 -0
  11. package/src/lib/components/routes/data_model/flow.svelte +82 -0
  12. package/src/lib/components/routes/data_model/flow.svelte.d.ts +5 -0
  13. package/src/lib/components/routes/data_model/syncManager.svelte +93 -0
  14. package/src/lib/components/routes/data_model/syncManager.svelte.d.ts +3 -0
  15. package/src/lib/components/routes/data_model/utils.d.ts +4 -0
  16. package/src/lib/components/routes/data_model/utils.ts +35 -0
  17. package/src/lib/components/routes/extensions/extension.svelte +16 -0
  18. package/src/lib/components/routes/home.svelte +36 -0
  19. package/src/lib/components/routes/workflows/workflows.svelte +135 -0
  20. package/src/lib/components/routes/workflows/workflows.svelte.d.ts +5 -0
  21. package/src/lib/eventSystem.d.ts +1 -0
  22. package/src/lib/eventSystem.ts +38 -0
  23. package/src/lib/extensions/extension.types.d.ts +83 -0
  24. package/src/lib/extensions/extension.types.ts +93 -0
  25. package/src/lib/extensions/extensionUtils.d.ts +8 -0
  26. package/src/lib/extensions/extensionUtils.ts +192 -0
  27. package/src/lib/index.d.ts +9 -0
  28. package/src/lib/index.ts +36 -0
  29. package/src/lib/store.svelte.d.ts +4 -0
  30. package/src/lib/store.svelte.ts +33 -0
  31. package/src/lib/store.types.d.ts +26 -0
  32. package/src/lib/store.types.ts +28 -0
  33. package/src/lib/utils.d.ts +27 -0
  34. package/src/lib/utils.ts +84 -0
@@ -0,0 +1,35 @@
1
+ import Dagre from '@dagrejs/dagre';
2
+
3
+ export function getLayoutedElements(nodes: any[], edges: any[]) {
4
+ const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
5
+ g.setGraph({ rankdir: "LR" });
6
+
7
+ edges.forEach((edge) => g.setEdge(edge.source, edge.target));
8
+ nodes.forEach((node) => {
9
+ return g.setNode(node.id, {
10
+ ...node,
11
+ width: node.measured?.width ?? 0,
12
+ height: node.measured?.height ?? 0,
13
+ });
14
+ });
15
+
16
+ Dagre.layout(g);
17
+
18
+ return {
19
+ nodes: nodes.map((node) => {
20
+ const position = g.node(node.id);
21
+ // We are shifting the dagre node position (anchor=center center) to the top left
22
+ // so it matches the Svelte Flow node anchor point (top left).
23
+ const x = position.x - (node.measured?.width ?? 0) / 2;
24
+ const y = position.y - (node.measured?.height ?? 0) / 2;
25
+
26
+ return {
27
+ ...node,
28
+ position: { x, y },
29
+ targetPosition: "left",
30
+ sourcePosition: "right",
31
+ };
32
+ }),
33
+ edges,
34
+ };
35
+ }
@@ -0,0 +1,16 @@
1
+ <script>
2
+ import ExtensionsComponents from "$lib/components/extensionsComponents.svelte";
3
+ import { getExtensionUtils } from "$lib/extensions/extensionUtils";
4
+
5
+ let { extension, page } = $props();
6
+ </script>
7
+
8
+ <div class="grid overflow-auto bg-background">
9
+ {#key extension && page}
10
+ <ExtensionsComponents
11
+ name="pages.{page}"
12
+ utils={getExtensionUtils()}
13
+ filterByExtensions={[extension]}
14
+ />
15
+ {/key}
16
+ </div>
@@ -0,0 +1,36 @@
1
+ <script>
2
+ import Button from "$lib/components/ui/button/button.svelte";
3
+ import { ctx } from "$lib/store.svelte";
4
+ import { location } from "@wjfe/n-savant";
5
+ import { ArrowRight } from "lucide-svelte";
6
+ </script>
7
+
8
+ <div class="flex flex-col">
9
+ <div
10
+ class="flex flex-1 w-full flex-col items-center justify-center gap-4 text-muted-foreground"
11
+ >
12
+ <div class="flex flex-col items-center justify-center p-4">
13
+ <div class="text-3xl">Welcome to Lobb!</div>
14
+ <div class="text-xs text-center">
15
+ Your journey starts here. Explore and make the most of your
16
+ experience.
17
+ </div>
18
+ </div>
19
+ <div class="flex flex-col items-center justify-center">
20
+ <Button
21
+ Icon={ArrowRight}
22
+ variant="outline"
23
+ class="h-7 px-3 text-xs font-normal"
24
+ onclick={() => location.navigate("/collections")}
25
+ >
26
+ Go to collections
27
+ </Button>
28
+ </div>
29
+ </div>
30
+ <div class="flex justify-end p-2 text-xs text-muted-foreground/50">
31
+ <div class="flex flex-col text-end">
32
+ <div>studio: v{ctx.studioVersion}</div>
33
+ <div>core: v{ctx.meta.version}</div>
34
+ </div>
35
+ </div>
36
+ </div>
@@ -0,0 +1,135 @@
1
+ <script lang="ts">
2
+ import type { SideBarData } from "$lib/components/sidebar/sidebarElements.svelte";
3
+ import WorkflowEditor, {
4
+ type WorkflowEntry,
5
+ } from "$lib/components/workflowEditor.svelte";
6
+ import { lobb } from "$lib";
7
+ import Sidebar from "$lib/components/sidebar/sidebar.svelte";
8
+ import Button from "$lib/components/ui/button/button.svelte";
9
+ import { ctx } from "$lib/store.svelte";
10
+ import { location } from "@wjfe/n-savant";
11
+ import { CircleSlash2, Plus, Trash2 } from "lucide-svelte";
12
+ import { onMount } from "svelte";
13
+ import { showDialog } from "$lib/components/confirmationDialog/store.svelte";
14
+ import SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
15
+
16
+ let { workflowName } = $props();
17
+
18
+ let sidebarData: SideBarData | null = $state(null);
19
+ let workflowEntry: WorkflowEntry | null = $state(null);
20
+
21
+ onMount(async () => {
22
+ getSidebarData();
23
+ });
24
+
25
+ $effect(() => {
26
+ fetchWorkflowData(workflowName);
27
+ });
28
+
29
+ async function getSidebarData() {
30
+ const response = await lobb.findAll("core_workflows", {});
31
+ const result = await response.json();
32
+ const workflows: any[] = result.data;
33
+ sidebarData = workflows.map((workflow) => {
34
+ return {
35
+ name: workflow.name,
36
+ path: workflow.directory,
37
+ onclick: () => {
38
+ location.navigate(`/workflows/${workflow.name}`);
39
+ },
40
+ meta: {
41
+ id: workflow.id,
42
+ },
43
+ };
44
+ });
45
+ }
46
+
47
+ async function fetchWorkflowData(workflowName: string) {
48
+ if (workflowName && workflowName !== "new") {
49
+ const response = await lobb.findAll("core_workflows", {
50
+ filter: {
51
+ name: workflowName,
52
+ },
53
+ });
54
+ const result = await response.json();
55
+ const workflow = result.data[0];
56
+ workflowEntry = workflow;
57
+ } else {
58
+ const workflowHandlerDefaultValue =
59
+ ctx.meta.collections.core_workflows.fields.handler
60
+ .pre_processors.default;
61
+ workflowEntry = {
62
+ name: "",
63
+ event_name: "",
64
+ handler: workflowHandlerDefaultValue,
65
+ directory: "",
66
+ };
67
+ }
68
+ }
69
+
70
+ async function handleWorkflowDelete(
71
+ workflowName: string,
72
+ workflowId: string,
73
+ ) {
74
+ const result = await showDialog(
75
+ "Are you sure?",
76
+ "This will delete the Workflow you selected.",
77
+ );
78
+ if (result) {
79
+ await lobb.deleteOne("core_workflows", workflowId);
80
+ getSidebarData();
81
+ if (workflowEntry && workflowName === workflowEntry.name) {
82
+ location.navigate("/workflows");
83
+ }
84
+ }
85
+ }
86
+ </script>
87
+
88
+ <Sidebar title="Workflows" data={sidebarData}>
89
+ {#snippet belowSearch()}
90
+ <div class="pb-4 px-2">
91
+ <Button
92
+ class="h-7 px-3 text-xs font-normal w-full"
93
+ variant="outline"
94
+ onclick={() => location.navigate("/workflows/new")}
95
+ Icon={Plus}
96
+ >
97
+ Create a Workflow
98
+ </Button>
99
+ </div>
100
+ {/snippet}
101
+ {#snippet elementRightSide(element)}
102
+ <Button
103
+ class="h-6 w-6 text-muted-foreground hover:bg-transparent"
104
+ variant="ghost"
105
+ size="icon"
106
+ onclick={() => handleWorkflowDelete(element.name, element.meta?.id)}
107
+ Icon={Trash2}
108
+ ></Button>
109
+ {/snippet}
110
+ <div class="relative h-full w-full">
111
+ {#if workflowName === undefined}
112
+ <div
113
+ class="flex h-full w-full flex-col items-center justify-center gap-4 text-muted-foreground"
114
+ >
115
+ <CircleSlash2 class="opacity-50" size="50" />
116
+ <div class="flex flex-col items-center justify-center">
117
+ <div>No workflow selected</div>
118
+ <div class="text-xs">
119
+ Select a workflow to edit it or create new ones
120
+ </div>
121
+ </div>
122
+ </div>
123
+ {:else if workflowEntry}
124
+ {#key workflowEntry}
125
+ <WorkflowEditor
126
+ bind:workflow={workflowEntry}
127
+ refreshSidebar={getSidebarData}
128
+ />
129
+ {/key}
130
+ {/if}
131
+ <div class="absolute top-0 left-0 p-2.5">
132
+ <SidebarTrigger />
133
+ </div>
134
+ </div>
135
+ </Sidebar>
@@ -0,0 +1,5 @@
1
+ declare const Workflows: import("svelte").Component<{
2
+ workflowName: any;
3
+ }, {}, "">;
4
+ type Workflows = ReturnType<typeof Workflows>;
5
+ export default Workflows;
@@ -0,0 +1 @@
1
+ export declare function emitEvent(eventName: string, input: Record<string, any>): Promise<Record<string, any>>;
@@ -0,0 +1,38 @@
1
+ import { toast } from "svelte-sonner";
2
+ import { ctx } from "./store.svelte";
3
+ import { openCreateDetailView, openUpdateDetailView } from "./components/detailView/store.svelte";
4
+
5
+ export async function emitEvent(eventName: string, input: Record<string, any>) {
6
+ const workflows = ctx.meta.studio_workflows.filter(
7
+ (workflow) => {
8
+ return eventName.startsWith(workflow.eventName);
9
+ },
10
+ );
11
+
12
+ for (let index = 0; index < workflows.length; index++) {
13
+ const workflow = workflows[index];
14
+ try {
15
+ const localOutput = await workflow.handler(
16
+ input,
17
+ await getEventContext(),
18
+ );
19
+
20
+ if (localOutput) {
21
+ input = localOutput;
22
+ }
23
+ } catch (error) {
24
+ toast.error((error as any).message);
25
+ throw error;
26
+ }
27
+ }
28
+
29
+ return input;
30
+ }
31
+
32
+ async function getEventContext() {
33
+ return {
34
+ toast,
35
+ openCreateDetailView,
36
+ openUpdateDetailView,
37
+ };
38
+ }
@@ -0,0 +1,83 @@
1
+ import type { Lobb } from "$lib/Lobb";
2
+ import type { CTX } from "../lib/store.types";
3
+ import type { Button } from "$lib/components/ui/button";
4
+ import type { Input } from "$lib/components/ui/input";
5
+ import type { Separator } from "$lib/components/ui/separator";
6
+ import type { Skeleton } from "$lib/components/ui/skeleton";
7
+ import type LlmButton from "$lib/components/LlmButton.svelte";
8
+ import type Sidebar from "$lib/components/sidebar/sidebar.svelte";
9
+ import type SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
10
+ import type CreateDetailViewButton from "$lib/components/detailView/create/createDetailViewButton.svelte";
11
+ import type UpdateDetailViewButton from "$lib/components/detailView/update/updateDetailViewButton.svelte";
12
+ import type { getFileFromUser, mediaQueries } from "$lib/utils";
13
+ import type Table from "$lib/components/dataTable/table.svelte";
14
+ import type { Location } from "@wjfe/n-savant";
15
+ import type RangeCalendarButton from "$lib/components/rangeCalendarButton.svelte";
16
+ import type DataTable from "$lib/components/dataTable/dataTable.svelte";
17
+ import type Drawer from "$lib/components/drawer.svelte";
18
+ import type SelectRecord from "$lib/components/selectRecord.svelte";
19
+ import * as Popover from "$lib/components/ui/popover";
20
+ import * as intlDate from "@internationalized/date";
21
+ import * as Icons from "lucide-svelte";
22
+ import { ContextMenu } from "bits-ui";
23
+ import * as Tooltip from "$lib/components/ui/tooltip";
24
+ import * as Breadcrumb from "$lib/components/ui/breadcrumb";
25
+ import { showDialog } from "$lib/components/confirmationDialog/store.svelte";
26
+ import { toast } from "svelte-sonner";
27
+ import { Switch } from "$lib/components/ui/switch";
28
+ export interface Components {
29
+ Button: typeof Button;
30
+ Input: typeof Input;
31
+ Separator: typeof Separator;
32
+ Skeleton: typeof Skeleton;
33
+ LlmButton: typeof LlmButton;
34
+ Sidebar: typeof Sidebar;
35
+ SidebarTrigger: typeof SidebarTrigger;
36
+ CreateDetailViewButton: typeof CreateDetailViewButton;
37
+ UpdateDetailViewButton: typeof UpdateDetailViewButton;
38
+ Tooltip: typeof Tooltip;
39
+ Breadcrumb: typeof Breadcrumb;
40
+ ContextMenu: typeof ContextMenu;
41
+ Popover: typeof Popover;
42
+ Icons: typeof Icons;
43
+ Table: typeof Table;
44
+ RangeCalendarButton: typeof RangeCalendarButton;
45
+ DataTable: typeof DataTable;
46
+ Drawer: typeof Drawer;
47
+ SelectRecord: typeof SelectRecord;
48
+ Switch: typeof Switch;
49
+ }
50
+ export interface ExtensionUtils {
51
+ ctx: CTX;
52
+ lobb: Lobb;
53
+ location: Location;
54
+ toast: typeof toast;
55
+ showDialog: typeof showDialog;
56
+ getFileFromUser: typeof getFileFromUser;
57
+ components: Components;
58
+ mediaQueries: typeof mediaQueries;
59
+ intlDate: typeof intlDate;
60
+ }
61
+ interface DashboardNav {
62
+ label: string;
63
+ icon: any;
64
+ href?: string;
65
+ onclick?: () => void;
66
+ navs?: DashboardNav[];
67
+ }
68
+ export interface DashboardNavs {
69
+ top?: DashboardNav[];
70
+ middle?: DashboardNav[];
71
+ bottom?: DashboardNav[];
72
+ }
73
+ export interface ExtensionProps {
74
+ utils: ExtensionUtils;
75
+ [key: string]: any;
76
+ }
77
+ export interface Extension {
78
+ name: string;
79
+ onStartup?: (utils: ExtensionUtils) => Promise<void>;
80
+ components?: Record<string, any>;
81
+ dashboardNavs?: DashboardNavs;
82
+ }
83
+ export {};
@@ -0,0 +1,93 @@
1
+ import type { Lobb } from "$lib/Lobb";
2
+ import type { CTX } from "../lib/store.types";
3
+ import type { Button } from "$lib/components/ui/button";
4
+ import type { Input } from "$lib/components/ui/input";
5
+ import type { Separator } from "$lib/components/ui/separator";
6
+ import type { Skeleton } from "$lib/components/ui/skeleton";
7
+ import type LlmButton from "$lib/components/LlmButton.svelte";
8
+ import type Sidebar from "$lib/components/sidebar/sidebar.svelte";
9
+ import type SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
10
+ import type CreateDetailViewButton from "$lib/components/detailView/create/createDetailViewButton.svelte";
11
+ import type UpdateDetailViewButton from "$lib/components/detailView/update/updateDetailViewButton.svelte";
12
+ import type { getFileFromUser, mediaQueries } from "$lib/utils";
13
+ import type Table from "$lib/components/dataTable/table.svelte";
14
+ import type { Location } from "@wjfe/n-savant";
15
+ import type RangeCalendarButton from "$lib/components/rangeCalendarButton.svelte";
16
+ import type DataTable from "$lib/components/dataTable/dataTable.svelte";
17
+ import type Drawer from "$lib/components/drawer.svelte";
18
+ import type SelectRecord from "$lib/components/selectRecord.svelte";
19
+ import * as Popover from "$lib/components/ui/popover";
20
+ import * as intlDate from "@internationalized/date";
21
+ import * as Icons from "lucide-svelte"
22
+ import { ContextMenu } from "bits-ui";
23
+ import * as Tooltip from "$lib/components/ui/tooltip";
24
+ import * as Breadcrumb from "$lib/components/ui/breadcrumb";
25
+ import { showDialog } from "$lib/components/confirmationDialog/store.svelte";
26
+ import { toast } from "svelte-sonner";
27
+ import type Drawer from "$lib/components/drawer.svelte";
28
+ import { Switch } from "$lib/components/ui/switch";
29
+
30
+ // extensions utils
31
+ export interface Components {
32
+ Button: typeof Button;
33
+ Input: typeof Input;
34
+ Separator: typeof Separator;
35
+ Skeleton: typeof Skeleton;
36
+ LlmButton: typeof LlmButton;
37
+ Sidebar: typeof Sidebar;
38
+ SidebarTrigger: typeof SidebarTrigger;
39
+ CreateDetailViewButton: typeof CreateDetailViewButton;
40
+ UpdateDetailViewButton: typeof UpdateDetailViewButton;
41
+ Tooltip: typeof Tooltip;
42
+ Breadcrumb: typeof Breadcrumb;
43
+ ContextMenu: typeof ContextMenu;
44
+ Popover: typeof Popover;
45
+ Icons: typeof Icons;
46
+ Table: typeof Table;
47
+ RangeCalendarButton: typeof RangeCalendarButton;
48
+ DataTable: typeof DataTable;
49
+ Drawer: typeof Drawer;
50
+ SelectRecord: typeof SelectRecord,
51
+ Switch: typeof Switch,
52
+ }
53
+
54
+ export interface ExtensionUtils {
55
+ ctx: CTX;
56
+ lobb: Lobb;
57
+ location: Location;
58
+ toast: typeof toast;
59
+ showDialog: typeof showDialog;
60
+ getFileFromUser: typeof getFileFromUser;
61
+ components: Components;
62
+ mediaQueries: typeof mediaQueries;
63
+ intlDate: typeof intlDate;
64
+ }
65
+
66
+ // dashboard nav
67
+ interface DashboardNav {
68
+ label: string;
69
+ icon: any;
70
+ href?: string;
71
+ onclick?: () => void;
72
+ navs?: DashboardNav[];
73
+ }
74
+
75
+ export interface DashboardNavs {
76
+ top?: DashboardNav[];
77
+ middle?: DashboardNav[];
78
+ bottom?: DashboardNav[];
79
+ }
80
+
81
+ // extension components base Props
82
+ export interface ExtensionProps {
83
+ utils: ExtensionUtils;
84
+ [key: string]: any;
85
+ }
86
+
87
+ // extension exported object
88
+ export interface Extension {
89
+ name: string;
90
+ onStartup?: (utils: ExtensionUtils) => Promise<void>;
91
+ components?: Record<string, any>;
92
+ dashboardNavs?: DashboardNavs;
93
+ }
@@ -0,0 +1,8 @@
1
+ import type { Components, DashboardNavs, Extension, ExtensionUtils } from "./extension.types";
2
+ export declare function getComponents(): Components;
3
+ export declare function getExtensionUtils(): ExtensionUtils;
4
+ export declare function getExtensionsThatHasDash(): string[];
5
+ export declare function loadExtensions(studioExtensions?: any[]): Promise<Record<string, Extension>>;
6
+ export declare function loadExtensionComponents(name: string, filterByExtensions?: string[]): any[];
7
+ export declare function executeExtensionsOnStartup(): Promise<void>;
8
+ export declare function getDashboardNavs(): DashboardNavs;
@@ -0,0 +1,192 @@
1
+ import type {
2
+ Components,
3
+ DashboardNavs,
4
+ Extension,
5
+ ExtensionUtils,
6
+ } from "./extension.types";
7
+ import { lobb } from "$lib";
8
+ import { ctx } from "$lib/store.svelte";
9
+ import { toast } from "svelte-sonner";
10
+ import { showDialog } from "$lib/components/confirmationDialog/store.svelte";
11
+ import { Button } from "$lib/components/ui/button";
12
+ import { Input } from "$lib/components/ui/input";
13
+ import { Separator } from "$lib/components/ui/separator";
14
+ import { Skeleton } from "$lib/components/ui/skeleton";
15
+ import Table from "$lib/components/dataTable/table.svelte";
16
+ import { getFileFromUser, mediaQueries } from "$lib/utils";
17
+ import LlmButton from "$lib/components/LlmButton.svelte";
18
+ import Sidebar from "$lib/components/sidebar/sidebar.svelte";
19
+ import SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
20
+ import CreateDetailViewButton from "$lib/components/detailView/create/createDetailViewButton.svelte";
21
+ import UpdateDetailViewButton from "$lib/components/detailView/update/updateDetailViewButton.svelte";
22
+ import * as intlDate from "@internationalized/date";
23
+ import * as Tooltip from "$lib/components/ui/tooltip";
24
+ import * as Breadcrumb from "$lib/components/ui/breadcrumb";
25
+ import { ContextMenu } from "bits-ui";
26
+ import * as Popover from "$lib/components/ui/popover";
27
+ import * as Icons from "lucide-svelte";
28
+ import { location } from "@wjfe/n-savant";
29
+ import RangeCalendarButton from "$lib/components/rangeCalendarButton.svelte";
30
+ import DataTable from "$lib/components/dataTable/dataTable.svelte";
31
+ import Drawer from "$lib/components/drawer.svelte";
32
+ import SelectRecord from "$lib/components/selectRecord.svelte";
33
+ import { Switch } from "$lib/components/ui/switch";
34
+
35
+ export function getComponents(): Components {
36
+ return {
37
+ Button: Button,
38
+ Input: Input,
39
+ Separator: Separator,
40
+ Skeleton: Skeleton,
41
+ LlmButton: LlmButton,
42
+ Sidebar: Sidebar,
43
+ SidebarTrigger: SidebarTrigger,
44
+ CreateDetailViewButton: CreateDetailViewButton,
45
+ UpdateDetailViewButton: UpdateDetailViewButton,
46
+ Tooltip: Tooltip,
47
+ Breadcrumb: Breadcrumb,
48
+ ContextMenu: ContextMenu,
49
+ Popover: Popover,
50
+ Icons: Icons,
51
+ Table: Table,
52
+ RangeCalendarButton: RangeCalendarButton,
53
+ DataTable: DataTable,
54
+ Drawer: Drawer,
55
+ SelectRecord: SelectRecord,
56
+ Switch: Switch,
57
+ };
58
+ }
59
+
60
+ export function getExtensionUtils(): ExtensionUtils {
61
+ return {
62
+ ctx: ctx,
63
+ lobb: lobb,
64
+ location: location,
65
+ toast: toast,
66
+ showDialog: showDialog,
67
+ getFileFromUser: getFileFromUser,
68
+ components: getComponents(),
69
+ mediaQueries: mediaQueries,
70
+ intlDate: intlDate,
71
+ };
72
+ }
73
+
74
+ export function getExtensionsThatHasDash(): string[] {
75
+ const extensionNames = Object.keys(ctx.meta.extensions);
76
+
77
+ const extensionsWithDashExt = [];
78
+ for (let index = 0; index < extensionNames.length; index++) {
79
+ const extensionName = extensionNames[index];
80
+ const extensionMeta = ctx.meta.extensions[extensionName];
81
+ if (extensionMeta.hasDashboardExtension) {
82
+ extensionsWithDashExt.push(extensionName);
83
+ }
84
+ }
85
+
86
+ return extensionsWithDashExt;
87
+ }
88
+
89
+ export async function loadExtensions(studioExtensions?: any[]): Promise<Record<string, Extension>> {
90
+ const extensions: Record<string, Extension> = {};
91
+
92
+
93
+ if (studioExtensions) {
94
+ for (let index = 0; index < studioExtensions.length; index++) {
95
+ const studioExtension = studioExtensions[index](getExtensionUtils());
96
+ extensions[studioExtension.name] = studioExtension;
97
+ }
98
+ }
99
+
100
+ const extensionsThatHasDash = getExtensionsThatHasDash();
101
+ for (let index = 0; index < extensionsThatHasDash.length; index++) {
102
+ const extensionName = extensionsThatHasDash[index];
103
+
104
+ // Try to import locally-installed extension by name first
105
+ if (extensionName && extensions[extensionName]) {
106
+ continue;
107
+ }
108
+
109
+ // Fall back to remote import
110
+ try {
111
+ extensions[extensionName] = (
112
+ await import(
113
+ /* @vite-ignore */ `${ctx.lobbUrl}/api/extensions/${extensionName}/dashboard?v=${ctx.meta.extensions[extensionName]?.version}`
114
+ )
115
+ ).extension(getExtensionUtils());
116
+ } catch (error) {
117
+ console.warn(`Failed to load remote extension ${extensionName}`, error);
118
+ }
119
+ }
120
+
121
+ return extensions;
122
+ }
123
+
124
+ export function loadExtensionComponents(
125
+ name: string,
126
+ filterByExtensions?: string[],
127
+ ): any[] {
128
+ const components = [];
129
+ for (const [extensionName, extensionValue] of Object.entries(
130
+ ctx.extensions,
131
+ )) {
132
+ if (filterByExtensions && !filterByExtensions.includes(extensionName)) {
133
+ continue;
134
+ }
135
+ if (extensionValue.components) {
136
+ for (const [componentName, componentValue] of Object.entries(
137
+ extensionValue.components,
138
+ )) {
139
+ if (name.startsWith(componentName)) {
140
+ components.push(componentValue);
141
+ }
142
+ }
143
+ }
144
+ }
145
+ return components;
146
+ }
147
+
148
+ export async function executeExtensionsOnStartup() {
149
+ const extensionNames: string[] = Object.keys(ctx.extensions);
150
+ for (let index = 0; index < extensionNames.length; index++) {
151
+ const extensionName = extensionNames[index];
152
+ const extension = ctx.extensions[extensionName];
153
+ if (extension) {
154
+ if (extension.onStartup) {
155
+ await extension.onStartup(getExtensionUtils());
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ export function getDashboardNavs(): DashboardNavs {
162
+ let navs: DashboardNavs = {
163
+ top: [],
164
+ middle: [],
165
+ bottom: [],
166
+ };
167
+ const extensionNames: string[] = Object.keys(ctx.extensions);
168
+ for (let index = 0; index < extensionNames.length; index++) {
169
+ const extensionName = extensionNames[index];
170
+ const extension = ctx.extensions[extensionName];
171
+ if (extension) {
172
+ if (extension.dashboardNavs && extension.dashboardNavs.top && navs.top) {
173
+ navs.top = [...navs.top, ...extension.dashboardNavs.top];
174
+ }
175
+ if (
176
+ extension.dashboardNavs &&
177
+ extension.dashboardNavs.middle &&
178
+ navs.middle
179
+ ) {
180
+ navs.middle = [...navs.middle, ...extension.dashboardNavs.middle];
181
+ }
182
+ if (
183
+ extension.dashboardNavs &&
184
+ extension.dashboardNavs.bottom &&
185
+ navs.bottom
186
+ ) {
187
+ navs.bottom = [...navs.bottom, ...extension.dashboardNavs.bottom];
188
+ }
189
+ }
190
+ }
191
+ return navs;
192
+ }
@@ -0,0 +1,9 @@
1
+ export { default as Studio } from "./components/Studio.svelte";
2
+ export { Lobb } from "./Lobb";
3
+ export * from "./utils";
4
+ export * from "./eventSystem";
5
+ export { ctx, lobb } from "./store.svelte";
6
+ export type * from "./store.types";
7
+ export declare function createSet(lastNumber: number): Set<number>;
8
+ export declare function moveElement<T>(array: T[], fromIndex: number, toIndex: number): T[];
9
+ export declare function pxToRem(px: number): number;