@qnsp/tenant-sdk 0.0.1

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.
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @qnsp/tenant-sdk@0.0.1 build /Volumes/ProjectQNSP/QNSP/packages/tenant-sdk
4
+ > tsc --project tsconfig.build.json
5
+
@@ -0,0 +1,6 @@
1
+
2
+ 
3
+ > @qnsp/tenant-sdk@0.0.1 lint /Volumes/ProjectQNSP/QNSP/packages/tenant-sdk
4
+ > biome check .
5
+
6
+ Checked 8 files in 9ms. No fixes applied.
@@ -0,0 +1,65 @@
1
+
2
+ 
3
+ > @qnsp/tenant-sdk@0.0.1 test /Volumes/ProjectQNSP/QNSP/packages/tenant-sdk
4
+ > vitest run
5
+
6
+ [?25l
7
+ RUN v4.0.13 /Volumes/ProjectQNSP/QNSP/packages/tenant-sdk
8
+
9
+ [?2026h
10
+ ❯ src/index.test.ts [queued]
11
+
12
+ Test Files 0 passed (1)
13
+ Tests 0 passed (0)
14
+ Start at 02:56:46
15
+ Duration 0ms
16
+ [?2026l[?2026h
17
+ ❯ src/index.test.ts 0/9
18
+
19
+ Test Files 0 passed (1)
20
+ Tests 0 passed (9)
21
+ Start at 02:56:46
22
+ Duration 222ms
23
+ [?2026l[?2026h
24
+ ❯ src/index.test.ts 1/9
25
+
26
+ Test Files 0 passed (1)
27
+ Tests 1 passed (9)
28
+ Start at 02:56:46
29
+ Duration 324ms
30
+ [?2026l[?2026h
31
+ ❯ src/index.test.ts 7/9
32
+
33
+ Test Files 0 passed (1)
34
+ Tests 7 passed (9)
35
+ Start at 02:56:46
36
+ Duration 932ms
37
+ [?2026l[?2026h
38
+ ❯ src/index.test.ts 8/9
39
+
40
+ Test Files 0 passed (1)
41
+ Tests 8 passed (9)
42
+ Start at 02:56:46
43
+ Duration 1.24s
44
+ [?2026l ✓ src/index.test.ts (9 tests) 1044ms
45
+ ✓ TenantClient Security Tests (9)
46
+ ✓ HTTPS Enforcement (2)
47
+ ✓ should reject HTTP URLs in production 1ms
48
+ ✓ should allow HTTP localhost in development 0ms
49
+ ✓ Input Validation (4)
50
+ ✓ should reject invalid UUIDs 1ms
51
+ ✓ should reject SQL injection in tenantId 0ms
52
+ ✓ should reject path traversal in tenantId 0ms
53
+ ✓ should reject XSS attempts in tenantId 0ms
54
+ ✓ Error Message Sanitization (1)
55
+ ✓ should not expose sensitive data in error messages 7ms
56
+ ✓ Rate Limiting (2)
57
+ ✓ should retry on 429 with Retry-After header 1003ms
58
+ ✓ should fail after max retries 32ms
59
+
60
+ Test Files 1 passed (1)
61
+ Tests 9 passed (9)
62
+ Start at 02:56:46
63
+ Duration 1.35s (transform 120ms, setup 0ms, collect 229ms, tests 1.04s, environment 0ms, prepare 2ms)
64
+
65
+ [?25h
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @qnsp/tenant-sdk@0.0.1 typecheck /Volumes/ProjectQNSP/QNSP/packages/tenant-sdk
4
+ > tsc --project tsconfig.json --noEmit
5
+
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # @qnsp/tenant-sdk
2
+
3
+ TypeScript client for the QNSP Tenant service. Manages tenant lifecycle (create, update, suspend),
4
+ domains, compliance tags, metadata, and PQC security envelopes.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pnpm add @qnsp/tenant-sdk
10
+ ```
11
+
12
+ ## Authentication
13
+
14
+ Provide a tenant-scoped **service token** via `apiKey`. Requests require PQC security envelopes and
15
+ signatures generated by the control plane; the SDK forwards your payloads but does not sign them.
16
+
17
+ ```ts
18
+ import { TenantClient } from "@qnsp/tenant-sdk";
19
+
20
+ const tenants = new TenantClient({
21
+ baseUrl: "https://tenant.qnsp.cuilabs.io",
22
+ apiKey: process.env.QNSP_SERVICE_TOKEN!,
23
+ });
24
+ ```
25
+
26
+ ## Tier requirements
27
+
28
+ Tenant management APIs are available on every tier. Higher tiers add more tenant seats or compliance
29
+ features, but there are no SDK-side restrictions.
30
+
31
+ ## Usage example
32
+
33
+ ```ts
34
+ import { TenantClient } from "@qnsp/tenant-sdk";
35
+
36
+ const tenants = new TenantClient({
37
+ baseUrl: "https://tenant.qnsp.cuilabs.io",
38
+ apiKey: process.env.QNSP_SERVICE_TOKEN!,
39
+ });
40
+
41
+ const created = await tenants.createTenant({
42
+ name: "CUI Labs",
43
+ slug: "cui-labs",
44
+ plan: "dev-pro",
45
+ region: "global",
46
+ security: {
47
+ controlPlaneTokenSha256: "...",
48
+ pqcSignatures: [],
49
+ hardwareProvider: null,
50
+ attestationStatus: null,
51
+ attestationProof: null,
52
+ },
53
+ });
54
+
55
+ const list = await tenants.listTenants({ limit: 25 });
56
+ ```
57
+
58
+ ## Telemetry
59
+
60
+ Set `telemetry` (or pass config to `createTenantClientTelemetry`) to emit OTLP metrics for every API
61
+ call—latency, HTTP code, retries—powering the tenant dashboards described in
62
+ `docs/observability/portal-dashboards.md`.
63
+
64
+ ## Related documentation
65
+
66
+ - [Developer onboarding guide](../../docs/guides/developer-onboarding.md#sdk-quick-links)
67
+ - [SDK inventory](../../docs/technical/SDK-INVENTORY.md)
68
+ - [Tier limits](../shared-kernel/src/tier-limits.ts)
69
+
70
+ © 2025 QNSP - CUI LABS, Singapore
@@ -0,0 +1,116 @@
1
+ import type { TenantClientTelemetry, TenantClientTelemetryConfig } from "./observability.js";
2
+ /**
3
+ * @qnsp/tenant-sdk
4
+ *
5
+ * TypeScript SDK client for the QNSP tenant-service API.
6
+ * Provides a high-level interface for tenant lifecycle and subscription management.
7
+ */
8
+ export interface TenantClientConfig {
9
+ readonly baseUrl: string;
10
+ readonly apiKey?: string;
11
+ readonly timeoutMs?: number;
12
+ readonly telemetry?: TenantClientTelemetry | TenantClientTelemetryConfig;
13
+ readonly maxRetries?: number;
14
+ readonly retryDelayMs?: number;
15
+ }
16
+ export type TenantStatus = "active" | "suspended" | "pending" | "deleted";
17
+ export interface TenantSecurityEnvelope {
18
+ readonly controlPlaneTokenSha256: string | null;
19
+ readonly pqcSignatures: readonly {
20
+ readonly provider: string;
21
+ readonly algorithm: string;
22
+ readonly value: string;
23
+ readonly publicKey: string;
24
+ }[];
25
+ readonly hardwareProvider: string | null;
26
+ readonly attestationStatus: string | null;
27
+ readonly attestationProof: string | null;
28
+ }
29
+ export interface TenantSignature {
30
+ readonly provider: string;
31
+ readonly algorithm: string;
32
+ readonly value: string;
33
+ readonly publicKey: string;
34
+ }
35
+ export interface TenantDomain {
36
+ readonly id: string;
37
+ readonly domain: string;
38
+ readonly verified: boolean;
39
+ readonly createdAt: string;
40
+ readonly updatedAt: string;
41
+ }
42
+ export interface Tenant {
43
+ readonly id: string;
44
+ readonly name: string;
45
+ readonly slug: string;
46
+ readonly status: TenantStatus;
47
+ readonly plan: string;
48
+ readonly region: string;
49
+ readonly complianceTags: readonly string[];
50
+ readonly metadata: Record<string, unknown>;
51
+ readonly security: TenantSecurityEnvelope;
52
+ readonly domains: readonly TenantDomain[];
53
+ readonly createdAt: string;
54
+ readonly updatedAt: string;
55
+ }
56
+ export interface CreateTenantRequest {
57
+ readonly name: string;
58
+ readonly slug: string;
59
+ readonly plan?: string;
60
+ readonly region?: string;
61
+ readonly complianceTags?: readonly string[];
62
+ readonly metadata?: Record<string, unknown>;
63
+ readonly domains?: readonly {
64
+ readonly domain: string;
65
+ readonly verified?: boolean;
66
+ }[];
67
+ readonly security: TenantSecurityEnvelope;
68
+ readonly signature?: TenantSignature;
69
+ }
70
+ export interface UpdateTenantRequest {
71
+ readonly plan?: string;
72
+ readonly status?: TenantStatus;
73
+ readonly complianceTags?: readonly string[];
74
+ readonly metadata?: Record<string, unknown>;
75
+ readonly security: TenantSecurityEnvelope;
76
+ readonly signature?: TenantSignature;
77
+ }
78
+ export interface ListTenantsResponse {
79
+ readonly items: readonly Tenant[];
80
+ readonly nextCursor: string | null;
81
+ }
82
+ export declare class TenantClient {
83
+ private readonly config;
84
+ private readonly telemetry;
85
+ private readonly targetService;
86
+ constructor(config: TenantClientConfig);
87
+ private request;
88
+ private requestWithRetry;
89
+ private recordTelemetryEvent;
90
+ /**
91
+ * Create a new tenant.
92
+ * Requires PQC-signed security envelope and optional signature.
93
+ */
94
+ createTenant(request: CreateTenantRequest): Promise<Tenant>;
95
+ /**
96
+ * Update a tenant's plan, status, compliance tags, or metadata.
97
+ * Requires PQC-signed security envelope and optional signature.
98
+ */
99
+ updateTenant(id: string, request: UpdateTenantRequest): Promise<Tenant>;
100
+ /**
101
+ * Get a tenant by ID.
102
+ * Returns the tenant with domains and security envelope.
103
+ */
104
+ getTenant(id: string): Promise<Tenant>;
105
+ /**
106
+ * List tenants with cursor-based pagination.
107
+ * Returns a list of tenants and an optional next cursor for pagination.
108
+ */
109
+ listTenants(options?: {
110
+ readonly limit?: number;
111
+ readonly cursor?: string;
112
+ }): Promise<ListTenantsResponse>;
113
+ }
114
+ export * from "./observability.js";
115
+ export * from "./validation.js";
116
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,207 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { createTenantClientTelemetry, isTenantClientTelemetry } from "./observability.js";
3
+ import { validateUUID } from "./validation.js";
4
+ export class TenantClient {
5
+ config;
6
+ telemetry;
7
+ targetService;
8
+ constructor(config) {
9
+ const baseUrl = config.baseUrl.replace(/\/$/, "");
10
+ // Enforce HTTPS in production (allow HTTP only for localhost in development)
11
+ if (!baseUrl.startsWith("https://")) {
12
+ const isLocalhost = baseUrl.startsWith("http://localhost") || baseUrl.startsWith("http://127.0.0.1");
13
+ const isDevelopment = process.env["NODE_ENV"] === "development" || process.env["NODE_ENV"] === "test";
14
+ if (!isLocalhost || !isDevelopment) {
15
+ throw new Error("baseUrl must use HTTPS in production. HTTP is only allowed for localhost in development.");
16
+ }
17
+ }
18
+ this.config = {
19
+ baseUrl,
20
+ apiKey: config.apiKey ?? "",
21
+ timeoutMs: config.timeoutMs ?? 30_000,
22
+ maxRetries: config.maxRetries ?? 3,
23
+ retryDelayMs: config.retryDelayMs ?? 1_000,
24
+ };
25
+ this.telemetry = config.telemetry
26
+ ? isTenantClientTelemetry(config.telemetry)
27
+ ? config.telemetry
28
+ : createTenantClientTelemetry(config.telemetry)
29
+ : null;
30
+ try {
31
+ this.targetService = new URL(this.config.baseUrl).host;
32
+ }
33
+ catch {
34
+ this.targetService = "tenant-service";
35
+ }
36
+ }
37
+ async request(method, path, options) {
38
+ return this.requestWithRetry(method, path, options, 0);
39
+ }
40
+ async requestWithRetry(method, path, options, attempt) {
41
+ const url = `${this.config.baseUrl}${path}`;
42
+ const headers = {
43
+ "Content-Type": "application/json",
44
+ ...options?.headers,
45
+ };
46
+ if (this.config.apiKey) {
47
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
48
+ }
49
+ const controller = new AbortController();
50
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs);
51
+ const signal = options?.signal ?? controller.signal;
52
+ const route = options?.telemetryRoute ?? new URL(path, this.config.baseUrl).pathname;
53
+ const target = options?.telemetryTarget ?? this.targetService;
54
+ const start = performance.now();
55
+ let status = "ok";
56
+ let httpStatus;
57
+ let errorMessage;
58
+ try {
59
+ const init = {
60
+ method,
61
+ headers,
62
+ signal,
63
+ };
64
+ if (options?.body !== undefined) {
65
+ init.body = JSON.stringify(options.body);
66
+ }
67
+ const response = await fetch(url, init);
68
+ clearTimeout(timeoutId);
69
+ httpStatus = response.status;
70
+ // Handle rate limiting (429) with retry logic
71
+ if (response.status === 429) {
72
+ if (attempt < this.config.maxRetries) {
73
+ const retryAfterHeader = response.headers.get("Retry-After");
74
+ let delayMs = this.config.retryDelayMs;
75
+ if (retryAfterHeader) {
76
+ const retryAfterSeconds = Number.parseInt(retryAfterHeader, 10);
77
+ if (!Number.isNaN(retryAfterSeconds) && retryAfterSeconds > 0) {
78
+ delayMs = retryAfterSeconds * 1_000;
79
+ }
80
+ }
81
+ else {
82
+ // Exponential backoff: 2^attempt * baseDelay, capped at 30 seconds
83
+ delayMs = Math.min(2 ** attempt * this.config.retryDelayMs, 30_000);
84
+ }
85
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
86
+ return this.requestWithRetry(method, path, options, attempt + 1);
87
+ }
88
+ status = "error";
89
+ errorMessage = `HTTP ${response.status}`;
90
+ throw new Error(`Tenant API error: Rate limit exceeded after ${this.config.maxRetries} retries`);
91
+ }
92
+ if (!response.ok) {
93
+ status = "error";
94
+ // Sanitize error message to prevent information disclosure
95
+ // Don't include full response text in error to avoid leaking sensitive data
96
+ errorMessage = `HTTP ${response.status}`;
97
+ throw new Error(`Tenant API error: ${response.status} ${response.statusText}`);
98
+ }
99
+ if (response.status === 204) {
100
+ return undefined;
101
+ }
102
+ return (await response.json());
103
+ }
104
+ catch (error) {
105
+ clearTimeout(timeoutId);
106
+ status = "error";
107
+ if (!errorMessage && error instanceof Error) {
108
+ errorMessage = error.message;
109
+ }
110
+ if (error instanceof Error && error.name === "AbortError") {
111
+ errorMessage = `timeout after ${this.config.timeoutMs}ms`;
112
+ throw new Error(`Request timeout after ${this.config.timeoutMs}ms`);
113
+ }
114
+ throw error;
115
+ }
116
+ finally {
117
+ const durationMs = performance.now() - start;
118
+ const event = {
119
+ operation: options?.operation ?? `${method} ${route}`,
120
+ method,
121
+ route,
122
+ target,
123
+ status,
124
+ durationMs,
125
+ ...(typeof httpStatus === "number" ? { httpStatus } : {}),
126
+ ...(status === "error" && errorMessage ? { error: errorMessage } : {}),
127
+ };
128
+ this.recordTelemetryEvent(event);
129
+ }
130
+ }
131
+ recordTelemetryEvent(event) {
132
+ if (!this.telemetry) {
133
+ return;
134
+ }
135
+ this.telemetry.record(event);
136
+ }
137
+ /**
138
+ * Create a new tenant.
139
+ * Requires PQC-signed security envelope and optional signature.
140
+ */
141
+ async createTenant(request) {
142
+ // Validation is handled by the service, but we validate format here for early feedback
143
+ return this.request("POST", "/tenant/v1/tenants", {
144
+ body: {
145
+ name: request.name,
146
+ slug: request.slug,
147
+ ...(request.plan !== undefined ? { plan: request.plan } : {}),
148
+ ...(request.region !== undefined ? { region: request.region } : {}),
149
+ ...(request.complianceTags !== undefined ? { complianceTags: request.complianceTags } : {}),
150
+ ...(request.metadata !== undefined ? { metadata: request.metadata } : {}),
151
+ ...(request.domains !== undefined ? { domains: request.domains } : {}),
152
+ security: request.security,
153
+ ...(request.signature !== undefined ? { signature: request.signature } : {}),
154
+ },
155
+ operation: "createTenant",
156
+ });
157
+ }
158
+ /**
159
+ * Update a tenant's plan, status, compliance tags, or metadata.
160
+ * Requires PQC-signed security envelope and optional signature.
161
+ */
162
+ async updateTenant(id, request) {
163
+ validateUUID(id, "id");
164
+ return this.request("PATCH", `/tenant/v1/tenants/${id}`, {
165
+ body: {
166
+ ...(request.plan !== undefined ? { plan: request.plan } : {}),
167
+ ...(request.status !== undefined ? { status: request.status } : {}),
168
+ ...(request.complianceTags !== undefined ? { complianceTags: request.complianceTags } : {}),
169
+ ...(request.metadata !== undefined ? { metadata: request.metadata } : {}),
170
+ security: request.security,
171
+ ...(request.signature !== undefined ? { signature: request.signature } : {}),
172
+ },
173
+ operation: "updateTenant",
174
+ });
175
+ }
176
+ /**
177
+ * Get a tenant by ID.
178
+ * Returns the tenant with domains and security envelope.
179
+ */
180
+ async getTenant(id) {
181
+ validateUUID(id, "id");
182
+ return this.request("GET", `/tenant/v1/tenants/${id}`, {
183
+ operation: "getTenant",
184
+ });
185
+ }
186
+ /**
187
+ * List tenants with cursor-based pagination.
188
+ * Returns a list of tenants and an optional next cursor for pagination.
189
+ */
190
+ async listTenants(options) {
191
+ const params = new URLSearchParams();
192
+ if (options?.limit !== undefined) {
193
+ params.set("limit", String(options.limit));
194
+ }
195
+ if (options?.cursor !== undefined) {
196
+ params.set("cursor", options.cursor);
197
+ }
198
+ const queryString = params.toString();
199
+ const path = queryString ? `/tenant/v1/tenants?${queryString}` : "/tenant/v1/tenants";
200
+ return this.request("GET", path, {
201
+ operation: "listTenants",
202
+ });
203
+ }
204
+ }
205
+ export * from "./observability.js";
206
+ export * from "./validation.js";
207
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAO9C,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA6G/C,MAAM,OAAO,YAAY;IACP,MAAM,CAA6B;IACnC,SAAS,CAA+B;IACxC,aAAa,CAAS;IAEvC,YAAY,MAA0B;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAElD,6EAA6E;QAC7E,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,MAAM,WAAW,GAChB,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;YAClF,MAAM,aAAa,GAClB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,MAAM,CAAC;YACjF,IAAI,CAAC,WAAW,IAAI,CAAC,aAAa,EAAE,CAAC;gBACpC,MAAM,IAAI,KAAK,CACd,0FAA0F,CAC1F,CAAC;YACH,CAAC;QACF,CAAC;QAED,IAAI,CAAC,MAAM,GAAG;YACb,OAAO;YACP,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,MAAM;YACrC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;YAClC,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,KAAK;SAC1C,CAAC;QAEF,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS;YAChC,CAAC,CAAC,uBAAuB,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC1C,CAAC,CAAC,MAAM,CAAC,SAAS;gBAClB,CAAC,CAAC,2BAA2B,CAAC,MAAM,CAAC,SAAS,CAAC;YAChD,CAAC,CAAC,IAAI,CAAC;QAER,IAAI,CAAC;YACJ,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACR,IAAI,CAAC,aAAa,GAAG,gBAAgB,CAAC;QACvC,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,OAAwB;QAC9E,OAAO,IAAI,CAAC,gBAAgB,CAAI,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC7B,MAAc,EACd,IAAY,EACZ,OAAmC,EACnC,OAAe;QAEf,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QAC5C,MAAM,OAAO,GAA2B;YACvC,cAAc,EAAE,kBAAkB;YAClC,GAAG,OAAO,EAAE,OAAO;SACnB,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC3D,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC;QACpD,MAAM,KAAK,GAAG,OAAO,EAAE,cAAc,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;QACrF,MAAM,MAAM,GAAG,OAAO,EAAE,eAAe,IAAI,IAAI,CAAC,aAAa,CAAC;QAC9D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,MAAM,GAAmB,IAAI,CAAC;QAClC,IAAI,UAA8B,CAAC;QACnC,IAAI,YAAgC,CAAC;QAErC,IAAI,CAAC;YACJ,MAAM,IAAI,GAAgB;gBACzB,MAAM;gBACN,OAAO;gBACP,MAAM;aACN,CAAC;YAEF,IAAI,OAAO,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1C,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAExC,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;YAE7B,8CAA8C;YAC9C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7B,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;oBACtC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;oBAC7D,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;oBAEvC,IAAI,gBAAgB,EAAE,CAAC;wBACtB,MAAM,iBAAiB,GAAG,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;wBAChE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;4BAC/D,OAAO,GAAG,iBAAiB,GAAG,KAAK,CAAC;wBACrC,CAAC;oBACF,CAAC;yBAAM,CAAC;wBACP,mEAAmE;wBACnE,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;oBACrE,CAAC;oBAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;oBAC7D,OAAO,IAAI,CAAC,gBAAgB,CAAI,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;gBACrE,CAAC;gBAED,MAAM,GAAG,OAAO,CAAC;gBACjB,YAAY,GAAG,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CACd,+CAA+C,IAAI,CAAC,MAAM,CAAC,UAAU,UAAU,CAC/E,CAAC;YACH,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,MAAM,GAAG,OAAO,CAAC;gBACjB,2DAA2D;gBAC3D,4EAA4E;gBAC5E,YAAY,GAAG,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAChF,CAAC;YAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7B,OAAO,SAAc,CAAC;YACvB,CAAC;YAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,MAAM,GAAG,OAAO,CAAC;YACjB,IAAI,CAAC,YAAY,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC7C,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;YAC9B,CAAC;YACD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC3D,YAAY,GAAG,iBAAiB,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC;gBAC1D,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;YACrE,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC;gBAAS,CAAC;YACV,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAC7C,MAAM,KAAK,GAA+B;gBACzC,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,GAAG,MAAM,IAAI,KAAK,EAAE;gBACrD,MAAM;gBACN,KAAK;gBACL,MAAM;gBACN,MAAM;gBACN,UAAU;gBACV,GAAG,CAAC,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzD,GAAG,CAAC,MAAM,KAAK,OAAO,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtE,CAAC;YACF,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;IACF,CAAC;IAEO,oBAAoB,CAAC,KAAiC;QAC7D,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO;QACR,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,OAA4B;QAC9C,uFAAuF;QACvF,OAAO,IAAI,CAAC,OAAO,CAAS,MAAM,EAAE,oBAAoB,EAAE;YACzD,IAAI,EAAE;gBACL,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7D,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3F,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzE,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtE,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5E;YACD,SAAS,EAAE,cAAc;SACzB,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,EAAU,EAAE,OAA4B;QAC1D,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAEvB,OAAO,IAAI,CAAC,OAAO,CAAS,OAAO,EAAE,sBAAsB,EAAE,EAAE,EAAE;YAChE,IAAI,EAAE;gBACL,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7D,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3F,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzE,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5E;YACD,SAAS,EAAE,cAAc;SACzB,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS,CAAC,EAAU;QACzB,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAEvB,OAAO,IAAI,CAAC,OAAO,CAAS,KAAK,EAAE,sBAAsB,EAAE,EAAE,EAAE;YAC9D,SAAS,EAAE,WAAW;SACtB,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,OAGjB;QACA,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,OAAO,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,OAAO,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;QAEtF,OAAO,IAAI,CAAC,OAAO,CAAsB,KAAK,EAAE,IAAI,EAAE;YACrD,SAAS,EAAE,aAAa;SACxB,CAAC,CAAC;IACJ,CAAC;CACD;AAED,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { MetricReader } from "@opentelemetry/sdk-metrics";
2
+ export interface TenantClientTelemetryConfig {
3
+ readonly serviceName: string;
4
+ readonly serviceVersion?: string;
5
+ readonly environment?: string;
6
+ readonly otlpEndpoint?: string;
7
+ readonly metricsIntervalMs?: number;
8
+ readonly metricsTimeoutMs?: number;
9
+ readonly exporterFactory?: () => MetricReader;
10
+ }
11
+ export interface TenantClientTelemetryEvent {
12
+ readonly operation: string;
13
+ readonly method: string;
14
+ readonly route: string;
15
+ readonly status: "ok" | "error";
16
+ readonly durationMs: number;
17
+ readonly httpStatus?: number;
18
+ readonly target?: string;
19
+ readonly error?: string;
20
+ }
21
+ export interface TenantClientTelemetry {
22
+ record(event: TenantClientTelemetryEvent): void;
23
+ }
24
+ export declare function createTenantClientTelemetry(config: TenantClientTelemetryConfig): TenantClientTelemetry;
25
+ export declare function isTenantClientTelemetry(value: TenantClientTelemetry | TenantClientTelemetryConfig): value is TenantClientTelemetry;
26
+ //# sourceMappingURL=observability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAS/D,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,YAAY,CAAC;CAC9C;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACrC,MAAM,CAAC,KAAK,EAAE,0BAA0B,GAAG,IAAI,CAAC;CAChD;AAED,wBAAgB,2BAA2B,CAC1C,MAAM,EAAE,2BAA2B,GACjC,qBAAqB,CAsEvB;AAED,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,qBAAqB,GAAG,2BAA2B,GACxD,KAAK,IAAI,qBAAqB,CAEhC"}
@@ -0,0 +1,66 @@
1
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
2
+ import { ConsoleMetricExporter, createCounter, createHistogram, createMeterProvider, PeriodicExportingMetricReader, } from "@qnsp/observability";
3
+ export function createTenantClientTelemetry(config) {
4
+ const interval = config.metricsIntervalMs ?? 60_000;
5
+ const timeout = config.metricsTimeoutMs ?? 15_000;
6
+ const readers = [];
7
+ if (typeof config.exporterFactory === "function") {
8
+ readers.push(config.exporterFactory());
9
+ }
10
+ else if (config.otlpEndpoint) {
11
+ readers.push(new PeriodicExportingMetricReader({
12
+ exporter: new OTLPMetricExporter({
13
+ url: config.otlpEndpoint,
14
+ }),
15
+ exportIntervalMillis: interval,
16
+ exportTimeoutMillis: timeout,
17
+ }));
18
+ }
19
+ else if (process.env["NODE_ENV"] !== "test") {
20
+ readers.push(new PeriodicExportingMetricReader({
21
+ exporter: new ConsoleMetricExporter(),
22
+ exportIntervalMillis: interval,
23
+ exportTimeoutMillis: timeout,
24
+ }));
25
+ }
26
+ const provider = createMeterProvider({
27
+ serviceName: config.serviceName,
28
+ serviceVersion: config.serviceVersion ?? "0.0.0",
29
+ environment: config.environment ?? process.env["NODE_ENV"] ?? "development",
30
+ }, readers);
31
+ const requestCounter = createCounter(provider, "tenant_sdk_requests_total", {
32
+ description: "Count of Tenant SDK HTTP requests",
33
+ });
34
+ const failureCounter = createCounter(provider, "tenant_sdk_request_failures_total", {
35
+ description: "Count of failed Tenant SDK HTTP requests",
36
+ });
37
+ const durationHistogram = createHistogram(provider, "tenant_sdk_request_duration_ms", {
38
+ description: "Latency of Tenant SDK HTTP requests",
39
+ unit: "ms",
40
+ });
41
+ return {
42
+ record(event) {
43
+ const baseAttributes = {
44
+ service: config.serviceName,
45
+ operation: event.operation,
46
+ method: event.method,
47
+ route: event.route,
48
+ target: event.target ?? event.route,
49
+ status: event.status,
50
+ ...(event.httpStatus ? { http_status: event.httpStatus } : {}),
51
+ };
52
+ requestCounter.add(1, baseAttributes);
53
+ durationHistogram.record(event.durationMs, baseAttributes);
54
+ if (event.status === "error") {
55
+ failureCounter.add(1, {
56
+ ...baseAttributes,
57
+ error: event.error ?? "unknown",
58
+ });
59
+ }
60
+ },
61
+ };
62
+ }
63
+ export function isTenantClientTelemetry(value) {
64
+ return typeof value?.record === "function";
65
+ }
66
+ //# sourceMappingURL=observability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability.js","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Validation schemas for tenant-sdk inputs
4
+ */
5
+ export declare const uuidSchema: z.ZodString;
6
+ /**
7
+ * Validates a UUID string
8
+ */
9
+ export declare function validateUUID(value: string, fieldName: string): void;
10
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AAEH,eAAO,MAAM,UAAU,aAAyC,CAAC;AAEjE;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CASnE"}
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Validation schemas for tenant-sdk inputs
4
+ */
5
+ export const uuidSchema = z.string().uuid("Invalid UUID format");
6
+ /**
7
+ * Validates a UUID string
8
+ */
9
+ export function validateUUID(value, fieldName) {
10
+ try {
11
+ uuidSchema.parse(value);
12
+ }
13
+ catch (error) {
14
+ if (error instanceof z.ZodError) {
15
+ throw new Error(`Invalid ${fieldName}: ${error.issues[0]?.message ?? "Invalid format"}`);
16
+ }
17
+ throw error;
18
+ }
19
+ }
20
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAEjE;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,SAAiB;IAC5D,IAAI,CAAC;QACJ,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC"}