@adminide-stack/yantra-mobile 12.0.108 → 12.0.109

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/lib/compute.js +57 -1
  2. package/lib/compute.js.map +1 -1
  3. package/lib/config/env-config.js +8 -0
  4. package/lib/config/env-config.js.map +1 -1
  5. package/lib/features/apps/AppsCatalog.js +10 -0
  6. package/lib/features/apps/AppsCatalog.js.map +1 -1
  7. package/lib/features/apps/appArt.js +2 -1
  8. package/lib/features/apps/appArt.js.map +1 -1
  9. package/lib/features/apps/mobileAppCatalog.js +11 -0
  10. package/lib/features/apps/mobileAppCatalog.js.map +1 -1
  11. package/lib/features/apps/nativeAppHandoff.js +2 -1
  12. package/lib/features/apps/nativeAppHandoff.js.map +1 -1
  13. package/lib/features/health/healthSyncStore.js +7 -1
  14. package/lib/features/health/healthSyncStore.js.map +1 -1
  15. package/lib/features/messaging/useChatViewer.js +3 -2
  16. package/lib/features/messaging/useChatViewer.js.map +1 -1
  17. package/lib/features/webbuilder/WebBuilderExperience.js +474 -0
  18. package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -0
  19. package/lib/features/webbuilder/brandKitStorage.js +69 -0
  20. package/lib/features/webbuilder/brandKitStorage.js.map +1 -0
  21. package/lib/features/webbuilder/buildFragments.js +360 -0
  22. package/lib/features/webbuilder/buildFragments.js.map +1 -0
  23. package/lib/features/webbuilder/components/BottomTabs.js +65 -0
  24. package/lib/features/webbuilder/components/BottomTabs.js.map +1 -0
  25. package/lib/features/webbuilder/components/BrandKitSheet.js +197 -0
  26. package/lib/features/webbuilder/components/BrandKitSheet.js.map +1 -0
  27. package/lib/features/webbuilder/components/CodeView.js +99 -0
  28. package/lib/features/webbuilder/components/CodeView.js.map +1 -0
  29. package/lib/features/webbuilder/components/Composer.js +217 -0
  30. package/lib/features/webbuilder/components/Composer.js.map +1 -0
  31. package/lib/features/webbuilder/components/PreviewFrame.js +72 -0
  32. package/lib/features/webbuilder/components/PreviewFrame.js.map +1 -0
  33. package/lib/features/webbuilder/components/PreviewPlaceholder.js +107 -0
  34. package/lib/features/webbuilder/components/PreviewPlaceholder.js.map +1 -0
  35. package/lib/features/webbuilder/components/PreviewScreen.js +200 -0
  36. package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -0
  37. package/lib/features/webbuilder/components/ProjectChat.js +580 -0
  38. package/lib/features/webbuilder/components/ProjectChat.js.map +1 -0
  39. package/lib/features/webbuilder/components/ProjectsScreen.js +339 -0
  40. package/lib/features/webbuilder/components/ProjectsScreen.js.map +1 -0
  41. package/lib/features/webbuilder/components/PublishSheet.js +143 -0
  42. package/lib/features/webbuilder/components/PublishSheet.js.map +1 -0
  43. package/lib/features/webbuilder/components/SiteScoreSheet.js +73 -0
  44. package/lib/features/webbuilder/components/SiteScoreSheet.js.map +1 -0
  45. package/lib/features/webbuilder/components/StudioHome.js +367 -0
  46. package/lib/features/webbuilder/components/StudioHome.js.map +1 -0
  47. package/lib/features/webbuilder/components/TemplateCard.js +73 -0
  48. package/lib/features/webbuilder/components/TemplateCard.js.map +1 -0
  49. package/lib/features/webbuilder/components/TemplatesSheet.js +178 -0
  50. package/lib/features/webbuilder/components/TemplatesSheet.js.map +1 -0
  51. package/lib/features/webbuilder/components/VersionsSheet.js +57 -0
  52. package/lib/features/webbuilder/components/VersionsSheet.js.map +1 -0
  53. package/lib/features/webbuilder/components/ui.js +291 -0
  54. package/lib/features/webbuilder/components/ui.js.map +1 -0
  55. package/lib/features/webbuilder/nativeWebBuilderRegistry.js +15 -0
  56. package/lib/features/webbuilder/nativeWebBuilderRegistry.js.map +1 -0
  57. package/lib/features/webbuilder/studioCatalog.js +147 -0
  58. package/lib/features/webbuilder/studioCatalog.js.map +1 -0
  59. package/lib/features/webbuilder/webbuilderPrompts.js +42 -0
  60. package/lib/features/webbuilder/webbuilderPrompts.js.map +1 -0
  61. package/lib/features/webbuilder/webbuilderTheme.js +63 -0
  62. package/lib/features/webbuilder/webbuilderTheme.js.map +1 -0
  63. package/lib/features/webbuilder/workflow.js +540 -0
  64. package/lib/features/webbuilder/workflow.js.map +1 -0
  65. package/lib/hooks/useChatApi.js +7 -2
  66. package/lib/hooks/useChatApi.js.map +1 -1
  67. package/lib/hooks/useChatStream.js +1 -1
  68. package/lib/hooks/useChatStream.js.map +1 -1
  69. package/lib/index.js +1 -1
  70. package/lib/index.js.map +1 -1
  71. package/lib/routes.json +106 -0
  72. package/lib/screens/WebBuilderNative/index.js +71 -0
  73. package/lib/screens/WebBuilderNative/index.js.map +1 -0
  74. package/lib/screens/WebBuilderNative/useCodeAssistantCatalog.js +45 -0
  75. package/lib/screens/WebBuilderNative/useCodeAssistantCatalog.js.map +1 -0
  76. package/lib/screens/WebBuilderNative/useWebBuilderGallery.js +125 -0
  77. package/lib/screens/WebBuilderNative/useWebBuilderGallery.js.map +1 -0
  78. package/lib/screens/WebBuilderNative/useWebBuilderHost.js +408 -0
  79. package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -0
  80. package/lib/screens/WebBuilderNative/webbuilderTransport.js +88 -0
  81. package/lib/screens/WebBuilderNative/webbuilderTransport.js.map +1 -0
  82. package/package.json +4 -4
