@k2b/cloud 0.40.0 → 0.42.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 +9 -5
- package/src/_internal/bounded-json.ts +14 -2
- package/src/_internal/capabilities.ts +87 -8
- package/src/_internal/capability-reviews.ts +6 -0
- package/src/_internal/capability-sentences.ts +2 -1
- package/src/_internal/capability-timeout.ts +71 -0
- package/src/_internal/define-app.ts +158 -92
- package/src/_internal/heartbeat.ts +203 -14
- package/src/_internal/http-drain.ts +56 -0
- package/src/_internal/registry-validation.ts +3 -0
- package/src/_internal/registry.ts +28 -1
- package/src/_internal/runtime-context.ts +1 -0
- package/src/_internal/setup-lock.ts +103 -0
- package/src/_internal/status-preserving-ssr.ts +2 -0
- package/src/access/PermissionEditor.tsx +16 -17
- package/src/access/PrincipalPicker.tsx +45 -10
- package/src/access/messages.ts +8 -0
- package/src/access/principal-label.ts +18 -0
- package/src/access/ui.ts +1 -0
- package/src/account/EntitySearch.tsx +5 -4
- package/src/ai/action-review.ts +2 -1
- package/src/ai/app-skill-store.ts +1 -1
- package/src/ai/capabilities.ts +21 -3
- package/src/ai/capability-execution.ts +14 -12
- package/src/ai/chat/action-card.ts +76 -4
- package/src/ai/chat/action-messages.ts +14 -0
- package/src/ai/chat/action-question.browser-harness.tsx +12 -0
- package/src/ai/chat/action-question.tsx +214 -23
- package/src/ai/chat/action-text.ts +288 -0
- package/src/ai/chat/tool-action-words.ts +31 -0
- package/src/ai/chat/tool-action.tsx +1 -26
- package/src/ai/chat-tasks.ts +2 -1
- package/src/ai/client/controller.ts +150 -32
- package/src/ai/client/transport.ts +14 -2
- package/src/ai/code-capability-routes.ts +27 -23
- package/src/ai/code-runtime-tools.ts +14 -16
- package/src/ai/code-source-tools.ts +16 -18
- package/src/ai/executor.ts +64 -21
- package/src/ai/fetch-file-tool.ts +67 -76
- package/src/ai/firecrawl-tools.ts +15 -2
- package/src/ai/http.ts +1 -0
- package/src/ai/index.ts +1 -0
- package/src/ai/migrate.ts +28 -0
- package/src/ai/open-questions.ts +168 -0
- package/src/ai/projects.ts +1 -2
- package/src/ai/protocol.ts +2 -2
- package/src/ai/question-text.ts +8 -0
- package/src/ai/recent-resources.ts +12 -5
- package/src/ai/review-content.ts +77 -0
- package/src/ai/routes.ts +119 -35
- package/src/ai/runtime.ts +1 -0
- package/src/ai/skill-tool.ts +17 -6
- package/src/ai/skills-routes.ts +72 -27
- package/src/ai/skills.ts +139 -60
- package/src/ai/store.ts +184 -31
- package/src/ai/testing.ts +36 -0
- package/src/ai/tool-sentences.ts +152 -34
- package/src/ai/tool-wording.ts +12 -6
- package/src/ai/tools.ts +8 -3
- package/src/ai/types.ts +25 -4
- package/src/ai/usage.ts +2 -2
- package/src/api/admin-core-settings.ts +15 -2
- package/src/api/admin-geo.ts +54 -0
- package/src/api/admin-linux-identities.ts +6 -3
- package/src/api/admin-outgoing-mail.ts +29 -15
- package/src/api/app-approval-actions.ts +31 -7
- package/src/api/approvals-loader.ts +3 -3
- package/src/api/approvals.ts +51 -0
- package/src/api/apps.ts +4 -2
- package/src/api/auth/schemas.ts +3 -0
- package/src/api/auth.ts +54 -18
- package/src/api/capabilities.ts +258 -181
- package/src/api/capability-streams.ts +21 -13
- package/src/api/cli-plugins.ts +4 -1
- package/src/api/geo-glyphs.ts +11 -0
- package/src/api/geo.ts +128 -0
- package/src/api/help.ts +12 -4
- package/src/api/index.ts +5 -0
- package/src/api/mcp.ts +73 -41
- package/src/api/me-panel-consent.ts +8 -5
- package/src/api/me.ts +79 -3
- package/src/api/search.ts +21 -14
- package/src/api/sync-ops.ts +19 -13
- package/src/api/widgets.ts +42 -18
- package/src/approvals/Approvals.tsx +30 -66
- package/src/approvals/approval-card.ts +68 -0
- package/src/browser/CloudResourceSearch.browser-harness.tsx +53 -1
- package/src/browser/CloudResourceSearch.tsx +3 -13
- package/src/browser/PanelLeaveNotice.tsx +18 -0
- package/src/browser/navigation-search.ts +78 -25
- package/src/browser/panel-leave.ts +69 -0
- package/src/browser/panel-messages.ts +12 -0
- package/src/browser/panel-slot.ts +173 -24
- package/src/browser/panel.ts +3 -0
- package/src/browser/resource-search-messages.ts +2 -0
- package/src/capabilities/client.ts +28 -1
- package/src/capabilities/executions.ts +22 -3
- package/src/capabilities/geo-client.ts +57 -0
- package/src/capabilities/response.ts +2 -1
- package/src/capabilities/review-storage.ts +24 -0
- package/src/capabilities/reviews.ts +17 -3
- package/src/capabilities/server.ts +36 -16
- package/src/cli/access.ts +15 -23
- package/src/cli/admin/linux.ts +13 -2
- package/src/cli/admin/outgoing-mail.ts +26 -4
- package/src/cli/capabilities.ts +19 -0
- package/src/config/env.ts +0 -6
- package/src/contracts/app-access.ts +48 -0
- package/src/contracts/app-approval.ts +3 -3
- package/src/contracts/app.ts +4 -1
- package/src/contracts/approvals.ts +2 -2
- package/src/contracts/avatar.ts +186 -0
- package/src/contracts/capabilities.ts +149 -55
- package/src/contracts/geo-admin.ts +127 -0
- package/src/contracts/geo-map.ts +19 -0
- package/src/contracts/geo-route.ts +168 -0
- package/src/contracts/geo.ts +248 -0
- package/src/contracts/index.ts +4 -0
- package/src/contracts/outgoing-mail.ts +17 -4
- package/src/contracts/registry.ts +2 -0
- package/src/contracts/shared.ts +3 -0
- package/src/events/app-access.ts +68 -0
- package/src/events/live-delivery.ts +128 -0
- package/src/events/live.ts +14 -130
- package/src/geo/CloudMap.tsx +95 -0
- package/src/geo/map-messages.ts +17 -0
- package/src/geo/ui.ts +1 -0
- package/src/index.ts +2 -0
- package/src/server/client-ip.ts +36 -0
- package/src/server/index.ts +3 -4
- package/src/server/middleware/app-access.ts +312 -0
- package/src/server/middleware/auth.ts +5 -3
- package/src/server/middleware/invocation.ts +11 -0
- package/src/server/middleware/rate-limit.ts +4 -4
- package/src/server/services/access.ts +13 -9
- package/src/server/services/index.ts +0 -2
- package/src/server/services/services.ts +0 -2
- package/src/services/accounts/app.ts +23 -3
- package/src/services/accounts/posix.ts +21 -7
- package/src/services/accounts/users.ts +12 -1
- package/src/services/allowed-network-fetch.ts +16 -10
- package/src/services/app-access-metrics.ts +24 -0
- package/src/services/app-access.ts +123 -0
- package/src/services/app-discovery.ts +27 -0
- package/src/services/approvals/content.ts +40 -0
- package/src/services/approvals/device.ts +49 -33
- package/src/services/approvals/index.ts +15 -6
- package/src/services/approvals/list.ts +6 -11
- package/src/services/approvals/question.ts +72 -0
- package/src/services/audit/index.ts +1 -0
- package/src/services/auth-flows/ipa.ts +39 -2
- package/src/services/auth-flows/password-reset.ts +32 -6
- package/src/services/downstream-budget.ts +87 -0
- package/src/services/geo/admin.ts +262 -0
- package/src/services/geo/bucket.ts +67 -0
- package/src/services/geo/cache.ts +57 -0
- package/src/services/geo/costs.ts +5 -0
- package/src/services/geo/errors.ts +41 -0
- package/src/services/geo/fixtures/README.md +17 -0
- package/src/services/geo/fixtures/along.json +355 -0
- package/src/services/geo/fixtures/autocomplete.json +218 -0
- package/src/services/geo/fixtures/geocode.json +129 -0
- package/src/services/geo/fixtures/places.json +355 -0
- package/src/services/geo/fixtures/reverse.json +61 -0
- package/src/services/geo/fixtures/routing.json +57 -0
- package/src/services/geo/geoapify-route.ts +93 -0
- package/src/services/geo/geoapify.ts +281 -0
- package/src/services/geo/ledger.ts +122 -0
- package/src/services/geo/map.ts +160 -0
- package/src/services/geo/migrate.ts +25 -0
- package/src/services/geo/polyline.ts +184 -0
- package/src/services/geo/route-chain.ts +145 -0
- package/src/services/geo/route-costs.ts +9 -0
- package/src/services/geo/route-geometry.ts +39 -0
- package/src/services/geo/route-plan.ts +172 -0
- package/src/services/geo/route-service.ts +433 -0
- package/src/services/geo/service.ts +300 -0
- package/src/services/geo/settings.ts +49 -0
- package/src/services/help/index.ts +16 -7
- package/src/services/help/types.ts +6 -1
- package/src/services/identity/invocation-actor.ts +20 -2
- package/src/services/identity/issue-invocation.ts +67 -0
- package/src/services/identity/key-ring.ts +5 -3
- package/src/services/identity/runtime-config.ts +23 -0
- package/src/services/index.ts +11 -0
- package/src/services/mandates/index.ts +40 -3
- package/src/services/network-security.ts +6 -3
- package/src/services/network-transport.ts +99 -0
- package/src/services/notifications/catalog.ts +3 -2
- package/src/services/notifications/runtime.ts +1 -0
- package/src/services/notifications/web-push-transport.ts +45 -38
- package/src/services/outgoing-mail/dispatcher.ts +6 -1
- package/src/services/outgoing-mail/index.ts +55 -1
- package/src/services/outgoing-mail/messages.ts +82 -3
- package/src/services/outgoing-mail/resolve-host.ts +2 -2
- package/src/services/outgoing-mail/retention.ts +13 -1
- package/src/services/outgoing-mail/store.ts +36 -6
- package/src/services/outgoing-mail/test-send.ts +34 -4
- package/src/services/outgoing-mail/transport.ts +1 -1
- package/src/services/pdf/gotenberg.ts +11 -38
- package/src/services/pdf/markdown.ts +160 -2
- package/src/services/pdf/template-preview.ts +1 -1
- package/src/services/public-http.ts +28 -40
- package/src/services/session/index.ts +203 -29
- package/src/services/settings/app.ts +4 -1
- package/src/services/settings/core-settings.ts +88 -0
- package/src/services/settings/defaults.ts +8 -2
- package/src/services/settings/errors.ts +11 -0
- package/src/services/settings/geo-budget.ts +40 -0
- package/src/services/settings/index.ts +4 -3
- package/src/services/settings/store.ts +25 -17
- package/src/services/weather/geo.ts +29 -111
- package/src/services/weather/index.ts +4 -3
- package/src/services/weather/locations.ts +8 -5
- package/src/services/weather/migrate.ts +1 -0
- package/src/services/weather/settings.ts +0 -16
- package/src/shared/__snapshots__/avatar-art.test.ts.snap +5 -0
- package/src/shared/avatar-art.ts +400 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/network-address.ts +22 -3
- package/src/shared/template-rendering.ts +36 -4
- package/src/shared-text/documents.ts +1 -1
- package/src/shared-text/index.ts +2 -0
- package/src/shared-text/log.ts +51 -3
- package/src/shared-text/snapshots.ts +340 -0
- package/src/ssr/AdminLayout.tsx +4 -2
- package/src/ssr/CloudShell.island.tsx +6 -0
- package/src/ssr/HelpPanelArticle.island.tsx +308 -0
- package/src/ssr/HelpPanelBack.island.tsx +32 -0
- package/src/ssr/HelpPanelMenu.island.tsx +133 -0
- package/src/ssr/HelpPanelSearch.island.tsx +123 -0
- package/src/ssr/HelpPanelShortcuts.island.tsx +22 -0
- package/src/ssr/HelpPanelView.island.tsx +27 -0
- package/src/ssr/Layout.tsx +65 -15
- package/src/ssr/LayoutHelp.browser-harness.tsx +1 -1
- package/src/ssr/LayoutHelp.tsx +185 -542
- package/src/ssr/LayoutHelpPanel.browser-harness.tsx +6 -7
- package/src/ssr/LayoutHelpPanel.server.browser-harness.tsx +131 -0
- package/src/ssr/LayoutHelpPanel.server.tsx +115 -0
- package/src/ssr/PanelRuntime.island.tsx +11 -7
- package/src/ssr/PwaLayout.tsx +2 -2
- package/src/ssr/RailApps.tsx +6 -0
- package/src/ssr/ShellRuntime.island.tsx +23 -7
- package/src/ssr/__snapshots__/Layout.unchanged.render.test.tsx.snap +151 -0
- package/src/ssr/__snapshots__/LayoutHelp.ssr.render.test.tsx.snap +29 -0
- package/src/ssr/admin-navigation.ts +1 -0
- package/src/ssr/app-badges.ts +6 -1
- package/src/ssr/compact-shell.browser-harness.ts +44 -5
- package/src/ssr/help.ts +7 -5
- package/src/ssr/index.ts +2 -1
- package/src/ssr/islands/index.ts +3 -4
- package/src/ssr/layout-context.ts +2 -0
- package/src/ssr/layout-help-panel-controls.tsx +43 -0
- package/src/ssr/layout-help-panel-document.ts +67 -0
- package/src/ssr/layout-help-panel-lifecycle.ts +32 -0
- package/src/ssr/layout-help-panel-menu.tsx +113 -0
- package/src/ssr/layout-help-panel-modules.ts +7 -0
- package/src/ssr/layout-help-panel-reader.tsx +159 -0
- package/src/ssr/layout-help-panel-search.tsx +69 -0
- package/src/ssr/layout-help-panel-shortcuts.ts +7 -0
- package/src/ssr/layout-help-panel-state.ts +141 -0
- package/src/ssr/layout-help-panel-types.ts +19 -0
- package/src/ssr/layout-help-views.tsx +484 -0
- package/src/ssr/mobile-menu-history.ts +4 -0
- package/src/ssr/page-swap-fixture/Column.island.tsx +15 -0
- package/src/ssr/page-swap-fixture/ProviderProbe.island.tsx +31 -0
- package/src/ssr/page-swap.browser-harness.tsx +177 -0
- package/src/ssr/page-swap.ts +28 -0
- package/src/ssr/page-trail-runtime.ts +32 -13
- package/src/ssr/panel-consent.ts +2 -2
- package/src/ssr/panel-idle.ts +9 -0
- package/src/ssr/panel-slot.browser-harness.tsx +3 -0
- package/src/ssr/platform-messages.ts +8 -0
- package/src/ssr/runtime.ts +17 -0
- package/src/ssr/shell-data.tsx +10 -2
- package/src/styles/approvals.css +6 -0
- package/src/styles/effects.css +15 -0
- package/src/styles/global.css +70 -6
- package/src/server/services/geo.ts +0 -215
|
@@ -1,123 +1,41 @@
|
|
|
1
|
-
import { err, fail, ok, type PageParams
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { err, fail, ok, type PageParams } from "@k2b/stdlib";
|
|
2
|
+
import { geoClient } from "../../capabilities/geo-client";
|
|
3
|
+
import type { CapabilityCaller } from "../../capabilities/server";
|
|
4
|
+
import type { GeoProvenance } from "../../contracts/geo";
|
|
4
5
|
|
|
5
6
|
export const WEATHER_COUNTRY_CODE = "DE";
|
|
7
|
+
export type WeatherCity = { name: string; lat: number; lon: number; country?: string; state?: string; provenance: GeoProvenance };
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
name: string;
|
|
9
|
-
lat: number;
|
|
10
|
-
lon: number;
|
|
11
|
-
country?: string;
|
|
12
|
-
state?: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const unavailable = <T>(): Result<T> =>
|
|
16
|
-
fail({
|
|
17
|
-
code: "WEATHER_CITY_SEARCH_UNAVAILABLE",
|
|
18
|
-
message: "Weather city search is unavailable",
|
|
19
|
-
status: 500,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Adapts generic geo place data to the weather app's city model.
|
|
24
|
-
*/
|
|
25
|
-
const mapPlace = (place: GeoPlace): WeatherCity => ({
|
|
26
|
-
name: place.name,
|
|
27
|
-
lat: place.lat,
|
|
28
|
-
lon: place.lon,
|
|
29
|
-
country: place.country,
|
|
30
|
-
state: place.state,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Resolves and validates the configured geo service base URL.
|
|
35
|
-
*/
|
|
36
|
-
const getGeoBaseUrl = async (): Promise<Result<string>> => {
|
|
37
|
-
const geoUrl = (await settings.get<string>("weather.geo_url")).trim();
|
|
38
|
-
if (!geoUrl) {
|
|
39
|
-
return fail({
|
|
40
|
-
code: "WEATHER_CITY_SEARCH_NOT_CONFIGURED",
|
|
41
|
-
message: "Geo API URL is not configured. Set weather.geo_url.",
|
|
42
|
-
status: 500,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return ok(geoUrl.replace(/\/$/, ""));
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Searches city candidates via the geo backend and enforces weather-specific country constraints.
|
|
50
|
-
*/
|
|
9
|
+
/** Weather adapts Core's public address contract; only Core owns provider access and budgets. */
|
|
51
10
|
const list = async (config: {
|
|
11
|
+
caller: CapabilityCaller;
|
|
52
12
|
pagination?: PageParams;
|
|
53
13
|
signal?: AbortSignal;
|
|
54
|
-
filter: {
|
|
55
|
-
|
|
56
|
-
country?: string;
|
|
57
|
-
};
|
|
58
|
-
}): Promise<Result<Paginated<WeatherCity>>> => {
|
|
14
|
+
filter: { query: string; country?: string };
|
|
15
|
+
}) => {
|
|
59
16
|
const query = config.filter.query.trim();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
page: config.pagination?.page ?? 1,
|
|
64
|
-
perPage: config.pagination?.perPage ?? 20,
|
|
65
|
-
total: 0,
|
|
66
|
-
hasNext: false,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const requestedCountry = config.filter.country?.trim().toUpperCase() ?? WEATHER_COUNTRY_CODE;
|
|
71
|
-
if (requestedCountry !== WEATHER_COUNTRY_CODE) {
|
|
17
|
+
const page = config.pagination?.page ?? 1;
|
|
18
|
+
const perPage = Math.min(5, config.pagination?.perPage ?? 5);
|
|
19
|
+
if ((config.filter.country?.trim().toUpperCase() ?? WEATHER_COUNTRY_CODE) !== WEATHER_COUNTRY_CODE)
|
|
72
20
|
return fail(err.badInput("Only German city search is supported (country=DE)."));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
baseUrl: geoUrl,
|
|
80
|
-
pagination: config.pagination,
|
|
81
|
-
signal: config.signal,
|
|
82
|
-
filter: {
|
|
83
|
-
query,
|
|
84
|
-
country: WEATHER_COUNTRY_CODE,
|
|
85
|
-
featureClass: "P",
|
|
21
|
+
if (query.length < 3 || page > 1) return ok({ items: [], page, perPage, total: 0, hasNext: false });
|
|
22
|
+
const result = await geoClient.autocomplete(
|
|
23
|
+
{ text: query, countryCode: WEATHER_COUNTRY_CODE, type: "city", limit: perPage },
|
|
24
|
+
{
|
|
25
|
+
...config.caller,
|
|
26
|
+
signal: config.signal ?? config.caller.signal,
|
|
86
27
|
},
|
|
87
|
-
|
|
88
|
-
if (!result.ok) return unavailable();
|
|
89
|
-
|
|
90
|
-
return ok({
|
|
91
|
-
...result.data,
|
|
92
|
-
items: result.data.items.map(mapPlace),
|
|
93
|
-
});
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Resolves one place by coordinates via the geo backend.
|
|
98
|
-
*/
|
|
99
|
-
const get = async (config: { lat: number; lon: number }): Promise<Result<WeatherCity | null>> => {
|
|
100
|
-
const baseUrlResult = await getGeoBaseUrl();
|
|
101
|
-
if (!baseUrlResult.ok) return baseUrlResult;
|
|
102
|
-
const result = await geoService.place.get({
|
|
103
|
-
baseUrl: baseUrlResult.data,
|
|
104
|
-
lat: config.lat,
|
|
105
|
-
lon: config.lon,
|
|
106
|
-
});
|
|
28
|
+
);
|
|
107
29
|
if (!result.ok) return result;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
export const weatherCityService = {
|
|
119
|
-
list,
|
|
120
|
-
get,
|
|
30
|
+
const items = result.data.data.suggestions.map((address) => ({
|
|
31
|
+
name: address.city || address.formatted,
|
|
32
|
+
lat: address.point.lat,
|
|
33
|
+
lon: address.point.lon,
|
|
34
|
+
country: address.countryCode,
|
|
35
|
+
provenance: address.provenance,
|
|
36
|
+
...(address.stateRegion ? { state: address.stateRegion } : {}),
|
|
37
|
+
}));
|
|
38
|
+
return ok({ items, page, perPage, total: items.length, hasNext: false });
|
|
121
39
|
};
|
|
122
|
-
|
|
40
|
+
export const weatherCityService = { list };
|
|
123
41
|
export type WeatherCityService = typeof weatherCityService;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { err, fail, ok
|
|
1
|
+
import { err, fail, ok } from "@k2b/stdlib";
|
|
2
|
+
import type { CapabilityCaller } from "../../capabilities/server";
|
|
2
3
|
import { registerSettings, toLegacySettingDefs } from "../settings/defaults";
|
|
3
4
|
import { getCurrentWeather, getWeatherData } from "./forecast";
|
|
4
5
|
import { WEATHER_COUNTRY_CODE } from "./geo";
|
|
5
6
|
import { weatherLocationService } from "./location";
|
|
6
7
|
import { weatherLocationsService } from "./locations";
|
|
7
8
|
import { WEATHER_SETTINGS } from "./settings";
|
|
8
|
-
import type { WeatherData } from "./types";
|
|
9
9
|
import { weatherUiService } from "./ui";
|
|
10
10
|
|
|
11
11
|
registerSettings(toLegacySettingDefs(WEATHER_SETTINGS));
|
|
@@ -13,13 +13,14 @@ registerSettings(toLegacySettingDefs(WEATHER_SETTINGS));
|
|
|
13
13
|
/**
|
|
14
14
|
* Resolves a city name to coordinates and returns weather for the first match.
|
|
15
15
|
*/
|
|
16
|
-
const getByCityName = async (config: { query: string })
|
|
16
|
+
const getByCityName = async (config: { query: string; caller: CapabilityCaller }) => {
|
|
17
17
|
const query = config.query.trim();
|
|
18
18
|
if (!query) {
|
|
19
19
|
return fail(err.badInput("City query is required"));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const cityResult = await weatherLocationService.city.list({
|
|
23
|
+
caller: config.caller,
|
|
23
24
|
pagination: { page: 1, perPage: 1 },
|
|
24
25
|
filter: {
|
|
25
26
|
query,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { err, fail, ok, type PageParams, type Paginated, paginate, type Result } from "@k2b/stdlib";
|
|
2
2
|
import { sql } from "bun";
|
|
3
|
+
import type { GeoProvenance } from "../../contracts/geo";
|
|
3
4
|
import { logger } from "../logging";
|
|
4
5
|
import { withWeatherLocationShortId } from "./short-id";
|
|
5
6
|
|
|
@@ -11,6 +12,7 @@ export type Location = {
|
|
|
11
12
|
state: string | null;
|
|
12
13
|
lat: number;
|
|
13
14
|
lon: number;
|
|
15
|
+
provenance?: GeoProvenance | null;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -23,6 +25,7 @@ const create = async (config: {
|
|
|
23
25
|
state?: string;
|
|
24
26
|
lat: number;
|
|
25
27
|
lon: number;
|
|
28
|
+
provenance?: GeoProvenance;
|
|
26
29
|
};
|
|
27
30
|
}): Promise<Result<Location>> => {
|
|
28
31
|
try {
|
|
@@ -30,10 +33,10 @@ const create = async (config: {
|
|
|
30
33
|
await tx`SELECT pg_advisory_xact_lock(hashtext('cloud.weather.location-short-id-backfill'))`;
|
|
31
34
|
return withWeatherLocationShortId(async (shortId) => {
|
|
32
35
|
const [row] = await tx`
|
|
33
|
-
INSERT INTO weather_locations (short_id, user_id, name, state, lat, lon)
|
|
34
|
-
VALUES (${shortId}, ${config.userId}, ${config.data.name}, ${config.data.state ?? null}, ${config.data.lat}, ${config.data.lon})
|
|
36
|
+
INSERT INTO weather_locations (short_id, user_id, name, state, lat, lon, provenance)
|
|
37
|
+
VALUES (${shortId}, ${config.userId}, ${config.data.name}, ${config.data.state ?? null}, ${config.data.lat}, ${config.data.lon}, (${config.data.provenance ? JSON.stringify(config.data.provenance) : null}::text)::jsonb)
|
|
35
38
|
ON CONFLICT (short_id) DO NOTHING
|
|
36
|
-
RETURNING short_id AS id, name, state, lat, lon
|
|
39
|
+
RETURNING short_id AS id, name, state, lat, lon, provenance
|
|
37
40
|
`;
|
|
38
41
|
return (row as Location | undefined) ?? null;
|
|
39
42
|
});
|
|
@@ -93,7 +96,7 @@ const list = async (config: { userId: string; pagination?: PageParams; filter?:
|
|
|
93
96
|
`;
|
|
94
97
|
|
|
95
98
|
const items = (await sql`
|
|
96
|
-
SELECT short_id AS id, name, state, lat, lon
|
|
99
|
+
SELECT short_id AS id, name, state, lat, lon, provenance
|
|
97
100
|
FROM weather_locations
|
|
98
101
|
WHERE user_id = ${config.userId}
|
|
99
102
|
AND ${queryMatch}
|
|
@@ -118,7 +121,7 @@ const list = async (config: { userId: string; pagination?: PageParams; filter?:
|
|
|
118
121
|
*/
|
|
119
122
|
const get = async (config: { id: string; userId: string }): Promise<Location | null> => {
|
|
120
123
|
const [location] = await sql`
|
|
121
|
-
SELECT short_id AS id, name, state, lat, lon
|
|
124
|
+
SELECT short_id AS id, name, state, lat, lon, provenance
|
|
122
125
|
FROM weather_locations
|
|
123
126
|
WHERE short_id = ${config.id} AND user_id = ${config.userId}
|
|
124
127
|
`;
|
|
@@ -14,6 +14,7 @@ export const migrate = async (): Promise<void> => {
|
|
|
14
14
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
15
15
|
)
|
|
16
16
|
`.simple();
|
|
17
|
+
await sql`ALTER TABLE weather_locations ADD COLUMN IF NOT EXISTS provenance JSONB`.simple();
|
|
17
18
|
console.log(" ✓ weather_locations table");
|
|
18
19
|
|
|
19
20
|
await sql`ALTER TABLE weather_locations ADD COLUMN IF NOT EXISTS short_id TEXT`.simple();
|
|
@@ -47,20 +47,4 @@ export const WEATHER_SETTINGS = {
|
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
|
-
"weather.geo_url": {
|
|
51
|
-
kind: "url",
|
|
52
|
-
label: "Geo API URL",
|
|
53
|
-
default: "",
|
|
54
|
-
description: "Geocoding API URL for the location search feature",
|
|
55
|
-
placeholder: "e.g. https://geocoding.example.com/search",
|
|
56
|
-
presentation: {
|
|
57
|
-
translations: {
|
|
58
|
-
de: {
|
|
59
|
-
label: "Geo-API-URL",
|
|
60
|
-
description: "Geocoding-API-URL für die Ortssuche",
|
|
61
|
-
placeholder: "z. B. https://geocoding.example.com/search",
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
50
|
} as const;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
|
+
|
|
3
|
+
exports[`rendering keeps rendering a stored version 1 config byte for byte 1`] = `"7ac4c8231955f18292bccc1574886dff7fafb1453d6cbaf6d58f02452b65c4ff"`;
|
|
4
|
+
|
|
5
|
+
exports[`rendering keeps rendering a stored version 1 config byte for byte 2`] = `"f2d19e9d678d902f9e7dcb85e0eb28ee95caaf28bd32e063d7dfd7bf21a7d4a6"`;
|