@musnows/scriverse 0.5.2 → 0.5.3

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/app.js CHANGED
@@ -28,7 +28,7 @@ import { currentRequestActor, runWithRequestActor } from "./request-context.js";
28
28
  import { APP_VERSION } from "./version.js";
29
29
  import { fullWorkModulePermissions, proseReplacementPermissionModules } from "./work-permissions.js";
30
30
  import { CollaborationPresence, editorPageKey, entityEditorPageKey, modulePageKey, pageLabelForKey, presencePageKinds } from "./collaboration-presence.js";
31
- import { clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, setSessionCookie, UserAuthService } from "./user-auth.js";
31
+ import { clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, relationshipAnalysisReadModules, setSessionCookie, UserAuthService } from "./user-auth.js";
32
32
  const nonEmpty = z.string().trim().min(1);
33
33
  const identifier = z.string().trim().min(1).max(200);
34
34
  const optionalStrings = z.array(z.string()).optional();
@@ -379,8 +379,8 @@ const relationshipAnalysisScopeSchema = z.object({
379
379
  }
380
380
  });
381
381
  const analysisTaskSchema = z.union([
382
- z.object({ taskType: z.literal("relationship-analysis"), scope: relationshipAnalysisScopeSchema.optional() }).strict(),
383
- z.object({ taskType: analysisTaskTypeSchema, scope: jsonObject.optional() }).strict().superRefine((input, context) => {
382
+ z.object({ taskType: z.literal("relationship-analysis"), scope: relationshipAnalysisScopeSchema.optional(), modelId: identifier.optional() }).strict(),
383
+ z.object({ taskType: analysisTaskTypeSchema, scope: jsonObject.optional(), modelId: identifier.optional() }).strict().superRefine((input, context) => {
384
384
  if (input.scope?.includeAllSettings !== undefined) {
385
385
  context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "includeAllSettings"], message: "包含所有设定仅支持人物关系分析" });
386
386
  }
@@ -570,7 +570,24 @@ export function createRuntime(options) {
570
570
  return auth.workModulePermissions(request.authUser, resolvedWorkId, request.authMethod !== "api-key") ?? fullWorkModulePermissions();
571
571
  };
572
572
  const captcha = new ImageCaptchaService({ revealAnswer: options.revealCaptchaAnswer === true });
573
- const ai = new AiManager(store, new CredentialVault(options.masterSecret), options.fetchImpl ?? fetch, options.security ? (url) => assertSafeAiEndpoint(url, options.security?.allowPrivateAiEndpoints) : undefined);
573
+ const ai = new AiManager(store, new CredentialVault(options.masterSecret), options.fetchImpl ?? fetch, options.security ? (url) => assertSafeAiEndpoint(url, options.security?.allowPrivateAiEndpoints) : undefined, (task, actor) => {
574
+ if (task.taskType !== "relationship-analysis")
575
+ return;
576
+ const requiredModules = relationshipAnalysisReadModules(task.scope);
577
+ if (requiredModules.length === 0)
578
+ return;
579
+ const creator = actor ? null : database.get("SELECT created_by_user_id FROM analysis_tasks WHERE id = ?", String(task.id));
580
+ const userId = actor?.userId ?? (typeof creator?.created_by_user_id === "string" ? creator.created_by_user_id : null);
581
+ if (!userId)
582
+ return;
583
+ const user = auth.getUser(userId);
584
+ if (user.status !== "active")
585
+ throw new AppError(403, "WORK_ACCESS_DENIED", "任务创建者已无法访问这部作品");
586
+ auth.assertWorkAccess(user, String(task.workId), {
587
+ read: requiredModules,
588
+ write: ["ai-analysis"]
589
+ }, false, actor?.allowAdminAccess ?? false);
590
+ });
574
591
  const app = express();
575
592
  const upload = multer({
576
593
  storage: multer.memoryStorage(),
@@ -1417,9 +1434,22 @@ export function createRuntime(options) {
1417
1434
  });
1418
1435
  app.post("/api/works/:workId/tasks", (request, response) => {
1419
1436
  const input = parse(analysisTaskSchema, request.body);
1420
- data(response, redactTaskCharacterNames(store.createTask(request.params.workId, input), requestPermissions(request, request.params.workId)), 201);
1437
+ data(response, redactTaskCharacterNames(ai.createTask(request.params.workId, input), requestPermissions(request, request.params.workId)), 201);
1421
1438
  });
1422
1439
  app.post("/api/works/:workId/tasks/auto-run", (request, response) => {
1440
+ const permissions = requestPermissions(request, request.params.workId);
1441
+ for (const taskId of store.listOldestPendingTaskIds(request.params.workId, store.countPendingTasks(request.params.workId))) {
1442
+ const task = store.getTask(taskId);
1443
+ if (task.taskType !== "relationship-analysis")
1444
+ continue;
1445
+ const deniedModules = relationshipAnalysisReadModules(task.scope).filter((module) => permissions[module] === "none");
1446
+ if (deniedModules.length > 0) {
1447
+ throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取待运行定向人物关系分析所需资料模块的权限", {
1448
+ taskId,
1449
+ modules: deniedModules
1450
+ });
1451
+ }
1452
+ }
1423
1453
  data(response, ai.startAutoRunBatch(request.params.workId));
1424
1454
  });
1425
1455
  app.get("/api/tasks/:taskId/detail", (request, response) => data(response, redactTaskCharacterNames(store.getTaskDetail(request.params.taskId), requestPermissions(request))));
@@ -1438,7 +1468,20 @@ export function createRuntime(options) {
1438
1468
  app.get("/api/tasks/:taskId/trace/calls/:callId", (request, response) => data(response, ai.getTaskTraceCall(request.params.taskId, request.params.callId)));
1439
1469
  app.post("/api/tasks/:taskId/run", async (request, response) => {
1440
1470
  const input = parse(z.object({ modelId: identifier.optional() }), request.body ?? {});
1441
- data(response, redactTaskCharacterNames(await ai.runTask(request.params.taskId, input.modelId), requestPermissions(request)));
1471
+ const task = store.getTask(request.params.taskId);
1472
+ if (task.taskType === "relationship-analysis") {
1473
+ const permissions = requestPermissions(request, String(task.workId));
1474
+ const deniedModules = relationshipAnalysisReadModules(task.scope).filter((module) => permissions[module] === "none");
1475
+ if (deniedModules.length > 0) {
1476
+ throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取本次定向人物关系分析所需资料模块的权限", {
1477
+ modules: deniedModules
1478
+ });
1479
+ }
1480
+ }
1481
+ data(response, redactTaskCharacterNames(await ai.runTask(request.params.taskId, input.modelId, request.authUser ? {
1482
+ userId: request.authUser.userId,
1483
+ allowAdminAccess: request.authMethod !== "api-key"
1484
+ } : undefined), requestPermissions(request)));
1442
1485
  });
1443
1486
  app.post("/api/tasks/:taskId/cancel", (request, response) => data(response, redactTaskCharacterNames(ai.cancelTask(request.params.taskId), requestPermissions(request))));
1444
1487
  app.get("/api/platform/ai/providers", (request, response) => {