@@ -0,0 +1,45 @@
1
+ import {useMemo}from'react';import {useSettings}from'@adminide-stack/platform-client';import {ConfigurationTarget,ContributionSchemaId}from'common';import {settingsUriForOrg}from'../../utils/cdecodeUri.js';import {CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,APP_SETTINGS_AIEDITOR_KEY,templatesFromSettings,workflowDefaultsFromSettings,FALLBACK_TEMPLATES}from'../../features/webbuilder/workflow.js';function useCodeAssistantCatalog(orgName) {
2
+ const slug = orgName.trim();
3
+ const resourceUri = useMemo(() => slug ? settingsUriForOrg(slug) : void 0, [slug]);
4
+ const ui = useSettings({
5
+ resourceUri,
6
+ skip: !resourceUri,
7
+ options: {
8
+ schemaId: ContributionSchemaId.UiLayout,
9
+ configKey: CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,
10
+ includeMarketplace: true,
11
+ target: ConfigurationTarget.ORGANIZATION
12
+ }
13
+ });
14
+ const app = useSettings({
15
+ resourceUri,
16
+ skip: !resourceUri,
17
+ options: {
18
+ schemaId: ContributionSchemaId.Configuration,
19
+ configKey: APP_SETTINGS_AIEDITOR_KEY,
20
+ includeMarketplace: true,
21
+ target: ConfigurationTarget.ORGANIZATION
22
+ }
23
+ });
24
+ const uiPayload = ui.settings;
25
+ const appPayload = app.settings;
26
+ const loading = Boolean(resourceUri) && (ui.loading || app.loading);
27
+ const loaded = Boolean(resourceUri) && !ui.loading && !app.loading;
28
+ const error = ui.error ? "Check your connection and try again." : null;
29
+ return useMemo(() => {
30
+ const remote = loaded ? templatesFromSettings(uiPayload, appPayload) : [];
31
+ return {
32
+ // The web falls back to its bundled starters only when the workspace has none.
33
+ templates: loaded && !error && remote.length === 0 ? FALLBACK_TEMPLATES : remote,
34
+ defaults: loaded ? workflowDefaultsFromSettings(uiPayload, appPayload) : null,
35
+ loading,
36
+ loaded,
37
+ error,
38
+ reload: () => {
39
+ var _a, _b;
40
+ (_a = ui.observable) == null ? void 0 : _a.refetch().catch(() => void 0);
41
+ (_b = app.observable) == null ? void 0 : _b.refetch().catch(() => void 0);
42
+ }
43
+ };
44
+ }, [uiPayload, appPayload, loaded, loading, error]);
45
+ }export{useCodeAssistantCatalog};//# sourceMappingURL=useCodeAssistantCatalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCodeAssistantCatalog.js","sources":["../../../src/screens/WebBuilderNative/useCodeAssistantCatalog.ts"],"sourcesContent":["/**\n * The workspace's starter templates and its build workflow model - the web\n * surface's `listCodeAssistantTemplatesViaGraphql`, read from the backend the\n * app is signed in to (the same `pageSettings` Home's Build mode reads), so the\n * phone shows what the web shows for the workspace: in local development both\n * read the local backend, in production both read the plane's.\n */\nimport { useMemo } from 'react';\nimport { useSettings } from '@adminide-stack/platform-client';\nimport { ConfigurationTarget, ContributionSchemaId } from 'common';\nimport { settingsUriForOrg, type SettingsUriInput } from '../../utils/cdecodeUri';\nimport {\n APP_SETTINGS_AIEDITOR_KEY,\n CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,\n FALLBACK_TEMPLATES,\n templatesFromSettings,\n workflowDefaultsFromSettings,\n type WebBuilderTemplate,\n} from '../../features/webbuilder/workflow';\n\nexport interface CodeAssistantCatalog {\n templates: WebBuilderTemplate[];\n /** The org's workflow model (form extension, E2B template ids) for builds without a template. */\n defaults: WebBuilderTemplate | null;\n loading: boolean;\n loaded: boolean;\n error: string | null;\n reload: () => void;\n}\n\nexport function useCodeAssistantCatalog(orgName: string): CodeAssistantCatalog {\n const slug = orgName.trim();\n const resourceUri: SettingsUriInput | undefined = useMemo(\n () => (slug ? settingsUriForOrg(slug) : undefined),\n [slug],\n );\n const ui = useSettings({\n resourceUri: resourceUri as never,\n skip: !resourceUri,\n options: {\n schemaId: ContributionSchemaId.UiLayout,\n configKey: CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,\n includeMarketplace: true,\n target: ConfigurationTarget.ORGANIZATION,\n },\n });\n const app = useSettings({\n resourceUri: resourceUri as never,\n skip: !resourceUri,\n options: {\n schemaId: ContributionSchemaId.Configuration,\n configKey: APP_SETTINGS_AIEDITOR_KEY,\n includeMarketplace: true,\n target: ConfigurationTarget.ORGANIZATION,\n },\n });\n\n // `settings` is the raw `pageSettings.settings` payload - what the web parses.\n const uiPayload = ui.settings;\n const appPayload = app.settings;\n const loading = Boolean(resourceUri) && (ui.loading || app.loading);\n const loaded = Boolean(resourceUri) && !ui.loading && !app.loading;\n const error = ui.error ? 'Check your connection and try again.' : null;\n\n return useMemo(() => {\n const remote = loaded ? templatesFromSettings(uiPayload, appPayload) : [];\n return {\n // The web falls back to its bundled starters only when the workspace has none.\n templates: loaded && !error && remote.length === 0 ? FALLBACK_TEMPLATES : remote,\n defaults: loaded ? workflowDefaultsFromSettings(uiPayload, appPayload) : null,\n loading,\n loaded,\n error,\n reload: () => {\n ui.observable?.refetch().catch(() => undefined);\n app.observable?.refetch().catch(() => undefined);\n },\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uiPayload, appPayload, loaded, loading, error]);\n}\n"],"names":[],"mappings":"qYAqBO,SAAS,wBAAwB,OAAuC,EAAA;AAC7E,EAAM,MAAA,IAAA,GAAO,QAAQ,IAAK,EAAA;AAC1B,EAAM,MAAA,WAAA,GAA4C,OAAQ,CAAA,MAAM,IAAO,GAAA,iBAAA,CAAkB,IAAI,CAAI,GAAA,MAAA,EAAW,CAAC,IAAI,CAAC,CAAA;AAClH,EAAA,MAAM,KAAK,WAAY,CAAA;AAAA,IACrB,WAAA;AAAA,IACA,MAAM,CAAC,WAAA;AAAA,IACP,OAAS,EAAA;AAAA,MACP,UAAU,oBAAqB,CAAA,QAAA;AAAA,MAC/B,SAAW,EAAA,kCAAA;AAAA,MACX,kBAAoB,EAAA,IAAA;AAAA,MACpB,QAAQ,mBAAoB,CAAA;AAAA;AAC9B,GACD,CAAA;AACD,EAAA,MAAM,MAAM,WAAY,CAAA;AAAA,IACtB,WAAA;AAAA,IACA,MAAM,CAAC,WAAA;AAAA,IACP,OAAS,EAAA;AAAA,MACP,UAAU,oBAAqB,CAAA,aAAA;AAAA,MAC/B,SAAW,EAAA,yBAAA;AAAA,MACX,kBAAoB,EAAA,IAAA;AAAA,MACpB,QAAQ,mBAAoB,CAAA;AAAA;AAC9B,GACD,CAAA;AAGD,EAAA,MAAM,YAAY,EAAG,CAAA,QAAA;AACrB,EAAA,MAAM,aAAa,GAAI,CAAA,QAAA;AACvB,EAAA,MAAM,UAAU,OAAQ,CAAA,WAAW,CAAM,KAAA,EAAA,CAAG,WAAW,GAAI,CAAA,OAAA,CAAA;AAC3D,EAAM,MAAA,MAAA,GAAS,QAAQ,WAAW,CAAA,IAAK,CAAC,EAAG,CAAA,OAAA,IAAW,CAAC,GAAI,CAAA,OAAA;AAC3D,EAAM,MAAA,KAAA,GAAQ,EAAG,CAAA,KAAA,GAAQ,sCAAyC,GAAA,IAAA;AAClE,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,MAAM,SAAS,MAAS,GAAA,qBAAA,CAAsB,SAAW,EAAA,UAAU,IAAI,EAAC;AACxE,IAAO,OAAA;AAAA;AAAA,MAEL,WAAW,MAAU,IAAA,CAAC,SAAS,MAAO,CAAA,MAAA,KAAW,IAAI,kBAAqB,GAAA,MAAA;AAAA,MAC1E,QAAU,EAAA,MAAA,GAAS,4BAA6B,CAAA,SAAA,EAAW,UAAU,CAAI,GAAA,IAAA;AAAA,MACzE,OAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAQ,MAAM;AA5DpB,QAAA,IAAA,EAAA,EAAA,EAAA;AA6DQ,QAAA,CAAA,EAAA,GAAA,EAAA,CAAG,UAAH,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAe,OAAU,EAAA,CAAA,KAAA,CAAM,MAAM,MAAA,CAAA;AACrC,QAAA,CAAA,EAAA,GAAA,GAAA,CAAI,UAAJ,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAgB,OAAU,EAAA,CAAA,KAAA,CAAM,MAAM,MAAA,CAAA;AAAA;AACxC,KACF;AAAA,KAEC,CAAC,SAAA,EAAW,YAAY,MAAQ,EAAA,OAAA,EAAS,KAAK,CAAC,CAAA;AACpD"}
@@ -0,0 +1,125 @@
1
+ import {useState,useRef,useCallback,useEffect}from'react';import {useApolloClient}from'@apollo/client/index.js';import {MessagesDocument,GetChannelsByUserWithLastMessageDocument}from'common/graphql';import {getThreadMessagesQueryVariables,getHistoryChannelsQueryVariables}from'../../hooks/useChatApi.js';import {lastMessageHasCover,projectFromPosts}from'../../features/webbuilder/buildFragments.js';const GALLERY_PAGE_SIZE = 10;
2
+ const MIN_FILL = 6;
3
+ const MAX_PAGES_PER_LOAD = 4;
4
+ function useWebBuilderGallery(orgName, cdnOrigin) {
5
+ const client = useApolloClient();
6
+ const [projects, setProjects] = useState([]);
7
+ const [loading, setLoading] = useState(false);
8
+ const [loadingMore, setLoadingMore] = useState(false);
9
+ const [hasMore, setHasMore] = useState(false);
10
+ const [error, setError] = useState(null);
11
+ const skipRef = useRef(0);
12
+ const busyRef = useRef(false);
13
+ const runRef = useRef(0);
14
+ const projectFor = useCallback(async (channel) => {
15
+ var _a, _b, _c, _d;
16
+ const id = (_a = channel.id) != null ? _a : "";
17
+ if (!id) return null;
18
+ if (lastMessageHasCover(channel)) {
19
+ const fromLast = projectFromPosts(channel, [channel.lastMessage], cdnOrigin);
20
+ if (fromLast) return fromLast;
21
+ }
22
+ try {
23
+ const result = await client.query({
24
+ query: MessagesDocument,
25
+ variables: getThreadMessagesQueryVariables(id),
26
+ fetchPolicy: "network-only",
27
+ errorPolicy: "all",
28
+ context: {
29
+ cacheKey: `messages-list:${id}`
30
+ }
31
+ });
32
+ const posts = (_d = (_c = (_b = result.data) == null ? void 0 : _b.messages) == null ? void 0 : _c.data) != null ? _d : [];
33
+ const withLast = channel.lastMessage ? [...posts, channel.lastMessage] : posts;
34
+ return projectFromPosts(channel, withLast, cdnOrigin);
35
+ } catch (err) {
36
+ console.warn("[WebBuilderNative] could not read builds of", id, err);
37
+ return null;
38
+ }
39
+ }, [client, cdnOrigin]);
40
+ const load = useCallback(async (mode) => {
41
+ var _a, _b;
42
+ if (!orgName || busyRef.current) return;
43
+ busyRef.current = true;
44
+ const run = runRef.current + 1;
45
+ runRef.current = run;
46
+ if (mode === "reset") {
47
+ skipRef.current = 0;
48
+ setLoading(true);
49
+ } else {
50
+ setLoadingMore(true);
51
+ }
52
+ setError(null);
53
+ const found = [];
54
+ let more = false;
55
+ try {
56
+ for (let page = 0; page < MAX_PAGES_PER_LOAD; page += 1) {
57
+ const result = await client.query({
58
+ query: GetChannelsByUserWithLastMessageDocument,
59
+ variables: getHistoryChannelsQueryVariables(orgName, {
60
+ limit: GALLERY_PAGE_SIZE,
61
+ skip: skipRef.current
62
+ }),
63
+ // cache-first served a stale first page on the web; always ask.
64
+ fetchPolicy: "network-only",
65
+ context: {
66
+ cacheKey: "webbuilder-gallery"
67
+ }
68
+ });
69
+ const channels = ((_b = (_a = result.data) == null ? void 0 : _a.channelsByUser) != null ? _b : []).filter((c) => c == null ? void 0 : c.id);
70
+ skipRef.current += channels.length;
71
+ more = channels.length >= GALLERY_PAGE_SIZE;
72
+ const rows = await Promise.all(channels.map((channel) => projectFor(channel)));
73
+ found.push(...rows.filter((row) => row !== null));
74
+ if (!more || found.length >= MIN_FILL) break;
75
+ }
76
+ if (runRef.current !== run) return;
77
+ setProjects((prev) => {
78
+ const base = mode === "reset" ? [] : prev;
79
+ const byId = new Map(base.map((p) => [p.channelId, p]));
80
+ for (const row of found) byId.set(row.channelId, row);
81
+ return [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);
82
+ });
83
+ setHasMore(more);
84
+ } catch (err) {
85
+ console.warn("[WebBuilderNative] could not load builds:", err);
86
+ if (runRef.current === run) setError("Check your connection and try again.");
87
+ } finally {
88
+ busyRef.current = false;
89
+ if (runRef.current === run) {
90
+ setLoading(false);
91
+ setLoadingMore(false);
92
+ }
93
+ }
94
+ }, [client, orgName, projectFor]);
95
+ useEffect(() => {
96
+ void load("reset");
97
+ }, [load]);
98
+ const refresh = useCallback(() => {
99
+ busyRef.current = false;
100
+ void load("reset");
101
+ }, [load]);
102
+ const loadMore = useCallback(() => {
103
+ if (hasMore) void load("more");
104
+ }, [hasMore, load]);
105
+ const upsert = useCallback((project) => {
106
+ setProjects((prev) => {
107
+ const existing = prev.find((p) => p.channelId === project.channelId);
108
+ if (existing && existing.title === project.title && existing.coverUrl === project.coverUrl && existing.liveUrl === project.liveUrl && existing.updatedAt === project.updatedAt) {
109
+ return prev;
110
+ }
111
+ const rest = prev.filter((p) => p.channelId !== project.channelId);
112
+ return [project, ...rest].sort((a, b) => b.updatedAt - a.updatedAt);
113
+ });
114
+ }, []);
115
+ return {
116
+ projects,
117
+ loading,
118
+ loadingMore,
119
+ hasMore,
120
+ error,
121
+ refresh,
122
+ loadMore,
123
+ upsert
124
+ };
125
+ }export{GALLERY_PAGE_SIZE,useWebBuilderGallery};//# sourceMappingURL=useWebBuilderGallery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebBuilderGallery.js","sources":["../../../src/screens/WebBuilderNative/useWebBuilderGallery.ts"],"sourcesContent":["/**\n * \"Recent builds\" - the web surface's gallery hydrate, on the host.\n *\n * Same steps as the web (`realServices` gallery load): page the person's AI\n * assistant chats 10 at a time, newest first; for each, read its posts (unless\n * the last post already carries the build's screenshot) and keep the chat only\n * if it holds a build. A chat that never built anything is not a site, which\n * is why history's \"build\" label alone is not used.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useApolloClient } from '@apollo/client';\nimport { GetChannelsByUserWithLastMessageDocument, MessagesDocument } from 'common/graphql';\nimport { getHistoryChannelsQueryVariables, getThreadMessagesQueryVariables } from '../../hooks/useChatApi';\nimport { lastMessageHasCover, projectFromPosts, type ChannelLike } from '../../features/webbuilder/buildFragments';\nimport type { WebBuilderProject } from '../../features/webbuilder/types';\n\n/** The web gallery's page size (`GALLERY_PAGE_SIZE`). */\nexport const GALLERY_PAGE_SIZE = 10;\n/** Keep paging (up to this many pages per call) while a page yields too few builds to fill the screen. */\nconst MIN_FILL = 6;\nconst MAX_PAGES_PER_LOAD = 4;\n\ntype Loose = Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n\nexport interface WebBuilderGallery {\n projects: WebBuilderProject[];\n loading: boolean;\n loadingMore: boolean;\n hasMore: boolean;\n error: string | null;\n refresh: () => void;\n loadMore: () => void;\n /** Put (or update) one site - the open one, as its posts change. */\n upsert: (project: WebBuilderProject) => void;\n}\n\nexport function useWebBuilderGallery(orgName: string, cdnOrigin: string): WebBuilderGallery {\n const client = useApolloClient();\n const [projects, setProjects] = useState<WebBuilderProject[]>([]);\n const [loading, setLoading] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const skipRef = useRef(0);\n const busyRef = useRef(false);\n const runRef = useRef(0);\n\n const projectFor = useCallback(\n async (channel: ChannelLike): Promise<WebBuilderProject | null> => {\n const id = channel.id ?? '';\n if (!id) return null;\n // The web skips the thread read only when the last post already has a cover.\n if (lastMessageHasCover(channel)) {\n const fromLast = projectFromPosts(channel, [channel.lastMessage], cdnOrigin);\n if (fromLast) return fromLast;\n }\n try {\n const result = await client.query({\n query: MessagesDocument,\n variables: getThreadMessagesQueryVariables(id),\n fetchPolicy: 'network-only',\n errorPolicy: 'all',\n context: { cacheKey: `messages-list:${id}` },\n });\n const posts = ((result.data as Loose)?.messages?.data ?? []) as unknown[];\n const withLast = channel.lastMessage ? [...posts, channel.lastMessage] : posts;\n return projectFromPosts(channel, withLast, cdnOrigin);\n } catch (err) {\n console.warn('[WebBuilderNative] could not read builds of', id, err);\n return null;\n }\n },\n [client, cdnOrigin],\n );\n\n const load = useCallback(\n async (mode: 'reset' | 'more') => {\n if (!orgName || busyRef.current) return;\n busyRef.current = true;\n const run = runRef.current + 1;\n runRef.current = run;\n if (mode === 'reset') {\n skipRef.current = 0;\n setLoading(true);\n } else {\n setLoadingMore(true);\n }\n setError(null);\n const found: WebBuilderProject[] = [];\n let more = false;\n try {\n for (let page = 0; page < MAX_PAGES_PER_LOAD; page += 1) {\n // eslint-disable-next-line no-await-in-loop -- pages are sequential by design\n const result = await client.query({\n query: GetChannelsByUserWithLastMessageDocument,\n variables: getHistoryChannelsQueryVariables(orgName, {\n limit: GALLERY_PAGE_SIZE,\n skip: skipRef.current,\n }),\n // cache-first served a stale first page on the web; always ask.\n fetchPolicy: 'network-only',\n context: { cacheKey: 'webbuilder-gallery' },\n });\n const channels = (((result.data as Loose)?.channelsByUser ?? []) as ChannelLike[]).filter(\n (c) => c?.id,\n );\n skipRef.current += channels.length;\n more = channels.length >= GALLERY_PAGE_SIZE;\n // eslint-disable-next-line no-await-in-loop\n const rows = await Promise.all(channels.map((channel) => projectFor(channel)));\n found.push(...rows.filter((row): row is WebBuilderProject => row !== null));\n if (!more || found.length >= MIN_FILL) break;\n }\n if (runRef.current !== run) return;\n setProjects((prev) => {\n const base = mode === 'reset' ? [] : prev;\n const byId = new Map(base.map((p) => [p.channelId, p]));\n for (const row of found) byId.set(row.channelId, row);\n return [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);\n });\n setHasMore(more);\n } catch (err) {\n console.warn('[WebBuilderNative] could not load builds:', err);\n if (runRef.current === run) setError('Check your connection and try again.');\n } finally {\n busyRef.current = false;\n if (runRef.current === run) {\n setLoading(false);\n setLoadingMore(false);\n }\n }\n },\n [client, orgName, projectFor],\n );\n\n useEffect(() => {\n void load('reset');\n }, [load]);\n\n const refresh = useCallback(() => {\n busyRef.current = false;\n void load('reset');\n }, [load]);\n const loadMore = useCallback(() => {\n if (hasMore) void load('more');\n }, [hasMore, load]);\n\n const upsert = useCallback((project: WebBuilderProject) => {\n setProjects((prev) => {\n const existing = prev.find((p) => p.channelId === project.channelId);\n if (\n existing &&\n existing.title === project.title &&\n existing.coverUrl === project.coverUrl &&\n existing.liveUrl === project.liveUrl &&\n existing.updatedAt === project.updatedAt\n ) {\n return prev;\n }\n const rest = prev.filter((p) => p.channelId !== project.channelId);\n return [project, ...rest].sort((a, b) => b.updatedAt - a.updatedAt);\n });\n }, []);\n\n return { projects, loading, loadingMore, hasMore, error, refresh, loadMore, upsert };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,408 @@
1
+ import {useRef,useState,useMemo,useEffect,useCallback}from'react';import {useAiCodeDeployToCloudflareMutation}from'common/graphql';import {v4}from'uuid';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useChatStream}from'../../hooks/useChatStream.js';import {useHostChatChannel}from'../../hooks/useHostChatChannel.js';import {config}from'../../config/env-config.js';import {useChatMessages}from'../../hooks/useChatApi.js';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {useCanvasSession}from'../../features/canvas/useCanvasSession.js';import {tokenClaims}from'../../features/canvas/sessionIdentity.js';import {buildsFromPosts,hasWorkflowPosts,projectFromPosts,turnState,pendingWork,transcriptFromPosts,stripAgentNote}from'../../features/webbuilder/buildFragments.js';import {WEBBUILDER_CHAT_SKILL,buildTriggerParams,templateRemixNote,newObjectId}from'../../features/webbuilder/workflow.js';import {useWebBuilderGallery}from'./useWebBuilderGallery.js';import {useCodeAssistantCatalog}from'./useCodeAssistantCatalog.js';import {uploadAttachment,triggerBuild,resumeSandbox}from'./webbuilderTransport.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ const POLL_MS = 2500;
21
+ const TURN_TIMEOUT_MS = 15 * 60 * 1e3;
22
+ function notSetUp(org) {
23
+ return `Builds are not set up for ${org || "this workspace"} yet. Ask an admin to configure the Code Assistant templates.`;
24
+ }
25
+ function failureText(error) {
26
+ if (/\b401\b|unauthori[sz]ed/i.test(error)) return "Your sign-in was not accepted. Try again in a moment.";
27
+ if (/network|fetch|timed out/i.test(error)) return "Couldn't reach the build service. Check your connection and try again.";
28
+ return "The build didn't start. Try again.";
29
+ }
30
+ function useWebBuilderHost(routeOrg) {
31
+ var _a, _b, _c;
32
+ const {
33
+ orgName,
34
+ projectId: appProjectId
35
+ } = usePrerequisiteIds();
36
+ const session = useCanvasSession();
37
+ const {
38
+ token,
39
+ indexUrl,
40
+ graphqlUrl
41
+ } = session;
42
+ const sessionOrg = String((_a = tokenClaims(token).orgName) != null ? _a : "");
43
+ const effectiveOrg = routeOrg || orgName || sessionOrg || "";
44
+ const tokenRef = useRef(token);
45
+ tokenRef.current = token;
46
+ const catalog = useCodeAssistantCatalog(effectiveOrg);
47
+ const reloadTemplates = catalog.reload;
48
+ const cdnOrigin = config.AWS_CDN_URL;
49
+ const gallery = useWebBuilderGallery(effectiveOrg, cdnOrigin);
50
+ const {
51
+ projects,
52
+ refresh: refreshProjects,
53
+ upsert: upsertProject
54
+ } = gallery;
55
+ const [activeChannelId, setActiveChannelId] = useState(null);
56
+ const projectIds = useRef(/* @__PURE__ */ new Map());
57
+ const {
58
+ posts: rawPosts,
59
+ refetch
60
+ } = useChatMessages(activeChannelId);
61
+ const posts = useMemo(() => activeChannelId ? rawPosts : [], [activeChannelId, rawPosts]);
62
+ const activeProject = projects.find((p) => p.channelId === activeChannelId);
63
+ const postBuilds = useMemo(() => buildsFromPosts(posts, activeProject == null ? void 0 : activeProject.title, cdnOrigin), [posts, activeProject == null ? void 0 : activeProject.title, cdnOrigin]);
64
+ const cdecli = useCdecliConnection();
65
+ const {
66
+ setActiveChannelId: setCdecliChannel
67
+ } = cdecli;
68
+ const [agentChannelId, setAgentChannelId] = useState(() => v4());
69
+ const agentChannels = useRef(/* @__PURE__ */ new Set());
70
+ const unsavedAgentChannels = useRef(/* @__PURE__ */ new Set());
71
+ const pendingAgentTurn = useRef(null);
72
+ useEffect(() => {
73
+ setCdecliChannel(agentChannelId);
74
+ return void 0;
75
+ }, [agentChannelId, setCdecliChannel]);
76
+ const {
77
+ ensureChannel
78
+ } = useHostChatChannel({
79
+ channelId: agentChannelId,
80
+ orgName: effectiveOrg,
81
+ projectId: appProjectId != null ? appProjectId : "",
82
+ label: "WebBuilderNative"
83
+ });
84
+ const chatRouting = useMemo(() => {
85
+ var _a2;
86
+ return {
87
+ channelConnected: cdecli.channelConnected,
88
+ accountId: cdecli.accountId,
89
+ persistenceMode: (_a2 = cdecli.persistenceMode) != null ? _a2 : "backend",
90
+ recoverAgentAuth: cdecli.recoverAgentAuth,
91
+ skill: WEBBUILDER_CHAT_SKILL
92
+ };
93
+ }, [cdecli.channelConnected, cdecli.accountId, cdecli.persistenceMode, cdecli.recoverAgentAuth]);
94
+ const chat = useChatStream(agentChannelId, chatRouting);
95
+ const agentLane = activeChannelId !== null && (agentChannels.current.has(activeChannelId) || posts.length > 0 && !hasWorkflowPosts(posts));
96
+ const agentBusy = agentLane && (chat.isLoading || chat.isStreaming);
97
+ const sendAgentTurn = useCallback((channelId, text, files) => {
98
+ const ready = unsavedAgentChannels.current.has(channelId) ? ensureChannel() : Promise.resolve();
99
+ ready.then(() => {
100
+ unsavedAgentChannels.current.delete(channelId);
101
+ return chat.sendMessage(text, files, channelId);
102
+ }).catch(() => void 0);
103
+ }, [chat, ensureChannel]);
104
+ useEffect(() => {
105
+ const pending = pendingAgentTurn.current;
106
+ if (!pending || pending.channelId !== agentChannelId) return;
107
+ pendingAgentTurn.current = null;
108
+ sendAgentTurn(pending.channelId, pending.text, pending.files);
109
+ }, [agentChannelId, sendAgentTurn]);
110
+ const wasAgentBusy = useRef(false);
111
+ useEffect(() => {
112
+ if (wasAgentBusy.current && !agentBusy) refetch().catch(() => void 0);
113
+ wasAgentBusy.current = agentBusy;
114
+ }, [agentBusy, refetch]);
115
+ const builds = useMemo(() => {
116
+ if (postBuilds.length || !agentLane) return postBuilds;
117
+ const now = Date.now();
118
+ return buildsFromPosts(chat.messages.map((m, index) => ({
119
+ id: `live-${index}`,
120
+ message: m.content,
121
+ props: {
122
+ role: m.role === "user" ? "USER" : "ASSISTANT"
123
+ },
124
+ createdAt: new Date(now + index).toISOString()
125
+ })), activeProject == null ? void 0 : activeProject.title, cdnOrigin);
126
+ }, [postBuilds, agentLane, chat.messages, activeProject == null ? void 0 : activeProject.title, cdnOrigin]);
127
+ useEffect(() => {
128
+ if (!activeChannelId || posts.length === 0) return;
129
+ const row = projectFromPosts({
130
+ id: activeChannelId,
131
+ title: activeProject == null ? void 0 : activeProject.title
132
+ }, posts, cdnOrigin);
133
+ if (row) upsertProject(row);
134
+ }, [activeChannelId, posts, cdnOrigin, upsertProject, activeProject == null ? void 0 : activeProject.title]);
135
+ const [turn, setTurn] = useState(null);
136
+ const [turnError, setTurnError] = useState(null);
137
+ const state = useMemo(() => turn && turn.channelId === activeChannelId ? turnState(posts, turn.startedAt) : null, [turn, activeChannelId, posts]);
138
+ useEffect(() => {
139
+ if (!turn || !state) return;
140
+ if (state.status === "done") setTurn(null);
141
+ if (state.status === "failed") {
142
+ setTurn(null);
143
+ setTurnError(state.error);
144
+ }
145
+ }, [turn, state]);
146
+ useEffect(() => {
147
+ if (!turn) return void 0;
148
+ const timer = setInterval(() => {
149
+ if (Date.now() - turn.startedAt > TURN_TIMEOUT_MS) {
150
+ setTurn(null);
151
+ setTurnError("The build is taking too long. It may still finish; reopen the site later to check.");
152
+ return;
153
+ }
154
+ refetch().catch(() => void 0);
155
+ }, POLL_MS);
156
+ return () => clearInterval(timer);
157
+ }, [turn, refetch]);
158
+ const runTurn = useCallback(async (opts) => {
159
+ var _a2, _b2, _c2, _d;
160
+ const {
161
+ current
162
+ } = tokenRef;
163
+ if (!current || !indexUrl) return "Web Builder is still signing in. Try again in a moment.";
164
+ let mode = "new";
165
+ if (opts.edit) mode = "edit";
166
+ else if ((_a2 = opts.template) == null ? void 0 : _a2.snapshotId) mode = "remix";
167
+ const uploaded = (await Promise.all(((_b2 = opts.attachments) != null ? _b2 : []).map((file) => uploadAttachment(current, indexUrl, {
168
+ name: file.name,
169
+ url: file.url,
170
+ dataUrl: file.dataUrl,
171
+ mimeType: file.mimeType
172
+ })))).filter((f) => f !== null);
173
+ const built = buildTriggerParams(__spreadProps(__spreadValues(__spreadValues(__spreadValues({
174
+ channelId: opts.channelId,
175
+ projectId: opts.projectId,
176
+ text: opts.text,
177
+ template: (_c2 = opts.template) != null ? _c2 : void 0,
178
+ defaults: catalog.defaults,
179
+ mode
180
+ }, opts.edit ? {
181
+ edit: {
182
+ sandboxId: opts.edit.sandboxId,
183
+ sandboxUrl: opts.edit.previewUrl,
184
+ title: opts.edit.title
185
+ },
186
+ // An edit keeps the build's stack (web `lastSandbox.templateId`).
187
+ stackHint: opts.edit.templateId
188
+ } : {}), opts.referenceUrl ? {
189
+ referenceUrl: opts.referenceUrl
190
+ } : {}), uploaded.length ? {
191
+ attachments: uploaded
192
+ } : {}), {
193
+ graphqlUrl,
194
+ token: current
195
+ }));
196
+ if (!built.ok) return notSetUp(effectiveOrg);
197
+ setTurnError(null);
198
+ setTurn({
199
+ channelId: opts.channelId,
200
+ text: opts.text,
201
+ startedAt: Date.now(),
202
+ mode
203
+ });
204
+ const outcome = await triggerBuild(current, indexUrl, built.params);
205
+ if (!outcome.ok) {
206
+ const reason = (_d = outcome.error) != null ? _d : "";
207
+ console.warn("[WebBuilderNative] trigger failed:", reason);
208
+ if (outcome.auth) session.retry();
209
+ setTurn(null);
210
+ setTurnError(failureText(reason));
211
+ return failureText(reason);
212
+ }
213
+ refetch().catch(() => void 0);
214
+ return null;
215
+ }, [indexUrl, graphqlUrl, catalog.defaults, effectiveOrg, refetch, session]);
216
+ const [startError, setStartError] = useState(null);
217
+ const startProject = useCallback((request) => {
218
+ var _a2;
219
+ setStartError(null);
220
+ const workflowReady = Boolean((_a2 = catalog.defaults) == null ? void 0 : _a2.formExtensionId);
221
+ if (request.template || request.agent || !workflowReady) {
222
+ const id = v4();
223
+ agentChannels.current.add(id);
224
+ unsavedAgentChannels.current.add(id);
225
+ pendingAgentTurn.current = {
226
+ channelId: id,
227
+ text: request.template ? `${request.text}
228
+
229
+ ${templateRemixNote(request.template)}` : request.text,
230
+ files: request.attachments
231
+ };
232
+ setTurnError(null);
233
+ setActiveChannelId(id);
234
+ setAgentChannelId(id);
235
+ return;
236
+ }
237
+ const channelId = newObjectId();
238
+ const projectId = newObjectId();
239
+ projectIds.current.set(channelId, projectId);
240
+ setStartError(null);
241
+ setActiveChannelId(channelId);
242
+ runTurn({
243
+ channelId,
244
+ projectId,
245
+ text: request.text,
246
+ template: request.template,
247
+ edit: null,
248
+ referenceUrl: request.referenceUrl,
249
+ attachments: request.attachments
250
+ }).then((error) => {
251
+ if (error && /not set up|signing in/i.test(error)) {
252
+ setActiveChannelId(null);
253
+ setStartError(error);
254
+ }
255
+ }).catch(() => void 0);
256
+ }, [runTurn, catalog.defaults]);
257
+ const openProject = useCallback((channelId) => {
258
+ setTurnError(null);
259
+ setActiveChannelId(channelId);
260
+ setAgentChannelId(channelId);
261
+ }, []);
262
+ const closeProject = useCallback(() => setActiveChannelId(null), []);
263
+ const work = useMemo(() => pendingWork(posts), [posts]);
264
+ const running = Boolean(turn && turn.channelId === activeChannelId);
265
+ const startedAt = (_b = turn == null ? void 0 : turn.startedAt) != null ? _b : 0;
266
+ const progress = (_c = state == null ? void 0 : state.progress) != null ? _c : null;
267
+ const building = useMemo(() => {
268
+ if (agentBusy) return {
269
+ statusText: "Building with the agent\u2026",
270
+ startedAt: startedAt || Date.now()
271
+ };
272
+ if (!running && work !== "creating") return null;
273
+ let fallback = "Starting your build\u2026";
274
+ if ((turn == null ? void 0 : turn.mode) === "edit") fallback = "Updating your app\u2026";
275
+ if (work === "creating") fallback = "Starting the preview\u2026";
276
+ return {
277
+ statusText: progress || fallback,
278
+ startedAt: startedAt || Date.now()
279
+ };
280
+ }, [agentBusy, running, work, turn == null ? void 0 : turn.mode, progress, startedAt]);
281
+ const messages = useMemo(() => {
282
+ const rows = transcriptFromPosts(posts).map((m) => ({
283
+ id: m.id,
284
+ role: m.role,
285
+ content: m.content
286
+ }));
287
+ const pending = running && (turn == null ? void 0 : turn.text) ? turn.text.replace(/^build\s*me\s*:\s*/i, "") : "";
288
+ if (pending && !rows.some((m) => m.role === "user" && pending.startsWith(m.content))) {
289
+ rows.push({
290
+ id: `pending-${turn == null ? void 0 : turn.startedAt}`,
291
+ role: "user",
292
+ content: pending
293
+ });
294
+ }
295
+ return rows;
296
+ }, [posts, running, turn]);
297
+ const send = useCallback((text, attachments, target) => {
298
+ var _a2;
299
+ const channelId = activeChannelId;
300
+ if (!channelId) return;
301
+ if (agentLane) {
302
+ sendAgentTurn(channelId, text, attachments);
303
+ return;
304
+ }
305
+ const projectId = projectIds.current.get(channelId) || (target == null ? void 0 : target.projectId) || ((_a2 = builds[0]) == null ? void 0 : _a2.projectId) || newObjectId();
306
+ projectIds.current.set(channelId, projectId);
307
+ runTurn({
308
+ channelId,
309
+ projectId,
310
+ text,
311
+ template: null,
312
+ edit: target != null ? target : null,
313
+ attachments
314
+ }).catch(() => void 0);
315
+ }, [activeChannelId, agentLane, builds, runTurn, sendAgentTurn]);
316
+ const agentMessages = useMemo(() => chat.messages.map((m, index) => ({
317
+ id: `${m.role}-${index}`,
318
+ role: m.role,
319
+ // The template note is for the agent; the person sees what they typed.
320
+ content: m.role === "user" ? stripAgentNote(m.content).replace(/^build\s*me\s*:\s*/i, "") : m.content,
321
+ attachments: m.attachments
322
+ })), [chat.messages]);
323
+ const hostChat = useMemo(() => agentLane ? {
324
+ messages: agentMessages,
325
+ streaming: chat.response || null,
326
+ busy: agentBusy,
327
+ error: chat.error,
328
+ connected: cdecli.channelConnected,
329
+ send
330
+ } : {
331
+ messages,
332
+ streaming: running ? progress || (building == null ? void 0 : building.statusText) || "Working on it\u2026" : null,
333
+ busy: running,
334
+ error: turnError || (session.ready ? session.error : null),
335
+ connected: Boolean(token),
336
+ send
337
+ }, [agentLane, agentMessages, chat.response, agentBusy, chat.error, cdecli.channelConnected, messages, running, progress, building == null ? void 0 : building.statusText, turnError, session.ready, session.error, token, send]);
338
+ const resumePreview = useCallback(async (build) => {
339
+ const {
340
+ current
341
+ } = tokenRef;
342
+ if (!current || !indexUrl || !build.sandboxId) return "failed";
343
+ return resumeSandbox(current, indexUrl, build.sandboxId);
344
+ }, [indexUrl]);
345
+ const [deployToCloudflare] = useAiCodeDeployToCloudflareMutation({});
346
+ const publish = useCallback(async (build, projectName) => {
347
+ var _a2;
348
+ if (!build.sandboxId || !activeChannelId) {
349
+ return {
350
+ ok: false,
351
+ message: "There is nothing to publish yet."
352
+ };
353
+ }
354
+ try {
355
+ const result = await deployToCloudflare({
356
+ variables: {
357
+ sandboxId: build.sandboxId,
358
+ projectName,
359
+ channelId: activeChannelId
360
+ }
361
+ });
362
+ const payload = (_a2 = result.data) == null ? void 0 : _a2.aiCodeDeployToCloudflare;
363
+ if (payload == null ? void 0 : payload.success) return {
364
+ ok: true
365
+ };
366
+ console.warn("[WebBuilderNative] publish refused:", payload == null ? void 0 : payload.message);
367
+ return {
368
+ ok: false,
369
+ message: "Publishing didn't start. Try again in a moment."
370
+ };
371
+ } catch (err) {
372
+ console.warn("[WebBuilderNative] publish failed:", err);
373
+ return {
374
+ ok: false,
375
+ message: "Publishing didn't start. Check your connection and try again."
376
+ };
377
+ }
378
+ }, [deployToCloudflare, activeChannelId]);
379
+ let startBlocked = null;
380
+ if (!token && !cdecli.channelConnected) {
381
+ startBlocked = session.ready && session.error ? session.error : "Connecting to Web Builder\u2026";
382
+ }
383
+ return {
384
+ projects,
385
+ projectsLoading: gallery.loading,
386
+ projectsError: gallery.error,
387
+ projectsHasMore: gallery.hasMore,
388
+ refreshProjects,
389
+ loadMoreProjects: gallery.loadMore,
390
+ templates: catalog.templates,
391
+ templatesLoading: catalog.loading,
392
+ templatesError: catalog.error,
393
+ reloadTemplates,
394
+ startBlocked,
395
+ startNotice: startError,
396
+ activeChannelId,
397
+ openProject,
398
+ closeProject,
399
+ startProject,
400
+ builds,
401
+ buildsLoading: activeChannelId !== null && posts.length === 0 && !running,
402
+ building,
403
+ publishing: work === "publishing",
404
+ hostChat,
405
+ publish,
406
+ resumePreview
407
+ };
408
+ }export{useWebBuilderHost};//# sourceMappingURL=useWebBuilderHost.js.map