@antelopejs/dms 0.4.8 → 0.5.1

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 (82) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/hooks/invite-extensions.js +0 -2
  3. package/dist/hooks/invite-extensions.js.map +1 -1
  4. package/dist/implementations/dms/page.js +6 -7
  5. package/dist/implementations/dms/page.js.map +1 -1
  6. package/dist/implementations/dms/realtime.d.ts +2 -2
  7. package/dist/implementations/dms/realtime.js +9 -3
  8. package/dist/implementations/dms/realtime.js.map +1 -1
  9. package/dist/implementations/dms-base/table-view.d.ts +5 -0
  10. package/dist/implementations/dms-base/table-view.js +7 -1
  11. package/dist/implementations/dms-base/table-view.js.map +1 -1
  12. package/dist/pages/settings/users/member-invite-form.d.ts +5 -0
  13. package/dist/pages/settings/users/member-invite-form.js +11 -2
  14. package/dist/pages/settings/users/member-invite-form.js.map +1 -1
  15. package/dist/pages/settings/users/members.d.ts +2 -0
  16. package/dist/pages/settings/users/members.js +11 -0
  17. package/dist/pages/settings/users/members.js.map +1 -1
  18. package/dist/realtime/index.js +0 -2
  19. package/dist/realtime/index.js.map +1 -1
  20. package/dist/realtime/registry.d.ts +1 -0
  21. package/dist/realtime/registry.js +9 -0
  22. package/dist/realtime/registry.js.map +1 -1
  23. package/dist/realtime/table-view.d.ts +3 -0
  24. package/dist/realtime/table-view.js +25 -0
  25. package/dist/realtime/table-view.js.map +1 -0
  26. package/dist/test/antelope.test.js +6 -0
  27. package/dist/test/antelope.test.js.map +1 -1
  28. package/dist/test/helpers/reload-host.d.ts +9 -0
  29. package/dist/test/helpers/reload-host.js +21 -0
  30. package/dist/test/helpers/reload-host.js.map +1 -0
  31. package/dist/test/integration/invite-resolution.test.js +0 -2
  32. package/dist/test/integration/invite-resolution.test.js.map +1 -1
  33. package/dist/test/reload-host/index.d.ts +2 -0
  34. package/dist/test/reload-host/index.js +32 -0
  35. package/dist/test/reload-host/index.js.map +1 -0
  36. package/dist/test/reload-host/package.json +8 -0
  37. package/dist/test/unit/frontend-renderer-range.test.d.ts +1 -0
  38. package/dist/test/unit/frontend-renderer-range.test.js +45 -0
  39. package/dist/test/unit/frontend-renderer-range.test.js.map +1 -0
  40. package/dist/test/unit/interfaces/dms/invite-extension.test.js +22 -24
  41. package/dist/test/unit/interfaces/dms/invite-extension.test.js.map +1 -1
  42. package/dist/test/unit/interfaces/dms/module-reload-registrations.test.d.ts +1 -0
  43. package/dist/test/unit/interfaces/dms/module-reload-registrations.test.js +51 -0
  44. package/dist/test/unit/interfaces/dms/module-reload-registrations.test.js.map +1 -0
  45. package/dist/test/unit/interfaces/dms/page-topics.test.d.ts +1 -0
  46. package/dist/test/unit/interfaces/dms/page-topics.test.js +194 -0
  47. package/dist/test/unit/interfaces/dms/page-topics.test.js.map +1 -0
  48. package/dist/test/unit/interfaces/dms-base/layouts.test.js +16 -0
  49. package/dist/test/unit/interfaces/dms-base/layouts.test.js.map +1 -1
  50. package/dist/test/unit/interfaces/dms-base/table-view-evaluation-order.fixture.d.ts +5 -0
  51. package/dist/test/unit/interfaces/dms-base/table-view-evaluation-order.fixture.js +82 -0
  52. package/dist/test/unit/interfaces/dms-base/table-view-evaluation-order.fixture.js.map +1 -0
  53. package/dist/test/unit/interfaces/dms-base/table-view-evaluation-order.test.d.ts +1 -0
  54. package/dist/test/unit/interfaces/dms-base/table-view-evaluation-order.test.js +24 -0
  55. package/dist/test/unit/interfaces/dms-base/table-view-evaluation-order.test.js.map +1 -0
  56. package/dist/test/unit/interfaces/dms-base/table-view-get-guard.test.js +10 -4
  57. package/dist/test/unit/interfaces/dms-base/table-view-get-guard.test.js.map +1 -1
  58. package/dist/test/unit/interfaces/dms-base/table-view-realtime.test.d.ts +1 -0
  59. package/dist/test/unit/interfaces/dms-base/table-view-realtime.test.js +139 -0
  60. package/dist/test/unit/interfaces/dms-base/table-view-realtime.test.js.map +1 -0
  61. package/dist/test/unit/pages/settings/invite-availability.test.d.ts +1 -0
  62. package/dist/test/unit/pages/settings/invite-availability.test.js +112 -0
  63. package/dist/test/unit/pages/settings/invite-availability.test.js.map +1 -0
  64. package/dist/test/unit/utils/owned-registry.test.d.ts +1 -0
  65. package/dist/test/unit/utils/owned-registry.test.js +61 -0
  66. package/dist/test/unit/utils/owned-registry.test.js.map +1 -0
  67. package/dist/validation/auth.schema.d.ts +2 -2
  68. package/frontend-vue/layers/dms-layout/app/composables/layout/usePageFillHeight.ts +37 -0
  69. package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +9 -0
  70. package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +16 -1
  71. package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +18 -8
  72. package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +12 -0
  73. package/frontend-vue/layers/dms-ui/app/composables/table-view/types/custom-button.ts +4 -0
  74. package/frontend-vue/package.json +4 -1
  75. package/frontend-vue/pnpm-lock.yaml +8 -8
  76. package/frontend-vue/tests/page-fill-height.test.ts +352 -0
  77. package/package.json +6 -6
  78. package/skills/dms-module/REFERENCE.md +2 -1
  79. package/skills/dms-module/SKILL.md +5 -0
  80. package/dist/realtime/tableview-bridge.d.ts +0 -1
  81. package/dist/realtime/tableview-bridge.js +0 -38
  82. package/dist/realtime/tableview-bridge.js.map +0 -1
