c8y-nitro 0.3.0 → 0.4.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/bootstrap-CGOe2HxK.mjs +61 -0
- package/dist/{cli/utils/c8y-api.mjs → c8y-api-BBSKRwKs.mjs} +73 -3
- package/dist/cli/index.mjs +5 -7
- package/dist/{cli/utils/config.mjs → config-Dqi-ttQi.mjs} +1 -3
- package/dist/{cli/utils/env-file.mjs → env-file-B0BK-uZW.mjs} +1 -3
- package/dist/{types/manifest.d.mts → index-B6HtYHU0.d.mts} +94 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +542 -11
- package/dist/{cli/commands/options.mjs → options-CuGdGP4l.mjs} +27 -30
- package/dist/{package.mjs → package-BAjMvZYS.mjs} +2 -3
- package/dist/{cli/commands/roles.mjs → roles-DrJsxUG-.mjs} +11 -14
- package/dist/runtime/handlers/liveness-readiness.d.mts +8 -0
- package/dist/runtime/handlers/liveness-readiness.mjs +7 -0
- package/dist/runtime/middlewares/dev-user.d.mts +6 -0
- package/dist/runtime/middlewares/dev-user.mjs +23 -0
- package/dist/runtime/plugins/c8y-variables.d.mts +6 -0
- package/dist/runtime/plugins/c8y-variables.mjs +17 -0
- package/dist/types.d.mts +2 -25
- package/dist/types.mjs +1 -1
- package/dist/utils.d.mts +292 -6
- package/dist/utils.mjs +444 -8
- package/package.json +10 -10
- package/dist/cli/commands/bootstrap.mjs +0 -64
- package/dist/module/apiClient.mjs +0 -207
- package/dist/module/autoBootstrap.mjs +0 -54
- package/dist/module/c8yzip.mjs +0 -66
- package/dist/module/constants.mjs +0 -6
- package/dist/module/docker.mjs +0 -101
- package/dist/module/manifest.mjs +0 -72
- package/dist/module/probeCheck.mjs +0 -30
- package/dist/module/register.mjs +0 -58
- package/dist/module/runtime/handlers/liveness-readiness.ts +0 -7
- package/dist/module/runtime/middlewares/dev-user.ts +0 -25
- package/dist/module/runtime/plugins/c8y-variables.ts +0 -24
- package/dist/module/runtime.mjs +0 -38
- package/dist/module/runtimeConfig.mjs +0 -20
- package/dist/types/apiClient.d.mts +0 -16
- package/dist/types/cache.d.mts +0 -28
- package/dist/types/roles.d.mts +0 -4
- package/dist/types/tenantOptions.d.mts +0 -13
- package/dist/types/zip.d.mts +0 -22
- package/dist/utils/client.d.mts +0 -52
- package/dist/utils/client.mjs +0 -90
- package/dist/utils/credentials.d.mts +0 -71
- package/dist/utils/credentials.mjs +0 -120
- package/dist/utils/internal/common.mjs +0 -26
- package/dist/utils/logging.d.mts +0 -3
- package/dist/utils/logging.mjs +0 -4
- package/dist/utils/middleware.d.mts +0 -89
- package/dist/utils/middleware.mjs +0 -62
- package/dist/utils/resources.d.mts +0 -30
- package/dist/utils/resources.mjs +0 -49
- package/dist/utils/tenantOptions.d.mts +0 -65
- package/dist/utils/tenantOptions.mjs +0 -127
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { createC8yManifest } from "
|
|
2
|
-
import {
|
|
3
|
-
import { loadC8yConfig, validateBootstrapEnv } from "../utils/config.mjs";
|
|
1
|
+
import { c as getTenantOptionsByCategory, f as updateTenantOption, i as deleteTenantOption, n as createBasicAuthHeader, p as createC8yManifest, s as getTenantOption } from "./c8y-api-BBSKRwKs.mjs";
|
|
2
|
+
import { n as validateBootstrapEnv, t as loadC8yConfig } from "./config-Dqi-ttQi.mjs";
|
|
4
3
|
import { defineCommand } from "citty";
|
|
5
|
-
import { consola } from "consola";
|
|
6
|
-
|
|
4
|
+
import { consola as consola$1 } from "consola";
|
|
7
5
|
//#region src/cli/commands/options.ts
|
|
8
6
|
var options_default = defineCommand({
|
|
9
7
|
meta: {
|
|
@@ -12,21 +10,21 @@ var options_default = defineCommand({
|
|
|
12
10
|
},
|
|
13
11
|
args: {},
|
|
14
12
|
async run() {
|
|
15
|
-
consola.info("Loading configuration...");
|
|
13
|
+
consola$1.info("Loading configuration...");
|
|
16
14
|
const { env, c8yOptions, configDir } = await loadC8yConfig();
|
|
17
|
-
consola.info("Validating environment variables...");
|
|
15
|
+
consola$1.info("Validating environment variables...");
|
|
18
16
|
const envVars = validateBootstrapEnv(env);
|
|
19
|
-
consola.info("Loading manifest...");
|
|
17
|
+
consola$1.info("Loading manifest...");
|
|
20
18
|
const manifest = await createC8yManifest(configDir, c8yOptions?.manifest);
|
|
21
19
|
const category = manifest.settingsCategory || manifest.contextPath || manifest.name;
|
|
22
20
|
if (!manifest.settings || manifest.settings.length === 0) throw new Error("No settings defined in manifest. Add settings to your c8y.manifest configuration.");
|
|
23
|
-
consola.success(`Using category: ${category}`);
|
|
21
|
+
consola$1.success(`Using category: ${category}`);
|
|
24
22
|
const authHeader = createBasicAuthHeader(envVars.C8Y_DEVELOPMENT_TENANT, envVars.C8Y_DEVELOPMENT_USER, envVars.C8Y_DEVELOPMENT_PASSWORD);
|
|
25
|
-
consola.info("Fetching current tenant options...");
|
|
23
|
+
consola$1.info("Fetching current tenant options...");
|
|
26
24
|
const currentOptions = await getTenantOptionsByCategory(envVars.C8Y_BASEURL, category, authHeader);
|
|
27
25
|
const availableKeys = manifest.settings.map((s) => s.key);
|
|
28
|
-
consola.success(`Found ${Object.keys(currentOptions).length} options set on tenant`);
|
|
29
|
-
const action = await consola.prompt("What do you want to do?", {
|
|
26
|
+
consola$1.success(`Found ${Object.keys(currentOptions).length} options set on tenant`);
|
|
27
|
+
const action = await consola$1.prompt("What do you want to do?", {
|
|
30
28
|
type: "select",
|
|
31
29
|
options: [
|
|
32
30
|
{
|
|
@@ -61,10 +59,10 @@ async function handleRead(baseUrl, category, authHeader, availableKeys, currentO
|
|
|
61
59
|
const credentialsKeys = availableKeys.filter((k) => k.startsWith("credentials."));
|
|
62
60
|
const allKeys = [...setKeys, ...credentialsKeys];
|
|
63
61
|
if (allKeys.length === 0) {
|
|
64
|
-
consola.warn("No options are currently set");
|
|
62
|
+
consola$1.warn("No options are currently set");
|
|
65
63
|
return;
|
|
66
64
|
}
|
|
67
|
-
const key = await consola.prompt("Select option to read:", {
|
|
65
|
+
const key = await consola$1.prompt("Select option to read:", {
|
|
68
66
|
type: "select",
|
|
69
67
|
options: allKeys.map((k) => ({
|
|
70
68
|
label: k.startsWith("credentials.") ? `${k} (unknown)` : k,
|
|
@@ -72,10 +70,10 @@ async function handleRead(baseUrl, category, authHeader, availableKeys, currentO
|
|
|
72
70
|
})),
|
|
73
71
|
cancel: "reject"
|
|
74
72
|
});
|
|
75
|
-
consola.info(`Reading option: ${key}`);
|
|
73
|
+
consola$1.info(`Reading option: ${key}`);
|
|
76
74
|
const value = await getTenantOption(baseUrl, category, key.startsWith("credentials.") ? key.replace(/^credentials\./, "") : key, authHeader);
|
|
77
|
-
if (value === void 0) consola.warn(`Option '${key}' is not set`);
|
|
78
|
-
else consola.success(`Value: ${value}`);
|
|
75
|
+
if (value === void 0) consola$1.warn(`Option '${key}' is not set`);
|
|
76
|
+
else consola$1.success(`Value: ${value}`);
|
|
79
77
|
}
|
|
80
78
|
/**
|
|
81
79
|
* Handle updating options (with loop for multiple updates)
|
|
@@ -88,7 +86,7 @@ async function handleRead(baseUrl, category, authHeader, availableKeys, currentO
|
|
|
88
86
|
async function handleUpdate(baseUrl, category, authHeader, availableKeys, currentOptions) {
|
|
89
87
|
let continueUpdating = true;
|
|
90
88
|
while (continueUpdating) {
|
|
91
|
-
const key = await consola.prompt("Select option to update:", {
|
|
89
|
+
const key = await consola$1.prompt("Select option to update:", {
|
|
92
90
|
type: "select",
|
|
93
91
|
options: availableKeys.map((k) => ({
|
|
94
92
|
label: currentOptions[k] !== void 0 ? `${k} (current: ${currentOptions[k]})` : k.startsWith("credentials.") ? `${k} (current: unknown)` : `${k} (not set)`,
|
|
@@ -97,16 +95,16 @@ async function handleUpdate(baseUrl, category, authHeader, availableKeys, curren
|
|
|
97
95
|
cancel: "reject"
|
|
98
96
|
});
|
|
99
97
|
const currentValue = currentOptions[key];
|
|
100
|
-
const newValue = await consola.prompt("Enter new value:", {
|
|
98
|
+
const newValue = await consola$1.prompt("Enter new value:", {
|
|
101
99
|
type: "text",
|
|
102
100
|
default: currentValue,
|
|
103
101
|
cancel: "reject"
|
|
104
102
|
});
|
|
105
|
-
consola.info(`Updating option: ${key}`);
|
|
103
|
+
consola$1.info(`Updating option: ${key}`);
|
|
106
104
|
await updateTenantOption(baseUrl, category, key.replace(/^credentials\./, ""), newValue, authHeader);
|
|
107
105
|
currentOptions[key] = newValue;
|
|
108
|
-
consola.success(`Option '${key}' updated successfully`);
|
|
109
|
-
if (!await consola.prompt("Update another option?", {
|
|
106
|
+
consola$1.success(`Option '${key}' updated successfully`);
|
|
107
|
+
if (!await consola$1.prompt("Update another option?", {
|
|
110
108
|
type: "confirm",
|
|
111
109
|
initial: false,
|
|
112
110
|
cancel: "reject"
|
|
@@ -126,23 +124,22 @@ async function handleDelete(baseUrl, category, authHeader, availableKeys, curren
|
|
|
126
124
|
const credentialsKeys = availableKeys.filter((k) => k.startsWith("credentials."));
|
|
127
125
|
const allKeys = [...setKeys, ...credentialsKeys];
|
|
128
126
|
if (allKeys.length === 0) {
|
|
129
|
-
consola.warn("No options are currently set");
|
|
127
|
+
consola$1.warn("No options are currently set");
|
|
130
128
|
return;
|
|
131
129
|
}
|
|
132
|
-
const keysToDelete = await consola.prompt("Select option(s) to delete:", {
|
|
130
|
+
const keysToDelete = await consola$1.prompt("Select option(s) to delete:", {
|
|
133
131
|
type: "multiselect",
|
|
134
132
|
options: allKeys,
|
|
135
133
|
required: true,
|
|
136
134
|
cancel: "reject"
|
|
137
135
|
});
|
|
138
|
-
consola.info(`Deleting ${keysToDelete.length} option(s)...`);
|
|
136
|
+
consola$1.info(`Deleting ${keysToDelete.length} option(s)...`);
|
|
139
137
|
for (const key of keysToDelete) {
|
|
140
|
-
consola.info(`Deleting option: ${key}`);
|
|
138
|
+
consola$1.info(`Deleting option: ${key}`);
|
|
141
139
|
await deleteTenantOption(baseUrl, category, key.startsWith("credentials.") ? key.replace(/^credentials\./, "") : key, authHeader);
|
|
142
|
-
consola.success(`✓ Deleted: ${key}`);
|
|
140
|
+
consola$1.success(`✓ Deleted: ${key}`);
|
|
143
141
|
}
|
|
144
|
-
consola.success("Delete operation completed");
|
|
142
|
+
consola$1.success("Delete operation completed");
|
|
145
143
|
}
|
|
146
|
-
|
|
147
144
|
//#endregion
|
|
148
|
-
export { options_default as default };
|
|
145
|
+
export { options_default as default };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
//#region package.json
|
|
2
2
|
var name = "c8y-nitro";
|
|
3
|
-
var version = "0.
|
|
3
|
+
var version = "0.4.0";
|
|
4
4
|
var description = "Lightning fast Cumulocity IoT microservice development powered by Nitro";
|
|
5
|
-
|
|
6
5
|
//#endregion
|
|
7
|
-
export {
|
|
6
|
+
export { name as n, version as r, description as t };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { createC8yManifest } from "
|
|
2
|
-
import {
|
|
3
|
-
import { loadC8yConfig, validateBootstrapEnv } from "../utils/config.mjs";
|
|
1
|
+
import { n as createBasicAuthHeader, p as createC8yManifest, t as assignUserRole, u as unassignUserRole } from "./c8y-api-BBSKRwKs.mjs";
|
|
2
|
+
import { n as validateBootstrapEnv, t as loadC8yConfig } from "./config-Dqi-ttQi.mjs";
|
|
4
3
|
import { defineCommand } from "citty";
|
|
5
|
-
import { consola } from "consola";
|
|
6
|
-
|
|
4
|
+
import { consola as consola$1 } from "consola";
|
|
7
5
|
//#region src/cli/commands/roles.ts
|
|
8
6
|
var roles_default = defineCommand({
|
|
9
7
|
meta: {
|
|
@@ -12,30 +10,29 @@ var roles_default = defineCommand({
|
|
|
12
10
|
},
|
|
13
11
|
args: {},
|
|
14
12
|
async run() {
|
|
15
|
-
consola.info("Loading configuration...");
|
|
13
|
+
consola$1.info("Loading configuration...");
|
|
16
14
|
const { env, c8yOptions, configDir } = await loadC8yConfig();
|
|
17
|
-
consola.info("Validating environment variables...");
|
|
15
|
+
consola$1.info("Validating environment variables...");
|
|
18
16
|
const envVars = validateBootstrapEnv(env);
|
|
19
|
-
consola.info("Building manifest...");
|
|
17
|
+
consola$1.info("Building manifest...");
|
|
20
18
|
const manifest = await createC8yManifest(configDir, c8yOptions?.manifest);
|
|
21
19
|
const authHeader = createBasicAuthHeader(envVars.C8Y_DEVELOPMENT_TENANT, envVars.C8Y_DEVELOPMENT_USER, envVars.C8Y_DEVELOPMENT_PASSWORD);
|
|
22
20
|
if (manifest.roles && manifest.roles.length > 0) {
|
|
23
|
-
const rolesToAssign = await consola.prompt("Select roles to assign to your user (unselected roles will be removed):", {
|
|
21
|
+
const rolesToAssign = await consola$1.prompt("Select roles to assign to your user (unselected roles will be removed):", {
|
|
24
22
|
type: "multiselect",
|
|
25
23
|
options: manifest.roles,
|
|
26
24
|
cancel: "reject",
|
|
27
25
|
required: false
|
|
28
26
|
});
|
|
29
|
-
consola.info("Managing user roles...");
|
|
27
|
+
consola$1.info("Managing user roles...");
|
|
30
28
|
const rolePromises = manifest.roles.map(async (role) => {
|
|
31
29
|
if (rolesToAssign.includes(role)) return await assignUserRole(envVars.C8Y_BASEURL, envVars.C8Y_DEVELOPMENT_TENANT, envVars.C8Y_DEVELOPMENT_USER, role, authHeader);
|
|
32
30
|
else return await unassignUserRole(envVars.C8Y_BASEURL, envVars.C8Y_DEVELOPMENT_TENANT, envVars.C8Y_DEVELOPMENT_USER, role, authHeader);
|
|
33
31
|
});
|
|
34
32
|
await Promise.all(rolePromises);
|
|
35
|
-
consola.success("Role management complete");
|
|
36
|
-
} else consola.warn("No roles defined in manifest. Nothing to manage.");
|
|
33
|
+
consola$1.success("Role management complete");
|
|
34
|
+
} else consola$1.warn("No roles defined in manifest. Nothing to manage.");
|
|
37
35
|
}
|
|
38
36
|
});
|
|
39
|
-
|
|
40
37
|
//#endregion
|
|
41
|
-
export { roles_default as default };
|
|
38
|
+
export { roles_default as default };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as nitro_h30 from "nitro/h3";
|
|
2
|
+
|
|
3
|
+
//#region src/module/runtime/handlers/liveness-readiness.d.ts
|
|
4
|
+
declare const _default: nitro_h30.EventHandlerWithFetch<nitro_h30.EventHandlerRequest, Promise<{
|
|
5
|
+
status: string;
|
|
6
|
+
}>>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { _default as default };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineEventHandler } from "nitro/h3";
|
|
2
|
+
//#region src/module/runtime/handlers/liveness-readiness.ts
|
|
3
|
+
var liveness_readiness_default = defineEventHandler(async () => {
|
|
4
|
+
return { status: "OK" };
|
|
5
|
+
});
|
|
6
|
+
//#endregion
|
|
7
|
+
export { liveness_readiness_default as default };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { defineHandler } from "nitro/h3";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
//#region src/module/runtime/middlewares/dev-user.ts
|
|
6
|
+
var dev_user_default = defineHandler((event) => {
|
|
7
|
+
if (import.meta.dev) {
|
|
8
|
+
const missingDevVars = [
|
|
9
|
+
"C8Y_DEVELOPMENT_TENANT",
|
|
10
|
+
"C8Y_DEVELOPMENT_USER",
|
|
11
|
+
"C8Y_DEVELOPMENT_PASSWORD"
|
|
12
|
+
].filter((varName) => !process.env[varName]);
|
|
13
|
+
if (missingDevVars.length > 0) consola.warn(`Missing development environment variables: ${missingDevVars.join(", ")}. Dev user injection will be skipped. Routes requiring authentication or roles will fail.`);
|
|
14
|
+
else {
|
|
15
|
+
const authString = `${process.env.C8Y_DEVELOPMENT_TENANT}/${process.env.C8Y_DEVELOPMENT_USER}:${process.env.C8Y_DEVELOPMENT_PASSWORD}`;
|
|
16
|
+
const authHeader = `Basic ${Buffer.from(authString).toString("base64")}`;
|
|
17
|
+
event.req.headers.set("authorization", authHeader);
|
|
18
|
+
}
|
|
19
|
+
if (event.req.headers.has("cookie")) event.req.headers.delete("cookie");
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
//#endregion
|
|
23
|
+
export { dev_user_default as default };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { definePlugin } from "nitro";
|
|
3
|
+
//#region src/module/runtime/plugins/c8y-variables.ts
|
|
4
|
+
var c8y_variables_default = definePlugin(() => {
|
|
5
|
+
if (import.meta.dev) {
|
|
6
|
+
const env = process.env;
|
|
7
|
+
const missingVars = [
|
|
8
|
+
"C8Y_BASEURL",
|
|
9
|
+
"C8Y_BOOTSTRAP_TENANT",
|
|
10
|
+
"C8Y_BOOTSTRAP_USER",
|
|
11
|
+
"C8Y_BOOTSTRAP_PASSWORD"
|
|
12
|
+
].filter((varName) => !env[varName]);
|
|
13
|
+
if (missingVars.length > 0) throw new Error(`Missing required environment variables for development: ${missingVars.join(", ")}\n\nTo set up your development environment, run:\n npx c8y-nitro bootstrap\n\nThis command will:\n 1. Require your development tenant credentials (C8Y_BASEURL C8Y_DEVELOPMENT_TENANT, C8Y_DEVELOPMENT_USER, C8Y_DEVELOPMENT_PASSWORD)\n 2. Register your microservice on the tenant\n 3. Generate the necessary bootstrap credentials in a .env file\n\nMake sure you have your development tenant credentials configured first.`);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
//#endregion
|
|
17
|
+
export { c8y_variables_default as default };
|
package/dist/types.d.mts
CHANGED
|
@@ -1,25 +1,2 @@
|
|
|
1
|
-
import { C8YAPIClientOptions } from "./
|
|
2
|
-
|
|
3
|
-
import { C8YZipOptions } from "./types/zip.mjs";
|
|
4
|
-
import { C8yCacheOptions } from "./types/cache.mjs";
|
|
5
|
-
import { C8YRoles } from "./types/roles.mjs";
|
|
6
|
-
import { C8YTenantOptionKey, C8YTenantOptionKeysCacheConfig } from "./types/tenantOptions.mjs";
|
|
7
|
-
|
|
8
|
-
//#region src/types/index.d.ts
|
|
9
|
-
interface C8yNitroModuleOptions {
|
|
10
|
-
manifest?: C8YManifestOptions;
|
|
11
|
-
apiClient?: C8YAPIClientOptions;
|
|
12
|
-
zip?: C8YZipOptions;
|
|
13
|
-
cache?: C8yCacheOptions;
|
|
14
|
-
/**
|
|
15
|
-
* Disable auto-bootstrap during development.
|
|
16
|
-
* When true, the module will not automatically register the microservice
|
|
17
|
-
* or retrieve bootstrap credentials on startup.
|
|
18
|
-
*
|
|
19
|
-
* Useful for CI/CD pipelines or manual bootstrap management.
|
|
20
|
-
* @default false
|
|
21
|
-
*/
|
|
22
|
-
skipBootstrap?: boolean;
|
|
23
|
-
}
|
|
24
|
-
//#endregion
|
|
25
|
-
export { C8YAPIClientOptions, type C8YManifestOptions, C8YRoles, C8YTenantOptionKey, C8YTenantOptionKeysCacheConfig, C8YZipOptions, type C8yCacheOptions, C8yNitroModuleOptions };
|
|
1
|
+
import { a as C8yCacheOptions, c as C8YAPIClientOptions, i as C8YRoles, n as C8YTenantOptionKey, o as C8YZipOptions, r as C8YTenantOptionKeysCacheConfig, s as C8YManifestOptions, t as C8yNitroModuleOptions } from "./index-B6HtYHU0.mjs";
|
|
2
|
+
export { C8YAPIClientOptions, C8YManifestOptions, C8YRoles, C8YTenantOptionKey, C8YTenantOptionKeysCacheConfig, C8YZipOptions, C8yCacheOptions, C8yNitroModuleOptions };
|
package/dist/types.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
package/dist/utils.d.mts
CHANGED
|
@@ -1,7 +1,293 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { useLogger } from "evlog/nitro/v3";
|
|
2
|
+
import { Client, ICredentials, ICurrentUser } from "@c8y/client";
|
|
3
|
+
import { EventHandler, H3Event } from "nitro/h3";
|
|
4
|
+
import { createError, createLogger } from "evlog";
|
|
5
|
+
import { ServerRequest } from "nitro/types";
|
|
6
|
+
import { C8YRoles, C8YTenantOptionKey } from "c8y-nitro/types";
|
|
7
|
+
|
|
8
|
+
//#region src/utils/client.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Creates a Cumulocity client authenticated with the current user's credentials.\
|
|
11
|
+
* Extracts credentials from the Authorization header of the current request.
|
|
12
|
+
* @param requestOrEvent - The H3Event or ServerRequest from the current request
|
|
13
|
+
* @returns A configured Cumulocity Client instance
|
|
14
|
+
* @example
|
|
15
|
+
* // In a request handler:
|
|
16
|
+
* const client = useUserClient(event)
|
|
17
|
+
* const { data } = await client.inventory.list()
|
|
18
|
+
*/
|
|
19
|
+
declare function useUserClient(requestOrEvent: ServerRequest | H3Event): Client;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a Cumulocity client for the tenant of the current user.\
|
|
22
|
+
* Uses the tenant's service user credentials rather than the user's own credentials.
|
|
23
|
+
* @param requestOrEvent - The H3Event or ServerRequest from the current request
|
|
24
|
+
* @returns A configured Cumulocity Client instance for the user's tenant
|
|
25
|
+
* @example
|
|
26
|
+
* // In a request handler:
|
|
27
|
+
* const tenantClient = await useUserTenantClient(event)
|
|
28
|
+
* const { data } = await tenantClient.inventory.list()
|
|
29
|
+
*/
|
|
30
|
+
declare function useUserTenantClient(requestOrEvent: ServerRequest | H3Event): Promise<Client>;
|
|
31
|
+
/**
|
|
32
|
+
* Creates Cumulocity clients for all tenants subscribed to this microservice.\
|
|
33
|
+
* Each client is authenticated with that tenant's service user credentials.\
|
|
34
|
+
* @returns Object mapping tenant IDs to their respective Client instances
|
|
35
|
+
* @example
|
|
36
|
+
* // Get clients for all subscribed tenants:
|
|
37
|
+
* const clients = await useSubscribedTenantClients()
|
|
38
|
+
* for (const [tenant, client] of Object.entries(clients)) {
|
|
39
|
+
* const { data } = await client.inventory.list()
|
|
40
|
+
* console.log(`Tenant ${tenant} has ${data.length} inventory items`)
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
declare function useSubscribedTenantClients(): Promise<Record<string, Client>>;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a Cumulocity client for the tenant where this microservice is deployed.\
|
|
46
|
+
* Uses the bootstrap tenant ID from runtime config to identify the deployed tenant.\
|
|
47
|
+
* @returns A configured Cumulocity Client instance for the deployed tenant
|
|
48
|
+
* @example
|
|
49
|
+
* // Get client for the tenant hosting this microservice:
|
|
50
|
+
* const client = await useDeployedTenantClient()
|
|
51
|
+
* const { data } = await client.application.list()
|
|
52
|
+
*/
|
|
53
|
+
declare function useDeployedTenantClient(): Promise<Client>;
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/utils/middleware.d.ts
|
|
56
|
+
type UserRole = keyof C8YRoles | (string & {});
|
|
57
|
+
/**
|
|
58
|
+
* Middleware to check if the current user has the required role.\
|
|
59
|
+
* If the user doesn't have the required role, throws a 403 Forbidden error.\
|
|
60
|
+
* Must be used within a request handler context.\
|
|
61
|
+
* @param role - Single role ID to check for
|
|
62
|
+
* @returns Event handler that validates user roles
|
|
63
|
+
* @example
|
|
64
|
+
* // Single role:
|
|
65
|
+
* export default defineHandler({
|
|
66
|
+
* middleware: [hasUserRequiredRole('ROLE_INVENTORY_ADMIN')],
|
|
67
|
+
* handler: async () => {
|
|
68
|
+
* return { message: 'You have access' }
|
|
69
|
+
* }
|
|
70
|
+
* })
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
declare function hasUserRequiredRole(role: UserRole): EventHandler;
|
|
74
|
+
/**
|
|
75
|
+
* Middleware to check if the current user has at least one of the required roles.\
|
|
76
|
+
* If the user doesn't have any of the required roles, throws a 403 Forbidden error.\
|
|
77
|
+
* Must be used within a request handler context.\
|
|
78
|
+
* @param roles - Array of role IDs to check for
|
|
79
|
+
* @returns Event handler that validates user roles
|
|
80
|
+
* @example
|
|
81
|
+
* // Multiple roles:
|
|
82
|
+
* export default defineHandler({
|
|
83
|
+
* middleware: [hasUserRequiredRole(['ROLE_INVENTORY_ADMIN', 'ROLE_DEVICE_CONTROL'])],
|
|
84
|
+
* handler: async () => {
|
|
85
|
+
* return { message: 'You have access' }
|
|
86
|
+
* }
|
|
87
|
+
* })
|
|
88
|
+
*/
|
|
89
|
+
declare function hasUserRequiredRole(roles: UserRole[]): EventHandler;
|
|
90
|
+
/**
|
|
91
|
+
* Middleware to check if the current user belongs to a specific allowed tenant.\
|
|
92
|
+
* If the user's tenant doesn't match, throws a 403 Forbidden error.\
|
|
93
|
+
* Must be used within a request handler context.\
|
|
94
|
+
* @param tenantId - Single tenant ID to allow
|
|
95
|
+
* @returns Event handler that validates user tenant
|
|
96
|
+
* @example
|
|
97
|
+
* // Single tenant:
|
|
98
|
+
* export default defineHandler({
|
|
99
|
+
* middleware: [isUserFromAllowedTenant('t123456')],
|
|
100
|
+
* handler: async () => {
|
|
101
|
+
* return { message: 'You have access' }
|
|
102
|
+
* }
|
|
103
|
+
* })
|
|
104
|
+
*
|
|
105
|
+
*/
|
|
106
|
+
declare function isUserFromAllowedTenant(tenantId: string): EventHandler;
|
|
107
|
+
/**
|
|
108
|
+
* Middleware to check if the current user belongs to one of the allowed tenants.\
|
|
109
|
+
* If the user's tenant doesn't match any of the allowed tenants, throws a 403 Forbidden error.\
|
|
110
|
+
* Must be used within a request handler context.\
|
|
111
|
+
* @param tenantIds - Array of tenant IDs to allow
|
|
112
|
+
* @returns Event handler that validates user tenant
|
|
113
|
+
* @example
|
|
114
|
+
* // Multiple tenants:
|
|
115
|
+
* export default defineHandler({
|
|
116
|
+
* middleware: [isUserFromAllowedTenant(['t123456', 't789012'])],
|
|
117
|
+
* handler: async () => {
|
|
118
|
+
* return { message: 'You have access' }
|
|
119
|
+
* }
|
|
120
|
+
* })
|
|
121
|
+
*/
|
|
122
|
+
declare function isUserFromAllowedTenant(tenantIds: string[]): EventHandler;
|
|
123
|
+
/**
|
|
124
|
+
* Middleware to check if the current user belongs to the deployed tenant.\
|
|
125
|
+
* The deployed tenant is where this microservice is hosted (C8Y_BOOTSTRAP_TENANT).\
|
|
126
|
+
* If the user's tenant doesn't match the deployed tenant, throws a 403 Forbidden error.\
|
|
127
|
+
* Must be used within a request handler context.\
|
|
128
|
+
* @returns Event handler that validates user is from deployed tenant
|
|
129
|
+
* @example
|
|
130
|
+
* // Only allow users from the deployed tenant:
|
|
131
|
+
* export default defineHandler({
|
|
132
|
+
* middleware: [isUserFromDeployedTenant()],
|
|
133
|
+
* handler: async () => {
|
|
134
|
+
* return { message: 'You have access' }
|
|
135
|
+
* }
|
|
136
|
+
* })
|
|
137
|
+
*/
|
|
138
|
+
declare function isUserFromDeployedTenant(): EventHandler;
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/utils/resources.d.ts
|
|
141
|
+
/**
|
|
142
|
+
* Fetches the current user from Cumulocity using credentials extracted from the current request's headers.
|
|
143
|
+
* This is a non-cached version - fetches fresh data on every call.
|
|
144
|
+
* @param requestOrEvent - The H3Event or ServerRequest from the current request
|
|
145
|
+
* @returns The current user object from Cumulocity
|
|
146
|
+
* @example
|
|
147
|
+
* // In a request handler:
|
|
148
|
+
* const user = await useUser(event)
|
|
149
|
+
* console.log(user.userName, user.email)
|
|
150
|
+
*/
|
|
151
|
+
declare function useUser(requestOrEvent: ServerRequest | H3Event): Promise<ICurrentUser>;
|
|
152
|
+
/**
|
|
153
|
+
* Fetches the roles of the current user from Cumulocity.
|
|
154
|
+
* Internally calls `useUser()` and extracts role IDs from the user object.
|
|
155
|
+
* This is a non-cached version - fetches fresh data on every call.
|
|
156
|
+
* @param requestOrEvent - The H3Event or ServerRequest from the current request
|
|
157
|
+
* @returns Array of role ID strings assigned to the current user
|
|
158
|
+
* @example
|
|
159
|
+
* // In a request handler:
|
|
160
|
+
* const roles = await useUserRoles(event)
|
|
161
|
+
* console.log(roles) // ['ROLE_INVENTORY_READ', 'ROLE_INVENTORY_ADMIN']
|
|
162
|
+
*/
|
|
163
|
+
declare function useUserRoles(requestOrEvent: ServerRequest | H3Event): Promise<string[]>;
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/utils/credentials.d.ts
|
|
166
|
+
/**
|
|
167
|
+
* Fetches credentials for all tenants subscribed to this microservice.\
|
|
168
|
+
* Uses bootstrap credentials from runtime config to query the microservice subscriptions API.\
|
|
169
|
+
* Results are cached based on the configured TTL (default: 10 minutes).\
|
|
170
|
+
* @returns Object mapping tenant IDs to their respective credentials
|
|
171
|
+
* @config Cache TTL can be configured via:
|
|
172
|
+
* - `c8y.cache.credentialsTTL` in the Nitro config (value in seconds)
|
|
173
|
+
* - `NITRO_C8Y_CACHE_CREDENTIALS_TTL` environment variable
|
|
174
|
+
* @example
|
|
175
|
+
* // Get all subscribed tenant credentials:
|
|
176
|
+
* const credentials = await useSubscribedTenantCredentials()
|
|
177
|
+
* console.log(Object.keys(credentials)) // ['t12345', 't67890']
|
|
178
|
+
*
|
|
179
|
+
* // Access specific tenant:
|
|
180
|
+
* const tenant1Creds = credentials['t12345']
|
|
181
|
+
*
|
|
182
|
+
* // Invalidate cache:
|
|
183
|
+
* await useSubscribedTenantCredentials.invalidate()
|
|
184
|
+
*
|
|
185
|
+
* // Force refresh:
|
|
186
|
+
* const freshCreds = await useSubscribedTenantCredentials.refresh()
|
|
187
|
+
*/
|
|
188
|
+
declare const useSubscribedTenantCredentials: (() => Promise<Record<string, ICredentials>>) & {
|
|
189
|
+
invalidate: () => Promise<void>;
|
|
190
|
+
refresh: () => Promise<Record<string, ICredentials>>;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Fetches credentials for the tenant where this microservice is deployed.\
|
|
194
|
+
* Uses the C8Y_BOOTSTRAP_TENANT environment variable to identify the deployed tenant.\
|
|
195
|
+
* Returns credentials from the subscribed tenant credentials cache (cached based on configured TTL, default: 10 minutes).
|
|
196
|
+
* @returns Credentials for the deployed tenant
|
|
197
|
+
* @throws {HTTPError} If no credentials found for the deployed tenant
|
|
198
|
+
* @example
|
|
199
|
+
* // Get deployed tenant credentials:
|
|
200
|
+
* const creds = await useDeployedTenantCredentials()
|
|
201
|
+
* console.log(creds.tenant, creds.user)
|
|
202
|
+
*
|
|
203
|
+
* // Invalidate cache:
|
|
204
|
+
* await useDeployedTenantCredentials.invalidate()
|
|
205
|
+
*
|
|
206
|
+
* // Force refresh:
|
|
207
|
+
* const freshCreds = await useDeployedTenantCredentials.refresh()
|
|
208
|
+
* @note This function is not cached separately. It uses the cache of `useSubscribedTenantCredentials()`. Invalidating or refreshing one will refresh `useDeployedTenantCredentials()`s cache.
|
|
209
|
+
*/
|
|
210
|
+
declare const useDeployedTenantCredentials: (() => Promise<ICredentials>) & {
|
|
211
|
+
invalidate: () => Promise<void>;
|
|
212
|
+
refresh: () => Promise<ICredentials>;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Fetches credentials for the tenant of the current user making the request.\
|
|
216
|
+
* Extracts the user's tenant ID from the request headers and returns corresponding credentials.\
|
|
217
|
+
* Results are cached in the request context for subsequent calls within the same request.
|
|
218
|
+
* @param requestOrEvent - The H3Event or ServerRequest from the current request
|
|
219
|
+
* @returns Credentials for the user's tenant
|
|
220
|
+
* @throws {HTTPError} If no subscribed tenant credentials found for the user's tenant
|
|
221
|
+
* @example
|
|
222
|
+
* // In a request handler:
|
|
223
|
+
* const userCreds = await useUserTenantCredentials(event)
|
|
224
|
+
* console.log(userCreds.tenant, userCreds.user)
|
|
225
|
+
*
|
|
226
|
+
* // Credentials are automatically cached for the request duration
|
|
227
|
+
* const sameCreds = await useUserTenantCredentials(event) // Uses cached value
|
|
228
|
+
*/
|
|
229
|
+
declare function useUserTenantCredentials(requestOrEvent: ServerRequest | H3Event): Promise<ICredentials>;
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/utils/tenantOptions.d.ts
|
|
232
|
+
/**
|
|
233
|
+
* Fetches a tenant option value by key.\
|
|
234
|
+
* Uses the deployed tenant's service user credentials to access the Options API.\
|
|
235
|
+
* Results are cached based on the configured TTL (default: 10 minutes).
|
|
236
|
+
*
|
|
237
|
+
* @param key - The tenant option key to fetch (as defined in `manifest.settings`)
|
|
238
|
+
* @returns The option value as a string
|
|
239
|
+
*
|
|
240
|
+
* @config Cache TTL can be configured via:
|
|
241
|
+
* - `c8y.cache.defaultTenantOptionsTTL` — Default TTL for all keys (in seconds)
|
|
242
|
+
* - `c8y.cache.tenantOptions` — Per-key TTL overrides
|
|
243
|
+
* - `NITRO_C8Y_DEFAULT_TENANT_OPTIONS_TTL` — Environment variable for default TTL
|
|
244
|
+
*
|
|
245
|
+
* @note For encrypted options (keys starting with `credentials.`), the value is automatically
|
|
246
|
+
* decrypted by Cumulocity if this microservice is the owner of the option (category matches
|
|
247
|
+
* the microservice's settingsCategory/contextPath/name). The `credentials.` prefix is
|
|
248
|
+
* automatically stripped when calling the API.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* // Fetch a tenant option:
|
|
252
|
+
* const value = await useTenantOption('myOption')
|
|
253
|
+
*
|
|
254
|
+
* // Fetch an encrypted secret:
|
|
255
|
+
* const secret = await useTenantOption('credentials.apiKey')
|
|
256
|
+
*
|
|
257
|
+
* // Invalidate cache for a specific key:
|
|
258
|
+
* await useTenantOption.invalidate('myOption')
|
|
259
|
+
*
|
|
260
|
+
* // Force refresh a specific key:
|
|
261
|
+
* const fresh = await useTenantOption.refresh('myOption')
|
|
262
|
+
*
|
|
263
|
+
* // Invalidate all tenant option caches:
|
|
264
|
+
* await useTenantOption.invalidateAll()
|
|
265
|
+
*
|
|
266
|
+
* // Refresh all tenant options:
|
|
267
|
+
* const all = await useTenantOption.refreshAll()
|
|
268
|
+
*/
|
|
269
|
+
declare const useTenantOption: ((key: C8YTenantOptionKey) => Promise<string | undefined>) & {
|
|
270
|
+
/**
|
|
271
|
+
* Invalidate the cache for a specific tenant option key.
|
|
272
|
+
* @param key - The tenant option key to invalidate
|
|
273
|
+
*/
|
|
274
|
+
invalidate: (key: C8YTenantOptionKey) => Promise<void>;
|
|
275
|
+
/**
|
|
276
|
+
* Force refresh a specific tenant option key (invalidates and re-fetches).
|
|
277
|
+
* @param key - The tenant option key to refresh
|
|
278
|
+
*/
|
|
279
|
+
refresh: (key: C8YTenantOptionKey) => Promise<string | undefined>;
|
|
280
|
+
/**
|
|
281
|
+
* Invalidate all tenant option caches that have been accessed.
|
|
282
|
+
* Only invalidates keys that have been fetched at least once.
|
|
283
|
+
*/
|
|
284
|
+
invalidateAll: () => Promise<void>;
|
|
285
|
+
/**
|
|
286
|
+
* Refresh all tenant options that have been accessed.
|
|
287
|
+
* Only refreshes keys that have been fetched at least once.
|
|
288
|
+
* @returns Object mapping keys to their refreshed values
|
|
289
|
+
*/
|
|
290
|
+
refreshAll: () => Promise<Record<string, string | undefined>>;
|
|
291
|
+
};
|
|
292
|
+
//#endregion
|
|
7
293
|
export { createError, createLogger, hasUserRequiredRole, isUserFromAllowedTenant, isUserFromDeployedTenant, useDeployedTenantClient, useDeployedTenantCredentials, useLogger, useSubscribedTenantClients, useSubscribedTenantCredentials, useTenantOption, useUser, useUserClient, useUserRoles, useUserTenantClient, useUserTenantCredentials };
|