@lobb-js/studio 0.28.5 → 0.29.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.
Files changed (92) hide show
  1. package/dist/components/Studio.svelte +7 -4
  2. package/dist/components/combobox.svelte +3 -3
  3. package/dist/components/confirmationDialog/confirmationDialog.svelte +1 -1
  4. package/dist/components/dataTable/dataTable.svelte +74 -82
  5. package/dist/components/dataTable/dataTable.svelte.d.ts +3 -19
  6. package/dist/components/dataTable/filter.svelte +1 -1
  7. package/dist/components/dataTable/filterButton.svelte +1 -1
  8. package/dist/components/dataTable/header.svelte +33 -54
  9. package/dist/components/dataTable/header.svelte.d.ts +3 -2
  10. package/dist/components/dataTable/sort.svelte +1 -1
  11. package/dist/components/dataTable/sortButton.svelte +2 -2
  12. package/dist/components/detailView/create/children.svelte +1 -1
  13. package/dist/components/detailView/create/createDetailView.svelte +77 -42
  14. package/dist/components/detailView/create/createDetailView.svelte.d.ts +2 -2
  15. package/dist/components/detailView/create/createDetailViewButton.svelte +2 -2
  16. package/dist/components/detailView/create/createDetailViewButton.svelte.d.ts +1 -1
  17. package/dist/components/detailView/create/createManyView.svelte +10 -6
  18. package/dist/components/detailView/fieldInput.svelte +1 -1
  19. package/dist/components/detailView/fieldInputReplacement.svelte +1 -1
  20. package/dist/components/detailView/update/detailViewChildren.svelte +15 -26
  21. package/dist/components/detailView/update/detailViewChildren.svelte.d.ts +3 -8
  22. package/dist/components/detailView/update/updateDetailView.svelte +85 -27
  23. package/dist/components/detailView/update/updateDetailView.svelte.d.ts +2 -2
  24. package/dist/components/detailView/update/updateDetailViewButton.svelte +3 -2
  25. package/dist/components/detailView/update/updateDetailViewButton.svelte.d.ts +1 -1
  26. package/dist/components/detailView/utils.d.ts +17 -0
  27. package/dist/components/miniSidebar.svelte +4 -4
  28. package/dist/components/rangeCalendarButton.svelte +3 -3
  29. package/dist/components/routes/collections/collection.svelte +3 -3
  30. package/dist/components/routes/collections/collections.svelte +2 -2
  31. package/dist/components/routes/data_model/dataModel.svelte +2 -2
  32. package/dist/components/routes/data_model/syncManager.svelte +4 -4
  33. package/dist/components/routes/extensions/extension.svelte +1 -1
  34. package/dist/components/routes/home.svelte +1 -1
  35. package/dist/components/routes/workflows/workflows.svelte +5 -5
  36. package/dist/components/selectRecord.svelte +2 -21
  37. package/dist/components/setServerPage.svelte +1 -1
  38. package/dist/components/ui/alert-dialog/alert-dialog-action.svelte +1 -1
  39. package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte +1 -1
  40. package/dist/components/ui/command/command-dialog.svelte +1 -1
  41. package/dist/components/ui/range-calendar/range-calendar-day.svelte +1 -1
  42. package/dist/components/ui/range-calendar/range-calendar-next-button.svelte +1 -1
  43. package/dist/components/ui/range-calendar/range-calendar-prev-button.svelte +1 -1
  44. package/dist/components/ui/select/select-separator.svelte +1 -1
  45. package/dist/components/workflowEditor.svelte +3 -3
  46. package/dist/store.types.d.ts +1 -1
  47. package/package.json +2 -2
  48. package/src/lib/components/Studio.svelte +7 -4
  49. package/src/lib/components/combobox.svelte +3 -3
  50. package/src/lib/components/confirmationDialog/confirmationDialog.svelte +1 -1
  51. package/src/lib/components/dataTable/dataTable.svelte +74 -82
  52. package/src/lib/components/dataTable/filter.svelte +1 -1
  53. package/src/lib/components/dataTable/filterButton.svelte +1 -1
  54. package/src/lib/components/dataTable/header.svelte +33 -54
  55. package/src/lib/components/dataTable/sort.svelte +1 -1
  56. package/src/lib/components/dataTable/sortButton.svelte +2 -2
  57. package/src/lib/components/detailView/create/children.svelte +1 -1
  58. package/src/lib/components/detailView/create/createDetailView.svelte +77 -42
  59. package/src/lib/components/detailView/create/createDetailViewButton.svelte +2 -2
  60. package/src/lib/components/detailView/create/createManyView.svelte +10 -6
  61. package/src/lib/components/detailView/fieldInput.svelte +1 -1
  62. package/src/lib/components/detailView/fieldInputReplacement.svelte +1 -1
  63. package/src/lib/components/detailView/update/detailViewChildren.svelte +15 -26
  64. package/src/lib/components/detailView/update/updateDetailView.svelte +85 -27
  65. package/src/lib/components/detailView/update/updateDetailViewButton.svelte +3 -2
  66. package/src/lib/components/detailView/utils.ts +13 -0
  67. package/src/lib/components/miniSidebar.svelte +4 -4
  68. package/src/lib/components/rangeCalendarButton.svelte +3 -3
  69. package/src/lib/components/routes/collections/collection.svelte +3 -3
  70. package/src/lib/components/routes/collections/collections.svelte +2 -2
  71. package/src/lib/components/routes/data_model/dataModel.svelte +2 -2
  72. package/src/lib/components/routes/data_model/syncManager.svelte +4 -4
  73. package/src/lib/components/routes/extensions/extension.svelte +1 -1
  74. package/src/lib/components/routes/home.svelte +1 -1
  75. package/src/lib/components/routes/workflows/workflows.svelte +5 -5
  76. package/src/lib/components/selectRecord.svelte +2 -21
  77. package/src/lib/components/setServerPage.svelte +1 -1
  78. package/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +1 -1
  79. package/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +1 -1
  80. package/src/lib/components/ui/command/command-dialog.svelte +1 -1
  81. package/src/lib/components/ui/range-calendar/range-calendar-day.svelte +1 -1
  82. package/src/lib/components/ui/range-calendar/range-calendar-next-button.svelte +1 -1
  83. package/src/lib/components/ui/range-calendar/range-calendar-prev-button.svelte +1 -1
  84. package/src/lib/components/ui/select/select-separator.svelte +1 -1
  85. package/src/lib/components/workflowEditor.svelte +3 -3
  86. package/src/lib/store.types.ts +1 -1
  87. package/vite-plugins/index.js +2 -4
  88. package/vite-plugins/lobb-extensions.js +12 -0
  89. package/vite-plugins/utils.js +15 -0
  90. package/vite-plugins/workspace-fs-allow.js +33 -0
  91. package/vite-plugins/contextual-lib-alias.js +0 -67
  92. package/vite-plugins/workspace-optimize.js +0 -106
