openxiangda-nest 2.0.0-alpha.12
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/README.md +25 -0
- package/dist/application-credentials.d.ts +19 -0
- package/dist/application-credentials.d.ts.map +1 -0
- package/dist/application-credentials.js +158 -0
- package/dist/application-credentials.js.map +1 -0
- package/dist/assignee-provider.d.ts +34 -0
- package/dist/assignee-provider.d.ts.map +1 -0
- package/dist/assignee-provider.js +216 -0
- package/dist/assignee-provider.js.map +1 -0
- package/dist/authz.d.ts +17 -0
- package/dist/authz.d.ts.map +1 -0
- package/dist/authz.js +129 -0
- package/dist/authz.js.map +1 -0
- package/dist/data-api.d.ts +61 -0
- package/dist/data-api.d.ts.map +1 -0
- package/dist/data-api.js +122 -0
- package/dist/data-api.js.map +1 -0
- package/dist/events.d.ts +46 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +359 -0
- package/dist/events.js.map +1 -0
- package/dist/health.d.ts +24 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +81 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +6 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +106 -0
- package/dist/module.js.map +1 -0
- package/dist/platform-client.d.ts +101 -0
- package/dist/platform-client.d.ts.map +1 -0
- package/dist/platform-client.js +250 -0
- package/dist/platform-client.js.map +1 -0
- package/dist/tokens.d.ts +4 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +4 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow.d.ts +59 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +84 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `openxiangda-nest`
|
|
2
|
+
|
|
3
|
+
Official NestJS backend boundary for OpenXiangda 2.0 applications.
|
|
4
|
+
|
|
5
|
+
It verifies the platform-issued user and active RoleSession, enforces declared
|
|
6
|
+
capabilities through the platform AuthZ service, forwards the verified context
|
|
7
|
+
to Data API v2, and installs the standard health/readiness/version endpoints.
|
|
8
|
+
Application code never receives PostgreSQL credentials and must not construct a
|
|
9
|
+
Principal from browser-supplied fields.
|
|
10
|
+
|
|
11
|
+
`OpenXiangdaApplicationCredentials` implements OAuth2 client credentials for
|
|
12
|
+
requestless Worker/Scheduler work. It single-flights token exchange, caches only
|
|
13
|
+
short-lived access tokens, refreshes before expiry and retries once after a 401.
|
|
14
|
+
`OpenXiangdaApplicationDataApiService` uses that identity with a null
|
|
15
|
+
RoleSession; inject it instead of the request-scoped Data API from background
|
|
16
|
+
jobs. Client id and secret must come from platform-managed runtime Secrets.
|
|
17
|
+
|
|
18
|
+
`OpenXiangdaEventReceiver` verifies structured CloudEvents HTTP pushes with the
|
|
19
|
+
subscription HMAC, timestamp window, application identity and a pluggable
|
|
20
|
+
idempotency receipt store. The module defaults to the platform-owned durable
|
|
21
|
+
receipt store; the explicit in-memory implementation is only for local tests.
|
|
22
|
+
Idempotent completion/release commands use bounded exponential retry (three
|
|
23
|
+
attempts by default). Once the business handler succeeds, an acknowledgement
|
|
24
|
+
failure never releases the receipt, avoiding an immediate duplicate execution;
|
|
25
|
+
external side effects must still use the CloudEvent id as their idempotency key.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { OpenXiangdaModuleOptions } from "./types.js";
|
|
2
|
+
export declare class OpenXiangdaApplicationCredentials {
|
|
3
|
+
private readonly options;
|
|
4
|
+
private readonly baseUrl;
|
|
5
|
+
private readonly fetch;
|
|
6
|
+
private cached;
|
|
7
|
+
private inFlight;
|
|
8
|
+
constructor(options: OpenXiangdaModuleOptions);
|
|
9
|
+
configured(): boolean;
|
|
10
|
+
getAuthorizationHeader(): Promise<string>;
|
|
11
|
+
invalidate(expectedAccessToken?: string): void;
|
|
12
|
+
withAuthorization<T>(operation: (authorization: string) => Promise<T>): Promise<T>;
|
|
13
|
+
private token;
|
|
14
|
+
private exchange;
|
|
15
|
+
private normalizedScopes;
|
|
16
|
+
private oauthErrorCode;
|
|
17
|
+
private isUnauthorized;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=application-credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-credentials.d.ts","sourceRoot":"","sources":["../src/application-credentials.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAmB3D,qBACa,iCAAiC;IAQ1C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiD;IACvE,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,QAAQ,CAA8C;gBAI3C,OAAO,EAAE,wBAAwB;IAMpD,UAAU,IAAI,OAAO;IAOf,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI/C,UAAU,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI;IAUxC,iBAAiB,CAAC,CAAC,EACvB,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC/C,OAAO,CAAC,CAAC,CAAC;YAYC,KAAK;YAcL,QAAQ;IAsGtB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,cAAc;CAOvB"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
14
|
+
import { OpenXiangdaPlatformError } from "./platform-client.js";
|
|
15
|
+
import { OPENXIANGDA_MODULE_OPTIONS } from "./tokens.js";
|
|
16
|
+
let OpenXiangdaApplicationCredentials = class OpenXiangdaApplicationCredentials {
|
|
17
|
+
options;
|
|
18
|
+
baseUrl;
|
|
19
|
+
fetch;
|
|
20
|
+
cached;
|
|
21
|
+
inFlight;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.baseUrl = options.platformBaseUrl.replace(/\/+$/, "");
|
|
25
|
+
this.fetch = options.fetch || globalThis.fetch.bind(globalThis);
|
|
26
|
+
}
|
|
27
|
+
configured() {
|
|
28
|
+
return Boolean(this.options.oauthClient?.clientId &&
|
|
29
|
+
this.options.oauthClient?.clientSecret);
|
|
30
|
+
}
|
|
31
|
+
async getAuthorizationHeader() {
|
|
32
|
+
return (await this.token()).authorization;
|
|
33
|
+
}
|
|
34
|
+
invalidate(expectedAccessToken) {
|
|
35
|
+
if (expectedAccessToken &&
|
|
36
|
+
this.cached?.accessToken !== expectedAccessToken) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.cached = undefined;
|
|
40
|
+
}
|
|
41
|
+
async withAuthorization(operation) {
|
|
42
|
+
const first = await this.token();
|
|
43
|
+
try {
|
|
44
|
+
return await operation(first.authorization);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (!this.isUnauthorized(error))
|
|
48
|
+
throw error;
|
|
49
|
+
this.invalidate(first.accessToken);
|
|
50
|
+
const refreshed = await this.token();
|
|
51
|
+
return await operation(refreshed.authorization);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async token() {
|
|
55
|
+
if (this.cached && Date.now() < this.cached.refreshAt)
|
|
56
|
+
return this.cached;
|
|
57
|
+
if (this.inFlight)
|
|
58
|
+
return await this.inFlight;
|
|
59
|
+
const pending = this.exchange();
|
|
60
|
+
this.inFlight = pending;
|
|
61
|
+
try {
|
|
62
|
+
const token = await pending;
|
|
63
|
+
this.cached = token;
|
|
64
|
+
return token;
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
if (this.inFlight === pending)
|
|
68
|
+
this.inFlight = undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async exchange() {
|
|
72
|
+
const oauth = this.options.oauthClient;
|
|
73
|
+
if (!oauth?.clientId || !oauth.clientSecret) {
|
|
74
|
+
throw new OpenXiangdaPlatformError(503, "APPLICATION_OAUTH_NOT_CONFIGURED", "OpenXiangda 应用后端尚未配置 OAuth2 Client Credentials");
|
|
75
|
+
}
|
|
76
|
+
const controller = new AbortController();
|
|
77
|
+
const timeout = setTimeout(() => controller.abort(), this.options.requestTimeoutMs || 5000);
|
|
78
|
+
try {
|
|
79
|
+
const body = new URLSearchParams({ grant_type: "client_credentials" });
|
|
80
|
+
const scopes = this.normalizedScopes(oauth.scopes);
|
|
81
|
+
if (scopes.length)
|
|
82
|
+
body.set("scope", scopes.join(" "));
|
|
83
|
+
const basic = Buffer.from(`${oauth.clientId}:${oauth.clientSecret}`, "utf8").toString("base64");
|
|
84
|
+
const response = await this.fetch(`${this.baseUrl}/openxiangda-api/v2/oauth2/token`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
signal: controller.signal,
|
|
87
|
+
headers: {
|
|
88
|
+
Accept: "application/json",
|
|
89
|
+
Authorization: `Basic ${basic}`,
|
|
90
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
91
|
+
},
|
|
92
|
+
body: body.toString(),
|
|
93
|
+
});
|
|
94
|
+
let payload;
|
|
95
|
+
try {
|
|
96
|
+
payload = (await response.json());
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw new OpenXiangdaPlatformError(response.status, "APPLICATION_OAUTH_RESPONSE_INVALID", "OAuth2 token endpoint 返回的不是有效 JSON");
|
|
100
|
+
}
|
|
101
|
+
if (!response.ok || payload.error) {
|
|
102
|
+
throw new OpenXiangdaPlatformError(response.status || 503, this.oauthErrorCode(payload.error), String(payload.error_description || "OAuth2 token 获取失败"));
|
|
103
|
+
}
|
|
104
|
+
const accessToken = String(payload.access_token || "").trim();
|
|
105
|
+
const tokenType = String(payload.token_type || "").trim();
|
|
106
|
+
const expiresIn = Math.floor(Number(payload.expires_in));
|
|
107
|
+
if (!accessToken ||
|
|
108
|
+
tokenType.toLowerCase() !== "bearer" ||
|
|
109
|
+
!Number.isFinite(expiresIn) ||
|
|
110
|
+
expiresIn < 1) {
|
|
111
|
+
throw new OpenXiangdaPlatformError(502, "APPLICATION_OAUTH_RESPONSE_INVALID", "OAuth2 token endpoint 返回了无效 token");
|
|
112
|
+
}
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
const configuredSkew = Math.max(0, Math.floor(Number(oauth.refreshSkewSeconds ?? 30)));
|
|
115
|
+
const refreshWindow = Math.min(configuredSkew, Math.max(0, Math.floor(expiresIn / 2)));
|
|
116
|
+
return {
|
|
117
|
+
accessToken,
|
|
118
|
+
authorization: `Bearer ${accessToken}`,
|
|
119
|
+
scope: String(payload.scope || ""),
|
|
120
|
+
expiresAt: now + expiresIn * 1000,
|
|
121
|
+
refreshAt: now + Math.max(1, expiresIn - refreshWindow) * 1000,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (error instanceof OpenXiangdaPlatformError)
|
|
126
|
+
throw error;
|
|
127
|
+
if (error?.name === "AbortError") {
|
|
128
|
+
throw new OpenXiangdaPlatformError(504, "APPLICATION_OAUTH_TIMEOUT", "OAuth2 token 获取超时");
|
|
129
|
+
}
|
|
130
|
+
throw new OpenXiangdaPlatformError(503, "APPLICATION_OAUTH_UNAVAILABLE", error?.message || "OAuth2 token endpoint 不可用");
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
clearTimeout(timeout);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
normalizedScopes(scopes) {
|
|
137
|
+
return [...new Set((scopes || []).map((scope) => scope.trim()).filter(Boolean))];
|
|
138
|
+
}
|
|
139
|
+
oauthErrorCode(error) {
|
|
140
|
+
const normalized = String(error || "token_exchange_failed")
|
|
141
|
+
.toUpperCase()
|
|
142
|
+
.replace(/[^A-Z0-9_]/g, "_")
|
|
143
|
+
.slice(0, 80);
|
|
144
|
+
return `APPLICATION_OAUTH_${normalized || "TOKEN_EXCHANGE_FAILED"}`;
|
|
145
|
+
}
|
|
146
|
+
isUnauthorized(error) {
|
|
147
|
+
return ((error instanceof OpenXiangdaPlatformError && error.httpStatus === 401) ||
|
|
148
|
+
Number(error?.status) === 401 ||
|
|
149
|
+
Number(error?.statusCode) === 401);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
OpenXiangdaApplicationCredentials = __decorate([
|
|
153
|
+
Injectable(),
|
|
154
|
+
__param(0, Inject(OPENXIANGDA_MODULE_OPTIONS)),
|
|
155
|
+
__metadata("design:paramtypes", [Object])
|
|
156
|
+
], OpenXiangdaApplicationCredentials);
|
|
157
|
+
export { OpenXiangdaApplicationCredentials };
|
|
158
|
+
//# sourceMappingURL=application-credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-credentials.js","sourceRoot":"","sources":["../src/application-credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { DiscoveryService, Reflector } from '@nestjs/core';
|
|
3
|
+
import type { WorkflowAssigneeRequest, WorkflowAssigneeResponse, WorkflowCandidatePrincipal } from 'openxiangda-contracts';
|
|
4
|
+
import type { OpenXiangdaModuleOptions } from './types.js';
|
|
5
|
+
export declare function WorkflowAssigneeProvider(code: string): ClassDecorator;
|
|
6
|
+
export interface WorkflowAssigneeProviderHandler {
|
|
7
|
+
resolve(request: WorkflowAssigneeRequest): Promise<WorkflowCandidatePrincipal[]> | WorkflowCandidatePrincipal[];
|
|
8
|
+
}
|
|
9
|
+
export declare class OpenXiangdaAssigneeProviderRegistry implements OnModuleInit {
|
|
10
|
+
private readonly discovery;
|
|
11
|
+
private readonly reflector;
|
|
12
|
+
private readonly handlers;
|
|
13
|
+
constructor(discovery: DiscoveryService, reflector: Reflector);
|
|
14
|
+
onModuleInit(): void;
|
|
15
|
+
resolve(code: string, request: WorkflowAssigneeRequest): Promise<WorkflowCandidatePrincipal[]>;
|
|
16
|
+
}
|
|
17
|
+
export declare function normalizeWorkflowCandidates(value: unknown): WorkflowCandidatePrincipal[];
|
|
18
|
+
export declare class OpenXiangdaAssigneeProviderReceiver {
|
|
19
|
+
private readonly options;
|
|
20
|
+
constructor(options: OpenXiangdaModuleOptions);
|
|
21
|
+
accept(providerCode: string, headers: Record<string, string | string[] | undefined>, rawBody: Buffer | string): WorkflowAssigneeRequest;
|
|
22
|
+
private assertTimestamp;
|
|
23
|
+
private assertSignature;
|
|
24
|
+
private header;
|
|
25
|
+
}
|
|
26
|
+
export declare class OpenXiangdaAssigneeProviderController {
|
|
27
|
+
private readonly receiver;
|
|
28
|
+
private readonly registry;
|
|
29
|
+
constructor(receiver: OpenXiangdaAssigneeProviderReceiver, registry: OpenXiangdaAssigneeProviderRegistry);
|
|
30
|
+
resolve(providerCode: string, headers: Record<string, string | string[] | undefined>, request: {
|
|
31
|
+
rawBody?: Buffer;
|
|
32
|
+
}, body: unknown): Promise<WorkflowAssigneeResponse>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=assignee-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assignee-provider.d.ts","sourceRoot":"","sources":["../src/assignee-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,YAAY,EAMb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAI3D,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAMrE;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CACL,OAAO,EAAE,uBAAuB,GAE9B,OAAO,CAAC,0BAA0B,EAAE,CAAC,GACrC,0BAA0B,EAAE,CAAC;CAClC;AAED,qBACa,mCAAoC,YAAW,YAAY;IAIpE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsD;gBAG5D,SAAS,EAAE,gBAAgB,EAC3B,SAAS,EAAE,SAAS;IAGvC,YAAY;IAgBN,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB;CAQ7D;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,gCAoCzD;AAED,qBACa,mCAAmC;IAG5C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,wBAAwB;IAGpD,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,OAAO,EAAE,MAAM,GAAG,MAAM,GACvB,uBAAuB;IAuC1B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,MAAM;CAWf;AAED,qBACa,qCAAqC;IAE9C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,QAAQ,EAAE,mCAAmC,EAC7C,QAAQ,EAAE,mCAAmC;IAI1D,OAAO,CACY,YAAY,EAAE,MAAM,EAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EAC1D,OAAO,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAC5B,IAAI,EAAE,OAAO,GACpB,OAAO,CAAC,wBAAwB,CAAC;CAUrC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
14
|
+
import { BadRequestException, Body, Controller, Headers, Inject, Injectable, Param, Post, Req, SetMetadata, UnauthorizedException, } from '@nestjs/common';
|
|
15
|
+
import { DiscoveryService, Reflector } from '@nestjs/core';
|
|
16
|
+
import { SCHEMA_VERSIONS } from 'openxiangda-contracts';
|
|
17
|
+
import { OPENXIANGDA_MODULE_OPTIONS } from './tokens.js';
|
|
18
|
+
const WORKFLOW_ASSIGNEE_PROVIDER = Symbol('OPENXIANGDA_WORKFLOW_ASSIGNEE_PROVIDER');
|
|
19
|
+
export function WorkflowAssigneeProvider(code) {
|
|
20
|
+
const normalized = String(code || '').trim();
|
|
21
|
+
if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(normalized)) {
|
|
22
|
+
throw new Error('WorkflowAssigneeProvider code 不合法');
|
|
23
|
+
}
|
|
24
|
+
return SetMetadata(WORKFLOW_ASSIGNEE_PROVIDER, normalized);
|
|
25
|
+
}
|
|
26
|
+
let OpenXiangdaAssigneeProviderRegistry = class OpenXiangdaAssigneeProviderRegistry {
|
|
27
|
+
discovery;
|
|
28
|
+
reflector;
|
|
29
|
+
handlers = new Map();
|
|
30
|
+
constructor(discovery, reflector) {
|
|
31
|
+
this.discovery = discovery;
|
|
32
|
+
this.reflector = reflector;
|
|
33
|
+
}
|
|
34
|
+
onModuleInit() {
|
|
35
|
+
for (const wrapper of this.discovery.getProviders()) {
|
|
36
|
+
const code = wrapper.metatype
|
|
37
|
+
? this.reflector.get(WORKFLOW_ASSIGNEE_PROVIDER, wrapper.metatype)
|
|
38
|
+
: undefined;
|
|
39
|
+
if (!code || !wrapper.instance)
|
|
40
|
+
continue;
|
|
41
|
+
if (typeof wrapper.instance.resolve !== 'function') {
|
|
42
|
+
throw new Error(`Workflow Assignee Provider ${code} 缺少 resolve()`);
|
|
43
|
+
}
|
|
44
|
+
if (this.handlers.has(code)) {
|
|
45
|
+
throw new Error(`Workflow Assignee Provider 重复: ${code}`);
|
|
46
|
+
}
|
|
47
|
+
this.handlers.set(code, wrapper.instance);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async resolve(code, request) {
|
|
51
|
+
const handler = this.handlers.get(code);
|
|
52
|
+
if (!handler) {
|
|
53
|
+
throw new BadRequestException(`Workflow Assignee Provider 未注册: ${code}`);
|
|
54
|
+
}
|
|
55
|
+
const candidates = await handler.resolve(request);
|
|
56
|
+
return normalizeWorkflowCandidates(candidates);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
OpenXiangdaAssigneeProviderRegistry = __decorate([
|
|
60
|
+
Injectable(),
|
|
61
|
+
__metadata("design:paramtypes", [DiscoveryService,
|
|
62
|
+
Reflector])
|
|
63
|
+
], OpenXiangdaAssigneeProviderRegistry);
|
|
64
|
+
export { OpenXiangdaAssigneeProviderRegistry };
|
|
65
|
+
export function normalizeWorkflowCandidates(value) {
|
|
66
|
+
if (!Array.isArray(value) || value.length > 200) {
|
|
67
|
+
throw new BadRequestException('Workflow Assignee Provider 返回值不合法');
|
|
68
|
+
}
|
|
69
|
+
const unique = new Map();
|
|
70
|
+
for (const item of value) {
|
|
71
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
72
|
+
throw new BadRequestException('Workflow Assignee Provider 候选人不合法');
|
|
73
|
+
}
|
|
74
|
+
const source = item;
|
|
75
|
+
const userId = String(source.userId || '').trim();
|
|
76
|
+
const candidateSource = String(source.source || '').trim();
|
|
77
|
+
if (!userId || !candidateSource) {
|
|
78
|
+
throw new BadRequestException('Workflow Assignee Provider 候选人不合法');
|
|
79
|
+
}
|
|
80
|
+
const candidate = {
|
|
81
|
+
userId,
|
|
82
|
+
source: candidateSource,
|
|
83
|
+
...(source.roleAssignmentId
|
|
84
|
+
? { roleAssignmentId: String(source.roleAssignmentId).trim() }
|
|
85
|
+
: {}),
|
|
86
|
+
...(source.roleCode
|
|
87
|
+
? { roleCode: String(source.roleCode).trim() }
|
|
88
|
+
: {}),
|
|
89
|
+
...(source.displayName
|
|
90
|
+
? { displayName: String(source.displayName).trim() }
|
|
91
|
+
: {}),
|
|
92
|
+
};
|
|
93
|
+
unique.set([candidate.userId, candidate.roleAssignmentId || '', candidate.roleCode || ''].join('\u0000'), candidate);
|
|
94
|
+
}
|
|
95
|
+
return [...unique.values()];
|
|
96
|
+
}
|
|
97
|
+
let OpenXiangdaAssigneeProviderReceiver = class OpenXiangdaAssigneeProviderReceiver {
|
|
98
|
+
options;
|
|
99
|
+
constructor(options) {
|
|
100
|
+
this.options = options;
|
|
101
|
+
}
|
|
102
|
+
accept(providerCode, headers, rawBody) {
|
|
103
|
+
const body = Buffer.isBuffer(rawBody)
|
|
104
|
+
? rawBody.toString('utf8')
|
|
105
|
+
: String(rawBody || '');
|
|
106
|
+
if (!body)
|
|
107
|
+
throw new BadRequestException('Provider raw body 不能为空');
|
|
108
|
+
const headerProvider = this.header(headers, 'x-openxiangda-workflow-provider');
|
|
109
|
+
const timestamp = this.header(headers, 'x-openxiangda-timestamp');
|
|
110
|
+
const signature = this.header(headers, 'x-openxiangda-signature');
|
|
111
|
+
this.header(headers, 'x-openxiangda-request-id');
|
|
112
|
+
if (headerProvider !== providerCode) {
|
|
113
|
+
throw new UnauthorizedException('Provider code 与请求路径不一致');
|
|
114
|
+
}
|
|
115
|
+
this.assertTimestamp(timestamp);
|
|
116
|
+
this.assertSignature(providerCode, timestamp, signature, body);
|
|
117
|
+
let value;
|
|
118
|
+
try {
|
|
119
|
+
value = JSON.parse(body);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
throw new BadRequestException('Provider body 不是有效 JSON');
|
|
123
|
+
}
|
|
124
|
+
const request = value;
|
|
125
|
+
if (request.schemaVersion !== SCHEMA_VERSIONS.workflowAssigneeRequest ||
|
|
126
|
+
request.providerCode !== providerCode ||
|
|
127
|
+
request.appCode !== this.options.appCode ||
|
|
128
|
+
!String(request.requestId || '').trim() ||
|
|
129
|
+
!String(request.workflowCode || '').trim() ||
|
|
130
|
+
!String(request.nodeId || '').trim() ||
|
|
131
|
+
!request.facts ||
|
|
132
|
+
typeof request.facts !== 'object') {
|
|
133
|
+
throw new BadRequestException('Provider 请求不符合 v2 协议');
|
|
134
|
+
}
|
|
135
|
+
return request;
|
|
136
|
+
}
|
|
137
|
+
assertTimestamp(value) {
|
|
138
|
+
const timestamp = Number(value);
|
|
139
|
+
const maxAgeSeconds = Math.max(30, this.options.workflowAssigneeProviderMaxAgeSeconds || 300);
|
|
140
|
+
if (!Number.isSafeInteger(timestamp) ||
|
|
141
|
+
Math.abs(Math.floor(Date.now() / 1000) - timestamp) > maxAgeSeconds) {
|
|
142
|
+
throw new UnauthorizedException('Provider 签名时间戳无效或已过期');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
assertSignature(providerCode, timestamp, value, body) {
|
|
146
|
+
const configured = this.options.workflowAssigneeProviderSecrets?.[providerCode];
|
|
147
|
+
const secrets = (Array.isArray(configured) ? configured : [configured])
|
|
148
|
+
.map(secret => String(secret || '').trim())
|
|
149
|
+
.filter(Boolean);
|
|
150
|
+
if (!secrets.length) {
|
|
151
|
+
throw new UnauthorizedException('Provider 签名密钥未配置');
|
|
152
|
+
}
|
|
153
|
+
const actual = value.startsWith('v1=') ? value.slice(3) : '';
|
|
154
|
+
const actualBuffer = Buffer.from(actual, 'hex');
|
|
155
|
+
const valid = secrets.some(secret => {
|
|
156
|
+
const expected = createHmac('sha256', secret)
|
|
157
|
+
.update(`${timestamp}.${body}`)
|
|
158
|
+
.digest('hex');
|
|
159
|
+
const expectedBuffer = Buffer.from(expected, 'hex');
|
|
160
|
+
return (actualBuffer.length === expectedBuffer.length &&
|
|
161
|
+
timingSafeEqual(actualBuffer, expectedBuffer));
|
|
162
|
+
});
|
|
163
|
+
if (!valid) {
|
|
164
|
+
throw new UnauthorizedException('Provider 签名无效');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
header(headers, name) {
|
|
168
|
+
const value = headers[name] ?? headers[name.toLowerCase()];
|
|
169
|
+
const normalized = Array.isArray(value) ? value[0] : value;
|
|
170
|
+
if (!String(normalized || '').trim()) {
|
|
171
|
+
throw new UnauthorizedException(`缺少 Provider 请求头 ${name}`);
|
|
172
|
+
}
|
|
173
|
+
return String(normalized).trim();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
OpenXiangdaAssigneeProviderReceiver = __decorate([
|
|
177
|
+
Injectable(),
|
|
178
|
+
__param(0, Inject(OPENXIANGDA_MODULE_OPTIONS)),
|
|
179
|
+
__metadata("design:paramtypes", [Object])
|
|
180
|
+
], OpenXiangdaAssigneeProviderReceiver);
|
|
181
|
+
export { OpenXiangdaAssigneeProviderReceiver };
|
|
182
|
+
let OpenXiangdaAssigneeProviderController = class OpenXiangdaAssigneeProviderController {
|
|
183
|
+
receiver;
|
|
184
|
+
registry;
|
|
185
|
+
constructor(receiver, registry) {
|
|
186
|
+
this.receiver = receiver;
|
|
187
|
+
this.registry = registry;
|
|
188
|
+
}
|
|
189
|
+
async resolve(providerCode, headers, request, body) {
|
|
190
|
+
const rawBody = request.rawBody || Buffer.from(JSON.stringify(body));
|
|
191
|
+
const input = this.receiver.accept(providerCode, headers, rawBody);
|
|
192
|
+
const candidates = await this.registry.resolve(providerCode, input);
|
|
193
|
+
return {
|
|
194
|
+
schemaVersion: SCHEMA_VERSIONS.workflowAssigneeResponse,
|
|
195
|
+
requestId: input.requestId,
|
|
196
|
+
candidates,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
__decorate([
|
|
201
|
+
Post('/:providerCode'),
|
|
202
|
+
__param(0, Param('providerCode')),
|
|
203
|
+
__param(1, Headers()),
|
|
204
|
+
__param(2, Req()),
|
|
205
|
+
__param(3, Body()),
|
|
206
|
+
__metadata("design:type", Function),
|
|
207
|
+
__metadata("design:paramtypes", [String, Object, Object, Object]),
|
|
208
|
+
__metadata("design:returntype", Promise)
|
|
209
|
+
], OpenXiangdaAssigneeProviderController.prototype, "resolve", null);
|
|
210
|
+
OpenXiangdaAssigneeProviderController = __decorate([
|
|
211
|
+
Controller('/openxiangda/workflow/assignee-providers'),
|
|
212
|
+
__metadata("design:paramtypes", [OpenXiangdaAssigneeProviderReceiver,
|
|
213
|
+
OpenXiangdaAssigneeProviderRegistry])
|
|
214
|
+
], OpenXiangdaAssigneeProviderController);
|
|
215
|
+
export { OpenXiangdaAssigneeProviderController };
|
|
216
|
+
//# sourceMappingURL=assignee-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assignee-provider.js","sourceRoot":"","sources":["../src/assignee-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/authz.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CanActivate, ExecutionContext } from "@nestjs/common";
|
|
2
|
+
import { Reflector } from "@nestjs/core";
|
|
3
|
+
import { OpenXiangdaPlatformClient } from "./platform-client.js";
|
|
4
|
+
import { OPENXIANGDA_REQUIRED_CAPABILITY } from "./tokens.js";
|
|
5
|
+
export declare const RequireCapability: (capability: string) => import("@nestjs/common").CustomDecorator<typeof OPENXIANGDA_REQUIRED_CAPABILITY>;
|
|
6
|
+
export declare const CurrentPrincipal: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
7
|
+
export declare const CurrentRoleSession: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
8
|
+
export declare const CurrentApplicationPrincipal: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
9
|
+
export declare const CurrentOpenXiangdaContext: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
10
|
+
export declare class OpenXiangdaAuthzGuard implements CanActivate {
|
|
11
|
+
private readonly platform;
|
|
12
|
+
private readonly reflector;
|
|
13
|
+
constructor(platform: OpenXiangdaPlatformClient, reflector: Reflector);
|
|
14
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
15
|
+
private servicePrincipal;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=authz.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz.d.ts","sourceRoot":"","sources":["../src/authz.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAMjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAO9D,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,qFACM,CAAC;AAE3D,eAAO,MAAM,gBAAgB,mDAG5B,CAAC;AAEF,eAAO,MAAM,kBAAkB,mDAQ9B,CAAC;AAEF,eAAO,MAAM,2BAA2B,mDAUvC,CAAC;AAEF,eAAO,MAAM,yBAAyB,mDAGrC,CAAC;AAEF,qBACa,qBAAsB,YAAW,WAAW;IAErD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,SAAS;IAGjC,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAqE9D,OAAO,CAAC,gBAAgB;CA6BzB"}
|
package/dist/authz.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { ForbiddenException, Injectable, SetMetadata, UnauthorizedException, createParamDecorator, } from "@nestjs/common";
|
|
11
|
+
import { Reflector } from "@nestjs/core";
|
|
12
|
+
import { SCHEMA_VERSIONS } from "openxiangda-contracts";
|
|
13
|
+
import { OpenXiangdaPlatformClient } from "./platform-client.js";
|
|
14
|
+
import { OPENXIANGDA_REQUIRED_CAPABILITY } from "./tokens.js";
|
|
15
|
+
export const RequireCapability = (capability) => SetMetadata(OPENXIANGDA_REQUIRED_CAPABILITY, capability);
|
|
16
|
+
export const CurrentPrincipal = createParamDecorator((_data, context) => requireContext(context).principal);
|
|
17
|
+
export const CurrentRoleSession = createParamDecorator((_data, context) => {
|
|
18
|
+
const roleSession = requireContext(context).roleSession;
|
|
19
|
+
if (!roleSession) {
|
|
20
|
+
throw new UnauthorizedException("OPENXIANGDA_USER_ROLE_SESSION_REQUIRED");
|
|
21
|
+
}
|
|
22
|
+
return roleSession;
|
|
23
|
+
});
|
|
24
|
+
export const CurrentApplicationPrincipal = createParamDecorator((_data, context) => {
|
|
25
|
+
const principal = requireContext(context).principal;
|
|
26
|
+
if (principal.principalType !== "service") {
|
|
27
|
+
throw new UnauthorizedException("OPENXIANGDA_APPLICATION_PRINCIPAL_REQUIRED");
|
|
28
|
+
}
|
|
29
|
+
return principal;
|
|
30
|
+
});
|
|
31
|
+
export const CurrentOpenXiangdaContext = createParamDecorator((_data, context) => requireContext(context));
|
|
32
|
+
let OpenXiangdaAuthzGuard = class OpenXiangdaAuthzGuard {
|
|
33
|
+
platform;
|
|
34
|
+
reflector;
|
|
35
|
+
constructor(platform, reflector) {
|
|
36
|
+
this.platform = platform;
|
|
37
|
+
this.reflector = reflector;
|
|
38
|
+
}
|
|
39
|
+
async canActivate(context) {
|
|
40
|
+
const request = context.switchToHttp().getRequest();
|
|
41
|
+
const authorization = header(request, "authorization");
|
|
42
|
+
if (!/^Bearer\s+\S+$/i.test(authorization)) {
|
|
43
|
+
throw new UnauthorizedException("OPENXIANGDA_BEARER_TOKEN_REQUIRED");
|
|
44
|
+
}
|
|
45
|
+
const roleSessionId = header(request, "x-openxiangda-role-session-id").trim();
|
|
46
|
+
const capability = this.reflector.getAllAndOverride(OPENXIANGDA_REQUIRED_CAPABILITY, [context.getHandler(), context.getClass()]);
|
|
47
|
+
if (!roleSessionId) {
|
|
48
|
+
const application = await this.platform.verifyApplicationPrincipal(authorization);
|
|
49
|
+
if (!application.scopes.includes("app:invoke")) {
|
|
50
|
+
throw new ForbiddenException({
|
|
51
|
+
code: "OPENXIANGDA_APPLICATION_INVOKE_DENIED",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (!capability) {
|
|
55
|
+
throw new ForbiddenException({
|
|
56
|
+
code: "OPENXIANGDA_SERVICE_CAPABILITY_REQUIRED",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (!application.scopes.includes(capability)) {
|
|
60
|
+
throw new ForbiddenException({
|
|
61
|
+
code: "OPENXIANGDA_CAPABILITY_DENIED",
|
|
62
|
+
capability,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
request.openxiangda = {
|
|
66
|
+
principal: this.servicePrincipal(application),
|
|
67
|
+
roleSession: null,
|
|
68
|
+
authorization,
|
|
69
|
+
roleSessionId: null,
|
|
70
|
+
};
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const verified = await this.platform.verifyPrincipal(authorization, roleSessionId);
|
|
74
|
+
request.openxiangda = {
|
|
75
|
+
...verified,
|
|
76
|
+
authorization,
|
|
77
|
+
roleSessionId,
|
|
78
|
+
};
|
|
79
|
+
if (!capability)
|
|
80
|
+
return true;
|
|
81
|
+
const decision = await this.platform.authorize(authorization, roleSessionId, { capability });
|
|
82
|
+
if (!decision.allowed) {
|
|
83
|
+
throw new ForbiddenException({
|
|
84
|
+
code: "OPENXIANGDA_CAPABILITY_DENIED",
|
|
85
|
+
capability,
|
|
86
|
+
explainId: decision.explainId,
|
|
87
|
+
decisions: decision.decisions,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
servicePrincipal(input) {
|
|
93
|
+
return {
|
|
94
|
+
schemaVersion: SCHEMA_VERSIONS.principal,
|
|
95
|
+
tenantId: input.tenantId,
|
|
96
|
+
appCode: input.appCode,
|
|
97
|
+
environmentId: input.environmentKey,
|
|
98
|
+
environmentKey: input.environmentKey,
|
|
99
|
+
principalType: "service",
|
|
100
|
+
subjectId: input.clientId,
|
|
101
|
+
clientRecordId: input.clientRecordId,
|
|
102
|
+
clientId: input.clientId,
|
|
103
|
+
credentialVersion: input.credentialVersion,
|
|
104
|
+
scopes: input.scopes,
|
|
105
|
+
rateLimitPerMinute: input.rateLimitPerMinute,
|
|
106
|
+
tokenId: input.tokenId,
|
|
107
|
+
authzVersion: input.credentialVersion,
|
|
108
|
+
isAppSuperAdmin: false,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
OpenXiangdaAuthzGuard = __decorate([
|
|
113
|
+
Injectable(),
|
|
114
|
+
__metadata("design:paramtypes", [OpenXiangdaPlatformClient,
|
|
115
|
+
Reflector])
|
|
116
|
+
], OpenXiangdaAuthzGuard);
|
|
117
|
+
export { OpenXiangdaAuthzGuard };
|
|
118
|
+
function requireContext(context) {
|
|
119
|
+
const request = context.switchToHttp().getRequest();
|
|
120
|
+
if (!request.openxiangda) {
|
|
121
|
+
throw new UnauthorizedException("OPENXIANGDA_CONTEXT_NOT_VERIFIED");
|
|
122
|
+
}
|
|
123
|
+
return request.openxiangda;
|
|
124
|
+
}
|
|
125
|
+
function header(request, name) {
|
|
126
|
+
const value = request.headers[name] || request.headers[name.toLowerCase()];
|
|
127
|
+
return Array.isArray(value) ? String(value[0] || "") : String(value || "");
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=authz.js.map
|