c8y-nitro 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/utils.d.mts CHANGED
@@ -1,11 +1,10 @@
1
- import { t as TenantCredentials } from "./credentials-9FO7rTIR.mjs";
1
+ import { t as TenantCredentials } from "./credentials-eKnJ7m9Y.mjs";
2
2
  import { useLogger } from "evlog/nitro/v3";
3
3
  import { Client, ICredentials, ICurrentUser } from "@c8y/client";
4
- import { EventHandler, H3Event } from "nitro/h3";
5
4
  import { createError, createLogger } from "evlog";
5
+ import { EventHandler, H3Event } from "nitro/h3";
6
6
  import { ServerRequest, TaskContext, TaskPayload } from "nitro/types";
7
- import { C8YRoles, C8YTenantOptionKey } from "c8y-nitro/types";
8
-
7
+ import { C8YRoles, C8YSettingsCategory, C8YTenantOptionKey } from "c8y-nitro/types";
9
8
  //#region src/utils/client.d.ts
10
9
  /**
11
10
  * Creates a Cumulocity client authenticated with the current user's credentials.\
@@ -173,7 +172,7 @@ declare const useSubscribedTenantCredentials: (() => Promise<TenantCredentials>)
173
172
  * Uses the C8Y_BOOTSTRAP_TENANT environment variable to identify the deployed tenant.\
174
173
  * Returns credentials from the subscribed tenant credentials cache (cached based on configured TTL, default: 10 minutes).
175
174
  * @returns Credentials for the deployed tenant
176
- * @throws {HTTPError} If no credentials found for the deployed tenant
175
+ * @throws {EvlogError} If no credentials found for the deployed tenant
177
176
  * @example
178
177
  * // Get deployed tenant credentials:
179
178
  * const creds = await useDeployedTenantCredentials()
@@ -196,7 +195,7 @@ declare const useDeployedTenantCredentials: (() => Promise<ICredentials>) & {
196
195
  * Results are cached in the request context for subsequent calls within the same request.
197
196
  * @param requestOrEvent - The H3Event or ServerRequest from the current request
198
197
  * @returns Credentials for the user's tenant
199
- * @throws {HTTPError} If no subscribed tenant credentials found for the user's tenant
198
+ * @throws {EvlogError} If no subscribed tenant credentials found for the user's tenant
200
199
  * @example
201
200
  * // In a request handler:
202
201
  * const userCreds = await useUserTenantCredentials(event)
@@ -209,12 +208,148 @@ declare function useUserTenantCredentials(requestOrEvent: ServerRequest | H3Even
209
208
  //#endregion
210
209
  //#region src/utils/tenantOptions.d.ts
211
210
  /**
212
- * Fetches a tenant option value by key.\
213
- * Uses the deployed tenant's service user credentials to access the Options API.\
214
- * Results are cached based on the configured TTL (default: 10 minutes).
211
+ * A tenant option key for the microservice's own settings category.
215
212
  *
216
- * @param key - The tenant option key to fetch (as defined in `manifest.settings`)
217
- * @returns The option value as a string
213
+ * Manifest-declared keys are offered via autocomplete (from the generated
214
+ * {@link C8YTenantOptionKey} union) while any other string is still accepted, so
215
+ * runtime-computed keys such as `encrypted.password.${hash}` work too.
216
+ */
217
+ type TenantOptionKeyInput = C8YTenantOptionKey | (string & {});
218
+ /**
219
+ * Guards a key used against a *foreign* settings category.
220
+ *
221
+ * `credentials.*` options are stored encrypted and can only be decrypted within
222
+ * the owning microservice's category, so they can never be read from a different
223
+ * category. Such keys collapse to `never`, turning the misuse into a compile error.
224
+ */
225
+ type ForeignTenantOptionKeyInput<K extends string> = K & (K extends `credentials.${string}` ? never : unknown);
226
+ /**
227
+ * Options for {@link TenantOption.setEditable}.
228
+ */
229
+ interface SetEditableOptions {
230
+ /**
231
+ * The tenant whose option `editable` flag is updated.
232
+ *
233
+ * Required by Cumulocity: the editable-flag endpoint is only permitted from
234
+ * the management tenant, and the target tenant must be given explicitly.
235
+ */
236
+ targetTenant: string;
237
+ }
238
+ /**
239
+ * Handle for a single tenant option (a `category` + `key` pair).
240
+ *
241
+ * Obtained via {@link useTenantOption} (own category) or
242
+ * `useTenantOptions(category).option(key)`.
243
+ */
244
+ interface TenantOption {
245
+ /**
246
+ * Read the current value. Returns `undefined` when the option is not set
247
+ * (Cumulocity responds `404`). The value is cached per the configured TTL.
248
+ */
249
+ read: () => Promise<string | undefined>;
250
+ /**
251
+ * Create or update the option value (upsert), then invalidate the cached read.
252
+ */
253
+ set: (value: string) => Promise<void>;
254
+ /**
255
+ * Read the value; if it is not set, write `fallback` and return it.
256
+ */
257
+ getOrInsert: (fallback: string) => Promise<string>;
258
+ /**
259
+ * Delete the option. Idempotent — a missing option resolves without error.
260
+ * Invalidates the cached read afterwards.
261
+ */
262
+ delete: () => Promise<void>;
263
+ /**
264
+ * Update the option's `editable` flag.
265
+ *
266
+ * @remarks Cumulocity only allows this from the **management tenant** (role
267
+ * `ROLE_OPTION_MANAGEMENT_ADMIN`). It will fail with `403` when called from a
268
+ * regular subscribed-tenant microservice.
269
+ */
270
+ setEditable: (editable: boolean, options: SetEditableOptions) => Promise<void>;
271
+ /**
272
+ * Invalidate the cached value, then re-read it.
273
+ */
274
+ refresh: () => Promise<string | undefined>;
275
+ /**
276
+ * Invalidate the cached value (no-op if it was never read).
277
+ */
278
+ invalidate: () => Promise<void>;
279
+ }
280
+ /**
281
+ * Handle for all options within the microservice's own settings category.
282
+ */
283
+ interface TenantOptionCategory {
284
+ /**
285
+ * Get a handle for a single option in this category.
286
+ */
287
+ option: (key: TenantOptionKeyInput) => TenantOption;
288
+ /**
289
+ * List all options set in this category as a key/value map.
290
+ */
291
+ list: () => Promise<Record<string, string>>;
292
+ /**
293
+ * Create or update multiple options in this category, then invalidate their caches.
294
+ */
295
+ setAll: (values: Record<string, string>) => Promise<void>;
296
+ /**
297
+ * Invalidate every already-read option cache in this category.
298
+ */
299
+ invalidateAll: () => Promise<void>;
300
+ /**
301
+ * Refresh every already-read option cache in this category.
302
+ * @returns A map of the refreshed keys to their new values.
303
+ */
304
+ refreshAll: () => Promise<Record<string, string | undefined>>;
305
+ }
306
+ /**
307
+ * Handle for a *foreign* settings category (one other than the microservice's own).
308
+ *
309
+ * Identical to {@link TenantOptionCategory} except that:
310
+ * - `credentials.*` keys are rejected — see {@link ForeignTenantOptionKeyInput};
311
+ * - the optional type parameter `K` sets the known key set for autocomplete
312
+ * (`useTenantOptions<'a' | 'b'>(client, 'other')`). It defaults to `string`,
313
+ * which accepts any key (still minus `credentials.*`).
314
+ */
315
+ interface ForeignTenantOptionCategory<K extends string = string> {
316
+ /**
317
+ * Get a handle for a single non-`credentials.*` option in this category.
318
+ * Completes to `K` when a key set was provided.
319
+ */
320
+ option: <Key extends K>(key: ForeignTenantOptionKeyInput<Key>) => TenantOption;
321
+ /**
322
+ * List all options set in this category as a key/value map.
323
+ */
324
+ list: () => Promise<Record<string, string>>;
325
+ /**
326
+ * Create or update multiple options in this category, then invalidate their caches.
327
+ */
328
+ setAll: (values: Record<string, string>) => Promise<void>;
329
+ /**
330
+ * Invalidate every already-read option cache in this category.
331
+ */
332
+ invalidateAll: () => Promise<void>;
333
+ /**
334
+ * Refresh every already-read option cache in this category.
335
+ * @returns A map of the refreshed keys to their new values.
336
+ */
337
+ refreshAll: () => Promise<Record<string, string | undefined>>;
338
+ }
339
+ /**
340
+ * Gets a handle for a single tenant option in the microservice's **own** settings
341
+ * category, targeting the tenant of the given `client`.\
342
+ * Reads are cached per tenant, using the client's service user credentials.
343
+ *
344
+ * This is a shortcut for `useTenantOptions(client).option(key)` — it only drops
345
+ * the category argument. For a single option in a **foreign** category, use
346
+ * `useTenantOptions(client, category).option(key)`.
347
+ *
348
+ * Manifest-declared keys are offered via autocomplete, but any dynamic string
349
+ * is accepted too (e.g. `encrypted.password.${hash}`).
350
+ *
351
+ * @param client - The Cumulocity client that determines the target tenant
352
+ * @param key - The tenant option key
218
353
  *
219
354
  * @config Cache TTL can be configured via:
220
355
  * - `c8y.cache.defaultTenantOptionsTTL` — Default TTL for all keys (in seconds)
@@ -222,47 +357,73 @@ declare function useUserTenantCredentials(requestOrEvent: ServerRequest | H3Even
222
357
  * - `NITRO_C8Y_DEFAULT_TENANT_OPTIONS_TTL` — Environment variable for default TTL
223
358
  *
224
359
  * @example
225
- * // Fetch a tenant option:
226
- * const value = await useTenantOption('myOption')
227
- *
228
- * // Fetch an encrypted secret:
229
- * const secret = await useTenantOption('credentials.apiKey')
230
- *
231
- * // Invalidate cache for a specific key:
232
- * await useTenantOption.invalidate('myOption')
233
- *
234
- * // Force refresh a specific key:
235
- * const fresh = await useTenantOption.refresh('myOption')
360
+ * // Read the owner tenant's config:
361
+ * const value = await useTenantOption(await useDeployedTenantClient(), 'featureMode').read()
236
362
  *
237
- * // Invalidate all tenant option caches:
238
- * await useTenantOption.invalidateAll()
363
+ * // Read the current request tenant's config (multi-tenant):
364
+ * const value = await useTenantOption(await useUserTenantClient(event), 'featureMode').read()
239
365
  *
240
- * // Refresh all tenant options:
241
- * const all = await useTenantOption.refreshAll()
366
+ * // Create or update, or seed a dynamic key:
367
+ * await useTenantOption(client, 'featureMode').set('advanced')
368
+ * const token = await useTenantOption(client, `encrypted.password.${hash}`).getOrInsert('')
242
369
  */