@@ -9,31 +9,32 @@
9
9
  recordId: string;
10
10
  values?: Record<string, any>;
11
11
  showRelatedRecords?: boolean;
12
- rollback?: boolean;
13
12
  submitButton?: SubmitButton;
14
13
  title?: Snippet<[string]>;
15
14
  onSuccessfullSave?: (entry: any) => Promise<void>;
16
15
  onCancel?: () => Promise<void>;
16
+ changes?: import("../utils").Changes | undefined;
17
17
  }
18
18
  </script>
19
19
 
20
20
  <script lang="ts">
21
21
  import { ArrowLeft, Pencil, X } from "lucide-svelte";
22
- import Button from "../../../components/ui/button/button.svelte";
23
- import { fade, fly } from "svelte/transition";
22
+ import Button from "../../ui/button/button.svelte";
24
23
  import { getStudioContext } from "../../../context";
25
24
  import { toast } from "svelte-sonner";
26
25
  import ExtensionsComponents from "../../extensionsComponents.svelte";
27
26
  import { getExtensionUtils } from "../../../extensions/extensionUtils";
27
+ import { untrack } from "svelte";
28
28
 
29
29
  const { lobb, ctx } = getStudioContext();
30
- import { calculateDrawerWidth, getChangedProperties } from "../../../utils";
30
+ import { getChangedProperties } from "../../../utils";
31
31
  import { getField, getFieldIcon } from "../../dataTable/utils";
