@burdenoff/be-sdk 2026.510.79
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 +173 -0
- package/configs/eslint/index.js +492 -0
- package/configs/tsconfig/tsconfig.json +53 -0
- package/dist/EventQueueFactory-6NMSGECR.js +8 -0
- package/dist/EventQueueFactory-6NMSGECR.js.map +1 -0
- package/dist/auth/index.d.ts +66 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/captcha/index.d.ts +1 -0
- package/dist/captcha/index.js +4 -0
- package/dist/captcha/index.js.map +1 -0
- package/dist/chunk-2HANKZZM.js +245 -0
- package/dist/chunk-2HANKZZM.js.map +1 -0
- package/dist/chunk-2SD5L2F2.js +816 -0
- package/dist/chunk-2SD5L2F2.js.map +1 -0
- package/dist/chunk-3O2RQOPV.js +1068 -0
- package/dist/chunk-3O2RQOPV.js.map +1 -0
- package/dist/chunk-4B43DZIS.js +560 -0
- package/dist/chunk-4B43DZIS.js.map +1 -0
- package/dist/chunk-4XAEES25.js +2444 -0
- package/dist/chunk-4XAEES25.js.map +1 -0
- package/dist/chunk-4XGGWW36.js +1405 -0
- package/dist/chunk-4XGGWW36.js.map +1 -0
- package/dist/chunk-5LXDPGDH.js +245 -0
- package/dist/chunk-5LXDPGDH.js.map +1 -0
- package/dist/chunk-AI7L22ZJ.js +472 -0
- package/dist/chunk-AI7L22ZJ.js.map +1 -0
- package/dist/chunk-CBZNP6RF.js +286 -0
- package/dist/chunk-CBZNP6RF.js.map +1 -0
- package/dist/chunk-ELLX3K54.js +613 -0
- package/dist/chunk-ELLX3K54.js.map +1 -0
- package/dist/chunk-F5XEAGHQ.js +1875 -0
- package/dist/chunk-F5XEAGHQ.js.map +1 -0
- package/dist/chunk-FNZEQOJY.js +628 -0
- package/dist/chunk-FNZEQOJY.js.map +1 -0
- package/dist/chunk-GTEMQXCA.js +516 -0
- package/dist/chunk-GTEMQXCA.js.map +1 -0
- package/dist/chunk-HIWTWIGQ.js +226 -0
- package/dist/chunk-HIWTWIGQ.js.map +1 -0
- package/dist/chunk-IYE2NTRX.js +764 -0
- package/dist/chunk-IYE2NTRX.js.map +1 -0
- package/dist/chunk-J26YGR2U.js +1484 -0
- package/dist/chunk-J26YGR2U.js.map +1 -0
- package/dist/chunk-JG2FTZPI.js +509 -0
- package/dist/chunk-JG2FTZPI.js.map +1 -0
- package/dist/chunk-JVBTNSPG.js +1551 -0
- package/dist/chunk-JVBTNSPG.js.map +1 -0
- package/dist/chunk-L7ZMN2FJ.js +12 -0
- package/dist/chunk-L7ZMN2FJ.js.map +1 -0
- package/dist/chunk-M5IMU3US.js +473 -0
- package/dist/chunk-M5IMU3US.js.map +1 -0
- package/dist/chunk-MLW2HPS5.js +1267 -0
- package/dist/chunk-MLW2HPS5.js.map +1 -0
- package/dist/chunk-MNCGUYLJ.js +269 -0
- package/dist/chunk-MNCGUYLJ.js.map +1 -0
- package/dist/chunk-MOCUBSTW.js +373 -0
- package/dist/chunk-MOCUBSTW.js.map +1 -0
- package/dist/chunk-NGMEI42S.js +103 -0
- package/dist/chunk-NGMEI42S.js.map +1 -0
- package/dist/chunk-NUB5GQTU.js +270 -0
- package/dist/chunk-NUB5GQTU.js.map +1 -0
- package/dist/chunk-OVSYMNCI.js +145 -0
- package/dist/chunk-OVSYMNCI.js.map +1 -0
- package/dist/chunk-QLVKMWFA.js +94 -0
- package/dist/chunk-QLVKMWFA.js.map +1 -0
- package/dist/chunk-SAG6ZYWQ.js +89 -0
- package/dist/chunk-SAG6ZYWQ.js.map +1 -0
- package/dist/chunk-SAK2JCA7.js +198 -0
- package/dist/chunk-SAK2JCA7.js.map +1 -0
- package/dist/chunk-SBS4S2PJ.js +100 -0
- package/dist/chunk-SBS4S2PJ.js.map +1 -0
- package/dist/chunk-SNEOLWXT.js +148 -0
- package/dist/chunk-SNEOLWXT.js.map +1 -0
- package/dist/chunk-TKBD2ONF.js +564 -0
- package/dist/chunk-TKBD2ONF.js.map +1 -0
- package/dist/chunk-UBXFIIAW.js +127 -0
- package/dist/chunk-UBXFIIAW.js.map +1 -0
- package/dist/chunk-VI4VSNTI.js +57 -0
- package/dist/chunk-VI4VSNTI.js.map +1 -0
- package/dist/chunk-VWCN5PMD.js +268 -0
- package/dist/chunk-VWCN5PMD.js.map +1 -0
- package/dist/chunk-XC2YD6CF.js +913 -0
- package/dist/chunk-XC2YD6CF.js.map +1 -0
- package/dist/chunk-XE4OXN2W.js +10 -0
- package/dist/chunk-XE4OXN2W.js.map +1 -0
- package/dist/chunk-YMZEUTD2.js +110 -0
- package/dist/chunk-YMZEUTD2.js.map +1 -0
- package/dist/chunk-Z4IRLBWO.js +758 -0
- package/dist/chunk-Z4IRLBWO.js.map +1 -0
- package/dist/client/internal-client.d.ts +7 -0
- package/dist/client/internal-client.js +5 -0
- package/dist/client/internal-client.js.map +1 -0
- package/dist/client-CSjIrYKS.d.ts +77 -0
- package/dist/config-UKE2E3BW.js +4 -0
- package/dist/config-UKE2E3BW.js.map +1 -0
- package/dist/crypto/index.d.ts +1 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/database/index.d.ts +117 -0
- package/dist/database/index.js +7 -0
- package/dist/database/index.js.map +1 -0
- package/dist/dataloader/index.d.ts +1 -0
- package/dist/dataloader/index.js +4 -0
- package/dist/dataloader/index.js.map +1 -0
- package/dist/esm-K6H7EIWK.js +1450 -0
- package/dist/esm-K6H7EIWK.js.map +1 -0
- package/dist/event-queue/index.d.ts +6 -0
- package/dist/event-queue/index.js +10 -0
- package/dist/event-queue/index.js.map +1 -0
- package/dist/export/index.d.ts +2 -0
- package/dist/export/index.js +9 -0
- package/dist/export/index.js.map +1 -0
- package/dist/feature-flags/index.d.ts +1 -0
- package/dist/feature-flags/index.js +4 -0
- package/dist/feature-flags/index.js.map +1 -0
- package/dist/gateway/index.d.ts +4 -0
- package/dist/gateway/index.js +8 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/security/index.d.ts +2 -0
- package/dist/gateway/security/index.js +5 -0
- package/dist/gateway/security/index.js.map +1 -0
- package/dist/graph/index.d.ts +9 -0
- package/dist/graph/index.js +13 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph-emitter-Bk0FqD53.d.ts +47 -0
- package/dist/graphql/index.d.ts +2 -0
- package/dist/graphql/index.js +7 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/services/index.d.ts +24 -0
- package/dist/graphql/services/index.js +5 -0
- package/dist/graphql/services/index.js.map +1 -0
- package/dist/graphql-BAVrUgBF.d.ts +22 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +5 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n-DA6IPnYy.d.ts +101 -0
- package/dist/index-4gKQKZ2B.d.ts +71 -0
- package/dist/index-B18rrFru.d.ts +42 -0
- package/dist/index-B70b5mYS.d.ts +33 -0
- package/dist/index-BMq3lFjj.d.ts +247 -0
- package/dist/index-BODgvRtL.d.ts +316 -0
- package/dist/index-BS2idbnr.d.ts +874 -0
- package/dist/index-BV3G48cH.d.ts +124 -0
- package/dist/index-CHbVw5M7.d.ts +73 -0
- package/dist/index-Cq_xNjcv.d.ts +602 -0
- package/dist/index-CrQgidpx.d.ts +77 -0
- package/dist/index-CyVEg86m.d.ts +309 -0
- package/dist/index-DOcBnmMe.d.ts +166 -0
- package/dist/index-DSOpj8DI.d.ts +17 -0
- package/dist/index-DW9q22GH.d.ts +75 -0
- package/dist/index-DlFDFyWD.d.ts +55 -0
- package/dist/index-DoK0bjhH.d.ts +607 -0
- package/dist/index-Dtf6FBaD.d.ts +199 -0
- package/dist/index-KVWGHMbS.d.ts +415 -0
- package/dist/index-PaojfSdd.d.ts +71 -0
- package/dist/index-RU_M5c74.d.ts +163 -0
- package/dist/index-UhkH2eaB.d.ts +192 -0
- package/dist/index-e_18DzAg.d.ts +18 -0
- package/dist/index-jOuh_TKn.d.ts +59 -0
- package/dist/index.d.ts +584 -0
- package/dist/index.js +2626 -0
- package/dist/index.js.map +1 -0
- package/dist/init/index.d.ts +2 -0
- package/dist/init/index.js +12 -0
- package/dist/init/index.js.map +1 -0
- package/dist/instrumentation/index.d.ts +3 -0
- package/dist/instrumentation/index.js +5 -0
- package/dist/instrumentation/index.js.map +1 -0
- package/dist/layer/index.d.ts +2 -0
- package/dist/layer/index.js +6 -0
- package/dist/layer/index.js.map +1 -0
- package/dist/layer-DDip18KY.d.ts +67 -0
- package/dist/logger/index.d.ts +2 -0
- package/dist/logger/index.js +4 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +5 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/notifications/index.d.ts +4 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/pino-logger-RYLGXPHZ.js +5 -0
- package/dist/pino-logger-RYLGXPHZ.js.map +1 -0
- package/dist/prisma/generator/index.d.ts +1 -0
- package/dist/prisma/generator/index.js +228 -0
- package/dist/prisma/generator/index.js.map +1 -0
- package/dist/prisma/index.d.ts +5 -0
- package/dist/prisma/index.js +12 -0
- package/dist/prisma/index.js.map +1 -0
- package/dist/prisma-extension-krXnYnrN.d.ts +30 -0
- package/dist/rbac/index.d.ts +116 -0
- package/dist/rbac/index.js +7 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/sdk-THO3IWEE.js +136 -0
- package/dist/sdk-THO3IWEE.js.map +1 -0
- package/dist/server/index.d.ts +359 -0
- package/dist/server/index.js +884 -0
- package/dist/server/index.js.map +1 -0
- package/dist/telemetry/index.d.ts +83 -0
- package/dist/telemetry/index.js +209 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/temporal/index.d.ts +148 -0
- package/dist/temporal/index.js +6 -0
- package/dist/temporal/index.js.map +1 -0
- package/dist/tracker/index.d.ts +5 -0
- package/dist/tracker/index.js +9 -0
- package/dist/tracker/index.js.map +1 -0
- package/dist/types-Bo2wkjSP.d.ts +35 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/workspace-guard-LHBNK4TG.js +5 -0
- package/dist/workspace-guard-LHBNK4TG.js.map +1 -0
- package/package.json +241 -0
|
@@ -0,0 +1,1551 @@
|
|
|
1
|
+
import { RBACModule } from './chunk-J26YGR2U.js';
|
|
2
|
+
import { NotificationsModule, NotificationType } from './chunk-XC2YD6CF.js';
|
|
3
|
+
import { ValidationError, QuotaExceededError, PermissionDeniedError } from './chunk-SAG6ZYWQ.js';
|
|
4
|
+
import { logger } from './chunk-CBZNP6RF.js';
|
|
5
|
+
import { __name } from './chunk-XE4OXN2W.js';
|
|
6
|
+
|
|
7
|
+
// src/activity/index.ts
|
|
8
|
+
var ActivityType = /* @__PURE__ */ (function(ActivityType2) {
|
|
9
|
+
ActivityType2["CREATE"] = "create";
|
|
10
|
+
ActivityType2["READ"] = "read";
|
|
11
|
+
ActivityType2["UPDATE"] = "update";
|
|
12
|
+
ActivityType2["DELETE"] = "delete";
|
|
13
|
+
ActivityType2["LOGIN"] = "login";
|
|
14
|
+
ActivityType2["LOGOUT"] = "logout";
|
|
15
|
+
ActivityType2["EXPORT"] = "export";
|
|
16
|
+
ActivityType2["IMPORT"] = "import";
|
|
17
|
+
ActivityType2["SHARE"] = "share";
|
|
18
|
+
ActivityType2["DOWNLOAD"] = "download";
|
|
19
|
+
ActivityType2["UPLOAD"] = "upload";
|
|
20
|
+
ActivityType2["EXECUTE"] = "execute";
|
|
21
|
+
ActivityType2["APPROVE"] = "approve";
|
|
22
|
+
ActivityType2["REJECT"] = "reject";
|
|
23
|
+
ActivityType2["CUSTOM"] = "custom";
|
|
24
|
+
return ActivityType2;
|
|
25
|
+
})({});
|
|
26
|
+
var ActivityStatus = /* @__PURE__ */ (function(ActivityStatus2) {
|
|
27
|
+
ActivityStatus2["SUCCESS"] = "success";
|
|
28
|
+
ActivityStatus2["FAILURE"] = "failure";
|
|
29
|
+
ActivityStatus2["PENDING"] = "pending";
|
|
30
|
+
ActivityStatus2["WARNING"] = "warning";
|
|
31
|
+
return ActivityStatus2;
|
|
32
|
+
})({});
|
|
33
|
+
var ActivitySeverity = /* @__PURE__ */ (function(ActivitySeverity2) {
|
|
34
|
+
ActivitySeverity2["LOW"] = "low";
|
|
35
|
+
ActivitySeverity2["MEDIUM"] = "medium";
|
|
36
|
+
ActivitySeverity2["HIGH"] = "high";
|
|
37
|
+
ActivitySeverity2["CRITICAL"] = "critical";
|
|
38
|
+
return ActivitySeverity2;
|
|
39
|
+
})({});
|
|
40
|
+
var ActivityModule = class {
|
|
41
|
+
static {
|
|
42
|
+
__name(this, "ActivityModule");
|
|
43
|
+
}
|
|
44
|
+
client;
|
|
45
|
+
context;
|
|
46
|
+
constructor(client, context) {
|
|
47
|
+
this.client = client;
|
|
48
|
+
this.context = context;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Log activity
|
|
52
|
+
*/
|
|
53
|
+
async log(options) {
|
|
54
|
+
if (!options.userId) {
|
|
55
|
+
throw new ValidationError("User ID is required");
|
|
56
|
+
}
|
|
57
|
+
if (!options.activityType) {
|
|
58
|
+
throw new ValidationError("Activity type is required");
|
|
59
|
+
}
|
|
60
|
+
if (!options.resourceType) {
|
|
61
|
+
throw new ValidationError("Resource type is required");
|
|
62
|
+
}
|
|
63
|
+
if (!options.action) {
|
|
64
|
+
throw new ValidationError("Action is required");
|
|
65
|
+
}
|
|
66
|
+
if (!options.status) {
|
|
67
|
+
throw new ValidationError("Status is required");
|
|
68
|
+
}
|
|
69
|
+
logger.debug("[Activity] Logging activity", {
|
|
70
|
+
userId: options.userId,
|
|
71
|
+
action: options.action,
|
|
72
|
+
resourceType: options.resourceType
|
|
73
|
+
});
|
|
74
|
+
const recordActivityMutation = `
|
|
75
|
+
mutation RecordActivity($input: RecordActivityInput!) {
|
|
76
|
+
recordActivity(input: $input) {
|
|
77
|
+
id
|
|
78
|
+
userId
|
|
79
|
+
activityType
|
|
80
|
+
resourceType
|
|
81
|
+
resourceId
|
|
82
|
+
action
|
|
83
|
+
status
|
|
84
|
+
workspaceId
|
|
85
|
+
organizationId
|
|
86
|
+
projectId
|
|
87
|
+
ipAddress
|
|
88
|
+
userAgent
|
|
89
|
+
metadata
|
|
90
|
+
severity
|
|
91
|
+
errorMessage
|
|
92
|
+
duration
|
|
93
|
+
createdAt
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
const legacyLogActivityMutation = `
|
|
98
|
+
mutation LogActivity($input: LogActivityInput!) {
|
|
99
|
+
logActivity(input: $input) {
|
|
100
|
+
id
|
|
101
|
+
userId
|
|
102
|
+
activityType
|
|
103
|
+
resourceType
|
|
104
|
+
resourceId
|
|
105
|
+
action
|
|
106
|
+
status
|
|
107
|
+
workspaceId
|
|
108
|
+
organizationId
|
|
109
|
+
projectId
|
|
110
|
+
ipAddress
|
|
111
|
+
userAgent
|
|
112
|
+
metadata
|
|
113
|
+
severity
|
|
114
|
+
errorMessage
|
|
115
|
+
duration
|
|
116
|
+
createdAt
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
`;
|
|
120
|
+
const variables = {
|
|
121
|
+
input: {
|
|
122
|
+
userId: options.userId,
|
|
123
|
+
activityType: options.activityType,
|
|
124
|
+
resourceType: options.resourceType,
|
|
125
|
+
resourceId: options.resourceId,
|
|
126
|
+
action: options.action,
|
|
127
|
+
status: options.status,
|
|
128
|
+
workspaceId: options.workspaceId,
|
|
129
|
+
organizationId: options.organizationId,
|
|
130
|
+
projectId: options.projectId,
|
|
131
|
+
ipAddress: options.ipAddress,
|
|
132
|
+
userAgent: options.userAgent,
|
|
133
|
+
metadata: options.metadata,
|
|
134
|
+
severity: options.severity || "low",
|
|
135
|
+
errorMessage: options.errorMessage,
|
|
136
|
+
duration: options.duration
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
try {
|
|
140
|
+
const response = await this.client.query(recordActivityMutation, variables, this.context);
|
|
141
|
+
logger.info("[Activity] Activity logged", {
|
|
142
|
+
activityId: response.recordActivity.id
|
|
143
|
+
});
|
|
144
|
+
return response.recordActivity;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
147
|
+
const isRecordActivityUnavailable = message.includes('Cannot query field "recordActivity"') || message.includes('Unknown type "RecordActivityInput"');
|
|
148
|
+
if (!isRecordActivityUnavailable) {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
logger.warn("[Activity] Falling back to legacy logActivity mutation", {
|
|
152
|
+
reason: message
|
|
153
|
+
});
|
|
154
|
+
const legacyResponse = await this.client.query(legacyLogActivityMutation, variables, this.context);
|
|
155
|
+
logger.info("[Activity] Activity logged (legacy)", {
|
|
156
|
+
activityId: legacyResponse.logActivity.id
|
|
157
|
+
});
|
|
158
|
+
return legacyResponse.logActivity;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Log activity with automatic status detection
|
|
163
|
+
*/
|
|
164
|
+
async logSuccess(userId, action, resourceType, resourceId, metadata) {
|
|
165
|
+
return this.log({
|
|
166
|
+
userId,
|
|
167
|
+
action,
|
|
168
|
+
resourceType,
|
|
169
|
+
resourceId,
|
|
170
|
+
activityType: this.inferActivityType(action),
|
|
171
|
+
status: "success",
|
|
172
|
+
severity: "low",
|
|
173
|
+
metadata,
|
|
174
|
+
workspaceId: this.context.workspaceId
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Log failed activity
|
|
179
|
+
*/
|
|
180
|
+
async logFailure(userId, action, resourceType, errorMessage, resourceId, metadata) {
|
|
181
|
+
return this.log({
|
|
182
|
+
userId,
|
|
183
|
+
action,
|
|
184
|
+
resourceType,
|
|
185
|
+
resourceId,
|
|
186
|
+
activityType: this.inferActivityType(action),
|
|
187
|
+
status: "failure",
|
|
188
|
+
severity: "high",
|
|
189
|
+
errorMessage,
|
|
190
|
+
metadata,
|
|
191
|
+
workspaceId: this.context.workspaceId
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get activities with filters
|
|
196
|
+
*/
|
|
197
|
+
async getActivities(options) {
|
|
198
|
+
logger.debug("[Activity] Getting activities", options);
|
|
199
|
+
const query = `
|
|
200
|
+
query GetActivities(
|
|
201
|
+
$userId: ID
|
|
202
|
+
$workspaceId: ID
|
|
203
|
+
$organizationId: ID
|
|
204
|
+
$projectId: ID
|
|
205
|
+
$activityType: ActivityType
|
|
206
|
+
$resourceType: String
|
|
207
|
+
$resourceId: ID
|
|
208
|
+
$status: ActivityStatus
|
|
209
|
+
$severity: ActivitySeverity
|
|
210
|
+
$startDate: DateTime
|
|
211
|
+
$endDate: DateTime
|
|
212
|
+
$search: String
|
|
213
|
+
$limit: Int
|
|
214
|
+
$offset: Int
|
|
215
|
+
$sortBy: String
|
|
216
|
+
$sortOrder: String
|
|
217
|
+
) {
|
|
218
|
+
getActivities(
|
|
219
|
+
userId: $userId
|
|
220
|
+
workspaceId: $workspaceId
|
|
221
|
+
organizationId: $organizationId
|
|
222
|
+
projectId: $projectId
|
|
223
|
+
activityType: $activityType
|
|
224
|
+
resourceType: $resourceType
|
|
225
|
+
resourceId: $resourceId
|
|
226
|
+
status: $status
|
|
227
|
+
severity: $severity
|
|
228
|
+
startDate: $startDate
|
|
229
|
+
endDate: $endDate
|
|
230
|
+
search: $search
|
|
231
|
+
limit: $limit
|
|
232
|
+
offset: $offset
|
|
233
|
+
sortBy: $sortBy
|
|
234
|
+
sortOrder: $sortOrder
|
|
235
|
+
) {
|
|
236
|
+
activities {
|
|
237
|
+
id
|
|
238
|
+
userId
|
|
239
|
+
activityType
|
|
240
|
+
resourceType
|
|
241
|
+
resourceId
|
|
242
|
+
action
|
|
243
|
+
status
|
|
244
|
+
workspaceId
|
|
245
|
+
organizationId
|
|
246
|
+
projectId
|
|
247
|
+
ipAddress
|
|
248
|
+
userAgent
|
|
249
|
+
metadata
|
|
250
|
+
severity
|
|
251
|
+
errorMessage
|
|
252
|
+
duration
|
|
253
|
+
createdAt
|
|
254
|
+
}
|
|
255
|
+
total
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
`;
|
|
259
|
+
const variables = {
|
|
260
|
+
userId: options.userId,
|
|
261
|
+
workspaceId: options.workspaceId,
|
|
262
|
+
organizationId: options.organizationId,
|
|
263
|
+
projectId: options.projectId,
|
|
264
|
+
activityType: options.activityType,
|
|
265
|
+
resourceType: options.resourceType,
|
|
266
|
+
resourceId: options.resourceId,
|
|
267
|
+
status: options.status,
|
|
268
|
+
severity: options.severity,
|
|
269
|
+
startDate: options.startDate,
|
|
270
|
+
endDate: options.endDate,
|
|
271
|
+
search: options.search,
|
|
272
|
+
limit: options.limit || 50,
|
|
273
|
+
offset: options.offset || 0,
|
|
274
|
+
sortBy: options.sortBy || "createdAt",
|
|
275
|
+
sortOrder: options.sortOrder || "desc"
|
|
276
|
+
};
|
|
277
|
+
const response = await this.client.query(query, variables, this.context);
|
|
278
|
+
return response.getActivities;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get activity by ID
|
|
282
|
+
*/
|
|
283
|
+
async getActivity(activityId) {
|
|
284
|
+
logger.debug("[Activity] Getting activity", {
|
|
285
|
+
activityId
|
|
286
|
+
});
|
|
287
|
+
const query = `
|
|
288
|
+
query GetActivity($activityId: ID!) {
|
|
289
|
+
getActivity(activityId: $activityId) {
|
|
290
|
+
id
|
|
291
|
+
userId
|
|
292
|
+
activityType
|
|
293
|
+
resourceType
|
|
294
|
+
resourceId
|
|
295
|
+
action
|
|
296
|
+
status
|
|
297
|
+
workspaceId
|
|
298
|
+
organizationId
|
|
299
|
+
projectId
|
|
300
|
+
ipAddress
|
|
301
|
+
userAgent
|
|
302
|
+
metadata
|
|
303
|
+
severity
|
|
304
|
+
errorMessage
|
|
305
|
+
duration
|
|
306
|
+
createdAt
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
`;
|
|
310
|
+
const response = await this.client.query(query, {
|
|
311
|
+
activityId
|
|
312
|
+
}, this.context);
|
|
313
|
+
return response.getActivity;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get activity statistics
|
|
317
|
+
*/
|
|
318
|
+
async getStats(options) {
|
|
319
|
+
logger.debug("[Activity] Getting activity stats", options);
|
|
320
|
+
const query = `
|
|
321
|
+
query GetActivityStats(
|
|
322
|
+
$userId: ID
|
|
323
|
+
$workspaceId: ID
|
|
324
|
+
$organizationId: ID
|
|
325
|
+
$projectId: ID
|
|
326
|
+
$activityType: ActivityType
|
|
327
|
+
$resourceType: String
|
|
328
|
+
$startDate: DateTime
|
|
329
|
+
$endDate: DateTime
|
|
330
|
+
) {
|
|
331
|
+
getActivityStats(
|
|
332
|
+
userId: $userId
|
|
333
|
+
workspaceId: $workspaceId
|
|
334
|
+
organizationId: $organizationId
|
|
335
|
+
projectId: $projectId
|
|
336
|
+
activityType: $activityType
|
|
337
|
+
resourceType: $resourceType
|
|
338
|
+
startDate: $startDate
|
|
339
|
+
endDate: $endDate
|
|
340
|
+
) {
|
|
341
|
+
totalActivities
|
|
342
|
+
successCount
|
|
343
|
+
failureCount
|
|
344
|
+
pendingCount
|
|
345
|
+
warningCount
|
|
346
|
+
averageDuration
|
|
347
|
+
activitiesByType
|
|
348
|
+
activitiesBySeverity
|
|
349
|
+
topUsers {
|
|
350
|
+
userId
|
|
351
|
+
count
|
|
352
|
+
}
|
|
353
|
+
topResources {
|
|
354
|
+
resourceType
|
|
355
|
+
count
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
`;
|
|
360
|
+
const variables = {
|
|
361
|
+
userId: options.userId,
|
|
362
|
+
workspaceId: options.workspaceId,
|
|
363
|
+
organizationId: options.organizationId,
|
|
364
|
+
projectId: options.projectId,
|
|
365
|
+
activityType: options.activityType,
|
|
366
|
+
resourceType: options.resourceType,
|
|
367
|
+
startDate: options.startDate,
|
|
368
|
+
endDate: options.endDate
|
|
369
|
+
};
|
|
370
|
+
const response = await this.client.query(query, variables, this.context);
|
|
371
|
+
return response.getActivityStats;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Delete old activities (cleanup)
|
|
375
|
+
*/
|
|
376
|
+
async cleanup(olderThanDays, workspaceId) {
|
|
377
|
+
logger.debug("[Activity] Cleaning up old activities", {
|
|
378
|
+
olderThanDays,
|
|
379
|
+
workspaceId
|
|
380
|
+
});
|
|
381
|
+
const mutation = `
|
|
382
|
+
mutation CleanupActivities($olderThanDays: Int!, $workspaceId: ID) {
|
|
383
|
+
cleanupActivities(olderThanDays: $olderThanDays, workspaceId: $workspaceId) {
|
|
384
|
+
deletedCount
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
`;
|
|
388
|
+
const response = await this.client.query(mutation, {
|
|
389
|
+
olderThanDays,
|
|
390
|
+
workspaceId
|
|
391
|
+
}, this.context);
|
|
392
|
+
logger.info("[Activity] Cleanup completed", {
|
|
393
|
+
deletedCount: response.cleanupActivities.deletedCount
|
|
394
|
+
});
|
|
395
|
+
return response.cleanupActivities.deletedCount;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Infer activity type from action string
|
|
399
|
+
*/
|
|
400
|
+
inferActivityType(action) {
|
|
401
|
+
const actionLower = action.toLowerCase();
|
|
402
|
+
if (actionLower.includes("create") || actionLower.includes("add")) {
|
|
403
|
+
return "create";
|
|
404
|
+
}
|
|
405
|
+
if (actionLower.includes("update") || actionLower.includes("edit") || actionLower.includes("modify")) {
|
|
406
|
+
return "update";
|
|
407
|
+
}
|
|
408
|
+
if (actionLower.includes("delete") || actionLower.includes("remove")) {
|
|
409
|
+
return "delete";
|
|
410
|
+
}
|
|
411
|
+
if (actionLower.includes("read") || actionLower.includes("view") || actionLower.includes("get")) {
|
|
412
|
+
return "read";
|
|
413
|
+
}
|
|
414
|
+
if (actionLower.includes("login") || actionLower.includes("signin")) {
|
|
415
|
+
return "login";
|
|
416
|
+
}
|
|
417
|
+
if (actionLower.includes("logout") || actionLower.includes("signout")) {
|
|
418
|
+
return "logout";
|
|
419
|
+
}
|
|
420
|
+
if (actionLower.includes("export")) {
|
|
421
|
+
return "export";
|
|
422
|
+
}
|
|
423
|
+
if (actionLower.includes("import")) {
|
|
424
|
+
return "import";
|
|
425
|
+
}
|
|
426
|
+
if (actionLower.includes("share")) {
|
|
427
|
+
return "share";
|
|
428
|
+
}
|
|
429
|
+
if (actionLower.includes("download")) {
|
|
430
|
+
return "download";
|
|
431
|
+
}
|
|
432
|
+
if (actionLower.includes("upload")) {
|
|
433
|
+
return "upload";
|
|
434
|
+
}
|
|
435
|
+
if (actionLower.includes("execute") || actionLower.includes("run")) {
|
|
436
|
+
return "execute";
|
|
437
|
+
}
|
|
438
|
+
if (actionLower.includes("approve")) {
|
|
439
|
+
return "approve";
|
|
440
|
+
}
|
|
441
|
+
if (actionLower.includes("reject")) {
|
|
442
|
+
return "reject";
|
|
443
|
+
}
|
|
444
|
+
return "custom";
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Export activities to CSV
|
|
448
|
+
*/
|
|
449
|
+
async exportToCSV(options) {
|
|
450
|
+
logger.debug("[Activity] Exporting activities to CSV");
|
|
451
|
+
const query = `
|
|
452
|
+
query ExportActivities(
|
|
453
|
+
$userId: ID
|
|
454
|
+
$workspaceId: ID
|
|
455
|
+
$organizationId: ID
|
|
456
|
+
$startDate: DateTime
|
|
457
|
+
$endDate: DateTime
|
|
458
|
+
) {
|
|
459
|
+
exportActivities(
|
|
460
|
+
userId: $userId
|
|
461
|
+
workspaceId: $workspaceId
|
|
462
|
+
organizationId: $organizationId
|
|
463
|
+
startDate: $startDate
|
|
464
|
+
endDate: $endDate
|
|
465
|
+
) {
|
|
466
|
+
csvData
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
`;
|
|
470
|
+
const response = await this.client.query(query, {
|
|
471
|
+
userId: options.userId,
|
|
472
|
+
workspaceId: options.workspaceId,
|
|
473
|
+
organizationId: options.organizationId,
|
|
474
|
+
startDate: options.startDate,
|
|
475
|
+
endDate: options.endDate
|
|
476
|
+
}, this.context);
|
|
477
|
+
logger.info("[Activity] Activities exported to CSV");
|
|
478
|
+
return response.exportActivities.csvData;
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// src/usage/index.ts
|
|
483
|
+
var UsageMetricType = /* @__PURE__ */ (function(UsageMetricType2) {
|
|
484
|
+
UsageMetricType2["API_CALLS"] = "api_calls";
|
|
485
|
+
UsageMetricType2["STORAGE"] = "storage";
|
|
486
|
+
UsageMetricType2["BANDWIDTH"] = "bandwidth";
|
|
487
|
+
UsageMetricType2["USERS"] = "users";
|
|
488
|
+
UsageMetricType2["PROJECTS"] = "projects";
|
|
489
|
+
UsageMetricType2["WORKSPACES"] = "workspaces";
|
|
490
|
+
UsageMetricType2["RECORDS"] = "records";
|
|
491
|
+
UsageMetricType2["COMPUTE_TIME"] = "compute_time";
|
|
492
|
+
UsageMetricType2["TRANSACTIONS"] = "transactions";
|
|
493
|
+
UsageMetricType2["CUSTOM"] = "custom";
|
|
494
|
+
return UsageMetricType2;
|
|
495
|
+
})({});
|
|
496
|
+
var UsageModule = class {
|
|
497
|
+
static {
|
|
498
|
+
__name(this, "UsageModule");
|
|
499
|
+
}
|
|
500
|
+
client;
|
|
501
|
+
context;
|
|
502
|
+
constructor(client, context) {
|
|
503
|
+
this.client = client;
|
|
504
|
+
this.context = context;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Track usage
|
|
508
|
+
*/
|
|
509
|
+
async track(options) {
|
|
510
|
+
if (!options.entityId) {
|
|
511
|
+
throw new ValidationError("Entity ID is required");
|
|
512
|
+
}
|
|
513
|
+
if (!options.entityType) {
|
|
514
|
+
throw new ValidationError("Entity type is required");
|
|
515
|
+
}
|
|
516
|
+
if (!options.metricType) {
|
|
517
|
+
throw new ValidationError("Metric type is required");
|
|
518
|
+
}
|
|
519
|
+
if (typeof options.amount !== "number" || options.amount <= 0) {
|
|
520
|
+
throw new ValidationError("Amount must be a positive number");
|
|
521
|
+
}
|
|
522
|
+
logger.debug("[Usage] Tracking usage", {
|
|
523
|
+
entityId: options.entityId,
|
|
524
|
+
metricType: options.metricType,
|
|
525
|
+
amount: options.amount
|
|
526
|
+
});
|
|
527
|
+
const mutation = `
|
|
528
|
+
mutation TrackUsage($input: TrackUsageInput!) {
|
|
529
|
+
trackUsage(input: $input) {
|
|
530
|
+
id
|
|
531
|
+
entityId
|
|
532
|
+
entityType
|
|
533
|
+
metricType
|
|
534
|
+
amount
|
|
535
|
+
resourceId
|
|
536
|
+
metadata
|
|
537
|
+
workspaceId
|
|
538
|
+
organizationId
|
|
539
|
+
recordedAt
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
`;
|
|
543
|
+
const variables = {
|
|
544
|
+
input: {
|
|
545
|
+
entityId: options.entityId,
|
|
546
|
+
entityType: options.entityType,
|
|
547
|
+
metricType: options.metricType,
|
|
548
|
+
amount: options.amount,
|
|
549
|
+
resourceId: options.resourceId,
|
|
550
|
+
metadata: options.metadata,
|
|
551
|
+
workspaceId: options.workspaceId || this.context.workspaceId,
|
|
552
|
+
organizationId: options.organizationId
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
const response = await this.client.query(mutation, variables, this.context);
|
|
556
|
+
logger.info("[Usage] Usage tracked", {
|
|
557
|
+
recordId: response.trackUsage.id
|
|
558
|
+
});
|
|
559
|
+
return response.trackUsage;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Check quota availability
|
|
563
|
+
*/
|
|
564
|
+
async checkQuota(options) {
|
|
565
|
+
if (!options.entityId) {
|
|
566
|
+
throw new ValidationError("Entity ID is required");
|
|
567
|
+
}
|
|
568
|
+
if (!options.metricType) {
|
|
569
|
+
throw new ValidationError("Metric type is required");
|
|
570
|
+
}
|
|
571
|
+
if (typeof options.requestedAmount !== "number" || options.requestedAmount <= 0) {
|
|
572
|
+
throw new ValidationError("Requested amount must be a positive number");
|
|
573
|
+
}
|
|
574
|
+
logger.debug("[Usage] Checking quota", {
|
|
575
|
+
entityId: options.entityId,
|
|
576
|
+
metricType: options.metricType,
|
|
577
|
+
requestedAmount: options.requestedAmount
|
|
578
|
+
});
|
|
579
|
+
const query = `
|
|
580
|
+
query CheckQuota($input: CheckQuotaInput!) {
|
|
581
|
+
checkQuota(input: $input) {
|
|
582
|
+
allowed
|
|
583
|
+
currentUsage
|
|
584
|
+
quotaLimit
|
|
585
|
+
remainingQuota
|
|
586
|
+
resetAt
|
|
587
|
+
period
|
|
588
|
+
reason
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
`;
|
|
592
|
+
const variables = {
|
|
593
|
+
input: {
|
|
594
|
+
entityId: options.entityId,
|
|
595
|
+
entityType: options.entityType,
|
|
596
|
+
metricType: options.metricType,
|
|
597
|
+
requestedAmount: options.requestedAmount,
|
|
598
|
+
workspaceId: options.workspaceId || this.context.workspaceId,
|
|
599
|
+
organizationId: options.organizationId
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
const response = await this.client.query(query, variables, this.context);
|
|
603
|
+
logger.debug("[Usage] Quota check result", {
|
|
604
|
+
allowed: response.checkQuota.allowed
|
|
605
|
+
});
|
|
606
|
+
return response.checkQuota;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Require quota (throws if exceeded)
|
|
610
|
+
*/
|
|
611
|
+
async requireQuota(options) {
|
|
612
|
+
const result = await this.checkQuota(options);
|
|
613
|
+
if (!result.allowed) {
|
|
614
|
+
throw new QuotaExceededError(result.reason || "Quota exceeded", {
|
|
615
|
+
entityId: options.entityId,
|
|
616
|
+
metricType: options.metricType,
|
|
617
|
+
currentUsage: result.currentUsage,
|
|
618
|
+
quotaLimit: result.quotaLimit,
|
|
619
|
+
requestedAmount: options.requestedAmount,
|
|
620
|
+
resetAt: result.resetAt
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Track usage and check quota atomically
|
|
626
|
+
*/
|
|
627
|
+
async trackAndCheck(options) {
|
|
628
|
+
const quotaCheck = await this.checkQuota({
|
|
629
|
+
entityId: options.entityId,
|
|
630
|
+
entityType: options.entityType,
|
|
631
|
+
metricType: options.metricType,
|
|
632
|
+
requestedAmount: options.amount,
|
|
633
|
+
workspaceId: options.workspaceId,
|
|
634
|
+
organizationId: options.organizationId
|
|
635
|
+
});
|
|
636
|
+
if (!quotaCheck.allowed) {
|
|
637
|
+
throw new QuotaExceededError(quotaCheck.reason || "Quota exceeded", {
|
|
638
|
+
entityId: options.entityId,
|
|
639
|
+
metricType: options.metricType,
|
|
640
|
+
currentUsage: quotaCheck.currentUsage,
|
|
641
|
+
quotaLimit: quotaCheck.quotaLimit
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
const usage = await this.track(options);
|
|
645
|
+
return {
|
|
646
|
+
usage,
|
|
647
|
+
quotaCheck
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Get usage records
|
|
652
|
+
*/
|
|
653
|
+
async getUsage(options) {
|
|
654
|
+
logger.debug("[Usage] Getting usage records", {
|
|
655
|
+
entityId: options.entityId
|
|
656
|
+
});
|
|
657
|
+
const query = `
|
|
658
|
+
query GetUsage(
|
|
659
|
+
$entityId: ID!
|
|
660
|
+
$entityType: String!
|
|
661
|
+
$metricType: UsageMetricType
|
|
662
|
+
$startDate: DateTime
|
|
663
|
+
$endDate: DateTime
|
|
664
|
+
$workspaceId: ID
|
|
665
|
+
$organizationId: ID
|
|
666
|
+
$limit: Int
|
|
667
|
+
$offset: Int
|
|
668
|
+
) {
|
|
669
|
+
getUsage(
|
|
670
|
+
entityId: $entityId
|
|
671
|
+
entityType: $entityType
|
|
672
|
+
metricType: $metricType
|
|
673
|
+
startDate: $startDate
|
|
674
|
+
endDate: $endDate
|
|
675
|
+
workspaceId: $workspaceId
|
|
676
|
+
organizationId: $organizationId
|
|
677
|
+
limit: $limit
|
|
678
|
+
offset: $offset
|
|
679
|
+
) {
|
|
680
|
+
records {
|
|
681
|
+
id
|
|
682
|
+
entityId
|
|
683
|
+
entityType
|
|
684
|
+
metricType
|
|
685
|
+
amount
|
|
686
|
+
resourceId
|
|
687
|
+
metadata
|
|
688
|
+
workspaceId
|
|
689
|
+
organizationId
|
|
690
|
+
recordedAt
|
|
691
|
+
}
|
|
692
|
+
total
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
`;
|
|
696
|
+
const variables = {
|
|
697
|
+
entityId: options.entityId,
|
|
698
|
+
entityType: options.entityType,
|
|
699
|
+
metricType: options.metricType,
|
|
700
|
+
startDate: options.startDate,
|
|
701
|
+
endDate: options.endDate,
|
|
702
|
+
workspaceId: options.workspaceId || this.context.workspaceId,
|
|
703
|
+
organizationId: options.organizationId,
|
|
704
|
+
limit: options.limit || 100,
|
|
705
|
+
offset: options.offset || 0
|
|
706
|
+
};
|
|
707
|
+
const response = await this.client.query(query, variables, this.context);
|
|
708
|
+
return response.getUsage;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Get usage summary
|
|
712
|
+
*/
|
|
713
|
+
async getSummary(entityId, entityType, metricType, period) {
|
|
714
|
+
logger.debug("[Usage] Getting usage summary", {
|
|
715
|
+
entityId,
|
|
716
|
+
metricType,
|
|
717
|
+
period
|
|
718
|
+
});
|
|
719
|
+
const query = `
|
|
720
|
+
query GetUsageSummary(
|
|
721
|
+
$entityId: ID!
|
|
722
|
+
$entityType: String!
|
|
723
|
+
$metricType: UsageMetricType!
|
|
724
|
+
$period: QuotaPeriod!
|
|
725
|
+
) {
|
|
726
|
+
getUsageSummary(
|
|
727
|
+
entityId: $entityId
|
|
728
|
+
entityType: $entityType
|
|
729
|
+
metricType: $metricType
|
|
730
|
+
period: $period
|
|
731
|
+
) {
|
|
732
|
+
entityId
|
|
733
|
+
entityType
|
|
734
|
+
metricType
|
|
735
|
+
totalUsage
|
|
736
|
+
period
|
|
737
|
+
periodStart
|
|
738
|
+
periodEnd
|
|
739
|
+
quotaLimit
|
|
740
|
+
utilizationPercentage
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
`;
|
|
744
|
+
const response = await this.client.query(query, {
|
|
745
|
+
entityId,
|
|
746
|
+
entityType,
|
|
747
|
+
metricType,
|
|
748
|
+
period
|
|
749
|
+
}, this.context);
|
|
750
|
+
return response.getUsageSummary;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Set quota limit
|
|
754
|
+
*/
|
|
755
|
+
async setQuota(options) {
|
|
756
|
+
if (!options.entityId) {
|
|
757
|
+
throw new ValidationError("Entity ID is required");
|
|
758
|
+
}
|
|
759
|
+
if (!options.metricType) {
|
|
760
|
+
throw new ValidationError("Metric type is required");
|
|
761
|
+
}
|
|
762
|
+
if (typeof options.limit !== "number" || options.limit < 0) {
|
|
763
|
+
throw new ValidationError("Limit must be a non-negative number");
|
|
764
|
+
}
|
|
765
|
+
logger.debug("[Usage] Setting quota", {
|
|
766
|
+
entityId: options.entityId,
|
|
767
|
+
metricType: options.metricType,
|
|
768
|
+
limit: options.limit
|
|
769
|
+
});
|
|
770
|
+
const mutation = `
|
|
771
|
+
mutation SetQuota($input: SetQuotaInput!) {
|
|
772
|
+
setQuota(input: $input) {
|
|
773
|
+
id
|
|
774
|
+
entityId
|
|
775
|
+
entityType
|
|
776
|
+
metricType
|
|
777
|
+
limit
|
|
778
|
+
period
|
|
779
|
+
currentUsage
|
|
780
|
+
resetAt
|
|
781
|
+
createdAt
|
|
782
|
+
updatedAt
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
`;
|
|
786
|
+
const variables = {
|
|
787
|
+
input: {
|
|
788
|
+
entityId: options.entityId,
|
|
789
|
+
entityType: options.entityType,
|
|
790
|
+
metricType: options.metricType,
|
|
791
|
+
limit: options.limit,
|
|
792
|
+
period: options.period,
|
|
793
|
+
workspaceId: options.workspaceId || this.context.workspaceId,
|
|
794
|
+
organizationId: options.organizationId
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
const response = await this.client.query(mutation, variables, this.context);
|
|
798
|
+
logger.info("[Usage] Quota set", {
|
|
799
|
+
quotaId: response.setQuota.id
|
|
800
|
+
});
|
|
801
|
+
return response.setQuota;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Get quota
|
|
805
|
+
*/
|
|
806
|
+
async getQuota(entityId, entityType, metricType) {
|
|
807
|
+
logger.debug("[Usage] Getting quota", {
|
|
808
|
+
entityId,
|
|
809
|
+
metricType
|
|
810
|
+
});
|
|
811
|
+
const query = `
|
|
812
|
+
query GetQuota($entityId: ID!, $entityType: String!, $metricType: UsageMetricType!) {
|
|
813
|
+
getQuota(entityId: $entityId, entityType: $entityType, metricType: $metricType) {
|
|
814
|
+
id
|
|
815
|
+
entityId
|
|
816
|
+
entityType
|
|
817
|
+
metricType
|
|
818
|
+
limit
|
|
819
|
+
period
|
|
820
|
+
currentUsage
|
|
821
|
+
resetAt
|
|
822
|
+
createdAt
|
|
823
|
+
updatedAt
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
`;
|
|
827
|
+
const response = await this.client.query(query, {
|
|
828
|
+
entityId,
|
|
829
|
+
entityType,
|
|
830
|
+
metricType
|
|
831
|
+
}, this.context);
|
|
832
|
+
return response.getQuota;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Get all quotas for entity
|
|
836
|
+
*/
|
|
837
|
+
async getQuotas(entityId, entityType) {
|
|
838
|
+
logger.debug("[Usage] Getting all quotas", {
|
|
839
|
+
entityId,
|
|
840
|
+
entityType
|
|
841
|
+
});
|
|
842
|
+
const query = `
|
|
843
|
+
query GetQuotas($entityId: ID!, $entityType: String!) {
|
|
844
|
+
getQuotas(entityId: $entityId, entityType: $entityType) {
|
|
845
|
+
id
|
|
846
|
+
entityId
|
|
847
|
+
entityType
|
|
848
|
+
metricType
|
|
849
|
+
limit
|
|
850
|
+
period
|
|
851
|
+
currentUsage
|
|
852
|
+
resetAt
|
|
853
|
+
createdAt
|
|
854
|
+
updatedAt
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
`;
|
|
858
|
+
const response = await this.client.query(query, {
|
|
859
|
+
entityId,
|
|
860
|
+
entityType
|
|
861
|
+
}, this.context);
|
|
862
|
+
return response.getQuotas;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Reset quota usage
|
|
866
|
+
*/
|
|
867
|
+
async resetQuota(entityId, entityType, metricType) {
|
|
868
|
+
logger.debug("[Usage] Resetting quota", {
|
|
869
|
+
entityId,
|
|
870
|
+
metricType
|
|
871
|
+
});
|
|
872
|
+
const mutation = `
|
|
873
|
+
mutation ResetQuota($entityId: ID!, $entityType: String!, $metricType: UsageMetricType!) {
|
|
874
|
+
resetQuota(entityId: $entityId, entityType: $entityType, metricType: $metricType) {
|
|
875
|
+
success
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
`;
|
|
879
|
+
await this.client.query(mutation, {
|
|
880
|
+
entityId,
|
|
881
|
+
entityType,
|
|
882
|
+
metricType
|
|
883
|
+
}, this.context);
|
|
884
|
+
logger.info("[Usage] Quota reset", {
|
|
885
|
+
entityId,
|
|
886
|
+
metricType
|
|
887
|
+
});
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Delete quota
|
|
892
|
+
*/
|
|
893
|
+
async deleteQuota(entityId, entityType, metricType) {
|
|
894
|
+
logger.debug("[Usage] Deleting quota", {
|
|
895
|
+
entityId,
|
|
896
|
+
metricType
|
|
897
|
+
});
|
|
898
|
+
const mutation = `
|
|
899
|
+
mutation DeleteQuota($entityId: ID!, $entityType: String!, $metricType: UsageMetricType!) {
|
|
900
|
+
deleteQuota(entityId: $entityId, entityType: $entityType, metricType: $metricType) {
|
|
901
|
+
success
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
`;
|
|
905
|
+
await this.client.query(mutation, {
|
|
906
|
+
entityId,
|
|
907
|
+
entityType,
|
|
908
|
+
metricType
|
|
909
|
+
}, this.context);
|
|
910
|
+
logger.info("[Usage] Quota deleted", {
|
|
911
|
+
entityId,
|
|
912
|
+
metricType
|
|
913
|
+
});
|
|
914
|
+
return true;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Bulk track usage
|
|
918
|
+
*/
|
|
919
|
+
async trackBulk(records) {
|
|
920
|
+
logger.debug("[Usage] Bulk tracking usage", {
|
|
921
|
+
count: records.length
|
|
922
|
+
});
|
|
923
|
+
const mutation = `
|
|
924
|
+
mutation TrackUsageBulk($records: [TrackUsageInput!]!) {
|
|
925
|
+
trackUsageBulk(records: $records) {
|
|
926
|
+
id
|
|
927
|
+
entityId
|
|
928
|
+
entityType
|
|
929
|
+
metricType
|
|
930
|
+
amount
|
|
931
|
+
resourceId
|
|
932
|
+
metadata
|
|
933
|
+
workspaceId
|
|
934
|
+
organizationId
|
|
935
|
+
recordedAt
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
`;
|
|
939
|
+
const response = await this.client.query(mutation, {
|
|
940
|
+
records
|
|
941
|
+
}, this.context);
|
|
942
|
+
logger.info("[Usage] Bulk usage tracked", {
|
|
943
|
+
count: response.trackUsageBulk.length
|
|
944
|
+
});
|
|
945
|
+
return response.trackUsageBulk;
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
// src/tracker/stub.ts
|
|
950
|
+
var _gatewayUrl;
|
|
951
|
+
var _gatewayUrlResolved = false;
|
|
952
|
+
function getGatewayUrl() {
|
|
953
|
+
if (!_gatewayUrlResolved) {
|
|
954
|
+
_gatewayUrl = process.env["WSPACE_INT_GATEWAY_URL"] ?? process.env["GLOBAL_INT_GATEWAY_URL"] ?? void 0;
|
|
955
|
+
_gatewayUrlResolved = true;
|
|
956
|
+
if (_gatewayUrl) {
|
|
957
|
+
logger.info(`[trackOperation] Real tracking enabled via gateway: ${_gatewayUrl}`);
|
|
958
|
+
} else {
|
|
959
|
+
logger.debug("[trackOperation] No gateway URL configured \u2014 running in stub mode");
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return _gatewayUrl;
|
|
963
|
+
}
|
|
964
|
+
__name(getGatewayUrl, "getGatewayUrl");
|
|
965
|
+
var LOG_ACTIVITY_MUTATION = (
|
|
966
|
+
/* GraphQL */
|
|
967
|
+
`
|
|
968
|
+
mutation RecordActivity($input: RecordActivityInput!) {
|
|
969
|
+
recordActivity(input: $input) {
|
|
970
|
+
id
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
`
|
|
974
|
+
);
|
|
975
|
+
async function fireActivityLog(gatewayUrl, options) {
|
|
976
|
+
try {
|
|
977
|
+
const actOpts = options.activityOptions;
|
|
978
|
+
const input = {
|
|
979
|
+
activityType: actOpts?.activityType ?? options.operationName ?? "unknown",
|
|
980
|
+
description: actOpts?.description ?? `${options.operationName ?? "operation"} executed`,
|
|
981
|
+
workspaceId: actOpts?.workspaceId ?? options.workspaceId,
|
|
982
|
+
resourceType: actOpts?.resourceType ?? options.resourceType,
|
|
983
|
+
resourceId: actOpts?.resourceId ?? options.resourceId,
|
|
984
|
+
metadata: {
|
|
985
|
+
...actOpts?.metadata,
|
|
986
|
+
userId: options.userId,
|
|
987
|
+
success: options.success ?? true,
|
|
988
|
+
...options.errorMessage ? {
|
|
989
|
+
errorMessage: options.errorMessage
|
|
990
|
+
} : {}
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
for (const key of Object.keys(input)) {
|
|
994
|
+
if (input[key] === void 0) delete input[key];
|
|
995
|
+
}
|
|
996
|
+
const headers = {
|
|
997
|
+
"Content-Type": "application/json"
|
|
998
|
+
};
|
|
999
|
+
if (options.userId) {
|
|
1000
|
+
headers["x-actor-id"] = options.userId;
|
|
1001
|
+
headers["x-actor-type"] = "service";
|
|
1002
|
+
}
|
|
1003
|
+
if (options.workspaceId ?? actOpts?.workspaceId) {
|
|
1004
|
+
headers["x-workspace-id"] = options.workspaceId ?? actOpts?.workspaceId;
|
|
1005
|
+
}
|
|
1006
|
+
const response = await fetch(gatewayUrl, {
|
|
1007
|
+
method: "POST",
|
|
1008
|
+
headers,
|
|
1009
|
+
body: JSON.stringify({
|
|
1010
|
+
query: LOG_ACTIVITY_MUTATION,
|
|
1011
|
+
variables: {
|
|
1012
|
+
input
|
|
1013
|
+
}
|
|
1014
|
+
}),
|
|
1015
|
+
signal: AbortSignal.timeout(5e3)
|
|
1016
|
+
});
|
|
1017
|
+
if (!response.ok) {
|
|
1018
|
+
logger.warn(`[trackOperation] Activity log HTTP ${response.status}: ${options.operationName}`);
|
|
1019
|
+
}
|
|
1020
|
+
} catch (err) {
|
|
1021
|
+
logger.warn(`[trackOperation] Activity log failed: ${err.message}`);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
__name(fireActivityLog, "fireActivityLog");
|
|
1025
|
+
var UnifiedTrackerStub = class _UnifiedTrackerStub {
|
|
1026
|
+
static {
|
|
1027
|
+
__name(this, "UnifiedTrackerStub");
|
|
1028
|
+
}
|
|
1029
|
+
static instance;
|
|
1030
|
+
static getInstance() {
|
|
1031
|
+
if (!_UnifiedTrackerStub.instance) {
|
|
1032
|
+
_UnifiedTrackerStub.instance = new _UnifiedTrackerStub();
|
|
1033
|
+
}
|
|
1034
|
+
return _UnifiedTrackerStub.instance;
|
|
1035
|
+
}
|
|
1036
|
+
async track(event) {
|
|
1037
|
+
const gatewayUrl = getGatewayUrl();
|
|
1038
|
+
if (gatewayUrl) {
|
|
1039
|
+
await fireActivityLog(gatewayUrl, {
|
|
1040
|
+
operationName: event.eventType,
|
|
1041
|
+
userId: event.userId,
|
|
1042
|
+
workspaceId: event.workspaceId,
|
|
1043
|
+
resourceType: event.entityType,
|
|
1044
|
+
resourceId: event.entityId,
|
|
1045
|
+
activityOptions: {
|
|
1046
|
+
activityType: event.eventType,
|
|
1047
|
+
metadata: event.metadata,
|
|
1048
|
+
workspaceId: event.workspaceId,
|
|
1049
|
+
resourceType: event.entityType,
|
|
1050
|
+
resourceId: event.entityId,
|
|
1051
|
+
enabled: true
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
} else {
|
|
1055
|
+
logger.debug("[UnifiedTracker:Stub]", event.eventType, event.entityType, event.entityId);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
async trackBatch(events) {
|
|
1059
|
+
for (const event of events) {
|
|
1060
|
+
await this.track(event);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
var trackerStub = UnifiedTrackerStub.getInstance();
|
|
1065
|
+
async function trackOperation(options) {
|
|
1066
|
+
const { operationName, userId, success = true } = options;
|
|
1067
|
+
const gatewayUrl = getGatewayUrl();
|
|
1068
|
+
if (!gatewayUrl) {
|
|
1069
|
+
logger.debug(`[trackOperation:Stub] ${operationName} for user ${userId} - success: ${success}`);
|
|
1070
|
+
return true;
|
|
1071
|
+
}
|
|
1072
|
+
const activityEnabled = options.activityOptions?.enabled !== false;
|
|
1073
|
+
if (activityEnabled) {
|
|
1074
|
+
void fireActivityLog(gatewayUrl, options);
|
|
1075
|
+
} else {
|
|
1076
|
+
logger.debug(`[trackOperation] ${operationName} for user ${userId} - activity disabled, skipping`);
|
|
1077
|
+
}
|
|
1078
|
+
return true;
|
|
1079
|
+
}
|
|
1080
|
+
__name(trackOperation, "trackOperation");
|
|
1081
|
+
function createProductTracker(productId, userId, billingAccountId, defaultContext) {
|
|
1082
|
+
return {
|
|
1083
|
+
async track(operationName, additionalOptions) {
|
|
1084
|
+
return trackOperation({
|
|
1085
|
+
...defaultContext,
|
|
1086
|
+
productId,
|
|
1087
|
+
operationName,
|
|
1088
|
+
userId,
|
|
1089
|
+
...additionalOptions
|
|
1090
|
+
});
|
|
1091
|
+
},
|
|
1092
|
+
async freeUp(operationName, additionalOptions) {
|
|
1093
|
+
return trackOperation({
|
|
1094
|
+
...defaultContext,
|
|
1095
|
+
productId,
|
|
1096
|
+
operationName,
|
|
1097
|
+
userId,
|
|
1098
|
+
...additionalOptions,
|
|
1099
|
+
activityOptions: {
|
|
1100
|
+
...defaultContext?.activityOptions,
|
|
1101
|
+
...additionalOptions?.activityOptions,
|
|
1102
|
+
activityType: "free_up"
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
},
|
|
1106
|
+
async trackActivityOnly(operationName, additionalOptions) {
|
|
1107
|
+
return trackOperation({
|
|
1108
|
+
...defaultContext,
|
|
1109
|
+
productId,
|
|
1110
|
+
operationName,
|
|
1111
|
+
userId,
|
|
1112
|
+
...additionalOptions,
|
|
1113
|
+
activityOptions: {
|
|
1114
|
+
...defaultContext?.activityOptions,
|
|
1115
|
+
...additionalOptions?.activityOptions,
|
|
1116
|
+
enabled: true
|
|
1117
|
+
},
|
|
1118
|
+
usageOptions: {
|
|
1119
|
+
enabled: false
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
},
|
|
1123
|
+
async trackUsageOnly(operationName, additionalOptions) {
|
|
1124
|
+
return trackOperation({
|
|
1125
|
+
...defaultContext,
|
|
1126
|
+
productId,
|
|
1127
|
+
operationName,
|
|
1128
|
+
userId,
|
|
1129
|
+
...additionalOptions,
|
|
1130
|
+
activityOptions: {
|
|
1131
|
+
enabled: false
|
|
1132
|
+
},
|
|
1133
|
+
usageOptions: {
|
|
1134
|
+
...defaultContext?.usageOptions,
|
|
1135
|
+
...additionalOptions?.usageOptions,
|
|
1136
|
+
enabled: true
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
},
|
|
1140
|
+
async trackCustom(operationName, additionalOptions) {
|
|
1141
|
+
return trackOperation({
|
|
1142
|
+
...defaultContext,
|
|
1143
|
+
productId,
|
|
1144
|
+
operationName,
|
|
1145
|
+
userId,
|
|
1146
|
+
...additionalOptions
|
|
1147
|
+
});
|
|
1148
|
+
},
|
|
1149
|
+
productId,
|
|
1150
|
+
userId,
|
|
1151
|
+
billingAccountId,
|
|
1152
|
+
defaultContext
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
__name(createProductTracker, "createProductTracker");
|
|
1156
|
+
var UNIFIED_TRACKER_CONSTANTS = {
|
|
1157
|
+
DEFAULT_PRODUCT_ID: "module",
|
|
1158
|
+
OPERATIONS: {},
|
|
1159
|
+
PRODUCTS: {}
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
// src/tracker/index.ts
|
|
1163
|
+
var TrackerModule = class {
|
|
1164
|
+
static {
|
|
1165
|
+
__name(this, "TrackerModule");
|
|
1166
|
+
}
|
|
1167
|
+
context;
|
|
1168
|
+
rbac;
|
|
1169
|
+
activity;
|
|
1170
|
+
usage;
|
|
1171
|
+
notifications;
|
|
1172
|
+
constructor(client, context = {}) {
|
|
1173
|
+
this.context = context;
|
|
1174
|
+
this.rbac = new RBACModule(client, context);
|
|
1175
|
+
this.activity = new ActivityModule(client, context);
|
|
1176
|
+
this.usage = new UsageModule(client, context);
|
|
1177
|
+
this.notifications = new NotificationsModule(client, context);
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Track operation with RBAC, Activity, Usage, and Notifications
|
|
1181
|
+
* This is the primary method products should use
|
|
1182
|
+
*/
|
|
1183
|
+
async track(options) {
|
|
1184
|
+
const startTime = Date.now();
|
|
1185
|
+
const result = {
|
|
1186
|
+
success: false,
|
|
1187
|
+
permissionGranted: false,
|
|
1188
|
+
duration: 0
|
|
1189
|
+
};
|
|
1190
|
+
try {
|
|
1191
|
+
this.validateOptions(options);
|
|
1192
|
+
if (options.rbac?.enabled !== false) {
|
|
1193
|
+
await this.checkPermission(options, result);
|
|
1194
|
+
if (!result.permissionGranted) {
|
|
1195
|
+
result.duration = Date.now() - startTime;
|
|
1196
|
+
await this.logFailedActivity(options, result, startTime);
|
|
1197
|
+
return result;
|
|
1198
|
+
}
|
|
1199
|
+
} else {
|
|
1200
|
+
result.permissionGranted = true;
|
|
1201
|
+
}
|
|
1202
|
+
if (options.usage?.enabled !== false && options.usage?.checkQuota !== false) {
|
|
1203
|
+
await this.checkQuota(options, result);
|
|
1204
|
+
if (result.quotaAvailable === false) {
|
|
1205
|
+
result.duration = Date.now() - startTime;
|
|
1206
|
+
await this.logFailedActivity(options, result, startTime);
|
|
1207
|
+
return result;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (options.usage?.enabled !== false && options.usage?.metricType) {
|
|
1211
|
+
await this.trackUsage(options, result);
|
|
1212
|
+
}
|
|
1213
|
+
if (options.activity?.enabled !== false) {
|
|
1214
|
+
await this.logSuccessActivity(options, result, startTime);
|
|
1215
|
+
}
|
|
1216
|
+
if (options.notification?.onSuccess) {
|
|
1217
|
+
await this.sendSuccessNotification(options, result);
|
|
1218
|
+
}
|
|
1219
|
+
result.success = true;
|
|
1220
|
+
result.duration = Date.now() - startTime;
|
|
1221
|
+
logger.info("[Tracker] Operation tracked successfully", {
|
|
1222
|
+
action: options.action,
|
|
1223
|
+
duration: result.duration
|
|
1224
|
+
});
|
|
1225
|
+
return result;
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
result.duration = Date.now() - startTime;
|
|
1228
|
+
result.success = false;
|
|
1229
|
+
if (error instanceof PermissionDeniedError) {
|
|
1230
|
+
result.error = {
|
|
1231
|
+
type: "permission",
|
|
1232
|
+
message: error.message,
|
|
1233
|
+
details: error.details
|
|
1234
|
+
};
|
|
1235
|
+
} else if (error instanceof QuotaExceededError) {
|
|
1236
|
+
result.error = {
|
|
1237
|
+
type: "quota",
|
|
1238
|
+
message: error.message,
|
|
1239
|
+
details: error.details
|
|
1240
|
+
};
|
|
1241
|
+
} else if (error instanceof ValidationError) {
|
|
1242
|
+
result.error = {
|
|
1243
|
+
type: "validation",
|
|
1244
|
+
message: error.message,
|
|
1245
|
+
details: error.details
|
|
1246
|
+
};
|
|
1247
|
+
} else {
|
|
1248
|
+
result.error = {
|
|
1249
|
+
type: "unknown",
|
|
1250
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
await this.logFailedActivity(options, result, startTime);
|
|
1254
|
+
if (options.notification?.onFailure) {
|
|
1255
|
+
await this.sendFailureNotification(options, result);
|
|
1256
|
+
}
|
|
1257
|
+
logger.error("[Tracker] Operation tracking failed", {
|
|
1258
|
+
action: options.action,
|
|
1259
|
+
error: result.error,
|
|
1260
|
+
duration: result.duration
|
|
1261
|
+
});
|
|
1262
|
+
return result;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Track operation and throw on failure
|
|
1267
|
+
* Convenience method that throws errors instead of returning them in result
|
|
1268
|
+
*/
|
|
1269
|
+
async trackOrThrow(options) {
|
|
1270
|
+
const result = await this.track(options);
|
|
1271
|
+
if (!result.success && result.error) {
|
|
1272
|
+
const errorMessage = result.error.message;
|
|
1273
|
+
const errorDetails = result.error.details;
|
|
1274
|
+
switch (result.error.type) {
|
|
1275
|
+
case "permission":
|
|
1276
|
+
throw new PermissionDeniedError(errorMessage, errorDetails);
|
|
1277
|
+
case "quota":
|
|
1278
|
+
throw new QuotaExceededError(errorMessage, errorDetails);
|
|
1279
|
+
case "validation":
|
|
1280
|
+
throw new ValidationError(errorMessage, errorDetails);
|
|
1281
|
+
default:
|
|
1282
|
+
throw new Error(errorMessage);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
return result;
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Simplified track method for common operations
|
|
1289
|
+
*/
|
|
1290
|
+
async trackSimple(userId, action, resourceType, resourceId, metricType) {
|
|
1291
|
+
const result = await this.track({
|
|
1292
|
+
userId,
|
|
1293
|
+
action,
|
|
1294
|
+
resourceType,
|
|
1295
|
+
resourceId,
|
|
1296
|
+
workspaceId: this.context.workspaceId,
|
|
1297
|
+
usage: metricType ? {
|
|
1298
|
+
enabled: true,
|
|
1299
|
+
metricType,
|
|
1300
|
+
amount: 1,
|
|
1301
|
+
checkQuota: true
|
|
1302
|
+
} : {
|
|
1303
|
+
enabled: false,
|
|
1304
|
+
metricType: "api_calls"
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
return result.success;
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Validate tracking options
|
|
1311
|
+
*/
|
|
1312
|
+
validateOptions(options) {
|
|
1313
|
+
if (!options.userId) {
|
|
1314
|
+
throw new ValidationError("User ID is required");
|
|
1315
|
+
}
|
|
1316
|
+
if (!options.action) {
|
|
1317
|
+
throw new ValidationError("Action is required");
|
|
1318
|
+
}
|
|
1319
|
+
if (!options.resourceType) {
|
|
1320
|
+
throw new ValidationError("Resource type is required");
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Check RBAC permission
|
|
1325
|
+
*/
|
|
1326
|
+
async checkPermission(options, result) {
|
|
1327
|
+
const permissionOptions = {
|
|
1328
|
+
userId: options.userId,
|
|
1329
|
+
action: options.rbac?.permissionAction || options.action,
|
|
1330
|
+
resourceType: options.resourceType,
|
|
1331
|
+
resourceId: options.resourceId,
|
|
1332
|
+
workspaceId: options.workspaceId
|
|
1333
|
+
};
|
|
1334
|
+
const hasPermission = await this.rbac.checkPermission(permissionOptions);
|
|
1335
|
+
result.permissionGranted = hasPermission;
|
|
1336
|
+
if (!hasPermission) {
|
|
1337
|
+
result.error = {
|
|
1338
|
+
type: "permission",
|
|
1339
|
+
message: "Permission denied",
|
|
1340
|
+
details: permissionOptions
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Check quota availability
|
|
1346
|
+
*/
|
|
1347
|
+
async checkQuota(options, result) {
|
|
1348
|
+
if (!options.usage?.metricType) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
const entityType = options.usage.entityType || "user";
|
|
1352
|
+
let entityId;
|
|
1353
|
+
if (entityType === "workspace") {
|
|
1354
|
+
entityId = options.workspaceId || options.userId;
|
|
1355
|
+
} else if (entityType === "organization") {
|
|
1356
|
+
entityId = options.organizationId || options.userId;
|
|
1357
|
+
} else {
|
|
1358
|
+
entityId = options.userId;
|
|
1359
|
+
}
|
|
1360
|
+
const quotaCheck = await this.usage.checkQuota({
|
|
1361
|
+
entityId,
|
|
1362
|
+
entityType,
|
|
1363
|
+
metricType: options.usage.metricType,
|
|
1364
|
+
requestedAmount: options.usage.amount || 1,
|
|
1365
|
+
workspaceId: options.workspaceId,
|
|
1366
|
+
organizationId: options.organizationId
|
|
1367
|
+
});
|
|
1368
|
+
result.quotaAvailable = quotaCheck.allowed;
|
|
1369
|
+
result.quotaRemaining = quotaCheck.remainingQuota;
|
|
1370
|
+
if (!quotaCheck.allowed) {
|
|
1371
|
+
result.error = {
|
|
1372
|
+
type: "quota",
|
|
1373
|
+
message: quotaCheck.reason || "Quota exceeded",
|
|
1374
|
+
details: {
|
|
1375
|
+
currentUsage: quotaCheck.currentUsage,
|
|
1376
|
+
quotaLimit: quotaCheck.quotaLimit,
|
|
1377
|
+
requestedAmount: options.usage.amount || 1
|
|
1378
|
+
}
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Track usage
|
|
1384
|
+
*/
|
|
1385
|
+
async trackUsage(options, result) {
|
|
1386
|
+
if (!options.usage?.metricType) {
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
const entityType = options.usage.entityType || "user";
|
|
1390
|
+
let entityId;
|
|
1391
|
+
if (entityType === "workspace") {
|
|
1392
|
+
entityId = options.workspaceId || options.userId;
|
|
1393
|
+
} else if (entityType === "organization") {
|
|
1394
|
+
entityId = options.organizationId || options.userId;
|
|
1395
|
+
} else {
|
|
1396
|
+
entityId = options.userId;
|
|
1397
|
+
}
|
|
1398
|
+
const trackOptions = {
|
|
1399
|
+
entityId,
|
|
1400
|
+
entityType,
|
|
1401
|
+
metricType: options.usage.metricType,
|
|
1402
|
+
amount: options.usage.amount || 1,
|
|
1403
|
+
resourceId: options.resourceId,
|
|
1404
|
+
workspaceId: options.workspaceId,
|
|
1405
|
+
organizationId: options.organizationId
|
|
1406
|
+
};
|
|
1407
|
+
const usageRecord = await this.usage.track(trackOptions);
|
|
1408
|
+
result.usageRecordId = usageRecord.id;
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Log successful activity
|
|
1412
|
+
*/
|
|
1413
|
+
async logSuccessActivity(options, result, startTime) {
|
|
1414
|
+
const activityRecord = await this.activity.log({
|
|
1415
|
+
userId: options.userId,
|
|
1416
|
+
activityType: options.activity?.activityType || this.inferActivityType(options.action),
|
|
1417
|
+
resourceType: options.resourceType,
|
|
1418
|
+
resourceId: options.resourceId,
|
|
1419
|
+
action: options.action,
|
|
1420
|
+
status: ActivityStatus.SUCCESS,
|
|
1421
|
+
workspaceId: options.workspaceId,
|
|
1422
|
+
organizationId: options.organizationId,
|
|
1423
|
+
projectId: options.projectId,
|
|
1424
|
+
ipAddress: options.activity?.ipAddress,
|
|
1425
|
+
userAgent: options.activity?.userAgent,
|
|
1426
|
+
metadata: options.activity?.metadata,
|
|
1427
|
+
severity: options.activity?.severity || ActivitySeverity.LOW,
|
|
1428
|
+
duration: Date.now() - startTime
|
|
1429
|
+
});
|
|
1430
|
+
result.activityId = activityRecord.id;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Log failed activity
|
|
1434
|
+
*/
|
|
1435
|
+
async logFailedActivity(options, result, startTime) {
|
|
1436
|
+
if (options.activity?.enabled === false) {
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
try {
|
|
1440
|
+
const activityRecord = await this.activity.log({
|
|
1441
|
+
userId: options.userId,
|
|
1442
|
+
activityType: options.activity?.activityType || this.inferActivityType(options.action),
|
|
1443
|
+
resourceType: options.resourceType,
|
|
1444
|
+
resourceId: options.resourceId,
|
|
1445
|
+
action: options.action,
|
|
1446
|
+
status: ActivityStatus.FAILURE,
|
|
1447
|
+
workspaceId: options.workspaceId,
|
|
1448
|
+
organizationId: options.organizationId,
|
|
1449
|
+
projectId: options.projectId,
|
|
1450
|
+
ipAddress: options.activity?.ipAddress,
|
|
1451
|
+
userAgent: options.activity?.userAgent,
|
|
1452
|
+
metadata: options.activity?.metadata,
|
|
1453
|
+
severity: ActivitySeverity.HIGH,
|
|
1454
|
+
errorMessage: result.error?.message,
|
|
1455
|
+
duration: Date.now() - startTime
|
|
1456
|
+
});
|
|
1457
|
+
result.activityId = activityRecord.id;
|
|
1458
|
+
} catch (error) {
|
|
1459
|
+
logger.error("[Tracker] Failed to log activity", {
|
|
1460
|
+
error
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Send success notification
|
|
1466
|
+
*/
|
|
1467
|
+
async sendSuccessNotification(options, result) {
|
|
1468
|
+
if (!options.notification?.onSuccess) {
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
try {
|
|
1472
|
+
const userIds = [
|
|
1473
|
+
options.userId,
|
|
1474
|
+
...options.notification.onSuccess.additionalUserIds || []
|
|
1475
|
+
];
|
|
1476
|
+
const response = await this.notifications.send({
|
|
1477
|
+
title: options.notification.onSuccess.title,
|
|
1478
|
+
message: options.notification.onSuccess.message,
|
|
1479
|
+
type: options.notification.onSuccess.type || NotificationType.SUCCESS,
|
|
1480
|
+
userIds
|
|
1481
|
+
});
|
|
1482
|
+
result.notificationIds = response.notificationIds;
|
|
1483
|
+
} catch (error) {
|
|
1484
|
+
logger.error("[Tracker] Failed to send success notification", {
|
|
1485
|
+
error
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Send failure notification
|
|
1491
|
+
*/
|
|
1492
|
+
async sendFailureNotification(options, result) {
|
|
1493
|
+
if (!options.notification?.onFailure) {
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
try {
|
|
1497
|
+
const userIds = [
|
|
1498
|
+
options.userId,
|
|
1499
|
+
...options.notification.onFailure.additionalUserIds || []
|
|
1500
|
+
];
|
|
1501
|
+
const response = await this.notifications.send({
|
|
1502
|
+
title: options.notification.onFailure.title,
|
|
1503
|
+
message: options.notification.onFailure.message,
|
|
1504
|
+
type: options.notification.onFailure.type || NotificationType.ERROR,
|
|
1505
|
+
userIds
|
|
1506
|
+
});
|
|
1507
|
+
result.notificationIds = response.notificationIds;
|
|
1508
|
+
} catch (error) {
|
|
1509
|
+
logger.error("[Tracker] Failed to send failure notification", {
|
|
1510
|
+
error
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Infer activity type from action
|
|
1516
|
+
*/
|
|
1517
|
+
inferActivityType(action) {
|
|
1518
|
+
const actionLower = action.toLowerCase();
|
|
1519
|
+
if (actionLower.includes("create") || actionLower.includes("add")) return ActivityType.CREATE;
|
|
1520
|
+
if (actionLower.includes("update") || actionLower.includes("edit")) return ActivityType.UPDATE;
|
|
1521
|
+
if (actionLower.includes("delete") || actionLower.includes("remove")) return ActivityType.DELETE;
|
|
1522
|
+
if (actionLower.includes("read") || actionLower.includes("view")) return ActivityType.READ;
|
|
1523
|
+
if (actionLower.includes("login")) return ActivityType.LOGIN;
|
|
1524
|
+
if (actionLower.includes("logout")) return ActivityType.LOGOUT;
|
|
1525
|
+
if (actionLower.includes("export")) return ActivityType.EXPORT;
|
|
1526
|
+
if (actionLower.includes("import")) return ActivityType.IMPORT;
|
|
1527
|
+
if (actionLower.includes("share")) return ActivityType.SHARE;
|
|
1528
|
+
if (actionLower.includes("download")) return ActivityType.DOWNLOAD;
|
|
1529
|
+
if (actionLower.includes("upload")) return ActivityType.UPLOAD;
|
|
1530
|
+
return ActivityType.CUSTOM;
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Batch track multiple operations
|
|
1534
|
+
*/
|
|
1535
|
+
async trackBatch(operations) {
|
|
1536
|
+
logger.debug("[Tracker] Batch tracking operations", {
|
|
1537
|
+
count: operations.length
|
|
1538
|
+
});
|
|
1539
|
+
const results = await Promise.all(operations.map((op) => this.track(op)));
|
|
1540
|
+
logger.info("[Tracker] Batch tracking completed", {
|
|
1541
|
+
total: results.length,
|
|
1542
|
+
successful: results.filter((r) => r.success).length,
|
|
1543
|
+
failed: results.filter((r) => !r.success).length
|
|
1544
|
+
});
|
|
1545
|
+
return results;
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
|
|
1549
|
+
export { ActivityModule, TrackerModule, UNIFIED_TRACKER_CONSTANTS, UnifiedTrackerStub, UsageMetricType, UsageModule, createProductTracker, trackOperation, trackerStub };
|
|
1550
|
+
//# sourceMappingURL=chunk-JVBTNSPG.js.map
|
|
1551
|
+
//# sourceMappingURL=chunk-JVBTNSPG.js.map
|