@noodleseed/one 0.172.1 → 0.173.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.
- package/dist/commands/solutions-draft-source.d.ts +9 -0
- package/dist/commands/solutions-draft-source.d.ts.map +1 -0
- package/dist/commands/solutions-draft-source.js +67 -0
- package/dist/commands/solutions-draft-source.js.map +1 -0
- package/dist/commands/solutions-drafts.d.ts +5 -0
- package/dist/commands/solutions-drafts.d.ts.map +1 -0
- package/dist/commands/solutions-drafts.js +159 -0
- package/dist/commands/solutions-drafts.js.map +1 -0
- package/dist/commands/solutions-ops.d.ts.map +1 -1
- package/dist/commands/solutions-ops.js +7 -1
- package/dist/commands/solutions-ops.js.map +1 -1
- package/dist/commands/solutions-page.d.ts +5 -0
- package/dist/commands/solutions-page.d.ts.map +1 -0
- package/dist/commands/solutions-page.js +85 -0
- package/dist/commands/solutions-page.js.map +1 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-drafts.js +141 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-page.js +57 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solutions.js +4 -0
- package/node_modules/@noodle-borg/service/dist/application-drafts/contracts.js +11 -0
- package/node_modules/@noodle-borg/service/dist/application-drafts/paths.js +26 -0
- package/node_modules/@noodle-borg/service/dist/business-information/business-page-paths.js +14 -0
- package/node_modules/@noodle-borg/service/dist/business-information/business-page.d.ts +39 -0
- package/node_modules/@noodle-borg/service/dist/business-information/business-page.js +81 -0
- package/node_modules/@noodle-borg/service/dist/business-information/contracts.d.ts +2 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-business-pages.js +37 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-store.js +3 -0
- package/node_modules/@noodle-borg/service/dist/business-information/managed-solution-executable.js +11 -3
- package/node_modules/@noodle-borg/service/dist/routes/application-drafts.js +162 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-channels.js +3 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +22 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-pages.js +158 -0
- package/node_modules/@noodle-borg/service/dist/routes/service-probes.js +31 -0
- package/node_modules/@noodle-borg/service/dist/service.js +14 -18
- package/node_modules/@noodle-borg/service/dist/solution-installation-activation.js +3 -3
- package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.d.ts +3 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.js +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-drafts.d.ts +322 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-drafts.js +152 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-org-transfer.d.ts +8 -8
- package/node_modules/@noodle-borg/wire-contracts/dist/billing-read.d.ts +5 -5
- package/node_modules/@noodle-borg/wire-contracts/dist/business-page.d.ts +157 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-page.js +105 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-workspaces.d.ts +22 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-workspaces.js +15 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/distribution.d.ts +10 -10
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +3 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +3 -0
- package/package.json +1 -1
|
@@ -64,6 +64,9 @@ export async function projectBusinessChannels(installation, canEdit, base, deps)
|
|
|
64
64
|
revision: installation.revision,
|
|
65
65
|
active: installation.intakeActive,
|
|
66
66
|
canEdit,
|
|
67
|
+
...(deps.pageOrigin
|
|
68
|
+
? { businessPageUrl: `${deps.pageOrigin}/b/${installation.publicId}` }
|
|
69
|
+
: {}),
|
|
67
70
|
...(whatsapp
|
|
68
71
|
? {
|
|
69
72
|
whatsapp: {
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { OrganizationAgreementError } from '@noodle-borg/control-plane/portable';
|
|
2
2
|
import { sendJson } from '@noodle-borg/transport-http';
|
|
3
|
+
import { parseApplicationDraftPath } from '../application-drafts/paths.js';
|
|
3
4
|
import { BusinessNoticeError } from '../business-information/business-notice.js';
|
|
5
|
+
import { parseBusinessPagePath } from '../business-information/business-page-paths.js';
|
|
4
6
|
import { InstallationCapacityError } from '../business-information/installation-capacity.js';
|
|
5
7
|
import { NativeStorageLimitError } from '../business-information/native-storage-budget.js';
|
|
6
8
|
import { SourceCredentialError } from '../business-information/source-credential-fence.js';
|
|
7
9
|
import { SourceCapacityError } from '../business-information/source-custody-budget.js';
|
|
8
10
|
import { respondRouteError } from '../http-util.js';
|
|
11
|
+
import { handleApplicationDraftRoute } from './application-drafts.js';
|
|
9
12
|
import { handleBusinessGrants, handleManagedRecords, handleSolutionCatalog, handleSolutionInstallations, } from './business-information.js';
|
|
10
13
|
import { handleApplicationActivity, } from './business-information-activity.js';
|
|
11
14
|
import { handleBusinessChannels, } from './business-information-channels.js';
|
|
12
15
|
import { handleApplicationConnectionCallback, handleApplicationConnections, } from './business-information-connections.js';
|
|
13
16
|
import { handleBusinessNotice, handleOrganizationAgreement, } from './business-information-notice.js';
|
|
14
17
|
import { handleSolutionInstallationOptions } from './business-information-onboarding.js';
|
|
18
|
+
import { handleBusinessPage, handlePublicBusinessPage } from './business-information-pages.js';
|
|
15
19
|
import { parsePublicSolutionIntakePath, parseSolutionInstallationPath, parseSolutionInvitationAcceptPath, } from './business-information-paths.js';
|
|
16
20
|
import { handlePublicSolutionIntake } from './business-information-public.js';
|
|
17
21
|
import { handleBusinessInformationReaderFloor } from './business-information-reader-floor.js';
|
|
@@ -19,6 +23,24 @@ import { handleBusinessSettings } from './business-information-settings.js';
|
|
|
19
23
|
import { handleCollectionSource } from './business-information-source.js';
|
|
20
24
|
import { handleBusinessInvitationAccept, handleBusinessInvitations, handleEligibleBusinessAssignees, handleMySolutionInstallations, } from './business-information-staff.js';
|
|
21
25
|
export function dispatchBusinessInformationRoutes(req, res, url, deps) {
|
|
26
|
+
const pageRef = parseBusinessPagePath(url.pathname);
|
|
27
|
+
const publicPage = /^\/v1\/business-pages\/(sol_[a-f0-9]{32})$/.exec(url.pathname);
|
|
28
|
+
if (pageRef || publicPage) {
|
|
29
|
+
if (!deps.pageOrigin || !deps.pageServiceUrl || !deps.registry || !deps.resolveEndpointBase)
|
|
30
|
+
return run(req, res, deps, () => Promise.resolve(sendJson(res, 404, { error: 'not found' })));
|
|
31
|
+
const pageDeps = {
|
|
32
|
+
...deps,
|
|
33
|
+
registry: deps.registry,
|
|
34
|
+
resolveEndpointBase: deps.resolveEndpointBase,
|
|
35
|
+
};
|
|
36
|
+
return run(req, res, deps, () => pageRef
|
|
37
|
+
? handleBusinessPage(req, res, pageRef, pageDeps)
|
|
38
|
+
: handlePublicBusinessPage(req, res, publicPage[1], pageDeps));
|
|
39
|
+
}
|
|
40
|
+
if (deps.authoring && parseApplicationDraftPath(url.pathname)) {
|
|
41
|
+
const draftDeps = { ...deps, ...deps.authoring, maxBody: deps.maxDraftBody ?? deps.maxBody };
|
|
42
|
+
return run(req, res, deps, () => handleApplicationDraftRoute(req, res, url, draftDeps));
|
|
43
|
+
}
|
|
22
44
|
const agreement = /^\/v1\/orgs\/([a-z0-9][a-z0-9-]{0,62})\/agreement$/.exec(url.pathname);
|
|
23
45
|
if (agreement?.[1])
|
|
24
46
|
return run(req, res, deps, () => handleOrganizationAgreement(req, res, agreement[1], deps));
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
+
import { BusinessPagePublishRequestSchema, BusinessPageResponseSchema, BusinessPageSaveRequestSchema, PublicBusinessPageResponseSchema, } from '@noodle-borg/wire-contracts';
|
|
3
|
+
import { BusinessPageError, } from '../business-information/business-page.js';
|
|
4
|
+
import { businessPageMethods, } from '../business-information/business-page-paths.js';
|
|
5
|
+
import { requireIdentity, requireInstallationPermission } from './business-information.js';
|
|
6
|
+
import { projectBusinessChannels, } from './business-information-channels.js';
|
|
7
|
+
/** Publication custody remains valid independently of temporary assistant availability. */
|
|
8
|
+
async function pageContext(scope, deps) {
|
|
9
|
+
const installation = await deps.store.getInstallation(scope);
|
|
10
|
+
const generation = await deps.registry.getAppGeneration(scope.org, scope.app);
|
|
11
|
+
if (!installation ||
|
|
12
|
+
!generation ||
|
|
13
|
+
installation.applicationGeneration !== generation ||
|
|
14
|
+
(await deps.registry.getAppArchivedAt(scope.org, scope.app)) !== undefined ||
|
|
15
|
+
!deps.pageOrigin ||
|
|
16
|
+
!deps.pageServiceUrl ||
|
|
17
|
+
(deps.businessOnboarding && !(await deps.businessOnboarding.ready(installation))))
|
|
18
|
+
throw new BusinessPageError('business_page_not_ready');
|
|
19
|
+
const origin = new URL(deps.pageOrigin);
|
|
20
|
+
if (origin.origin !== deps.pageOrigin ||
|
|
21
|
+
!(origin.protocol === 'https:' ||
|
|
22
|
+
(origin.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(origin.hostname))))
|
|
23
|
+
throw new BusinessPageError('business_page_not_ready');
|
|
24
|
+
return { installation, origin: origin.origin, serviceUrl: deps.pageServiceUrl };
|
|
25
|
+
}
|
|
26
|
+
/** Only a current, explicitly configured public assistant can be attached to a hosted page. */
|
|
27
|
+
async function pageReadiness(scope, deps) {
|
|
28
|
+
const { installation, origin, serviceUrl } = await pageContext(scope, deps);
|
|
29
|
+
if (!installation.intakeActive || deps.publicIntakeEnabled === false)
|
|
30
|
+
throw new BusinessPageError('business_page_not_ready');
|
|
31
|
+
const channels = await projectBusinessChannels(installation, false, serviceUrl, deps);
|
|
32
|
+
const assistant = channels.assistant;
|
|
33
|
+
if (assistant.status !== 'ready' ||
|
|
34
|
+
!assistant.origins.includes(origin) ||
|
|
35
|
+
!channels.deploymentId ||
|
|
36
|
+
!assistant.embedId ||
|
|
37
|
+
!assistant.serviceUrl ||
|
|
38
|
+
!assistant.scriptUrl)
|
|
39
|
+
throw new BusinessPageError('business_page_not_ready');
|
|
40
|
+
return {
|
|
41
|
+
deploymentId: channels.deploymentId,
|
|
42
|
+
assistant: {
|
|
43
|
+
embedId: assistant.embedId,
|
|
44
|
+
serviceUrl: assistant.serviceUrl,
|
|
45
|
+
scriptUrl: assistant.scriptUrl,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function handleBusinessPage(req, res, ref, deps) {
|
|
50
|
+
res.setHeader('cache-control', 'private, no-store');
|
|
51
|
+
if (!businessPageMethods(ref).includes(req.method ?? '')) {
|
|
52
|
+
res.setHeader('allow', businessPageMethods(ref).join(', '));
|
|
53
|
+
return sendJson(res, 405, { error: 'method not allowed' });
|
|
54
|
+
}
|
|
55
|
+
const identity = await requireIdentity(req, res, deps);
|
|
56
|
+
if (identity === false)
|
|
57
|
+
return;
|
|
58
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'installation:administer', deps);
|
|
59
|
+
if (!authorized)
|
|
60
|
+
return;
|
|
61
|
+
try {
|
|
62
|
+
let record = await deps.store.pages.get(authorized.scope);
|
|
63
|
+
if (req.method !== 'GET') {
|
|
64
|
+
const body = await readJsonBody(req, Math.min(deps.maxBody, 256 * 1024));
|
|
65
|
+
if (!body.ok)
|
|
66
|
+
return sendJson(res, body.status, { error: body.error });
|
|
67
|
+
let change;
|
|
68
|
+
if (ref.operation) {
|
|
69
|
+
const parsed = BusinessPagePublishRequestSchema.safeParse(body.value);
|
|
70
|
+
if (!parsed.success)
|
|
71
|
+
return invalidPage(res);
|
|
72
|
+
change = { operation: ref.operation, ...parsed.data };
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const parsed = BusinessPageSaveRequestSchema.safeParse(body.value);
|
|
76
|
+
if (!parsed.success)
|
|
77
|
+
return invalidPage(res);
|
|
78
|
+
change = { operation: 'save', ...parsed.data };
|
|
79
|
+
}
|
|
80
|
+
record = await deps.store.pages.update({ scope: authorized.scope, actorSubject: identity.subject, change }, () => pageReadiness(authorized.scope, deps));
|
|
81
|
+
}
|
|
82
|
+
return sendJson(res, 200, BusinessPageResponseSchema.parse({
|
|
83
|
+
ok: true,
|
|
84
|
+
data: {
|
|
85
|
+
revision: record?.revision ?? 0,
|
|
86
|
+
draft: record?.draft ?? null,
|
|
87
|
+
published: record?.published ?? null,
|
|
88
|
+
canEdit: true,
|
|
89
|
+
},
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return pageFailure(res, error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export async function handlePublicBusinessPage(req, res, publicId, deps) {
|
|
97
|
+
res.setHeader('cache-control', 'no-store');
|
|
98
|
+
res.setHeader('x-robots-tag', 'noindex');
|
|
99
|
+
if (req.method !== 'GET') {
|
|
100
|
+
res.setHeader('allow', 'GET');
|
|
101
|
+
return sendJson(res, 405, { error: 'method not allowed' });
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const installation = await deps.store.resolveInstallationByPublicId(publicId);
|
|
105
|
+
if (!installation)
|
|
106
|
+
return unavailablePage(res);
|
|
107
|
+
const record = await deps.store.pages.get(installation.scope);
|
|
108
|
+
if (!record?.published)
|
|
109
|
+
return unavailablePage(res);
|
|
110
|
+
await pageContext(installation.scope, deps);
|
|
111
|
+
const notice = await deps.store.getBusinessNotice(installation.scope);
|
|
112
|
+
if (notice?.revision !== record.published.noticeRevision)
|
|
113
|
+
return unavailablePage(res);
|
|
114
|
+
const ready = await pageReadiness(installation.scope, deps).catch((error) => {
|
|
115
|
+
if (error instanceof BusinessPageError)
|
|
116
|
+
return undefined;
|
|
117
|
+
throw error;
|
|
118
|
+
});
|
|
119
|
+
return sendJson(res, 200, PublicBusinessPageResponseSchema.parse({
|
|
120
|
+
ok: true,
|
|
121
|
+
data: {
|
|
122
|
+
publicId,
|
|
123
|
+
content: record.published.content,
|
|
124
|
+
notice: record.published.notice,
|
|
125
|
+
assistant: ready?.deploymentId === record.published.deploymentId ? ready.assistant : null,
|
|
126
|
+
},
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (error instanceof BusinessPageError)
|
|
131
|
+
return unavailablePage(res);
|
|
132
|
+
return pageFailure(res, error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function unavailablePage(res) {
|
|
136
|
+
sendJson(res, 404, { code: 'page_unavailable', error: 'This page is not available.' });
|
|
137
|
+
}
|
|
138
|
+
function invalidPage(res) {
|
|
139
|
+
sendJson(res, 400, {
|
|
140
|
+
code: 'business_page_invalid',
|
|
141
|
+
error: 'Check the page content and revision.',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function pageFailure(res, error) {
|
|
145
|
+
if (error instanceof BusinessPageError) {
|
|
146
|
+
sendJson(res, error.code === 'business_page_forbidden' ? 403 : 409, {
|
|
147
|
+
code: error.code,
|
|
148
|
+
error: error.message,
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Neither decrypted content nor provider/parser exceptions may escape via generic route logging.
|
|
153
|
+
sendJson(res, 503, {
|
|
154
|
+
code: 'page_unavailable',
|
|
155
|
+
error: 'The page service is temporarily unavailable.',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=business-information-pages.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { applySecurityHeaders, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
+
import { serviceInfoPayload } from '../build-info.js';
|
|
3
|
+
export function createServiceProbeDispatcher(deps) {
|
|
4
|
+
return (req, res, url) => {
|
|
5
|
+
if (req.method !== 'GET' || !['/healthz', '/readyz', '/v1/service/info'].includes(url.pathname))
|
|
6
|
+
return false;
|
|
7
|
+
handleServiceProbe(req, res, url, deps);
|
|
8
|
+
return true;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function handleServiceProbe(req, res, url, { tls, moduleHost, buildInfo, options, whatsapp }) {
|
|
12
|
+
// Liveness/readiness probes: un-gated and **not** HTTPS-enforced — Cloud Run's internal probe is plain
|
|
13
|
+
// HTTP, so enforcing HTTPS here would `426` the probe and the revision would never go healthy (ADR 0034).
|
|
14
|
+
// `/healthz` is a pure liveness 200 (no store touch); `/readyz` reflects the injected readiness probe.
|
|
15
|
+
if (req.method === 'GET' && (url.pathname === '/healthz' || url.pathname === '/readyz')) {
|
|
16
|
+
applySecurityHeaders(res, tls);
|
|
17
|
+
if (url.pathname === '/healthz')
|
|
18
|
+
return sendJson(res, 200, { status: 'ok' });
|
|
19
|
+
void Promise.resolve(moduleHost.ready())
|
|
20
|
+
.then((ready) => sendJson(res, ready ? 200 : 503, { status: ready ? 'ready' : 'unready' }))
|
|
21
|
+
.catch(() => sendJson(res, 503, { status: 'unready' }));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Deployed-version visibility (ADR 0080): un-gated, non-HTTPS-enforced like the probes so the
|
|
25
|
+
// post-deploy smoke can confirm exactly which commit is live. Non-sensitive fields only.
|
|
26
|
+
if (req.method === 'GET' && url.pathname === '/v1/service/info') {
|
|
27
|
+
applySecurityHeaders(res, tls);
|
|
28
|
+
return sendJson(res, 200, serviceInfoPayload(buildInfo, options.developerMcp === true, whatsapp !== undefined));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=service-probes.js.map
|
|
@@ -12,7 +12,7 @@ import { createArchivePreflight } from './archive-preflight.js';
|
|
|
12
12
|
import { ArchiveSweeper, resolveArchiveRetentionDays } from './archive-sweeper.js';
|
|
13
13
|
import { serveLocalAsset } from './assets.js';
|
|
14
14
|
import { assistantRouteDependencies } from './assistant-composition.js';
|
|
15
|
-
import { resolveBuildInfo
|
|
15
|
+
import { resolveBuildInfo } from './build-info.js';
|
|
16
16
|
import { createBusinessInformationRuntime, resolvePrivateInstallationDefinition, } from './business-information-runtime.js';
|
|
17
17
|
import { serviceCapabilityReport } from './capabilities.js';
|
|
18
18
|
import { createWhatsAppRuntime } from './channels/composition.js';
|
|
@@ -52,6 +52,7 @@ import { dispatchProtectedResourceMetadata } from './routes/protected-resource-m
|
|
|
52
52
|
import { dispatchResourceReads } from './routes/resource-read-dispatch.js';
|
|
53
53
|
import { handleRollback } from './routes/rollback.js';
|
|
54
54
|
import { createServicePrincipalDispatcher } from './routes/service-principals-dispatch.js';
|
|
55
|
+
import { createServiceProbeDispatcher } from './routes/service-probes.js';
|
|
55
56
|
import { dispatchWhatsAppRoutes } from './routes/whatsapp.js';
|
|
56
57
|
import { servicePrincipalDataPlaneHooks } from './service-principal-data-plane.js';
|
|
57
58
|
import { InMemoryAlertRuleStore } from './store/alert-rules.js';
|
|
@@ -201,20 +202,17 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
201
202
|
installations: businessInformationStore,
|
|
202
203
|
activity,
|
|
203
204
|
});
|
|
205
|
+
const dispatchProbe = createServiceProbeDispatcher({
|
|
206
|
+
tls,
|
|
207
|
+
moduleHost,
|
|
208
|
+
buildInfo,
|
|
209
|
+
options,
|
|
210
|
+
whatsapp,
|
|
211
|
+
});
|
|
204
212
|
return (req, res) => {
|
|
205
213
|
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
206
|
-
|
|
207
|
-
// HTTP, so enforcing HTTPS here would `426` the probe and the revision would never go healthy (ADR 0034).
|
|
208
|
-
// `/healthz` is a pure liveness 200 (no store touch); `/readyz` reflects the injected readiness probe.
|
|
209
|
-
if (req.method === 'GET' && (url.pathname === '/healthz' || url.pathname === '/readyz')) {
|
|
210
|
-
applySecurityHeaders(res, tls);
|
|
211
|
-
if (url.pathname === '/healthz')
|
|
212
|
-
return sendJson(res, 200, { status: 'ok' });
|
|
213
|
-
void Promise.resolve(moduleHost.ready())
|
|
214
|
-
.then((ready) => sendJson(res, ready ? 200 : 503, { status: ready ? 'ready' : 'unready' }))
|
|
215
|
-
.catch(() => sendJson(res, 503, { status: 'unready' }));
|
|
214
|
+
if (dispatchProbe(req, res, url))
|
|
216
215
|
return;
|
|
217
|
-
}
|
|
218
216
|
if (options.developerMcp === true && url.pathname === DEVELOPER_MCP_PATH) {
|
|
219
217
|
const mount = createDeveloperMcpMountOptions({
|
|
220
218
|
registry,
|
|
@@ -228,12 +226,6 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
228
226
|
void handleDeveloperMcpRequest(req, res, mount).catch((error) => respondRouteError(logger, res, 'developer.mcp.failed', error));
|
|
229
227
|
return;
|
|
230
228
|
}
|
|
231
|
-
// Deployed-version visibility (ADR 0080): un-gated, non-HTTPS-enforced like the probes so the
|
|
232
|
-
// post-deploy smoke can confirm exactly which commit is live. Non-sensitive fields only.
|
|
233
|
-
if (req.method === 'GET' && url.pathname === '/v1/service/info') {
|
|
234
|
-
applySecurityHeaders(res, tls);
|
|
235
|
-
return sendJson(res, 200, serviceInfoPayload(buildInfo, options.developerMcp === true, whatsapp !== undefined));
|
|
236
|
-
}
|
|
237
229
|
if (url.pathname.startsWith('/v1/') && rejectIncompatibleCli(req, res, buildInfo, tls))
|
|
238
230
|
return;
|
|
239
231
|
if (req.method === 'GET' || req.method === 'HEAD') {
|
|
@@ -305,6 +297,10 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
305
297
|
if (businessInformationStore !== undefined &&
|
|
306
298
|
options.businessInformationEnabled !== false &&
|
|
307
299
|
dispatchBusinessInformationRoutes(req, res, url, {
|
|
300
|
+
authoring: options.businessAuthoring,
|
|
301
|
+
pageOrigin: options.businessPageOrigin,
|
|
302
|
+
pageServiceUrl: options.publicBaseUrl,
|
|
303
|
+
maxDraftBody: maxDeployBody,
|
|
308
304
|
...(whatsapp ? { readWhatsApp: whatsapp.projection.bind(whatsapp) } : {}),
|
|
309
305
|
store: businessInformationStore,
|
|
310
306
|
...(businessOnboarding ? { businessOnboarding } : {}),
|
|
@@ -95,7 +95,7 @@ export async function activateSolutionInstallation(input, dependencies) {
|
|
|
95
95
|
}
|
|
96
96
|
return { ok: true, deploymentId };
|
|
97
97
|
};
|
|
98
|
-
const source = await executableSource(installation, dependencies.registry);
|
|
98
|
+
const source = await executableSource(installation, dependencies.registry, dependencies.options.businessPageOrigin);
|
|
99
99
|
if (!source.ok)
|
|
100
100
|
return source;
|
|
101
101
|
const current = await dependencies.registry.getActiveByTenant(tenant);
|
|
@@ -152,13 +152,13 @@ export async function activateSolutionInstallation(input, dependencies) {
|
|
|
152
152
|
};
|
|
153
153
|
return bind(deployed.result.deploymentId, false);
|
|
154
154
|
}
|
|
155
|
-
async function executableSource(installation, registry) {
|
|
155
|
+
async function executableSource(installation, registry, hostedPageOrigin) {
|
|
156
156
|
const reference = installation.definition.reference;
|
|
157
157
|
if (reference.kind === 'managed') {
|
|
158
158
|
return {
|
|
159
159
|
ok: true,
|
|
160
160
|
value: {
|
|
161
|
-
manifest: JSON.stringify(managedSolutionManifest(installation.definition)),
|
|
161
|
+
manifest: JSON.stringify(managedSolutionManifest(installation.definition, hostedPageOrigin)),
|
|
162
162
|
accessMode: 'public',
|
|
163
163
|
serverVersion: '1',
|
|
164
164
|
},
|
|
@@ -3,6 +3,7 @@ export declare const ApplicationChannelsProjectionSchema: z.ZodObject<{
|
|
|
3
3
|
revision: z.ZodNumber;
|
|
4
4
|
active: z.ZodBoolean;
|
|
5
5
|
canEdit: z.ZodBoolean;
|
|
6
|
+
businessPageUrl: z.ZodOptional<z.ZodURL>;
|
|
6
7
|
deploymentId: z.ZodOptional<z.ZodString>;
|
|
7
8
|
mcp: z.ZodObject<{
|
|
8
9
|
status: z.ZodEnum<{
|
|
@@ -56,6 +57,7 @@ export declare const ApplicationChannelsResponseSchema: z.ZodObject<{
|
|
|
56
57
|
revision: z.ZodNumber;
|
|
57
58
|
active: z.ZodBoolean;
|
|
58
59
|
canEdit: z.ZodBoolean;
|
|
60
|
+
businessPageUrl: z.ZodOptional<z.ZodURL>;
|
|
59
61
|
deploymentId: z.ZodOptional<z.ZodString>;
|
|
60
62
|
mcp: z.ZodObject<{
|
|
61
63
|
status: z.ZodEnum<{
|
|
@@ -109,6 +111,7 @@ export declare const ApplicationChannelsClientResponseSchema: z.ZodObject<{
|
|
|
109
111
|
revision: z.ZodNumber;
|
|
110
112
|
active: z.ZodBoolean;
|
|
111
113
|
canEdit: z.ZodBoolean;
|
|
114
|
+
businessPageUrl: z.ZodOptional<z.ZodURL>;
|
|
112
115
|
deploymentId: z.ZodOptional<z.ZodString>;
|
|
113
116
|
mcp: z.ZodObject<{
|
|
114
117
|
status: z.ZodEnum<{
|