openxiangda-nest 2.0.0-alpha.100
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 +158 -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 +35 -0
- package/dist/assignee-provider.d.ts.map +1 -0
- package/dist/assignee-provider.js +223 -0
- package/dist/assignee-provider.js.map +1 -0
- package/dist/authz.d.ts +28 -0
- package/dist/authz.d.ts.map +1 -0
- package/dist/authz.js +207 -0
- package/dist/authz.js.map +1 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +40 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/business-action-context.d.ts +14 -0
- package/dist/business-action-context.d.ts.map +1 -0
- package/dist/business-action-context.js +41 -0
- package/dist/business-action-context.js.map +1 -0
- package/dist/business-directory.d.ts +14 -0
- package/dist/business-directory.d.ts.map +1 -0
- package/dist/business-directory.js +40 -0
- package/dist/business-directory.js.map +1 -0
- package/dist/business-notification.d.ts +23 -0
- package/dist/business-notification.d.ts.map +1 -0
- package/dist/business-notification.js +58 -0
- package/dist/business-notification.js.map +1 -0
- package/dist/business-process.d.ts +23 -0
- package/dist/business-process.d.ts.map +1 -0
- package/dist/business-process.js +106 -0
- package/dist/business-process.js.map +1 -0
- package/dist/data-api.d.ts +116 -0
- package/dist/data-api.d.ts.map +1 -0
- package/dist/data-api.js +248 -0
- package/dist/data-api.js.map +1 -0
- package/dist/event-context.d.ts +15 -0
- package/dist/event-context.d.ts.map +1 -0
- package/dist/event-context.js +33 -0
- package/dist/event-context.js.map +1 -0
- package/dist/event-handler.d.ts +36 -0
- package/dist/event-handler.d.ts.map +1 -0
- package/dist/event-handler.js +174 -0
- package/dist/event-handler.js.map +1 -0
- package/dist/events.d.ts +64 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +513 -0
- package/dist/events.js.map +1 -0
- package/dist/gateway-transport.d.ts +53 -0
- package/dist/gateway-transport.d.ts.map +1 -0
- package/dist/gateway-transport.js +369 -0
- package/dist/gateway-transport.js.map +1 -0
- package/dist/health.d.ts +36 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +105 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure-controller.d.ts +8 -0
- package/dist/infrastructure-controller.d.ts.map +1 -0
- package/dist/infrastructure-controller.js +15 -0
- package/dist/infrastructure-controller.js.map +1 -0
- package/dist/logger.d.ts +20 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +62 -0
- package/dist/logger.js.map +1 -0
- package/dist/module.d.ts +6 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +293 -0
- package/dist/module.js.map +1 -0
- package/dist/notification.d.ts +18 -0
- package/dist/notification.d.ts.map +1 -0
- package/dist/notification.js +52 -0
- package/dist/notification.js.map +1 -0
- package/dist/platform-client.d.ts +115 -0
- package/dist/platform-client.d.ts.map +1 -0
- package/dist/platform-client.js +506 -0
- package/dist/platform-client.js.map +1 -0
- package/dist/runtime.d.ts +56 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +253 -0
- package/dist/runtime.js.map +1 -0
- package/dist/standard-operations.d.ts +62 -0
- package/dist/standard-operations.d.ts.map +1 -0
- package/dist/standard-operations.js +169 -0
- package/dist/standard-operations.js.map +1 -0
- package/dist/todo.d.ts +20 -0
- package/dist/todo.d.ts.map +1 -0
- package/dist/todo.js +48 -0
- package/dist/todo.js.map +1 -0
- package/dist/tokens.d.ts +5 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +5 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +178 -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 +41 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +97 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# openxiangda-nest
|
|
2
|
+
|
|
3
|
+
NestJS integration for platform-gateway requests. The global transport guard verifies the gateway assertion and exposes `@CurrentUser()` with the verified user, role union and capability union. `@OpenXiangdaOperation()` binds typed business actions to declared capabilities.
|
|
4
|
+
|
|
5
|
+
Ordinary CRUD remains in the platform Data API. Use NestJS only for real business actions, and keep the platform as the authoritative identity and authorization owner.
|
|
6
|
+
|
|
7
|
+
A declared interactive action injects `OpenXiangdaBusinessDataApiService` (or
|
|
8
|
+
`OpenXiangdaStandardOperations`, which uses it). `@OpenXiangdaOperation` checks
|
|
9
|
+
the caller's action capability once at App API ingress. Native Data then runs
|
|
10
|
+
as the trusted backend for that exact application/environment without applying
|
|
11
|
+
the caller's ordinary resource, row and field permissions again. The platform
|
|
12
|
+
retains the initiating user and operation code in records, files, events and
|
|
13
|
+
audit. Do not author or forward an `authorizationJSON` permission mirror.
|
|
14
|
+
|
|
15
|
+
Start application backends with the canonical bootstrap so gateway signatures
|
|
16
|
+
are verified against the exact incoming request bytes:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import 'reflect-metadata';
|
|
20
|
+
import { bootstrapOpenXiangdaApplication } from 'openxiangda-nest';
|
|
21
|
+
import { AppModule } from './app.module.js';
|
|
22
|
+
|
|
23
|
+
await bootstrapOpenXiangdaApplication(AppModule);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Do not create a separate `NestFactory` or `FastifyAdapter` in application code.
|
|
27
|
+
The standard bootstrap owns raw-body capture, proxy trust, shutdown hooks, and
|
|
28
|
+
the runtime listen contract.
|
|
29
|
+
|
|
30
|
+
`OpenXiangdaStandardOperations` provides the default transaction patterns for
|
|
31
|
+
meeting interval overlap, course capacity/duplicate selection, and visitor
|
|
32
|
+
duplicate reservation checks. Each pattern submits one stable command to the
|
|
33
|
+
verified Native Data API transaction kernel. Mutable business state is never
|
|
34
|
+
pre-read by the application: record assertions lock their row, bounded integer
|
|
35
|
+
increments update derived counters, and the platform idempotency receipt is
|
|
36
|
+
consulted before guards or mutations.
|
|
37
|
+
|
|
38
|
+
For a verified Named Action, the SDK propagates the platform Gateway
|
|
39
|
+
`x-request-id` to nested platform calls automatically. Application code must
|
|
40
|
+
not replace it. Reuse the exact transaction payload and `idempotencyKey` after
|
|
41
|
+
a retryable authorization-projection readiness response; a previously
|
|
42
|
+
committed transaction returns its stored result with `replayed: true` without
|
|
43
|
+
duplicating rows or events.
|
|
44
|
+
|
|
45
|
+
Visitor duplicate detection accepts actual submitted values, not a field-name
|
|
46
|
+
list:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
await operations.createVisitorReservation({
|
|
50
|
+
reservationResourceCode: 'visitor-reservations',
|
|
51
|
+
duplicateMatch: {
|
|
52
|
+
visitorIdentityNumber: body.visitorIdentityNumber,
|
|
53
|
+
visitDate: body.visitDate,
|
|
54
|
+
},
|
|
55
|
+
data: body,
|
|
56
|
+
idempotencyKey: body.idempotencyKey,
|
|
57
|
+
activeStatusField: 'status',
|
|
58
|
+
activeStatusValues: ['pending', 'approved'],
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`duplicateMatch` must be a non-empty object. Its values and `data` come from
|
|
63
|
+
the same immutable request body; the application does not perform a pre-read.
|
|
64
|
+
|
|
65
|
+
## Standard application notifications
|
|
66
|
+
|
|
67
|
+
`OpenXiangdaBusinessNotificationService.send()` is the application-facing API
|
|
68
|
+
inside an `@OpenXiangdaOperation`. App Gateway authorizes the current user once,
|
|
69
|
+
then the platform revalidates the immutable operation proof and sends as a
|
|
70
|
+
platform-managed application principal. The original login token never reaches
|
|
71
|
+
the application; the audit retains the initiating user and action. Ordinary
|
|
72
|
+
users do not need `app:notification2:send`.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import {
|
|
76
|
+
OPENXIANGDA_NOTIFICATION_BUSINESS_SEND_V2,
|
|
77
|
+
} from 'openxiangda-contracts';
|
|
78
|
+
import { OpenXiangdaBusinessNotificationService } from 'openxiangda-nest';
|
|
79
|
+
|
|
80
|
+
await notifications.send({
|
|
81
|
+
schemaVersion: OPENXIANGDA_NOTIFICATION_BUSINESS_SEND_V2,
|
|
82
|
+
eventId: request.submittedEventId,
|
|
83
|
+
correlationId: `purchase:${request.id}`,
|
|
84
|
+
messageKey: `purchase:${request.id}:applicant`,
|
|
85
|
+
sourceSequence: request.revision,
|
|
86
|
+
state: 'informational',
|
|
87
|
+
recipients: [{ userId: request.applicantUserId }],
|
|
88
|
+
title: '采购申请已提交',
|
|
89
|
+
summary: '点击查看申请详情',
|
|
90
|
+
navigationTarget: {
|
|
91
|
+
kind: 'APP_ROUTE',
|
|
92
|
+
appCode: 'purchase_app',
|
|
93
|
+
routeCodes: {
|
|
94
|
+
desktop: 'purchase.detail',
|
|
95
|
+
mobile: 'purchase.detail-mobile',
|
|
96
|
+
},
|
|
97
|
+
pathParams: { id: request.id },
|
|
98
|
+
access: 'AUTHENTICATED',
|
|
99
|
+
},
|
|
100
|
+
idempotencyKey: `purchase:${request.id}:revision:${request.revision}`,
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The platform-owned `application.informational.standard` template renders
|
|
105
|
+
`title` and optional `summary`. Replaying the same `eventId` or
|
|
106
|
+
`idempotencyKey` returns the existing message. Reuse the same `messageKey` with
|
|
107
|
+
a greater `sourceSequence` and a new `idempotencyKey` to converge state.
|
|
108
|
+
|
|
109
|
+
In a signed Application Events or date-trigger handler, use
|
|
110
|
+
`notifications.sendFromEvent()`. Declare `recipientPaths`, `titlePath` and an
|
|
111
|
+
optional `summaryPath` beneath the immutable event `data`. The SDK forwards the
|
|
112
|
+
current event/delivery proof with an application credential; Notification Hub
|
|
113
|
+
verifies the active delivery and resolves recipients and presentation itself.
|
|
114
|
+
The event path never accepts caller-supplied recipient IDs or a user identity.
|
|
115
|
+
|
|
116
|
+
`OpenXiangdaNotificationService` remains the privileged management facade for
|
|
117
|
+
platform administrators that explicitly own `app:notification2:send` and need
|
|
118
|
+
to select an already activated template. It is not the default Named Action
|
|
119
|
+
path.
|
|
120
|
+
|
|
121
|
+
## Advanced DingTalk cards
|
|
122
|
+
|
|
123
|
+
`OpenXiangdaNotificationService` exposes the opt-in DingTalk card channel. The
|
|
124
|
+
platform owns the robot credentials and delivery state; application code only
|
|
125
|
+
selects an active binding, supplies its own template ID and string parameters,
|
|
126
|
+
and provides a canonical authenticated detail target. This channel is not the
|
|
127
|
+
default Workflow notification route.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import {
|
|
131
|
+
OPENXIANGDA_NOTIFICATION_DINGTALK_ADVANCED_CARD_SEND_V2,
|
|
132
|
+
} from 'openxiangda-contracts';
|
|
133
|
+
import { OpenXiangdaNotificationService } from 'openxiangda-nest';
|
|
134
|
+
|
|
135
|
+
await notifications.sendDingTalkCard({
|
|
136
|
+
schemaVersion: OPENXIANGDA_NOTIFICATION_DINGTALK_ADVANCED_CARD_SEND_V2,
|
|
137
|
+
bindingCode: 'dingtalk_card_advanced',
|
|
138
|
+
idempotencyKey: `purchase-created:${request.id}`,
|
|
139
|
+
title: '采购申请已创建',
|
|
140
|
+
recipients: [{ userId: approverUserId }],
|
|
141
|
+
cardTemplateId: 'purchase-result-v2',
|
|
142
|
+
cardParamMap: { applicant: request.applicantName },
|
|
143
|
+
navigationTarget: {
|
|
144
|
+
kind: 'APP_ROUTE',
|
|
145
|
+
appCode: 'purchase_app',
|
|
146
|
+
routeCodes: {
|
|
147
|
+
desktop: 'purchase.detail',
|
|
148
|
+
mobile: 'purchase.detail-mobile',
|
|
149
|
+
},
|
|
150
|
+
pathParams: { id: request.id },
|
|
151
|
+
access: 'AUTHENTICATED',
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This privileged service is request-scoped and requires the platform permission
|
|
157
|
+
`app:notification2:send`; recipient, parameter, URL and idempotency bounds are
|
|
158
|
+
enforced by Notification Hub 2.0.
|
|
@@ -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,35 @@
|
|
|
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
|
+
private readonly validateRequest;
|
|
21
|
+
constructor(options: OpenXiangdaModuleOptions);
|
|
22
|
+
accept(providerCode: string, headers: Record<string, string | string[] | undefined>, rawBody: Buffer | string): WorkflowAssigneeRequest;
|
|
23
|
+
private assertTimestamp;
|
|
24
|
+
private assertSignature;
|
|
25
|
+
private header;
|
|
26
|
+
}
|
|
27
|
+
export declare class OpenXiangdaAssigneeProviderController {
|
|
28
|
+
private readonly receiver;
|
|
29
|
+
private readonly registry;
|
|
30
|
+
constructor(receiver: OpenXiangdaAssigneeProviderReceiver, registry: OpenXiangdaAssigneeProviderRegistry);
|
|
31
|
+
resolve(providerCode: string, headers: Record<string, string | string[] | undefined>, request: {
|
|
32
|
+
rawBody?: Buffer;
|
|
33
|
+
}, body: unknown): Promise<WorkflowAssigneeResponse>;
|
|
34
|
+
}
|
|
35
|
+
//# 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;AAE3D,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,uBAAuB,CAAC;AAO/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;IAKpE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsD;gBAI5D,SAAS,EAAE,gBAAgB,EAE3B,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;IAS5C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAIU;gBAIvB,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;IAkC1B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,MAAM;CAWf;AAED,qBAEa,qCAAqC;IAG9C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAEzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAFR,QAAQ,EAAE,mCAAmC,EAE7C,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,223 @@
|
|
|
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 { Ajv2020 } from 'ajv/dist/2020.js';
|
|
17
|
+
import { SCHEMA_VERSIONS, workflowAssigneeRequestSchema, } from 'openxiangda-contracts';
|
|
18
|
+
import { OpenXiangdaInfrastructureController } from './infrastructure-controller.js';
|
|
19
|
+
import { OPENXIANGDA_MODULE_OPTIONS } from './tokens.js';
|
|
20
|
+
const WORKFLOW_ASSIGNEE_PROVIDER = Symbol('OPENXIANGDA_WORKFLOW_ASSIGNEE_PROVIDER');
|
|
21
|
+
export function WorkflowAssigneeProvider(code) {
|
|
22
|
+
const normalized = String(code || '').trim();
|
|
23
|
+
if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(normalized)) {
|
|
24
|
+
throw new Error('WorkflowAssigneeProvider code 不合法');
|
|
25
|
+
}
|
|
26
|
+
return SetMetadata(WORKFLOW_ASSIGNEE_PROVIDER, normalized);
|
|
27
|
+
}
|
|
28
|
+
let OpenXiangdaAssigneeProviderRegistry = class OpenXiangdaAssigneeProviderRegistry {
|
|
29
|
+
discovery;
|
|
30
|
+
reflector;
|
|
31
|
+
handlers = new Map();
|
|
32
|
+
constructor(discovery, reflector) {
|
|
33
|
+
this.discovery = discovery;
|
|
34
|
+
this.reflector = reflector;
|
|
35
|
+
}
|
|
36
|
+
onModuleInit() {
|
|
37
|
+
for (const wrapper of this.discovery.getProviders()) {
|
|
38
|
+
const code = wrapper.metatype
|
|
39
|
+
? this.reflector.get(WORKFLOW_ASSIGNEE_PROVIDER, wrapper.metatype)
|
|
40
|
+
: undefined;
|
|
41
|
+
if (!code || !wrapper.instance)
|
|
42
|
+
continue;
|
|
43
|
+
if (typeof wrapper.instance.resolve !== 'function') {
|
|
44
|
+
throw new Error(`Workflow Assignee Provider ${code} 缺少 resolve()`);
|
|
45
|
+
}
|
|
46
|
+
if (this.handlers.has(code)) {
|
|
47
|
+
throw new Error(`Workflow Assignee Provider 重复: ${code}`);
|
|
48
|
+
}
|
|
49
|
+
this.handlers.set(code, wrapper.instance);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async resolve(code, request) {
|
|
53
|
+
const handler = this.handlers.get(code);
|
|
54
|
+
if (!handler) {
|
|
55
|
+
throw new BadRequestException(`Workflow Assignee Provider 未注册: ${code}`);
|
|
56
|
+
}
|
|
57
|
+
const candidates = await handler.resolve(request);
|
|
58
|
+
return normalizeWorkflowCandidates(candidates);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
OpenXiangdaAssigneeProviderRegistry = __decorate([
|
|
62
|
+
Injectable(),
|
|
63
|
+
__param(0, Inject(DiscoveryService)),
|
|
64
|
+
__param(1, Inject(Reflector)),
|
|
65
|
+
__metadata("design:paramtypes", [DiscoveryService,
|
|
66
|
+
Reflector])
|
|
67
|
+
], OpenXiangdaAssigneeProviderRegistry);
|
|
68
|
+
export { OpenXiangdaAssigneeProviderRegistry };
|
|
69
|
+
export function normalizeWorkflowCandidates(value) {
|
|
70
|
+
if (!Array.isArray(value) || value.length > 200) {
|
|
71
|
+
throw new BadRequestException('Workflow Assignee Provider 返回值不合法');
|
|
72
|
+
}
|
|
73
|
+
const unique = new Map();
|
|
74
|
+
for (const item of value) {
|
|
75
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
76
|
+
throw new BadRequestException('Workflow Assignee Provider 候选人不合法');
|
|
77
|
+
}
|
|
78
|
+
const source = item;
|
|
79
|
+
const userId = String(source.userId || '').trim();
|
|
80
|
+
const candidateSource = String(source.source || '').trim();
|
|
81
|
+
if (!userId || !candidateSource) {
|
|
82
|
+
throw new BadRequestException('Workflow Assignee Provider 候选人不合法');
|
|
83
|
+
}
|
|
84
|
+
const candidate = {
|
|
85
|
+
userId,
|
|
86
|
+
source: candidateSource,
|
|
87
|
+
...(source.roleSubjectKey
|
|
88
|
+
? { roleSubjectKey: String(source.roleSubjectKey).trim() }
|
|
89
|
+
: {}),
|
|
90
|
+
...(source.roleCode
|
|
91
|
+
? { roleCode: String(source.roleCode).trim() }
|
|
92
|
+
: {}),
|
|
93
|
+
...(source.displayName
|
|
94
|
+
? { displayName: String(source.displayName).trim() }
|
|
95
|
+
: {}),
|
|
96
|
+
};
|
|
97
|
+
unique.set([candidate.userId, candidate.roleSubjectKey || '', candidate.roleCode || ''].join('\u0000'), candidate);
|
|
98
|
+
}
|
|
99
|
+
return [...unique.values()];
|
|
100
|
+
}
|
|
101
|
+
let OpenXiangdaAssigneeProviderReceiver = class OpenXiangdaAssigneeProviderReceiver {
|
|
102
|
+
options;
|
|
103
|
+
validateRequest = new Ajv2020({
|
|
104
|
+
allErrors: true,
|
|
105
|
+
strict: false,
|
|
106
|
+
validateFormats: false,
|
|
107
|
+
}).compile(workflowAssigneeRequestSchema);
|
|
108
|
+
constructor(options) {
|
|
109
|
+
this.options = options;
|
|
110
|
+
}
|
|
111
|
+
accept(providerCode, headers, rawBody) {
|
|
112
|
+
const body = Buffer.isBuffer(rawBody)
|
|
113
|
+
? rawBody.toString('utf8')
|
|
114
|
+
: String(rawBody || '');
|
|
115
|
+
if (!body)
|
|
116
|
+
throw new BadRequestException('Provider raw body 不能为空');
|
|
117
|
+
const headerProvider = this.header(headers, 'x-openxiangda-workflow-provider');
|
|
118
|
+
const timestamp = this.header(headers, 'x-openxiangda-timestamp');
|
|
119
|
+
const signature = this.header(headers, 'x-openxiangda-signature');
|
|
120
|
+
this.header(headers, 'x-openxiangda-request-id');
|
|
121
|
+
if (headerProvider !== providerCode) {
|
|
122
|
+
throw new UnauthorizedException('Provider code 与请求路径不一致');
|
|
123
|
+
}
|
|
124
|
+
this.assertTimestamp(timestamp);
|
|
125
|
+
this.assertSignature(providerCode, timestamp, signature, body);
|
|
126
|
+
let value;
|
|
127
|
+
try {
|
|
128
|
+
value = JSON.parse(body);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
throw new BadRequestException('Provider body 不是有效 JSON');
|
|
132
|
+
}
|
|
133
|
+
const request = value;
|
|
134
|
+
if (!this.validateRequest(value) ||
|
|
135
|
+
request.providerCode !== providerCode ||
|
|
136
|
+
request.appCode !== this.options.appCode) {
|
|
137
|
+
throw new BadRequestException('Provider 请求不符合 v2.1 协议');
|
|
138
|
+
}
|
|
139
|
+
return request;
|
|
140
|
+
}
|
|
141
|
+
assertTimestamp(value) {
|
|
142
|
+
const timestamp = Number(value);
|
|
143
|
+
const maxAgeSeconds = Math.max(30, this.options.workflowAssigneeProviderMaxAgeSeconds || 300);
|
|
144
|
+
if (!Number.isSafeInteger(timestamp) ||
|
|
145
|
+
Math.abs(Math.floor(Date.now() / 1000) - timestamp) > maxAgeSeconds) {
|
|
146
|
+
throw new UnauthorizedException('Provider 签名时间戳无效或已过期');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
assertSignature(providerCode, timestamp, value, body) {
|
|
150
|
+
const configured = this.options.workflowAssigneeProviderSecrets?.[providerCode];
|
|
151
|
+
const secrets = (Array.isArray(configured) ? configured : [configured])
|
|
152
|
+
.map(secret => String(secret || '').trim())
|
|
153
|
+
.filter(Boolean);
|
|
154
|
+
if (!secrets.length) {
|
|
155
|
+
throw new UnauthorizedException('Provider 签名密钥未配置');
|
|
156
|
+
}
|
|
157
|
+
const actual = value.startsWith('v1=') ? value.slice(3) : '';
|
|
158
|
+
const actualBuffer = Buffer.from(actual, 'hex');
|
|
159
|
+
const valid = secrets.some(secret => {
|
|
160
|
+
const expected = createHmac('sha256', secret)
|
|
161
|
+
.update(`${timestamp}.${body}`)
|
|
162
|
+
.digest('hex');
|
|
163
|
+
const expectedBuffer = Buffer.from(expected, 'hex');
|
|
164
|
+
return (actualBuffer.length === expectedBuffer.length &&
|
|
165
|
+
timingSafeEqual(actualBuffer, expectedBuffer));
|
|
166
|
+
});
|
|
167
|
+
if (!valid) {
|
|
168
|
+
throw new UnauthorizedException('Provider 签名无效');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
header(headers, name) {
|
|
172
|
+
const value = headers[name] ?? headers[name.toLowerCase()];
|
|
173
|
+
const normalized = Array.isArray(value) ? value[0] : value;
|
|
174
|
+
if (!String(normalized || '').trim()) {
|
|
175
|
+
throw new UnauthorizedException(`缺少 Provider 请求头 ${name}`);
|
|
176
|
+
}
|
|
177
|
+
return String(normalized).trim();
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
OpenXiangdaAssigneeProviderReceiver = __decorate([
|
|
181
|
+
Injectable(),
|
|
182
|
+
__param(0, Inject(OPENXIANGDA_MODULE_OPTIONS)),
|
|
183
|
+
__metadata("design:paramtypes", [Object])
|
|
184
|
+
], OpenXiangdaAssigneeProviderReceiver);
|
|
185
|
+
export { OpenXiangdaAssigneeProviderReceiver };
|
|
186
|
+
let OpenXiangdaAssigneeProviderController = class OpenXiangdaAssigneeProviderController {
|
|
187
|
+
receiver;
|
|
188
|
+
registry;
|
|
189
|
+
constructor(receiver, registry) {
|
|
190
|
+
this.receiver = receiver;
|
|
191
|
+
this.registry = registry;
|
|
192
|
+
}
|
|
193
|
+
async resolve(providerCode, headers, request, body) {
|
|
194
|
+
const rawBody = request.rawBody || Buffer.from(JSON.stringify(body));
|
|
195
|
+
const input = this.receiver.accept(providerCode, headers, rawBody);
|
|
196
|
+
const candidates = await this.registry.resolve(providerCode, input);
|
|
197
|
+
return {
|
|
198
|
+
schemaVersion: SCHEMA_VERSIONS.workflowAssigneeResponse,
|
|
199
|
+
requestId: input.requestId,
|
|
200
|
+
candidates,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
__decorate([
|
|
205
|
+
Post('/:providerCode'),
|
|
206
|
+
__param(0, Param('providerCode')),
|
|
207
|
+
__param(1, Headers()),
|
|
208
|
+
__param(2, Req()),
|
|
209
|
+
__param(3, Body()),
|
|
210
|
+
__metadata("design:type", Function),
|
|
211
|
+
__metadata("design:paramtypes", [String, Object, Object, Object]),
|
|
212
|
+
__metadata("design:returntype", Promise)
|
|
213
|
+
], OpenXiangdaAssigneeProviderController.prototype, "resolve", null);
|
|
214
|
+
OpenXiangdaAssigneeProviderController = __decorate([
|
|
215
|
+
OpenXiangdaInfrastructureController(),
|
|
216
|
+
Controller('/openxiangda/workflow/assignee-providers'),
|
|
217
|
+
__param(0, Inject(OpenXiangdaAssigneeProviderReceiver)),
|
|
218
|
+
__param(1, Inject(OpenXiangdaAssigneeProviderRegistry)),
|
|
219
|
+
__metadata("design:paramtypes", [OpenXiangdaAssigneeProviderReceiver,
|
|
220
|
+
OpenXiangdaAssigneeProviderRegistry])
|
|
221
|
+
], OpenXiangdaAssigneeProviderController);
|
|
222
|
+
export { OpenXiangdaAssigneeProviderController };
|
|
223
|
+
//# 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,28 @@
|
|
|
1
|
+
import { CanActivate, ExecutionContext } from "@nestjs/common";
|
|
2
|
+
import { Reflector } from "@nestjs/core";
|
|
3
|
+
import type { NativePrincipal } from "openxiangda-contracts";
|
|
4
|
+
import type { AppApiOperationContract } from "openxiangda-contracts";
|
|
5
|
+
import { OPENXIANGDA_REQUIRED_CAPABILITY } from "./tokens.js";
|
|
6
|
+
import type { OpenXiangdaCurrentUser, OpenXiangdaVerifiedContext } from "./types.js";
|
|
7
|
+
export declare const RequireCapability: (capability: string) => import("@nestjs/common").CustomDecorator<typeof OPENXIANGDA_REQUIRED_CAPABILITY>;
|
|
8
|
+
/**
|
|
9
|
+
* Binds one controller route to the immutable App API contract and protects it
|
|
10
|
+
* with the same generated capability constant. The release verifier can inspect
|
|
11
|
+
* this metadata without bootstrapping application business code.
|
|
12
|
+
*/
|
|
13
|
+
export declare function OpenXiangdaOperation(operation: AppApiOperationContract): (target: object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<any>) => void;
|
|
14
|
+
export declare const CurrentPrincipal: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
15
|
+
export declare const CurrentUser: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
16
|
+
export declare function currentUserFromVerifiedContext(verified: OpenXiangdaVerifiedContext): OpenXiangdaCurrentUser;
|
|
17
|
+
export declare function currentUserFromPrincipal(principal: NativePrincipal, roleCodes?: string[]): OpenXiangdaCurrentUser;
|
|
18
|
+
export declare const CurrentPerspective: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
19
|
+
export declare const CurrentApplicationPrincipal: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
20
|
+
export declare const CurrentOpenXiangdaContext: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
21
|
+
export declare class OpenXiangdaAuthzGuard implements CanActivate {
|
|
22
|
+
private readonly reflector;
|
|
23
|
+
constructor(reflector: Reflector);
|
|
24
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
25
|
+
private isVerifiedRoleUnion;
|
|
26
|
+
private servicePrincipal;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=authz.d.ts.map
|