32
- import DetailViewChildren from "../update/detailViewChildren.svelte";
32
+ import DetailViewChildren from "./detailViewChildren.svelte";
33
33
  import type { Snippet } from "svelte";
34
34
  import { getDefaultEntry } from "../utils";
35
+ import type { Changes, ChildrenChanges } from "../utils";
35
36
  import FieldInput from "../fieldInput.svelte";
36
- import Drawer from "../../../components/drawer.svelte";
37
+ import Drawer from "../../drawer.svelte";
37
38
 
38
39
  let {
39
40
  collectionName,
@@ -44,29 +45,74 @@
44
45
  title,
45
46
  submitButton,
46
47
  recordId,
48
+ changes = $bindable<Changes | undefined>(undefined),
47
49
  }: UpdateDetailViewProp = $props();
48
50
 
51
+ // Internal changes — used when not in recording mode, passed down to children
52
+ let _changes = $state<Changes>({ data: {}, children: {} });
53
+
54
+ // Recording mode = changes was passed from a parent component
55
+ const isRecordingMode = $derived(changes !== undefined);
56
+
49
57
  const fieldNames = Object.keys(ctx.meta.collections[collectionName].fields);
50
58
  let entry: Record<string, any> = $state(
51
59
  getDefaultEntry(ctx, fieldNames, collectionName, values),
52
60
  );
53
61
  const initialEntry = $state.snapshot(entry);
54
- let localEntry = $derived(
55
- getChangedProperties(initialEntry, $state.snapshot(entry)),
56
- );
57
62
  let fieldsErrors: Record<string, any> = $state({});
58
- let pendingChildren = $state<Record<string, any>>({});
63
+
64
+ // Tracks field edits into the active changes object.
65
+ // Child ops (create/link/unlink/delete) are written directly by DataTable into changes.children.
66
+ $effect(() => {
67
+ const currentEntrySnap = $state.snapshot(entry);
68
+
69
+ untrack(() => {
70
+ const target = changes ?? _changes;
71
+ target.data = getChangedProperties(initialEntry, currentEntrySnap);
72
+
73
+ if (!isRecordingMode) {
74
+ console.log(`[${collectionName}] changes:`, $state.snapshot(target));
75
+ }
76
+ });
77
+ });
78
+
79
+ function buildApiChildren(children: Record<string, ChildrenChanges>): Record<string, any> | undefined {
80
+ const result: Record<string, any> = {};
81
+ for (const [collection, ops] of Object.entries(children)) {
82
+ const hasOps = ops.created.length || ops.deleted.length || ops.linked.length || ops.unlinked.length;
83
+ if (!hasOps) continue;
84
+ result[collection] = {
85
+ ...(ops.created.length ? { create: ops.created.map((c) => c.data) } : {}),
86
+ ...(ops.deleted.length ? { delete: ops.deleted.map((r) => r.id) } : {}),
87
+ ...(ops.linked.length ? { link: ops.linked.map((r) => r.id) } : {}),
88
+ ...(ops.unlinked.length ? { unlink: ops.unlinked.map((r) => r.id) } : {}),
89
+ };
90
+ }
91
+ return Object.keys(result).length ? result : undefined;
92
+ }
93
+
94
+ function handleCancel() {
95
+ if (changes !== undefined) {
96
+ changes.data = {};
97
+ changes.children = {};
98
+ }
99
+ onCancel?.();
100
+ }
59
101
 
