@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
@@ -0,0 +1,54 @@
1
+ import {
2
+ ensureModuleToken,
3
+ persistModuleAuth,
4
+ revokeModuleToken
5
+ } from "./module-auth.js";
6
+ import {
7
+ registerBuiltinPluginForModule,
8
+ unregisterBuiltinPluginForModule
9
+ } from "./services/builtin-handlers.js";
10
+ import { log } from "./lib/log.js";
11
+ function syncModuleRuntimeState(opts) {
12
+ const {
13
+ moduleId,
14
+ enabled,
15
+ dbPath,
16
+ envAuthToken,
17
+ enabledSet,
18
+ enabledManifests,
19
+ loadedManifest,
20
+ moduleAuth,
21
+ serviceRegistry,
22
+ builtinDeps
23
+ } = opts;
24
+ if (enabled) {
25
+ const manifest = loadedManifest.modules[moduleId];
26
+ if (!manifest) {
27
+ log.warn(`[modules] \u70ED\u542F\u7528 ${moduleId}: manifest \u7F3A\u5931(\u672A\u5B89\u88C5?),\u4EC5\u5199 lock`);
28
+ return;
29
+ }
30
+ enabledSet.add(moduleId);
31
+ enabledManifests.set(moduleId, manifest);
32
+ if (ensureModuleToken(moduleAuth, moduleId)) {
33
+ log.info(`[modules] \u70ED\u542F\u7528 ${moduleId}: \u6D3E\u751F module token`);
34
+ }
35
+ persistModuleAuth(dbPath, moduleAuth, envAuthToken);
36
+ if (registerBuiltinPluginForModule(serviceRegistry, builtinDeps, moduleId)) {
37
+ log.success(`[modules] \u70ED\u542F\u7528 ${moduleId}: \u5DF2\u6CE8\u518C\u5185\u7F6E service handlers`);
38
+ }
39
+ return;
40
+ }
41
+ enabledSet.delete(moduleId);
42
+ enabledManifests.delete(moduleId);
43
+ if (revokeModuleToken(moduleAuth, moduleId)) {
44
+ persistModuleAuth(dbPath, moduleAuth, envAuthToken);
45
+ }
46
+ const n = unregisterBuiltinPluginForModule(serviceRegistry, moduleId);
47
+ if (n > 0) {
48
+ log.info(`[modules] \u70ED\u7981\u7528 ${moduleId}: \u5378\u4E0B ${n} \u4E2A\u5185\u7F6E handlers`);
49
+ }
50
+ }
51
+ export {
52
+ syncModuleRuntimeState
53
+ };
54
+ //# sourceMappingURL=module-runtime-sync.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/module-runtime-sync.ts"],
4
+ "sourcesContent": ["/**\n * module-runtime-sync.ts \u2014 enable/disable \u65F6\u540C\u6B65\u8FDB\u7A0B\u5185\u8FD0\u884C\u6001\n *\n * lock \u843D\u76D8\u540E,\u5185\u5B58\u6001(enabledSet / enabledManifests / moduleAuth.tokens /\n * builtin service handlers)\u5FC5\u987B\u4E0E\u4E4B\u4E00\u81F4,\u5426\u5219\u300C\u53EA\u91CD\u542F BDS\u300D\u62FF\u4E0D\u5230\u65B0 token\n * (DIP:\u8DEF\u7531\u53EA\u4F9D\u8D56\u6CE8\u5165\u7684\u96C6\u5408,\u4E0D\u611F\u77E5\u542F\u505C\u5B9E\u73B0)\u3002\n *\n * DRY:token \u843D\u76D8 / \u5185\u7F6E handler \u542F\u505C\u590D\u7528 module-auth \u4E0E builtin-handlers,\n * \u4E0D\u5728\u6B64\u5904\u518D\u5199\u4E00\u4EFD\u6D3E\u751F\u4E0E\u5378\u8F7D\u903B\u8F91\u3002\n */\n\nimport type { ModuleManifestV2 } from \"./manifest-loader.js\";\nimport {\n ensureModuleToken,\n persistModuleAuth,\n revokeModuleToken,\n type ModuleAuthMap,\n} from \"./module-auth.js\";\nimport {\n registerBuiltinPluginForModule,\n unregisterBuiltinPluginForModule,\n type BuiltinServiceDeps,\n} from \"./services/builtin-handlers.js\";\nimport type { ServiceRegistry } from \"./service-registry.js\";\nimport { log } from \"./lib/log.js\";\n\nexport type LoadedModules = {\n modules: Record<string, ModuleManifestV2 | undefined>;\n};\n\nexport type SyncModuleRuntimeOpts = {\n moduleId: string;\n enabled: boolean;\n /** SQLite \u8DEF\u5F84\uFF1Btoken \u6587\u4EF6\u5199\u5728\u540C\u76EE\u5F55 */\n dbPath: string;\n /** \u4E0E buildModuleAuth \u4E00\u81F4:\u65E0 AUTH_TOKEN \u65F6 secretGenerated=true */\n envAuthToken: string;\n enabledSet: Set<string>;\n enabledManifests: Map<string, ModuleManifestV2>;\n loadedManifest: LoadedModules;\n moduleAuth: ModuleAuthMap;\n serviceRegistry: ServiceRegistry;\n builtinDeps: BuiltinServiceDeps;\n};\n\n/**\n * \u540C\u6B65 enable/disable \u540E\u7684\u8FDB\u7A0B\u5185\u96C6\u5408\u4E0E token \u6587\u4EF6\u3002\n * \u8C03\u7528\u65B9\u8D1F\u8D23\u5148\u5199 lock;\u672C\u51FD\u6570\u4E0D\u78B0\u78C1\u76D8 lock\u3002\n */\nexport function syncModuleRuntimeState(opts: SyncModuleRuntimeOpts): void {\n const {\n moduleId,\n enabled,\n dbPath,\n envAuthToken,\n enabledSet,\n enabledManifests,\n loadedManifest,\n moduleAuth,\n serviceRegistry,\n builtinDeps,\n } = opts;\n\n if (enabled) {\n const manifest = loadedManifest.modules[moduleId];\n if (!manifest) {\n log.warn(`[modules] \u70ED\u542F\u7528 ${moduleId}: manifest \u7F3A\u5931(\u672A\u5B89\u88C5?),\u4EC5\u5199 lock`);\n return;\n }\n enabledSet.add(moduleId);\n enabledManifests.set(moduleId, manifest);\n if (ensureModuleToken(moduleAuth, moduleId)) {\n log.info(`[modules] \u70ED\u542F\u7528 ${moduleId}: \u6D3E\u751F module token`);\n }\n persistModuleAuth(dbPath, moduleAuth, envAuthToken);\n if (registerBuiltinPluginForModule(serviceRegistry, builtinDeps, moduleId)) {\n log.success(`[modules] \u70ED\u542F\u7528 ${moduleId}: \u5DF2\u6CE8\u518C\u5185\u7F6E service handlers`);\n }\n return;\n }\n\n enabledSet.delete(moduleId);\n enabledManifests.delete(moduleId);\n if (revokeModuleToken(moduleAuth, moduleId)) {\n persistModuleAuth(dbPath, moduleAuth, envAuthToken);\n }\n const n = unregisterBuiltinPluginForModule(serviceRegistry, moduleId);\n if (n > 0) {\n log.info(`[modules] \u70ED\u7981\u7528 ${moduleId}: \u5378\u4E0B ${n} \u4E2A\u5185\u7F6E handlers`);\n }\n}\n"],
5
+ "mappings": "AAYA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,WAAW;AAyBb,SAAS,uBAAuB,MAAmC;AACxE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,SAAS;AACX,UAAM,WAAW,eAAe,QAAQ,QAAQ;AAChD,QAAI,CAAC,UAAU;AACb,UAAI,KAAK,gCAAiB,QAAQ,gEAA6B;AAC/D;AAAA,IACF;AACA,eAAW,IAAI,QAAQ;AACvB,qBAAiB,IAAI,UAAU,QAAQ;AACvC,QAAI,kBAAkB,YAAY,QAAQ,GAAG;AAC3C,UAAI,KAAK,gCAAiB,QAAQ,6BAAmB;AAAA,IACvD;AACA,sBAAkB,QAAQ,YAAY,YAAY;AAClD,QAAI,+BAA+B,iBAAiB,aAAa,QAAQ,GAAG;AAC1E,UAAI,QAAQ,gCAAiB,QAAQ,mDAA0B;AAAA,IACjE;AACA;AAAA,EACF;AAEA,aAAW,OAAO,QAAQ;AAC1B,mBAAiB,OAAO,QAAQ;AAChC,MAAI,kBAAkB,YAAY,QAAQ,GAAG;AAC3C,sBAAkB,QAAQ,YAAY,YAAY;AAAA,EACpD;AACA,QAAM,IAAI,iCAAiC,iBAAiB,QAAQ;AACpE,MAAI,IAAI,GAAG;AACT,QAAI,KAAK,gCAAiB,QAAQ,kBAAQ,CAAC,8BAAe;AAAA,EAC5D;AACF;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"permission-gate.d.ts","sourceRoot":"","sources":["../src/permission-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACrC,gBAAgB;IAChB,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,sBAAsB;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAoBD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAChD,QAAQ,EAAE,MAAM,GACf,OAAO,CAUT;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAChD,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG3B,QAAQ,EAAE,MAAM;IAAS,UAAU,EAAE,MAAM;IAF9D,IAAI,SAAuB;IAC3B,MAAM,SAAO;gBACM,QAAQ,EAAE,MAAM,EAAS,UAAU,EAAE,MAAM;CAG/D;AAED;;GAEG;AACH,eAAO,MAAM,IAAI;6BACC,MAAM;8BACL,MAAM;+BACL,MAAM;gCACL,MAAM;6BACT,MAAM;CACd,CAAC;AAEX,eAAO,MAAM,wBAAwB,aAAkB,CAAC"}
1
+ {"version":3,"file":"permission-gate.d.ts","sourceRoot":"","sources":["../src/permission-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,sBAAsB;IACrC,gBAAgB;IAChB,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,sBAAsB;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAoBD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAChD,QAAQ,EAAE,MAAM,GACf,OAAO,CAUT;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAChD,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG3B,QAAQ,EAAE,MAAM;IAAS,UAAU,EAAE,MAAM;IAF9D,IAAI,SAAuB;IAC3B,MAAM,SAAO;IACb,YAAmB,QAAQ,EAAE,MAAM,EAAS,UAAU,EAAE,MAAM,EAE7D;CACF;AAED;;GAEG;AACH,eAAO,MAAM,IAAI;aACf,MAAM,UAAU,MAAM;aACtB,OAAO,UAAU,MAAM;aACvB,UAAU,QAAQ,MAAM;aACxB,WAAW,QAAQ,MAAM;aACzB,OAAO,SAAS,MAAM;CACd,CAAC;AAEX,eAAO,MAAM,wBAAwB,aAAkB,CAAC"}
@@ -1,94 +1,63 @@
1
- /**
2
- * permission-gate.ts 模块权限校验
3
- *
4
- * 启动期:manifest.permissions 全在白名单(PERMISSION_KEYS),否则抛错启动失败。
5
- * (白名单 = db:read:*, db:write:*, config:read:*, config:write:*,
6
- * service:* + 通配 ** / <table>)
7
- *
8
- * 运行时:发起 db / config / service 调用时,gatesdb.<op>.requirePermission =
9
- * "db:read:<table>" / "db:write:<table>" / "config:read:<key>" /
10
- * "config:write:<key>" / "service:<name>"
11
- *
12
- * 设计:gate 不替路由拦截,是业务逻辑自己检查(避免每条路由都验)。
13
- * 路由层 fail-closed:不通过 manifest.permissions 表的调用 = 直接 403。
14
- */
15
- const PERMISSION_KEYS = new Set([
16
- // db:* 走模式匹配 db:read:* / db:write:*
17
- // 配置权限
18
- "config:read:*",
19
- "config:write:*",
20
- // service 在调用时按 service 名字匹配 service:* 通配
1
+ const PERMISSION_KEYS = /* @__PURE__ */ new Set([
2
+ // db:* 走模式匹配 db:read:* / db:write:*
3
+ // 配置权限
4
+ "config:read:*",
5
+ "config:write:*"
6
+ // service 在调用时按 service 名字匹配 service:* 通配
21
7
  ]);
22
8
  function validPermissionKey(k) {
23
- // 三类合法格式:
24
- // db:<op>:<table> (例 db:read:lands / db:write:land_members)
25
- // config:<op>:<key> (例 config:read:land / config:write:afk)
26
- // service:<name> (例 service:economy.debit / service:land.byId — 名字可含 .)
27
- // 不允许 raw "*"(要求明确对象) — 调试时一律 Resource-level
28
- if (/^service:[A-Za-z0-9_.]+$/.test(k))
29
- return true;
30
- return /^[a-z]+:[a-z]+:[A-Za-z0-9_.]+$/.test(k);
9
+ if (/^service:[A-Za-z0-9_.]+$/.test(k)) return true;
10
+ return /^[a-z]+:[a-z]+:[A-Za-z0-9_.]+$/.test(k);
31
11
  }
32
- /**
33
- * 启动期一次性校验:manifest.permissions 是否都合规。
34
- * 失败 = 抛错(启动失败)
35
- */
36
- export function validateManifestPermissions(moduleId, permissions) {
37
- const seen = new Set();
38
- for (const k of permissions) {
39
- if (!k || typeof k !== "string")
40
- throw new Error(`[perm] ${moduleId}: permission 不是字符串 "${k}"`);
41
- if (!validPermissionKey(k))
42
- throw new Error(`[perm] ${moduleId}: permission 格式不合法 "${k}"`);
43
- if (seen.has(k))
44
- throw new Error(`[perm] ${moduleId}: permission 重复 "${k}"`);
45
- seen.add(k);
46
- }
12
+ function validateManifestPermissions(moduleId, permissions) {
13
+ const seen = /* @__PURE__ */ new Set();
14
+ for (const k of permissions) {
15
+ if (!k || typeof k !== "string") throw new Error(`[perm] ${moduleId}: permission \u4E0D\u662F\u5B57\u7B26\u4E32 "${k}"`);
16
+ if (!validPermissionKey(k)) throw new Error(`[perm] ${moduleId}: permission \u683C\u5F0F\u4E0D\u5408\u6CD5 "${k}"`);
17
+ if (seen.has(k)) throw new Error(`[perm] ${moduleId}: permission \u91CD\u590D "${k}"`);
18
+ seen.add(k);
19
+ }
47
20
  }
48
- /**
49
- * 运行时:模块 id 是否拥有所需 permission。
50
- * 当前实现:必须精确等于才放行,不解释通配。
51
- * (PoC 简化;生产可加 db:read:* → 通配)
52
- */
53
- export function moduleHasPermission(modulePermissions, required) {
54
- if (!modulePermissions)
55
- return false;
56
- if (modulePermissions.includes(required))
57
- return true;
58
- // db:read:* / db:write:* / config:read:* / config:write:* 通配
59
- const parts = required.split(":");
60
- if (parts.length === 3) {
61
- const wildcard = `${parts[0]}:${parts[1]}:*`;
62
- if (modulePermissions.includes(wildcard))
63
- return true;
64
- }
65
- return false;
21
+ function moduleHasPermission(modulePermissions, required) {
22
+ if (!modulePermissions) return false;
23
+ if (modulePermissions.includes(required)) return true;
24
+ const parts = required.split(":");
25
+ if (parts.length === 3) {
26
+ const wildcard = `${parts[0]}:${parts[1]}:*`;
27
+ if (modulePermissions.includes(wildcard)) return true;
28
+ }
29
+ return false;
66
30
  }
67
- export function assertModulePermission(moduleId, modulePermissions, required) {
68
- if (!moduleHasPermission(modulePermissions, required)) {
69
- throw new PermissionDeniedError(moduleId, required);
70
- }
31
+ function assertModulePermission(moduleId, modulePermissions, required) {
32
+ if (!moduleHasPermission(modulePermissions, required)) {
33
+ throw new PermissionDeniedError(moduleId, required);
34
+ }
71
35
  }
72
- export class PermissionDeniedError extends Error {
73
- moduleId;
74
- permission;
75
- code = "permission_denied";
76
- status = 403;
77
- constructor(moduleId, permission) {
78
- super(`[perm] 模块 ${moduleId} 缺少权限 "${permission}"`);
79
- this.moduleId = moduleId;
80
- this.permission = permission;
81
- }
36
+ class PermissionDeniedError extends Error {
37
+ constructor(moduleId, permission) {
38
+ super(`[perm] \u6A21\u5757 ${moduleId} \u7F3A\u5C11\u6743\u9650 "${permission}"`);
39
+ this.moduleId = moduleId;
40
+ this.permission = permission;
41
+ }
42
+ moduleId;
43
+ permission;
44
+ code = "permission_denied";
45
+ status = 403;
82
46
  }
83
- /**
84
- * 所有 platform 派发的 required permission key 计算助手。
85
- */
86
- export const Perm = {
87
- dbRead: (table) => `db:read:${table}`,
88
- dbWrite: (table) => `db:write:${table}`,
89
- configRead: (key) => `config:read:${key}`,
90
- configWrite: (key) => `config:write:${key}`,
91
- service: (name) => `service:${name}`,
47
+ const Perm = {
48
+ dbRead: (table) => `db:read:${table}`,
49
+ dbWrite: (table) => `db:write:${table}`,
50
+ configRead: (key) => `config:read:${key}`,
51
+ configWrite: (key) => `config:write:${key}`,
52
+ service: (name) => `service:${name}`
92
53
  };
93
- export const PlatformTablePermissions = PERMISSION_KEYS;
94
- //# sourceMappingURL=permission-gate.js.map
54
+ const PlatformTablePermissions = PERMISSION_KEYS;
55
+ export {
56
+ Perm,
57
+ PermissionDeniedError,
58
+ PlatformTablePermissions,
59
+ assertModulePermission,
60
+ moduleHasPermission,
61
+ validateManifestPermissions
62
+ };
63
+ //# sourceMappingURL=permission-gate.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"permission-gate.js","sourceRoot":"","sources":["../src/permission-gate.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/permission-gate.ts"],
4
+ "sourcesContent": ["/**\n * permission-gate.ts \u2014 \u6A21\u5757\u6743\u9650\u6821\u9A8C\n *\n * \u542F\u52A8\u671F:manifest.permissions \u5168\u5728\u767D\u540D\u5355(PERMISSION_KEYS),\u5426\u5219\u629B\u9519\u542F\u52A8\u5931\u8D25\u3002\n * (\u767D\u540D\u5355 = db:read:*, db:write:*, config:read:*, config:write:*,\n * service:* + \u901A\u914D ** / <table>)\n *\n * \u8FD0\u884C\u65F6:\u53D1\u8D77 db / config / service \u8C03\u7528\u65F6,gatesdb.<op>.requirePermission =\n * \"db:read:<table>\" / \"db:write:<table>\" / \"config:read:<key>\" /\n * \"config:write:<key>\" / \"service:<name>\"\n *\n * \u8BBE\u8BA1:gate \u4E0D\u66FF\u8DEF\u7531\u62E6\u622A,\u662F\u4E1A\u52A1\u903B\u8F91\u81EA\u5DF1\u68C0\u67E5(\u907F\u514D\u6BCF\u6761\u8DEF\u7531\u90FD\u9A8C)\u3002\n * \u8DEF\u7531\u5C42 fail-closed:\u4E0D\u901A\u8FC7 manifest.permissions \u8868\u7684\u8C03\u7528 = \u76F4\u63A5 403\u3002\n */\n\nexport type PermissionKey = string;\nexport type PermissionLevel = \"Any\" | \"Member\" | \"OP\" | \"Admin\";\n\nexport interface ManifestPermissionRule {\n /** \u6A21\u5757\u58F0\u660E\u7684\u6743\u9650\u5168\u96C6 */\n permissions: PermissionKey[];\n /** \u8DE8\u6A21\u5757\u8C03\u7528\u5BF9\u5E94\u662F\u5426\u9700\u8981\u663E\u5F0F\u58F0\u660E */\n serviceRequires: string[];\n}\n\nconst PERMISSION_KEYS = new Set<string>([\n // db:* \u8D70\u6A21\u5F0F\u5339\u914D db:read:* / db:write:*\n // \u914D\u7F6E\u6743\u9650\n \"config:read:*\",\n \"config:write:*\",\n // service \u5728\u8C03\u7528\u65F6\u6309 service \u540D\u5B57\u5339\u914D service:* \u901A\u914D\n]);\n\nfunction validPermissionKey(k: string): boolean {\n // \u4E09\u7C7B\u5408\u6CD5\u683C\u5F0F:\n // db:<op>:<table> (\u4F8B db:read:lands / db:write:land_members)\n // config:<op>:<key> (\u4F8B config:read:land / config:write:afk)\n // service:<name> (\u4F8B service:economy.debit / service:land.byId \u2014 \u540D\u5B57\u53EF\u542B .)\n // \u4E0D\u5141\u8BB8 raw \"*\"(\u8981\u6C42\u660E\u786E\u5BF9\u8C61) \u2014 \u8C03\u8BD5\u65F6\u4E00\u5F8B Resource-level\n if (/^service:[A-Za-z0-9_.]+$/.test(k)) return true;\n return /^[a-z]+:[a-z]+:[A-Za-z0-9_.]+$/.test(k);\n}\n\n/**\n * \u542F\u52A8\u671F\u4E00\u6B21\u6027\u6821\u9A8C:manifest.permissions \u662F\u5426\u90FD\u5408\u89C4\u3002\n * \u5931\u8D25 = \u629B\u9519(\u542F\u52A8\u5931\u8D25)\u3002\n */\nexport function validateManifestPermissions(\n moduleId: string,\n permissions: readonly string[]\n): void {\n const seen = new Set<string>();\n for (const k of permissions) {\n if (!k || typeof k !== \"string\") throw new Error(`[perm] ${moduleId}: permission \u4E0D\u662F\u5B57\u7B26\u4E32 \"${k}\"`);\n if (!validPermissionKey(k)) throw new Error(`[perm] ${moduleId}: permission \u683C\u5F0F\u4E0D\u5408\u6CD5 \"${k}\"`);\n if (seen.has(k)) throw new Error(`[perm] ${moduleId}: permission \u91CD\u590D \"${k}\"`);\n seen.add(k);\n }\n}\n\n/**\n * \u8FD0\u884C\u65F6:\u6A21\u5757 id \u662F\u5426\u62E5\u6709\u6240\u9700 permission\u3002\n * \u5F53\u524D\u5B9E\u73B0:\u5FC5\u987B\u7CBE\u786E\u7B49\u4E8E\u624D\u653E\u884C,\u4E0D\u89E3\u91CA\u901A\u914D\u3002\n * (PoC \u7B80\u5316;\u751F\u4EA7\u53EF\u52A0 db:read:* \u2192 \u901A\u914D)\n */\nexport function moduleHasPermission(\n modulePermissions: readonly string[] | undefined,\n required: string\n): boolean {\n if (!modulePermissions) return false;\n if (modulePermissions.includes(required)) return true;\n // db:read:* / db:write:* / config:read:* / config:write:* \u901A\u914D\n const parts = required.split(\":\");\n if (parts.length === 3) {\n const wildcard = `${parts[0]}:${parts[1]}:*`;\n if (modulePermissions.includes(wildcard)) return true;\n }\n return false;\n}\n\nexport function assertModulePermission(\n moduleId: string,\n modulePermissions: readonly string[] | undefined,\n required: string\n): void {\n if (!moduleHasPermission(modulePermissions, required)) {\n throw new PermissionDeniedError(moduleId, required);\n }\n}\n\nexport class PermissionDeniedError extends Error {\n code = \"permission_denied\";\n status = 403;\n constructor(public moduleId: string, public permission: string) {\n super(`[perm] \u6A21\u5757 ${moduleId} \u7F3A\u5C11\u6743\u9650 \"${permission}\"`);\n }\n}\n\n/**\n * \u6240\u6709 platform \u6D3E\u53D1\u7684 required permission key \u8BA1\u7B97\u52A9\u624B\u3002\n */\nexport const Perm = {\n dbRead: (table: string) => `db:read:${table}`,\n dbWrite: (table: string) => `db:write:${table}`,\n configRead: (key: string) => `config:read:${key}`,\n configWrite: (key: string) => `config:write:${key}`,\n service: (name: string) => `service:${name}`,\n} as const;\n\nexport const PlatformTablePermissions = PERMISSION_KEYS;\n"],
5
+ "mappings": "AAyBA,MAAM,kBAAkB,oBAAI,IAAY;AAAA;AAAA;AAAA,EAGtC;AAAA,EACA;AAAA;AAEF,CAAC;AAED,SAAS,mBAAmB,GAAoB;AAM9C,MAAI,2BAA2B,KAAK,CAAC,EAAG,QAAO;AAC/C,SAAO,iCAAiC,KAAK,CAAC;AAChD;AAMO,SAAS,4BACd,UACA,aACM;AACN,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,KAAK,aAAa;AAC3B,QAAI,CAAC,KAAK,OAAO,MAAM,SAAU,OAAM,IAAI,MAAM,UAAU,QAAQ,gDAAuB,CAAC,GAAG;AAC9F,QAAI,CAAC,mBAAmB,CAAC,EAAG,OAAM,IAAI,MAAM,UAAU,QAAQ,gDAAuB,CAAC,GAAG;AACzF,QAAI,KAAK,IAAI,CAAC,EAAG,OAAM,IAAI,MAAM,UAAU,QAAQ,8BAAoB,CAAC,GAAG;AAC3E,SAAK,IAAI,CAAC;AAAA,EACZ;AACF;AAOO,SAAS,oBACd,mBACA,UACS;AACT,MAAI,CAAC,kBAAmB,QAAO;AAC/B,MAAI,kBAAkB,SAAS,QAAQ,EAAG,QAAO;AAEjD,QAAM,QAAQ,SAAS,MAAM,GAAG;AAChC,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,WAAW,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AACxC,QAAI,kBAAkB,SAAS,QAAQ,EAAG,QAAO;AAAA,EACnD;AACA,SAAO;AACT;AAEO,SAAS,uBACd,UACA,mBACA,UACM;AACN,MAAI,CAAC,oBAAoB,mBAAmB,QAAQ,GAAG;AACrD,UAAM,IAAI,sBAAsB,UAAU,QAAQ;AAAA,EACpD;AACF;AAEO,MAAM,8BAA8B,MAAM;AAAA,EAG/C,YAAmB,UAAyB,YAAoB;AAC9D,UAAM,uBAAa,QAAQ,8BAAU,UAAU,GAAG;AADjC;AAAyB;AAAA,EAE5C;AAAA,EAFmB;AAAA,EAAyB;AAAA,EAF5C,OAAO;AAAA,EACP,SAAS;AAIX;AAKO,MAAM,OAAO;AAAA,EAClB,QAAQ,CAAC,UAAkB,WAAW,KAAK;AAAA,EAC3C,SAAS,CAAC,UAAkB,YAAY,KAAK;AAAA,EAC7C,YAAY,CAAC,QAAgB,eAAe,GAAG;AAAA,EAC/C,aAAa,CAAC,QAAgB,gBAAgB,GAAG;AAAA,EACjD,SAAS,CAAC,SAAiB,WAAW,IAAI;AAC5C;AAEO,MAAM,2BAA2B;",
6
+ "names": []
7
+ }
@@ -60,9 +60,14 @@ export declare const json: typeof sharedJson;
60
60
  export declare const body: typeof sharedBody;
61
61
  /**
62
62
  * v2 失败信封权威形态(DRY + LSP):
63
- * 一律 `{ ok:false, error, code? }`,勿再混用 `{ success:false }`。
63
+ * 一律 `{ ok:false, error, code? }`(+ 可选 extra),勿再混用 `{ success:false }`。
64
64
  * service-routes / db / module-config / index 模块鉴权门应走此助手。
65
65
  */
66
- export declare function jsonV2Fail(res: ServerResponse, error: string, status: number, code?: string): void;
66
+ export declare function jsonV2Fail(res: ServerResponse, error: string, status: number, code?: string, extra?: Record<string, unknown>): void;
67
+ /**
68
+ * v2 成功信封权威形态(DRY + LSP):
69
+ * 一律 `{ ok:true, ...fields }`,与 jsonV2Fail 对称;客户端已双认 ok/success。
70
+ */
71
+ export declare function jsonV2Ok(res: ServerResponse, fields?: Record<string, unknown>, status?: number): void;
67
72
  export {};
68
73
  //# sourceMappingURL=_shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/routes/_shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/routes/_shared.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,18 @@
1
- /**
2
- * routes/_shared.ts — 路由模块共享类型 + 工厂
3
- *
4
- * 所有 db-server 路由统一:
5
- * - deps: { query, db, body, json, ... } ← 共享注入
6
- * - ctx: { path, method, params, req, res } ← 共享请求上下文
7
- * - return: boolean ← true 表示已处理
8
- *
9
- * http 工具 (json / body) 来自 lib/http.ts
10
- */
11
1
  import { body as sharedBody, json as sharedJson } from "../lib/http.js";
12
- /** 便捷 re-export:路由默认从这里取 json/body */
13
- export const json = sharedJson;
14
- export const body = sharedBody;
15
- /**
16
- * v2 失败信封权威形态(DRY + LSP):
17
- * 一律 `{ ok:false, error, code? }`,勿再混用 `{ success:false }`。
18
- * service-routes / db / module-config / index 模块鉴权门应走此助手。
19
- */
20
- export function jsonV2Fail(res, error, status, code) {
21
- const payload = { ok: false, error };
22
- if (code)
23
- payload.code = code;
24
- sharedJson(res, payload, status);
2
+ const json = sharedJson;
3
+ const body = sharedBody;
4
+ function jsonV2Fail(res, error, status, code, extra) {
5
+ const payload = { ...extra ?? {}, ok: false, error };
6
+ if (code) payload.code = code;
7
+ sharedJson(res, payload, status);
25
8
  }
26
- export {};
27
- //# sourceMappingURL=_shared.js.map
9
+ function jsonV2Ok(res, fields = {}, status = 200) {
10
+ sharedJson(res, { ...fields, ok: true }, status);
11
+ }
12
+ export {
13
+ body,
14
+ json,
15
+ jsonV2Fail,
16
+ jsonV2Ok
17
+ };
18
+ //# sourceMappingURL=_shared.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"_shared.js","sourceRoot":"","sources":["../../src/routes/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAyCxE,sCAAsC;AACtC,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC;AAC/B,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC;AAE/B;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,GAAmB,EACnB,KAAa,EACb,MAAc,EACd,IAAa;IAEb,MAAM,OAAO,GAA4B,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC9D,IAAI,IAAI;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,OAAO,EAAE,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/routes/_shared.ts"],
4
+ "sourcesContent": ["/**\n * routes/_shared.ts \u2014 \u8DEF\u7531\u6A21\u5757\u5171\u4EAB\u7C7B\u578B + \u5DE5\u5382\n *\n * \u6240\u6709 db-server \u8DEF\u7531\u7EDF\u4E00:\n * - deps: { query, db, body, json, ... } \u2190 \u5171\u4EAB\u6CE8\u5165\n * - ctx: { path, method, params, req, res } \u2190 \u5171\u4EAB\u8BF7\u6C42\u4E0A\u4E0B\u6587\n * - return: boolean \u2190 true \u8868\u793A\u5DF2\u5904\u7406\n *\n * http \u5DE5\u5177 (json / body) \u6765\u81EA lib/http.ts\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport type { Method } from \"../lib/http.js\";\nimport { body as sharedBody, json as sharedJson } from \"../lib/http.js\";\nimport type { QueryFn } from \"../lib/sqlite.js\";\n\nexport type { Method } from \"../lib/http.js\";\nexport type { QueryFn };\n\n/** shared deps factory \u2014 \u8DEF\u7531\u53EF\u58F0\u660E\u6700\u5C0F\u5316 deps \u5B50\u96C6 */\nexport type RouteDeps = {\n query: QueryFn;\n db: DatabaseSync;\n json: (res: ServerResponse, data: Record<string, unknown>, status?: number) => void;\n body: (req: IncomingMessage) => Promise<Record<string, unknown>>;\n params: URLSearchParams;\n projectRoot: string;\n monitorState?: { metrics: object | null; players: object[] };\n ensureEconomyAccount?: (\n playerId: string,\n playerName: string\n ) => { balance: number; player_id: string; version: number };\n economyResult?: (account: object | undefined) => { balance: number; version: number } | null;\n forwardToQQBridge?: (channelId: string, fromName: string, content: string, fromId: string) => void;\n land?: Record<string, (...args: unknown[]) => unknown>;\n};\n\n/** v2 \u6A21\u5757\u8EAB\u4EFD \u2014 \u7531 handle \u6821\u9A8C\u540E\u5199\u5165\u8DEF\u7531 ctx(\u52FF\u6302 req \u79C1\u6709\u5B57\u6BB5,LoD)\u3002 */\nexport type ModuleAuth = { id: string; permissions: string[] };\n\nexport type RouteCtx = {\n path: string;\n method: Method | string;\n params: URLSearchParams;\n req: IncomingMessage;\n res: ServerResponse;\n /** v2 \u8DEF\u7531\u4E13\u7528:\u6A21\u5757\u9274\u6743\u7ED3\u679C */\n moduleAuth?: ModuleAuth;\n};\n\nexport type RouteHandler = (ctx: RouteCtx) => Promise<boolean> | boolean;\n\nexport type RouteFactory = (deps: Partial<RouteDeps>) => RouteHandler;\n\n/** \u4FBF\u6377 re-export\uFF1A\u8DEF\u7531\u9ED8\u8BA4\u4ECE\u8FD9\u91CC\u53D6 json/body */\nexport const json = sharedJson;\nexport const body = sharedBody;\n\n/**\n * v2 \u5931\u8D25\u4FE1\u5C01\u6743\u5A01\u5F62\u6001(DRY + LSP):\n * \u4E00\u5F8B `{ ok:false, error, code? }`(+ \u53EF\u9009 extra),\u52FF\u518D\u6DF7\u7528 `{ success:false }`\u3002\n * service-routes / db / module-config / index \u6A21\u5757\u9274\u6743\u95E8\u5E94\u8D70\u6B64\u52A9\u624B\u3002\n */\nexport function jsonV2Fail(\n res: ServerResponse,\n error: string,\n status: number,\n code?: string,\n extra?: Record<string, unknown>\n): void {\n const payload: Record<string, unknown> = { ...(extra ?? {}), ok: false, error };\n if (code) payload.code = code;\n sharedJson(res, payload, status);\n}\n\n/**\n * v2 \u6210\u529F\u4FE1\u5C01\u6743\u5A01\u5F62\u6001(DRY + LSP):\n * \u4E00\u5F8B `{ ok:true, ...fields }`,\u4E0E jsonV2Fail \u5BF9\u79F0;\u5BA2\u6237\u7AEF\u5DF2\u53CC\u8BA4 ok/success\u3002\n */\nexport function jsonV2Ok(\n res: ServerResponse,\n fields: Record<string, unknown> = {},\n status = 200\n): void {\n sharedJson(res, { ...fields, ok: true }, status);\n}\n\nexport {};\n\n"],
5
+ "mappings": "AAcA,SAAS,QAAQ,YAAY,QAAQ,kBAAkB;AA0ChD,MAAM,OAAO;AACb,MAAM,OAAO;AAOb,SAAS,WACd,KACA,OACA,QACA,MACA,OACM;AACN,QAAM,UAAmC,EAAE,GAAI,SAAS,CAAC,GAAI,IAAI,OAAO,MAAM;AAC9E,MAAI,KAAM,SAAQ,OAAO;AACzB,aAAW,KAAK,SAAS,MAAM;AACjC;AAMO,SAAS,SACd,KACA,SAAkC,CAAC,GACnC,SAAS,KACH;AACN,aAAW,KAAK,EAAE,GAAG,QAAQ,IAAI,KAAK,GAAG,MAAM;AACjD;",
6
+ "names": []
7
+ }
@@ -16,8 +16,18 @@
16
16
  interface Deps {
17
17
  json: (res: import("http").ServerResponse, data: Record<string, unknown>, status?: number) => void;
18
18
  projectRoot: string;
19
+ /**
20
+ * 注入模块列表(与 GET /api/sfmc/modules 同源 — DRY)。
21
+ * 勿在本路由再读 catalog/lock(DIP:高层装配,路由只消费抽象)。
22
+ */
23
+ listModules?: () => Array<Record<string, unknown>>;
24
+ /**
25
+ * 注入模块 HMAC token 表(仅 loopback 可达;供 SAPI host-bootstrap 注入
26
+ * set*ModuleContext,因 SAPI 不能直接读与 DB 同目录的 module-tokens.json)。
27
+ */
28
+ getModuleTokens?: () => Record<string, string>;
19
29
  }
20
- declare function createConfigRoutes({ json, projectRoot }: Deps): ({ path: requestPath, method, params, res, }: {
30
+ declare function createConfigRoutes({ json, projectRoot, listModules, getModuleTokens }: Deps): ({ path: requestPath, method, params, res, }: {
21
31
  path: string;
22
32
  method: string;
23
33
  params: URLSearchParams;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/routes/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,UAAU,IAAI;IACZ,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;IACnG,WAAW,EAAE,MAAM,CAAC;CACrB;AAmCD,iBAAS,kBAAkB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,IAgIb,6CAKrC;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,CAAC;CACpC,KAAG,OAAO,CAAC,OAAO,CAAC,CAuErB;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/routes/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,UAAU,IAAI;IACZ,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;IACnG,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChD;AAmCD,iBAAS,kBAAkB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,IAAI,iDAgHhF;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,CAAC;CACpC,KAAG,OAAO,CAAC,OAAO,CAAC,CAuErB;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}