@sfmc-bds/db-server 0.1.0 → 0.2.0-beta.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.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/dist/db-tables.js +16 -17
  3. package/dist/db-tables.js.map +7 -1
  4. package/dist/domain/bridge.js +54 -77
  5. package/dist/domain/bridge.js.map +7 -1
  6. package/dist/domain/economy.d.ts +83 -2
  7. package/dist/domain/economy.d.ts.map +1 -1
  8. package/dist/domain/economy.js +292 -281
  9. package/dist/domain/economy.js.map +7 -1
  10. package/dist/domain/schema.js +480 -426
  11. package/dist/domain/schema.js.map +7 -1
  12. package/dist/domain/transaction.js +32 -80
  13. package/dist/domain/transaction.js.map +7 -1
  14. package/dist/env.d.ts.map +1 -1
  15. package/dist/env.js +85 -84
  16. package/dist/env.js.map +7 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +218 -240
  20. package/dist/index.js.map +7 -1
  21. package/dist/lib/http.js +30 -39
  22. package/dist/lib/http.js.map +7 -1
  23. package/dist/lib/idempotency-store.js +34 -47
  24. package/dist/lib/idempotency-store.js.map +7 -1
  25. package/dist/lib/idempotency.js +8 -13
  26. package/dist/lib/idempotency.js.map +7 -1
  27. package/dist/lib/identifiers.js +18 -14
  28. package/dist/lib/identifiers.js.map +7 -1
  29. package/dist/lib/log.d.ts +3 -6
  30. package/dist/lib/log.d.ts.map +1 -1
  31. package/dist/lib/log.js +13 -14
  32. package/dist/lib/log.js.map +7 -1
  33. package/dist/lib/module-state.d.ts.map +1 -1
  34. package/dist/lib/module-state.js +32 -21
  35. package/dist/lib/module-state.js.map +7 -1
  36. package/dist/lib/order-by.d.ts +17 -0
  37. package/dist/lib/order-by.d.ts.map +1 -0
  38. package/dist/lib/order-by.js +24 -0
  39. package/dist/lib/order-by.js.map +7 -0
  40. package/dist/lib/runtime.js +16 -31
  41. package/dist/lib/runtime.js.map +7 -1
  42. package/dist/lib/sql-helpers.js +9 -27
  43. package/dist/lib/sql-helpers.js.map +7 -1
  44. package/dist/lib/sqlite.js +40 -52
  45. package/dist/lib/sqlite.js.map +7 -1
  46. package/dist/manifest-loader.d.ts.map +1 -1
  47. package/dist/manifest-loader.js +154 -195
  48. package/dist/manifest-loader.js.map +7 -1
  49. package/dist/manifest.d.ts +3 -7
  50. package/dist/manifest.d.ts.map +1 -1
  51. package/dist/manifest.js +76 -115
  52. package/dist/manifest.js.map +7 -1
  53. package/dist/module-auth.d.ts +17 -6
  54. package/dist/module-auth.d.ts.map +1 -1
  55. package/dist/module-auth.js +93 -107
  56. package/dist/module-auth.js.map +7 -1
  57. package/dist/module-runtime-sync.d.ts +37 -0
  58. package/dist/module-runtime-sync.d.ts.map +1 -0
  59. package/dist/module-runtime-sync.js +54 -0
  60. package/dist/module-runtime-sync.js.map +7 -0
  61. package/dist/permission-gate.d.ts.map +1 -1
  62. package/dist/permission-gate.js +55 -86
  63. package/dist/permission-gate.js.map +7 -1
  64. package/dist/routes/_shared.d.ts +7 -2
  65. package/dist/routes/_shared.d.ts.map +1 -1
  66. package/dist/routes/_shared.js +16 -25
  67. package/dist/routes/_shared.js.map +7 -1
  68. package/dist/routes/config.d.ts +11 -1
  69. package/dist/routes/config.d.ts.map +1 -1
  70. package/dist/routes/config.js +167 -213
  71. package/dist/routes/config.js.map +7 -1
  72. package/dist/routes/db-routes.d.ts +6 -10
  73. package/dist/routes/db-routes.d.ts.map +1 -1
  74. package/dist/routes/db-routes.js +198 -172
  75. package/dist/routes/db-routes.js.map +7 -1
  76. package/dist/routes/health.js +15 -20
  77. package/dist/routes/health.js.map +7 -1
  78. package/dist/routes/messages.d.ts.map +1 -1
  79. package/dist/routes/messages.js +56 -63
  80. package/dist/routes/messages.js.map +7 -1
  81. package/dist/routes/module-config-routes.d.ts.map +1 -1
  82. package/dist/routes/module-config-routes.js +92 -111
  83. package/dist/routes/module-config-routes.js.map +7 -1
  84. package/dist/routes/modules.d.ts.map +1 -1
  85. package/dist/routes/modules.js +82 -88
  86. package/dist/routes/modules.js.map +7 -1
  87. package/dist/routes/service-routes.d.ts.map +1 -1
  88. package/dist/routes/service-routes.js +54 -61
  89. package/dist/routes/service-routes.js.map +7 -1
  90. package/dist/runtime.test.js +248 -49
  91. package/dist/runtime.test.js.map +7 -1
  92. package/dist/schema-registry.d.ts.map +1 -1
  93. package/dist/schema-registry.js +119 -160
  94. package/dist/schema-registry.js.map +7 -1
  95. package/dist/server.js +69 -72
  96. package/dist/server.js.map +7 -1
  97. package/dist/service-registry.d.ts.map +1 -1
  98. package/dist/service-registry.js +60 -67
  99. package/dist/service-registry.js.map +7 -1
  100. package/dist/services/builtin-handlers.d.ts +4 -0
  101. package/dist/services/builtin-handlers.d.ts.map +1 -1
  102. package/dist/services/builtin-handlers.js +34 -20
  103. package/dist/services/builtin-handlers.js.map +7 -1
  104. package/dist/services/economy-handlers.js +143 -132
  105. package/dist/services/economy-handlers.js.map +7 -1
  106. package/dist/tx-runner.d.ts +35 -11
  107. package/dist/tx-runner.d.ts.map +1 -1
  108. package/dist/tx-runner.js +293 -250
  109. package/dist/tx-runner.js.map +7 -1
  110. package/dist/where.js +71 -94
  111. package/dist/where.js.map +7 -1
  112. package/package.json +4 -4
