@aglyn/aglyn 1.0.0-beta.277 → 1.0.0-beta.283

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 (95) hide show
  1. package/package.json +11 -11
  2. package/src/lib/app-utils/account-preferences.d.ts +146 -11
  3. package/src/lib/app-utils/account-preferences.js +266 -18
  4. package/src/lib/app-utils/account-preferences.js.map +1 -1
  5. package/src/lib/app-utils/activity-presenter.js +2 -26
  6. package/src/lib/app-utils/activity-presenter.js.map +1 -1
  7. package/src/lib/app-utils/activity-type-labels.d.ts +18 -0
  8. package/src/lib/app-utils/activity-type-labels.js +46 -0
  9. package/src/lib/app-utils/activity-type-labels.js.map +1 -0
  10. package/src/lib/app-utils/artifact-provenance.d.ts +3 -1
  11. package/src/lib/app-utils/artifact-provenance.js.map +1 -1
  12. package/src/lib/app-utils/bundle-intent.d.ts +37 -0
  13. package/src/lib/app-utils/bundle-intent.js +47 -3
  14. package/src/lib/app-utils/bundle-intent.js.map +1 -1
  15. package/src/lib/app-utils/compose-reusable-components.d.ts +17 -1
  16. package/src/lib/app-utils/compose-reusable-components.js +80 -5
  17. package/src/lib/app-utils/compose-reusable-components.js.map +1 -1
  18. package/src/lib/app-utils/docs-help-sections.generated.js +13 -1
  19. package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
  20. package/src/lib/app-utils/docs-help.generated.d.ts +23 -11
  21. package/src/lib/app-utils/docs-help.generated.js +64 -7
  22. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  23. package/src/lib/app-utils/docs-index.generated.js +359 -51
  24. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  25. package/src/lib/app-utils/error-beacon.d.ts +19 -0
  26. package/src/lib/app-utils/error-beacon.js +28 -0
  27. package/src/lib/app-utils/error-beacon.js.map +1 -1
  28. package/src/lib/app-utils/health-report.d.ts +3 -2
  29. package/src/lib/app-utils/health-report.js +22 -2
  30. package/src/lib/app-utils/health-report.js.map +1 -1
  31. package/src/lib/app-utils/native-nav.d.ts +39 -4
  32. package/src/lib/app-utils/native-nav.js +69 -3
  33. package/src/lib/app-utils/native-nav.js.map +1 -1
  34. package/src/lib/app-utils/native-themes.d.ts +28 -17
  35. package/src/lib/app-utils/native-themes.js +123 -45
  36. package/src/lib/app-utils/native-themes.js.map +1 -1
  37. package/src/lib/app-utils/operator-alerts.js +4 -2
  38. package/src/lib/app-utils/operator-alerts.js.map +1 -1
  39. package/src/lib/app-utils/org-permission-editor.d.ts +75 -0
  40. package/src/lib/app-utils/org-permission-editor.js +124 -0
  41. package/src/lib/app-utils/org-permission-editor.js.map +1 -0
  42. package/src/lib/app-utils/org-permissions.d.ts +36 -0
  43. package/src/lib/app-utils/org-permissions.js +78 -26
  44. package/src/lib/app-utils/org-permissions.js.map +1 -1
  45. package/src/lib/app-utils/org-role-grants.d.ts +59 -9
  46. package/src/lib/app-utils/org-role-grants.js +97 -10
  47. package/src/lib/app-utils/org-role-grants.js.map +1 -1
  48. package/src/lib/app-utils/plan-entitlements.d.ts +13 -0
  49. package/src/lib/app-utils/plan-entitlements.js +22 -0
  50. package/src/lib/app-utils/plan-entitlements.js.map +1 -1
  51. package/src/lib/app-utils/release-flags.d.ts +52 -1
  52. package/src/lib/app-utils/release-flags.js +68 -2
  53. package/src/lib/app-utils/release-flags.js.map +1 -1
  54. package/src/lib/app-utils/reusable-component-keys.d.ts +13 -0
  55. package/src/lib/app-utils/reusable-component-keys.js +12 -0
  56. package/src/lib/app-utils/reusable-component-keys.js.map +1 -1
  57. package/src/lib/app-utils/screen-analytics-aggregate.d.ts +34 -0
  58. package/src/lib/app-utils/screen-analytics-aggregate.js +37 -0
  59. package/src/lib/app-utils/screen-analytics-aggregate.js.map +1 -1
  60. package/src/lib/app-utils/site-care.d.ts +35 -0
  61. package/src/lib/app-utils/site-care.js +48 -0
  62. package/src/lib/app-utils/site-care.js.map +1 -1
  63. package/src/lib/app-utils/site-font-pairings.d.ts +59 -0
  64. package/src/lib/app-utils/site-font-pairings.js +514 -0
  65. package/src/lib/app-utils/site-font-pairings.js.map +1 -0
  66. package/src/lib/app-utils/site-starter.d.ts +136 -0
  67. package/src/lib/app-utils/site-starter.js +116 -0
  68. package/src/lib/app-utils/site-starter.js.map +1 -0
  69. package/src/lib/app-utils/stock-photos/stock-photo-picker-server.d.ts +95 -0
  70. package/src/lib/app-utils/stock-photos/stock-photo-picker-server.js +333 -0
  71. package/src/lib/app-utils/stock-photos/stock-photo-picker-server.js.map +1 -0
  72. package/src/lib/app-utils/stock-photos/stock-photo-picker.d.ts +188 -0
  73. package/src/lib/app-utils/stock-photos/stock-photo-picker.js +193 -0
  74. package/src/lib/app-utils/stock-photos/stock-photo-picker.js.map +1 -0
  75. package/src/lib/plugin-manager/feature-plugins.d.ts +32 -0
  76. package/src/lib/plugin-manager/feature-plugins.js +12 -0
  77. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  78. package/src/lib/plugin-manager/first-party-plugins.generated.js +27 -1
  79. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  80. package/src/lib/plugin-manager/plugin-entitlements.d.ts +37 -0
  81. package/src/lib/plugin-manager/plugin-entitlements.js +84 -2
  82. package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -1
  83. package/src/lib/plugin-manager/plugin-media-ingest.d.ts +15 -0
  84. package/src/lib/plugin-manager/plugin-media-ingest.js.map +1 -1
  85. package/src/lib/plugin-manager/plugin-permissions.d.ts +7 -0
  86. package/src/lib/plugin-manager/plugin-permissions.js.map +1 -1
  87. package/src/lib/plugin-manager/plugin-product-catalog.d.ts +12 -0
  88. package/src/lib/plugin-manager/plugin-product-catalog.js.map +1 -1
  89. package/src/lib/plugin-manager/plugin-site-starters.d.ts +73 -0
  90. package/src/lib/plugin-manager/plugin-site-starters.js +30 -0
  91. package/src/lib/plugin-manager/plugin-site-starters.js.map +1 -0
  92. package/src/lib/plugin-manager/plugin-sitemap-sections.d.ts +8 -1
  93. package/src/lib/plugin-manager/plugin-sitemap-sections.js.map +1 -1
  94. package/src/lib/plugin-manager/stock-photo-provider.d.ts +12 -0
  95. package/src/lib/plugin-manager/stock-photo-provider.js.map +1 -1
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type StockPhotoOrientation } from '../../plugin-manager/stock-photo-provider';
18
+ /**
19
+ * STOCK PHOTOS IN THE MEDIA PICKER (AGL-4066): the wire between the
20
+ * console's media picker and its server route, `/api/media/stock-photos`.
21
+ *
22
+ * A person editing a site by hand searches the deployment's stock photo
23
+ * library from the picker's Stock photos tab and places one. The route asks
24
+ * core's `core.stock-photos` provider and copies the chosen photo into the
25
+ * library the picker is filing into through `core.media-ingest`, as the
26
+ * signed-in member; the placed image is always that copy, never an address
27
+ * at the library. This module is the shapes both sides agree on, the checks
28
+ * the server makes on what a browser sends, and the browser's client. It
29
+ * names no library: the provider's own label comes back in every answer.
30
+ *
31
+ * Every request names one library, the target: a site's (`hostId`) or the
32
+ * workspace's shared one (`orgId`). A hit is named back to the server by
33
+ * {@link StockPhotoHitRef} — the search that found it and its id — never by
34
+ * the addresses or the credit, so the server finds the photo again in the
35
+ * provider's own cached answer and nothing a browser claims about a photo
36
+ * is stored.
37
+ */
38
+ /** The console route the picker's Stock photos tab talks to. */
39
+ export declare const STOCK_PHOTO_PICKER_ROUTE = "/api/media/stock-photos";
40
+ /** The library a request searches for and copies into. */
41
+ export type StockPhotoPickerTarget = {
42
+ hostId: string;
43
+ orgId?: undefined;
44
+ } | {
45
+ orgId: string;
46
+ hostId?: undefined;
47
+ };
48
+ /** The orientations the tab offers, in its order. */
49
+ export declare const STOCK_PHOTO_PICKER_ORIENTATIONS: readonly StockPhotoOrientation[];
50
+ /** How a search result names its photo back to the server. */
51
+ export interface StockPhotoHitRef {
52
+ /** The search words exactly as searched, after {@link normalizeStockPhotoQuery}. */
53
+ query: string;
54
+ orientation: StockPhotoOrientation;
55
+ /** The library's own id for the photo. */
56
+ id: string;
57
+ }
58
+ /** One photo a search found, as the tab shows it. */
59
+ export interface StockPhotoPickerHit {
60
+ ref: StockPhotoHitRef;
61
+ /** `{provider}:{id}`: what the library reuses an earlier copy by. */
62
+ sourceKey: string;
63
+ /** The size of the copy that is stored when the photo is used. */
64
+ width: number;
65
+ height: number;
66
+ photographer: string;
67
+ photographerUrl?: string;
68
+ /** The photo's page at the library. */
69
+ pageUrl: string;
70
+ /** The library's tags, a few, lowercase. */
71
+ tags: string[];
72
+ /** The library's own description of the photo, where it writes one. */
73
+ alt?: string;
74
+ /** The sentence the stored copy's description carries: "Photo by … on …". */
75
+ credit: string;
76
+ license: string;
77
+ licenseUrl: string;
78
+ attributionRequired: boolean;
79
+ }
80
+ /** The library the deployment searches, by the name its terms ask for. */
81
+ export interface StockPhotoPickerLibrary {
82
+ label: string;
83
+ }
84
+ /** What the tab is told when it opens. */
85
+ export type StockPhotoStatusAnswer = {
86
+ status: 'ready';
87
+ library: StockPhotoPickerLibrary;
88
+ } | {
89
+ status: 'unconfigured';
90
+ message: string;
91
+ } | {
92
+ status: 'refused';
93
+ message: string;
94
+ };
95
+ /** What a search answers. `busy`: the library could not be asked just now. */
96
+ export type StockPhotoSearchAnswer = {
97
+ status: 'ok';
98
+ library: StockPhotoPickerLibrary;
99
+ query: string;
100
+ orientation: StockPhotoOrientation;
101
+ hits: StockPhotoPickerHit[];
102
+ } | {
103
+ status: 'busy';
104
+ message: string;
105
+ } | {
106
+ status: 'unconfigured';
107
+ message: string;
108
+ } | {
109
+ status: 'refused';
110
+ message: string;
111
+ };
112
+ /**
113
+ * A stored asset as the picker places it: the media document's own fields,
114
+ * the ones a library pick hands on.
115
+ */
116
+ export interface StockPhotoPickerMedia {
117
+ $id: string;
118
+ fileName?: string;
119
+ contentType?: string;
120
+ sizeBytes?: number;
121
+ url?: string;
122
+ cdnPath?: string;
123
+ folderId?: string | null;
124
+ alt?: string;
125
+ description?: string;
126
+ width?: number;
127
+ height?: number;
128
+ variants?: number[];
129
+ visibleTo?: string[];
130
+ }
131
+ /** What using a photo answers. `reused`: the library already held a copy, which is placed. */
132
+ export type StockPhotoImportAnswer = {
133
+ status: 'ok';
134
+ reused: boolean;
135
+ media: StockPhotoPickerMedia;
136
+ } | {
137
+ status: 'busy';
138
+ message: string;
139
+ } | {
140
+ status: 'gone';
141
+ message: string;
142
+ } | {
143
+ status: 'unconfigured';
144
+ message: string;
145
+ } | {
146
+ status: 'refused';
147
+ message: string;
148
+ };
149
+ /** Said when the deployment has no stock photo library. */
150
+ export declare const STOCK_PHOTOS_UNCONFIGURED_MESSAGE: string;
151
+ /** Said when the library could not be asked, or could not send a photo, just now. */
152
+ export declare function stockPhotosBusyMessage(label: string): string;
153
+ /** Said when the photo is no longer among the search's results. */
154
+ export declare const STOCK_PHOTO_GONE_MESSAGE = "That photo is no longer in the search results. Search again and choose it from the new results.";
155
+ /**
156
+ * The search words as searched: control characters dropped, runs of space
157
+ * made one, trimmed. `null` when nothing is left or it is longer than
158
+ * {@link STOCK_PHOTO_QUERY_MAX_CHARS}.
159
+ */
160
+ export declare function normalizeStockPhotoQuery(value: unknown): string | null;
161
+ /** An orientation the tab offers, `any` for anything else. */
162
+ export declare function stockPhotoOrientationOf(value: unknown): StockPhotoOrientation;
163
+ /** The library a request names, or `null` when it names none, or both. */
164
+ export declare function stockPhotoTargetOf(body: unknown): StockPhotoPickerTarget | null;
165
+ /** The photo a request names, or `null` when it is not one a search could have found. */
166
+ export declare function stockPhotoHitRefOf(value: unknown): StockPhotoHitRef | null;
167
+ /** `value` when it is an https address, else `undefined`: nothing else is ever linked. */
168
+ export declare function stockPhotoSafeLink(value: unknown): string | undefined;
169
+ /** The fields of a stored media document the picker hands on, from the document. */
170
+ export declare function stockPhotoPickerMediaOf(mediaId: string, data: Record<string, unknown>): StockPhotoPickerMedia;
171
+ /** Posts one JSON request to the route, with whatever credentials the caller adds. */
172
+ export type StockPhotoPickerPost = (body: Record<string, unknown>) => Promise<Response>;
173
+ /** The browser's side of the route, for one library. */
174
+ export interface StockPhotoPickerClient {
175
+ status(): Promise<StockPhotoStatusAnswer>;
176
+ search(query: string, orientation: StockPhotoOrientation): Promise<StockPhotoSearchAnswer>;
177
+ /** The hit's small copy, or `null` when none can be had. */
178
+ preview(ref: StockPhotoHitRef): Promise<Blob | null>;
179
+ /** Copies the photo into the library, or finds the copy it holds. */
180
+ importPhoto(ref: StockPhotoHitRef, options?: {
181
+ folderId?: string | null;
182
+ }): Promise<StockPhotoImportAnswer>;
183
+ }
184
+ /**
185
+ * The client for one library. `post` carries the member's credentials: the
186
+ * console hands in `authorizedFetch` bound to the route.
187
+ */
188
+ export declare function createStockPhotoPickerClient(post: StockPhotoPickerPost, target: StockPhotoPickerTarget): StockPhotoPickerClient;
@@ -0,0 +1,193 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { STOCK_PHOTO_QUERY_MAX_CHARS } from "../../plugin-manager/stock-photo-provider.js";
18
+ /**
19
+ * STOCK PHOTOS IN THE MEDIA PICKER (AGL-4066): the wire between the
20
+ * console's media picker and its server route, `/api/media/stock-photos`.
21
+ *
22
+ * A person editing a site by hand searches the deployment's stock photo
23
+ * library from the picker's Stock photos tab and places one. The route asks
24
+ * core's `core.stock-photos` provider and copies the chosen photo into the
25
+ * library the picker is filing into through `core.media-ingest`, as the
26
+ * signed-in member; the placed image is always that copy, never an address
27
+ * at the library. This module is the shapes both sides agree on, the checks
28
+ * the server makes on what a browser sends, and the browser's client. It
29
+ * names no library: the provider's own label comes back in every answer.
30
+ *
31
+ * Every request names one library, the target: a site's (`hostId`) or the
32
+ * workspace's shared one (`orgId`). A hit is named back to the server by
33
+ * {@link StockPhotoHitRef} — the search that found it and its id — never by
34
+ * the addresses or the credit, so the server finds the photo again in the
35
+ * provider's own cached answer and nothing a browser claims about a photo
36
+ * is stored.
37
+ */ /** The console route the picker's Stock photos tab talks to. */ export const STOCK_PHOTO_PICKER_ROUTE = '/api/media/stock-photos';
38
+ /** The orientations the tab offers, in its order. */ export const STOCK_PHOTO_PICKER_ORIENTATIONS = [
39
+ 'any',
40
+ 'horizontal',
41
+ 'vertical'
42
+ ];
43
+ /** Said when the deployment has no stock photo library. */ export const STOCK_PHOTOS_UNCONFIGURED_MESSAGE = 'Stock photos are not set up here, so there is no library to search. ' + 'You can still upload your own photos in the library tabs.';
44
+ /** Said when the library could not be asked, or could not send a photo, just now. */ export function stockPhotosBusyMessage(label) {
45
+ return `${label || 'The stock photo library'} is busy right now. Try again in a minute.`;
46
+ }
47
+ /** Said when the photo is no longer among the search's results. */ export const STOCK_PHOTO_GONE_MESSAGE = 'That photo is no longer in the search results. Search again and choose it from the new results.';
48
+ /** The longest id a library may give a photo here. */ const MAX_ID_CHARS = 64;
49
+ /** A library id: a site's or a workspace's document id, never a path. */ const isDocumentId = (value)=>typeof value === 'string' && value.length > 0 && value.length <= 128 && !value.includes('/') && value.trim() === value;
50
+ /**
51
+ * The search words as searched: control characters dropped, runs of space
52
+ * made one, trimmed. `null` when nothing is left or it is longer than
53
+ * {@link STOCK_PHOTO_QUERY_MAX_CHARS}.
54
+ */ export function normalizeStockPhotoQuery(value) {
55
+ if (typeof value !== 'string') return null;
56
+ // eslint-disable-next-line no-control-regex
57
+ const query = value.replace(/[\u0000-\u001f\u007f]/g, ' ').replace(/\s+/g, ' ').trim();
58
+ if (!query || query.length > STOCK_PHOTO_QUERY_MAX_CHARS) return null;
59
+ return query;
60
+ }
61
+ /** An orientation the tab offers, `any` for anything else. */ export function stockPhotoOrientationOf(value) {
62
+ return STOCK_PHOTO_PICKER_ORIENTATIONS.includes(value) ? value : 'any';
63
+ }
64
+ /** The library a request names, or `null` when it names none, or both. */ export function stockPhotoTargetOf(body) {
65
+ const record = body != null ? body : {};
66
+ const hostId = record['hostId'];
67
+ const orgId = record['orgId'];
68
+ const hasHost = hostId !== undefined && hostId !== null && hostId !== '';
69
+ const hasOrg = orgId !== undefined && orgId !== null && orgId !== '';
70
+ if (hasHost === hasOrg) return null;
71
+ if (hasHost) return isDocumentId(hostId) ? {
72
+ hostId
73
+ } : null;
74
+ return isDocumentId(orgId) ? {
75
+ orgId
76
+ } : null;
77
+ }
78
+ /** The photo a request names, or `null` when it is not one a search could have found. */ export function stockPhotoHitRefOf(value) {
79
+ const record = value != null ? value : {};
80
+ const query = normalizeStockPhotoQuery(record['query']);
81
+ const id = record['id'];
82
+ if (!query || typeof id !== 'string' || !id || id.length > MAX_ID_CHARS || !/^[\w.-]+$/.test(id)) return null;
83
+ return {
84
+ query,
85
+ orientation: stockPhotoOrientationOf(record['orientation']),
86
+ id
87
+ };
88
+ }
89
+ /** `value` when it is an https address, else `undefined`: nothing else is ever linked. */ export function stockPhotoSafeLink(value) {
90
+ if (typeof value !== 'string') return undefined;
91
+ try {
92
+ const url = new URL(value);
93
+ return url.protocol === 'https:' && !url.username && !url.password ? url.toString() : undefined;
94
+ } catch (unused) {
95
+ return undefined;
96
+ }
97
+ }
98
+ /** The fields of a stored media document the picker hands on, from the document. */ export function stockPhotoPickerMediaOf(mediaId, data) {
99
+ const text = (key)=>typeof data[key] === 'string' ? data[key] : undefined;
100
+ const count = (key)=>typeof data[key] === 'number' && Number.isFinite(data[key]) ? data[key] : undefined;
101
+ const list = (key, keep)=>Array.isArray(data[key]) ? data[key].filter(keep) : undefined;
102
+ const media = {
103
+ $id: mediaId
104
+ };
105
+ const fields = {
106
+ fileName: text('fileName'),
107
+ contentType: text('contentType'),
108
+ sizeBytes: count('sizeBytes'),
109
+ url: text('url'),
110
+ cdnPath: text('cdnPath'),
111
+ alt: text('alt'),
112
+ description: text('description'),
113
+ width: count('width'),
114
+ height: count('height'),
115
+ variants: list('variants', (item)=>typeof item === 'number'),
116
+ visibleTo: list('visibleTo', (item)=>typeof item === 'string')
117
+ };
118
+ for (const [key, value] of Object.entries(fields)){
119
+ if (value !== undefined) media[key] = value;
120
+ }
121
+ if (typeof data['folderId'] === 'string' || data['folderId'] === null) media.folderId = data['folderId'];
122
+ return media;
123
+ }
124
+ /** Said when a request failed before the server could answer it. */ const UNREACHABLE = 'Stock photos could not be reached. Check your connection and try again.';
125
+ /** What a refusal says: the route's own words, else `fallback`. */ async function refusalOf(response, fallback) {
126
+ const body = await response.json().catch(()=>null);
127
+ const said = typeof (body == null ? void 0 : body.message) === 'string' ? body.message : typeof (body == null ? void 0 : body.error) === 'string' ? body.error : '';
128
+ return {
129
+ status: 'refused',
130
+ message: said || fallback
131
+ };
132
+ }
133
+ /** The JSON answer of a request, or a refusal that says why there is none. */ async function answerOf(request) {
134
+ let response;
135
+ try {
136
+ response = await request();
137
+ } catch (unused) {
138
+ return {
139
+ status: 'refused',
140
+ message: UNREACHABLE
141
+ };
142
+ }
143
+ if (!response.ok) return refusalOf(response, UNREACHABLE);
144
+ const body = await response.json().catch(()=>null);
145
+ return body && typeof body.status === 'string' ? body : {
146
+ status: 'refused',
147
+ message: UNREACHABLE
148
+ };
149
+ }
150
+ /**
151
+ * The client for one library. `post` carries the member's credentials: the
152
+ * console hands in `authorizedFetch` bound to the route.
153
+ */ export function createStockPhotoPickerClient(post, target) {
154
+ const library = target.hostId ? {
155
+ hostId: target.hostId
156
+ } : {
157
+ orgId: target.orgId
158
+ };
159
+ return {
160
+ status: ()=>answerOf(()=>post(_extends({
161
+ action: 'status'
162
+ }, library))),
163
+ search: (query, orientation)=>answerOf(()=>post(_extends({
164
+ action: 'search'
165
+ }, library, {
166
+ query,
167
+ orientation
168
+ }))),
169
+ async preview (ref) {
170
+ try {
171
+ const response = await post(_extends({
172
+ action: 'preview'
173
+ }, library, {
174
+ ref
175
+ }));
176
+ if (response.status !== 200) return null;
177
+ const blob = await response.blob();
178
+ return blob.size && blob.type.startsWith('image/') ? blob : null;
179
+ } catch (unused) {
180
+ return null;
181
+ }
182
+ },
183
+ importPhoto: (ref, options)=>answerOf(()=>post(_extends({
184
+ action: 'import'
185
+ }, library, {
186
+ ref
187
+ }, (options == null ? void 0 : options.folderId) ? {
188
+ folderId: options.folderId
189
+ } : {})))
190
+ };
191
+ }
192
+
193
+ //# sourceMappingURL=stock-photo-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/aglyn/src/lib/app-utils/stock-photos/stock-photo-picker.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n STOCK_PHOTO_QUERY_MAX_CHARS,\n type StockPhotoOrientation,\n} from '../../plugin-manager/stock-photo-provider'\n\n/**\n * STOCK PHOTOS IN THE MEDIA PICKER (AGL-4066): the wire between the\n * console's media picker and its server route, `/api/media/stock-photos`.\n *\n * A person editing a site by hand searches the deployment's stock photo\n * library from the picker's Stock photos tab and places one. The route asks\n * core's `core.stock-photos` provider and copies the chosen photo into the\n * library the picker is filing into through `core.media-ingest`, as the\n * signed-in member; the placed image is always that copy, never an address\n * at the library. This module is the shapes both sides agree on, the checks\n * the server makes on what a browser sends, and the browser's client. It\n * names no library: the provider's own label comes back in every answer.\n *\n * Every request names one library, the target: a site's (`hostId`) or the\n * workspace's shared one (`orgId`). A hit is named back to the server by\n * {@link StockPhotoHitRef} — the search that found it and its id — never by\n * the addresses or the credit, so the server finds the photo again in the\n * provider's own cached answer and nothing a browser claims about a photo\n * is stored.\n */\n\n/** The console route the picker's Stock photos tab talks to. */\nexport const STOCK_PHOTO_PICKER_ROUTE = '/api/media/stock-photos'\n\n/** The library a request searches for and copies into. */\nexport type StockPhotoPickerTarget = { hostId: string; orgId?: undefined } | { orgId: string; hostId?: undefined }\n\n/** The orientations the tab offers, in its order. */\nexport const STOCK_PHOTO_PICKER_ORIENTATIONS: readonly StockPhotoOrientation[] = ['any', 'horizontal', 'vertical']\n\n/** How a search result names its photo back to the server. */\nexport interface StockPhotoHitRef {\n /** The search words exactly as searched, after {@link normalizeStockPhotoQuery}. */\n query: string\n orientation: StockPhotoOrientation\n /** The library's own id for the photo. */\n id: string\n}\n\n/** One photo a search found, as the tab shows it. */\nexport interface StockPhotoPickerHit {\n ref: StockPhotoHitRef\n /** `{provider}:{id}`: what the library reuses an earlier copy by. */\n sourceKey: string\n /** The size of the copy that is stored when the photo is used. */\n width: number\n height: number\n photographer: string\n photographerUrl?: string\n /** The photo's page at the library. */\n pageUrl: string\n /** The library's tags, a few, lowercase. */\n tags: string[]\n /** The library's own description of the photo, where it writes one. */\n alt?: string\n /** The sentence the stored copy's description carries: \"Photo by … on …\". */\n credit: string\n license: string\n licenseUrl: string\n attributionRequired: boolean\n}\n\n/** The library the deployment searches, by the name its terms ask for. */\nexport interface StockPhotoPickerLibrary {\n label: string\n}\n\n/** What the tab is told when it opens. */\nexport type StockPhotoStatusAnswer =\n | { status: 'ready'; library: StockPhotoPickerLibrary }\n | { status: 'unconfigured'; message: string }\n | { status: 'refused'; message: string }\n\n/** What a search answers. `busy`: the library could not be asked just now. */\nexport type StockPhotoSearchAnswer =\n | { status: 'ok'; library: StockPhotoPickerLibrary; query: string; orientation: StockPhotoOrientation; hits: StockPhotoPickerHit[] }\n | { status: 'busy'; message: string }\n | { status: 'unconfigured'; message: string }\n | { status: 'refused'; message: string }\n\n/**\n * A stored asset as the picker places it: the media document's own fields,\n * the ones a library pick hands on.\n */\nexport interface StockPhotoPickerMedia {\n $id: string\n fileName?: string\n contentType?: string\n sizeBytes?: number\n url?: string\n cdnPath?: string\n folderId?: string | null\n alt?: string\n description?: string\n width?: number\n height?: number\n variants?: number[]\n visibleTo?: string[]\n}\n\n/** What using a photo answers. `reused`: the library already held a copy, which is placed. */\nexport type StockPhotoImportAnswer =\n | { status: 'ok'; reused: boolean; media: StockPhotoPickerMedia }\n | { status: 'busy'; message: string }\n | { status: 'gone'; message: string }\n | { status: 'unconfigured'; message: string }\n | { status: 'refused'; message: string }\n\n/** Said when the deployment has no stock photo library. */\nexport const STOCK_PHOTOS_UNCONFIGURED_MESSAGE =\n 'Stock photos are not set up here, so there is no library to search. ' +\n 'You can still upload your own photos in the library tabs.'\n\n/** Said when the library could not be asked, or could not send a photo, just now. */\nexport function stockPhotosBusyMessage(label: string): string {\n return `${label || 'The stock photo library'} is busy right now. Try again in a minute.`\n}\n\n/** Said when the photo is no longer among the search's results. */\nexport const STOCK_PHOTO_GONE_MESSAGE =\n 'That photo is no longer in the search results. Search again and choose it from the new results.'\n\n/** The longest id a library may give a photo here. */\nconst MAX_ID_CHARS = 64\n\n/** A library id: a site's or a workspace's document id, never a path. */\nconst isDocumentId = (value: unknown): value is string =>\n typeof value === 'string' && value.length > 0 && value.length <= 128 && !value.includes('/') && value.trim() === value\n\n/**\n * The search words as searched: control characters dropped, runs of space\n * made one, trimmed. `null` when nothing is left or it is longer than\n * {@link STOCK_PHOTO_QUERY_MAX_CHARS}.\n */\nexport function normalizeStockPhotoQuery(value: unknown): string | null {\n if (typeof value !== 'string') return null\n // eslint-disable-next-line no-control-regex\n const query = value.replace(/[\\u0000-\\u001f\\u007f]/g, ' ').replace(/\\s+/g, ' ').trim()\n if (!query || query.length > STOCK_PHOTO_QUERY_MAX_CHARS) return null\n return query\n}\n\n/** An orientation the tab offers, `any` for anything else. */\nexport function stockPhotoOrientationOf(value: unknown): StockPhotoOrientation {\n return STOCK_PHOTO_PICKER_ORIENTATIONS.includes(value as StockPhotoOrientation)\n ? (value as StockPhotoOrientation)\n : 'any'\n}\n\n/** The library a request names, or `null` when it names none, or both. */\nexport function stockPhotoTargetOf(body: unknown): StockPhotoPickerTarget | null {\n const record = (body ?? {}) as Record<string, unknown>\n const hostId = record['hostId']\n const orgId = record['orgId']\n const hasHost = hostId !== undefined && hostId !== null && hostId !== ''\n const hasOrg = orgId !== undefined && orgId !== null && orgId !== ''\n if (hasHost === hasOrg) return null\n if (hasHost) return isDocumentId(hostId) ? { hostId } : null\n return isDocumentId(orgId) ? { orgId } : null\n}\n\n/** The photo a request names, or `null` when it is not one a search could have found. */\nexport function stockPhotoHitRefOf(value: unknown): StockPhotoHitRef | null {\n const record = (value ?? {}) as Record<string, unknown>\n const query = normalizeStockPhotoQuery(record['query'])\n const id = record['id']\n if (!query || typeof id !== 'string' || !id || id.length > MAX_ID_CHARS || !/^[\\w.-]+$/.test(id)) return null\n return { query, orientation: stockPhotoOrientationOf(record['orientation']), id }\n}\n\n/** `value` when it is an https address, else `undefined`: nothing else is ever linked. */\nexport function stockPhotoSafeLink(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n try {\n const url = new URL(value)\n return url.protocol === 'https:' && !url.username && !url.password ? url.toString() : undefined\n } catch {\n return undefined\n }\n}\n\n/** The fields of a stored media document the picker hands on, from the document. */\nexport function stockPhotoPickerMediaOf(mediaId: string, data: Record<string, unknown>): StockPhotoPickerMedia {\n const text = (key: string) => (typeof data[key] === 'string' ? (data[key] as string) : undefined)\n const count = (key: string) => (typeof data[key] === 'number' && Number.isFinite(data[key]) ? (data[key] as number) : undefined)\n const list = <T>(key: string, keep: (item: unknown) => item is T): T[] | undefined =>\n Array.isArray(data[key]) ? (data[key] as unknown[]).filter(keep) : undefined\n const media: StockPhotoPickerMedia = { $id: mediaId }\n const fields: Partial<StockPhotoPickerMedia> = {\n fileName: text('fileName'),\n contentType: text('contentType'),\n sizeBytes: count('sizeBytes'),\n url: text('url'),\n cdnPath: text('cdnPath'),\n alt: text('alt'),\n description: text('description'),\n width: count('width'),\n height: count('height'),\n variants: list('variants', (item): item is number => typeof item === 'number'),\n visibleTo: list('visibleTo', (item): item is string => typeof item === 'string'),\n }\n for (const [key, value] of Object.entries(fields)) {\n if (value !== undefined) (media as unknown as Record<string, unknown>)[key] = value\n }\n if (typeof data['folderId'] === 'string' || data['folderId'] === null) media.folderId = data['folderId'] as string | null\n return media\n}\n\n/** Posts one JSON request to the route, with whatever credentials the caller adds. */\nexport type StockPhotoPickerPost = (body: Record<string, unknown>) => Promise<Response>\n\n/** The browser's side of the route, for one library. */\nexport interface StockPhotoPickerClient {\n status(): Promise<StockPhotoStatusAnswer>\n search(query: string, orientation: StockPhotoOrientation): Promise<StockPhotoSearchAnswer>\n /** The hit's small copy, or `null` when none can be had. */\n preview(ref: StockPhotoHitRef): Promise<Blob | null>\n /** Copies the photo into the library, or finds the copy it holds. */\n importPhoto(ref: StockPhotoHitRef, options?: { folderId?: string | null }): Promise<StockPhotoImportAnswer>\n}\n\n/** Said when a request failed before the server could answer it. */\nconst UNREACHABLE = 'Stock photos could not be reached. Check your connection and try again.'\n\n/** What a refusal says: the route's own words, else `fallback`. */\nasync function refusalOf(response: Response, fallback: string): Promise<{ status: 'refused'; message: string }> {\n const body = (await response.json().catch((): null => null)) as { message?: unknown; error?: unknown } | null\n const said = typeof body?.message === 'string' ? body.message : typeof body?.error === 'string' ? body.error : ''\n return { status: 'refused', message: said || fallback }\n}\n\n/** The JSON answer of a request, or a refusal that says why there is none. */\nasync function answerOf<Answer>(request: () => Promise<Response>): Promise<Answer | { status: 'refused'; message: string }> {\n let response: Response\n try {\n response = await request()\n } catch {\n return { status: 'refused', message: UNREACHABLE }\n }\n if (!response.ok) return refusalOf(response, UNREACHABLE)\n const body = (await response.json().catch((): null => null)) as Answer | null\n return body && typeof (body as { status?: unknown }).status === 'string' ? body : { status: 'refused', message: UNREACHABLE }\n}\n\n/**\n * The client for one library. `post` carries the member's credentials: the\n * console hands in `authorizedFetch` bound to the route.\n */\nexport function createStockPhotoPickerClient(\n post: StockPhotoPickerPost,\n target: StockPhotoPickerTarget,\n): StockPhotoPickerClient {\n const library = target.hostId ? { hostId: target.hostId } : { orgId: target.orgId }\n return {\n status: () => answerOf<StockPhotoStatusAnswer>(() => post({ action: 'status', ...library })),\n search: (query, orientation) =>\n answerOf<StockPhotoSearchAnswer>(() => post({ action: 'search', ...library, query, orientation })),\n async preview(ref) {\n try {\n const response = await post({ action: 'preview', ...library, ref })\n if (response.status !== 200) return null\n const blob = await response.blob()\n return blob.size && blob.type.startsWith('image/') ? blob : null\n } catch {\n return null\n }\n },\n importPhoto: (ref, options) =>\n answerOf<StockPhotoImportAnswer>(() =>\n post({\n action: 'import',\n ...library,\n ref,\n ...(options?.folderId ? { folderId: options.folderId } : {}),\n }),\n ),\n }\n}\n"],"names":["STOCK_PHOTO_QUERY_MAX_CHARS","STOCK_PHOTO_PICKER_ROUTE","STOCK_PHOTO_PICKER_ORIENTATIONS","STOCK_PHOTOS_UNCONFIGURED_MESSAGE","stockPhotosBusyMessage","label","STOCK_PHOTO_GONE_MESSAGE","MAX_ID_CHARS","isDocumentId","value","length","includes","trim","normalizeStockPhotoQuery","query","replace","stockPhotoOrientationOf","stockPhotoTargetOf","body","record","hostId","orgId","hasHost","undefined","hasOrg","stockPhotoHitRefOf","id","test","orientation","stockPhotoSafeLink","url","URL","protocol","username","password","toString","stockPhotoPickerMediaOf","mediaId","data","text","key","count","Number","isFinite","list","keep","Array","isArray","filter","media","$id","fields","fileName","contentType","sizeBytes","cdnPath","alt","description","width","height","variants","item","visibleTo","Object","entries","folderId","UNREACHABLE","refusalOf","response","fallback","json","catch","said","message","error","status","answerOf","request","ok","createStockPhotoPickerClient","post","target","library","action","search","preview","ref","blob","size","type","startsWith","importPhoto","options"],"mappings":"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"}
@@ -19,9 +19,11 @@ import type { OrgPermissions } from '../app-utils/org-permissions';
19
19
  import type { ReleaseFlagKey } from '../app-utils/release-flags';
