@memberjunction/server 5.39.0 → 5.40.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.
- package/dist/auth/index.js +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +58 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.js +99 -0
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +33 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -0
- package/dist/auth/magicLink/MagicLinkRouter.js +184 -0
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkService.d.ts +123 -0
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -0
- package/dist/auth/magicLink/MagicLinkService.js +605 -0
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -0
- package/dist/auth/magicLink/index.d.ts +6 -0
- package/dist/auth/magicLink/index.d.ts.map +1 -0
- package/dist/auth/magicLink/index.js +6 -0
- package/dist/auth/magicLink/index.js.map +1 -0
- package/dist/auth/magicLink/magicLinkCore.d.ts +82 -0
- package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -0
- package/dist/auth/magicLink/magicLinkCore.js +164 -0
- package/dist/auth/magicLink/magicLinkCore.js.map +1 -0
- package/dist/auth/magicLink/redeemLanding.d.ts +22 -0
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -0
- package/dist/auth/magicLink/redeemLanding.js +61 -0
- package/dist/auth/magicLink/redeemLanding.js.map +1 -0
- package/dist/auth/magicLink/types.d.ts +131 -0
- package/dist/auth/magicLink/types.d.ts.map +1 -0
- package/dist/auth/magicLink/types.js +6 -0
- package/dist/auth/magicLink/types.js.map +1 -0
- package/dist/config.d.ts +411 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +225 -2
- package/dist/context.js.map +1 -1
- package/dist/generated/generated.d.ts +877 -4
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +17779 -12750
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +35 -7
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/CurrentUserContextResolver.d.ts +9 -3
- package/dist/resolvers/CurrentUserContextResolver.d.ts.map +1 -1
- package/dist/resolvers/CurrentUserContextResolver.js +19 -5
- package/dist/resolvers/CurrentUserContextResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +13 -2
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/GenerateSeedTaxonomyResolver.d.ts +28 -0
- package/dist/resolvers/GenerateSeedTaxonomyResolver.d.ts.map +1 -0
- package/dist/resolvers/GenerateSeedTaxonomyResolver.js +100 -0
- package/dist/resolvers/GenerateSeedTaxonomyResolver.js.map +1 -0
- package/dist/resolvers/RunClusterAnalysisResolver.d.ts +74 -0
- package/dist/resolvers/RunClusterAnalysisResolver.d.ts.map +1 -0
- package/dist/resolvers/RunClusterAnalysisResolver.js +243 -0
- package/dist/resolvers/RunClusterAnalysisResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts +16 -2
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +45 -2
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.d.ts +19 -0
- package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -0
- package/dist/rest/SignatureWebhookHandler.js +86 -0
- package/dist/rest/SignatureWebhookHandler.js.map +1 -0
- package/package.json +75 -71
- package/src/__tests__/magicLink.test.ts +387 -0
- package/src/auth/index.ts +2 -2
- package/src/auth/magicLink/MagicLinkKeys.ts +122 -0
- package/src/auth/magicLink/MagicLinkRouter.ts +209 -0
- package/src/auth/magicLink/MagicLinkService.ts +724 -0
- package/src/auth/magicLink/index.ts +17 -0
- package/src/auth/magicLink/magicLinkCore.ts +216 -0
- package/src/auth/magicLink/redeemLanding.ts +62 -0
- package/src/auth/magicLink/types.ts +137 -0
- package/src/config.ts +62 -0
- package/src/context.ts +252 -3
- package/src/generated/generated.ts +12302 -8878
- package/src/generic/ResolverBase.ts +35 -7
- package/src/index.ts +28 -0
- package/src/resolvers/CurrentUserContextResolver.ts +21 -5
- package/src/resolvers/EntityResolver.ts +17 -5
- package/src/resolvers/GenerateSeedTaxonomyResolver.ts +90 -0
- package/src/resolvers/RunClusterAnalysisResolver.ts +249 -0
- package/src/resolvers/UserResolver.ts +38 -2
- package/src/rest/SignatureWebhookHandler.ts +103 -0
|
@@ -0,0 +1,243 @@
|
|
|
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 { Resolver, Mutation, Arg, Ctx, ObjectType, InputType, Field, Float, Int } from 'type-graphql';
|
|
14
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
15
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
16
|
+
import { GetReadWriteProvider } from '../util.js';
|
|
17
|
+
import { ClusteringEngine, EntityDocumentVectorSource, } from '@memberjunction/clustering-engine';
|
|
18
|
+
/* ───── GraphQL input ───── */
|
|
19
|
+
let RunClusterAnalysisInput = class RunClusterAnalysisInput {
|
|
20
|
+
};
|
|
21
|
+
__decorate([
|
|
22
|
+
Field({ nullable: true }),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], RunClusterAnalysisInput.prototype, "EntityName", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
Field({ nullable: true }),
|
|
27
|
+
__metadata("design:type", String)
|
|
28
|
+
], RunClusterAnalysisInput.prototype, "EntityID", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
Field({ nullable: true }),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], RunClusterAnalysisInput.prototype, "EntityDocumentID", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
Field(() => [String], { nullable: true }),
|
|
35
|
+
__metadata("design:type", Array)
|
|
36
|
+
], RunClusterAnalysisInput.prototype, "EntityDocumentIDs", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
Field({ nullable: true }),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], RunClusterAnalysisInput.prototype, "ColorBy", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
Field({ nullable: true }),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], RunClusterAnalysisInput.prototype, "Algorithm", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
Field(() => Int, { nullable: true }),
|
|
47
|
+
__metadata("design:type", Number)
|
|
48
|
+
], RunClusterAnalysisInput.prototype, "K", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
Field(() => Float, { nullable: true }),
|
|
51
|
+
__metadata("design:type", Number)
|
|
52
|
+
], RunClusterAnalysisInput.prototype, "Epsilon", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
Field(() => Int, { nullable: true }),
|
|
55
|
+
__metadata("design:type", Number)
|
|
56
|
+
], RunClusterAnalysisInput.prototype, "MinPoints", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
Field({ nullable: true }),
|
|
59
|
+
__metadata("design:type", String)
|
|
60
|
+
], RunClusterAnalysisInput.prototype, "DistanceMetric", void 0);
|
|
61
|
+
__decorate([
|
|
62
|
+
Field(() => Int, { nullable: true }),
|
|
63
|
+
__metadata("design:type", Number)
|
|
64
|
+
], RunClusterAnalysisInput.prototype, "MaxRecords", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
Field({ nullable: true }),
|
|
67
|
+
__metadata("design:type", String)
|
|
68
|
+
], RunClusterAnalysisInput.prototype, "Filter", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
Field({ nullable: true }),
|
|
71
|
+
__metadata("design:type", Boolean)
|
|
72
|
+
], RunClusterAnalysisInput.prototype, "NameClusters", void 0);
|
|
73
|
+
__decorate([
|
|
74
|
+
Field(() => Int, { nullable: true }),
|
|
75
|
+
__metadata("design:type", Number)
|
|
76
|
+
], RunClusterAnalysisInput.prototype, "Dimensions", void 0);
|
|
77
|
+
__decorate([
|
|
78
|
+
Field({ nullable: true }),
|
|
79
|
+
__metadata("design:type", String)
|
|
80
|
+
], RunClusterAnalysisInput.prototype, "PersistName", void 0);
|
|
81
|
+
RunClusterAnalysisInput = __decorate([
|
|
82
|
+
InputType()
|
|
83
|
+
], RunClusterAnalysisInput);
|
|
84
|
+
export { RunClusterAnalysisInput };
|
|
85
|
+
/* ───── GraphQL output ───── */
|
|
86
|
+
let RunClusterAnalysisResult = class RunClusterAnalysisResult {
|
|
87
|
+
};
|
|
88
|
+
__decorate([
|
|
89
|
+
Field(),
|
|
90
|
+
__metadata("design:type", Boolean)
|
|
91
|
+
], RunClusterAnalysisResult.prototype, "Success", void 0);
|
|
92
|
+
__decorate([
|
|
93
|
+
Field({ nullable: true }),
|
|
94
|
+
__metadata("design:type", String)
|
|
95
|
+
], RunClusterAnalysisResult.prototype, "ErrorMessage", void 0);
|
|
96
|
+
__decorate([
|
|
97
|
+
Field(() => Int),
|
|
98
|
+
__metadata("design:type", Number)
|
|
99
|
+
], RunClusterAnalysisResult.prototype, "ClusterCount", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
Field(() => Int),
|
|
102
|
+
__metadata("design:type", Number)
|
|
103
|
+
], RunClusterAnalysisResult.prototype, "RecordCount", void 0);
|
|
104
|
+
__decorate([
|
|
105
|
+
Field(() => Int),
|
|
106
|
+
__metadata("design:type", Number)
|
|
107
|
+
], RunClusterAnalysisResult.prototype, "OutlierCount", void 0);
|
|
108
|
+
__decorate([
|
|
109
|
+
Field(() => Float),
|
|
110
|
+
__metadata("design:type", Number)
|
|
111
|
+
], RunClusterAnalysisResult.prototype, "SilhouetteScore", void 0);
|
|
112
|
+
__decorate([
|
|
113
|
+
Field(() => Float),
|
|
114
|
+
__metadata("design:type", Number)
|
|
115
|
+
], RunClusterAnalysisResult.prototype, "ComputationTimeMs", void 0);
|
|
116
|
+
__decorate([
|
|
117
|
+
Field(),
|
|
118
|
+
__metadata("design:type", String)
|
|
119
|
+
], RunClusterAnalysisResult.prototype, "MetricsJSON", void 0);
|
|
120
|
+
__decorate([
|
|
121
|
+
Field(),
|
|
122
|
+
__metadata("design:type", String)
|
|
123
|
+
], RunClusterAnalysisResult.prototype, "ClustersJSON", void 0);
|
|
124
|
+
__decorate([
|
|
125
|
+
Field(),
|
|
126
|
+
__metadata("design:type", String)
|
|
127
|
+
], RunClusterAnalysisResult.prototype, "PointsJSON", void 0);
|
|
128
|
+
__decorate([
|
|
129
|
+
Field({ nullable: true }),
|
|
130
|
+
__metadata("design:type", String)
|
|
131
|
+
], RunClusterAnalysisResult.prototype, "AnalysisID", void 0);
|
|
132
|
+
RunClusterAnalysisResult = __decorate([
|
|
133
|
+
ObjectType()
|
|
134
|
+
], RunClusterAnalysisResult);
|
|
135
|
+
export { RunClusterAnalysisResult };
|
|
136
|
+
/* ───── Resolver ───── */
|
|
137
|
+
let RunClusterAnalysisResolver = class RunClusterAnalysisResolver extends ResolverBase {
|
|
138
|
+
async RunClusterAnalysis(input, context = {}) {
|
|
139
|
+
try {
|
|
140
|
+
const currentUser = this.GetUserFromPayload(context.userPayload);
|
|
141
|
+
if (!currentUser) {
|
|
142
|
+
return this.errorResult('Unable to determine current user');
|
|
143
|
+
}
|
|
144
|
+
// Per-request provider so reads/writes use this user's connection +
|
|
145
|
+
// security context (multi-user safe), not the process global.
|
|
146
|
+
const provider = GetReadWriteProvider(context.providers);
|
|
147
|
+
const config = this.buildConfig(input);
|
|
148
|
+
const engine = new ClusteringEngine();
|
|
149
|
+
const vectorSource = new EntityDocumentVectorSource(currentUser, provider);
|
|
150
|
+
LogStatus(`RunClusterAnalysis: algorithm=${config.Algorithm} entity=${config.EntityName ?? config.EntityID ?? config.EntityDocumentID}`);
|
|
151
|
+
const result = await engine.RunPipeline(config, vectorSource, currentUser);
|
|
152
|
+
let analysisID;
|
|
153
|
+
if (input.PersistName && input.PersistName.trim().length > 0) {
|
|
154
|
+
analysisID = await this.persistAnalysis(engine, result, config, input.PersistName.trim(), currentUser, provider);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
Success: true,
|
|
158
|
+
ClusterCount: result.Metrics.ClusterCount,
|
|
159
|
+
RecordCount: result.Metrics.RecordCount,
|
|
160
|
+
OutlierCount: result.Metrics.OutlierCount,
|
|
161
|
+
SilhouetteScore: result.Metrics.SilhouetteScore,
|
|
162
|
+
ComputationTimeMs: result.Metrics.ComputationTimeMs,
|
|
163
|
+
MetricsJSON: JSON.stringify(result.Metrics),
|
|
164
|
+
ClustersJSON: JSON.stringify(result.Clusters),
|
|
165
|
+
PointsJSON: JSON.stringify(result.Points),
|
|
166
|
+
AnalysisID: analysisID,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
171
|
+
LogError(`RunClusterAnalysis mutation failed: ${msg}`);
|
|
172
|
+
return this.errorResult(msg);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** Build a {@link ClusterConfig} from the GraphQL input, applying defaults. */
|
|
176
|
+
buildConfig(input) {
|
|
177
|
+
return {
|
|
178
|
+
EntityName: input.EntityName ?? '',
|
|
179
|
+
EntityID: input.EntityID ?? '',
|
|
180
|
+
EntityDocumentID: input.EntityDocumentID ?? '',
|
|
181
|
+
EntityDocumentIDs: (input.EntityDocumentIDs ?? []).filter((id) => !!id && id.trim().length > 0),
|
|
182
|
+
ColorBy: input.ColorBy === 'entity' ? 'entity' : 'cluster',
|
|
183
|
+
Algorithm: this.normalizeAlgorithm(input.Algorithm),
|
|
184
|
+
K: input.K ?? 4,
|
|
185
|
+
Epsilon: input.Epsilon ?? 0.3,
|
|
186
|
+
MinPoints: input.MinPoints ?? 3,
|
|
187
|
+
DistanceMetric: this.normalizeMetric(input.DistanceMetric),
|
|
188
|
+
MaxRecords: input.MaxRecords ?? 500,
|
|
189
|
+
Filter: input.Filter ?? '',
|
|
190
|
+
NameClusters: input.NameClusters ?? false,
|
|
191
|
+
Dimensions: input.Dimensions === 3 ? 3 : 2,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** Coerce a raw algorithm string to a supported {@link ClusterAlgorithm}. */
|
|
195
|
+
normalizeAlgorithm(value) {
|
|
196
|
+
return value?.toLowerCase() === 'dbscan' ? 'dbscan' : 'kmeans';
|
|
197
|
+
}
|
|
198
|
+
/** Coerce a raw metric string to a supported {@link ClusterDistanceMetric}. */
|
|
199
|
+
normalizeMetric(value) {
|
|
200
|
+
const v = value?.toLowerCase();
|
|
201
|
+
if (v === 'euclidean' || v === 'dotproduct') {
|
|
202
|
+
return v;
|
|
203
|
+
}
|
|
204
|
+
return 'cosine';
|
|
205
|
+
}
|
|
206
|
+
/** Persist the result and return the new analysis ID (or undefined on failure). */
|
|
207
|
+
async persistAnalysis(engine, result, config, persistName, currentUser, provider) {
|
|
208
|
+
const owner = { Name: persistName, UserID: currentUser.ID };
|
|
209
|
+
const savedID = await engine.SaveAnalysis(result, config, owner, currentUser, provider);
|
|
210
|
+
if (!savedID) {
|
|
211
|
+
LogError(`RunClusterAnalysis: failed to persist analysis "${persistName}".`);
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
return savedID;
|
|
215
|
+
}
|
|
216
|
+
errorResult(message) {
|
|
217
|
+
return {
|
|
218
|
+
Success: false,
|
|
219
|
+
ErrorMessage: message,
|
|
220
|
+
ClusterCount: 0,
|
|
221
|
+
RecordCount: 0,
|
|
222
|
+
OutlierCount: 0,
|
|
223
|
+
SilhouetteScore: 0,
|
|
224
|
+
ComputationTimeMs: 0,
|
|
225
|
+
MetricsJSON: '{}',
|
|
226
|
+
ClustersJSON: '[]',
|
|
227
|
+
PointsJSON: '[]',
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
__decorate([
|
|
232
|
+
Mutation(() => RunClusterAnalysisResult),
|
|
233
|
+
__param(0, Arg('input', () => RunClusterAnalysisInput)),
|
|
234
|
+
__param(1, Ctx()),
|
|
235
|
+
__metadata("design:type", Function),
|
|
236
|
+
__metadata("design:paramtypes", [RunClusterAnalysisInput, Object]),
|
|
237
|
+
__metadata("design:returntype", Promise)
|
|
238
|
+
], RunClusterAnalysisResolver.prototype, "RunClusterAnalysis", null);
|
|
239
|
+
RunClusterAnalysisResolver = __decorate([
|
|
240
|
+
Resolver()
|
|
241
|
+
], RunClusterAnalysisResolver);
|
|
242
|
+
export { RunClusterAnalysisResolver };
|
|
243
|
+
//# sourceMappingURL=RunClusterAnalysisResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunClusterAnalysisResolver.js","sourceRoot":"","sources":["../../src/resolvers/RunClusterAnalysisResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import { AppContext } from '@memberjunction/server';
|
|
2
|
-
import { MJUserResolverBase } from '../generated/generated.js';
|
|
1
|
+
import { AppContext, PubSubEngine } from '@memberjunction/server';
|
|
2
|
+
import { MJUser_, MJUserResolverBase } from '../generated/generated.js';
|
|
3
3
|
export declare class UserResolver extends MJUserResolverBase {
|
|
4
|
+
/**
|
|
5
|
+
* Roles for the current user row.
|
|
6
|
+
*
|
|
7
|
+
* Overrides the generated field resolver to support ANONYMOUS magic-link sessions: those
|
|
8
|
+
* resolve to a shared Anonymous principal that holds NO roles in the database (by design —
|
|
9
|
+
* persisting them would let anonymous sessions accrete privileges across links). The roles
|
|
10
|
+
* are synthesized per-request in {@link buildMagicLinkSessionUser} and live only on the
|
|
11
|
+
* request's `UserInfo`. For the session's OWN user row we serve those synthesized roles
|
|
12
|
+
* directly, skipping the generated DB query (which returns empty) and its `MJ: User Roles`
|
|
13
|
+
* read-permission check (which the restricted anon role wouldn't pass). Every other case —
|
|
14
|
+
* named users, named magic-link users, listing other users' roles — falls through to the
|
|
15
|
+
* generated resolver unchanged, so there is no behavioral or security change off this path.
|
|
16
|
+
*/
|
|
17
|
+
MJUserRoles_UserIDArray(mjuser_: MJUser_, context: AppContext, pubSub: PubSubEngine): Promise<any[]>;
|
|
4
18
|
CurrentUser(context: AppContext): Promise<any>;
|
|
5
19
|
UserByID(ID: number, { providers, userPayload }: AppContext): Promise<any>;
|
|
6
20
|
UserByEmployeeID(EmployeeID: number, { providers, userPayload }: AppContext): Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/UserResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"UserResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/UserResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAwC,YAAY,EAAyB,MAAM,wBAAwB,CAAC;AAE/H,OAAO,EAAE,OAAO,EAAe,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGrF,qBACa,YAAa,SAAQ,kBAAkB;IAElD;;;;;;;;;;;;OAYG;IAEG,uBAAuB,CAAS,OAAO,EAAE,OAAO,EAAS,OAAO,EAAE,UAAU,EAAY,MAAM,EAAE,YAAY;IAqB5G,WAAW,CAAQ,OAAO,EAAE,UAAU;IA8CtC,QAAQ,CAAuB,EAAE,EAAE,MAAM,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,UAAU;IAUxF,gBAAgB,CAA+B,UAAU,EAAE,MAAM,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,UAAU;IAUhH,WAAW,CAA6B,KAAK,EAAE,MAAM,EAAS,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,UAAU;CAU3G;AACD,eAAe,YAAY,CAAC"}
|
|
@@ -10,10 +10,44 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
12
|
};
|
|
13
|
-
import { Arg, Ctx, Int, Query, Resolver } from '@memberjunction/server';
|
|
14
|
-
import {
|
|
13
|
+
import { Arg, Ctx, FieldResolver, Int, PubSub, PubSubEngine, Query, Resolver, Root } from '@memberjunction/server';
|
|
14
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
15
|
+
import { MJUser_, MJUserRole_, MJUserResolverBase } from '../generated/generated.js';
|
|
15
16
|
import { GetReadOnlyProvider } from '../util.js';
|
|
16
17
|
let UserResolver = class UserResolver extends MJUserResolverBase {
|
|
18
|
+
/**
|
|
19
|
+
* Roles for the current user row.
|
|
20
|
+
*
|
|
21
|
+
* Overrides the generated field resolver to support ANONYMOUS magic-link sessions: those
|
|
22
|
+
* resolve to a shared Anonymous principal that holds NO roles in the database (by design —
|
|
23
|
+
* persisting them would let anonymous sessions accrete privileges across links). The roles
|
|
24
|
+
* are synthesized per-request in {@link buildMagicLinkSessionUser} and live only on the
|
|
25
|
+
* request's `UserInfo`. For the session's OWN user row we serve those synthesized roles
|
|
26
|
+
* directly, skipping the generated DB query (which returns empty) and its `MJ: User Roles`
|
|
27
|
+
* read-permission check (which the restricted anon role wouldn't pass). Every other case —
|
|
28
|
+
* named users, named magic-link users, listing other users' roles — falls through to the
|
|
29
|
+
* generated resolver unchanged, so there is no behavioral or security change off this path.
|
|
30
|
+
*/
|
|
31
|
+
async MJUserRoles_UserIDArray(mjuser_, context, pubSub) {
|
|
32
|
+
const sessionUser = context.userPayload?.userRecord;
|
|
33
|
+
if (sessionUser?.IsMagicLinkAnonymous && UUIDsEqual(mjuser_.ID, sessionUser.ID)) {
|
|
34
|
+
const now = new Date();
|
|
35
|
+
// Build rows with the entity's RAW field names, then run them through the same
|
|
36
|
+
// name→code-name mapping the generated resolver uses (e.g. __mj_CreatedAt →
|
|
37
|
+
// _mj__CreatedAt). Returning raw names directly trips GraphQL's non-nullable check.
|
|
38
|
+
const rows = (sessionUser.UserRoles ?? []).map((r) => ({
|
|
39
|
+
ID: sessionUser.ID,
|
|
40
|
+
UserID: r.UserID,
|
|
41
|
+
RoleID: r.RoleID,
|
|
42
|
+
User: sessionUser.Name,
|
|
43
|
+
Role: r.RoleName ?? r.Role,
|
|
44
|
+
__mj_CreatedAt: now,
|
|
45
|
+
__mj_UpdatedAt: now,
|
|
46
|
+
}));
|
|
47
|
+
return this.ArrayMapFieldNamesToCodeNames('MJ: User Roles', rows, sessionUser);
|
|
48
|
+
}
|
|
49
|
+
return super.MJUserRoles_UserIDArray(mjuser_, context, pubSub);
|
|
50
|
+
}
|
|
17
51
|
async CurrentUser(context) {
|
|
18
52
|
// Check API key scope authorization for user read (self)
|
|
19
53
|
await this.CheckAPIKeyScopeAuthorization('user:read', '*', context.userPayload);
|
|
@@ -80,6 +114,15 @@ let UserResolver = class UserResolver extends MJUserResolverBase {
|
|
|
80
114
|
return this.MapFieldNamesToCodeNames('MJ: Users', returnVal);
|
|
81
115
|
}
|
|
82
116
|
};
|
|
117
|
+
__decorate([
|
|
118
|
+
FieldResolver(() => [MJUserRole_]),
|
|
119
|
+
__param(0, Root()),
|
|
120
|
+
__param(1, Ctx()),
|
|
121
|
+
__param(2, PubSub()),
|
|
122
|
+
__metadata("design:type", Function),
|
|
123
|
+
__metadata("design:paramtypes", [MJUser_, Object, PubSubEngine]),
|
|
124
|
+
__metadata("design:returntype", Promise)
|
|
125
|
+
], UserResolver.prototype, "MJUserRoles_UserIDArray", null);
|
|
83
126
|
__decorate([
|
|
84
127
|
Query(() => MJUser_),
|
|
85
128
|
__param(0, Ctx()),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserResolver.js","sourceRoot":"","sources":["../../src/resolvers/UserResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"UserResolver.js","sourceRoot":"","sources":["../../src/resolvers/UserResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Inbound eSignature webhook handler (DocuSign Connect, Adobe events, …).
|
|
3
|
+
*
|
|
4
|
+
* Unauthenticated by design — external signature providers call this endpoint without an MJ bearer
|
|
5
|
+
* token. Payload authenticity is verified by the provider DRIVER's `ParseWebhookEvent` (HMAC /
|
|
6
|
+
* signature), not by MJ auth. Must be registered BEFORE the unified auth middleware.
|
|
7
|
+
*
|
|
8
|
+
* Endpoint:
|
|
9
|
+
* - POST /esignature/webhook/:driverKey
|
|
10
|
+
*
|
|
11
|
+
* @module @memberjunction/server/rest/SignatureWebhookHandler
|
|
12
|
+
*/
|
|
13
|
+
import express from 'express';
|
|
14
|
+
/**
|
|
15
|
+
* Build an Express router exposing the eSignature webhook. Mount it unauthenticated:
|
|
16
|
+
* `app.use('/esignature', createSignatureWebhookHandler())`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createSignatureWebhookHandler(): express.Router;
|
|
19
|
+
//# sourceMappingURL=SignatureWebhookHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignatureWebhookHandler.d.ts","sourceRoot":"","sources":["../../src/rest/SignatureWebhookHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAM9B;;;GAGG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAAC,MAAM,CAa9D"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Inbound eSignature webhook handler (DocuSign Connect, Adobe events, …).
|
|
3
|
+
*
|
|
4
|
+
* Unauthenticated by design — external signature providers call this endpoint without an MJ bearer
|
|
5
|
+
* token. Payload authenticity is verified by the provider DRIVER's `ParseWebhookEvent` (HMAC /
|
|
6
|
+
* signature), not by MJ auth. Must be registered BEFORE the unified auth middleware.
|
|
7
|
+
*
|
|
8
|
+
* Endpoint:
|
|
9
|
+
* - POST /esignature/webhook/:driverKey
|
|
10
|
+
*
|
|
11
|
+
* @module @memberjunction/server/rest/SignatureWebhookHandler
|
|
12
|
+
*/
|
|
13
|
+
import express from 'express';
|
|
14
|
+
import BodyParser from 'body-parser';
|
|
15
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
16
|
+
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
17
|
+
import { SignatureEngine } from '@memberjunction/esignature/server';
|
|
18
|
+
/**
|
|
19
|
+
* Build an Express router exposing the eSignature webhook. Mount it unauthenticated:
|
|
20
|
+
* `app.use('/esignature', createSignatureWebhookHandler())`.
|
|
21
|
+
*/
|
|
22
|
+
export function createSignatureWebhookHandler() {
|
|
23
|
+
const router = express.Router();
|
|
24
|
+
// Capture the raw body so drivers that HMAC-verify over the exact bytes can do so.
|
|
25
|
+
router.post('/webhook/:driverKey', BodyParser.json({ limit: '25mb', verify: captureRawBody }), async (req, res) => {
|
|
26
|
+
await handleWebhook(req, res);
|
|
27
|
+
});
|
|
28
|
+
return router;
|
|
29
|
+
}
|
|
30
|
+
/** Stash the raw request bytes on the request for signature verification by the driver. */
|
|
31
|
+
function captureRawBody(req, _res, buf) {
|
|
32
|
+
req.rawBody = buf;
|
|
33
|
+
}
|
|
34
|
+
async function handleWebhook(req, res) {
|
|
35
|
+
const driverKey = req.params.driverKey;
|
|
36
|
+
if (!driverKey) {
|
|
37
|
+
res.status(400).json({ error: 'Missing driver key in path.' });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const contextUser = getSystemUser();
|
|
41
|
+
if (!contextUser) {
|
|
42
|
+
LogError('[eSignature webhook] No system user available; cannot process webhook.');
|
|
43
|
+
res.status(503).json({ error: 'Server not ready to process webhooks.' });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
await SignatureEngine.Instance.Config(false, contextUser);
|
|
48
|
+
const headers = normalizeHeaders(req.headers);
|
|
49
|
+
const rawBody = req.rawBody;
|
|
50
|
+
const result = await SignatureEngine.Instance.RecordWebhookEvent(driverKey, req.body, headers, contextUser, rawBody);
|
|
51
|
+
if (!result.Success) {
|
|
52
|
+
// 202: we received it but couldn't act (e.g. unrecognized payload / no matching envelope).
|
|
53
|
+
// Returning 2xx prevents most providers from aggressively retrying a payload we'll never match.
|
|
54
|
+
LogStatus(`[eSignature webhook] ${driverKey}: not actioned — ${result.ErrorMessage}`);
|
|
55
|
+
res.status(202).json({ received: true, actioned: false, message: result.ErrorMessage });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
res.status(200).json({ received: true, actioned: true, status: result.event?.status });
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
LogError(`[eSignature webhook] ${driverKey}: ${e instanceof Error ? e.message : String(e)}`);
|
|
62
|
+
res.status(500).json({ error: 'Failed to process webhook.' });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Flatten Express header values to a simple string map for the driver. */
|
|
66
|
+
function normalizeHeaders(headers) {
|
|
67
|
+
const out = {};
|
|
68
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
69
|
+
if (typeof value === 'string') {
|
|
70
|
+
out[key] = value;
|
|
71
|
+
}
|
|
72
|
+
else if (Array.isArray(value)) {
|
|
73
|
+
out[key] = value.join(', ');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
function getSystemUser() {
|
|
79
|
+
try {
|
|
80
|
+
return UserCache.Instance.GetSystemUser() ?? null;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=SignatureWebhookHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignatureWebhookHandler.js","sourceRoot":"","sources":["../../src/rest/SignatureWebhookHandler.ts"],"names":[],"mappings":"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"}
|