@@ -0,0 +1,352 @@
1
+ // @vitest-environment jsdom
2
+ import {
3
+ computed,
4
+ createApp,
5
+ createSSRApp,
6
+ h,
7
+ inject,
8
+ nextTick,
9
+ onMounted,
10
+ onUnmounted,
11
+ provide,
12
+ reactive,
13
+ ref,
14
+ Suspense,
15
+ toRef,
16
+ watch,
17
+ type App,
18
+ type Component,
19
+ type FunctionalComponent,
20
+ } from "vue";
21
+ import { renderToString } from "vue/server-renderer";
22
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
23
+ import DefaultLayout from "../layers/dms-layout/app/custom-layouts/DefaultLayout.vue";
24
+ import CatchAllPage from "../layers/dms-layout/app/pages/[...slug].vue";
25
+ import {
26
+ PAGE_FILL_HEIGHT_CLASSES,
27
+ providePageFillHeight,
28
+ usePageFillHeight,
29
+ } from "../layers/dms-layout/app/composables/layout/usePageFillHeight";
30
+
31
+ vi.mock(
32
+ "../layers/dms-layout/app/build/components/layout/DashboardSidebar.vue",
33
+ () => ({ default: () => null }),
34
+ );
35
+ vi.mock(
36
+ "../layers/dms-layout/app/build/components/layout/DashboardHeader.vue",
37
+ () => ({ default: () => null }),
38
+ );
39
+ vi.mock(
40
+ "../layers/dms-layout/app/build/components/layout/DashboardBanners.vue",
41
+ () => ({ default: () => null }),
42
+ );
43
+
44
+ interface PageLayoutFixture {
45
+ components: Record<string, { componentName: string }>;
46
+ }
47
+
48
+ const route = reactive({ path: "/tools/explorer", query: {} });
49
+ const pageLayout = ref<PageLayoutFixture | null>(null);
50
+
51
+ // The markup `DefaultLayout` and `pages/[...slug].vue` rendered for a
52
+ // two-component page before `fillHeight` existed, with the stubs below.
53
+ const FLOW_PAGE_MARKUP =
54
+ "<div data-dms-persistent-shell data-group><!---->" +
55
+ "<div data-panel><!--[--><!----><!----><!--]-->" +
56
+ "<div data-body>" +
57
+ '<div class="w-full max-w-none" data-dms-page-region data-dms-page-content><!--[-->' +
58
+ '<section class="flex gap-4 items-start pt-6 pb-7">' +
59
+ '<div class="rounded-lg bg-primary/10 shrink-0 ring ring-primary/20 flex items-center justify-center size-12"><i class="text-primary"></i></div>' +
60
+ '<div class="flex-1 min-w-0">' +
61
+ '<h1 class="text-highlighted text-[22px] font-semibold leading-tight tracking-tight"><!--[-->Explorer<!--]--></h1><!--v-if--></div><!--[--><!--]--></section><!--[-->' +
62
+ '<div class="dms-page-stack space-y-6">' +
63
+ '<div class="">' +
64
+ '<section data-component="stats" page-id="tools.explorer"></section></div>' +
65
+ '<div class="">' +
66
+ '<section data-component="explorer" page-id="tools.explorer"></section></div></div><!--]--><!--]--></div></div><!--[--><!----><!--]--></div></div>';
67
+
68
+ function withComponents(...ids: string[]): PageLayoutFixture {
69
+ return {
70
+ components: Object.fromEntries(
71
+ ids.map((id) => [id, { componentName: `tool-${id}` }]),
72
+ ),
73
+ };
74
+ }
75
+
76
+ // Functional stubs hand non-class attributes on only when told to: these two
77
+ // spread them, so the markers the layout sets stay in the markup.
78
+ const Group: FunctionalComponent = (_, { attrs, slots }) =>
79
+ h("div", { ...attrs, "data-group": "" }, slots.default?.());
80
+ Group.inheritAttrs = false;
81
+
82
+ const Panel: FunctionalComponent = (_, { slots }) =>
83
+ h("div", { "data-panel": "" }, [
84
+ slots.header?.(),
85
+ h("div", { "data-body": "" }, slots.body?.()),
86
+ slots.footer?.(),
87
+ ]);
88
+
89
+ // Nuxt UI merges its container classes with the ones it is given; the stub
90
+ // keeps the given ones next to one of its own, so a lost class shows.
91
+ const Container: FunctionalComponent = (_, { attrs, slots }) =>
92
+ h("div", { ...attrs, class: ["w-full", attrs.class] }, slots.default?.());
93
+ Container.inheritAttrs = false;
94
+
95
+ const PageComponent: FunctionalComponent<{ componentId: string }> = (props) =>
96
+ h("section", { "data-component": props.componentId });
97
+ PageComponent.props = ["componentId"];
98
+
99
+ const FillHeightProbe: FunctionalComponent = () =>
100
+ h("output", String(usePageFillHeight().value));
101
+
102
+ function installRuntime(): void {
103
+ const runtime: Record<string, unknown> = {
104
+ computed,
105
+ inject,
106
+ onMounted,
107
+ onUnmounted,
108
+ provide,
109
+ ref,
110
+ toRef,
111
+ watch,
112
+ HTTP_FORBIDDEN: 403,
113
+ HTTP_INTERNAL_SERVER_ERROR: 500,
114
+ HTTP_NOT_FOUND: 404,
115
+ PAGE_FILL_HEIGHT_CLASSES,
116
+ providePageFillHeight,
117
+ usePageFillHeight,
118
+ createError: vi.fn(),
119
+ defineDmsPageMeta: vi.fn(),
120
+ firstAccessiblePagePath: vi.fn(),
121
+ navigateDms: vi.fn(),
122
+ preloadPageLayoutComponents: vi.fn(),
123
+ providePageRealtime: vi.fn(),
124
+ resolveDmsComponent: () => "div",
125
+ runCustomValidation: vi.fn(),
126
+ showError: vi.fn(),
127
+ validateRequiredQueryParams: vi.fn(),
128
+ useDefinedFunctions: () => ({ getFunction: () => undefined }),
129
+ useDevReloading: () => ref(false),
130
+ useDmsRoute: () => route,
131
+ useHomepage: () => "/",
132
+ usePageLayout: async () => ({ pageLayout }),
133
+ usePageRealtime: () => ({}),
134
+ usePermissions: () => ({
135
+ permissions: ref([]),
136
+ refreshIfStale: async () => {},
137
+ }),
138
+ useSessionRecovery: () => ({
139
+ loggedIn: ref(true),
140
+ reconcileSession: async () => {},
141
+ redirectToAuth: async () => {},
142
+ }),
143
+ useSiteLayout: () => ({
144
+ siteLayout: ref({ pages: {} }),
145
+ siteLayoutTree: ref([]),
146
+ loadingError: ref(null),
147
+ loadSiteLayout: async () => {},
148
+ refresh: async () => {},
149
+ refreshIfStale: async () => {},
150
+ findMatchingRoute: () => ({
151
+ metadata: { fullId: "tools.explorer", hasAccess: true },
152
+ params: {},
153
+ }),
154
+ }),
155
+ useTranslation: () => ({ processI18n: (value: string) => value }),
156
+ };
157
+ Object.entries(runtime).forEach(([name, value]) =>
158
+ vi.stubGlobal(name, value),
159
+ );
160
+ }
161
+
162
+ function withStubs(app: App): App {
163
+ app.component("UDashboardGroup", Group);
164
+ app.component("UDashboardPanel", Panel);
165
+ app.component("UContainer", Container);
166
+ app.component("UIcon", () => h("i"));
167
+ app.component("DmsAppWidgetsDock", () => null);
168
+ app.component("DmsRecursiveComponent", PageComponent);
169
+ return app;
170
+ }
171
+
172
+ function renderInLayout(
173
+ layoutProps: Record<string, unknown>,
174
+ page: Component,
175
+ ): Promise<string> {
176
+ const root = () =>
177
+ h(
178
+ DefaultLayout,
179
+ { title: "Explorer", ...layoutProps },
180
+ { default: () => h(page) },
181
+ );
182
+ return renderToString(withStubs(createSSRApp(root)));
183
+ }
184
+
185
+ function parse(markup: string): HTMLElement {
186
+ const host = document.createElement("div");
187
+ host.innerHTML = markup;
188
+ return host;
189
+ }
190
+
191
+ function classesOf(element: Element | null | undefined): string[] {
192
+ return element?.getAttribute("class")?.split(" ").filter(Boolean) ?? [];
193
+ }
194
+
195
+ function expectClasses(element: Element | null | undefined, classes: string) {
196
+ expect(classesOf(element)).toEqual(
197
+ expect.arrayContaining(classes.split(" ")),
198
+ );
199
+ }
200
+
201
+ function expectNoFillClasses(element: Element | null | undefined) {
202
+ const fillClasses = new Set(
203
+ `${PAGE_FILL_HEIGHT_CLASSES.region} ${PAGE_FILL_HEIGHT_CLASSES.column}`.split(
204
+ " ",
205
+ ),
206
+ );
207
+ expect(classesOf(element).filter((name) => fillClasses.has(name))).toEqual(
208
+ [],
209
+ );
210
+ }
211
+
212
+ beforeEach(() => {
213
+ installRuntime();
214
+ route.path = "/tools/explorer";
215
+ pageLayout.value = withComponents("stats", "explorer");
216
+ });
217
+
218
+ afterEach(() => {
219
+ vi.unstubAllGlobals();
220
+ });
221
+
222
+ describe("usePageFillHeight", () => {
223
+ it("reads false under a layout that does not provide it", async () => {
224
+ const markup = await renderToString(createSSRApp(FillHeightProbe));
225
+ expect(markup).toBe("<output>false</output>");
226
+ });
227
+
228
+ it("follows the layout that provides it", async () => {
229
+ const fillHeight = ref(true);
230
+ const app = withStubs(
231
+ createApp(() =>
232
+ h(
233
+ DefaultLayout,
234
+ { fillHeight: fillHeight.value },
235
+ { default: () => h(FillHeightProbe) },
236
+ ),
237
+ ),
238
+ );
239
+ const host = document.createElement("div");
240
+ app.mount(host);
241
+ expect(host.querySelector("output")?.textContent).toBe("true");
242
+ fillHeight.value = false;
243
+ await nextTick();
244
+ expect(host.querySelector("output")?.textContent).toBe("false");
245
+ app.unmount();
246
+ });
247
+ });
248
+
249
+ describe("DefaultLayout without fillHeight", () => {
250
+ it("renders the page exactly as it did before the option existed", async () => {
251
+ expect(await renderInLayout({}, CatchAllPage)).toBe(FLOW_PAGE_MARKUP);
252
+ });
253
+
254
+ it("tells the page it does not fill the panel", async () => {
255
+ const markup = await renderInLayout({}, FillHeightProbe);
256
+ expect(parse(markup).querySelector("output")?.textContent).toBe("false");
257
+ });
258
+ });
259
+
260
+ describe("DefaultLayout with fillHeight", () => {
261
+ it("makes the page region a flex column with a minimum height", async () => {
262
+ const host = parse(
263
+ await renderInLayout({ fillHeight: true }, CatchAllPage),
264
+ );
265
+ const region = host.querySelector("[data-dms-page-content]");
266
+ expectClasses(region, PAGE_FILL_HEIGHT_CLASSES.region);
267
+ expectClasses(region, "w-full max-w-none");
268
+ });
269
+
270
+ it("keeps the page header a plain item of that column", async () => {
271
+ const host = parse(
272
+ await renderInLayout({ fillHeight: true }, CatchAllPage),
273
+ );
274
+ const header = host.querySelector("[data-dms-page-content] > section");
275
+ expect(classesOf(header)).toEqual([
276
+ "flex",
277
+ "gap-4",
278
+ "items-start",
279
+ "pt-6",
280
+ "pb-7",
281
+ ]);
282
+ });
283
+
284
+ it("gives the height left to the last component only", async () => {
285
+ const host = parse(
286
+ await renderInLayout({ fillHeight: true }, CatchAllPage),
287
+ );
288
+ const stack = host.querySelector(".dms-page-stack");
289
+ const [stats, explorer] = Array.from(stack?.children ?? []);
290
+ expectClasses(
291
+ stack,
292
+ `dms-page-stack space-y-6 ${PAGE_FILL_HEIGHT_CLASSES.column}`,
293
+ );
294
+ expectNoFillClasses(stats);
295
+ expectClasses(explorer, PAGE_FILL_HEIGHT_CLASSES.column);
296
+ expect(
297
+ explorer
298
+ ?.querySelector("[data-component]")
299
+ ?.getAttribute("data-component"),
300
+ ).toBe("explorer");
301
+ });
302
+
303
+ it("fills with the only component of a single-component page", async () => {
304
+ pageLayout.value = withComponents("explorer");
305
+ const host = parse(
306
+ await renderInLayout({ fillHeight: true }, CatchAllPage),
307
+ );
308
+ const wrappers = host.querySelectorAll(".dms-page-stack > div");
309
+ expect(wrappers).toHaveLength(1);
310
+ expectClasses(wrappers[0], PAGE_FILL_HEIGHT_CLASSES.column);
311
+ });
312
+
313
+ it("tells a custom page, rendered straight in the slot, to fill", async () => {
314
+ const markup = await renderInLayout({ fillHeight: true }, FillHeightProbe);
315
+ expect(parse(markup).querySelector("output")?.textContent).toBe("true");
316
+ });
317
+
318
+ it("drops the fill classes when a navigation lands on a page without the option", async () => {
319
+ const fillHeight = ref(true);
320
+ const app = withStubs(
321
+ createApp(() =>
322
+ h(
323
+ DefaultLayout,
324
+ { title: "Explorer", fillHeight: fillHeight.value },
325
+ {
326
+ default: () =>
327
+ h(Suspense, null, { default: () => h(CatchAllPage) }),
328
+ },
329
+ ),
330
+ ),
331
+ );
332
+ const host = document.createElement("div");
333
+ app.mount(host);
334
+ await vi.waitFor(() =>
335
+ expect(host.querySelector(".dms-page-stack")).not.toBeNull(),
336
+ );
337
+ expectClasses(
338
+ host.querySelector(".dms-page-stack"),
339
+ PAGE_FILL_HEIGHT_CLASSES.column,
340
+ );
341
+
342
+ fillHeight.value = false;
343
+ await nextTick();
344
+
345
+ expectNoFillClasses(host.querySelector("[data-dms-page-content]"));
346
+ expectNoFillClasses(host.querySelector(".dms-page-stack"));
347
+ host
348
+ .querySelectorAll(".dms-page-stack > div")
349
+ .forEach((wrapper) => expectNoFillClasses(wrapper));
350
+ app.unmount();
351
+ });
352
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antelopejs/dms",
3
- "version": "0.4.8",
3
+ "version": "0.5.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/AntelopeJS/dms.git"
@@ -36,7 +36,7 @@
36
36
  "@antelopejs/interface-data-api": ">=0.1.9 <1.0.0",
37
37
  "@antelopejs/interface-database": ">=0.1.8 <1.0.0",
38
38
  "@antelopejs/interface-database-decorators": ">=0.1.7 <1.0.0",
39
- "@antelopejs/interface-dms": ">=0.2.6 <1.0.0",
39
+ "@antelopejs/interface-dms": ">=0.3.2 <0.4.0",
40
40
  "@antelopejs/interface-email": ">=0.0.5 <1.0.0",
41
41
  "@antelopejs/interface-file-storage": ">=0.1.3 <1.0.0",
42
42
  "archiver": "^7.0.1",
@@ -52,8 +52,8 @@
52
52
  "zod": "~3.24.2"
53
53
  },
54
54
  "devDependencies": {
55
- "@antelopejs/core": ">=1.9.1 <2",
56
- "@antelopejs/tooling-configs": ">=0.0.6 <1.0.0",
55
+ "@antelopejs/core": ">=1.10.1 <2",
56
+ "@antelopejs/tooling-configs": ">=0.0.7 <1.0.0",
57
57
  "@types/archiver": "^6.0.4",
58
58
  "@types/chai": "^4.3.20",
59
59
  "@types/jsonwebtoken": "^9.0.10",
@@ -94,7 +94,7 @@
94
94
  "@antelopejs/interface-redis": ">=0.0.8 <1.0.0"
95
95
  },
96
96
  "peerDependencies": {
97
- "@antelopejs/core": ">=1.9.1 <2"
97
+ "@antelopejs/core": ">=1.10.1 <2"
98
98
  },
99
99
  "peerDependenciesMeta": {
100
100
  "@antelopejs/core": {
@@ -107,7 +107,7 @@
107
107
  "dev": "ajs project run --inspect -w -p playground",
108
108
  "frontend:dev": "pnpm --dir playground frontend:dev",
109
109
  "lint:fix": "oxlint --fix --max-warnings=1000000 && oxfmt . && pnpm --dir frontend-vue lint:fix",
110
- "lint": "oxlint && oxfmt --check . && pnpm --dir frontend-vue lint",
110
+ "lint": "oxlint && oxfmt --check . && pnpm --dir frontend-vue lint && antelopejs-check-interface-ranges",
111
111
  "typecheck": "pnpm --filter @antelopejs/interface-dms build && tsc --noEmit",
112
112
  "test": "pnpm run build && ajs module test .",
113
113
  "test:unit": "pnpm run build && DMS_TEST_DIR=dist/test/unit ajs module test .",
@@ -19,7 +19,8 @@ first-party modules follow `dms-<name>` purely for discoverability.
19
19
  pages/ # @RegisterPage classes + category.ts (see dms-pages)
20
20
  routes/ # HTTP controllers feeding the components
21
21
  implementations/<name>/index.ts # implementation of the module's own interface
22
- frontend-vue/ # Vue module: dms.frontend.ts, app/, i18n/locales/
22
+ frontend-vue/ # Vue module: dms.frontend.ts, app/, i18n/locales/,
23
+ # package.json (engines: the loader releases it supports)
23
24
  package.json / tsconfig.json
24
25
  interface-<name>/ # the module's OWN interface, its own published package
25
26
  src/index.ts # (rare — many modules ship none)
@@ -77,6 +77,11 @@ export function destroy(): void { /* deactivate subscriptions */ }
77
77
  register — it returns the module's root `CategoryInfo`. `AddFrontendModule` is what surfaces the
78
78
  module's frontend; without it the module is backend-only.
79
79
 
80
+ `renderer` names the framework (Vue 3), not a loader release. The `@antelopejs/dms-frontend`
81
+ releases the frontend module runs on go in the frontend module's own `package.json`, as
82
+ `"engines": { "@antelopejs/dms-frontend": ">=0.3.2 <0.4.0" }`: the loader refuses the module
83
+ outside that range. Cap it below the next loader minor while the loader is 0.x.
84
+
80
85
  ## Navigation & access — module pages are owner-only
81
86
 
82
87
  Three constraints are enforced at registration: a page's `category` must **descend from the
@@ -1 +0,0 @@
1
- export declare function installTableViewRealtimeBridge(): void;
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.installTableViewRealtimeBridge = installTableViewRealtimeBridge;
4
- const table_view_1 = require("@antelopejs/interface-dms/base/table-view");
5
- const current_1 = require("./current");
6
- const registry_1 = require("./registry");
7
- const TABLEVIEW_ROW_TOPIC_PREFIX = "tableview:row:";
8
- const TABLEVIEW_PRESENCE_TOPIC_PREFIX = "tableview:presence:";
9
- const buildRowTopic = (location) => `${TABLEVIEW_ROW_TOPIC_PREFIX}${location}`;
10
- const buildPresenceTopic = (location) => `${TABLEVIEW_PRESENCE_TOPIC_PREFIX}${location}`;
11
- let isInstalled = false;
12
- function installTableViewRealtimeBridge() {
13
- if (isInstalled)
14
- return;
15
- isInstalled = true;
16
- (0, table_view_1.setRealtimeMutationHook)(async ({ controllerLocation, eventType, ids, sessionId, actor }) => {
17
- await (0, current_1.getRealtimeBroker)().publish({
18
- topic: buildRowTopic(controllerLocation),
19
- type: eventType,
20
- payload: { ids },
21
- actorId: actor?.id,
22
- ts: Date.now(),
23
- });
24
- if (sessionId && (eventType === "updated" || eventType === "deleted")) {
25
- const presenceTopic = buildPresenceTopic(controllerLocation);
26
- const tracker = (0, current_1.getPresenceTracker)();
27
- await Promise.all(ids.map((id) => tracker.release(sessionId, presenceTopic, id)));
28
- }
29
- });
30
- (0, table_view_1.setRealtimePresenceHook)(async ({ controllerLocation, sessionId, rowId, actor }) => {
31
- await (0, current_1.getPresenceTracker)().acquire(sessionId, buildPresenceTopic(controllerLocation), rowId, actor);
32
- });
33
- (0, table_view_1.setRealtimePageTopicHook)(({ pageId, controllerLocation }) => {
34
- (0, registry_1.registerPageTopic)(pageId, buildRowTopic(controllerLocation));
35
- (0, registry_1.registerPageTopic)(pageId, buildPresenceTopic(controllerLocation));
36
- });
37
- }
38
- //# sourceMappingURL=tableview-bridge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tableview-bridge.js","sourceRoot":"","sources":["../../src/realtime/tableview-bridge.ts"],"names":[],"mappings":";;AAmBA,wEAsCC;AAzDD,0EAImD;AACnD,uCAAkE;AAClE,yCAA+C;AAE/C,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AACpD,MAAM,+BAA+B,GAAG,qBAAqB,CAAC;AAE9D,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAU,EAAE,CACjD,GAAG,0BAA0B,GAAG,QAAQ,EAAE,CAAC;AAE7C,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAU,EAAE,CACtD,GAAG,+BAA+B,GAAG,QAAQ,EAAE,CAAC;AAElD,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,SAAgB,8BAA8B;IAC5C,IAAI,WAAW;QAAE,OAAO;IACxB,WAAW,GAAG,IAAI,CAAC;IAEnB,IAAA,oCAAuB,EACrB,KAAK,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;QACjE,MAAM,IAAA,2BAAiB,GAAE,CAAC,OAAO,CAAC;YAChC,KAAK,EAAE,aAAa,CAAC,kBAAkB,CAAC;YACxC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,EAAE,GAAG,EAAE;YAChB,OAAO,EAAE,KAAK,EAAE,EAAE;YAClB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;SACf,CAAC,CAAC;QACH,IAAI,SAAS,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,CAAC,EAAE,CAAC;YACtE,MAAM,aAAa,GAAG,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;YAC7D,MAAM,OAAO,GAAG,IAAA,4BAAkB,GAAE,CAAC;YACrC,MAAM,OAAO,CAAC,GAAG,CACf,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,IAAA,oCAAuB,EACrB,KAAK,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACxD,MAAM,IAAA,4BAAkB,GAAE,CAAC,OAAO,CAChC,SAAS,EACT,kBAAkB,CAAC,kBAAkB,CAAC,EACtC,KAAK,EACL,KAAK,CACN,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,IAAA,qCAAwB,EAAC,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,EAAE;QAC1D,IAAA,4BAAiB,EAAC,MAAM,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC7D,IAAA,4BAAiB,EAAC,MAAM,EAAE,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC"}