20
20
  import type { SeoAuditReport } from '../app-utils/seo-audit';
21
21
  import type { SeoListingFieldKey } from '../app-utils/seo-listing-fields';
22
+ import type { SiteStarterFacets, SiteStarterMode } from '../app-utils/site-starter';
22
23
  import type { AglynOrgBilling, OrgFeatureFlags } from '../foundation';
23
24
  import type { ComponentSchema, MdiIconProps, PresetSchema } from '../types/nodes';
24
25
  import type { Plugin, PluginId } from './plugin-manager';
26
+ import type { SiteStarterSummary } from './plugin-site-starters';
25
27
  import type { HostThemeSource } from '../app-utils/site-theme';
26
28
  import type { HostTheme, HostThemeScheme } from '@aglyn/shared-data-types';
27
29
  import type { ComponentType, ReactNode } from 'react';
@@ -800,6 +802,19 @@ export declare const CONSOLE_WIDGET_SLOTS: {
800
802
  * gets the shell's plain name-and-address dialog instead.
801
803
  */
802
804
  readonly hostFirstRun: "hostFirstRun";
805
+ /**
806
+ * The starter picker inside "Start your site" (AGL-4049), drawn before the
807
+ * site exists. Props: {@link ConsoleHostStarterPickerZoneProps} — the
808
+ * workspace, how the site will be filled, the person's search and filter,
809
+ * `onPick` and `ready`.
810
+ *
811
+ * A pick is required: there is no Skip, and the listing the platform starts
812
+ * a site from by default comes first. A widget here lists and picks and
813
+ * creates nothing; the site is created by the dialog from the starter it was
814
+ * handed. Not a staff zone and not host-gated: the widget's own extension
815
+ * gates it, as on any other zone.
816
+ */
817
+ readonly hostStarterPicker: "hostStarterPicker";
803
818
  /**
804
819
  * The host setup Theme section, between the Theme picker and the editor
805
820
  * (AGL-2938). Props: {@link ConsoleHostThemeZoneProps} — the
@@ -1512,6 +1527,23 @@ export interface ConsoleArtifactPublishZoneProps {
1512
1527
  /** Closes it, however it was closed — cancelled, published, or refused. */
1513
1528
  onClose: () => void;
1514
1529
  }