243
- declare const useTenantOption: ((key: C8YTenantOptionKey) => Promise<string | undefined>) & {
370
+ declare function useTenantOption(client: Client, key: TenantOptionKeyInput): TenantOption;
371
+ /**
372
+ * @internal
373
+ */
374
+ interface UseTenantOptions {
244
375
  /**
245
- * Invalidate the cache for a specific tenant option key.
246
- * @param key - The tenant option key to invalidate
376
+ * Handle for the client tenant's own settings category.
247
377
  */
248
- invalidate: (key: C8YTenantOptionKey) => Promise<void>;
378
+ (client: Client): TenantOptionCategory;
249
379
  /**
250
- * Force refresh a specific tenant option key (invalidates and re-fetches).
251
- * @param key - The tenant option key to refresh
380
+ * Handle for the client tenant's own settings category (given explicitly).
252
381
  */
253
- refresh: (key: C8YTenantOptionKey) => Promise<string | undefined>;
382
+ (client: Client, category: C8YSettingsCategory): TenantOptionCategory;
254
383
  /**
255
- * Invalidate all tenant option caches that have been accessed.
256
- * Only invalidates keys that have been fetched at least once.
384
+ * Handle for a foreign settings category (`credentials.*` keys are rejected).
385
+ *
386
+ * Provide the key set as a type argument for autocomplete, e.g.
387
+ * `useTenantOptions<'featureA' | 'featureB'>(client, 'other-service')`.
388
+ * Supplying a type argument also explicitly selects this overload.
389
+ */
390
+ <K extends string = string>(client: Client, category: string): ForeignTenantOptionCategory<K>;
391
+ /**
392
+ * Invalidate every already-read option cache, across all tenants and categories.
257
393
  */
258
394
  invalidateAll: () => Promise<void>;
259
395
  /**
260
- * Refresh all tenant options that have been accessed.
261
- * Only refreshes keys that have been fetched at least once.
262
- * @returns Object mapping keys to their refreshed values
396
+ * Refresh every already-read option cache, across all tenants and categories.
397
+ * @returns Map of `${tenant}::${category}::${key}` store keys to their refreshed values.
263
398
  */
264
399
  refreshAll: () => Promise<Record<string, string | undefined>>;
265
- };
400
+ }
401
+ /**
402
+ * Gets a handle for a whole settings category, targeting the tenant of the given
403
+ * `client`.\
404
+ * Omit the category (or pass the own {@link C8YSettingsCategory}) for the
405
+ * microservice's own category; pass any other category to read/write options in
406
+ * a foreign category (where `credentials.*` keys are rejected).
407
+ *
408
+ * @param client - The Cumulocity client that determines the target tenant
409
+ *
410
+ * @example
411
+ * const client = await useUserTenantClient(event)
412
+ *
413
+ * // Own category:
414
+ * const values = await useTenantOptions(client).list()
415
+ * await useTenantOptions(client).option('featureMode').set('advanced')
416
+ *
417
+ * // Foreign category:
418
+ * const value = await useTenantOptions(client, 'other-service').option('someKey').read()
419
+ *
420
+ * // Invalidate all cached options of one tenant + category:
421
+ * await useTenantOptions(client, 'other-service').invalidateAll()
422
+ *
423
+ * // Invalidate everything, across all tenants and categories:
424
+ * await useTenantOptions.invalidateAll()
425
+ */
426
+ declare const useTenantOptions: UseTenantOptions;
266
427
  //#endregion
