@guinetik/primitives-ts 0.14.1 → 0.16.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.
@@ -1,5 +1,5 @@
1
1
  import type { GeoLocation } from "./geo.types";
2
- export type HomeWidgetType = "launchpad" | "clock" | "webpage" | "analytics" | "utility" | "news" | "weather" | "currency";
2
+ export type HomeWidgetType = "launchpad" | "clock" | "webpage" | "analytics" | "utility" | "news" | "weather" | "currency" | "crypto" | "apod" | "flight";
3
3
  export type HomeWidgetColSpan = 1 | 2 | 3;
4
4
  export interface LaunchpadWidgetConfig {
5
5
  /** Launchpad group ids to show. Omitted on legacy widgets means all groups. */
@@ -51,7 +51,28 @@ export interface CurrencyWidgetConfig {
51
51
  quote: string;
52
52
  defaultAmount: number;
53
53
  }
54
- export type HomeWidgetConfig = LaunchpadWidgetConfig | ClockWidgetConfig | WebpageWidgetConfig | AnalyticsWidgetConfig | UtilityWidgetConfig | NewsWidgetConfig | WeatherWidgetConfig | CurrencyWidgetConfig;
54
+ export declare const CRYPTO_MAX_COINS = 5;
55
+ export interface CryptoWidgetConfig {
56
+ /** Enabled provider to use. Omitted means the category default. */
57
+ providerId?: string;
58
+ /** CoinGecko-style coin ids, e.g. "bitcoin". */
59
+ coins: string[];
60
+ /** Uppercase ISO 4217 code the coins are priced in, e.g. "BRL". */
61
+ vsCurrency: string;
62
+ }
63
+ export interface ApodWidgetConfig {
64
+ /** Enabled NASA provider to use. Omitted means the NASA category default. */
65
+ providerId?: string;
66
+ }
67
+ /**
68
+ * Flight numbers are ephemeral, so the persisted config carries only the
69
+ * provider choice; the tracked number lives in the viewer's browser.
70
+ */
71
+ export interface FlightWidgetConfig {
72
+ /** Enabled flight provider to use. Omitted means the category default. */
73
+ providerId?: string;
74
+ }
75
+ export type HomeWidgetConfig = LaunchpadWidgetConfig | ClockWidgetConfig | WebpageWidgetConfig | AnalyticsWidgetConfig | UtilityWidgetConfig | NewsWidgetConfig | WeatherWidgetConfig | CurrencyWidgetConfig | CryptoWidgetConfig | ApodWidgetConfig | FlightWidgetConfig;
55
76
  export interface HomeDashboardWidget {
56
77
  id: string;
57
78
  /** Optional user-defined chrome title. The widget type is used when omitted. */
@@ -1 +1 @@
1
- {"version":3,"file":"home-dashboard.types.d.ts","sourceRoot":"","sources":["../src/home-dashboard.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,OAAO,GACP,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,UAAU,CAAC;AAEf,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE1C,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,gBAAgB,kEAInB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,GACxB,qBAAqB,GACrB,iBAAiB,GACjB,mBAAmB,GACnB,qBAAqB,GACrB,mBAAmB,GACnB,gBAAgB,GAChB,mBAAmB,GACnB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAStD,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C,eAAO,MAAM,aAAa,uEAMhB,CAAC;AAEX,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAEvE;AAED,MAAM,MAAM,gCAAgC,GAAG,MAAM,GAAG,IAAI,CAAC;AA0K7D,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,OAAO,GACd,gCAAgC,CAElC"}
1
+ {"version":3,"file":"home-dashboard.types.d.ts","sourceRoot":"","sources":["../src/home-dashboard.types.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLOCK_PRESETS = exports.CLOCK_DEFAULT_PRESET = exports.CLOCK_DEFAULT_TIMEZONE = exports.MAX_HOME_WIDGETS = exports.HOME_WIDGET_TYPES = exports.UTILITY_TOOL_IDS = void 0;
3
+ exports.CLOCK_PRESETS = exports.CLOCK_DEFAULT_PRESET = exports.CLOCK_DEFAULT_TIMEZONE = exports.MAX_HOME_WIDGETS = exports.HOME_WIDGET_TYPES = exports.CRYPTO_MAX_COINS = exports.UTILITY_TOOL_IDS = void 0;
4
4
  exports.isHomeWidgetType = isHomeWidgetType;
5
5
  exports.validateHomeWidgetConfig = validateHomeWidgetConfig;
6
6
  exports.UTILITY_TOOL_IDS = [
@@ -8,6 +8,7 @@ exports.UTILITY_TOOL_IDS = [
8
8
  "text-workbench",
9
9
  "date-calculator",
10
10
  ];
11
+ exports.CRYPTO_MAX_COINS = 5;
11
12
  exports.HOME_WIDGET_TYPES = [
12
13
  "launchpad",
13
14
  "clock",
@@ -17,6 +18,9 @@ exports.HOME_WIDGET_TYPES = [
17
18
  "news",
18
19
  "weather",
19
20
  "currency",
21
+ "crypto",
22
+ "apod",
23
+ "flight",
20
24
  ];
21
25
  exports.MAX_HOME_WIDGETS = 30;
22
26
  exports.CLOCK_DEFAULT_TIMEZONE = "America/Sao_Paulo";
@@ -186,6 +190,50 @@ const HOME_WIDGET_CONFIG_VALIDATORS = {
186
190
  ? "currency widget requires base, quote, and defaultAmount"
187
191
  : null;
188
192
  },
193
+ crypto(config) {
194
+ const value = configRecord(config);
195
+ if (!value)
196
+ return "crypto widget config must be an object";
197
+ const providerError = providerIdError(value);
198
+ if (providerError)
199
+ return providerError;
200
+ const coins = value.coins;
201
+ if (!Array.isArray(coins) ||
202
+ coins.length < 1 ||
203
+ coins.length > exports.CRYPTO_MAX_COINS ||
204
+ coins.some((coin) => typeof coin !== "string" || !/^[a-z0-9-]{1,100}$/.test(coin)) ||
205
+ new Set(coins).size !== coins.length) {
206
+ return `crypto widget requires 1 to ${exports.CRYPTO_MAX_COINS} unique lowercase coin ids`;
207
+ }
208
+ return typeof value.vsCurrency !== "string" ||
209
+ !/^[A-Z]{3}$/.test(value.vsCurrency)
210
+ ? "crypto widget vsCurrency must be a 3-letter uppercase currency code"
211
+ : null;
212
+ },
213
+ apod(config) {
214
+ const value = configRecord(config);
215
+ if (!value)
216
+ return "apod widget config must be an object";
217
+ const providerError = providerIdError(value);
218
+ if (providerError)
219
+ return providerError;
220
+ return Object.keys(value).some((key) => key !== "providerId")
221
+ ? "apod widget config contains an unsupported setting"
222
+ : null;
223
+ },
224
+ flight(config) {
225
+ const value = configRecord(config);
226
+ if (!value)
227
+ return "flight widget config must be an object";
228
+ const providerError = providerIdError(value);
229
+ if (providerError)
230
+ return providerError;
231
+ // Flight numbers are deliberately not persisted; reject them so a board
232
+ // written directly through the API cannot smuggle one in.
233
+ return Object.keys(value).some((key) => key !== "providerId")
234
+ ? "flight widget config contains an unsupported setting"
235
+ : null;
236
+ },
189
237
  };
190
238
  function validateHomeWidgetConfig(type, config) {
191
239
  return HOME_WIDGET_CONFIG_VALIDATORS[type](config);
@@ -16,13 +16,52 @@ describe("home dashboard types", () => {
16
16
  "news",
17
17
  "weather",
18
18
  "currency",
19
+ "crypto",
20
+ "apod",
21
+ "flight",
19
22
  ]);
20
23
  expect((0, home_dashboard_types_1.isHomeWidgetType)("clock")).toBe(true);
21
24
  expect((0, home_dashboard_types_1.isHomeWidgetType)("analytics")).toBe(true);
22
25
  expect((0, home_dashboard_types_1.isHomeWidgetType)("utility")).toBe(true);
23
26
  expect((0, home_dashboard_types_1.isHomeWidgetType)("weather")).toBe(true);
27
+ expect((0, home_dashboard_types_1.isHomeWidgetType)("apod")).toBe(true);
24
28
  expect((0, home_dashboard_types_1.isHomeWidgetType)("stock-ticker")).toBe(false);
25
29
  });
30
+ it("validates flight widget configs as provider-only", () => {
31
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("flight", {})).toBeNull();
32
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("flight", { providerId: "fa-1" })).toBeNull();
33
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("flight", { providerId: "" })).not.toBeNull();
34
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("flight", null)).not.toBeNull();
35
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("flight", { flightNumber: "LA8084" })).not.toBeNull();
36
+ });
37
+ it("validates the APOD provider selection", () => {
38
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("apod", {})).toBeNull();
39
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("apod", { providerId: "nasa-1" })).toBeNull();
40
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("apod", { providerId: "" })).not.toBeNull();
41
+ });
42
+ it("validates crypto widget configs", () => {
43
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("crypto", {
44
+ coins: ["bitcoin", "ethereum"],
45
+ vsCurrency: "BRL",
46
+ })).toBeNull();
47
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("crypto", {
48
+ providerId: "crypto-1",
49
+ coins: ["bitcoin"],
50
+ vsCurrency: "USD",
51
+ })).toBeNull();
52
+ const invalid = [
53
+ { coins: [], vsCurrency: "BRL" },
54
+ { coins: ["a", "b", "c", "d", "e", "f"], vsCurrency: "BRL" },
55
+ { coins: ["bitcoin", "bitcoin"], vsCurrency: "BRL" },
56
+ { coins: ["Bitcoin!"], vsCurrency: "BRL" },
57
+ { coins: ["bitcoin"], vsCurrency: "brl" },
58
+ { coins: ["bitcoin"], vsCurrency: "BRLX" },
59
+ { providerId: "", coins: ["bitcoin"], vsCurrency: "BRL" },
60
+ ];
61
+ for (const config of invalid) {
62
+ expect((0, home_dashboard_types_1.validateHomeWidgetConfig)("crypto", config)).not.toBeNull();
63
+ }
64
+ });
26
65
  it("stores a versioned allowlisted utility configuration", () => {
27
66
  const widget = {
28
67
  id: "utility-1",
@@ -1,5 +1,5 @@
1
1
  /** Shared contracts for provider-backed dashboard widgets. */
2
- export type WidgetServiceKind = "news" | "weather" | "currency" | "geo";
2
+ export type WidgetServiceKind = "news" | "weather" | "currency" | "geo" | "crypto" | "nasa" | "flight";
3
3
  export type WidgetServiceSettingValue = string | number | boolean;
4
4
  export type WidgetServiceSettings = Record<string, WidgetServiceSettingValue>;
5
5
  export interface WidgetServiceProviderSettingsMap {
@@ -11,6 +11,16 @@ export interface WidgetServiceProviderSettingsMap {
11
11
  "google-places": {
12
12
  apiKey: string;
13
13
  };
14
+ coingecko: {
15
+ apiKey?: string;
16
+ };
17
+ nasa: {
18
+ apiKey?: string;
19
+ };
20
+ flightaware: {
21
+ apiKey: string;
22
+ };
23
+ adsb: Record<string, never>;
14
24
  }
15
25
  export type WidgetServiceProviderType = keyof WidgetServiceProviderSettingsMap;
16
26
  export interface WidgetServiceSettingsField {
@@ -37,6 +47,15 @@ declare function normalizeRssSettings(settings: WidgetServiceSettings): {
37
47
  declare function normalizeGooglePlacesSettings(settings: WidgetServiceSettings): {
38
48
  apiKey: string;
39
49
  };
50
+ declare function normalizeCoingeckoSettings(settings: WidgetServiceSettings): {
51
+ apiKey?: string;
52
+ };
53
+ declare function normalizeOptionalApiKey(settings: WidgetServiceSettings): {
54
+ apiKey?: string;
55
+ };
56
+ declare function normalizeFlightAwareSettings(settings: WidgetServiceSettings): {
57
+ apiKey: string;
58
+ };
40
59
  /** Single registration point for provider metadata and per-type settings schemas. */
41
60
  export declare const WIDGET_SERVICE_PROVIDER_DEFINITIONS: {
42
61
  rss: {
@@ -84,6 +103,56 @@ export declare const WIDGET_SERVICE_PROVIDER_DEFINITIONS: {
84
103
  secretSettingKeys: "apiKey"[];
85
104
  normalizeSettings: typeof normalizeGooglePlacesSettings;
86
105
  };
106
+ coingecko: {
107
+ type: "coingecko";
108
+ kind: "crypto";
109
+ label: string;
110
+ settingsFields: {
111
+ key: string;
112
+ label: string;
113
+ input: "password";
114
+ required: false;
115
+ maxLength: number;
116
+ }[];
117
+ secretSettingKeys: "apiKey"[];
118
+ normalizeSettings: typeof normalizeCoingeckoSettings;
119
+ };
120
+ nasa: {
121
+ type: "nasa";
122
+ kind: "nasa";
123
+ label: string;
124
+ settingsFields: {
125
+ key: string;
126
+ label: string;
127
+ input: "password";
128
+ required: false;
129
+ maxLength: number;
130
+ }[];
131
+ secretSettingKeys: "apiKey"[];
132
+ normalizeSettings: typeof normalizeOptionalApiKey;
133
+ };
134
+ flightaware: {
135
+ type: "flightaware";
136
+ kind: "flight";
137
+ label: string;
138
+ settingsFields: {
139
+ key: string;
140
+ label: string;
141
+ input: "password";
142
+ required: true;
143
+ maxLength: number;
144
+ }[];
145
+ secretSettingKeys: "apiKey"[];
146
+ normalizeSettings: typeof normalizeFlightAwareSettings;
147
+ };
148
+ adsb: {
149
+ type: "adsb";
150
+ kind: "flight";
151
+ label: string;
152
+ settingsFields: never[];
153
+ secretSettingKeys: never[];
154
+ normalizeSettings: typeof noSettings;
155
+ };
87
156
  };
88
157
  export declare const WIDGET_SERVICE_PROVIDER_TYPES: readonly (keyof WidgetServiceProviderSettingsMap)[];
89
158
  export declare function normalizeWidgetServiceProviderSettings<T extends WidgetServiceProviderType>(type: T, settings: WidgetServiceSettings): WidgetServiceProviderSettingsMap[T];
@@ -145,5 +214,70 @@ export interface CurrencyRate {
145
214
  rate: number;
146
215
  date: string;
147
216
  }
217
+ export interface CryptoQuote {
218
+ /** CoinGecko-style coin id, e.g. "bitcoin". */
219
+ coinId: string;
220
+ /** Display symbol, e.g. "BTC". */
221
+ symbol: string;
222
+ /** Price in `vsCurrency`. */
223
+ price: number;
224
+ /** Uppercase ISO 4217 code the price is quoted in. */
225
+ vsCurrency: string;
226
+ change24hPercent: number;
227
+ fetchedAt: string;
228
+ }
229
+ export interface CryptoBoard {
230
+ quotes: CryptoQuote[];
231
+ fetchedAt: string;
232
+ }
233
+ export type FlightPhase = "scheduled" | "active" | "landed" | "cancelled" | "diverted" | "unknown";
234
+ export interface FlightAirport {
235
+ /** IATA or ICAO code as the provider reports it, e.g. "GRU". */
236
+ code: string;
237
+ name?: string;
238
+ city?: string;
239
+ }
240
+ export interface FlightPosition {
241
+ lat: number;
242
+ lon: number;
243
+ altitudeM?: number;
244
+ groundSpeedKph?: number;
245
+ headingDegrees?: number;
246
+ }
247
+ /**
248
+ * Normalized flight lookup result. Providers fill what they know: a
249
+ * schedule-aware provider fills times and phase; a live ADS-B provider fills
250
+ * callsign and position only, with phase "active" while broadcasting.
251
+ */
252
+ export interface FlightStatus {
253
+ /** Flight number or callsign as queried, e.g. "LA8084". */
254
+ ident: string;
255
+ callsign?: string;
256
+ phase: FlightPhase;
257
+ origin?: FlightAirport;
258
+ destination?: FlightAirport;
259
+ scheduledDeparture?: string;
260
+ actualDeparture?: string;
261
+ scheduledArrival?: string;
262
+ estimatedArrival?: string;
263
+ actualArrival?: string;
264
+ /** Positive means late, negative early, in minutes. */
265
+ arrivalDelayMinutes?: number;
266
+ /** 0-100 while en route, when the provider reports it. */
267
+ progressPercent?: number;
268
+ position?: FlightPosition;
269
+ aircraftType?: string;
270
+ fetchedAt: string;
271
+ }
272
+ export interface AstronomyPictureOfTheDay {
273
+ date: string;
274
+ title: string;
275
+ explanation: string;
276
+ mediaType: "image" | "video";
277
+ url: string;
278
+ hdUrl?: string;
279
+ thumbnailUrl?: string;
280
+ copyright?: string;
281
+ }
148
282
  export {};
149
283
  //# sourceMappingURL=widget-services.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"widget-services.types.d.ts","sourceRoot":"","sources":["../src/widget-services.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"widget-services.types.d.ts","sourceRoot":"","sources":["../src/widget-services.types.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,22 @@ function normalizeGooglePlacesSettings(settings) {
38
38
  }
39
39
  return { apiKey };
40
40
  }
41
+ function normalizeCoingeckoSettings(settings) {
42
+ const apiKey = typeof settings.apiKey === "string" ? settings.apiKey.trim() : "";
43
+ // The free tier needs no key; a surviving mask means no key was ever stored.
44
+ return apiKey && apiKey !== exports.WIDGET_SERVICE_SECRET_MASK ? { apiKey } : {};
45
+ }
46
+ function normalizeOptionalApiKey(settings) {
47
+ const apiKey = typeof settings.apiKey === "string" ? settings.apiKey.trim() : "";
48
+ return apiKey && apiKey !== exports.WIDGET_SERVICE_SECRET_MASK ? { apiKey } : {};
49
+ }
50
+ function normalizeFlightAwareSettings(settings) {
51
+ const apiKey = typeof settings.apiKey === "string" ? settings.apiKey.trim() : "";
52
+ if (!apiKey || apiKey === exports.WIDGET_SERVICE_SECRET_MASK) {
53
+ throw new Error("FlightAware API key is required");
54
+ }
55
+ return { apiKey };
56
+ }
41
57
  /** Single registration point for provider metadata and per-type settings schemas. */
42
58
  exports.WIDGET_SERVICE_PROVIDER_DEFINITIONS = {
43
59
  rss: {
@@ -89,6 +105,62 @@ exports.WIDGET_SERVICE_PROVIDER_DEFINITIONS = {
89
105
  secretSettingKeys: ["apiKey"],
90
106
  normalizeSettings: normalizeGooglePlacesSettings,
91
107
  },
108
+ coingecko: {
109
+ type: "coingecko",
110
+ kind: "crypto",
111
+ label: "CoinGecko",
112
+ settingsFields: [
113
+ {
114
+ key: "apiKey",
115
+ label: "API key (optional)",
116
+ input: "password",
117
+ required: false,
118
+ maxLength: 512,
119
+ },
120
+ ],
121
+ secretSettingKeys: ["apiKey"],
122
+ normalizeSettings: normalizeCoingeckoSettings,
123
+ },
124
+ nasa: {
125
+ type: "nasa",
126
+ kind: "nasa",
127
+ label: "NASA Open APIs",
128
+ settingsFields: [
129
+ {
130
+ key: "apiKey",
131
+ label: "API key (optional; DEMO_KEY when empty)",
132
+ input: "password",
133
+ required: false,
134
+ maxLength: 512,
135
+ },
136
+ ],
137
+ secretSettingKeys: ["apiKey"],
138
+ normalizeSettings: normalizeOptionalApiKey,
139
+ },
140
+ flightaware: {
141
+ type: "flightaware",
142
+ kind: "flight",
143
+ label: "FlightAware AeroAPI",
144
+ settingsFields: [
145
+ {
146
+ key: "apiKey",
147
+ label: "API key",
148
+ input: "password",
149
+ required: true,
150
+ maxLength: 512,
151
+ },
152
+ ],
153
+ secretSettingKeys: ["apiKey"],
154
+ normalizeSettings: normalizeFlightAwareSettings,
155
+ },
156
+ adsb: {
157
+ type: "adsb",
158
+ kind: "flight",
159
+ label: "ADS-B (adsb.lol)",
160
+ settingsFields: [],
161
+ secretSettingKeys: [],
162
+ normalizeSettings: noSettings,
163
+ },
92
164
  };
93
165
  exports.WIDGET_SERVICE_PROVIDER_TYPES = Object.freeze(Object.keys(exports.WIDGET_SERVICE_PROVIDER_DEFINITIONS));
94
166
  function normalizeWidgetServiceProviderSettings(type, settings) {
@@ -9,9 +9,17 @@ describe("widget service contracts", () => {
9
9
  value: { base: "USD", quote: "EUR", rate: 0.86, date: "2026-09-02" },
10
10
  };
11
11
  const weather = {};
12
+ const apod = {
13
+ date: "2026-09-04",
14
+ title: "The sky today",
15
+ explanation: "A test entry",
16
+ mediaType: "video",
17
+ url: "https://www.youtube.com/embed/example",
18
+ };
12
19
  expect(news.ok).toBe(false);
13
20
  expect(currency.ok).toBe(true);
14
21
  expect(weather).toEqual({});
22
+ expect(apod.mediaType).toBe("video");
15
23
  });
16
24
  });
17
25
  describe("widget service provider definitions", () => {
@@ -21,11 +29,50 @@ describe("widget service provider definitions", () => {
21
29
  "open-meteo",
22
30
  "frankfurter",
23
31
  "google-places",
32
+ "coingecko",
33
+ "nasa",
34
+ "flightaware",
35
+ "adsb",
24
36
  ]);
25
37
  expect(widget_services_types_1.WIDGET_SERVICE_PROVIDER_DEFINITIONS["google-places"]).toMatchObject({
26
38
  kind: "geo",
27
39
  secretSettingKeys: ["apiKey"],
28
40
  });
41
+ expect(widget_services_types_1.WIDGET_SERVICE_PROVIDER_DEFINITIONS.coingecko).toMatchObject({
42
+ kind: "crypto",
43
+ secretSettingKeys: ["apiKey"],
44
+ });
45
+ expect(widget_services_types_1.WIDGET_SERVICE_PROVIDER_DEFINITIONS.nasa).toMatchObject({
46
+ kind: "nasa",
47
+ secretSettingKeys: ["apiKey"],
48
+ });
49
+ expect(widget_services_types_1.WIDGET_SERVICE_PROVIDER_DEFINITIONS.flightaware).toMatchObject({
50
+ kind: "flight",
51
+ secretSettingKeys: ["apiKey"],
52
+ });
53
+ expect(widget_services_types_1.WIDGET_SERVICE_PROVIDER_DEFINITIONS.adsb).toMatchObject({
54
+ kind: "flight",
55
+ secretSettingKeys: [],
56
+ });
57
+ });
58
+ it("requires the FlightAware API key but keeps adsb keyless", () => {
59
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("flightaware", {
60
+ apiKey: " fa-key ",
61
+ })).toEqual({ apiKey: "fa-key" });
62
+ expect(() => (0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("flightaware", { apiKey: "" })).toThrow("FlightAware API key is required");
63
+ expect(() => (0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("flightaware", {
64
+ apiKey: widget_services_types_1.WIDGET_SERVICE_SECRET_MASK,
65
+ })).toThrow("FlightAware API key is required");
66
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("adsb", { ignored: true })).toEqual({});
67
+ });
68
+ it("keeps the CoinGecko API key optional", () => {
69
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("coingecko", { apiKey: " k-1 " })).toEqual({ apiKey: "k-1" });
70
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("coingecko", {})).toEqual({});
71
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("coingecko", { apiKey: "" })).toEqual({});
72
+ });
73
+ it("keeps the NASA API key optional and trims configured keys", () => {
74
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("nasa", {})).toEqual({});
75
+ expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("nasa", { apiKey: " nasa-key " })).toEqual({ apiKey: "nasa-key" });
29
76
  });
30
77
  it("normalizes settings through the selected provider schema", () => {
31
78
  expect((0, widget_services_types_1.normalizeWidgetServiceProviderSettings)("rss", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guinetik/primitives-ts",
3
- "version": "0.14.1",
3
+ "version": "0.16.0",
4
4
  "description": "Shared TypeScript primitives for Guinetik projects",
5
5
  "author": "Guinetik",
6
6
  "license": "MIT",