1530
+ /** What the `hostStarterPicker` zone hands each widget (AGL-4049). */
1531
+ export interface ConsoleHostStarterPickerZoneProps {
1532
+ /** The org the site will belong to; `undefined` while it resolves. */
1533
+ orgId: string | undefined;
1534
+ /** Path slug for building `/[orgSlug]/…` links. */
1535
+ orgSlug: string;
1536
+ /** How the site will be filled: its pages as they are, or by the AI site start. */
1537
+ mode: SiteStarterMode;
1538
+ /** The person's search words, as typed. */
1539
+ search: string;
1540
+ /** The facets the person narrowed to; an absent one is any. */
1541
+ filter: Partial<SiteStarterFacets>;
1542
+ /** Hands the dialog the starter the person picked. */
1543
+ onPick: (pick: SiteStarterSummary) => void;
1544
+ /** Reports whether the widget drew a picker; `false` gives the dialog its own default. */
1545
+ ready: (shown: boolean) => void;
1546
+ }
1515
1547
  /** What the `hostTheme` zone hands each widget (AGL-2938). */
1516
1548
  export interface ConsoleHostThemeZoneProps {
1517
1549
  hostId: string;
@@ -295,6 +295,18 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
295
295
  * gets the shell's plain name-and-address dialog instead.
296
296
  */ hostFirstRun: 'hostFirstRun',
297
297
  /**
298
+ * The starter picker inside "Start your site" (AGL-4049), drawn before the
299
+ * site exists. Props: {@link ConsoleHostStarterPickerZoneProps} — the
300
+ * workspace, how the site will be filled, the person's search and filter,
301
+ * `onPick` and `ready`.
302
+ *
303
+ * A pick is required: there is no Skip, and the listing the platform starts
304
+ * a site from by default comes first. A widget here lists and picks and
305
+ * creates nothing; the site is created by the dialog from the starter it was
306
+ * handed. Not a staff zone and not host-gated: the widget's own extension
307
+ * gates it, as on any other zone.
308
+ */ hostStarterPicker: 'hostStarterPicker',
309
+ /**
298
310
  * The host setup Theme section, between the Theme picker and the editor
299
311
  * (AGL-2938). Props: {@link ConsoleHostThemeZoneProps} — the
300
312
  * site, the theme the editor shows, where that theme came from, the