@byline/host-tanstack-start 4.16.0 → 4.17.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 (146) hide show
  1. package/dist/admin-shell/chrome/admin-menu-drawer.js +14 -14
  2. package/dist/admin-shell/chrome/dashboard.js +41 -5
  3. package/dist/admin-shell/chrome/dashboard.test.d.ts +8 -0
  4. package/dist/admin-shell/collections/api.d.ts +2 -2
  5. package/dist/admin-shell/collections/create.d.ts +2 -2
  6. package/dist/admin-shell/collections/create.js +1 -0
  7. package/dist/admin-shell/collections/edit.d.ts +2 -2
  8. package/dist/admin-shell/collections/edit.js +1 -0
  9. package/dist/admin-shell/collections/history.d.ts +4 -12
  10. package/dist/admin-shell/collections/history.js +112 -303
  11. package/dist/admin-shell/collections/reindex-button.d.ts +1 -1
  12. package/dist/admin-shell/collections/reindex-button.js +5 -1
  13. package/dist/admin-shell/collections/restore-version-modal.d.ts +4 -4
  14. package/dist/admin-shell/collections/restore-version-modal.js +8 -24
  15. package/dist/admin-shell/collections/version-history.d.ts +72 -0
  16. package/dist/admin-shell/collections/version-history.js +259 -0
  17. package/dist/admin-shell/singletons/history.d.ts +19 -0
  18. package/dist/admin-shell/singletons/history.js +170 -0
  19. package/dist/admin-shell/singletons/history.test.d.ts +8 -0
  20. package/dist/admin-shell/singletons/preview-link.d.ts +12 -0
  21. package/dist/admin-shell/singletons/preview-link.js +54 -0
  22. package/dist/admin-shell/singletons/view-menu.d.ts +13 -0
  23. package/dist/admin-shell/singletons/view-menu.js +116 -0
  24. package/dist/admin-shell/singletons/view.d.ts +18 -0
  25. package/dist/admin-shell/singletons/view.js +259 -0
  26. package/dist/admin-shell/singletons/view.test.d.ts +8 -0
  27. package/dist/integrations/api-utils.d.ts +18 -4
  28. package/dist/integrations/api-utils.js +10 -3
  29. package/dist/routes/create-admin-dashboard-route.js +2 -2
  30. package/dist/routes/create-collection-api-route.js +3 -3
  31. package/dist/routes/create-collection-create-route.js +4 -3
  32. package/dist/routes/create-collection-edit-route.js +4 -3
  33. package/dist/routes/create-collection-history-route.js +4 -3
  34. package/dist/routes/create-collection-list-route.js +4 -3
  35. package/dist/routes/create-singleton-history-route.d.ts +8 -0
  36. package/dist/routes/create-singleton-history-route.js +99 -0
  37. package/dist/routes/create-singleton-route.d.ts +35 -0
  38. package/dist/routes/create-singleton-route.js +130 -0
  39. package/dist/routes/get-multi-collection-definition.d.ts +10 -0
  40. package/dist/routes/get-multi-collection-definition.js +6 -0
  41. package/dist/routes/get-singleton-definition.d.ts +10 -0
  42. package/dist/routes/get-singleton-definition.js +6 -0
  43. package/dist/routes/index.d.ts +2 -0
  44. package/dist/routes/index.js +2 -0
  45. package/dist/server-fns/actors.d.ts +16 -0
  46. package/dist/server-fns/actors.js +25 -0
  47. package/dist/server-fns/admin-document-presentation.d.ts +30 -0
  48. package/dist/server-fns/admin-document-presentation.js +32 -0
  49. package/dist/server-fns/collections/actors.d.ts +1 -10
  50. package/dist/server-fns/collections/actors.js +1 -25
  51. package/dist/server-fns/collections/get.js +9 -26
  52. package/dist/server-fns/collections/reorder.js +1 -1
  53. package/dist/server-fns/collections/scheduled-publication.js +2 -2
  54. package/dist/server-fns/collections/upload.js +3 -3
  55. package/dist/server-fns/collections/utils.d.ts +1 -7
  56. package/dist/server-fns/collections/utils.js +1 -4
  57. package/dist/server-fns/serialise.d.ts +14 -0
  58. package/dist/server-fns/serialise.js +4 -0
  59. package/dist/server-fns/singleton-document-read.d.ts +20 -0
  60. package/dist/server-fns/singleton-document-read.js +10 -0
  61. package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +12 -0
  62. package/dist/server-fns/singletons/cancel-scheduled-publish.js +7 -0
  63. package/dist/server-fns/singletons/change-status.d.ts +14 -0
  64. package/dist/server-fns/singletons/change-status.js +7 -0
  65. package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +14 -0
  66. package/dist/server-fns/singletons/confirm-scheduled-publish.js +9 -0
  67. package/dist/server-fns/singletons/copy-to-locale.d.ts +18 -0
  68. package/dist/server-fns/singletons/copy-to-locale.js +11 -0
  69. package/dist/server-fns/singletons/find-by-version.d.ts +16 -0
  70. package/dist/server-fns/singletons/find-by-version.js +9 -0
  71. package/dist/server-fns/singletons/get-scheduled-publish.d.ts +12 -0
  72. package/dist/server-fns/singletons/get-scheduled-publish.js +7 -0
  73. package/dist/server-fns/singletons/get.d.ts +24 -0
  74. package/dist/server-fns/singletons/get.js +6 -0
  75. package/dist/server-fns/singletons/history.d.ts +31 -0
  76. package/dist/server-fns/singletons/history.js +22 -0
  77. package/dist/server-fns/singletons/index.d.ts +19 -0
  78. package/dist/server-fns/singletons/index.js +12 -0
  79. package/dist/server-fns/singletons/restore-version.d.ts +14 -0
  80. package/dist/server-fns/singletons/restore-version.js +7 -0
  81. package/dist/server-fns/singletons/schedule-publish.d.ts +16 -0
  82. package/dist/server-fns/singletons/schedule-publish.js +10 -0
  83. package/dist/server-fns/singletons/unpublish.d.ts +12 -0
  84. package/dist/server-fns/singletons/unpublish.js +7 -0
  85. package/dist/server-fns/singletons/update.d.ts +14 -0
  86. package/dist/server-fns/singletons/update.js +14 -0
  87. package/dist/vitest-jsdom.test.d.ts +8 -0
  88. package/package.json +24 -18
  89. package/src/admin-shell/chrome/admin-menu-drawer.tsx +13 -13
  90. package/src/admin-shell/chrome/dashboard.test.tsx +199 -0
  91. package/src/admin-shell/chrome/dashboard.tsx +43 -9
  92. package/src/admin-shell/collections/api.tsx +2 -2
  93. package/src/admin-shell/collections/create.tsx +6 -2
  94. package/src/admin-shell/collections/edit.tsx +6 -2
  95. package/src/admin-shell/collections/history.module.css +1 -1
  96. package/src/admin-shell/collections/history.tsx +162 -442
  97. package/src/admin-shell/collections/reindex-button.tsx +4 -2
  98. package/src/admin-shell/collections/restore-version-modal.tsx +19 -25
  99. package/src/admin-shell/collections/version-history.tsx +349 -0
  100. package/src/admin-shell/singletons/history.test.tsx +407 -0
  101. package/src/admin-shell/singletons/history.tsx +185 -0
  102. package/src/admin-shell/singletons/preview-link.tsx +75 -0
  103. package/src/admin-shell/singletons/view-menu.tsx +136 -0
  104. package/src/admin-shell/singletons/view.test.tsx +400 -0
  105. package/src/admin-shell/singletons/view.tsx +351 -0
  106. package/src/integrations/api-utils.ts +34 -9
  107. package/src/routes/create-admin-dashboard-route.test.node.ts +70 -0
  108. package/src/routes/create-admin-dashboard-route.tsx +10 -2
  109. package/src/routes/create-collection-api-route.tsx +4 -4
  110. package/src/routes/create-collection-create-route.tsx +5 -8
  111. package/src/routes/create-collection-edit-route.tsx +5 -4
  112. package/src/routes/create-collection-history-route.tsx +5 -8
  113. package/src/routes/create-collection-list-route.tsx +5 -8
  114. package/src/routes/create-singleton-history-route.test.node.ts +148 -0
  115. package/src/routes/create-singleton-history-route.tsx +116 -0
  116. package/src/routes/create-singleton-route.test.node.ts +172 -0
  117. package/src/routes/create-singleton-route.tsx +176 -0
  118. package/src/routes/get-multi-collection-definition.ts +16 -0
  119. package/src/routes/get-singleton-definition.ts +16 -0
  120. package/src/routes/index.ts +2 -0
  121. package/src/server-fns/actors.ts +43 -0
  122. package/src/server-fns/admin-document-presentation.ts +78 -0
  123. package/src/server-fns/collections/actors.ts +1 -52
  124. package/src/server-fns/collections/get.ts +10 -49
  125. package/src/server-fns/collections/reorder.ts +1 -1
  126. package/src/server-fns/collections/scheduled-publication.ts +7 -1
  127. package/src/server-fns/collections/upload-singleton.test.node.ts +164 -0
  128. package/src/server-fns/collections/upload.ts +7 -3
  129. package/src/server-fns/collections/utils.ts +1 -9
  130. package/src/server-fns/serialise.ts +17 -0
  131. package/src/server-fns/singleton-document-read.ts +32 -0
  132. package/src/server-fns/singletons/cancel-scheduled-publish.ts +19 -0
  133. package/src/server-fns/singletons/change-status.ts +19 -0
  134. package/src/server-fns/singletons/confirm-scheduled-publish.ts +23 -0
  135. package/src/server-fns/singletons/copy-to-locale.ts +32 -0
  136. package/src/server-fns/singletons/find-by-version.ts +23 -0
  137. package/src/server-fns/singletons/get-scheduled-publish.ts +19 -0
  138. package/src/server-fns/singletons/get.ts +32 -0
  139. package/src/server-fns/singletons/history.ts +41 -0
  140. package/src/server-fns/singletons/index.ts +20 -0
  141. package/src/server-fns/singletons/restore-version.ts +19 -0
  142. package/src/server-fns/singletons/schedule-publish.ts +24 -0
  143. package/src/server-fns/singletons/singletons.test.node.ts +298 -0
  144. package/src/server-fns/singletons/unpublish.ts +19 -0
  145. package/src/server-fns/singletons/update.ts +31 -0
  146. package/src/vitest-jsdom.test.tsx +27 -0
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export declare function createSingletonHistoryRoute(path: string): any;
@@ -0,0 +1,99 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { createFileRoute, notFound } from "@tanstack/react-router";
3
+ import { getSingletonAdminConfig, getWorkflowStatuses } from "@byline/core";
4
+ import { useTranslation } from "@byline/i18n/react";
5
+ import { z } from "zod";
6
+ import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
7
+ import { SingletonHistoryView } from "../admin-shell/singletons/history.js";
8
+ import { getSingleton, getSingletonHistory } from "../server-fns/singletons/index.js";
9
+ import { getAdminRoutePath } from "./admin-path.js";
10
+ import { getContentLocaleRouteConfig } from "./get-content-locale-route-config.js";
11
+ import { getSingletonDefinition } from "./get-singleton-definition.js";
12
+ const searchSchema = z.object({
13
+ page: z.coerce.number().min(1).optional(),
14
+ page_size: z.coerce.number().max(100).optional(),
15
+ order: z.string().optional(),
16
+ desc: z.coerce.boolean().optional(),
17
+ locale: z.string().optional()
18
+ });
19
+ function createSingletonHistoryRoute(path) {
20
+ const Route = createFileRoute(path)({
21
+ validateSearch: searchSchema,
22
+ loaderDeps: ({ search })=>({
23
+ page: search.page,
24
+ page_size: search.page_size,
25
+ order: search.order,
26
+ desc: search.desc,
27
+ locale: search.locale
28
+ }),
29
+ loader: async ({ params, deps })=>{
30
+ if (null == getSingletonDefinition(params.singleton)) throw notFound();
31
+ const [history, currentDocument] = await Promise.all([
32
+ getSingletonHistory({
33
+ data: {
34
+ singleton: params.singleton,
35
+ params: {
36
+ page: deps.page,
37
+ page_size: deps.page_size,
38
+ order: deps.order,
39
+ desc: deps.desc,
40
+ locale: deps.locale
41
+ }
42
+ }
43
+ }),
44
+ getSingleton({
45
+ data: {
46
+ singleton: params.singleton,
47
+ locale: deps.locale ?? 'all'
48
+ }
49
+ })
50
+ ]);
51
+ return {
52
+ history,
53
+ currentDocument
54
+ };
55
+ },
56
+ staleTime: 0,
57
+ gcTime: 0,
58
+ shouldReload: true,
59
+ component: function() {
60
+ const { history, currentDocument } = Route.useLoaderData();
61
+ const { singleton } = Route.useParams();
62
+ const definition = getSingletonDefinition(singleton);
63
+ if (null == definition) throw notFound();
64
+ const { t } = useTranslation('byline-admin');
65
+ const { contentLocales, defaultContentLocale } = getContentLocaleRouteConfig();
66
+ return /*#__PURE__*/ jsxs(Fragment, {
67
+ children: [
68
+ /*#__PURE__*/ jsx(BreadcrumbsClient, {
69
+ breadcrumbs: [
70
+ {
71
+ label: t('chrome.menu.dashboard'),
72
+ href: getAdminRoutePath()
73
+ },
74
+ {
75
+ label: definition.label,
76
+ href: getAdminRoutePath('singletons', singleton)
77
+ },
78
+ {
79
+ label: t('collections.breadcrumbs.history'),
80
+ href: getAdminRoutePath('singletons', singleton, 'history')
81
+ }
82
+ ]
83
+ }),
84
+ /*#__PURE__*/ jsx(SingletonHistoryView, {
85
+ singletonDefinition: definition,
86
+ adminConfig: getSingletonAdminConfig(singleton) ?? void 0,
87
+ data: history,
88
+ currentDocument: currentDocument,
89
+ contentLocales: contentLocales,
90
+ defaultContentLocale: defaultContentLocale,
91
+ workflowStatuses: getWorkflowStatuses(definition)
92
+ })
93
+ ]
94
+ });
95
+ }
96
+ });
97
+ return Route;
98
+ }
99
+ export { createSingletonHistoryRoute };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import type { DocumentPublishScheduleInfo } from '@byline/client';
9
+ /**
10
+ * Load the mapped singleton document and attach the admin-only lifecycle
11
+ * metadata consumed by the editor. Keeping this composition in the route
12
+ * layer leaves ordinary singleton reads free of publication timing and actor
13
+ * capability details.
14
+ */
15
+ export declare const getSingletonRouteDocument: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
16
+ singleton: string;
17
+ locale?: string;
18
+ }) => {
19
+ singleton: string;
20
+ locale?: string;
21
+ }, Promise<{
22
+ document: null;
23
+ initialData: Record<string, any>;
24
+ } | {
25
+ document: {
26
+ _publishedVersion: Record<string, any> | null;
27
+ _scheduledPublicationEnabled: boolean;
28
+ _canSchedulePublication: boolean;
29
+ _scheduledPublish: DocumentPublishScheduleInfo | null;
30
+ scheduledPublishAt?: Date | undefined;
31
+ scheduledPublishVersionId?: string | undefined;
32
+ };
33
+ initialData: undefined;
34
+ } | null>>;
35
+ export declare function createSingletonRoute(path: string): any;
@@ -0,0 +1,130 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { createFileRoute, notFound } from "@tanstack/react-router";
3
+ import { createServerFn } from "@tanstack/react-start";
4
+ import { getAdminBylineClient, getAdminRequestContext } from "@byline/client/server";
5
+ import { buildInitialDataFromFields, documentAbilityKey, getServerConfig, getSingletonAdminConfig } from "@byline/core";
6
+ import { useTranslation } from "@byline/i18n/react";
7
+ import { z } from "zod";
8
+ import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
9
+ import { SingletonView } from "../admin-shell/singletons/view.js";
10
+ import { bylineCore } from "../integrations/byline-core.js";
11
+ import { serialise } from "../server-fns/serialise.js";
12
+ import { readSingletonDocument } from "../server-fns/singleton-document-read.js";
13
+ import { getAdminRoutePath } from "./admin-path.js";
14
+ import { getContentLocaleRouteConfig } from "./get-content-locale-route-config.js";
15
+ import { getSingletonDefinition } from "./get-singleton-definition.js";
16
+ const searchSchema = z.object({
17
+ locale: z.string().optional()
18
+ });
19
+ const getSingletonRouteDocument = createServerFn({
20
+ method: 'GET'
21
+ }).validator((input)=>input).handler(async ({ data })=>{
22
+ const definition = getSingletonDefinition(data.singleton);
23
+ if (null == definition) return null;
24
+ const document = await readSingletonDocument({
25
+ singleton: data.singleton,
26
+ locale: data.locale,
27
+ populateRelations: true
28
+ });
29
+ if (null == document) return {
30
+ document: null,
31
+ initialData: serialise(await buildInitialDataFromFields(definition.fields, {
32
+ locale: data.locale ?? getServerConfig().i18n.content.defaultLocale
33
+ }))
34
+ };
35
+ const config = getServerConfig();
36
+ const record = bylineCore().getCollectionRecord(data.singleton);
37
+ let publishedVersion = null;
38
+ if ('published' !== document.status) {
39
+ const published = await config.db.queries.documents.getPublishedVersion({
40
+ collection_id: record.collectionId,
41
+ document_id: String(document.id)
42
+ });
43
+ publishedVersion = published ? serialise({
44
+ id: published.document_id,
45
+ versionId: published.document_version_id,
46
+ status: published.status,
47
+ createdAt: published.created_at,
48
+ updatedAt: published.updated_at
49
+ }) : null;
50
+ }
51
+ const scheduledPublicationEnabled = config.scheduledPublication?.enabled === true;
52
+ let canSchedulePublication = false;
53
+ let scheduledPublish = null;
54
+ if (scheduledPublicationEnabled) {
55
+ const actor = (await getAdminRequestContext()).actor;
56
+ canSchedulePublication = actor?.hasAbility(documentAbilityKey(definition, 'changeStatus')) === true && actor.hasAbility(documentAbilityKey(definition, 'publish'));
57
+ if (canSchedulePublication) scheduledPublish = await getAdminBylineClient().singleton(data.singleton).getScheduledPublish();
58
+ }
59
+ const serializedSchedule = null == scheduledPublish ? null : serialise(scheduledPublish);
60
+ return {
61
+ document: {
62
+ ...document,
63
+ _publishedVersion: publishedVersion,
64
+ _scheduledPublicationEnabled: scheduledPublicationEnabled,
65
+ _canSchedulePublication: canSchedulePublication,
66
+ _scheduledPublish: serializedSchedule,
67
+ ...null == serializedSchedule ? {} : {
68
+ scheduledPublishAt: serializedSchedule.publishAt,
69
+ scheduledPublishVersionId: serializedSchedule.targetVersionId
70
+ }
71
+ },
72
+ initialData: void 0
73
+ };
74
+ });
75
+ function createSingletonRoute(path) {
76
+ const Route = createFileRoute(path)({
77
+ validateSearch: searchSchema,
78
+ loaderDeps: ({ search })=>({
79
+ locale: search.locale
80
+ }),
81
+ loader: async ({ params, deps })=>{
82
+ if (null == getSingletonDefinition(params.singleton)) throw notFound();
83
+ return getSingletonRouteDocument({
84
+ data: {
85
+ singleton: params.singleton,
86
+ locale: deps.locale
87
+ }
88
+ });
89
+ },
90
+ staleTime: 0,
91
+ gcTime: 0,
92
+ shouldReload: true,
93
+ component: function() {
94
+ const routeState = Route.useLoaderData();
95
+ const { singleton } = Route.useParams();
96
+ const { locale } = Route.useSearch();
97
+ const definition = getSingletonDefinition(singleton);
98
+ if (null == definition) throw notFound();
99
+ const { t } = useTranslation('byline-admin');
100
+ const { contentLocales, defaultContentLocale } = getContentLocaleRouteConfig();
101
+ return /*#__PURE__*/ jsxs(Fragment, {
102
+ children: [
103
+ /*#__PURE__*/ jsx(BreadcrumbsClient, {
104
+ breadcrumbs: [
105
+ {
106
+ label: t('chrome.menu.dashboard'),
107
+ href: getAdminRoutePath()
108
+ },
109
+ {
110
+ label: definition.label,
111
+ href: getAdminRoutePath('singletons', singleton)
112
+ }
113
+ ]
114
+ }),
115
+ /*#__PURE__*/ jsx(SingletonView, {
116
+ singletonDefinition: definition,
117
+ adminConfig: getSingletonAdminConfig(singleton) ?? void 0,
118
+ document: routeState.document,
119
+ initialData: routeState.initialData,
120
+ locale: locale,
121
+ contentLocales: contentLocales,
122
+ defaultContentLocale: defaultContentLocale
123
+ })
124
+ ]
125
+ });
126
+ }
127
+ });
128
+ return Route;
129
+ }
130
+ export { createSingletonRoute, getSingletonRouteDocument };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import type { MultiCollectionDefinition } from '@byline/core';
9
+ /** Resolve only the resource kind supported by the collection route family. */
10
+ export declare function getMultiCollectionDefinition(path: string): MultiCollectionDefinition | null;
@@ -0,0 +1,6 @@
1
+ import { getCollectionDefinition, isSingleton } from "@byline/core";
2
+ function getMultiCollectionDefinition(path) {
3
+ const definition = getCollectionDefinition(path);
4
+ return null == definition || isSingleton(definition) ? null : definition;
5
+ }
6
+ export { getMultiCollectionDefinition };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import type { SingletonDefinition } from '@byline/core';
9
+ /** Resolve only the resource kind supported by the singleton route family. */
10
+ export declare function getSingletonDefinition(path: string): SingletonDefinition | null;
@@ -0,0 +1,6 @@
1
+ import { getCollectionDefinition, isSingleton } from "@byline/core";
2
+ function getSingletonDefinition(path) {
3
+ const definition = getCollectionDefinition(path);
4
+ return null != definition && isSingleton(definition) ? definition : null;
5
+ }
6
+ export { getSingletonDefinition };
@@ -38,3 +38,5 @@ export { createCollectionEditRoute } from './create-collection-edit-route.js';
38
38
  export { createCollectionHistoryRoute } from './create-collection-history-route.js';
