@k2b/cloud 0.42.0 → 0.44.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/package.json +13 -5
- package/scripts/app-favicon.ts +7 -6
- package/scripts/build.ts +3 -0
- package/scripts/installable-assets.ts +61 -0
- package/scripts/preload.ts +3 -0
- package/src/_internal/app-access-path.ts +12 -0
- package/src/_internal/app-access-request.ts +13 -0
- package/src/_internal/app-access-resources.ts +141 -0
- package/src/_internal/app-event-catalog.ts +40 -0
- package/src/_internal/app-event-schemas.ts +127 -0
- package/src/_internal/application-package.ts +40 -0
- package/src/_internal/built-in-app-ids.json +27 -0
- package/src/_internal/capabilities.ts +185 -12
- package/src/_internal/capability-origin.ts +4 -0
- package/src/_internal/capability-streams.ts +10 -5
- package/src/_internal/define-app.ts +159 -45
- package/src/_internal/installable-assets.ts +90 -0
- package/src/_internal/installable-head.ts +22 -0
- package/src/_internal/object-store-area.ts +9 -0
- package/src/_internal/object-store-config.ts +101 -0
- package/src/_internal/object-store-key.ts +14 -0
- package/src/_internal/page-responses.ts +34 -3
- package/src/_internal/process-identity.ts +7 -2
- package/src/_internal/registry-validation.ts +15 -1
- package/src/_internal/registry.ts +44 -1
- package/src/_internal/runtime-context.ts +9 -1
- package/src/_internal/runtime-watcher.ts +8 -0
- package/src/_internal/status-preserving-ssr.ts +12 -1
- package/src/access/AppAccessEditor.browser-fixture.ts +429 -0
- package/src/access/AppAccessEditor.browser-frame.tsx +68 -0
- package/src/access/AppAccessEditor.browser-harness.tsx +65 -0
- package/src/access/AppAccessEditor.tsx +380 -0
- package/src/access/PermissionEditor.browser-harness.tsx +22 -2
- package/src/access/PermissionEditor.tsx +386 -77
- package/src/access/PrincipalAvatar.tsx +63 -0
- package/src/access/PrincipalPicker.tsx +29 -8
- package/src/access/ResourceApiKeys.tsx +3 -4
- package/src/access/app-access-adapter.ts +51 -0
- package/src/access/app-access-messages.ts +172 -0
- package/src/access/messages.ts +14 -0
- package/src/access/ui.ts +4 -1
- package/src/account/Avatar.tsx +21 -3
- package/src/account/ProfilePictureDialog.tsx +699 -0
- package/src/account/profile-picture-messages.ts +269 -0
- package/src/account/ui.ts +8 -1
- package/src/ai/admin.ts +3 -0
- package/src/ai/app-frame.ts +12 -0
- package/src/ai/application-tasks.ts +101 -0
- package/src/ai/assistant-models.ts +126 -64
- package/src/ai/capabilities.ts +19 -4
- package/src/ai/capability-execution.ts +5 -2
- package/src/ai/chart-block.ts +63 -30
- package/src/ai/chat/chart-block.tsx +12 -3
- package/src/ai/chat/composer-adapter.ts +8 -7
- package/src/ai/chat/message-actions.tsx +1 -1
- package/src/ai/chat/message-utils.ts +2 -2
- package/src/ai/chat/presentation.tsx +22 -1
- package/src/ai/chat-quotas.ts +5 -4
- package/src/ai/chat-tasks.ts +2 -2
- package/src/ai/client/controller.ts +11 -10
- package/src/ai/client/projection.ts +3 -3
- package/src/ai/code-capability-routes.ts +1 -0
- package/src/ai/compaction.ts +3 -3
- package/src/ai/credentials.ts +13 -114
- package/src/ai/default-tool-contracts.ts +4 -3
- package/src/ai/dictation-runtime.ts +4 -4
- package/src/ai/enrich.ts +2 -2
- package/src/ai/executor.ts +38 -27
- package/src/ai/http.ts +17 -29
- package/src/ai/index.ts +11 -5
- package/src/ai/inference-calls.ts +6 -4
- package/src/ai/maintenance.ts +1 -1
- package/src/ai/memory-learning-runs.ts +5 -5
- package/src/ai/memory-learning.ts +3 -3
- package/src/ai/message-queue.ts +1 -2
- package/src/ai/migrate.ts +75 -42
- package/src/ai/model-access-migrate.ts +3 -17
- package/src/ai/model-access.ts +44 -85
- package/src/ai/model-card.tsx +134 -0
- package/src/ai/model-catalog.ts +359 -0
- package/src/ai/model-chooser-messages.ts +88 -0
- package/src/ai/model-chooser.tsx +577 -0
- package/src/ai/model-delete.ts +234 -0
- package/src/ai/model-fixture.ts +39 -0
- package/src/ai/model-icon.tsx +36 -0
- package/src/ai/model-overview.ts +53 -0
- package/src/ai/model-usage.ts +45 -0
- package/src/ai/openai-api-messages.ts +0 -4
- package/src/ai/openai-api-slots.ts +10 -2
- package/src/ai/openai-api.ts +83 -16
- package/src/ai/personal-agent.ts +1 -1
- package/src/ai/prefs.ts +12 -10
- package/src/ai/projects-routes.ts +2 -1
- package/src/ai/projects.ts +13 -12
- package/src/ai/protocol.ts +2 -2
- package/src/ai/provider-connections.ts +161 -0
- package/src/ai/provider-errors.ts +138 -0
- package/src/ai/provider-fetch.ts +4 -0
- package/src/ai/provider-retry.ts +1 -1
- package/src/ai/provider.ts +2 -1
- package/src/ai/quota-limits.ts +36 -0
- package/src/ai/quota-provider.ts +11 -2
- package/src/ai/quota-report.ts +7 -4
- package/src/ai/quotas-migrate.ts +1 -0
- package/src/ai/quotas.ts +19 -8
- package/src/ai/recent-resources.ts +6 -0
- package/src/ai/request-headers.ts +14 -87
- package/src/ai/resource-refs.ts +6 -2
- package/src/ai/routes.ts +17 -18
- package/src/ai/runtime.ts +50 -22
- package/src/ai/settings.ts +93 -580
- package/src/ai/store.ts +45 -23
- package/src/ai/stream.ts +1 -1
- package/src/ai/structured-runs.ts +2 -2
- package/src/ai/structured.ts +29 -46
- package/src/ai/task-contracts.ts +25 -5
- package/src/ai/task-execution.ts +15 -6
- package/src/ai/task-model.ts +9 -0
- package/src/ai/transcription.ts +37 -21
- package/src/ai/turn-failure.ts +24 -2
- package/src/ai/types.ts +50 -62
- package/src/ai/ui.tsx +13 -0
- package/src/ai/usage.ts +8 -8
- package/src/ai/validate.ts +8 -7
- package/src/ai/view-block.ts +2 -2
- package/src/api/accounts-entities.ts +40 -16
- package/src/api/admin-ai-quotas.ts +34 -56
- package/src/api/admin-ai-usage.ts +1 -1
- package/src/api/admin-ai.ts +173 -0
- package/src/api/admin-core-settings.ts +68 -244
- package/src/api/admin-directory-shares.ts +55 -0
- package/src/api/admin-identity.ts +81 -2
- package/src/api/app-access.ts +85 -0
- package/src/api/app-approval.ts +3 -1
- package/src/api/app-event-delivery.ts +51 -0
- package/src/api/app-events.ts +123 -0
- package/src/api/app-resource-access.ts +48 -0
- package/src/api/auth/account-mismatch.ts +24 -0
- package/src/api/auth.ts +26 -3
- package/src/api/capabilities.ts +127 -15
- package/src/api/capability-streams.ts +2 -5
- package/src/api/identity-child-invocation.ts +145 -0
- package/src/api/index.ts +11 -2
- package/src/api/mcp.ts +180 -5
- package/src/api/me.ts +38 -17
- package/src/api/pwa-phone.ts +87 -48
- package/src/api/pwa.ts +34 -8
- package/src/api/resource-links.ts +83 -6
- package/src/api/resource-resolve.ts +50 -0
- package/src/api/search/schemas.ts +3 -1
- package/src/api/search.ts +9 -7
- package/src/api/widgets.ts +1 -0
- package/src/app-pwa/authority.ts +75 -0
- package/src/app-pwa/contracts.ts +177 -0
- package/src/app-pwa/core-query-error.ts +20 -0
- package/src/app-pwa/index.ts +23 -0
- package/src/app-pwa/protocol.ts +27 -0
- package/src/app-pwa/schema.ts +59 -0
- package/src/app-pwa/service.ts +861 -0
- package/src/app-pwa/transaction.ts +338 -0
- package/src/app-pwa/transport-input.ts +57 -0
- package/src/app-pwa/transport.ts +235 -0
- package/src/approvals/messages.ts +2 -2
- package/src/browser/app-access-recovery.ts +44 -0
- package/src/browser/app-session.ts +14 -3
- package/src/browser/cloud-id.ts +86 -0
- package/src/browser/live-websocket.ts +5 -0
- package/src/browser/pwa-drafts.ts +57 -0
- package/src/browser/resource-clipboard.ts +4 -0
- package/src/browser/resource-links.ts +52 -0
- package/src/browser/resource-picker.tsx +3 -2
- package/src/capabilities/calendar-sources.ts +302 -0
- package/src/capabilities/executions.ts +10 -3
- package/src/capabilities/migrate.ts +4 -0
- package/src/capabilities/nested.ts +43 -0
- package/src/capabilities/server-invoke.ts +202 -0
- package/src/capabilities/server.ts +26 -187
- package/src/capabilities/testing.ts +5 -2
- package/src/cli/access.ts +6 -5
- package/src/cli/account.ts +57 -0
- package/src/cli/admin/agents.ts +66 -0
- package/src/cli/admin/ai-models.ts +199 -0
- package/src/cli/admin/ai-quotas.ts +6 -102
- package/src/cli/admin/ai-usage.ts +4 -4
- package/src/cli/admin/app-credentials.ts +5 -3
- package/src/cli/admin/index.ts +7 -3
- package/src/cli/app-access.ts +60 -0
- package/src/cli/apps.ts +89 -26
- package/src/cli/avatar.ts +64 -0
- package/src/cli/capabilities.ts +22 -1
- package/src/cli/events.ts +320 -0
- package/src/cli/index.ts +1 -1
- package/src/config/env.ts +40 -0
- package/src/contracts/app-access.ts +52 -5
- package/src/contracts/app-approval.ts +8 -1
- package/src/contracts/app-details.ts +89 -0
- package/src/contracts/app-events.ts +51 -0
- package/src/contracts/app.ts +24 -5
- package/src/contracts/calendar-source.ts +274 -0
- package/src/contracts/calendar-view.ts +35 -0
- package/src/contracts/capabilities.ts +164 -3
- package/src/contracts/geo-admin.ts +2 -0
- package/src/contracts/geo-route.ts +0 -11
- package/src/contracts/geo.ts +14 -2
- package/src/contracts/index.ts +6 -0
- package/src/contracts/installable.ts +40 -0
- package/src/contracts/notification-types.ts +36 -9
- package/src/contracts/profile.ts +32 -0
- package/src/contracts/pwa-builds.ts +14 -0
- package/src/contracts/pwa-location.ts +38 -0
- package/src/contracts/pwa.ts +24 -3
- package/src/contracts/registry.ts +8 -0
- package/src/contracts/resource-clipboard.ts +35 -0
- package/src/contracts/resource-pages.ts +140 -0
- package/src/contracts/resource-resolution.ts +13 -0
- package/src/contracts/shared.ts +4 -0
- package/src/contracts/user-notifications.ts +2 -0
- package/src/events/app-event-delivery.ts +100 -0
- package/src/events/app-events.testing.ts +65 -0
- package/src/events/app-events.ts +134 -0
- package/src/events/core-user-created.ts +24 -0
- package/src/events/index.ts +9 -0
- package/src/events/testing.ts +2 -0
- package/src/index.ts +2 -1
- package/src/server/api/respond.ts +8 -3
- package/src/server/index.ts +1 -0
- package/src/server/middleware/app-access.ts +7 -6
- package/src/server/middleware/auth.ts +168 -66
- package/src/server/middleware/index.ts +1 -0
- package/src/server/middleware/invocation.ts +4 -2
- package/src/server/middleware/workload.ts +3 -3
- package/src/server/oauth-scope.ts +10 -0
- package/src/server/public-storage.ts +106 -0
- package/src/server/services/access.ts +8 -0
- package/src/services/accounts/app.ts +35 -3
- package/src/services/accounts/avatar.ts +342 -35
- package/src/services/accounts/base-group.ts +4 -5
- package/src/services/accounts/directory-shares.ts +157 -0
- package/src/services/accounts/entities.ts +50 -6
- package/src/services/accounts/groups.ts +3 -1
- package/src/services/accounts/identities.ts +64 -12
- package/src/services/accounts/local-groups.ts +1 -1
- package/src/services/accounts/users.ts +23 -15
- package/src/services/app-access-management.ts +519 -0
- package/src/services/app-access.ts +25 -7
- package/src/services/app-approval.ts +15 -4
- package/src/services/app-details.ts +224 -0
- package/src/services/app-discovery.ts +2 -1
- package/src/services/app-event-shapes.ts +139 -0
- package/src/services/app-events/accept.ts +116 -0
- package/src/services/app-events/admin.ts +250 -0
- package/src/services/app-events/declarations.ts +187 -0
- package/src/services/app-events/deliver.ts +218 -0
- package/src/services/app-events.ts +92 -0
- package/src/services/config-conflict.ts +11 -0
- package/src/services/core-user-events.ts +1 -0
- package/src/services/freeipa-config.ts +9 -0
- package/src/services/geo/admin.ts +4 -1
- package/src/services/geo/ledger.ts +47 -14
- package/src/services/geo/route-chain.ts +40 -18
- package/src/services/geo/route-estimate.ts +19 -0
- package/src/services/geo/route-plan.ts +0 -2
- package/src/services/geo/route-service.ts +57 -39
- package/src/services/geo/service.ts +51 -25
- package/src/services/identity/core-origin.ts +12 -0
- package/src/services/identity/index.ts +2 -1
- package/src/services/identity/invocation-actor.ts +50 -2
- package/src/services/identity/invocation-authority.ts +38 -1
- package/src/services/identity/invocation-token.ts +255 -50
- package/src/services/identity/issue-invocation.ts +9 -1
- package/src/services/identity/models-only-auth.ts +13 -4
- package/src/services/identity/nested-invocation.ts +128 -0
- package/src/services/image-metadata.ts +65 -1
- package/src/services/index.ts +24 -1
- package/src/services/ipa/sync.ts +6 -2
- package/src/services/ipa/users.ts +4 -1
- package/src/services/mandates/policy.ts +19 -12
- package/src/services/notifications/browser.ts +4 -0
- package/src/services/notifications/catalog.ts +5 -2
- package/src/services/notifications/platform.ts +7 -2
- package/src/services/notifications/user.ts +18 -7
- package/src/services/oauth-tokens.ts +28 -2
- package/src/services/object-store.ts +217 -0
- package/src/services/providers/local/users.ts +5 -0
- package/src/services/pwa-devices.ts +147 -37
- package/src/services/service-account-credentials.ts +5 -2
- package/src/services/session/index.ts +14 -0
- package/src/services/settings/core-settings.ts +91 -47
- package/src/services/settings/index.ts +8 -0
- package/src/services/settings/versions.ts +26 -0
- package/src/shared/ai-models.ts +274 -0
- package/src/shared/ai-quotas.ts +2 -2
- package/src/shared/ai-usage.ts +2 -2
- package/src/shared/index.ts +2 -0
- package/src/shared-text/documents.ts +25 -8
- package/src/shared-text/log.ts +1 -1
- package/src/shared-text/text-diff.ts +75 -0
- package/src/ssr/AdminArea.tsx +131 -0
- package/src/ssr/AdminLayout.tsx +11 -3
- package/src/ssr/AdminSidebar.tsx +7 -7
- package/src/ssr/AppAccessDenied.tsx +114 -0
- package/src/ssr/AppBadge.tsx +14 -0
- package/src/ssr/AppLaunchpadPanel.tsx +1 -1
- package/src/ssr/AppPwaRuntime.island.tsx +82 -0
- package/src/ssr/CloudShell.island.tsx +25 -4
- package/src/ssr/Layout.tsx +15 -7
- package/src/ssr/PwaLayout.tsx +73 -8
- package/src/ssr/PwaPartCount.island.tsx +23 -0
- package/src/ssr/PwaRuntime.island.tsx +85 -6
- package/src/ssr/SettingsSaveOutcome.tsx +58 -0
- package/src/ssr/SettingsSaveStatus.island.tsx +16 -0
- package/src/ssr/ShellRuntime.island.tsx +5 -0
- package/src/ssr/__snapshots__/Layout.unchanged.render.test.tsx.snap +3 -3
- package/src/ssr/__snapshots__/LayoutHelp.ssr.render.test.tsx.snap +1 -1
- package/src/ssr/admin-active-link.ts +16 -0
- package/src/ssr/admin-navigation.ts +26 -20
- package/src/ssr/app-badges.ts +31 -7
- package/src/ssr/app-pwa-document.tsx +16 -0
- package/src/ssr/app-pwa-messages.ts +17 -0
- package/src/ssr/index.ts +8 -0
- package/src/ssr/layout-context.ts +1 -1
- package/src/ssr/page-trail-runtime.ts +3 -1
- package/src/ssr/platform-messages.ts +9 -1
- package/src/ssr/pwa-messages.ts +10 -2
- package/src/ssr/rail-navigation.ts +5 -1
- package/src/ssr/settings-draft.ts +153 -0
- package/src/ssr/shell-data.tsx +2 -0
- package/src/styles/global.css +1 -0
- package/src/styles/profile-picture.css +270 -0
- package/src/styles/utilities-navigation.css +6 -0
- package/src/workflows/ai/policy.ts +49 -0
- package/src/workflows/ai/runtime.ts +131 -21
- package/src/workflows/ai/store.ts +283 -35
- package/src/workflows/ai/types.ts +8 -2
- package/src/workflows/ai-actions.ts +148 -120
- package/src/workflows/authoring.ts +31 -0
- package/src/workflows/contracts.ts +1 -0
- package/src/workflows/definition.ts +2 -0
- package/src/workflows/editor.ts +15 -0
- package/src/workflows/index.ts +2 -1
- package/src/workflows/language/compiler.ts +34 -3
- package/src/workflows/runtime/executor.ts +132 -33
- package/src/workflows/runtime/index.ts +2 -0
- package/src/workflows/runtime/ports.ts +5 -1
- package/src/workflows/store/actions.ts +1 -1
- package/src/workflows/store/definitions.ts +5 -0
- package/src/workflows/store/runs.ts +5 -3
- package/src/workflows/store/worker.ts +7 -2
- package/src/ai/model-pricing.ts +0 -43
- package/src/ai/model-request-settings.ts +0 -98
- package/src/ai/settings-messages.ts +0 -129
- package/src/shared/ai-model-request-settings.ts +0 -21
|
@@ -54,6 +54,9 @@ export const capabilityValueMeta = (value: unknown): CapabilityValueMeta => {
|
|
|
54
54
|
export type CapabilityExecutionInput = {
|
|
55
55
|
/** Correlation id shared with the invocation token, the app audit row, and request logs. */
|
|
56
56
|
requestId: string;
|
|
57
|
+
invocationId?: string | null;
|
|
58
|
+
parentInvocationId?: string | null;
|
|
59
|
+
viaAppId?: string | null;
|
|
57
60
|
origin: CapabilityOrigin;
|
|
58
61
|
appId: string;
|
|
59
62
|
/** Fully qualified capability name, such as `contacts.list`. */
|
|
@@ -79,6 +82,9 @@ export type CapabilityExecutionInput = {
|
|
|
79
82
|
export type CapabilityExecution = {
|
|
80
83
|
id: string;
|
|
81
84
|
requestId: string;
|
|
85
|
+
invocationId?: string | null;
|
|
86
|
+
parentInvocationId?: string | null;
|
|
87
|
+
viaAppId?: string | null;
|
|
82
88
|
origin: CapabilityOrigin;
|
|
83
89
|
appId: string;
|
|
84
90
|
capability: string;
|
|
@@ -115,12 +121,12 @@ export const recordCapabilityExecution = async (input: CapabilityExecutionInput)
|
|
|
115
121
|
deadline.check();
|
|
116
122
|
const [row] = await db<{ id: string }[]>`
|
|
117
123
|
INSERT INTO capabilities.executions (
|
|
118
|
-
request_id, origin, app_id, capability, kind, destructive,
|
|
124
|
+
request_id, invocation_id, parent_invocation_id, via_app_id, origin, app_id, capability, kind, destructive,
|
|
119
125
|
actor_kind, actor_id, user_id, access_subject_type, access_subject_id,
|
|
120
126
|
status, error_code, input_meta, output_meta, idempotency_key, replayed,
|
|
121
127
|
started_at, completed_at, duration_ms
|
|
122
128
|
) VALUES (
|
|
123
|
-
${input.requestId}, ${input.origin}, ${input.appId}, ${input.capability}, ${input.kind}, ${input.destructive},
|
|
129
|
+
${input.requestId}, ${input.invocationId ?? null}, ${input.parentInvocationId ?? null}, ${input.viaAppId ?? null}, ${input.origin}, ${input.appId}, ${input.capability}, ${input.kind}, ${input.destructive},
|
|
124
130
|
${input.actorKind ?? null}, ${input.actorId ?? null}, ${input.userId ?? null},
|
|
125
131
|
${input.accessSubject?.type ?? null}, ${input.accessSubject?.id ?? null},
|
|
126
132
|
${input.status}, ${input.errorCode ?? null},
|
|
@@ -168,7 +174,8 @@ const filterSql = (filter: CapabilityExecutionFilter) => sql`
|
|
|
168
174
|
`;
|
|
169
175
|
|
|
170
176
|
const columns = () => sql`
|
|
171
|
-
execution.id::text AS id, execution.request_id AS "requestId",
|
|
177
|
+
execution.id::text AS id, execution.request_id AS "requestId",
|
|
178
|
+
execution.invocation_id::text AS "invocationId", execution.parent_invocation_id::text AS "parentInvocationId", execution.via_app_id AS "viaAppId", execution.origin, execution.app_id AS "appId",
|
|
172
179
|
execution.capability, execution.kind, execution.destructive,
|
|
173
180
|
execution.actor_kind AS "actorKind", execution.actor_id::text AS "actorId", execution.user_id::text AS "userId",
|
|
174
181
|
execution.access_subject_type AS "accessSubjectType", execution.access_subject_id::text AS "accessSubjectId",
|
|
@@ -55,6 +55,10 @@ export const migrateCloudCapabilities = async (): Promise<void> => {
|
|
|
55
55
|
|
|
56
56
|
await sql`ALTER TABLE capabilities.executions ADD COLUMN IF NOT EXISTS replayed BOOLEAN NOT NULL DEFAULT false`.simple();
|
|
57
57
|
|
|
58
|
+
await sql`ALTER TABLE capabilities.executions ADD COLUMN IF NOT EXISTS invocation_id UUID`.simple();
|
|
59
|
+
await sql`ALTER TABLE capabilities.executions ADD COLUMN IF NOT EXISTS parent_invocation_id UUID`.simple();
|
|
60
|
+
await sql`ALTER TABLE capabilities.executions ADD COLUMN IF NOT EXISTS via_app_id TEXT`.simple();
|
|
61
|
+
|
|
58
62
|
// Platform-owned idempotency claims. One row per
|
|
59
63
|
// (app, capability, principal, key); the dispatcher claims before it
|
|
60
64
|
// forwards and resolves the row once the outcome is known. Response bodies
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { env } from "../config/env";
|
|
2
|
+
import type { CapabilityExecutionContext } from "../contracts/capabilities";
|
|
3
|
+
import { capabilityMessages } from "../shared/capability-messages";
|
|
4
|
+
import { invokeCapabilityWithDataSchema } from "./server";
|
|
5
|
+
|
|
6
|
+
/** Framework-owned closure: the invocation credential never becomes handler data. */
|
|
7
|
+
export const createNestedCapabilityQuery =
|
|
8
|
+
(source: Request): NonNullable<CapabilityExecutionContext["query"]> =>
|
|
9
|
+
async (invocation, schema) => {
|
|
10
|
+
if (!env.CLOUD_CORE_INTERNAL_ORIGIN)
|
|
11
|
+
return {
|
|
12
|
+
ok: false,
|
|
13
|
+
error: {
|
|
14
|
+
code: "APP_UNAVAILABLE",
|
|
15
|
+
message: capabilityMessages(source.headers.get("x-cloud-locale") ?? undefined).cloudUnavailable,
|
|
16
|
+
status: 503,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
return invokeCapabilityWithDataSchema({ ...invocation, kind: "query" }, schema, {
|
|
20
|
+
signal: source.signal,
|
|
21
|
+
locale: source.headers.get("x-cloud-locale"),
|
|
22
|
+
transport: async (request) => {
|
|
23
|
+
const match = new URL(request.url).pathname.match(/^\/api\/capabilities\/v1\/queries\/([^/]+)\/([^/]+)$/);
|
|
24
|
+
if (!match) throw new Error("Only a nested Query is supported");
|
|
25
|
+
const { input } = await request.json();
|
|
26
|
+
const headers = new Headers({ "content-type": "application/json" });
|
|
27
|
+
const token = source.headers.get("authorization");
|
|
28
|
+
if (!token) throw new Error("A parent invocation is required");
|
|
29
|
+
headers.set("authorization", token);
|
|
30
|
+
for (const name of ["x-cloud-locale", "traceparent", "tracestate"]) {
|
|
31
|
+
const value = source.headers.get(name);
|
|
32
|
+
if (value) headers.set(name, value);
|
|
33
|
+
}
|
|
34
|
+
return fetch(new URL("/api/_internal/identity/v1/invoke-child", request.url), {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers,
|
|
37
|
+
signal: request.signal,
|
|
38
|
+
redirect: "error",
|
|
39
|
+
body: JSON.stringify({ targetApp: decodeURIComponent(match[1]!), capabilityId: decodeURIComponent(match[2]!), input }),
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { dispatchCapability, loadCapabilityCatalogPage } from "../api/capabilities";
|
|
3
|
+
import {
|
|
4
|
+
CAPABILITY_FRAMEWORK_ERROR_CODES,
|
|
5
|
+
CAPABILITY_MAX_CATALOG_BYTES,
|
|
6
|
+
CapabilityCatalogSchema,
|
|
7
|
+
type CapabilityOrigin,
|
|
8
|
+
capabilityResultSchema,
|
|
9
|
+
} from "../contracts/capabilities";
|
|
10
|
+
import type { RequestAuthority } from "../server";
|
|
11
|
+
import { coreOrigin } from "../services/identity/core-origin";
|
|
12
|
+
import { capabilityMessages } from "../shared/capability-messages";
|
|
13
|
+
import { LOCALE_HEADER } from "../shared/locale";
|
|
14
|
+
import { readCapabilityResponse } from "./response";
|
|
15
|
+
import { combineCapabilitySignals } from "./signals";
|
|
16
|
+
import type { CapabilityCatalogClientResult, CapabilityClientError, CapabilityClientResult, CapabilityInvocation } from "./types";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The server capability client: the caller's credentials, the request to Core, invocation, and the catalog. Its own
|
|
20
|
+
* module, so readers built on it, such as the calendar reader, and the public `capabilities/server` entry share it.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export type CapabilityCaller = {
|
|
24
|
+
/** Core-only in-process authority; other applications must use a Core transport. */
|
|
25
|
+
authority?: RequestAuthority;
|
|
26
|
+
/** Trusted server transport to Core. Never supplied by a browser or sandbox. */
|
|
27
|
+
transport?: (request: Request) => Promise<Response>;
|
|
28
|
+
origin?: CapabilityOrigin;
|
|
29
|
+
|
|
30
|
+
authorization?: string | null;
|
|
31
|
+
cookie?: string | null;
|
|
32
|
+
requestId?: string | null;
|
|
33
|
+
traceparent?: string | null;
|
|
34
|
+
tracestate?: string | null;
|
|
35
|
+
/** BCP 47 locale of the originating request, forwarded as invocation metadata. */
|
|
36
|
+
locale?: string | null;
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
/** Durable background authority. `authorization` must be the owning app's workload credential. */
|
|
39
|
+
mandate?: { id: string; revision: number; callingAppId: string };
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export { coreOrigin } from "../services/identity/core-origin";
|
|
43
|
+
|
|
44
|
+
export const callerRequest = async (
|
|
45
|
+
caller: CapabilityCaller,
|
|
46
|
+
path: string,
|
|
47
|
+
idempotencyKey?: string,
|
|
48
|
+
invocationSignal?: AbortSignal,
|
|
49
|
+
): Promise<Request> => {
|
|
50
|
+
const headers = new Headers();
|
|
51
|
+
if (caller.authorization) headers.set("authorization", caller.authorization);
|
|
52
|
+
if (!caller.mandate) {
|
|
53
|
+
if (caller.cookie) headers.set("cookie", caller.cookie);
|
|
54
|
+
if (caller.requestId) headers.set("x-request-id", caller.requestId);
|
|
55
|
+
if (caller.traceparent) headers.set("traceparent", caller.traceparent);
|
|
56
|
+
if (caller.tracestate) headers.set("tracestate", caller.tracestate);
|
|
57
|
+
if (caller.locale) headers.set(LOCALE_HEADER, caller.locale);
|
|
58
|
+
if (idempotencyKey) headers.set("idempotency-key", idempotencyKey);
|
|
59
|
+
} else {
|
|
60
|
+
headers.set("x-cloud-app-id", caller.mandate.callingAppId);
|
|
61
|
+
}
|
|
62
|
+
const signal = combineCapabilitySignals(caller.signal, invocationSignal);
|
|
63
|
+
return new Request(new URL(path, await coreOrigin(caller.mandate !== undefined)), { method: "POST", headers, signal });
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const unavailable = (
|
|
67
|
+
cause: unknown,
|
|
68
|
+
invocation?: Pick<CapabilityInvocation, "kind" | "idempotencyKey">,
|
|
69
|
+
locale?: string,
|
|
70
|
+
): { ok: false; error: CapabilityClientError } => ({
|
|
71
|
+
ok: false,
|
|
72
|
+
error:
|
|
73
|
+
invocation?.kind === "action" && !invocation.idempotencyKey
|
|
74
|
+
? {
|
|
75
|
+
code: CAPABILITY_FRAMEWORK_ERROR_CODES.actionOutcomeUnknown,
|
|
76
|
+
message: capabilityMessages(locale).actionOutcomeUnknown,
|
|
77
|
+
status: 502,
|
|
78
|
+
details: { retrySafe: false },
|
|
79
|
+
}
|
|
80
|
+
: cause instanceof Error && cause.name === "AbortError"
|
|
81
|
+
? {
|
|
82
|
+
code: CAPABILITY_FRAMEWORK_ERROR_CODES.requestCancelled,
|
|
83
|
+
message: capabilityMessages(locale).requestCancelled,
|
|
84
|
+
status: 499,
|
|
85
|
+
}
|
|
86
|
+
: {
|
|
87
|
+
code: CAPABILITY_FRAMEWORK_ERROR_CODES.appUnavailable,
|
|
88
|
+
message: capabilityMessages(locale).cloudUnavailable,
|
|
89
|
+
status: 503,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const invokeCapabilityWithResultSchema = async <TDataSchema extends z.ZodType, TInput = unknown>(
|
|
94
|
+
invocation: CapabilityInvocation<TInput>,
|
|
95
|
+
dataSchema: TDataSchema,
|
|
96
|
+
caller: CapabilityCaller,
|
|
97
|
+
): Promise<CapabilityClientResult<z.output<TDataSchema>>> => {
|
|
98
|
+
try {
|
|
99
|
+
const path = caller.mandate
|
|
100
|
+
? "/api/_internal/identity/v1/invoke"
|
|
101
|
+
: `/api/capabilities/v1/${invocation.kind === "query" ? "queries" : "actions"}/${encodeURIComponent(invocation.appId)}/${encodeURIComponent(invocation.capabilityId)}`;
|
|
102
|
+
const request = await callerRequest(caller, path, invocation.idempotencyKey, invocation.signal);
|
|
103
|
+
if (caller.authority) {
|
|
104
|
+
if (caller.authorization || caller.cookie || caller.mandate || caller.transport)
|
|
105
|
+
throw new Error("Use exactly one capability authority source");
|
|
106
|
+
const outcome = await dispatchCapability({
|
|
107
|
+
request,
|
|
108
|
+
kind: invocation.kind === "query" ? "queries" : "actions",
|
|
109
|
+
appId: invocation.appId,
|
|
110
|
+
capabilityId: invocation.capabilityId,
|
|
111
|
+
input: invocation.input,
|
|
112
|
+
authority: caller.authority,
|
|
113
|
+
locale: caller.locale ?? undefined,
|
|
114
|
+
origin: caller.origin ?? "app",
|
|
115
|
+
});
|
|
116
|
+
return readCapabilityResponse(outcome, capabilityResultSchema(dataSchema, { consumer: true }));
|
|
117
|
+
}
|
|
118
|
+
const response = await (caller.transport ?? fetch)(
|
|
119
|
+
new Request(request, {
|
|
120
|
+
body: JSON.stringify(
|
|
121
|
+
caller.mandate
|
|
122
|
+
? {
|
|
123
|
+
kind: invocation.kind,
|
|
124
|
+
targetApp: invocation.appId,
|
|
125
|
+
capabilityId: invocation.capabilityId,
|
|
126
|
+
input: invocation.input,
|
|
127
|
+
mandateId: caller.mandate.id,
|
|
128
|
+
mandateRevision: caller.mandate.revision,
|
|
129
|
+
...(invocation.idempotencyKey ? { idempotencyKey: invocation.idempotencyKey } : {}),
|
|
130
|
+
...(caller.requestId || caller.traceparent || caller.tracestate || caller.locale
|
|
131
|
+
? {
|
|
132
|
+
metadata: {
|
|
133
|
+
...(caller.requestId ? { requestId: caller.requestId } : {}),
|
|
134
|
+
...(caller.traceparent ? { traceparent: caller.traceparent } : {}),
|
|
135
|
+
...(caller.tracestate ? { tracestate: caller.tracestate } : {}),
|
|
136
|
+
...(caller.locale ? { locale: caller.locale } : {}),
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
: {}),
|
|
140
|
+
}
|
|
141
|
+
: { input: invocation.input },
|
|
142
|
+
),
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
return readCapabilityResponse(response, capabilityResultSchema(dataSchema, { consumer: true }));
|
|
146
|
+
} catch (cause) {
|
|
147
|
+
return unavailable(cause, invocation, caller.locale ?? undefined);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const invokeCapability = <TInput = unknown>(
|
|
152
|
+
invocation: CapabilityInvocation<TInput>,
|
|
153
|
+
caller: CapabilityCaller,
|
|
154
|
+
): Promise<CapabilityClientResult<unknown>> => invokeCapabilityWithResultSchema(invocation, z.unknown(), caller);
|
|
155
|
+
|
|
156
|
+
export const invokeCapabilityWithDataSchema = <TDataSchema extends z.ZodType, TInput = unknown>(
|
|
157
|
+
invocation: CapabilityInvocation<TInput>,
|
|
158
|
+
dataSchema: TDataSchema,
|
|
159
|
+
caller: CapabilityCaller,
|
|
160
|
+
): Promise<CapabilityClientResult<z.output<TDataSchema>>> => invokeCapabilityWithResultSchema(invocation, dataSchema, caller);
|
|
161
|
+
|
|
162
|
+
export const listCapabilityCatalog = async (
|
|
163
|
+
options: { cursor?: string; limit?: number; locale?: string; authority?: RequestAuthority | null; caller?: CapabilityCaller } = {},
|
|
164
|
+
): Promise<CapabilityCatalogClientResult> => {
|
|
165
|
+
const limit = options.limit ?? 25;
|
|
166
|
+
const messages = capabilityMessages(options.locale);
|
|
167
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 25) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
error: { code: "VALIDATION_FAILED", message: messages.catalogLimit({ max: 25 }), status: 400 },
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
if (options.caller) {
|
|
175
|
+
const caller = options.caller;
|
|
176
|
+
if (options.authority) throw new Error("Use one catalog authority source");
|
|
177
|
+
if (caller.authority && (caller.authorization || caller.cookie || caller.mandate || caller.transport))
|
|
178
|
+
throw new Error("Use exactly one capability authority source");
|
|
179
|
+
if (caller.authority)
|
|
180
|
+
return {
|
|
181
|
+
ok: true,
|
|
182
|
+
data: await loadCapabilityCatalogPage({ cursor: options.cursor, limit }, {}, caller.locale ?? options.locale, caller.authority),
|
|
183
|
+
};
|
|
184
|
+
if (caller.mandate) throw new Error("Calendar discovery requires request credentials");
|
|
185
|
+
const query = new URLSearchParams({ limit: String(limit) });
|
|
186
|
+
if (options.cursor) query.set("cursor", options.cursor);
|
|
187
|
+
const request = new Request(await callerRequest(caller, `/api/capabilities/v1/catalog?${query}`), { method: "GET" });
|
|
188
|
+
return await readCapabilityResponse(
|
|
189
|
+
await (caller.transport ?? fetch)(request),
|
|
190
|
+
CapabilityCatalogSchema,
|
|
191
|
+
CAPABILITY_MAX_CATALOG_BYTES,
|
|
192
|
+
caller.signal,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
ok: true,
|
|
197
|
+
data: await loadCapabilityCatalogPage({ cursor: options.cursor, limit }, {}, options.locale, options.authority ?? null),
|
|
198
|
+
};
|
|
199
|
+
} catch {
|
|
200
|
+
return { ok: false, error: { code: "APP_UNAVAILABLE", message: messages.cloudUnavailable, status: 503 } };
|
|
201
|
+
}
|
|
202
|
+
};
|
|
@@ -1,35 +1,25 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
1
|
import { resolveCapabilityActionWording, resolveCapabilityManifestPresentation } from "../_internal/capabilities";
|
|
3
2
|
import type { CapabilityActionWording } from "../_internal/capability-sentences";
|
|
4
3
|
import { getApp, getCapability } from "../_internal/registry";
|
|
5
|
-
import { dispatchCapability
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
CAPABILITY_FRAMEWORK_ERROR_CODES,
|
|
9
|
-
CAPABILITY_MAX_REVIEW_RESPONSE_BYTES,
|
|
10
|
-
CapabilityActionReviewDataSchema,
|
|
11
|
-
type CapabilityOrigin,
|
|
12
|
-
capabilityResultSchema,
|
|
13
|
-
} from "../contracts/capabilities";
|
|
4
|
+
import { dispatchCapability } from "../api/capabilities";
|
|
5
|
+
import { CAPABILITY_MAX_REVIEW_RESPONSE_BYTES, CapabilityActionReviewDataSchema } from "../contracts/capabilities";
|
|
14
6
|
import type { RequestAuthority } from "../server";
|
|
15
7
|
import { canUseApp } from "../services/app-access";
|
|
16
|
-
import { get } from "../services/settings";
|
|
17
8
|
import { resolveAppPresentation } from "../shared/app-presentation";
|
|
18
|
-
import { publicCloudOrigin } from "../shared/app-url";
|
|
19
9
|
import { capabilityMessages } from "../shared/capability-messages";
|
|
20
10
|
import { DEFAULT_LOCALE, LOCALE_HEADER } from "../shared/locale";
|
|
21
11
|
import { readCapabilityResponse } from "./response";
|
|
12
|
+
import { type CapabilityCaller, callerRequest, coreOrigin, unavailable } from "./server-invoke";
|
|
22
13
|
import { combineCapabilitySignals } from "./signals";
|
|
23
|
-
import type {
|
|
24
|
-
CapabilityCatalogAppClientResult,
|
|
25
|
-
CapabilityCatalogClientResult,
|
|
26
|
-
CapabilityClientError,
|
|
27
|
-
CapabilityClientResult,
|
|
28
|
-
CapabilityInvocation,
|
|
29
|
-
CapabilityReviewClientResult,
|
|
30
|
-
} from "./types";
|
|
14
|
+
import type { CapabilityCatalogAppClientResult, CapabilityInvocation, CapabilityReviewClientResult } from "./types";
|
|
31
15
|
|
|
32
16
|
export type { CapabilityActionWording } from "../_internal/capability-sentences";
|
|
17
|
+
export {
|
|
18
|
+
type CapabilityCaller,
|
|
19
|
+
invokeCapability,
|
|
20
|
+
invokeCapabilityWithDataSchema,
|
|
21
|
+
listCapabilityCatalog,
|
|
22
|
+
} from "./server-invoke";
|
|
33
23
|
export type {
|
|
34
24
|
CapabilityCatalogApp,
|
|
35
25
|
CapabilityCatalogAppClientResult,
|
|
@@ -39,173 +29,6 @@ export type {
|
|
|
39
29
|
CapabilityReviewClientResult,
|
|
40
30
|
} from "./types";
|
|
41
31
|
|
|
42
|
-
export type CapabilityCaller = {
|
|
43
|
-
/** Core-only in-process authority; other applications must use a Core transport. */
|
|
44
|
-
authority?: RequestAuthority;
|
|
45
|
-
/** Trusted server transport to Core. Never supplied by a browser or sandbox. */
|
|
46
|
-
transport?: (request: Request) => Promise<Response>;
|
|
47
|
-
origin?: CapabilityOrigin;
|
|
48
|
-
|
|
49
|
-
authorization?: string | null;
|
|
50
|
-
cookie?: string | null;
|
|
51
|
-
requestId?: string | null;
|
|
52
|
-
traceparent?: string | null;
|
|
53
|
-
tracestate?: string | null;
|
|
54
|
-
/** BCP 47 locale of the originating request, forwarded as invocation metadata. */
|
|
55
|
-
locale?: string | null;
|
|
56
|
-
signal?: AbortSignal;
|
|
57
|
-
/** Durable background authority. `authorization` must be the owning app's workload credential. */
|
|
58
|
-
mandate?: { id: string; revision: number; callingAppId: string };
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const coreOrigin = async (internal = false): Promise<string> => {
|
|
62
|
-
const configured = env.CLOUD_CORE_INTERNAL_ORIGIN;
|
|
63
|
-
if (internal && !configured) throw new Error("CLOUD_CORE_INTERNAL_ORIGIN is required for mandate-backed invocation");
|
|
64
|
-
const origin = configured || publicCloudOrigin(await get<string>("app.url"));
|
|
65
|
-
const url = new URL(origin);
|
|
66
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("CLOUD_CORE_INTERNAL_ORIGIN must use http or https");
|
|
67
|
-
return url.origin;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const callerRequest = async (
|
|
71
|
-
caller: CapabilityCaller,
|
|
72
|
-
path: string,
|
|
73
|
-
idempotencyKey?: string,
|
|
74
|
-
invocationSignal?: AbortSignal,
|
|
75
|
-
): Promise<Request> => {
|
|
76
|
-
const headers = new Headers();
|
|
77
|
-
if (caller.authorization) headers.set("authorization", caller.authorization);
|
|
78
|
-
if (!caller.mandate) {
|
|
79
|
-
if (caller.cookie) headers.set("cookie", caller.cookie);
|
|
80
|
-
if (caller.requestId) headers.set("x-request-id", caller.requestId);
|
|
81
|
-
if (caller.traceparent) headers.set("traceparent", caller.traceparent);
|
|
82
|
-
if (caller.tracestate) headers.set("tracestate", caller.tracestate);
|
|
83
|
-
if (caller.locale) headers.set(LOCALE_HEADER, caller.locale);
|
|
84
|
-
if (idempotencyKey) headers.set("idempotency-key", idempotencyKey);
|
|
85
|
-
} else {
|
|
86
|
-
headers.set("x-cloud-app-id", caller.mandate.callingAppId);
|
|
87
|
-
}
|
|
88
|
-
const signal = combineCapabilitySignals(caller.signal, invocationSignal);
|
|
89
|
-
return new Request(new URL(path, await coreOrigin(caller.mandate !== undefined)), { method: "POST", headers, signal });
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const unavailable = (
|
|
93
|
-
cause: unknown,
|
|
94
|
-
invocation?: Pick<CapabilityInvocation, "kind" | "idempotencyKey">,
|
|
95
|
-
locale?: string,
|
|
96
|
-
): { ok: false; error: CapabilityClientError } => ({
|
|
97
|
-
ok: false,
|
|
98
|
-
error:
|
|
99
|
-
invocation?.kind === "action" && !invocation.idempotencyKey
|
|
100
|
-
? {
|
|
101
|
-
code: CAPABILITY_FRAMEWORK_ERROR_CODES.actionOutcomeUnknown,
|
|
102
|
-
message: capabilityMessages(locale).actionOutcomeUnknown,
|
|
103
|
-
status: 502,
|
|
104
|
-
details: { retrySafe: false },
|
|
105
|
-
}
|
|
106
|
-
: cause instanceof Error && cause.name === "AbortError"
|
|
107
|
-
? {
|
|
108
|
-
code: CAPABILITY_FRAMEWORK_ERROR_CODES.requestCancelled,
|
|
109
|
-
message: capabilityMessages(locale).requestCancelled,
|
|
110
|
-
status: 499,
|
|
111
|
-
}
|
|
112
|
-
: {
|
|
113
|
-
code: CAPABILITY_FRAMEWORK_ERROR_CODES.appUnavailable,
|
|
114
|
-
message: capabilityMessages(locale).cloudUnavailable,
|
|
115
|
-
status: 503,
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const invokeCapabilityWithResultSchema = async <TDataSchema extends z.ZodType, TInput = unknown>(
|
|
120
|
-
invocation: CapabilityInvocation<TInput>,
|
|
121
|
-
dataSchema: TDataSchema,
|
|
122
|
-
caller: CapabilityCaller,
|
|
123
|
-
): Promise<CapabilityClientResult<z.output<TDataSchema>>> => {
|
|
124
|
-
try {
|
|
125
|
-
const path = caller.mandate
|
|
126
|
-
? "/api/_internal/identity/v1/invoke"
|
|
127
|
-
: `/api/capabilities/v1/${invocation.kind === "query" ? "queries" : "actions"}/${encodeURIComponent(invocation.appId)}/${encodeURIComponent(invocation.capabilityId)}`;
|
|
128
|
-
const request = await callerRequest(caller, path, invocation.idempotencyKey, invocation.signal);
|
|
129
|
-
if (caller.authority) {
|
|
130
|
-
if (caller.authorization || caller.cookie || caller.mandate || caller.transport)
|
|
131
|
-
throw new Error("Use exactly one capability authority source");
|
|
132
|
-
const outcome = await dispatchCapability({
|
|
133
|
-
request,
|
|
134
|
-
kind: invocation.kind === "query" ? "queries" : "actions",
|
|
135
|
-
appId: invocation.appId,
|
|
136
|
-
capabilityId: invocation.capabilityId,
|
|
137
|
-
input: invocation.input,
|
|
138
|
-
authority: caller.authority,
|
|
139
|
-
locale: caller.locale ?? undefined,
|
|
140
|
-
origin: caller.origin ?? "app",
|
|
141
|
-
});
|
|
142
|
-
return readCapabilityResponse(outcome, capabilityResultSchema(dataSchema, { consumer: true }));
|
|
143
|
-
}
|
|
144
|
-
const response = await (caller.transport ?? fetch)(
|
|
145
|
-
new Request(request, {
|
|
146
|
-
body: JSON.stringify(
|
|
147
|
-
caller.mandate
|
|
148
|
-
? {
|
|
149
|
-
kind: invocation.kind,
|
|
150
|
-
targetApp: invocation.appId,
|
|
151
|
-
capabilityId: invocation.capabilityId,
|
|
152
|
-
input: invocation.input,
|
|
153
|
-
mandateId: caller.mandate.id,
|
|
154
|
-
mandateRevision: caller.mandate.revision,
|
|
155
|
-
...(invocation.idempotencyKey ? { idempotencyKey: invocation.idempotencyKey } : {}),
|
|
156
|
-
...(caller.requestId || caller.traceparent || caller.tracestate || caller.locale
|
|
157
|
-
? {
|
|
158
|
-
metadata: {
|
|
159
|
-
...(caller.requestId ? { requestId: caller.requestId } : {}),
|
|
160
|
-
...(caller.traceparent ? { traceparent: caller.traceparent } : {}),
|
|
161
|
-
...(caller.tracestate ? { tracestate: caller.tracestate } : {}),
|
|
162
|
-
...(caller.locale ? { locale: caller.locale } : {}),
|
|
163
|
-
},
|
|
164
|
-
}
|
|
165
|
-
: {}),
|
|
166
|
-
}
|
|
167
|
-
: { input: invocation.input },
|
|
168
|
-
),
|
|
169
|
-
}),
|
|
170
|
-
);
|
|
171
|
-
return readCapabilityResponse(response, capabilityResultSchema(dataSchema, { consumer: true }));
|
|
172
|
-
} catch (cause) {
|
|
173
|
-
return unavailable(cause, invocation, caller.locale ?? undefined);
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export const invokeCapability = <TInput = unknown>(
|
|
178
|
-
invocation: CapabilityInvocation<TInput>,
|
|
179
|
-
caller: CapabilityCaller,
|
|
180
|
-
): Promise<CapabilityClientResult<unknown>> => invokeCapabilityWithResultSchema(invocation, z.unknown(), caller);
|
|
181
|
-
|
|
182
|
-
export const invokeCapabilityWithDataSchema = <TDataSchema extends z.ZodType, TInput = unknown>(
|
|
183
|
-
invocation: CapabilityInvocation<TInput>,
|
|
184
|
-
dataSchema: TDataSchema,
|
|
185
|
-
caller: CapabilityCaller,
|
|
186
|
-
): Promise<CapabilityClientResult<z.output<TDataSchema>>> => invokeCapabilityWithResultSchema(invocation, dataSchema, caller);
|
|
187
|
-
|
|
188
|
-
export const listCapabilityCatalog = async (
|
|
189
|
-
options: { cursor?: string; limit?: number; locale?: string; authority?: RequestAuthority | null } = {},
|
|
190
|
-
): Promise<CapabilityCatalogClientResult> => {
|
|
191
|
-
const limit = options.limit ?? 25;
|
|
192
|
-
const messages = capabilityMessages(options.locale);
|
|
193
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 25) {
|
|
194
|
-
return {
|
|
195
|
-
ok: false,
|
|
196
|
-
error: { code: "VALIDATION_FAILED", message: messages.catalogLimit({ max: 25 }), status: 400 },
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
return {
|
|
201
|
-
ok: true,
|
|
202
|
-
data: await loadCapabilityCatalogPage({ cursor: options.cursor, limit }, {}, options.locale, options.authority ?? null),
|
|
203
|
-
};
|
|
204
|
-
} catch {
|
|
205
|
-
return { ok: false, error: { code: "APP_UNAVAILABLE", message: messages.cloudUnavailable, status: 503 } };
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
|
|
209
32
|
export const getCapabilityCatalogApp = async (
|
|
210
33
|
appId: string,
|
|
211
34
|
locale?: string,
|
|
@@ -333,6 +156,22 @@ export async function transferCapabilityStream(
|
|
|
333
156
|
return caller.transport ? caller.transport(request) : fetch(request, { redirect: "error" });
|
|
334
157
|
}
|
|
335
158
|
|
|
159
|
+
export {
|
|
160
|
+
CALENDAR_VIEW_MAX_RANGE_MS,
|
|
161
|
+
type CalendarReadResult,
|
|
162
|
+
CalendarReadResultSchema,
|
|
163
|
+
type CalendarSelection,
|
|
164
|
+
CalendarSourceErrorSchema,
|
|
165
|
+
type CalendarSourceListEntry,
|
|
166
|
+
CalendarSourceListEntrySchema,
|
|
167
|
+
type CalendarSourceState,
|
|
168
|
+
CalendarSourceStateSchema,
|
|
169
|
+
type CalendarSourceSummary,
|
|
170
|
+
CalendarSourceSummarySchema,
|
|
171
|
+
CalendarViewRangeSchema,
|
|
172
|
+
listCalendarSources,
|
|
173
|
+
readCalendarEvents,
|
|
174
|
+
} from "./calendar-sources";
|
|
336
175
|
export {
|
|
337
176
|
actionReview,
|
|
338
177
|
type CapabilityReviewForms,
|
|
@@ -17,8 +17,11 @@ import {
|
|
|
17
17
|
} from "../contracts/capabilities";
|
|
18
18
|
|
|
19
19
|
/** Compile and validate the public manifest an app would register at startup. */
|
|
20
|
-
export const compileCapabilityManifest = (
|
|
21
|
-
|
|
20
|
+
export const compileCapabilityManifest = (
|
|
21
|
+
appId: string,
|
|
22
|
+
definitions: CapabilityDefinitions,
|
|
23
|
+
routes?: readonly string[],
|
|
24
|
+
): CapabilityManifest => compileCapabilities(appId, definitions, routes).manifest;
|
|
22
25
|
|
|
23
26
|
/** Fail a provider compatibility test when a published local id changed incompatibly. */
|
|
24
27
|
export const assertCapabilityManifestEvolution = (previous: CapabilityManifest, next: CapabilityManifest): void => {
|
package/src/cli/access.ts
CHANGED
|
@@ -49,6 +49,7 @@ export type AccessCommandAdapter<TResource extends AccessResource> = {
|
|
|
49
49
|
scopes?: readonly [string, ...string[]];
|
|
50
50
|
allowPublic?: boolean;
|
|
51
51
|
allowAuthenticated?: boolean;
|
|
52
|
+
/** Defaults to true; false preserves an explicitly restricted resource contract. */
|
|
52
53
|
allowServiceAccounts?: boolean;
|
|
53
54
|
examples?: {
|
|
54
55
|
list?: readonly string[];
|
|
@@ -217,7 +218,7 @@ export const resolveAccessPrincipal = async (
|
|
|
217
218
|
"--group",
|
|
218
219
|
...(options.allowAuthenticated === false ? [] : ["--authenticated"]),
|
|
219
220
|
...(options.allowPublic === true ? ["--public"] : []),
|
|
220
|
-
...(options.allowServiceAccounts
|
|
221
|
+
...(options.allowServiceAccounts !== false ? ["--service-account"] : []),
|
|
221
222
|
];
|
|
222
223
|
throw new Error(`Pass exactly one principal flag: ${allowedFlags.join(", ")}.`);
|
|
223
224
|
}
|
|
@@ -225,8 +226,8 @@ export const resolveAccessPrincipal = async (
|
|
|
225
226
|
if (flags.authenticated && options.allowAuthenticated === false) {
|
|
226
227
|
throw new Error("This resource does not allow authenticated-audience grants.");
|
|
227
228
|
}
|
|
228
|
-
if (flags.serviceAccount && options.allowServiceAccounts
|
|
229
|
-
throw new Error("
|
|
229
|
+
if (flags.serviceAccount && options.allowServiceAccounts === false) {
|
|
230
|
+
throw new Error("This resource does not allow service-account access grants.");
|
|
230
231
|
}
|
|
231
232
|
if (flags.authenticated) return { type: "authenticated" };
|
|
232
233
|
if (flags.public) return { type: "public" };
|
|
@@ -348,11 +349,11 @@ const accessIdFlag = {
|
|
|
348
349
|
|
|
349
350
|
export const createAccessCommands = <TResource extends AccessResource>(adapter: AccessCommandAdapter<TResource>) => {
|
|
350
351
|
const allowed = normalizeAllowedPermissions(adapter.allowedPermissions);
|
|
351
|
-
const searchableKinds = adapter.allowServiceAccounts ? PRINCIPAL_KINDS : (["user", "group"] as const);
|
|
352
|
+
const searchableKinds = adapter.allowServiceAccounts !== false ? PRINCIPAL_KINDS : (["user", "group"] as const);
|
|
352
353
|
const principalFlagOptions = {
|
|
353
354
|
includePublicFlag: adapter.allowPublic === true,
|
|
354
355
|
includeAuthenticatedFlag: adapter.allowAuthenticated !== false,
|
|
355
|
-
includeServiceAccountFlag: adapter.allowServiceAccounts
|
|
356
|
+
includeServiceAccountFlag: adapter.allowServiceAccounts !== false,
|
|
356
357
|
};
|
|
357
358
|
const resolve = (ctx: CloudCliContext, args: string[]) => adapter.resolveResource(ctx, args);
|
|
358
359
|
const scopeFlag: { scope?: ReturnType<typeof flag.string> } = adapter.scopes
|