267
428
  //#region src/utils/schedule.d.ts
268
429
  type ScheduledTaskPayload = TaskPayload;
@@ -370,4 +531,4 @@ declare function listScheduledTasks(): Promise<Record<string, ScheduledTaskInfo>
370
531
  */
371
532
  declare function cancelScheduledTask(id: string): Promise<boolean>;
372
533
  //#endregion
373
- export { ScheduleTaskOptions, ScheduledTaskContext, ScheduledTaskInfo, ScheduledTaskInput, ScheduledTaskPayload, cancelScheduledTask, createError, createLogger, hasUserRequiredRole, isUserFromAllowedTenant, isUserFromDeployedTenant, listScheduledTasks, scheduleTask, useDeployedTenantClient, useDeployedTenantCredentials, useLogger, useSubscribedTenantClients, useSubscribedTenantCredentials, useTenantOption, useUser, useUserClient, useUserRoles, useUserTenantClient, useUserTenantCredentials };
534
+ export { ForeignTenantOptionCategory, ForeignTenantOptionKeyInput, ScheduleTaskOptions, ScheduledTaskContext, ScheduledTaskInfo, ScheduledTaskInput, ScheduledTaskPayload, SetEditableOptions, TenantOption, TenantOptionCategory, TenantOptionKeyInput, cancelScheduledTask, createError, createLogger, hasUserRequiredRole, isUserFromAllowedTenant, isUserFromDeployedTenant, listScheduledTasks, scheduleTask, useDeployedTenantClient, useDeployedTenantCredentials, useLogger, useSubscribedTenantClients, useSubscribedTenantCredentials, useTenantOption, useTenantOptions, useUser, useUserClient, useUserRoles, useUserTenantClient, useUserTenantCredentials };