@@ -1 +1,7 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/routes/messages.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/routes/messages.ts"],
4
+ "sourcesContent": ["/**\n * routes/messages.ts \u2014 \u804A\u5929\u6D88\u606F (sfmc_chat_messages)\n *\n * \u8DEF\u7531\u5217\u8868\uFF1A\n * GET /api/sfmc/messages \u2014 \u6A21\u7CCA/\u8FC7\u6EE4\u67E5\u8BE2\u6D88\u606F\n * POST /api/sfmc/messages \u2014 \u6279\u91CF INSERT OR REPLACE \u6D88\u606F\uFF08\u540C\u65F6\u8F6C\u53D1\u81F3 QQ Bridge\uFF09\n */\n\nimport { SQL } from \"sql-template-strings\";\nimport type { QueryFn } from \"../lib/sqlite.js\";\n\ninterface Deps {\n query: QueryFn;\n body: (req: import(\"http\").IncomingMessage) => Promise<Record<string, unknown>>;\n json: (res: import(\"http\").ServerResponse, data: Record<string, unknown>, status?: number) => void;\n forwardToQQBridge: (channelId: string, fromName: string, content: string, fromId: string) => void;\n}\n\nfunction createMessagesRoutes({ query, body, json, forwardToQQBridge }: Deps) {\n return async function handle({\n path,\n method,\n params,\n req,\n res,\n }: {\n path: string;\n method: string;\n params: URLSearchParams;\n req: import(\"http\").IncomingMessage;\n res: import(\"http\").ServerResponse;\n }): Promise<boolean> {\n if (path === \"/api/sfmc/messages\") {\n if (method === \"GET\") {\n const stmt = SQL`SELECT * FROM sfmc_chat_messages WHERE 1=1`;\n const search = params.get(\"search\")?.trim();\n if (search) stmt.append(SQL` AND (content LIKE ${`%${search}%`})`);\n const type = params.get(\"type\")?.trim();\n if (type) stmt.append(SQL` AND type = ${type}`);\n const channelId = params.get(\"channelId\")?.trim();\n if (channelId) stmt.append(SQL` AND channel_id = ${channelId}`);\n const from = params.get(\"from\")?.trim();\n if (from) stmt.append(SQL` AND from_id = ${from}`);\n const minCreatedAt = params.get(\"minCreatedAt\")?.trim();\n if (minCreatedAt) stmt.append(SQL` AND created_at >= ${Number(minCreatedAt)}`);\n const minSentAt = params.get(\"minSentAt\")?.trim();\n if (minSentAt) stmt.append(SQL` AND created_at >= ${Number(minSentAt)}`);\n const maxCreatedAt = params.get(\"maxCreatedAt\")?.trim();\n if (maxCreatedAt) stmt.append(SQL` AND created_at <= ${Number(maxCreatedAt)}`);\n stmt.append(SQL` ORDER BY created_at ASC`);\n json(res, { messages: query(stmt) });\n } else if (method === \"POST\") {\n const { messages } = await body(req);\n if (!Array.isArray(messages) || messages.length === 0) {\n json(res, { success: false, error: \"invalid\" }, 400);\n return true;\n }\n if ((messages as unknown[]).length > 100) {\n json(res, { success: false, error: \"too many requests\" }, 413);\n return true;\n }\n // \u591A\u884C INSERT \u6539\u6210\u5FAA\u73AF\u5355\u6761 INSERT OR REPLACE \u2014\u2014 \u7B80\u5355\u4F18\u5148\n for (const m of messages as Array<Record<string, unknown>>) {\n query(\n SQL`INSERT OR REPLACE INTO sfmc_chat_messages (\n id, channel_id, from_id, from_name, type, content, attachment, show_timestamp, created_at\n ) VALUES (\n ${m.id}, ${m.channelId}, ${m.fromid}, ${m.fromName},\n ${m.type ?? \"text\"}, ${m.content}, ${m.attachment ?? null},\n ${m.showTimestamp ? 1 : 0}, ${m.timestamp}\n )`\n );\n }\n for (const m of messages as Array<Record<string, unknown>>) {\n forwardToQQBridge(m.channelId as string, m.fromName as string, m.content as string, m.fromid as string);\n }\n json(res, { success: true });\n } else {\n json(res, { success: false, error: \"not_found\" }, 404);\n }\n return true;\n }\n return false;\n };\n}\n\nexport { createMessagesRoutes };\n"],
5
+ "mappings": "AAQA,SAAS,WAAW;AAUpB,SAAS,qBAAqB,EAAE,OAAO,MAAM,MAAM,kBAAkB,GAAS;AAC5E,SAAO,eAAe,OAAO;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAMqB;AACnB,QAAI,SAAS,sBAAsB;AACjC,UAAI,WAAW,OAAO;AACpB,cAAM,OAAO;AACb,cAAM,SAAS,OAAO,IAAI,QAAQ,GAAG,KAAK;AAC1C,YAAI,OAAQ,MAAK,OAAO,yBAAyB,IAAI,MAAM,GAAG,GAAG;AACjE,cAAM,OAAO,OAAO,IAAI,MAAM,GAAG,KAAK;AACtC,YAAI,KAAM,MAAK,OAAO,kBAAkB,IAAI,EAAE;AAC9C,cAAM,YAAY,OAAO,IAAI,WAAW,GAAG,KAAK;AAChD,YAAI,UAAW,MAAK,OAAO,wBAAwB,SAAS,EAAE;AAC9D,cAAM,OAAO,OAAO,IAAI,MAAM,GAAG,KAAK;AACtC,YAAI,KAAM,MAAK,OAAO,qBAAqB,IAAI,EAAE;AACjD,cAAM,eAAe,OAAO,IAAI,cAAc,GAAG,KAAK;AACtD,YAAI,aAAc,MAAK,OAAO,yBAAyB,OAAO,YAAY,CAAC,EAAE;AAC7E,cAAM,YAAY,OAAO,IAAI,WAAW,GAAG,KAAK;AAChD,YAAI,UAAW,MAAK,OAAO,yBAAyB,OAAO,SAAS,CAAC,EAAE;AACvE,cAAM,eAAe,OAAO,IAAI,cAAc,GAAG,KAAK;AACtD,YAAI,aAAc,MAAK,OAAO,yBAAyB,OAAO,YAAY,CAAC,EAAE;AAC7E,aAAK,OAAO,6BAA6B;AACzC,aAAK,KAAK,EAAE,UAAU,MAAM,IAAI,EAAE,CAAC;AAAA,MACrC,WAAW,WAAW,QAAQ;AAC5B,cAAM,EAAE,SAAS,IAAI,MAAM,KAAK,GAAG;AACnC,YAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,GAAG;AACrD,eAAK,KAAK,EAAE,SAAS,OAAO,OAAO,UAAU,GAAG,GAAG;AACnD,iBAAO;AAAA,QACT;AACA,YAAK,SAAuB,SAAS,KAAK;AACxC,eAAK,KAAK,EAAE,SAAS,OAAO,OAAO,oBAAoB,GAAG,GAAG;AAC7D,iBAAO;AAAA,QACT;AAEA,mBAAW,KAAK,UAA4C;AAC1D;AAAA,YACE;AAAA;AAAA;AAAA,kBAGM,EAAE,EAAE,KAAK,EAAE,SAAS,KAAK,EAAE,MAAM,KAAK,EAAE,QAAQ;AAAA,kBAChD,EAAE,QAAQ,MAAM,KAAK,EAAE,OAAO,KAAK,EAAE,cAAc,IAAI;AAAA,kBACvD,EAAE,gBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS;AAAA;AAAA,UAE/C;AAAA,QACF;AACA,mBAAW,KAAK,UAA4C;AAC1D,4BAAkB,EAAE,WAAqB,EAAE,UAAoB,EAAE,SAAmB,EAAE,MAAgB;AAAA,QACxG;AACA,aAAK,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,MAC7B,OAAO;AACL,aAAK,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,GAAG,GAAG;AAAA,MACvD;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"module-config-routes.d.ts","sourceRoot":"","sources":["../../src/routes/module-config-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,WAAW,CAAC;CAC3B;AA+BD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,IAShE,KAAK;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,GAAG,EAAE,eAAe,CAAC;IACrB,GAAG,EAAE,cAAc,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,KAAG,OAAO,CAAC,OAAO,CAAC,CAwErB"}
1
+ {"version":3,"file":"module-config-routes.d.ts","sourceRoot":"","sources":["../../src/routes/module-config-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,WAAW,CAAC;CAC3B;AA+BD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,SAS3D;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,GAAG,EAAE,eAAe,CAAC;IACrB,GAAG,EAAE,cAAc,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,KAAG,OAAO,CAAC,OAAO,CAAC,CAwErB"}
@@ -1,128 +1,109 @@
1
- /**
2
- * routes/module-config-routes.ts — 模块配置文件管理
3
- *
4
- * 端点:
5
- * GET /api/sfmc/configs/:configKey → { config: <configs/<configKey>.json> }
6
- * POST /api/sfmc/configs/:configKey/set → 写一个 key
7
- * GET /api/sfmc/configs/:configKey/notify (SSE:onChange 推送)
8
- *
9
- * 鉴权:模块身份来自 ctx.moduleAuth;Permission = config:read:configKey / config:write:configKey。
10
- *
11
- * 设计:文件 = configs/<configKey>.json;整文件 read-modify-write(lock by
12
- * 简单 mutex),不是细粒度 lock — 模块 config 文件本来就小;并发冲突概率极低。
13
- */
14
1
  import { join } from "node:path";
15
2
  import { readJson, writeJson } from "@sfmc-bds/sdk/node/config";
16
3
  import { json as defaultJson } from "../lib/http.js";
17
4
  import { assertModulePermission, Perm } from "../permission-gate.js";
18
5
  import { jsonV2Fail } from "./_shared.js";
19
6
  function configPath(projectRoot, key) {
20
- if (!/^[A-Za-z0-9_-]+$/.test(key)) {
21
- throw new Error(`invalid configKey "${key}"`);
22
- }
23
- return join(projectRoot, "configs", `${key}.json`);
7
+ if (!/^[A-Za-z0-9_-]+$/.test(key)) {
8
+ throw new Error(`invalid configKey "${key}"`);
9
+ }
10
+ return join(projectRoot, "configs", `${key}.json`);
24
11
  }
25
12
  function readConfig(file) {
26
- const parsed = readJson(file);
27
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
28
- return {};
29
- return parsed;
13
+ const parsed = readJson(file);
14
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
15
+ return parsed;
30
16
  }
31
- const subscribers = new Map();
17
+ const subscribers = /* @__PURE__ */ new Map();
32
18
  function subscribe(configKey, cb) {
33
- if (!subscribers.has(configKey))
34
- subscribers.set(configKey, new Set());
35
- subscribers.get(configKey).add(cb);
36
- return () => {
37
- subscribers.get(configKey)?.delete(cb);
38
- };
19
+ if (!subscribers.has(configKey)) subscribers.set(configKey, /* @__PURE__ */ new Set());
20
+ subscribers.get(configKey).add(cb);
21
+ return () => {
22
+ subscribers.get(configKey)?.delete(cb);
23
+ };
39
24
  }
40
25
  function notify(configKey, key, value) {
41
- const set = subscribers.get(configKey);
42
- if (!set)
43
- return;
44
- for (const cb of set)
45
- cb({ key, value });
26
+ const set = subscribers.get(configKey);
27
+ if (!set) return;
28
+ for (const cb of set) cb({ key, value });
46
29
  }
47
- export function createModuleConfigRoutes(depsIn) {
48
- const deps = depsIn;
49
- if (!deps.projectRoot || !deps.enabled) {
50
- throw new Error("createModuleConfigRoutes: 缺少 projectRoot / enabled map");
30
+ function createModuleConfigRoutes(depsIn) {
31
+ const deps = depsIn;
32
+ if (!deps.projectRoot || !deps.enabled) {
33
+ throw new Error("createModuleConfigRoutes: \u7F3A\u5C11 projectRoot / enabled map");
34
+ }
35
+ const json = deps.json || defaultJson;
36
+ const projectRoot = deps.projectRoot;
37
+ const enabled = deps.enabled;
38
+ return async (ctx) => {
39
+ const { path, method, req, res } = ctx;
40
+ const m = path.match(/^\/api\/sfmc\/configs\/([A-Za-z0-9_-]+)(?:\/(set|notify))?$/);
41
+ if (!m) return false;
42
+ const configKey = m[1];
43
+ const tail = m[2];
44
+ const auth = ctx.moduleAuth;
45
+ if (!auth) {
46
+ jsonV2Fail(res, "unauthorized", 401, "unauthorized");
47
+ return true;
51
48
  }
52
- const json = deps.json || defaultJson;
53
- const projectRoot = deps.projectRoot;
54
- const enabled = deps.enabled;
55
- return async (ctx) => {
56
- const { path, method, req, res } = ctx;
57
- const m = path.match(/^\/api\/sfmc\/configs\/([A-Za-z0-9_-]+)(?:\/(set|notify))?$/);
58
- if (!m)
59
- return false;
60
- const configKey = m[1];
61
- const tail = m[2];
62
- const auth = ctx.moduleAuth;
63
- if (!auth) {
64
- jsonV2Fail(res, "unauthorized", 401, "unauthorized");
65
- return true;
66
- }
67
- const manifest = enabled.get(auth.id);
68
- if (!manifest || manifest.configKey !== configKey) {
69
- jsonV2Fail(res, `模块 ${auth.id} 不持有 configKey "${configKey}"`, 403, "forbidden");
70
- return true;
71
- }
72
- const file = configPath(projectRoot, configKey);
73
- if (!tail && method === "GET") {
74
- try {
75
- assertModulePermission(auth.id, manifest.permissions, Perm.configRead(configKey));
76
- const cfg = readConfig(file);
77
- json(res, { config: cfg });
78
- }
79
- catch (e) {
80
- const code = e.name === "PermissionDeniedError" ? 403 : 500;
81
- // LSP: GET 失败与 /set 同用 ok 方言
82
- jsonV2Fail(res, e.message, code);
83
- }
84
- return true;
85
- }
86
- if (tail === "set" && method === "POST") {
87
- try {
88
- assertModulePermission(auth.id, manifest.permissions, Perm.configWrite(configKey));
89
- const body = (await ctx.body) || {};
90
- const key = String(body.key);
91
- const value = body.value;
92
- const cfg = readConfig(file);
93
- cfg[key] = value;
94
- writeJson(file, cfg);
95
- notify(configKey, key, value);
96
- json(res, { ok: true });
97
- }
98
- catch (e) {
99
- // LSP: /set 成功用 ok:true,失败统一 ok:false(勿混用 success)
100
- const code = e.name === "PermissionDeniedError" ? 403 : 500;
101
- jsonV2Fail(res, e.message, code);
102
- }
103
- return true;
104
- }
105
- if (tail === "notify" && method === "GET") {
106
- // SSE — PoC 把监听留在内存里,不持久化
107
- res.writeHead(200, {
108
- "Content-Type": "text/event-stream",
109
- "Cache-Control": "no-cache",
110
- Connection: "keep-alive",
111
- });
112
- res.write(":ok\n\n");
113
- const unsub = subscribe(configKey, (payload) => {
114
- try {
115
- res.write(`data: ${JSON.stringify(payload)}\n\n`);
116
- }
117
- catch {
118
- unsub();
119
- }
120
- });
121
- req.on("close", unsub);
122
- return true;
49
+ const manifest = enabled.get(auth.id);
50
+ if (!manifest || manifest.configKey !== configKey) {
51
+ jsonV2Fail(res, `\u6A21\u5757 ${auth.id} \u4E0D\u6301\u6709 configKey "${configKey}"`, 403, "forbidden");
52
+ return true;
53
+ }
54
+ const file = configPath(projectRoot, configKey);
55
+ if (!tail && method === "GET") {
56
+ try {
57
+ assertModulePermission(auth.id, manifest.permissions, Perm.configRead(configKey));
58
+ const cfg = readConfig(file);
59
+ json(res, { config: cfg });
60
+ } catch (e) {
61
+ const code = e.name === "PermissionDeniedError" ? 403 : 500;
62
+ jsonV2Fail(res, e.message, code);
63
+ }
64
+ return true;
65
+ }
66
+ if (tail === "set" && method === "POST") {
67
+ try {
68
+ assertModulePermission(auth.id, manifest.permissions, Perm.configWrite(configKey));
69
+ const body = await ctx.body || {};
70
+ const key = String(body.key);
71
+ const value = body.value;
72
+ const cfg = readConfig(file);
73
+ cfg[key] = value;
74
+ writeJson(file, cfg);
75
+ notify(configKey, key, value);
76
+ json(res, { ok: true });
77
+ } catch (e) {
78
+ const code = e.name === "PermissionDeniedError" ? 403 : 500;
79
+ jsonV2Fail(res, e.message, code);
80
+ }
81
+ return true;
82
+ }
83
+ if (tail === "notify" && method === "GET") {
84
+ res.writeHead(200, {
85
+ "Content-Type": "text/event-stream",
86
+ "Cache-Control": "no-cache",
87
+ Connection: "keep-alive"
88
+ });
89
+ res.write(":ok\n\n");
90
+ const unsub = subscribe(configKey, (payload) => {
91
+ try {
92
+ res.write(`data: ${JSON.stringify(payload)}
93
+
94
+ `);
95
+ } catch {
96
+ unsub();
123
97
  }
124
- return false;
125
- };
98
+ });
99
+ req.on("close", unsub);
100
+ return true;
101
+ }
102
+ return false;
103
+ };
126
104
  }
127
105
  ;
128
- //# sourceMappingURL=module-config-routes.js.map
106
+ export {
107
+ createModuleConfigRoutes
108
+ };
109
+ //# sourceMappingURL=module-config-routes.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"module-config-routes.js","sourceRoot":"","sources":["../../src/routes/module-config-routes.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/routes/module-config-routes.ts"],
4
+ "sourcesContent": ["/**\n * routes/module-config-routes.ts \u2014 \u6A21\u5757\u914D\u7F6E\u6587\u4EF6\u7BA1\u7406\n *\n * \u7AEF\u70B9:\n * GET /api/sfmc/configs/:configKey \u2192 { config: <configs/<configKey>.json> }\n * POST /api/sfmc/configs/:configKey/set \u2192 \u5199\u4E00\u4E2A key\n * GET /api/sfmc/configs/:configKey/notify (SSE:onChange \u63A8\u9001)\n *\n * \u9274\u6743:\u6A21\u5757\u8EAB\u4EFD\u6765\u81EA ctx.moduleAuth;Permission = config:read:configKey / config:write:configKey\u3002\n *\n * \u8BBE\u8BA1:\u6587\u4EF6 = configs/<configKey>.json;\u6574\u6587\u4EF6 read-modify-write(lock by\n * \u7B80\u5355 mutex),\u4E0D\u662F\u7EC6\u7C92\u5EA6 lock \u2014 \u6A21\u5757 config \u6587\u4EF6\u672C\u6765\u5C31\u5C0F;\u5E76\u53D1\u51B2\u7A81\u6982\u7387\u6781\u4F4E\u3002\n */\n\nimport { join } from \"node:path\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { readJson, writeJson } from \"@sfmc-bds/sdk/node/config\";\nimport { json as defaultJson, type Method } from \"../lib/http.js\";\nimport { assertModulePermission, Perm } from \"../permission-gate.js\";\nimport type { ModuleManifestV2 } from \"../manifest-loader.js\";\nimport { jsonV2Fail, type ModuleAuth } from \"./_shared.js\";\n\nexport interface ModuleConfigRoutesDeps {\n projectRoot: string;\n enabled: Map<string, ModuleManifestV2>;\n json?: typeof defaultJson;\n}\n\nfunction configPath(projectRoot: string, key: string): string {\n if (!/^[A-Za-z0-9_-]+$/.test(key)) {\n throw new Error(`invalid configKey \"${key}\"`);\n }\n return join(projectRoot, \"configs\", `${key}.json`);\n}\n\nfunction readConfig(file: string): Record<string, unknown> {\n const parsed = readJson<unknown>(file);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n return parsed as Record<string, unknown>;\n}\n\nconst subscribers = new Map<string, Set<(payload: unknown) => void>>();\n\nfunction subscribe(configKey: string, cb: (payload: unknown) => void): () => void {\n if (!subscribers.has(configKey)) subscribers.set(configKey, new Set());\n subscribers.get(configKey)!.add(cb);\n return () => {\n subscribers.get(configKey)?.delete(cb);\n };\n}\n\nfunction notify(configKey: string, key: string, value: unknown): void {\n const set = subscribers.get(configKey);\n if (!set) return;\n for (const cb of set) cb({ key, value });\n}\n\nexport function createModuleConfigRoutes(depsIn: Partial<ModuleConfigRoutesDeps>) {\n const deps = depsIn as Partial<ModuleConfigRoutesDeps>;\n if (!deps.projectRoot || !deps.enabled) {\n throw new Error(\"createModuleConfigRoutes: \u7F3A\u5C11 projectRoot / enabled map\");\n }\n const json = deps.json || defaultJson;\n const projectRoot = deps.projectRoot;\n const enabled = deps.enabled!;\n\n return async (ctx: {\n path: string;\n method: Method | string;\n req: IncomingMessage;\n res: ServerResponse;\n body?: Promise<Record<string, unknown>>;\n moduleAuth?: ModuleAuth;\n }): Promise<boolean> => {\n const { path, method, req, res } = ctx;\n const m = path.match(/^\\/api\\/sfmc\\/configs\\/([A-Za-z0-9_-]+)(?:\\/(set|notify))?$/);\n if (!m) return false;\n const configKey = m[1];\n const tail = m[2];\n const auth = ctx.moduleAuth;\n if (!auth) {\n jsonV2Fail(res, \"unauthorized\", 401, \"unauthorized\");\n return true;\n }\n const manifest = enabled.get(auth.id);\n if (!manifest || manifest.configKey !== configKey) {\n jsonV2Fail(res, `\u6A21\u5757 ${auth.id} \u4E0D\u6301\u6709 configKey \"${configKey}\"`, 403, \"forbidden\");\n return true;\n }\n\n const file = configPath(projectRoot, configKey);\n\n if (!tail && method === \"GET\") {\n try {\n assertModulePermission(auth.id, manifest.permissions, Perm.configRead(configKey));\n const cfg = readConfig(file);\n json(res, { config: cfg });\n } catch (e) {\n const code = (e as { name?: string }).name === \"PermissionDeniedError\" ? 403 : 500;\n // LSP: GET \u5931\u8D25\u4E0E /set \u540C\u7528 ok \u65B9\u8A00\n jsonV2Fail(res, (e as Error).message, code);\n }\n return true;\n }\n\n if (tail === \"set\" && method === \"POST\") {\n try {\n assertModulePermission(auth.id, manifest.permissions, Perm.configWrite(configKey));\n const body = (await (ctx.body as Promise<Record<string, unknown>>)) || {};\n const key = String(body.key);\n const value = body.value;\n const cfg = readConfig(file);\n cfg[key] = value;\n writeJson(file, cfg);\n notify(configKey, key, value);\n json(res, { ok: true });\n } catch (e) {\n // LSP: /set \u6210\u529F\u7528 ok:true,\u5931\u8D25\u7EDF\u4E00 ok:false(\u52FF\u6DF7\u7528 success)\n const code = (e as { name?: string }).name === \"PermissionDeniedError\" ? 403 : 500;\n jsonV2Fail(res, (e as Error).message, code);\n }\n return true;\n }\n\n if (tail === \"notify\" && method === \"GET\") {\n // SSE \u2014 PoC \u628A\u76D1\u542C\u7559\u5728\u5185\u5B58\u91CC,\u4E0D\u6301\u4E45\u5316\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(\":ok\\n\\n\");\n const unsub = subscribe(configKey, (payload) => {\n try {\n res.write(`data: ${JSON.stringify(payload)}\\n\\n`);\n } catch {\n unsub();\n }\n });\n req.on(\"close\", unsub);\n return true;\n }\n\n return false;\n };\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/routes/modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU,IAAI;IACZ,iBAAiB,EAAE,MAAM,OAAO,EAAE,CAAC;IACnC,eAAe,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAChF,gBAAgB,EAAE,CAChB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,EAC3C,OAAO,EAAE,OAAO,KACb,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpG;AAED,iBAAS,kBAAkB,CAAC,EAC1B,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,IAAI,EACJ,IAAI,GACL,EAAE,IAAI,IACmC,qCAMrC;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,CAAC;IACpC,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,CAAC;CACpC,KAAG,OAAO,CAAC,OAAO,CAAC,CAqErB;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/routes/modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU,IAAI;IACZ,iBAAiB,EAAE,MAAM,OAAO,EAAE,CAAC;IACnC,eAAe,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAChF,gBAAgB,EAAE,CAChB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,EAC3C,OAAO,EAAE,OAAO,KACb,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpG;AAED,iBAAS,kBAAkB,CAAC,EAC1B,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,IAAI,EACJ,IAAI,GACL,EAAE,IAAI,yCAOF;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,CAAC;IACpC,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,CAAC;CACpC,KAAG,OAAO,CAAC,OAAO,CAAC,CAqErB;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -1,92 +1,86 @@
1
- /**
2
- * routes/modules.ts — 模块目录与启停(基于 modules/catalog.json + module-lock.json)
3
- *
4
- * 路由列表:
5
- * GET /api/sfmc/modules — 模块列表(含 enable 状态)
6
- * GET /api/sfmc/modules/catalog — 原始 catalog 列表
7
- * GET /api/sfmc/modules/:key — 单个模块详情
8
- * PATCH/PUT /api/sfmc/modules/:key — 设置 enabled
9
- * POST /api/sfmc/modules/:key/enable — 启用模块
10
- * POST /api/sfmc/modules/:key/disable — 禁用模块
11
- */
12
- function createModuleRoutes({ loadModuleCatalog, buildModuleList, resolveModuleByKey, setModuleEnabled, body, json, }) {
13
- return async function handleModuleRoute({ path, method, params, req, res, }) {
14
- void params; // unused
15
- if (path === "/api/sfmc/modules/catalog") {
16
- if (method === "GET") {
17
- json(res, { modules: loadModuleCatalog() });
18
- }
19
- else {
20
- json(res, { success: false, error: "not_found" }, 404);
21
- }
22
- return true;
23
- }
24
- if (path === "/api/sfmc/modules") {
25
- if (method === "GET")
26
- json(res, { modules: buildModuleList() });
27
- else
28
- json(res, { success: false, error: "not_found" }, 404);
29
- return true;
30
- }
31
- if (!path.startsWith("/api/sfmc/modules/"))
32
- return false;
33
- const rest = path.slice("/api/sfmc/modules/".length);
34
- const [rawKey, action] = rest.split("/");
35
- const module = resolveModuleByKey(decodeURIComponent(rawKey ?? ""));
36
- if (!module) {
37
- json(res, { success: false, error: "module_not_found" }, 404);
38
- return true;
39
- }
40
- const current = () => buildModuleList().find((entry) => entry.id === module.id);
41
- if (!action && method === "GET") {
42
- json(res, { module: current() ?? null });
43
- }
44
- else if (!action && (method === "PATCH" || method === "PUT")) {
45
- const { enabled } = await body(req);
46
- if (!enabled && !module.canDisable) {
47
- json(res, { success: false, error: "module_cannot_disable" }, 400);
48
- return true;
49
- }
50
- try {
51
- setModuleEnabled(module, !!enabled);
52
- }
53
- catch (error) {
54
- const e = error;
55
- if (e.code === "dependency_unmet") {
56
- json(res, { success: false, error: "dependency_unmet", unmet: e.unmet }, 409);
57
- return true;
58
- }
59
- throw error;
60
- }
61
- json(res, { success: true, module: current() });
62
- }
63
- else if (action === "enable" && method === "POST") {
64
- try {
65
- setModuleEnabled(module, true);
66
- }
67
- catch (error) {
68
- const e = error;
69
- if (e.code === "dependency_unmet") {
70
- json(res, { success: false, error: "dependency_unmet", unmet: e.unmet }, 409);
71
- return true;
72
- }
73
- throw error;
74
- }
75
- json(res, { success: true, module: current() });
76
- }
77
- else if (action === "disable" && method === "POST") {
78
- if (!module.canDisable) {
79
- json(res, { success: false, error: "module_cannot_disable" }, 400);
80
- return true;
81
- }
82
- setModuleEnabled(module, false);
83
- json(res, { success: true, module: current() });
1
+ function createModuleRoutes({
2
+ loadModuleCatalog,
3
+ buildModuleList,
4
+ resolveModuleByKey,
5
+ setModuleEnabled,
6
+ body,
7
+ json
8
+ }) {
9
+ return async function handleModuleRoute({
10
+ path,
11
+ method,
12
+ params,
13
+ req,
14
+ res
15
+ }) {
16
+ void params;
17
+ if (path === "/api/sfmc/modules/catalog") {
18
+ if (method === "GET") {
19
+ json(res, { modules: loadModuleCatalog() });
20
+ } else {
21
+ json(res, { success: false, error: "not_found" }, 404);
22
+ }
23
+ return true;
24
+ }
25
+ if (path === "/api/sfmc/modules") {
26
+ if (method === "GET") json(res, { modules: buildModuleList() });
27
+ else json(res, { success: false, error: "not_found" }, 404);
28
+ return true;
29
+ }
30
+ if (!path.startsWith("/api/sfmc/modules/")) return false;
31
+ const rest = path.slice("/api/sfmc/modules/".length);
32
+ const [rawKey, action] = rest.split("/");
33
+ const module = resolveModuleByKey(decodeURIComponent(rawKey ?? ""));
34
+ if (!module) {
35
+ json(res, { success: false, error: "module_not_found" }, 404);
36
+ return true;
37
+ }
38
+ const current = () => buildModuleList().find((entry) => entry.id === module.id);
39
+ if (!action && method === "GET") {
40
+ json(res, { module: current() ?? null });
41
+ } else if (!action && (method === "PATCH" || method === "PUT")) {
42
+ const { enabled } = await body(req);
43
+ if (!enabled && !module.canDisable) {
44
+ json(res, { success: false, error: "module_cannot_disable" }, 400);
45
+ return true;
46
+ }
47
+ try {
48
+ setModuleEnabled(module, !!enabled);
49
+ } catch (error) {
50
+ const e = error;
51
+ if (e.code === "dependency_unmet") {
52
+ json(res, { success: false, error: "dependency_unmet", unmet: e.unmet }, 409);
53
+ return true;
84
54
  }
85
- else {
86
- json(res, { success: false, error: "not_found" }, 404);
55
+ throw error;
56
+ }
57
+ json(res, { success: true, module: current() });
58
+ } else if (action === "enable" && method === "POST") {
59
+ try {
60
+ setModuleEnabled(module, true);
61
+ } catch (error) {
62
+ const e = error;
63
+ if (e.code === "dependency_unmet") {
64
+ json(res, { success: false, error: "dependency_unmet", unmet: e.unmet }, 409);
65
+ return true;
87
66
  }
67
+ throw error;
68
+ }
69
+ json(res, { success: true, module: current() });
70
+ } else if (action === "disable" && method === "POST") {
71
+ if (!module.canDisable) {
72
+ json(res, { success: false, error: "module_cannot_disable" }, 400);
88
73
  return true;
89
- };
74
+ }
75
+ setModuleEnabled(module, false);
76
+ json(res, { success: true, module: current() });
77
+ } else {
78
+ json(res, { success: false, error: "not_found" }, 404);
79
+ }
80
+ return true;
81
+ };
90
82
  }
91
- export { createModuleRoutes };
92
- //# sourceMappingURL=modules.js.map
83
+ export {
84
+ createModuleRoutes
85
+ };
86
+ //# sourceMappingURL=modules.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"modules.js","sourceRoot":"","sources":["../../src/routes/modules.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/routes/modules.ts"],
4
+ "sourcesContent": ["/**\n * routes/modules.ts \u2014 \u6A21\u5757\u76EE\u5F55\u4E0E\u542F\u505C\uFF08\u57FA\u4E8E modules/catalog.json + module-lock.json\uFF09\n *\n * \u8DEF\u7531\u5217\u8868\uFF1A\n * GET /api/sfmc/modules \u2014 \u6A21\u5757\u5217\u8868\uFF08\u542B enable \u72B6\u6001\uFF09\n * GET /api/sfmc/modules/catalog \u2014 \u539F\u59CB catalog \u5217\u8868\n * GET /api/sfmc/modules/:key \u2014 \u5355\u4E2A\u6A21\u5757\u8BE6\u60C5\n * PATCH/PUT /api/sfmc/modules/:key \u2014 \u8BBE\u7F6E enabled\n * POST /api/sfmc/modules/:key/enable \u2014 \u542F\u7528\u6A21\u5757\n * POST /api/sfmc/modules/:key/disable \u2014 \u7981\u7528\u6A21\u5757\n */\n\ninterface Deps {\n loadModuleCatalog: () => unknown[];\n buildModuleList: () => Array<Record<string, unknown>>;\n resolveModuleByKey: (key: string) => { id: string; canDisable: boolean } | null;\n setModuleEnabled: (\n module: { id: string; canDisable: boolean },\n enabled: boolean\n ) => void;\n body: (req: import(\"http\").IncomingMessage) => Promise<Record<string, unknown>>;\n json: (res: import(\"http\").ServerResponse, data: Record<string, unknown>, status?: number) => void;\n}\n\nfunction createModuleRoutes({\n loadModuleCatalog,\n buildModuleList,\n resolveModuleByKey,\n setModuleEnabled,\n body,\n json,\n}: Deps) {\n return async function handleModuleRoute({\n path,\n method,\n params,\n req,\n res,\n }: {\n path: string;\n method: string;\n params: URLSearchParams;\n req: import(\"http\").IncomingMessage;\n res: import(\"http\").ServerResponse;\n }): Promise<boolean> {\n void params; // unused\n if (path === \"/api/sfmc/modules/catalog\") {\n if (method === \"GET\") {\n json(res, { modules: loadModuleCatalog() });\n } else {\n json(res, { success: false, error: \"not_found\" }, 404);\n }\n return true;\n }\n if (path === \"/api/sfmc/modules\") {\n if (method === \"GET\") json(res, { modules: buildModuleList() });\n else json(res, { success: false, error: \"not_found\" }, 404);\n return true;\n }\n if (!path.startsWith(\"/api/sfmc/modules/\")) return false;\n\n const rest = path.slice(\"/api/sfmc/modules/\".length);\n const [rawKey, action] = rest.split(\"/\");\n const module = resolveModuleByKey(decodeURIComponent(rawKey ?? \"\"));\n if (!module) {\n json(res, { success: false, error: \"module_not_found\" }, 404);\n return true;\n }\n\n const current = () => buildModuleList().find((entry) => entry.id === module.id);\n if (!action && method === \"GET\") {\n json(res, { module: current() ?? null });\n } else if (!action && (method === \"PATCH\" || method === \"PUT\")) {\n const { enabled } = await body(req);\n if (!enabled && !module.canDisable) {\n json(res, { success: false, error: \"module_cannot_disable\" }, 400);\n return true;\n }\n try {\n setModuleEnabled(module, !!enabled);\n } catch (error) {\n const e = error as { code?: string; unmet?: Array<{ id: string }> };\n if (e.code === \"dependency_unmet\") {\n json(res, { success: false, error: \"dependency_unmet\", unmet: e.unmet }, 409);\n return true;\n }\n throw error;\n }\n json(res, { success: true, module: current() });\n } else if (action === \"enable\" && method === \"POST\") {\n try {\n setModuleEnabled(module, true);\n } catch (error) {\n const e = error as { code?: string; unmet?: Array<{ id: string }> };\n if (e.code === \"dependency_unmet\") {\n json(res, { success: false, error: \"dependency_unmet\", unmet: e.unmet }, 409);\n return true;\n }\n throw error;\n }\n json(res, { success: true, module: current() });\n } else if (action === \"disable\" && method === \"POST\") {\n if (!module.canDisable) {\n json(res, { success: false, error: \"module_cannot_disable\" }, 400);\n return true;\n }\n setModuleEnabled(module, false);\n json(res, { success: true, module: current() });\n } else {\n json(res, { success: false, error: \"not_found\" }, 404);\n }\n return true;\n };\n}\n\nexport { createModuleRoutes };\n"],
5
+ "mappings": "AAwBA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAS;AACP,SAAO,eAAe,kBAAkB;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAMqB;AACnB,SAAK;AACL,QAAI,SAAS,6BAA6B;AACxC,UAAI,WAAW,OAAO;AACpB,aAAK,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;AAAA,MAC5C,OAAO;AACL,aAAK,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,GAAG,GAAG;AAAA,MACvD;AACA,aAAO;AAAA,IACT;AACA,QAAI,SAAS,qBAAqB;AAChC,UAAI,WAAW,MAAO,MAAK,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;AAAA,UACzD,MAAK,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,GAAG,GAAG;AAC1D,aAAO;AAAA,IACT;AACA,QAAI,CAAC,KAAK,WAAW,oBAAoB,EAAG,QAAO;AAEnD,UAAM,OAAO,KAAK,MAAM,qBAAqB,MAAM;AACnD,UAAM,CAAC,QAAQ,MAAM,IAAI,KAAK,MAAM,GAAG;AACvC,UAAM,SAAS,mBAAmB,mBAAmB,UAAU,EAAE,CAAC;AAClE,QAAI,CAAC,QAAQ;AACX,WAAK,KAAK,EAAE,SAAS,OAAO,OAAO,mBAAmB,GAAG,GAAG;AAC5D,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,MAAM,gBAAgB,EAAE,KAAK,CAAC,UAAU,MAAM,OAAO,OAAO,EAAE;AAC9E,QAAI,CAAC,UAAU,WAAW,OAAO;AAC/B,WAAK,KAAK,EAAE,QAAQ,QAAQ,KAAK,KAAK,CAAC;AAAA,IACzC,WAAW,CAAC,WAAW,WAAW,WAAW,WAAW,QAAQ;AAC9D,YAAM,EAAE,QAAQ,IAAI,MAAM,KAAK,GAAG;AAClC,UAAI,CAAC,WAAW,CAAC,OAAO,YAAY;AAClC,aAAK,KAAK,EAAE,SAAS,OAAO,OAAO,wBAAwB,GAAG,GAAG;AACjE,eAAO;AAAA,MACT;AACA,UAAI;AACF,yBAAiB,QAAQ,CAAC,CAAC,OAAO;AAAA,MACpC,SAAS,OAAO;AACd,cAAM,IAAI;AACV,YAAI,EAAE,SAAS,oBAAoB;AACjC,eAAK,KAAK,EAAE,SAAS,OAAO,OAAO,oBAAoB,OAAO,EAAE,MAAM,GAAG,GAAG;AAC5E,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AACA,WAAK,KAAK,EAAE,SAAS,MAAM,QAAQ,QAAQ,EAAE,CAAC;AAAA,IAChD,WAAW,WAAW,YAAY,WAAW,QAAQ;AACnD,UAAI;AACF,yBAAiB,QAAQ,IAAI;AAAA,MAC/B,SAAS,OAAO;AACd,cAAM,IAAI;AACV,YAAI,EAAE,SAAS,oBAAoB;AACjC,eAAK,KAAK,EAAE,SAAS,OAAO,OAAO,oBAAoB,OAAO,EAAE,MAAM,GAAG,GAAG;AAC5E,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AACA,WAAK,KAAK,EAAE,SAAS,MAAM,QAAQ,QAAQ,EAAE,CAAC;AAAA,IAChD,WAAW,WAAW,aAAa,WAAW,QAAQ;AACpD,UAAI,CAAC,OAAO,YAAY;AACtB,aAAK,KAAK,EAAE,SAAS,OAAO,OAAO,wBAAwB,GAAG,GAAG;AACjE,eAAO;AAAA,MACT;AACA,uBAAiB,QAAQ,KAAK;AAC9B,WAAK,KAAK,EAAE,SAAS,MAAM,QAAQ,QAAQ,EAAE,CAAC;AAAA,IAChD,OAAO;AACL,WAAK,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,GAAG,GAAG;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"service-routes.d.ts","sourceRoot":"","sources":["../../src/routes/service-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,uBAAuB,EAAE,gBAAgB,CAAC,CAAC;IACvE,IAAI,CAAC,EAAE,OAAO,WAAW,CAAC;CAC3B;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,IAOtD,KAAK;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,eAAe,CAAC;IACrB,GAAG,EAAE,cAAc,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,KAAG,OAAO,CAAC,OAAO,CAAC,CA8DrB"}
1
+ {"version":3,"file":"service-routes.d.ts","sourceRoot":"","sources":["../../src/routes/service-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,uBAAuB,EAAE,gBAAgB,CAAC,CAAC;IACvE,IAAI,CAAC,EAAE,OAAO,WAAW,CAAC;CAC3B;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,SAOjD;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,eAAe,CAAC;IACrB,GAAG,EAAE,cAAc,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,KAAG,OAAO,CAAC,OAAO,CAAC,CAsDrB"}