39
39
  export { createCollectionListRoute } from './create-collection-list-route.js';
40
40
  export { type CreateSignInRouteOptions, createSignInRoute, } from './create-sign-in-route.js';
41
+ export { createSingletonHistoryRoute } from './create-singleton-history-route.js';
42
+ export { createSingletonRoute } from './create-singleton-route.js';
@@ -17,3 +17,5 @@ export { createCollectionEditRoute } from "./create-collection-edit-route.js";
17
17
  export { createCollectionHistoryRoute } from "./create-collection-history-route.js";
18
18
  export { createCollectionListRoute } from "./create-collection-list-route.js";
19
19
  export { createSignInRoute } from "./create-sign-in-route.js";
20
+ export { createSingletonHistoryRoute } from "./create-singleton-history-route.js";
21
+ export { createSingletonRoute } from "./create-singleton-route.js";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export type ActorLabelMap = Record<string, {
9
+ label: string;
10
+ }>;
11
+ /**
12
+ * Batch-resolve admin-user ids to display labels. The admin server-fn layer
13
+ * owns this presentation concern so both collection and singleton history
14
+ * can share it without teaching document storage about admin-realm tables.
15
+ */
16
+ export declare function resolveActorLabels(ids: Iterable<string | null | undefined>): Promise<ActorLabelMap>;
@@ -0,0 +1,25 @@
1
+ import { bylineCore } from "../integrations/byline-core.js";
2
+ function labelFor(row) {
3
+ const name = [
4
+ row.given_name,
5
+ row.family_name
6
+ ].filter(Boolean).join(' ');
7
+ return name || row.username || row.email;
8
+ }
9
+ async function resolveActorLabels(ids) {
10
+ const unique = [
11
+ ...new Set([
12
+ ...ids
13
+ ].filter((id)=>'string' == typeof id && id.length > 0))
14
+ ];
15
+ if (0 === unique.length) return {};
16
+ const store = bylineCore().adminStore;
17
+ if (null == store) return {};
18
+ const rows = await store.adminUsers.getByIds(unique);
19
+ const map = {};
20
+ for (const row of rows)map[row.id] = {
21
+ label: labelFor(row)
22
+ };
23
+ return map;
24
+ }
25
+ export { resolveActorLabels };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { type CollectionDefinition, type PopulateSpec } from '@byline/core';
9
+ export interface AdminDocumentReadInput {
10
+ locale?: string;
11
+ depth?: number;
12
+ populateRelations?: boolean;
13
+ }
14
+ export interface AdminDocumentReadOptions {
15
+ locale: string;
16
+ populate?: PopulateSpec;
17
+ depth?: number;
18
+ status: 'any';
19
+ onMissingLocale: 'empty';
20
+ lenient: true;
21
+ }
22
+ /**
23
+ * Resolve the shared read controls used by collection and singleton editors.
24
+ * Explicit depth is the API-preview mode; otherwise relation-summary mode
25
+ * projects only each target's picker/title fields for first-paint tiles.
26
+ */
27
+ export declare function resolveAdminDocumentRead(definition: CollectionDefinition | null, input: AdminDocumentReadInput): {
28
+ options: AdminDocumentReadOptions;
29
+ populatedTree: boolean;
30
+ };
@@ -0,0 +1,32 @@
1
+ import { buildRelationSummaryPopulateMap, getCollectionAdminConfig, getCollectionDefinition } from "@byline/core";
2
+ function resolveAdminDocumentRead(definition, input) {
3
+ const populateRequested = 'number' == typeof input.depth && input.depth > 0;
4
+ const autoRelationsActive = !populateRequested && true === input.populateRelations;
5
+ let populate;
6
+ let depth;
7
+ if (populateRequested) {
8
+ populate = '*';
9
+ depth = input.depth;
10
+ } else if (autoRelationsActive && null != definition) {
11
+ const populateMap = buildRelationSummaryPopulateMap(definition.fields, (targetPath)=>({
12
+ def: getCollectionDefinition(targetPath),
13
+ admin: getCollectionAdminConfig(targetPath)
14
+ }));
15
+ if (Object.keys(populateMap).length > 0) {
16
+ populate = populateMap;
17
+ depth = 1;
18
+ }
19
+ }
20
+ return {
21
+ options: {
22
+ locale: input.locale ?? 'en',
23
+ populate,
24
+ depth,
25
+ status: 'any',
26
+ onMissingLocale: 'empty',
27
+ lenient: true
28
+ },
29
+ populatedTree: populateRequested || autoRelationsActive
30
+ };
31
+ }
32
+ export { resolveAdminDocumentRead };
@@ -5,13 +5,4 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- export type ActorLabelMap = Record<string, {
9
- label: string;
10
- }>;
11
- /**
12
- * Batch-resolve admin-user ids to display labels. Accepts the raw
13
- * `createdBy` values straight off a page of shaped documents — nullish
14
- * and duplicate entries are tolerated and deduplicated. Returns `{}`
15
- * when there is nothing to resolve or no admin store is configured.
16
- */
17
- export declare function resolveActorLabels(ids: Iterable<string | null | undefined>): Promise<ActorLabelMap>;
8
+ export { type ActorLabelMap, resolveActorLabels } from '../actors.js';
@@ -1,25 +1 @@
1
- import { bylineCore } from "../../integrations/byline-core.js";
2
- function labelFor(row) {
3
- const name = [
4
- row.given_name,
5
- row.family_name
6
- ].filter(Boolean).join(' ');
7
- return name || row.username || row.email;
8
- }
9
- async function resolveActorLabels(ids) {
10
- const unique = [
11
- ...new Set([
12
- ...ids
13
- ].filter((id)=>'string' == typeof id && id.length > 0))
14
- ];
15
- if (0 === unique.length) return {};
16
- const store = bylineCore().adminStore;
17
- if (null == store) return {};
18
- const rows = await store.adminUsers.getByIds(unique);
19
- const map = {};
20
- for (const row of rows)map[row.id] = {
21
- label: labelFor(row)
22
- };
23
- return map;
24
- }
25
- export { resolveActorLabels };
1
+ export { resolveActorLabels } from "../actors.js";
@@ -1,7 +1,8 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
2
  import { getAdminBylineClient, getAdminRequestContext } from "@byline/client/server";
