@noodleseed/one 0.173.0 → 0.175.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-activity.js +1 -1
- package/dist/commands/solutions-activity.js.map +1 -1
- package/dist/commands/solutions-drafts.d.ts.map +1 -1
- package/dist/commands/solutions-drafts.js +36 -9
- package/dist/commands/solutions-drafts.js.map +1 -1
- package/dist/commands/solutions-native-lifecycle.d.ts +5 -0
- package/dist/commands/solutions-native-lifecycle.d.ts.map +1 -0
- package/dist/commands/solutions-native-lifecycle.js +77 -0
- package/dist/commands/solutions-native-lifecycle.js.map +1 -0
- package/dist/commands/solutions-ops-args.d.ts +42 -0
- package/dist/commands/solutions-ops-args.d.ts.map +1 -0
- package/dist/commands/solutions-ops-args.js +47 -0
- package/dist/commands/solutions-ops-args.js.map +1 -0
- package/dist/commands/solutions-ops.d.ts.map +1 -1
- package/dist/commands/solutions-ops.js +9 -46
- package/dist/commands/solutions-ops.js.map +1 -1
- package/dist/commands/solutions-workspace.d.ts +5 -0
- package/dist/commands/solutions-workspace.d.ts.map +1 -0
- package/dist/commands/solutions-workspace.js +157 -0
- package/dist/commands/solutions-workspace.js.map +1 -0
- package/dist/commands/whatsapp-output.d.ts.map +1 -1
- package/dist/commands/whatsapp-output.js +20 -4
- package/dist/commands/whatsapp-output.js.map +1 -1
- package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.d.ts +16 -9
- package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.js +5 -2
- package/node_modules/@noodle-borg/agent-kit/dist/curated/error-fixes.js +9 -0
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +5 -5
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +9 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +13 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.d.ts +5 -3
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.js +5 -4
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-inbox.js +6 -2
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-store.d.ts +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-types.d.ts +12 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-work.d.ts +7 -2
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-work.js +14 -4
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-capture.js +104 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-judgment.js +93 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-ledger.d.ts +105 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-ledger.js +183 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-model-call.js +38 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-parsers.d.ts +22 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-parsers.js +109 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-review.d.ts +21 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-review.js +44 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-spec.d.ts +18 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-spec.js +86 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-store.d.ts +11 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/collection-store.js +18 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/messaging-tool-dispatch.d.ts +20 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/messaging-tool-dispatch.js +38 -2
- package/node_modules/@noodle-borg/assistant-gateway/dist/model-runtime.js +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +5 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +5 -0
- package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/authoring/dist/interaction.d.ts +49 -0
- package/node_modules/@noodle-borg/authoring/dist/interaction.js +25 -0
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -0
- package/node_modules/@noodle-borg/authoring/dist/server.js +4 -0
- package/node_modules/@noodle-borg/authoring/package.json +6 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-channels.js +1 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-drafts.js +7 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-native-lifecycle.js +43 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-records.js +154 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-workspace.js +95 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solutions.js +4 -149
- package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +2 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +33 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +2 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +2 -1
- package/node_modules/@noodle-borg/compiler/dist/compile.js +5 -0
- package/node_modules/@noodle-borg/compiler/dist/errors.d.ts +1 -1
- package/node_modules/@noodle-borg/compiler/dist/index.d.ts +2 -2
- package/node_modules/@noodle-borg/compiler/dist/index.js +1 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/interaction-schema.d.ts +41 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/interaction-schema.js +62 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/interaction-validation.js +220 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +60 -4
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +7 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/website-projection.d.ts +9 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/website-projection.js +58 -10
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-atomic-state.d.ts +8 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-atomic-state.js +136 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-control-plane-store.d.ts +7 -0
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-control-plane-store.js +16 -24
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.d.ts +4 -2
- package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.js +8 -6
- package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.d.ts +2 -1
- package/node_modules/@noodle-borg/control-plane/dist/mcp-subdomain-claims.js +13 -8
- package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.d.ts +13 -4
- package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.js +23 -7
- package/node_modules/@noodle-borg/control-plane/dist/portable.d.ts +2 -1
- package/node_modules/@noodle-borg/control-plane/dist/portable.js +1 -0
- package/node_modules/@noodle-borg/module/dist/platform-human-identity.d.ts +5 -2
- package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +16 -4
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +3 -6
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/application-activity.js +85 -63
- package/node_modules/@noodle-borg/service/dist/application-drafts/contracts.js +9 -0
- package/node_modules/@noodle-borg/service/dist/application-drafts/paths.js +2 -2
- package/node_modules/@noodle-borg/service/dist/application-runtime-target.js +1 -1
- package/node_modules/@noodle-borg/service/dist/business-information/contracts.d.ts +18 -4
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-business-pages.js +3 -5
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-installation-lifecycle.js +8 -6
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-native-lifecycle.js +80 -0
- package/node_modules/@noodle-borg/service/dist/business-information/in-memory-store.js +27 -31
- package/node_modules/@noodle-borg/service/dist/business-information/memory-native-retention.js +29 -0
- package/node_modules/@noodle-borg/service/dist/business-information/model.js +9 -2
- package/node_modules/@noodle-borg/service/dist/business-information/native-query.js +3 -1
- package/node_modules/@noodle-borg/service/dist/business-information/native-record-lifecycle.d.ts +27 -0
- package/node_modules/@noodle-borg/service/dist/business-information/native-record-lifecycle.js +63 -0
- package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.d.ts +3 -1
- package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.js +9 -4
- package/node_modules/@noodle-borg/service/dist/business-information/staff-authority.d.ts +16 -0
- package/node_modules/@noodle-borg/service/dist/business-information/staff-authority.js +60 -0
- package/node_modules/@noodle-borg/service/dist/business-information/workspace-permissions.js +18 -0
- package/node_modules/@noodle-borg/service/dist/business-information-runtime.js +1 -0
- package/node_modules/@noodle-borg/service/dist/business-onboarding.js +16 -3
- package/node_modules/@noodle-borg/service/dist/business-workspaces/contracts.d.ts +110 -0
- package/node_modules/@noodle-borg/service/dist/business-workspaces/contracts.js +52 -0
- package/node_modules/@noodle-borg/service/dist/business-workspaces/paths.js +17 -0
- package/node_modules/@noodle-borg/service/dist/business-workspaces/permissions.d.ts +7 -0
- package/node_modules/@noodle-borg/service/dist/business-workspaces/store.d.ts +102 -0
- package/node_modules/@noodle-borg/service/dist/channels/360dialog.js +70 -8
- package/node_modules/@noodle-borg/service/dist/channels/capability-report.js +73 -0
- package/node_modules/@noodle-borg/service/dist/channels/collection-turn.js +232 -0
- package/node_modules/@noodle-borg/service/dist/channels/composition.js +1 -0
- package/node_modules/@noodle-borg/service/dist/channels/messaging-eligibility.js +45 -0
- package/node_modules/@noodle-borg/service/dist/channels/reply-buttons.js +23 -0
- package/node_modules/@noodle-borg/service/dist/channels/runtime.js +127 -33
- package/node_modules/@noodle-borg/service/dist/native-record-connector.js +19 -4
- package/node_modules/@noodle-borg/service/dist/routes/application-drafts.js +44 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +4 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-authoring-dispatch.js +23 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-access.js +39 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-activity.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/business-information-channels.js +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/business-information-connections.js +10 -4
- package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +11 -6
- package/node_modules/@noodle-borg/service/dist/routes/business-information-installation.js +3 -1
- package/node_modules/@noodle-borg/service/dist/routes/business-information-notice.js +6 -2
- package/node_modules/@noodle-borg/service/dist/routes/business-information-pages.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/business-information-paths.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/business-information-record-create.js +7 -2
- package/node_modules/@noodle-borg/service/dist/routes/business-information-record-reads.js +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/business-information-records.js +332 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-information-settings.js +6 -3
- package/node_modules/@noodle-borg/service/dist/routes/business-information-staff.js +9 -5
- package/node_modules/@noodle-borg/service/dist/routes/business-information.js +12 -356
- package/node_modules/@noodle-borg/service/dist/routes/business-native-lifecycle.js +46 -0
- package/node_modules/@noodle-borg/service/dist/routes/business-workspaces.js +119 -0
- package/node_modules/@noodle-borg/service/dist/routes/service-probes.js +2 -1
- package/node_modules/@noodle-borg/service/dist/service.js +9 -2
- package/node_modules/@noodle-borg/service/dist/web-capabilities.js +3 -1
- package/node_modules/@noodle-borg/service/package.json +2 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/application-draft-validation.d.ts +59 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-draft-validation.js +38 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-information.d.ts +144 -50
- package/node_modules/@noodle-borg/wire-contracts/dist/business-information.js +44 -4
- package/node_modules/@noodle-borg/wire-contracts/dist/business-workspaces.d.ts +258 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/business-workspaces.js +118 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +2 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +2 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/native-record-lifecycle.d.ts +81 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/native-record-lifecycle.js +39 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.d.ts +26 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.js +24 -1
- package/package.json +2 -2
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
-
import { BusinessGrantCreateRequestSchema, formatWireError,
|
|
3
|
-
import {
|
|
2
|
+
import { BusinessGrantCreateRequestSchema, formatWireError, SolutionInstallationCreateRequestSchema, SolutionInstallationIntakeRequestSchema, } from '@noodle-borg/wire-contracts';
|
|
3
|
+
import { admitBusinessTarget } from '../business-api-admission.js';
|
|
4
4
|
import { resolveInstallDefinition } from '../business-information/definition-resolver.js';
|
|
5
|
-
import { BUILT_IN_SOLUTION_PROFILES,
|
|
5
|
+
import { BUILT_IN_SOLUTION_PROFILES, MANAGED_SOLUTION_PROFILE_KEYS, validateCollectionEnabled, } from '../business-information/portable.js';
|
|
6
6
|
import { sendForbidden } from '../http-util.js';
|
|
7
|
-
import {
|
|
7
|
+
import { requireIdentity, requireInstallationGrant, requireInstallationPermission, resolveBusinessStaffGrant, runBusinessStaffOperation, } from './business-information-access.js';
|
|
8
8
|
import { installationProjection, retryInstallationActivation, stableInstallationId, } from './business-information-installation.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { expectedRevision, mutationPermission, parseNativeRecordQuery, parseBusinessPaging as parsePaging, requestIdempotencyKey, } from './business-information-request.js';
|
|
12
|
-
import { collectionToWire, externalRecordToWire, grantToWire, profileToWire, recordDetailToWire, recordToWire, } from './business-information-wire.js';
|
|
9
|
+
import { expectedRevision } from './business-information-request.js';
|
|
10
|
+
import { grantToWire, profileToWire } from './business-information-wire.js';
|
|
13
11
|
import { canManageMembers } from './org-admin.js';
|
|
14
12
|
export function handleSolutionCatalog(req, res) {
|
|
15
13
|
if (req.method !== 'GET') {
|
|
@@ -70,7 +68,7 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
|
|
|
70
68
|
code: 'installation_conflict',
|
|
71
69
|
});
|
|
72
70
|
}
|
|
73
|
-
const grant = await deps
|
|
71
|
+
const grant = await resolveBusinessStaffGrant(deps, result.installation.scope, identity.subject);
|
|
74
72
|
if (grant === undefined || grant.revokedAt !== undefined) {
|
|
75
73
|
return sendForbidden(res, 'business grant required');
|
|
76
74
|
}
|
|
@@ -107,7 +105,7 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
|
|
|
107
105
|
const installations = await deps.store.listInstallations(ref.org);
|
|
108
106
|
const permitted = [];
|
|
109
107
|
for (const installation of installations) {
|
|
110
|
-
const grant = await deps
|
|
108
|
+
const grant = await resolveBusinessStaffGrant(deps, installation.scope, identity.subject);
|
|
111
109
|
if (grant !== undefined && grant.revokedAt === undefined) {
|
|
112
110
|
permitted.push({ installation, role: grant.role });
|
|
113
111
|
}
|
|
@@ -142,12 +140,12 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
|
|
|
142
140
|
const parsed = SolutionInstallationIntakeRequestSchema.safeParse(body.value);
|
|
143
141
|
if (!parsed.success)
|
|
144
142
|
return invalid(res, parsed.error);
|
|
145
|
-
const result = await deps.store.setIntakeState({
|
|
143
|
+
const result = await runBusinessStaffOperation(deps, authorized.scope, identity.subject, 'installation:administer', () => deps.store.setIntakeState({
|
|
146
144
|
scope: authorized.scope,
|
|
147
145
|
expectedRevision: parsed.data.expectedRevision,
|
|
148
146
|
active: parsed.data.active,
|
|
149
147
|
actorSubject: identity.subject,
|
|
150
|
-
});
|
|
148
|
+
}));
|
|
151
149
|
if (!result.ok)
|
|
152
150
|
return mutationFailure(res, result);
|
|
153
151
|
return sendJson(res, 200, {
|
|
@@ -213,350 +211,8 @@ export async function handleBusinessGrants(req, res, ref, deps) {
|
|
|
213
211
|
}
|
|
214
212
|
return methodNotAllowed(res);
|
|
215
213
|
}
|
|
216
|
-
export
|
|
217
|
-
|
|
218
|
-
if (identity === false)
|
|
219
|
-
return;
|
|
220
|
-
if (ref.collection === undefined)
|
|
221
|
-
return sendJson(res, 404, { error: 'not found' });
|
|
222
|
-
const collection = ref.collection;
|
|
223
|
-
if (ref.action === 'activity' && req.method === 'GET' && ref.recordId !== undefined) {
|
|
224
|
-
const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
|
|
225
|
-
if (authorized === undefined)
|
|
226
|
-
return;
|
|
227
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
228
|
-
if (definition === undefined)
|
|
229
|
-
return;
|
|
230
|
-
if (definition.authority.authority === 'external') {
|
|
231
|
-
return sendJson(res, 200, { ok: true, data: { activities: [] } });
|
|
232
|
-
}
|
|
233
|
-
return sendNativeRecordActivity(res, url, authorized.installation.scope, collection, ref.recordId, deps.store);
|
|
234
|
-
}
|
|
235
|
-
if (ref.action === 'export' && req.method === 'GET') {
|
|
236
|
-
const authorized = await requireInstallationPermission(res, ref, identity, 'records:export', deps);
|
|
237
|
-
if (authorized === undefined)
|
|
238
|
-
return;
|
|
239
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
240
|
-
if (definition === undefined)
|
|
241
|
-
return;
|
|
242
|
-
const paging = parsePaging(url, 500);
|
|
243
|
-
if (!paging.ok)
|
|
244
|
-
return sendJson(res, 400, { error: paging.error });
|
|
245
|
-
if (definition.authority.authority === 'external') {
|
|
246
|
-
return sendExternalRecordPage(res, authorized.installation, definition, { ...paging.value, limit: paging.value.limit ?? 500 }, deps);
|
|
247
|
-
}
|
|
248
|
-
const page = await cursorRequest(res, () => deps.store.exportRequests({
|
|
249
|
-
scope: authorized.installation.scope,
|
|
250
|
-
collectionKey: collection,
|
|
251
|
-
...paging.value,
|
|
252
|
-
includeDeleted: url.searchParams.get('includeDeleted') === 'true',
|
|
253
|
-
}));
|
|
254
|
-
if (page === undefined)
|
|
255
|
-
return;
|
|
256
|
-
return sendJson(res, 200, {
|
|
257
|
-
ok: true,
|
|
258
|
-
data: {
|
|
259
|
-
records: page.records.map((record) => ({
|
|
260
|
-
...recordToWire(record),
|
|
261
|
-
...(record.content ? { notes: record.content.notes } : {}),
|
|
262
|
-
})),
|
|
263
|
-
...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
|
|
264
|
-
},
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
if (ref.recordId === undefined && req.method === 'GET') {
|
|
268
|
-
const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
|
|
269
|
-
if (authorized === undefined)
|
|
270
|
-
return;
|
|
271
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
272
|
-
if (definition === undefined)
|
|
273
|
-
return;
|
|
274
|
-
const paging = parsePaging(url, 100);
|
|
275
|
-
if (!paging.ok)
|
|
276
|
-
return sendJson(res, 400, { error: paging.error });
|
|
277
|
-
const query = parseNativeRecordQuery(url);
|
|
278
|
-
if (!query.ok)
|
|
279
|
-
return sendJson(res, 400, { error: query.error, code: 'invalid_query' });
|
|
280
|
-
if (definition.authority.authority === 'external') {
|
|
281
|
-
if (Object.keys(query.value).length > 0)
|
|
282
|
-
return sendJson(res, 400, {
|
|
283
|
-
error: 'Field and date queries currently require a native collection.',
|
|
284
|
-
code: 'invalid_query',
|
|
285
|
-
});
|
|
286
|
-
return sendExternalRecordPage(res, authorized.installation, definition, paging.value, deps);
|
|
287
|
-
}
|
|
288
|
-
const statusValue = url.searchParams.get('status');
|
|
289
|
-
const status = statusValue === null ? undefined : ManagedRecordStatusSchema.safeParse(statusValue);
|
|
290
|
-
if (status !== undefined && !status.success)
|
|
291
|
-
return sendJson(res, 400, { error: 'invalid status' });
|
|
292
|
-
const assigneeSubject = url.searchParams.get('assigneeSubject') ?? undefined;
|
|
293
|
-
const page = await cursorRequest(res, () => deps.store.listRequests({
|
|
294
|
-
scope: authorized.installation.scope,
|
|
295
|
-
collectionKey: collection,
|
|
296
|
-
...paging.value,
|
|
297
|
-
...query.value,
|
|
298
|
-
...(status === undefined ? {} : { status: status.data }),
|
|
299
|
-
...(assigneeSubject === undefined ? {} : { assigneeSubject }),
|
|
300
|
-
includeDeleted: url.searchParams.get('includeDeleted') === 'true',
|
|
301
|
-
}));
|
|
302
|
-
if (page === undefined)
|
|
303
|
-
return;
|
|
304
|
-
return sendJson(res, 200, {
|
|
305
|
-
ok: true,
|
|
306
|
-
data: {
|
|
307
|
-
records: page.records.map(recordToWire),
|
|
308
|
-
...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
if (ref.recordId === undefined && req.method === 'POST') {
|
|
313
|
-
const authorized = await requireInstallationPermission(res, ref, identity, 'records:create', deps);
|
|
314
|
-
if (authorized === undefined)
|
|
315
|
-
return;
|
|
316
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
317
|
-
if (definition === undefined)
|
|
318
|
-
return;
|
|
319
|
-
if (definition.authority.authority === 'external') {
|
|
320
|
-
return unsupportedExternalOperation(res, 'create');
|
|
321
|
-
}
|
|
322
|
-
const idempotencyKey = requestIdempotencyKey(req);
|
|
323
|
-
if (idempotencyKey === undefined) {
|
|
324
|
-
return sendJson(res, 400, { error: 'Idempotency-Key header is required (1-128 characters)' });
|
|
325
|
-
}
|
|
326
|
-
const body = await readJsonBody(req, deps.maxBody);
|
|
327
|
-
if (!body.ok)
|
|
328
|
-
return sendJson(res, body.status, { error: body.error });
|
|
329
|
-
const parsed = ManagedRecordCreateRequestSchema.safeParse(body.value);
|
|
330
|
-
if (!parsed.success)
|
|
331
|
-
return invalid(res, parsed.error);
|
|
332
|
-
const result = await createNativeRecord(res, deps, {
|
|
333
|
-
installation: authorized.installation,
|
|
334
|
-
collection,
|
|
335
|
-
idempotencyKey,
|
|
336
|
-
payload: parsed.data.payload,
|
|
337
|
-
origin: { kind: 'portal' },
|
|
338
|
-
actorSubject: identity.subject,
|
|
339
|
-
admit: () => admitBusinessMutation(res, authorized.scope),
|
|
340
|
-
});
|
|
341
|
-
if (result === undefined)
|
|
342
|
-
return;
|
|
343
|
-
if (result.disposition === 'conflict')
|
|
344
|
-
return idempotencyConflict(res);
|
|
345
|
-
if (result.disposition === 'paused') {
|
|
346
|
-
return sendJson(res, 503, {
|
|
347
|
-
error: 'Record creation requires an active application.',
|
|
348
|
-
code: 'application_unavailable',
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
return sendJson(res, result.disposition === 'created' ? 201 : 200, {
|
|
352
|
-
ok: true,
|
|
353
|
-
data: { record: recordToWire(result.record) },
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
if (ref.recordId !== undefined && req.method === 'GET') {
|
|
357
|
-
const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
|
|
358
|
-
if (authorized === undefined)
|
|
359
|
-
return;
|
|
360
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
361
|
-
if (definition === undefined)
|
|
362
|
-
return;
|
|
363
|
-
if (definition.authority.authority === 'external') {
|
|
364
|
-
const loaded = await loadExternalRecord(authorized.installation, definition, ref.recordId, deps);
|
|
365
|
-
if (loaded === undefined)
|
|
366
|
-
return sendJson(res, 503, { error: 'collection source unavailable' });
|
|
367
|
-
if (loaded.record === undefined)
|
|
368
|
-
return sendJson(res, 404, { error: 'record not found' });
|
|
369
|
-
return sendJson(res, 200, {
|
|
370
|
-
ok: true,
|
|
371
|
-
data: {
|
|
372
|
-
record: externalRecordToWire(loaded.record, loaded.binding),
|
|
373
|
-
collection: collectionToWire(definition),
|
|
374
|
-
},
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
const record = await deps.store.getRequest(authorized.installation.scope, collection, ref.recordId);
|
|
378
|
-
if (record === undefined)
|
|
379
|
-
return sendJson(res, 404, { error: 'record not found' });
|
|
380
|
-
return sendJson(res, 200, {
|
|
381
|
-
ok: true,
|
|
382
|
-
data: recordDetailToWire(authorized.installation, record),
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
if (ref.recordId !== undefined && req.method === 'PATCH') {
|
|
386
|
-
const body = await readJsonBody(req, deps.maxBody);
|
|
387
|
-
if (!body.ok)
|
|
388
|
-
return sendJson(res, body.status, { error: body.error });
|
|
389
|
-
const parsed = ManagedRecordMutationRequestSchema.safeParse(body.value);
|
|
390
|
-
if (!parsed.success)
|
|
391
|
-
return invalid(res, parsed.error);
|
|
392
|
-
const permission = mutationPermission(parsed.data.operation);
|
|
393
|
-
const authorized = await requireInstallationPermission(res, ref, identity, permission, deps);
|
|
394
|
-
if (authorized === undefined)
|
|
395
|
-
return;
|
|
396
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
397
|
-
if (definition === undefined)
|
|
398
|
-
return;
|
|
399
|
-
if (definition.authority.authority === 'external') {
|
|
400
|
-
return unsupportedExternalOperation(res, parsed.data.operation);
|
|
401
|
-
}
|
|
402
|
-
if (parsed.data.operation === 'migrate-schema') {
|
|
403
|
-
const result = await deps.store.migrateLegacyRequest({
|
|
404
|
-
scope: authorized.installation.scope,
|
|
405
|
-
collectionKey: collection,
|
|
406
|
-
id: ref.recordId,
|
|
407
|
-
expectedRevision: parsed.data.expectedRevision,
|
|
408
|
-
actorSubject: identity.subject,
|
|
409
|
-
});
|
|
410
|
-
if (!result.ok)
|
|
411
|
-
return mutationFailure(res, result);
|
|
412
|
-
return sendJson(res, 200, { ok: true, data: { record: recordToWire(result.record) } });
|
|
413
|
-
}
|
|
414
|
-
let operation;
|
|
415
|
-
if (parsed.data.operation === 'update') {
|
|
416
|
-
operation = {
|
|
417
|
-
kind: 'update',
|
|
418
|
-
payload: parsed.data.patch,
|
|
419
|
-
...(parsed.data.unset ? { unset: parsed.data.unset } : {}),
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
else if (parsed.data.operation === 'assign') {
|
|
423
|
-
if (parsed.data.assigneeSubject !== null) {
|
|
424
|
-
const assigneeGrant = await deps.store.getGrant(authorized.installation.scope, parsed.data.assigneeSubject);
|
|
425
|
-
if (assigneeGrant === undefined ||
|
|
426
|
-
assigneeGrant.revokedAt !== undefined ||
|
|
427
|
-
assigneeGrant.role === 'viewer') {
|
|
428
|
-
return sendJson(res, 422, {
|
|
429
|
-
error: 'assignee must have an active operator grant',
|
|
430
|
-
code: 'invalid_assignee',
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
operation = {
|
|
435
|
-
kind: 'assign',
|
|
436
|
-
assigneeSubject: parsed.data.assigneeSubject ?? undefined,
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
else if (parsed.data.operation === 'set-status') {
|
|
440
|
-
operation = { kind: 'set_status', status: parsed.data.status };
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
operation = { kind: 'add_note', note: parsed.data.note };
|
|
444
|
-
}
|
|
445
|
-
let result;
|
|
446
|
-
try {
|
|
447
|
-
result = await deps.store.mutateRequest({
|
|
448
|
-
scope: authorized.installation.scope,
|
|
449
|
-
collectionKey: collection,
|
|
450
|
-
id: ref.recordId,
|
|
451
|
-
expectedRevision: parsed.data.expectedRevision,
|
|
452
|
-
actorSubject: identity.subject,
|
|
453
|
-
operation,
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
catch (error) {
|
|
457
|
-
if (error instanceof PayloadValidationError) {
|
|
458
|
-
return sendJson(res, 400, { error: error.message, code: error.code });
|
|
459
|
-
}
|
|
460
|
-
throw error;
|
|
461
|
-
}
|
|
462
|
-
if (!result.ok)
|
|
463
|
-
return mutationFailure(res, result);
|
|
464
|
-
return sendJson(res, 200, { ok: true, data: { record: recordToWire(result.record) } });
|
|
465
|
-
}
|
|
466
|
-
if (ref.recordId !== undefined && req.method === 'DELETE') {
|
|
467
|
-
const authorized = await requireInstallationPermission(res, ref, identity, 'records:delete', deps);
|
|
468
|
-
if (authorized === undefined)
|
|
469
|
-
return;
|
|
470
|
-
const definition = enabledCollection(res, authorized.installation, collection);
|
|
471
|
-
if (definition === undefined)
|
|
472
|
-
return;
|
|
473
|
-
const body = await readJsonBody(req, deps.maxBody);
|
|
474
|
-
if (!body.ok)
|
|
475
|
-
return sendJson(res, body.status, { error: body.error });
|
|
476
|
-
const revision = expectedRevision(body.value);
|
|
477
|
-
if (revision === undefined) {
|
|
478
|
-
return sendJson(res, 400, { error: 'expectedRevision must be a positive integer' });
|
|
479
|
-
}
|
|
480
|
-
if (definition.authority.authority === 'external') {
|
|
481
|
-
const loaded = await loadExternalRecord(authorized.installation, definition, ref.recordId, deps);
|
|
482
|
-
if (loaded === undefined)
|
|
483
|
-
return sendJson(res, 503, { error: 'collection source unavailable' });
|
|
484
|
-
if (loaded.record === undefined)
|
|
485
|
-
return sendJson(res, 404, { error: 'record not found' });
|
|
486
|
-
const { record } = loaded;
|
|
487
|
-
if (record.revision !== revision) {
|
|
488
|
-
return sendJson(res, 409, {
|
|
489
|
-
error: 'record revision conflict',
|
|
490
|
-
code: 'revision_conflict',
|
|
491
|
-
currentRevision: record.revision,
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
await deps.sourceStore?.suppressExternalRecord({
|
|
495
|
-
...sourceBindingKey(authorized.installation, definition),
|
|
496
|
-
sourceId: record.source.id,
|
|
497
|
-
reason: 'customer_request',
|
|
498
|
-
now: now(deps),
|
|
499
|
-
});
|
|
500
|
-
const deletedAt = now(deps).toISOString();
|
|
501
|
-
return sendJson(res, 200, {
|
|
502
|
-
ok: true,
|
|
503
|
-
data: {
|
|
504
|
-
recordId: record.id,
|
|
505
|
-
authority: 'external',
|
|
506
|
-
disposition: 'suppressed',
|
|
507
|
-
deletedAt,
|
|
508
|
-
},
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
const result = await deps.store.deleteRequest({
|
|
512
|
-
scope: authorized.installation.scope,
|
|
513
|
-
collectionKey: collection,
|
|
514
|
-
id: ref.recordId,
|
|
515
|
-
expectedRevision: revision,
|
|
516
|
-
actorSubject: identity.subject,
|
|
517
|
-
reason: 'customer_request',
|
|
518
|
-
});
|
|
519
|
-
if (!result.ok)
|
|
520
|
-
return mutationFailure(res, result);
|
|
521
|
-
return sendJson(res, 200, {
|
|
522
|
-
ok: true,
|
|
523
|
-
data: {
|
|
524
|
-
recordId: result.record.id,
|
|
525
|
-
authority: 'native',
|
|
526
|
-
disposition: 'deleted',
|
|
527
|
-
deletedAt: result.record.deletedAt,
|
|
528
|
-
},
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
return methodNotAllowed(res);
|
|
532
|
-
}
|
|
533
|
-
export async function requireIdentity(req, res, deps) {
|
|
534
|
-
return authorizeBusinessApi(req, res, deps);
|
|
535
|
-
}
|
|
536
|
-
export async function requireInstallationGrant(res, ref, identity, deps, permission) {
|
|
537
|
-
if (ref.installationId === undefined)
|
|
538
|
-
return undefined;
|
|
539
|
-
const installation = await deps.store.getInstallationById(ref.org, ref.installationId);
|
|
540
|
-
if (installation === undefined) {
|
|
541
|
-
sendJson(res, 404, { error: 'installation not found' });
|
|
542
|
-
return undefined;
|
|
543
|
-
}
|
|
544
|
-
const grant = await deps.store.getGrant(installation.scope, identity.subject);
|
|
545
|
-
if (grant?.revokedAt !== undefined || grant === undefined) {
|
|
546
|
-
sendForbidden(res, 'business grant required');
|
|
547
|
-
return undefined;
|
|
548
|
-
}
|
|
549
|
-
if (permission && !businessGrantAllows(grant, permission)) {
|
|
550
|
-
sendForbidden(res, `business permission required: ${permission}`);
|
|
551
|
-
return undefined;
|
|
552
|
-
}
|
|
553
|
-
if (!(await admitBusinessTarget(res, installation.scope)))
|
|
554
|
-
return undefined;
|
|
555
|
-
return { installation, scope: installation.scope, grant };
|
|
556
|
-
}
|
|
557
|
-
export async function requireInstallationPermission(res, ref, identity, permission, deps) {
|
|
558
|
-
return requireInstallationGrant(res, ref, identity, deps, permission);
|
|
559
|
-
}
|
|
214
|
+
export { requireIdentity, requireInstallationGrant, requireInstallationPermission, } from './business-information-access.js';
|
|
215
|
+
export { handleManagedRecords } from './business-information-records.js';
|
|
560
216
|
export function mutationFailure(res, result) {
|
|
561
217
|
const status = result.reason === 'not_found'
|
|
562
218
|
? 404
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
+
import { NativeRecordLifecycleMigrateRequestSchema, NativeRecordLifecyclePreviewResponseSchema, NativeRecordLifecycleResponseSchema, } from '@noodle-borg/wire-contracts';
|
|
3
|
+
import { NativeLifecycleError } from '../business-information/native-record-lifecycle.js';
|
|
4
|
+
import { invalid, methodNotAllowed, requireIdentity, requireInstallationPermission, } from './business-information.js';
|
|
5
|
+
export async function handleNativeRecordLifecycle(req, res, ref, deps) {
|
|
6
|
+
res.setHeader('cache-control', 'private, no-store');
|
|
7
|
+
if (req.method !== 'GET' && req.method !== 'POST')
|
|
8
|
+
return methodNotAllowed(res);
|
|
9
|
+
const identity = await requireIdentity(req, res, deps);
|
|
10
|
+
if (identity === false)
|
|
11
|
+
return;
|
|
12
|
+
const authorized = await requireInstallationPermission(res, ref, identity, 'installation:administer', deps);
|
|
13
|
+
if (!authorized)
|
|
14
|
+
return;
|
|
15
|
+
try {
|
|
16
|
+
if (req.method === 'GET') {
|
|
17
|
+
const data = await deps.store.nativeLifecycle.preview(authorized.scope, identity.subject);
|
|
18
|
+
return sendJson(res, 200, NativeRecordLifecyclePreviewResponseSchema.parse({ ok: true, data }));
|
|
19
|
+
}
|
|
20
|
+
const body = await readJsonBody(req, deps.maxBody);
|
|
21
|
+
if (!body.ok)
|
|
22
|
+
return sendJson(res, body.status, { error: body.error });
|
|
23
|
+
const parsed = NativeRecordLifecycleMigrateRequestSchema.safeParse(body.value);
|
|
24
|
+
if (!parsed.success)
|
|
25
|
+
return invalid(res, parsed.error);
|
|
26
|
+
const data = await deps.store.nativeLifecycle.migrate({
|
|
27
|
+
scope: authorized.scope,
|
|
28
|
+
actor: identity.subject,
|
|
29
|
+
preview: parsed.data.preview,
|
|
30
|
+
});
|
|
31
|
+
return sendJson(res, 200, NativeRecordLifecycleResponseSchema.parse({ ok: true, data }));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (!(error instanceof NativeLifecycleError))
|
|
35
|
+
throw error;
|
|
36
|
+
return sendJson(res, error.code === 'lifecycle_denied' ? 403 : error.code === 'lifecycle_conflict' ? 409 : 503, {
|
|
37
|
+
code: error.code,
|
|
38
|
+
error: error.code === 'lifecycle_conflict'
|
|
39
|
+
? 'The reviewed inventory changed or expired. Review again before applying the migration.'
|
|
40
|
+
: error.code === 'lifecycle_denied'
|
|
41
|
+
? 'Current Owner or Admin permission is required.'
|
|
42
|
+
: 'Native record lifecycle is unavailable.',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=business-native-lifecycle.js.map
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
+
import { BusinessWorkspaceAcceptRequestSchema, BusinessWorkspaceInvitationRequestSchema, BusinessWorkspaceIssuedInvitationResponseSchema, BusinessWorkspaceListResponseSchema, BusinessWorkspaceMutationResponseSchema, BusinessWorkspaceResponseSchema, BusinessWorkspaceRevisionRequestSchema, BusinessWorkspaceRoleChangeRequestSchema, } from '@noodle-borg/wire-contracts';
|
|
3
|
+
import { admitBusinessTarget, authorizeBusinessApi } from '../business-api-admission.js';
|
|
4
|
+
import { BusinessWorkspaceError } from '../business-workspaces/contracts.js';
|
|
5
|
+
import { businessWorkspaceMethod, parseBusinessWorkspacePath, } from '../business-workspaces/paths.js';
|
|
6
|
+
export async function handleBusinessWorkspaceRoute(req, res, url, deps) {
|
|
7
|
+
res.setHeader('cache-control', 'private, no-store');
|
|
8
|
+
try {
|
|
9
|
+
await handle(req, res, url, deps);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error instanceof BusinessWorkspaceError) {
|
|
13
|
+
const status = error.code === 'forbidden'
|
|
14
|
+
? 403
|
|
15
|
+
: error.code === 'invalid_request'
|
|
16
|
+
? 400
|
|
17
|
+
: error.code === 'not_found'
|
|
18
|
+
? 404
|
|
19
|
+
: 409;
|
|
20
|
+
return sendJson(res, status, {
|
|
21
|
+
error: error.code.replaceAll('_', ' '),
|
|
22
|
+
code: error.code,
|
|
23
|
+
...(error.currentRevision === undefined ? {} : { currentRevision: error.currentRevision }),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
sendJson(res, 503, {
|
|
27
|
+
error: 'Workspace access is temporarily unavailable.',
|
|
28
|
+
code: 'workspace_unavailable',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function handle(req, res, url, deps) {
|
|
33
|
+
if (url.pathname === '/v1/me/business-workspaces') {
|
|
34
|
+
const identity = await authorizeBusinessApi(req, res, deps);
|
|
35
|
+
if (!identity)
|
|
36
|
+
return;
|
|
37
|
+
if (req.method !== 'GET') {
|
|
38
|
+
res.setHeader('allow', 'GET');
|
|
39
|
+
return sendJson(res, 405, { error: 'method not allowed' });
|
|
40
|
+
}
|
|
41
|
+
if (new Set(url.searchParams.keys()).size !== [...url.searchParams].length)
|
|
42
|
+
return invalid(res);
|
|
43
|
+
const data = await deps.workspaces.listForSubject(identity.subject, Object.fromEntries(url.searchParams));
|
|
44
|
+
return sendJson(res, 200, BusinessWorkspaceListResponseSchema.parse({ ok: true, data }));
|
|
45
|
+
}
|
|
46
|
+
const ref = parseBusinessWorkspacePath(url.pathname);
|
|
47
|
+
if (!ref)
|
|
48
|
+
return sendJson(res, 404, { error: 'not found' });
|
|
49
|
+
const identity = await authorizeBusinessApi(req, res, deps);
|
|
50
|
+
if (!identity)
|
|
51
|
+
return;
|
|
52
|
+
const method = businessWorkspaceMethod(ref);
|
|
53
|
+
if (req.method !== method) {
|
|
54
|
+
res.setHeader('allow', method);
|
|
55
|
+
return sendJson(res, 405, { error: 'method not allowed' });
|
|
56
|
+
}
|
|
57
|
+
if ([...url.searchParams].length)
|
|
58
|
+
return invalid(res);
|
|
59
|
+
const { org } = ref;
|
|
60
|
+
if (ref.action !== 'accept') {
|
|
61
|
+
const state = await deps.workspaces.inspect(org, identity.subject);
|
|
62
|
+
if (ref.action && !state.permissions.includes('team:manage'))
|
|
63
|
+
throw new BusinessWorkspaceError('forbidden');
|
|
64
|
+
if (!(await admitBusinessTarget(res, { org })))
|
|
65
|
+
return;
|
|
66
|
+
if (!ref.action)
|
|
67
|
+
return sendJson(res, 200, BusinessWorkspaceResponseSchema.parse({ ok: true, data: state }));
|
|
68
|
+
}
|
|
69
|
+
const body = await readJsonBody(req, Math.min(deps.maxBody, 16 * 1024));
|
|
70
|
+
if (!body.ok)
|
|
71
|
+
return sendJson(res, body.status, { error: body.error });
|
|
72
|
+
if (ref.action === 'accept') {
|
|
73
|
+
const input = BusinessWorkspaceAcceptRequestSchema.safeParse(body.value);
|
|
74
|
+
if (!input.success)
|
|
75
|
+
return invalid(res);
|
|
76
|
+
const email = await deps.verifiedEmail?.(identity.subject, identity.email);
|
|
77
|
+
if (!email)
|
|
78
|
+
return sendJson(res, 403, {
|
|
79
|
+
error: 'Sign in with a verified invited email address.',
|
|
80
|
+
code: 'verified_email_required',
|
|
81
|
+
});
|
|
82
|
+
// Subject admission already ran. The opaque one-use invitation supplies authority, not the org in the URL.
|
|
83
|
+
const result = await deps.workspaces.accept({
|
|
84
|
+
org,
|
|
85
|
+
subject: identity.subject,
|
|
86
|
+
verifiedEmail: email,
|
|
87
|
+
token: input.data.token,
|
|
88
|
+
});
|
|
89
|
+
return sendJson(res, 200, BusinessWorkspaceMutationResponseSchema.parse({ ok: true, data: result }));
|
|
90
|
+
}
|
|
91
|
+
if (ref.action === 'invitations' && !ref.id) {
|
|
92
|
+
const input = BusinessWorkspaceInvitationRequestSchema.safeParse(body.value);
|
|
93
|
+
if (!input.success)
|
|
94
|
+
return invalid(res);
|
|
95
|
+
const result = await deps.workspaces.invite({ ...input.data, org, actor: identity.subject });
|
|
96
|
+
return sendJson(res, 201, BusinessWorkspaceIssuedInvitationResponseSchema.parse({ ok: true, data: result }));
|
|
97
|
+
}
|
|
98
|
+
if (ref.action === 'invitations' && ref.id) {
|
|
99
|
+
const input = BusinessWorkspaceRevisionRequestSchema.safeParse(body.value);
|
|
100
|
+
if (!input.success)
|
|
101
|
+
return invalid(res);
|
|
102
|
+
const result = await deps.workspaces.revokeInvitation({
|
|
103
|
+
...input.data,
|
|
104
|
+
org,
|
|
105
|
+
actor: identity.subject,
|
|
106
|
+
invitationId: ref.id,
|
|
107
|
+
});
|
|
108
|
+
return sendJson(res, 200, BusinessWorkspaceMutationResponseSchema.parse({ ok: true, data: result }));
|
|
109
|
+
}
|
|
110
|
+
const input = BusinessWorkspaceRoleChangeRequestSchema.safeParse(body.value);
|
|
111
|
+
if (!input.success)
|
|
112
|
+
return invalid(res);
|
|
113
|
+
const result = await deps.workspaces.changeRole({ ...input.data, org, actor: identity.subject });
|
|
114
|
+
return sendJson(res, 200, BusinessWorkspaceMutationResponseSchema.parse({ ok: true, data: result }));
|
|
115
|
+
}
|
|
116
|
+
function invalid(res) {
|
|
117
|
+
return sendJson(res, 400, { error: 'Invalid workspace request.', code: 'invalid_request' });
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=business-workspaces.js.map
|
|
@@ -16,7 +16,8 @@ function handleServiceProbe(req, res, url, { tls, moduleHost, buildInfo, options
|
|
|
16
16
|
applySecurityHeaders(res, tls);
|
|
17
17
|
if (url.pathname === '/healthz')
|
|
18
18
|
return sendJson(res, 200, { status: 'ok' });
|
|
19
|
-
void Promise.resolve(
|
|
19
|
+
void Promise.resolve()
|
|
20
|
+
.then(() => moduleHost.ready())
|
|
20
21
|
.then((ready) => sendJson(res, ready ? 200 : 503, { status: ready ? 'ready' : 'unready' }))
|
|
21
22
|
.catch(() => sendJson(res, 503, { status: 'unready' }));
|
|
22
23
|
return;
|
|
@@ -36,6 +36,7 @@ import { handleAppArchive, handleAppRestore } from './routes/archive.js';
|
|
|
36
36
|
import { handleAssetPreflight } from './routes/asset-control-plane.js';
|
|
37
37
|
import { dispatchAssistantRoutes } from './routes/assistant-dispatch.js';
|
|
38
38
|
import { dispatchAuthDiscoveryRoute } from './routes/auth-discovery.js';
|
|
39
|
+
import { dispatchBusinessAuthoringRoutes } from './routes/business-authoring-dispatch.js';
|
|
39
40
|
import { dispatchBusinessInformationRoutes } from './routes/business-information-dispatch.js';
|
|
40
41
|
import { dispatchConfigValueRequest } from './routes/config-values-dispatch.js';
|
|
41
42
|
import { authorizeTenantControl, handleDeploymentStatus, handleWhoami, } from './routes/control-plane.js';
|
|
@@ -294,15 +295,21 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
294
295
|
}
|
|
295
296
|
if (servicePrincipalDispatcher?.(req, res, url))
|
|
296
297
|
return;
|
|
298
|
+
if (dispatchBusinessAuthoringRoutes(req, res, url, options.businessAuthoring, {
|
|
299
|
+
gate,
|
|
300
|
+
publicCounters,
|
|
301
|
+
maxBody: maxDeployBody,
|
|
302
|
+
tls,
|
|
303
|
+
}))
|
|
304
|
+
return;
|
|
297
305
|
if (businessInformationStore !== undefined &&
|
|
298
306
|
options.businessInformationEnabled !== false &&
|
|
299
307
|
dispatchBusinessInformationRoutes(req, res, url, {
|
|
300
|
-
authoring: options.businessAuthoring,
|
|
301
308
|
pageOrigin: options.businessPageOrigin,
|
|
302
309
|
pageServiceUrl: options.publicBaseUrl,
|
|
303
|
-
maxDraftBody: maxDeployBody,
|
|
304
310
|
...(whatsapp ? { readWhatsApp: whatsapp.projection.bind(whatsapp) } : {}),
|
|
305
311
|
store: businessInformationStore,
|
|
312
|
+
...(options.businessAuthoring ? { workspaces: options.businessAuthoring.workspaces } : {}),
|
|
306
313
|
...(businessOnboarding ? { businessOnboarding } : {}),
|
|
307
314
|
activateInstallation,
|
|
308
315
|
readInstallationActivation,
|
|
@@ -30,7 +30,9 @@ export function deploymentWebConnector(artifact, tenant, deploymentId, service)
|
|
|
30
30
|
}, call.caller).allow,
|
|
31
31
|
anonymous: call.caller === undefined || call.caller.identityKind === 'anonymous',
|
|
32
32
|
...(call.caller === undefined ? {} : { subject: call.caller.subject }),
|
|
33
|
-
...(call.publicAdmission === undefined
|
|
33
|
+
...(call.publicAdmission?.network === undefined
|
|
34
|
+
? {}
|
|
35
|
+
: { network: call.publicAdmission.network }),
|
|
34
36
|
budget: call.capabilityBudget,
|
|
35
37
|
...(call.signal === undefined ? {} : { signal: call.signal }),
|
|
36
38
|
});
|
|
@@ -37,10 +37,11 @@
|
|
|
37
37
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
+
"@noodle-borg/authoring": "0.0.0",
|
|
40
41
|
"@noodle-borg/managed-capabilities": "0.0.0",
|
|
41
42
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
43
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
43
|
-
"@noodle-borg/agent-kit": "0.
|
|
44
|
+
"@noodle-borg/agent-kit": "0.107.0",
|
|
44
45
|
"@noodle-borg/app-package": "0.0.0",
|
|
45
46
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
46
47
|
"@noodle-borg/auth": "0.0.0",
|