60
102
  async function handleSave() {
61
- delete localEntry.id;
103
+ const target = changes ?? _changes;
104
+ const snap = $state.snapshot(target);
105
+ const { id: _id, ...data } = snap.data;
106
+ const children = buildApiChildren(snap.children);
62
107
 
63
- const children = Object.keys(pendingChildren).length ? pendingChildren : undefined;
64
- const response = await lobb.updateOne(
65
- collectionName,
66
- recordId,
67
- localEntry,
68
- children,
69
- );
108
+ const response = await lobb.updateOne(collectionName, recordId, data, children, isRecordingMode);
109
+
110
+ if (response.status === 204) {
111
+ if (onSuccessfullSave) await onSuccessfullSave(snap);
112
+ toast.success(`The record was successfully updated`);
113
+ onCancel?.();
114
+ return;
115
+ }
70
116
 
71
117
  if (!response.bodyUsed) {
72
118
  const result = await response.json();
@@ -80,22 +126,34 @@
80
126
  }
81
127
  }
82
128
 
83
- // close detailView side bar
84
- if (onSuccessfullSave) {
85
- await onSuccessfullSave(localEntry);
129
+ // Real mode: also fire separate update requests for edited children
130
+ if (!isRecordingMode) {
131
+ for (const [collection, ops] of Object.entries(snap.children)) {
132
+ for (const updated of ops.updated) {
133
+ await lobb.updateOne(collection, String(updated.id), updated.data);
134
+ }
135
+ }
86
136
  }
87
137
 
138
+ if (onSuccessfullSave) await onSuccessfullSave(snap);
88
139
  toast.success(`The record was successfully updated`);
89
-
90
140
  onCancel?.();
91
141
  }
142
+
143
+ const activeChanges = $derived(changes ?? _changes);
144
+ const hasChanges = $derived(
145
+ Object.keys(activeChanges.data).length > 0 ||
146
+ Object.values(activeChanges.children).some(
147
+ (c) => c.created.length || c.updated.length || c.deleted.length || c.linked.length || c.unlinked.length,
148
+ ),
149
+ );
92
150
  </script>
93
151
 
94
- <Drawer onHide={onCancel}>
152
+ <Drawer onHide={handleCancel}>
95
153
  <div class="flex h-12 items-center gap-4 border-b px-4">
96
154
  <Button
97
155
  variant="outline"
98
- onclick={onCancel}
156
+ onclick={handleCancel}
99
157
  class=" h-8 w-8 rounded-full text-xs font-normal"
100
158
  Icon={ArrowLeft}
101
159
  ></Button>
@@ -145,14 +203,14 @@
145
203
  {/each}
146
204
  </div>
