@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
+
import type { AppPwaActor } from "../../app-pwa/contracts";
|
|
2
3
|
import type { AccessSubject, CapabilityExecutionContext, RequestActor } from "../../contracts";
|
|
3
4
|
import {
|
|
4
5
|
GeoAutocompleteDataSchema,
|
|
@@ -26,17 +27,27 @@ import { createGeoRouteService } from "./route-service";
|
|
|
26
27
|
import { type GeoConfig, geoPlan, readGeoConfig } from "./settings";
|
|
27
28
|
|
|
28
29
|
export type GeoContext = Partial<Pick<CapabilityExecutionContext, "actor" | "accessSubject" | "locale" | "signal" | "requestId">>;
|
|
30
|
+
/** Internal, narrow App-PWA autocomplete adapter; never a RequestActor or capability caller. */
|
|
31
|
+
export type AppPwaGeoContext = { actor: AppPwaActor; locale?: string; signal?: AbortSignal; requestId?: string };
|
|
32
|
+
type GeoCallContext = GeoContext | AppPwaGeoContext;
|
|
29
33
|
export const geoIdentity = (context: GeoContext): { actor: RequestActor; accessSubject: AccessSubject } => {
|
|
30
34
|
const { actor, accessSubject } = context;
|
|
31
35
|
if (
|
|
32
36
|
!actor ||
|
|
33
37
|
!accessSubject ||
|
|
34
|
-
!(actor.kind === "user" ? actor.user?.id : actor.serviceAccount?.id) ||
|
|
38
|
+
!(actor.kind === "user" ? actor.user?.id : actor.kind === "service_account" ? actor.serviceAccount?.id : undefined) ||
|
|
35
39
|
!(accessSubject.type === "user" ? accessSubject.userId : accessSubject.serviceAccountId)
|
|
36
40
|
)
|
|
37
41
|
throw new GeoError("GEO_FORBIDDEN");
|
|
38
42
|
return { actor, accessSubject };
|
|
39
43
|
};
|
|
44
|
+
const geoCallIdentity = (context: GeoCallContext): { actor: RequestActor | AppPwaActor; accessSubject: AccessSubject } => {
|
|
45
|
+
if (context.actor?.kind === "device" || context.actor?.kind === "visit") {
|
|
46
|
+
if (!context.actor.ownerUserId) throw new GeoError("GEO_FORBIDDEN");
|
|
47
|
+
return { actor: context.actor, accessSubject: { type: "user", userId: context.actor.ownerUserId } };
|
|
48
|
+
}
|
|
49
|
+
return geoIdentity({ actor: context.actor, accessSubject: "accessSubject" in context ? context.accessSubject : undefined });
|
|
50
|
+
};
|
|
40
51
|
const bound = (name: string, value: number, min: number, max: number, integer = false) => {
|
|
41
52
|
if (!Number.isFinite(value) || value > max || value < min || (integer && !Number.isInteger(value)))
|
|
42
53
|
limitExceeded(name, value < min ? min : max, value);
|
|
@@ -81,14 +92,21 @@ export const createGeoService = (
|
|
|
81
92
|
monthlyCredits: settings.monthlyCredits,
|
|
82
93
|
personDailyCredits: settings.personDailyCredits,
|
|
83
94
|
});
|
|
84
|
-
const recordTransition = async (
|
|
85
|
-
|
|
95
|
+
const recordTransition = async (
|
|
96
|
+
event: "monthly_budget_exhausted" | "provider_key_rejected" | "route_cost_overrun",
|
|
97
|
+
timezone: string,
|
|
98
|
+
context: GeoCallContext,
|
|
99
|
+
metadata?: Record<string, number>,
|
|
100
|
+
) => {
|
|
101
|
+
const identity = geoCallIdentity(context);
|
|
86
102
|
try {
|
|
87
|
-
await ledger.recordTransition(event, timezone, { ...context, ...identity }, now());
|
|
103
|
+
await ledger.recordTransition(event, timezone, { ...context, ...identity }, now(), metadata);
|
|
104
|
+
return true;
|
|
88
105
|
} catch {
|
|
89
106
|
// The transaction rolls back the dedup row too, allowing the next refusal to record it.
|
|
90
107
|
// Preserve the original recovery details and paid/unknown costs on audit outages.
|
|
91
108
|
console.error("[geo] Audit transition could not be recorded", { event });
|
|
109
|
+
return false;
|
|
92
110
|
}
|
|
93
111
|
};
|
|
94
112
|
const configured = async (context: GeoContext) => {
|
|
@@ -100,7 +118,7 @@ export const createGeoService = (
|
|
|
100
118
|
const paid = async <T>(
|
|
101
119
|
fn: GeoFunction,
|
|
102
120
|
input: unknown,
|
|
103
|
-
context:
|
|
121
|
+
context: GeoCallContext,
|
|
104
122
|
settings: GeoConfig,
|
|
105
123
|
schema: z.ZodType<T>,
|
|
106
124
|
request: (signal: AbortSignal) => Promise<T>,
|
|
@@ -108,7 +126,7 @@ export const createGeoService = (
|
|
|
108
126
|
cacheInput = input,
|
|
109
127
|
empty: (value: T) => boolean = () => false,
|
|
110
128
|
): Promise<T> => {
|
|
111
|
-
const identity =
|
|
129
|
+
const identity = geoCallIdentity(context);
|
|
112
130
|
const locale = context.locale ?? "en";
|
|
113
131
|
const key = geoCacheKey(fn, cacheInput, locale);
|
|
114
132
|
const hit = await cache.get(key, schema);
|
|
@@ -169,29 +187,37 @@ export const createGeoService = (
|
|
|
169
187
|
await release();
|
|
170
188
|
}
|
|
171
189
|
};
|
|
190
|
+
const autocomplete = async (input: GeoAutocompleteInput, context: GeoCallContext) => {
|
|
191
|
+
geoCallIdentity(context);
|
|
192
|
+
const settings = await config();
|
|
193
|
+
if (!settings.apiKey.trim()) throw new GeoError("GEO_NOT_CONFIGURED");
|
|
194
|
+
const value = parse(GeoAutocompleteInputSchema, input);
|
|
195
|
+
bound("text", value.text.length, 3, 300);
|
|
196
|
+
bound("text", value.text.trim().length, 3, 300);
|
|
197
|
+
bound("limit", value.limit ?? 5, 1, 5, true);
|
|
198
|
+
country(value.countryCode);
|
|
199
|
+
area(value.area);
|
|
200
|
+
return paid(
|
|
201
|
+
"autocomplete",
|
|
202
|
+
value,
|
|
203
|
+
context,
|
|
204
|
+
settings,
|
|
205
|
+
GeoAutocompleteDataSchema,
|
|
206
|
+
(signal) => adapter.autocomplete(value, settings.apiKey, context.locale ?? "en", signal),
|
|
207
|
+
value.limit,
|
|
208
|
+
{ ...value, limit: value.limit ?? 5 },
|
|
209
|
+
(result) => !result.suggestions.length,
|
|
210
|
+
);
|
|
211
|
+
};
|
|
172
212
|
const routes = createGeoRouteService({ configured, adapter, cache, bucket, ledger, now, recordTransition });
|
|
173
213
|
return {
|
|
174
214
|
...routes,
|
|
175
|
-
async
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
bound("text", value.text.length, 3, 300);
|
|
179
|
-
bound("text", value.text.trim().length, 3, 300);
|
|
180
|
-
bound("limit", value.limit ?? 5, 1, 5, true);
|
|
181
|
-
country(value.countryCode);
|
|
182
|
-
area(value.area);
|
|
183
|
-
return paid(
|
|
184
|
-
"autocomplete",
|
|
185
|
-
value,
|
|
186
|
-
context,
|
|
187
|
-
settings,
|
|
188
|
-
GeoAutocompleteDataSchema,
|
|
189
|
-
(signal) => adapter.autocomplete(value, settings.apiKey, context.locale ?? "en", signal),
|
|
190
|
-
value.limit,
|
|
191
|
-
{ ...value, limit: value.limit ?? 5 },
|
|
192
|
-
(result) => !result.suggestions.length,
|
|
193
|
-
);
|
|
215
|
+
autocomplete: async (input: GeoAutocompleteInput, context: GeoContext) => {
|
|
216
|
+
geoIdentity(context);
|
|
217
|
+
return autocomplete(input, context);
|
|
194
218
|
},
|
|
219
|
+
// Only the App-PWA service calls this after locking the pairing and optional visit authority.
|
|
220
|
+
autocompleteForAppPwa: (input: GeoAutocompleteInput, context: AppPwaGeoContext) => autocomplete(input, context),
|
|
195
221
|
async geocode(input: GeoGeocodeInput, context: GeoContext) {
|
|
196
222
|
const settings = await configured(context);
|
|
197
223
|
const value = parse(GeoGeocodeInputSchema, input);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { env } from "../../config/env";
|
|
2
|
+
import { publicCloudOrigin } from "../../shared/app-url";
|
|
3
|
+
import { get } from "../settings";
|
|
4
|
+
|
|
5
|
+
export const coreOrigin = async (internal = false): Promise<string> => {
|
|
6
|
+
const configured = env.CLOUD_CORE_INTERNAL_ORIGIN;
|
|
7
|
+
if (internal && !configured) throw new Error("CLOUD_CORE_INTERNAL_ORIGIN is required for internal Core requests");
|
|
8
|
+
const origin = configured || publicCloudOrigin(await get<string>("app.url"));
|
|
9
|
+
const url = new URL(origin);
|
|
10
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("CLOUD_CORE_INTERNAL_ORIGIN must use http or https");
|
|
11
|
+
return url.origin;
|
|
12
|
+
};
|
|
@@ -8,7 +8,7 @@ export {
|
|
|
8
8
|
CLOUD_SESSION_TOKEN_TYPE,
|
|
9
9
|
} from "./constants";
|
|
10
10
|
export { type ResolvedInvocationAuthority, resolveInvocationAuthority } from "./invocation-actor";
|
|
11
|
-
export { invocationAuthorityFromRequest } from "./invocation-authority";
|
|
11
|
+
export { authorityFromParentInvocation, invocationAuthorityFromRequest, matchesInvocationSubject } from "./invocation-authority";
|
|
12
12
|
export { capabilityInvocationOperation, searchInvocationOperation, widgetInvocationOperation } from "./invocation-operations";
|
|
13
13
|
export {
|
|
14
14
|
type CloudInvocationClaims,
|
|
@@ -36,6 +36,7 @@ export {
|
|
|
36
36
|
withActiveIdentitySigner,
|
|
37
37
|
} from "./key-ring";
|
|
38
38
|
export { identityMetrics } from "./metrics";
|
|
39
|
+
export { isNestedSourceCurrent, type NestedInvocationLease, nestedInvocationLeases } from "./nested-invocation";
|
|
39
40
|
export { createIdentityPublicRoutes } from "./routes";
|
|
40
41
|
export {
|
|
41
42
|
type CloudSessionClaims,
|
|
@@ -3,9 +3,11 @@ import type { RequestActor } from "../../server/middleware/auth";
|
|
|
3
3
|
import type { AccessSubject } from "../../server/services/access";
|
|
4
4
|
import { isAccountCategoryAllowed } from "../account-category-policy";
|
|
5
5
|
import { isAccountExpired } from "../account-model";
|
|
6
|
+
import { isServiceAccountOAuthAuthorityCurrent } from "../oauth-tokens";
|
|
6
7
|
import type { ServiceAccount } from "../service-accounts";
|
|
7
8
|
import { buildProjectedUser, loadCurrentUser, userProjectionJoin, userProjectionSql, withoutAdminRole } from "../session/user";
|
|
8
9
|
import type { CloudInvocationClaims } from "./invocation-token";
|
|
10
|
+
import { isNestedSourceCurrent, nestedInvocationLeases } from "./nested-invocation";
|
|
9
11
|
import { getIdentityRuntimeConfig } from "./runtime-config";
|
|
10
12
|
|
|
11
13
|
type ServiceAccountRow = Record<string, unknown> & {
|
|
@@ -32,9 +34,13 @@ export type InvocationPrincipalClaims = Pick<
|
|
|
32
34
|
CloudInvocationClaims,
|
|
33
35
|
| "sub"
|
|
34
36
|
| "principal_type"
|
|
37
|
+
| "access_subject_type"
|
|
38
|
+
| "access_subject_id"
|
|
35
39
|
| "session_kind"
|
|
36
40
|
| "scopes"
|
|
37
41
|
| "credential_id"
|
|
42
|
+
| "oauth_client_id"
|
|
43
|
+
| "credential_expires_at"
|
|
38
44
|
| "exp"
|
|
39
45
|
| "act"
|
|
40
46
|
| "credential_kind"
|
|
@@ -44,6 +50,7 @@ export type InvocationPrincipalClaims = Pick<
|
|
|
44
50
|
| "mandate_revision"
|
|
45
51
|
| "workload_type"
|
|
46
52
|
| "workload_id"
|
|
53
|
+
| "parent_invocation_id"
|
|
47
54
|
>;
|
|
48
55
|
|
|
49
56
|
const provenance = (claims: InvocationPrincipalClaims): NonNullable<RequestActor["delegation"]> => ({
|
|
@@ -51,6 +58,7 @@ const provenance = (claims: InvocationPrincipalClaims): NonNullable<RequestActor
|
|
|
51
58
|
callingAppId: claims.act.sub.slice("app:".length),
|
|
52
59
|
credentialKind: claims.credential_kind,
|
|
53
60
|
invocationId: claims.jti,
|
|
61
|
+
...(claims.parent_invocation_id ? { parentInvocationId: claims.parent_invocation_id } : {}),
|
|
54
62
|
requestId: claims.request_id ?? null,
|
|
55
63
|
...(claims.mandate_id
|
|
56
64
|
? {
|
|
@@ -80,10 +88,29 @@ export const resolveInvocationAuthority = async (
|
|
|
80
88
|
query: typeof sql = sql,
|
|
81
89
|
groupsAdminOverride?: string[],
|
|
82
90
|
): Promise<ResolvedInvocationAuthority | null> => {
|
|
91
|
+
if (claims.parent_invocation_id) {
|
|
92
|
+
const lease = await nestedInvocationLeases.read(claims.parent_invocation_id).catch(() => null);
|
|
93
|
+
if (!lease || `app:${lease.appId}` !== claims.act.sub) return null;
|
|
94
|
+
if (lease.proof && !(await isNestedSourceCurrent(lease.proof, claims).catch(() => false))) return null;
|
|
95
|
+
if (claims.mandate_id) {
|
|
96
|
+
// Policy was checked under Core's issuance transaction; admission also
|
|
97
|
+
// checks the parent's current mandate state and subject.
|
|
98
|
+
const [mandate] = await query<{ id: string }[]>`
|
|
99
|
+
SELECT id FROM auth.mandates
|
|
100
|
+
WHERE id = ${claims.mandate_id}::uuid AND revision = ${claims.mandate_revision}
|
|
101
|
+
AND state = 'active' AND confirmed_at IS NOT NULL
|
|
102
|
+
AND (expires_at IS NULL OR expires_at > now())
|
|
103
|
+
AND subject_kind = ${claims.principal_type}
|
|
104
|
+
AND COALESCE(subject_user_id, subject_service_account_id) = ${claims.sub}::uuid
|
|
105
|
+
`;
|
|
106
|
+
if (!mandate) return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
83
109
|
const groupsAdmin = groupsAdminOverride ?? (await getIdentityRuntimeConfig()).groupsAdmin;
|
|
84
110
|
const delegation = provenance(claims);
|
|
85
111
|
|
|
86
112
|
if (claims.principal_type === "user") {
|
|
113
|
+
if (claims.access_subject_type !== "user" || claims.access_subject_id !== claims.sub) return null;
|
|
87
114
|
const current = await loadCurrentUser({ userId: claims.sub, groupsAdmin }, query);
|
|
88
115
|
if (!current || isAccountExpired(current.accountExpires)) return null;
|
|
89
116
|
if (!(await isAccountCategoryAllowed(current, query))) return null;
|
|
@@ -125,15 +152,36 @@ export const resolveInvocationAuthority = async (
|
|
|
125
152
|
if (serviceAccount.kind === "user_delegated" && (!delegatedUser || isAccountExpired(delegatedUser.accountExpires))) return null;
|
|
126
153
|
if (delegatedUser && !(await isAccountCategoryAllowed(delegatedUser, query))) return null;
|
|
127
154
|
|
|
128
|
-
|
|
155
|
+
if (
|
|
156
|
+
claims.access_subject_type !== (delegatedUser ? "user" : "service_account") ||
|
|
157
|
+
claims.access_subject_id !== (delegatedUser?.id ?? serviceAccount.id)
|
|
158
|
+
)
|
|
159
|
+
return null;
|
|
160
|
+
|
|
161
|
+
const actor: Extract<RequestActor, { kind: "service_account" }> = {
|
|
129
162
|
kind: "service_account",
|
|
130
163
|
serviceAccount,
|
|
131
164
|
delegatedUser,
|
|
132
165
|
scopes: [...claims.scopes],
|
|
133
166
|
credentialId: claims.credential_id ?? null,
|
|
134
|
-
|
|
167
|
+
oauthClientId: claims.oauth_client_id ?? null,
|
|
168
|
+
credentialExpiresAt: new Date(
|
|
169
|
+
Math.min(claims.exp * 1_000, claims.credential_expires_at ? Date.parse(claims.credential_expires_at) : Infinity),
|
|
170
|
+
).toISOString(),
|
|
135
171
|
delegation,
|
|
136
172
|
};
|
|
173
|
+
if (
|
|
174
|
+
claims.oauth_client_id &&
|
|
175
|
+
!(await isServiceAccountOAuthAuthorityCurrent(
|
|
176
|
+
{
|
|
177
|
+
serviceAccountId: serviceAccount.id,
|
|
178
|
+
clientId: claims.oauth_client_id,
|
|
179
|
+
expiresAt: actor.credentialExpiresAt,
|
|
180
|
+
},
|
|
181
|
+
{ query, groupsAdmin },
|
|
182
|
+
))
|
|
183
|
+
)
|
|
184
|
+
return null;
|
|
137
185
|
const accessSubject: AccessSubject = delegatedUser
|
|
138
186
|
? { type: "user", userId: delegatedUser.id, delegatedByServiceAccountId: serviceAccount.id }
|
|
139
187
|
: { type: "service_account", serviceAccountId: serviceAccount.id };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RequestAuthority } from "../../server/middleware/auth";
|
|
2
|
-
import type { InvocationAuthority } from "./invocation-token";
|
|
2
|
+
import type { CloudInvocationClaims, InvocationAuthority } from "./invocation-token";
|
|
3
3
|
|
|
4
4
|
export const invocationAuthorityFromRequest = (authority: RequestAuthority): InvocationAuthority => {
|
|
5
5
|
if (authority.credentialKind === "invocation") {
|
|
@@ -35,6 +35,8 @@ export const invocationAuthorityFromRequest = (authority: RequestAuthority): Inv
|
|
|
35
35
|
delegated_user_id: actor.delegatedUser.id,
|
|
36
36
|
credential_kind: authority.credentialKind,
|
|
37
37
|
...(actor.credentialId ? { credential_id: actor.credentialId } : {}),
|
|
38
|
+
...(actor.oauthClientId ? { oauth_client_id: actor.oauthClientId } : {}),
|
|
39
|
+
...(actor.credentialExpiresAt ? { credential_expires_at: actor.credentialExpiresAt } : {}),
|
|
38
40
|
scopes: [...new Set(authority.scopes)].sort(),
|
|
39
41
|
};
|
|
40
42
|
}
|
|
@@ -49,6 +51,41 @@ export const invocationAuthorityFromRequest = (authority: RequestAuthority): Inv
|
|
|
49
51
|
access_subject_id: actor.serviceAccount.id,
|
|
50
52
|
credential_kind: authority.credentialKind,
|
|
51
53
|
...(actor.credentialId ? { credential_id: actor.credentialId } : {}),
|
|
54
|
+
...(actor.oauthClientId ? { oauth_client_id: actor.oauthClientId } : {}),
|
|
55
|
+
...(actor.credentialExpiresAt ? { credential_expires_at: actor.credentialExpiresAt } : {}),
|
|
52
56
|
scopes: [...new Set(authority.scopes)].sort(),
|
|
53
57
|
};
|
|
54
58
|
};
|
|
59
|
+
|
|
60
|
+
/** A principal or delegation change cannot turn an existing invocation into new authority. */
|
|
61
|
+
export const matchesInvocationSubject = (parent: CloudInvocationClaims, current: RequestAuthority): boolean => {
|
|
62
|
+
const actor = current.actor;
|
|
63
|
+
const subject = current.accessSubject;
|
|
64
|
+
return (
|
|
65
|
+
(actor.kind === "user" ? actor.user.id : actor.serviceAccount.id) === parent.sub &&
|
|
66
|
+
actor.kind === parent.principal_type &&
|
|
67
|
+
subject.type === parent.access_subject_type &&
|
|
68
|
+
(subject.type === "user" ? subject.userId : subject.serviceAccountId) === parent.access_subject_id
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** Copy only authority fields, preserving every ceiling. Never relabel an invocation as a session. */
|
|
73
|
+
export const authorityFromParentInvocation = (parent: CloudInvocationClaims): InvocationAuthority => ({
|
|
74
|
+
sub: parent.sub,
|
|
75
|
+
principal_type: parent.principal_type,
|
|
76
|
+
access_subject_type: parent.access_subject_type,
|
|
77
|
+
access_subject_id: parent.access_subject_id,
|
|
78
|
+
...(parent.delegated_user_id ? { delegated_user_id: parent.delegated_user_id } : {}),
|
|
79
|
+
credential_kind: parent.credential_kind,
|
|
80
|
+
...(parent.session_kind ? { session_kind: parent.session_kind } : {}),
|
|
81
|
+
...(parent.credential_id ? { credential_id: parent.credential_id } : {}),
|
|
82
|
+
scopes: [...parent.scopes],
|
|
83
|
+
...(parent.mandate_id
|
|
84
|
+
? {
|
|
85
|
+
mandate_id: parent.mandate_id,
|
|
86
|
+
mandate_revision: parent.mandate_revision,
|
|
87
|
+
workload_type: parent.workload_type,
|
|
88
|
+
workload_id: parent.workload_id,
|
|
89
|
+
}
|
|
90
|
+
: {}),
|
|
91
|
+
});
|