3
- import { BylineError, ERR_NOT_FOUND, ErrorCodes, buildRelationSummaryPopulateMap, collectionAbilityKey, getCollectionAdminConfig, getCollectionDefinition, getCollectionSchemasForPath, getLogger, getServerConfig } from "@byline/core";
3
+ import { BylineError, ERR_NOT_FOUND, ErrorCodes, documentAbilityKey, getCollectionSchemasForPath, getLogger, getServerConfig } from "@byline/core";
4
4
  import { ensureCollection } from "../../integrations/api-utils.js";
5
+ import { resolveAdminDocumentRead } from "../admin-document-presentation.js";
5
6
  import { serialise } from "./utils.js";
6
7
  const getDocumentFn = createServerFn({
7
8
  method: 'GET'
@@ -17,30 +18,13 @@ const getDocumentFn = createServerFn({
17
18
  }).log(logger);
18
19
  const client = getAdminBylineClient();
19
20
  const handle = client.collection(path);
20
- const populateRequested = 'number' == typeof depth && depth > 0;
21
- const autoRelationsActive = !populateRequested && true === populateRelations;
22
- let populate;
23
- let resolvedDepth;
24
- if (populateRequested) {
25
- populate = '*';
26
- resolvedDepth = depth;
27
- } else if (autoRelationsActive) {
28
- const populateMap = buildRelationSummaryPopulateMap(config.definition.fields, (targetPath)=>({
29
- def: getCollectionDefinition(targetPath),
30
- admin: getCollectionAdminConfig(targetPath)
31
- }));
32
- if (Object.keys(populateMap).length > 0) {
33
- populate = populateMap;
34
- resolvedDepth = 1;
35
- }
36
- }
21
+ const { options: readOptions, populatedTree } = resolveAdminDocumentRead(config.definition, {
22
+ locale,
23
+ depth,
24
+ populateRelations
25
+ });
37
26
  const document = await handle.findById(id, {
38
- locale: locale ?? 'en',
39
- populate,
40
- depth: resolvedDepth,
41
- status: 'any',
42
- onMissingLocale: 'empty',
43
- lenient: true
27
+ ...readOptions
44
28
  });
45
29
  if (!document) throw ERR_NOT_FOUND({
46
30
  message: 'Document not found',
@@ -50,7 +34,6 @@ const getDocumentFn = createServerFn({
50
34
  }
51
35
  }).log(logger);
52
36
  const serialised = serialise(document);
53
- const populatedTree = populateRequested || autoRelationsActive;
54
37
  const parsed = 'all' === locale || populatedTree ? serialised : (()=>{
55
38
  const { get } = getCollectionSchemasForPath(path);
56
39
  return get.parse(serialised);
@@ -77,7 +60,7 @@ const getDocumentFn = createServerFn({
77
60
  let scheduledPublish = null;
78
61
  if (scheduledPublicationEnabled) {
79
62
  const actor = (await getAdminRequestContext()).actor;
80
- canSchedulePublication = actor?.hasAbility(collectionAbilityKey(path, 'changeStatus')) === true && actor.hasAbility(collectionAbilityKey(path, 'publish'));
63
+ canSchedulePublication = actor?.hasAbility(documentAbilityKey(config.definition, 'changeStatus')) === true && actor.hasAbility(documentAbilityKey(config.definition, 'publish'));
81
64
  if (canSchedulePublication) scheduledPublish = await handle.getScheduledPublish(id);
82
65
  }
83
66
  const serializedSchedule = null == scheduledPublish ? null : serialise(scheduledPublish);
@@ -21,7 +21,7 @@ const reorderCollectionDocument = createServerFn({
21
21
  }
22
22
  }).log(logger);
23
23
  const requestContext = await getAdminRequestContext();
24
- assertActorCanPerform(requestContext, path, 'update');
24
+ assertActorCanPerform(requestContext, config.definition, 'update');
25
25
  const serverConfig = getServerConfig();
26
26
  const collectionId = config.collection.id;
27
27
  const canonical = await serverConfig.db.queries.documents.getCanonicalDocumentOrder({
@@ -1,6 +1,6 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
2
  import { getAdminBylineClient, getAdminRequestContext } from "@byline/client/server";
3
- import { ERR_NOT_FOUND, ERR_VALIDATION } from "@byline/core";
3
+ import { ERR_NOT_FOUND, ERR_VALIDATION, isSingleton } from "@byline/core";
4
4
  import { listDocumentPublishSchedules } from "@byline/core/services";
5
5
  import { bylineCore } from "../../integrations/byline-core.js";
6
6
  import { omitScheduleExecutionState } from "./scheduled-publication-response.js";
@@ -138,7 +138,7 @@ const listScheduledPublications = createServerFn({
138
138
  return {
139
139
  ...serializeSchedule(schedule),
140
140
  collectionPath: definition?.path ?? schedule.collectionId,
141
- collectionLabel: definition?.labels.plural ?? definition?.path ?? schedule.collectionId,
141
+ collectionLabel: null == definition ? schedule.collectionId : isSingleton(definition) ? definition.label : definition.labels.plural,
142
142
  documentPath,
143
143
  lastAuthorizedByName: null == schedule.lastAuthorizedBy ? null : authorizerNames.get(schedule.lastAuthorizedBy) ?? null
144
144
  };
@@ -4,7 +4,7 @@ import { ERR_NOT_FOUND, ERR_VALIDATION, getServerConfig, getUploadFields } from
4
4
  import { extractImageMeta, generateImageVariants, isBypassMimeType } from "@byline/core/image";
5
5
  import { getLogger, withLogContext } from "@byline/core/logger";
6
6
  import { uploadField } from "@byline/core/services";
7
- import { ensureCollection } from "../../integrations/api-utils.js";
7
+ import { ensureDocumentResource } from "../../integrations/api-utils.js";
8
8
  function parseUploadFormData(data) {
9
9
  if (!(data instanceof FormData)) throw new Error('Expected FormData upload payload.');
10
10
  const collectionEntry = data.get('collection');
@@ -64,9 +64,9 @@ const uploadCollectionField = createServerFn({
64
64
  module: 'upload',
65
65
  function: 'uploadCollectionField'
66
66
  }, async ()=>{
67
- const config = await ensureCollection(collectionPath);
67
+ const config = await ensureDocumentResource(collectionPath);
68
68
  if (null == config) throw ERR_NOT_FOUND({
69
- message: 'Collection not found.',
69
+ message: 'Document resource not found.',
70
70
  details: {
71
71
  collectionPath
72
72
  }
@@ -5,10 +5,4 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- /**
9
- * Deep-serialise a value through JSON to convert Date objects to ISO strings.
10
- * TanStack Start server functions pass return values directly during SSR
11
- * (no automatic JSON round-trip), so Date instances from the DB driver would
12
- * fail downstream Zod z.string() checks without this explicit step.
13
- */
14
- export declare function serialise<T>(value: T): T;
8
+ export { serialise } from '../serialise.js';
@@ -1,4 +1 @@
1
- function serialise(value) {
2
- return JSON.parse(JSON.stringify(value));
3
- }
4
- export { serialise };
1
+ export { serialise } from "../serialise.js";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ /**
9
+ * Deep-serialise a value through JSON to convert Date objects to ISO strings.
10
+ * TanStack Start server functions pass return values directly during SSR
11
+ * (no automatic JSON round-trip), so Date instances from the DB driver would
12
+ * fail downstream string checks without this explicit step.
13
+ */
14
+ export declare function serialise<T>(value: T): T;
@@ -0,0 +1,4 @@
1
+ function serialise(value) {
2
+ return JSON.parse(JSON.stringify(value));
3
+ }
4
+ export { serialise };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export interface SingletonDocumentReadInput {
9
+ singleton: string;
10
+ locale?: string;
11
+ depth?: number;
12
+ populateRelations?: boolean;
13
+ }
14
+ /**
15
+ * Read the singleton document with the presentation controls shared by the
16
+ * editor route and the public server function. Route-only lifecycle metadata
17
+ * is deliberately composed one layer up, where host database and actor
18
+ * context are available without widening the singleton transport contract.
19
+ */
20
+ export declare function readSingletonDocument(data: SingletonDocumentReadInput): Promise<import("@byline/client").SingletonDocument<Record<string, any>> | null>;