147
205
  {#if showRelatedRecords}
148
- <DetailViewChildren {collectionName} {entry} bind:pendingChildren />
206
+ <DetailViewChildren {collectionName} {entry} {activeChanges} />
149
207
  {/if}
150
208
  </div>
151
209
  <div class="flex h-12 items-center justify-end gap-2 border-t px-4">
152
210
  <div class="flex gap-3">
153
211
  <Button
154
212
  variant="outline"
155
- onclick={onCancel}
213
+ onclick={handleCancel}
156
214
  class="h-7 px-3 text-xs font-normal"
157
215
  Icon={X}
158
216
  >
@@ -163,7 +221,7 @@
163
221
  class="h-7 px-3 text-xs font-normal"
164
222
  Icon={submitButton?.icon ? submitButton.icon : Pencil}
165
223
  onclick={handleSave}
166
- disabled={!Object.keys(localEntry).length && !Object.keys(pendingChildren).length}
224
+ disabled={!hasChanges}
167
225
  >
168
226
  {submitButton?.text ? submitButton.text : "Update"}
169
227
  </Button>
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { UpdateDetailViewProp } from "./updateDetailView.svelte";
3
- import type { ButtonProps } from "../../../components/ui/button/button.svelte";
4
- import Button from "../../../components/ui/button/button.svelte";
3
+ import type { ButtonProps } from "../../ui/button/button.svelte";
4
+ import Button from "../../ui/button/button.svelte";
5
5
  import UpdateDetailView from "./updateDetailView.svelte";
6
6
  import { getStudioContext } from "../../../context";
7
7
 
@@ -46,6 +46,7 @@
46
46
  <UpdateDetailView
47
47
  {...props}
48
48
  {values}
49
+ changes={props.changes}
49
50
  onCancel={async () => {
50
51
  open = false;
51
52
  values = undefined;
@@ -3,6 +3,19 @@ import type { CTX } from "../../store.types";
3
3
  import { getField } from "../dataTable/utils";
4
4
  import type { DetailFormField } from "./detailViewForm.svelte";
5
5
 
6
+ export type ChildrenChanges = {
7
+ created: Array<{ data: Record<string, any> }>;
8
+ updated: Array<{ id: string | number; data: Record<string, any>; children: Record<string, ChildrenChanges> }>;
9
+ deleted: Array<Record<string, any>>;
10
+ linked: Array<Record<string, any>>;
11
+ unlinked: Array<Record<string, any>>;
12
+ };
13
+
14
+ export type Changes = {
15
+ data: Record<string, any>;
16
+ children: Record<string, ChildrenChanges>;
17
+ };
18
+
6
19
  export function getDefaultEntry(ctx: CTX, fieldNames: string[], collectionName: string, values?: Record<string, any>) {
7
20
  return Object.fromEntries(
8
21
  fieldNames.map((fieldName) => {
@@ -12,10 +12,10 @@
12
12
 
13
13
  <script lang="ts">
14
14
  import { House, Layers, Library, Workflow, X } from "lucide-svelte";
15
- import Button from "../components/ui/button/button.svelte";
16
- import Separator from "../components/ui/separator/separator.svelte";
17
- import * as Tooltip from "../components/ui/tooltip";
18
- import * as Accordion from "../components/ui/accordion/index.js";
15
+ import Button from "./ui/button/button.svelte";
16
+ import Separator from "./ui/separator/separator.svelte";
17
+ import * as Tooltip from "./ui/tooltip";
18
+ import * as Accordion from "./ui/accordion/index.js";
19
19
 
20
20
  import { getStudioContext } from "../context";
21
21
  import { getDashboardNavs } from "../extensions/extensionUtils";
@@ -11,9 +11,9 @@
11
11
  today,
12
12
  } from "@internationalized/date";
13
13
  import { cn } from "../utils.js";
14
- import { buttonVariants } from "../components/ui/button/index.js";
15
- import { RangeCalendar } from "../components/ui/range-calendar/index.js";
16
- import * as Popover from "../components/ui/popover/index.js";
14
+ import { buttonVariants } from "./ui/button/index.js";
15
+ import { RangeCalendar } from "./ui/range-calendar/index.js";
16
+ import * as Popover from "./ui/popover/index.js";
17
17
  import Input from "./ui/input/input.svelte";
18
18
 
19
19
  interface Props {
@@ -1,9 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { CircleSlash2, Zap } from "lucide-svelte";
3
- import DataTable from "../../../components/dataTable/dataTable.svelte";
4
- import SidebarTrigger from "../../../components/sidebar/sidebarTrigger.svelte";
3
+ import DataTable from "../../dataTable/dataTable.svelte";
4
+ import SidebarTrigger from "../../sidebar/sidebarTrigger.svelte";
5
5
  import { getStudioContext } from "../../../context";
6
- import Singletone from "../../../components/singletone.svelte";
6
+ import Singletone from "../../singletone.svelte";
7
7
 
8
8
  const { ctx } = getStudioContext();
9
9
 
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
- import type { SideBarData, SideBarNode } from "../../../components/sidebar/sidebarElements.svelte";
3
- import Sidebar from "../../../components/sidebar/sidebar.svelte";
2
+ import type { SideBarData, SideBarNode } from "../../sidebar/sidebarElements.svelte";
3
+ import Sidebar from "../../sidebar/sidebar.svelte";
4
4
  import { getStudioContext } from "../../../context";
5
5
  import Collection from "./collection.svelte";
6
6
 
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
2
  import { SvelteFlowProvider } from "@xyflow/svelte";
3
3
  import Flow from "./flow.svelte";
4
- import Sidebar from "../../../components/sidebar/sidebar.svelte";
4
+ import Sidebar from "../../sidebar/sidebar.svelte";
5
5
  import { location } from "@wjfe/n-savant";
6
6
  import SyncManager from "./syncManager.svelte";
7
- import SidebarTrigger from "../../../components/sidebar/sidebarTrigger.svelte";
7
+ import SidebarTrigger from "../../sidebar/sidebarTrigger.svelte";
8
8
 
9
9
  const currentPage = $derived(location.url.pathname.replace("/studio", "").split("/")[2]);
10
10
  </script>
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
- import DiffViewer from "../../../components/diffViewer.svelte";
2
+ import DiffViewer from "../../diffViewer.svelte";
3
3
  import { getStudioContext } from "../../../context";
4
4
 
5
5
  const { lobb, ctx } = getStudioContext();
6
6
  import { onMount } from "svelte";
7
7
  import stringify from "json-stable-stringify";
8
- import CodeEditor from "../../../components/codeEditor.svelte";
9
- import Table from "../../../components/dataTable/table.svelte";
10
- import Button from "../../../components/ui/button/button.svelte";
8
+ import CodeEditor from "../../codeEditor.svelte";
9
+ import Table from "../../dataTable/table.svelte";
10
+ import Button from "../../ui/button/button.svelte";
11
11
  import { LoaderCircle, SendHorizontal } from "lucide-svelte";
12
12
 
13
13
  let configSchema: string = $state("");
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import ExtensionsComponents from "../../../components/extensionsComponents.svelte";
2
+ import ExtensionsComponents from "../../extensionsComponents.svelte";
3
3
  import { getExtensionUtils } from "../../../extensions/extensionUtils";
4
4
  import { getStudioContext } from "../../../context";
5
5
 
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import Button from "../../components/ui/button/button.svelte";
2
+ import Button from "../ui/button/button.svelte";
3
3
  import { location } from "@wjfe/n-savant";
4
4
  import { ArrowRight } from "lucide-svelte";
5
5
  import HomeFooter from "./homeFooter.svelte";
@@ -1,18 +1,18 @@
1
1
  <script lang="ts">
2
- import type { SideBarData, SideBarNode } from "../../../components/sidebar/sidebarElements.svelte";
2
+ import type { SideBarData, SideBarNode } from "../../sidebar/sidebarElements.svelte";
3
3
  import WorkflowEditor, {
4
4
  type WorkflowEntry,
5
- } from "../../../components/workflowEditor.svelte";
5
+ } from "../../workflowEditor.svelte";
6
6
  import { getStudioContext } from "../../../context";
7
7
 
8
8
  const { lobb, ctx } = getStudioContext();
9
- import Sidebar from "../../../components/sidebar/sidebar.svelte";
10
- import Button from "../../../components/ui/button/button.svelte";
9
+ import Sidebar from "../../sidebar/sidebar.svelte";
10
+ import Button from "../../ui/button/button.svelte";
11
11
  import { location } from "@wjfe/n-savant";
12
12
  import { CircleSlash2, Plus, Trash2 } from "lucide-svelte";
13
13
  import { onMount } from "svelte";
14
14
  import { showDialog } from "../../../actions";
15
- import SidebarTrigger from "../../../components/sidebar/sidebarTrigger.svelte";
15
+ import SidebarTrigger from "../../sidebar/sidebarTrigger.svelte";
16
16
 
17
17
  let { workflowName } = $props();
18
18
 
@@ -3,7 +3,6 @@
3
3
  import Button, { type ButtonProps } from "./ui/button/button.svelte";
4
4
  import DataTable from "./dataTable/dataTable.svelte";
5
5
  import { getCollectionPrimaryField } from "./dataTable/utils";
6
- import { emitEvent } from "../eventSystem";
7
6
  import { getStudioContext } from "../context";
8
7
  import Drawer from "./drawer.svelte";
9
8
 
@@ -36,26 +35,8 @@
36
35
 
37
36
  let openDrawer = $state(false);
38
37
 
39
- async function handleButtonClick() {
40
- try {
41
- const eventResult = await emitEvent(
42
- { lobb, ctx },
43
- "studio.collections.preForeignKeySelect",
44
- {
45
- parentCollectionName,
46
- collectionName,
47
- fieldName,
48
- entry,
49
- },
50
- );
51
- if (eventResult.filter) {
52
- additionalFilter = eventResult.filter;
53
- }
54
-
55
- openDrawer = true;
56
- } catch (error) {
57
- console.error(error);
58
- }
38
+ function handleButtonClick() {
39
+ openDrawer = true;
59
40
  }
60
41
 
61
42
  async function onSelectHandler(entry: any) {
@@ -2,7 +2,7 @@
2
2
  import { toast } from "svelte-sonner";
3
3
  import Button from "./ui/button/button.svelte";
4
4
  import { getStudioContext } from "../context";
5
- import { Input } from "../components/ui/input";
5
+ import { Input } from "./ui/input";
6
6
 
7
7
  const { ctx } = getStudioContext();
8
8
 
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
- import { buttonVariants } from "../../../components/ui/button/index.js";
3
+ import { buttonVariants } from "../button/index.js";
4
4
  import { cn } from "../../../utils.js";
5
5
 
6
6
  let {
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
- import { buttonVariants } from "../../../components/ui/button/index.js";
3
+ import { buttonVariants } from "../button/index.js";
4
4
  import { cn } from "../../../utils.js";
5
5
 
6
6
  let {
@@ -6,7 +6,7 @@
6
6
  } from "bits-ui";
7
7
  import type { Snippet } from "svelte";
8
8
  import Command from "./command.svelte";
9
- import * as Dialog from "../../../components/ui/dialog/index.js";
9
+ import * as Dialog from "../dialog/index.js";
10
10
 
11
11
  let {
12
12
  open = $bindable(false),
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { RangeCalendar as RangeCalendarPrimitive } from "bits-ui";
3
- import { buttonVariants } from "../../../components/ui/button/index.js";
3
+ import { buttonVariants } from "../button/index.js";
4
4
  import { cn } from "../../../utils.js";
5
5
 
6
6
  let {
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { RangeCalendar as RangeCalendarPrimitive } from "bits-ui";
3
3
  import ChevronRight from "@lucide/svelte/icons/chevron-right";
4
- import { buttonVariants } from "../../../components/ui/button/index.js";
4
+ import { buttonVariants } from "../button/index.js";
5
5
  import { cn } from "../../../utils.js";
6
6
  let {
7
7
  ref = $bindable(null),
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { RangeCalendar as RangeCalendarPrimitive } from "bits-ui";
3
3
  import ChevronLeft from "@lucide/svelte/icons/chevron-left";
4
- import { buttonVariants } from "../../../components/ui/button/index.js";
4
+ import { buttonVariants } from "../button/index.js";
5
5
  import { cn } from "../../../utils.js";
6
6
  let {
7
7
  ref = $bindable(null),
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Separator as SeparatorPrimitive } from "bits-ui";
3
- import { Separator } from "../../../components/ui/separator/index.js";
3
+ import { Separator } from "../separator/index.js";
4
4
  import { cn } from "../../../utils.js";
5
5
 
6
6
  let {
@@ -12,11 +12,11 @@
12
12
 
13
13
  <script lang="ts">
14
14
  import { getStudioContext } from "../context";
15
- import CodeEditor from "../components/codeEditor.svelte";
15
+ import CodeEditor from "./codeEditor.svelte";
16
16
 
17
17
  const { lobb, ctx } = getStudioContext();
18
- import Button from "../components/ui/button/button.svelte";
19
- import Input from "../components/ui/input/input.svelte";
18
+ import Button from "./ui/button/button.svelte";
19
+ import Input from "./ui/input/input.svelte";
20
20
  import { location } from "@wjfe/n-savant";
21
21
  import { Edit, Plus } from "lucide-svelte";
22
22
  import { toast } from "svelte-sonner";
@@ -1,4 +1,4 @@
1
- import type { Extension } from "../extensions/extension.types";
1
+ import type { Extension } from "./extensions/extension.types";
2
2
 
3
3
  interface CollectionTab {
4
4
  id?: string;
@@ -1,12 +1,10 @@
1
- import { contextualLibAlias } from "./contextual-lib-alias.js";
2
- import { lobbWorkspaceOptimize } from "./workspace-optimize.js";
1
+ import { lobbWorkspaceFsAllow } from "./workspace-fs-allow.js";
3
2
  import { lobbExtensionsPlugin } from "./lobb-extensions.js";
4
3
  import { lobbProxyPlugin } from "./lobb-proxy.js";
5
4
 
6
5
  export function lobbStudioPlugins() {
7
6
  return [
8
- contextualLibAlias(),
9
- lobbWorkspaceOptimize(),
7
+ lobbWorkspaceFsAllow(),
10
8
  lobbExtensionsPlugin(),
11
9
  lobbProxyPlugin(),
12
10
  ];
@@ -13,6 +13,18 @@ export function lobbExtensionsPlugin() {
13
13
 
14
14
  return {
15
15
  name: "lobb-studio-extensions",
16
+ // The dep optimizer's bundler doesn't run our resolveId/load hooks, so any
17
+ // package whose prebundled output references this virtual module would
18
+ // crash with "Failed to resolve". Excluding the bare virtual ID tells the
19
+ // optimizer to leave the import statement untouched, so the browser asks
20
+ // the dev server for it at runtime — where the hooks below actually fire.
21
+ config() {
22
+ return {
23
+ optimizeDeps: {
24
+ exclude: [virtualModuleId],
25
+ },
26
+ };
27
+ },
16
28
  resolveId(id) {
17
29
  if (id === virtualModuleId) return resolvedVirtualModuleId;
18
30
  },
@@ -0,0 +1,15 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ export function getMonorepoRoot() {
5
+ let dir = process.cwd();
6
+ while (true) {
7
+ try {
8
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
9
+ if (pkg?.workspaces) return dir;
10
+ } catch { /* no package.json here, keep walking */ }
11
+ const parent = dirname(dir);
12
+ if (parent === dir) return null;
13
+ dir = parent;
14
+ }
15
+ }
@@ -0,0 +1,33 @@
1
+ import { getMonorepoRoot } from "./utils.js";
2
+
3
+ /**
4
+ * In monorepo dev, workspace packages are symlinked into node_modules.
5
+ * Vite's default `server.fs.allow` only covers the project root, so requests
6
+ * for files inside those symlinked packages (source maps, HMR updates, etc.)
7
+ * are denied. This plugin walks up from cwd to find the monorepo root and
8
+ * allows Vite to serve from there.
9
+ *
10
+ * For standalone npm-installed users there's no workspaces field above them,
11
+ * the plugin does nothing, and the config has no effect.
12
+ *
13
+ * @returns {import('vite').Plugin}
14
+ */
15
+ export function lobbWorkspaceFsAllow() {
16
+ return {
17
+ name: "lobb-workspace-fs-allow",
18
+ config(_, { command }) {
19
+ if (command !== "serve") return;
20
+
21
+ const monorepoRoot = getMonorepoRoot();
22
+ if (!monorepoRoot) return;
23
+
24
+ return {
25
+ server: {
26
+ fs: {
27
+ allow: [monorepoRoot],
28
+ },
29
+ },
30
+ };
31
+ },
32
+ };
33
+ }