@oneentry/mcp-platform-server 0.1.3 → 0.1.5

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 (74) hide show
  1. package/dist/api/audit.d.ts.map +1 -0
  2. package/dist/api/audit.js.map +1 -0
  3. package/dist/api/auth.d.ts.map +1 -0
  4. package/dist/api/auth.js.map +1 -0
  5. package/dist/api/build-catalog.d.ts +1 -0
  6. package/dist/api/build-catalog.js +133 -20
  7. package/dist/api/catalog.d.ts +6 -1
  8. package/dist/api/catalog.d.ts.map +1 -0
  9. package/dist/api/catalog.js +53 -17
  10. package/dist/api/catalog.js.map +1 -0
  11. package/dist/api/client.d.ts +1 -0
  12. package/dist/api/client.d.ts.map +1 -0
  13. package/dist/api/client.js +9 -0
  14. package/dist/api/client.js.map +1 -0
  15. package/dist/api/normalize-schema.js +6 -1
  16. package/dist/api/operation-notes.d.ts +10 -0
  17. package/dist/api/operation-notes.js +146 -0
  18. package/dist/api/policy.d.ts.map +1 -0
  19. package/dist/api/policy.js.map +1 -0
  20. package/dist/api/shape.d.ts.map +1 -0
  21. package/dist/api/shape.js.map +1 -0
  22. package/dist/api/swagger-source.d.ts +13 -1
  23. package/dist/api/swagger-source.js +93 -32
  24. package/dist/api/types.d.ts +16 -0
  25. package/dist/api/types.d.ts.map +1 -0
  26. package/dist/api/types.js.map +1 -0
  27. package/dist/bin/cli.d.ts.map +1 -0
  28. package/dist/bin/cli.js.map +1 -0
  29. package/dist/config/config.d.ts.map +1 -0
  30. package/dist/config/config.js.map +1 -0
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +1 -1
  34. package/dist/index.js.map +1 -0
  35. package/dist/knowledge/chunk.d.ts.map +1 -0
  36. package/dist/knowledge/chunk.js.map +1 -0
  37. package/dist/knowledge/loader.d.ts.map +1 -0
  38. package/dist/knowledge/loader.js.map +1 -0
  39. package/dist/knowledge/ru-en-terms.d.ts +1 -0
  40. package/dist/knowledge/ru-en-terms.js +67 -0
  41. package/dist/knowledge/search.d.ts.map +1 -0
  42. package/dist/knowledge/search.js +2 -1
  43. package/dist/knowledge/search.js.map +1 -0
  44. package/dist/knowledge/types.d.ts.map +1 -0
  45. package/dist/knowledge/types.js.map +1 -0
  46. package/dist/server.d.ts.map +1 -0
  47. package/dist/server.js +19 -1
  48. package/dist/server.js.map +1 -0
  49. package/dist/session.d.ts.map +1 -0
  50. package/dist/session.js.map +1 -0
  51. package/dist/tools/api-call.d.ts.map +1 -0
  52. package/dist/tools/api-call.js +14 -1
  53. package/dist/tools/api-call.js.map +1 -0
  54. package/dist/tools/api-discovery.d.ts.map +1 -0
  55. package/dist/tools/api-discovery.js +109 -13
  56. package/dist/tools/api-discovery.js.map +1 -0
  57. package/dist/tools/docs.d.ts.map +1 -0
  58. package/dist/tools/docs.js +4 -1
  59. package/dist/tools/docs.js.map +1 -0
  60. package/dist/tools/guide.d.ts.map +1 -0
  61. package/dist/tools/guide.js +14 -2
  62. package/dist/tools/guide.js.map +1 -0
  63. package/dist/tools/result.d.ts.map +1 -0
  64. package/dist/tools/result.js.map +1 -0
  65. package/dist/tools/whoami.d.ts.map +1 -0
  66. package/dist/tools/whoami.js +5 -0
  67. package/dist/tools/whoami.js.map +1 -0
  68. package/dist/transports/http.d.ts.map +1 -0
  69. package/dist/transports/http.js +1 -1
  70. package/dist/transports/http.js.map +1 -0
  71. package/dist/transports/stdio.d.ts.map +1 -0
  72. package/dist/transports/stdio.js.map +1 -0
  73. package/knowledge/operating-rules.md +50 -41
  74. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/api/audit.ts"],"names":[],"mappings":"AAGA,6CAA6C;AAC7C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,QAAQ,GAAG,eAAe,GAAG,MAAM,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAKnD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM;IAItC;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI;CAWrD"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/api/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAezC;;;;GAIG;AACH,MAAM,OAAO,QAAQ;IACF,IAAI,CAAqB;IACzB,IAAI,CAAS;IAE9B,YAAY,MAAuC;QACjD,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAAa;QAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAsC;QAC3C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC;YACH,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,gEAAgE;AAChE,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oEAAoE;AACpE,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAevC,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAQhD,CAAC;AAEF;;;;GAIG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,WAAW,CAAA;KAAE;IASpF,8CAA8C;IAC9C,IAAI,YAAY,IAAI,OAAO,CAI1B;YAEa,IAAI;IAuBlB,OAAO,CAAC,MAAM,CAAC,QAAQ;IAgBvB,8DAA8D;IACxD,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBpC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;CAgBjC;AAED,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,KAAG,WAIrD,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAsBA,oEAAoE;AACpE,MAAM,OAAO,SAAU,SAAQ,KAAK;CAAG;AAEvC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAA2B,EAAE;IAClE,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChG,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAiC,CAAC;AAC3C,CAAC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAU,EAAE;IACxD,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACb,IAAI,CAAwB;IACnB,OAAO,CAAS;IAChB,SAAS,CAAS;IAClB,WAAW,CAAc;IAE1C,YAAY,MAAwE;QAClF,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI,YAAY;QACd,OAAO,OAAO,CACZ,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAChF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,IAAa;QAC5C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACrD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;SAC5C,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB;;;;eAIG;YACH,MAAM,IAAI,GACR,QAAQ,CAAC,MAAM,KAAK,GAAG;gBACrB,CAAC,CAAC,0IAA0I;gBAC5I,CAAC,CAAC,EAAE,CAAC;YACT,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,gBAAgB,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAEO,MAAM,CAAC,QAAQ,CAAC,GAAY;QAClC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC5C,MAAM,IAAI,SAAS,CAAC,gCAAgC,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,MAAM,GAAG,GAA8B,CAAC;QAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1C,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;QAC5C,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO;YACL,WAAW;YACX,YAAY,EAAE,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;SACnE,CAAC;IACJ,CAAC;IAED,8DAA8D;IAC9D,KAAK,CAAC,WAAW;QACf,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC1D,MAAM,IAAI,SAAS,CACjB,wFAAwF,CACzF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,QAAQ,CAC7B,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YAC7B,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK;YAC7B,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;SACpC,CAAC,CACH,CAAC;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;gBACpF,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;YACxB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC1D,MAAM,IAAI,SAAS,CAAC,2EAA2E,CAAC,CAAC;QACnG,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAc,EAAe,EAAE,CAAC,CAAC;IACrE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CACjD,CAAC,CAAC"}
@@ -7,4 +7,5 @@ export declare const buildCatalog: (params: {
7
7
  rawSwagger: string;
8
8
  permissions: PermissionMap;
9
9
  builtAt: string;
10
+ sourceUrl?: string;
10
11
  }) => Catalog;
@@ -1,24 +1,69 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { capSchema, normalizeSchema } from './normalize-schema.js';
3
+ import { ALWAYS_CONFIRM_PREFIXES, OPERATION_NOTES } from './operation-notes.js';
3
4
  const API_PREFIX = '/api/admin';
4
5
  const METHODS = ['get', 'post', 'put', 'patch', 'delete'];
5
- const ALWAYS_CONFIRM = [
6
- /^\/immutable-settings/,
7
- /^\/admins/,
8
- /^\/backups/,
9
- /^\/modules/,
10
- /^\/payments\/webhook/,
11
- /^\/auth\/logout\/all-users/,
12
- /^\/settings-general/,
13
- /^\/system\/captcha-keys/,
14
- ];
15
- const riskOf = (method) => {
6
+ const ALWAYS_CONFIRM = ALWAYS_CONFIRM_PREFIXES.map((prefix) => new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`));
7
+ const isGated = (path) => ALWAYS_CONFIRM.some((pattern) => pattern.test(path));
8
+ const riskOf = (method, opId, path) => {
16
9
  if (method === 'get') {
17
10
  return 'read';
18
11
  }
12
+ if (method === 'post' && OPERATION_NOTES[opId]?.readOnly === true && !isGated(path)) {
13
+ return 'read';
14
+ }
19
15
  return method === 'delete' ? 'destructive' : 'write';
20
16
  };
21
17
  const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
18
+ const jsonTypeOf = (value) => {
19
+ if (value === null) {
20
+ return 'null';
21
+ }
22
+ if (Array.isArray(value)) {
23
+ return 'array';
24
+ }
25
+ if (typeof value === 'number') {
26
+ return Number.isInteger(value) ? 'integer' : 'number';
27
+ }
28
+ return typeof value;
29
+ };
30
+ const typeFits = (declared, actual) => declared === actual ||
31
+ (declared === 'number' && actual === 'integer') ||
32
+ (declared === 'integer' && actual === 'number');
33
+ const markExampleMismatch = (schema, field) => {
34
+ if (schema['x-loose'] === true || schema.example === undefined || schema.type === undefined) {
35
+ return undefined;
36
+ }
37
+ const actual = jsonTypeOf(schema.example);
38
+ if (!typeFits(schema.type, actual)) {
39
+ const message = `declared "${schema.type}", example is ${actual}`;
40
+ schema['x-example-mismatch'] = message;
41
+ return `${field} (${message})`;
42
+ }
43
+ if (schema.type === 'array' && schema.items?.type !== undefined && schema.items['x-loose'] !== true) {
44
+ const first = schema.example[0];
45
+ if (first !== undefined && !typeFits(schema.items.type, jsonTypeOf(first))) {
46
+ const message = `items declared "${schema.items.type}", example items are ${jsonTypeOf(first)}`;
47
+ schema['x-example-mismatch'] = message;
48
+ return `${field} (${message})`;
49
+ }
50
+ }
51
+ return undefined;
52
+ };
53
+ const exampleMismatches = (body) => {
54
+ const properties = body?.schema.properties;
55
+ if (!properties) {
56
+ return [];
57
+ }
58
+ const found = [];
59
+ for (const [name, schema] of Object.entries(properties)) {
60
+ const mismatch = markExampleMismatch(schema, name);
61
+ if (mismatch) {
62
+ found.push(mismatch);
63
+ }
64
+ }
65
+ return found;
66
+ };
22
67
  const asString = (value) => typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;
23
68
  const responseSummary = (responses) => {
24
69
  if (!isRecord(responses)) {
@@ -60,6 +105,21 @@ const buildParams = (raw, components) => {
60
105
  }
61
106
  return params;
62
107
  };
108
+ const bodyExample = (media) => {
109
+ if (media['example'] !== undefined) {
110
+ return media['example'];
111
+ }
112
+ const examples = media['examples'];
113
+ if (!isRecord(examples)) {
114
+ return undefined;
115
+ }
116
+ for (const entry of Object.values(examples)) {
117
+ if (isRecord(entry) && entry['value'] !== undefined) {
118
+ return entry['value'];
119
+ }
120
+ }
121
+ return undefined;
122
+ };
63
123
  const buildBody = (raw, components) => {
64
124
  if (!isRecord(raw)) {
65
125
  return undefined;
@@ -76,9 +136,18 @@ const buildBody = (raw, components) => {
76
136
  if (!isRecord(media)) {
77
137
  return undefined;
78
138
  }
139
+ const schema = capSchema(normalizeSchema(media['schema'], components));
140
+ const example = bodyExample(media);
141
+ if (example !== undefined && schema.example === undefined) {
142
+ schema.example = example;
143
+ }
144
+ const description = asString(raw['description']);
145
+ if (description && schema['x-unresolved'] === true) {
146
+ schema.description = description.replace(/\s+/g, ' ').slice(0, 240);
147
+ }
79
148
  return {
80
149
  contentType,
81
- schema: capSchema(normalizeSchema(media['schema'], components)),
150
+ schema,
82
151
  required: raw['required'] === true,
83
152
  };
84
153
  };
@@ -96,6 +165,8 @@ export const buildCatalog = (params) => {
96
165
  const operations = [];
97
166
  const foreignPaths = [];
98
167
  const withoutOpId = [];
168
+ const unresolvedBodies = [];
169
+ const contradictoryExamples = [];
99
170
  for (const [fullPath, pathItem] of Object.entries(swagger['paths'])) {
100
171
  if (!isRecord(pathItem)) {
101
172
  continue;
@@ -118,9 +189,18 @@ export const buildCatalog = (params) => {
118
189
  const tags = operation['tags'];
119
190
  const tag = (Array.isArray(tags) ? asString(tags[0]) : undefined) ?? 'Other';
120
191
  const summary = asString(operation['summary']) ?? asString(operation['description']) ?? '';
121
- const risk = riskOf(method);
122
- const alwaysConfirm = method !== 'get' && ALWAYS_CONFIRM.some((pattern) => pattern.test(path));
192
+ const risk = riskOf(method, opId, path);
193
+ const alwaysConfirm = method !== 'get' && isGated(path);
123
194
  const permission = byOpId[opId];
195
+ const body = buildBody(operation['requestBody'], components);
196
+ if (body?.schema['x-unresolved'] === true) {
197
+ unresolvedBodies.push(body.schema.example === undefined ? `${opId} (no example)` : opId);
198
+ }
199
+ const mismatches = exampleMismatches(body);
200
+ if (mismatches.length > 0) {
201
+ contradictoryExamples.push(`${opId}: ${mismatches.join('; ')}`);
202
+ }
203
+ const notes = OPERATION_NOTES[opId];
124
204
  const entry = {
125
205
  opId,
126
206
  method,
@@ -132,12 +212,13 @@ export const buildCatalog = (params) => {
132
212
  risk,
133
213
  alwaysConfirm,
134
214
  params: buildParams(operation['parameters'], components),
135
- ...(buildBody(operation['requestBody'], components)
136
- ? { body: buildBody(operation['requestBody'], components) }
137
- : {}),
215
+ ...(body ? { body } : {}),
138
216
  ...(responseSummary(operation['responses'])
139
217
  ? { responseSummary: responseSummary(operation['responses']) }
140
218
  : {}),
219
+ ...(notes?.note ? { note: notes.note } : {}),
220
+ ...(notes?.verifyWith ? { verifyWith: notes.verifyWith } : {}),
221
+ ...(notes?.silentNoOp ? { silentNoOp: notes.silentNoOp } : {}),
141
222
  searchText: '',
142
223
  };
143
224
  entry.searchText = [opId, method.toUpperCase(), path, tag, summary, permission ?? '']
@@ -156,14 +237,45 @@ export const buildCatalog = (params) => {
156
237
  warnings.push(`${String(withoutOpId.length)} operation(s) have no operationId and cannot be called ` +
157
238
  `(e.g. ${withoutOpId.slice(0, 3).join(', ')}). Report it against the CMS.`);
158
239
  }
240
+ if (unresolvedBodies.length > 0) {
241
+ warnings.push(`${String(unresolvedBodies.length)} operation(s) declare a request body whose schema ` +
242
+ `does not resolve in the document (${unresolvedBodies.slice(0, 5).join(', ')}). ` +
243
+ 'Their body schema is marked "x-unresolved": true — build the body from the example ' +
244
+ 'cms_api_describe returns, and never from the empty schema. Report it against the CMS.');
245
+ }
246
+ if (contradictoryExamples.length > 0) {
247
+ warnings.push(`${String(contradictoryExamples.length)} field(s) carry an example that contradicts their ` +
248
+ `own declared type (${contradictoryExamples.slice(0, 3).join(' | ')}). ` +
249
+ 'Those fields are marked "x-example-mismatch" and listed by cms_api_describe — ' +
250
+ 'copy the example, not the type. Report it against the CMS.');
251
+ }
252
+ const noted = Object.keys(OPERATION_NOTES);
253
+ const notedButAbsent = noted.filter((opId) => !operations.some((operation) => operation.opId === opId));
254
+ if (notedButAbsent.length > 0 && notedButAbsent.length <= noted.length / 2) {
255
+ warnings.push(`${String(notedButAbsent.length)} operation(s) carry a curated behaviour note but are ` +
256
+ `absent from this catalog (${notedButAbsent.slice(0, 5).join(', ')}). ` +
257
+ 'Either this instance does not expose them, or the note table has gone stale — ' +
258
+ 'the note is not shown for an operation that is not there.');
259
+ }
159
260
  const known = new Set(operations.map((o) => o.opId));
160
261
  const missing = Object.keys(byOpId).filter((opId) => !known.has(opId) && !opId.startsWith('Developer') && !opId.startsWith('Content'));
161
262
  if (missing.length > 0) {
263
+ const isFiltered = missing.length > Object.keys(byOpId).length / 2;
162
264
  warnings.push(`${String(missing.length)} admin operation(s) declare a permission but are absent from the ` +
163
- `instance's API document (e.g. ${missing.slice(0, 3).join(', ')}). The bundled permission ` +
164
- 'map was generated from a different platform revision than this instance runs — update ' +
165
- 'the package if the catalog looks incomplete.');
265
+ `document served by ${params.sourceUrl ?? "the instance's API document"} ` +
266
+ `(e.g. ${missing.slice(0, 3).join(', ')}). ` +
267
+ (isFiltered
268
+ ? 'Most of the Admin API is missing, so that URL is serving the operation subset ' +
269
+ 'whitelisted for the workflow "admin-api" node rather than the whole API. The ' +
270
+ 'complete document is published by the instance itself at the base URL with ' +
271
+ '"-json" appended, but only while it runs with CORS_MODE=DEV. Until this ' +
272
+ 'instance supports the "full" parameter on the node endpoint, expect the ' +
273
+ 'catalog to cover only a fraction of the endpoints that exist.'
274
+ : 'The bundled permission map was generated from a different platform revision than ' +
275
+ 'this instance runs — update the package if the catalog looks incomplete.'));
166
276
  }
277
+ const mappedPermissions = new Set(Object.values(byOpId));
278
+ const permissionsWithoutOperation = permissions.filter((permission) => !mappedPermissions.has(permission));
167
279
  const knownPermissions = new Set(permissions);
168
280
  const orphanPermissions = [
169
281
  ...new Set(operations
@@ -182,6 +294,7 @@ export const buildCatalog = (params) => {
182
294
  swaggerHash: createHash('sha256').update(rawSwagger).digest('hex').slice(0, 16),
183
295
  permissions,
184
296
  warnings,
297
+ coverage: { unexposedOpIds: missing, permissionsWithoutOperation },
185
298
  operations,
186
299
  };
187
300
  };
@@ -11,17 +11,22 @@ export interface OperationHit {
11
11
  risk: Operation['risk'];
12
12
  score: number;
13
13
  }
14
+ export interface StartupAuth {
15
+ bearer?: string;
16
+ error?: string;
17
+ }
14
18
  export declare class OperationCatalog {
15
19
  private byOpId;
16
20
  catalog: Catalog;
17
21
  constructor(catalog: Catalog);
18
22
  static permissionMap(): PermissionMap;
19
- static resolve(config: Config, bearer?: string): Promise<OperationCatalog>;
23
+ static resolve(config: Config, auth?: StartupAuth): Promise<OperationCatalog>;
20
24
  get isEmpty(): boolean;
21
25
  adopt(other: OperationCatalog): void;
22
26
  get(opId: string): Operation | undefined;
23
27
  operations(): readonly Operation[];
24
28
  suggest(opId: string, limit?: number): string[];
29
+ unexposedMatches(query: string, limit?: number): string[];
25
30
  search(params: {
26
31
  query: string;
27
32
  tag?: string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/api/catalog.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAErD,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;gBAEd,OAAO,EAAE,OAAO;IAS5B,MAAM,CAAC,IAAI,IAAI,gBAAgB;IAK/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIxC,UAAU,IAAI,SAAS,SAAS,EAAE;IAIlC;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE;IAU1C,MAAM,CAAC,MAAM,EAAE;QACb,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,YAAY,EAAE;CA+CnB"}
@@ -2,7 +2,25 @@ import { readFileSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { dataDir } from '../knowledge/loader.js';
4
4
  import { buildCatalog } from './build-catalog.js';
5
- import { fetchSwagger } from './swagger-source.js';
5
+ import { fetchSwagger, nestSwaggerUrl, nodeSwaggerUrl, } from './swagger-source.js';
6
+ const loginWarning = (error) => `The startup login failed, so the API document was requested without a token: ${error}`;
7
+ const sourceWarnings = (swagger, auth) => {
8
+ const warnings = [];
9
+ const why = swagger.failures.length > 0 ? ` (${swagger.failures.join('; ')})` : '';
10
+ if (swagger.origin === 'cache') {
11
+ warnings.push(`Neither API document could be read${why}; this catalog came from the on-disk cache ` +
12
+ 'and may not match the API that is actually running.');
13
+ }
14
+ if (swagger.origin === 'instance-node') {
15
+ warnings.push(`${swagger.url} serves only the operations whitelisted for the workflow "admin-api" ` +
16
+ 'node, not the whole Admin API, so this catalog is a small subset of the endpoints ' +
17
+ `that exist. The complete document was not available${why}.`);
18
+ }
19
+ if (auth.error !== undefined) {
20
+ warnings.push(loginWarning(auth.error));
21
+ }
22
+ return warnings;
23
+ };
6
24
  export class OperationCatalog {
7
25
  byOpId;
8
26
  catalog;
@@ -10,7 +28,11 @@ export class OperationCatalog {
10
28
  if (catalog.version !== 1) {
11
29
  throw new Error(`Unsupported catalog version ${String(catalog.version)}`);
12
30
  }
13
- this.catalog = { ...catalog, warnings: catalog.warnings ?? [] };
31
+ this.catalog = {
32
+ ...catalog,
33
+ warnings: catalog.warnings ?? [],
34
+ coverage: catalog.coverage ?? { unexposedOpIds: [], permissionsWithoutOperation: [] },
35
+ };
14
36
  this.byOpId = new Map(catalog.operations.map((o) => [o.opId, o]));
15
37
  }
16
38
  static permissionMap() {
@@ -18,30 +40,25 @@ export class OperationCatalog {
18
40
  const parsed = JSON.parse(readFileSync(file, 'utf8'));
19
41
  return { byOpId: parsed.byOpId, permissions: parsed.permissions };
20
42
  }
21
- static async resolve(config, bearer) {
43
+ static async resolve(config, auth = {}) {
22
44
  const builtAt = new Date().toISOString();
23
45
  try {
24
46
  const swagger = await fetchSwagger({
25
47
  baseUrl: config.baseUrl,
26
48
  cacheDir: config.cacheDir,
27
49
  timeoutMs: config.requestTimeoutMs,
28
- ...(bearer ? { bearer } : {}),
50
+ ...(auth.bearer ? { bearer: auth.bearer } : {}),
29
51
  });
30
52
  const catalog = buildCatalog({
31
53
  rawSwagger: swagger.raw,
32
54
  permissions: OperationCatalog.permissionMap(),
33
55
  builtAt,
56
+ sourceUrl: swagger.url,
57
+ });
58
+ return new OperationCatalog({
59
+ ...catalog,
60
+ warnings: [...catalog.warnings, ...sourceWarnings(swagger, auth)],
34
61
  });
35
- return new OperationCatalog(swagger.origin === 'cache'
36
- ? {
37
- ...catalog,
38
- warnings: [
39
- ...catalog.warnings,
40
- `The instance at ${config.baseUrl} was unreachable; this catalog came from the ` +
41
- 'on-disk cache and may not match the API that is actually running.',
42
- ],
43
- }
44
- : catalog);
45
62
  }
46
63
  catch (error) {
47
64
  return new OperationCatalog({
@@ -51,10 +68,13 @@ export class OperationCatalog {
51
68
  swaggerHash: '',
52
69
  permissions: [],
53
70
  warnings: [
54
- `The operation catalog is EMPTY: ${config.baseUrl} did not serve its API document ` +
55
- `(${error instanceof Error ? error.message : String(error)}). ` +
56
- 'No API operation can be searched or called until the instance is reachable.',
71
+ `The operation catalog is EMPTY: ${error instanceof Error ? error.message : String(error)}. ` +
72
+ 'No API operation can be searched or called until either ' +
73
+ `${nestSwaggerUrl(config.baseUrl)} or ${nodeSwaggerUrl(config.baseUrl)} ` +
74
+ 'answers 200 with an OpenAPI document.',
75
+ ...(auth.error === undefined ? [] : [loginWarning(auth.error)]),
57
76
  ],
77
+ coverage: { unexposedOpIds: [], permissionsWithoutOperation: [] },
58
78
  operations: [],
59
79
  });
60
80
  }
@@ -81,6 +101,22 @@ export class OperationCatalog {
81
101
  .slice(0, limit)
82
102
  .map((entry) => entry.opId);
83
103
  }
104
+ unexposedMatches(query, limit = 5) {
105
+ const terms = query
106
+ .toLowerCase()
107
+ .split(/[\s/.]+/)
108
+ .filter((term) => term.length > 2);
109
+ if (terms.length === 0) {
110
+ return [];
111
+ }
112
+ const { unexposedOpIds, permissionsWithoutOperation } = this.catalog.coverage;
113
+ return [...unexposedOpIds, ...permissionsWithoutOperation]
114
+ .filter((name) => {
115
+ const haystack = name.toLowerCase();
116
+ return terms.some((term) => haystack.includes(term));
117
+ })
118
+ .slice(0, limit);
119
+ }
84
120
  search(params) {
85
121
  const terms = params.query
86
122
  .toLowerCase()
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/api/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAejD;;;;;GAKG;AACH,MAAM,OAAO,gBAAgB;IACV,MAAM,CAAyB;IACvC,OAAO,CAAU;IAE1B,YAAY,OAAgB;QAC1B,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,mFAAmF;QACnF,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QAChE,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,IAAI;QACT,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;QAChD,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC,CAAC;IACjF,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,IAAY,EAAE,KAAK,GAAG,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU;aAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;aAC5E,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;aAClC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;aACjC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;aACf,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,MAMN;QACC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK;aACvB,WAAW,EAAE;aACb,KAAK,CAAC,SAAS,CAAC;aAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAmB,EAAE,CAAC;QAEhC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YAChD,IAAI,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC3E,SAAS;YACX,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;gBACtE,SAAS;YACX,CAAC;YACD,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,CAAC;gBACrF,SAAS;YACX,CAAC;YAED,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAChD,KAAK,IAAI,CAAC,CAAC;gBACb,CAAC;gBACD,IAAI,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/C,KAAK,IAAI,CAAC,CAAC;gBACb,CAAC;gBACD,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxC,KAAK,IAAI,CAAC,CAAC;gBACb,CAAC;YACH,CAAC;YACD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,IAAI,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE;oBACtC,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,GAAG,EAAE,SAAS,CAAC,GAAG;oBAClB,OAAO,EAAE,SAAS,CAAC,OAAO;oBAC1B,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrE,IAAI,EAAE,SAAS,CAAC,IAAI;oBACpB,KAAK;iBACN,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,iFAAiF;AACjF,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;IAC/C,MAAM,KAAK,GAAG,CAAC,KAAa,EAAe,EAAE;QAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC;AACpD,CAAC,CAAC"}
@@ -21,6 +21,7 @@ export type CallResult = {
21
21
  export declare class RequestBuildError extends Error {
22
22
  }
23
23
  export declare const normalizeBody: (body: unknown) => unknown;
24
+ export declare const unsupportedBodyFormat: (operation: Operation) => string | undefined;
24
25
  export declare const buildUrl: (baseUrl: string, operation: Operation, args: CallArgs) => string;
25
26
  export declare class AdminApiClient {
26
27
  private readonly baseUrl;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uEAAuE;AACvE,MAAM,MAAM,UAAU,GAClB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC3C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC;AAE1C,2DAA2D;AAC3D,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,OAAO,KAAG,OAc7C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GACnB,SAAS,MAAM,EACf,WAAW,SAAS,EACpB,MAAM,QAAQ,KACb,MAkCF,CAAC;AAqDF;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAMxE,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAiDrE,8EAA8E;IACxE,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAyB3D"}
@@ -16,6 +16,15 @@ export const normalizeBody = (body) => {
16
16
  return body;
17
17
  }
18
18
  };
19
+ export const unsupportedBodyFormat = (operation) => {
20
+ const contentType = operation.body?.contentType;
21
+ if (contentType === undefined || /^application\/(\w[\w.+-]*\+)?json$/.test(contentType)) {
22
+ return undefined;
23
+ }
24
+ return (`Operation ${operation.opId} expects a "${contentType}" request body, and this server ` +
25
+ 'can only send application/json. The call is not executable through MCP — no body ' +
26
+ 'shape will help. Report it to the human and use another route to that instance.');
27
+ };
19
28
  export const buildUrl = (baseUrl, operation, args) => {
20
29
  let path = operation.path;
21
30
  const provided = args.path ?? {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -36,7 +36,12 @@ export const normalizeSchema = (node, components, depth = 0, refStack = []) => {
36
36
  }
37
37
  const target = components[name];
38
38
  if (target === undefined) {
39
- return { type: 'object', description: `(unresolved ${name})` };
39
+ return {
40
+ type: 'object',
41
+ description: `(unresolved ${name})`,
42
+ 'x-loose': true,
43
+ 'x-unresolved': true,
44
+ };
40
45
  }
41
46
  return normalizeSchema(target, components, depth, [...refStack, name]);
42
47
  }
@@ -0,0 +1,10 @@
1
+ import type { VerifyWith } from './types.js';
2
+ export interface OperationNote {
3
+ note?: string;
4
+ verifyWith?: VerifyWith;
5
+ silentNoOp?: string;
6
+ readOnly?: true;
7
+ }
8
+ export declare const ALWAYS_CONFIRM_PREFIXES: readonly string[];
9
+ export declare const OPERATION_NOTES: Readonly<Record<string, OperationNote>>;
10
+ export declare const readOnlyOpIds: () => string[];
@@ -0,0 +1,146 @@
1
+ export const ALWAYS_CONFIRM_PREFIXES = [
2
+ '/immutable-settings',
3
+ '/admins',
4
+ '/backups',
5
+ '/modules',
6
+ '/payments/webhook',
7
+ '/auth/logout/all-users',
8
+ '/settings-general',
9
+ '/system/captcha-keys',
10
+ ];
11
+ export const OPERATION_NOTES = {
12
+ AdminProductsController_findAll: {
13
+ readOnly: true,
14
+ note: 'Pagination and locale are query parameters, not body fields: pass limit, offset and ' +
15
+ 'langCode in "query". The body is an ARRAY of filter objects — send [] for no filter. ' +
16
+ 'A body of { limit, offset, langCode } answers 400 complaining about langCode, because ' +
17
+ 'the validator is describing the query parameter you did not send.',
18
+ },
19
+ AdminProductsController_setStatusForProducts: {
20
+ silentNoOp: 'The status id goes in "id", not "statusId". With "statusId" the handler reads ' +
21
+ 'undefined, writes NULL over the product status and still answers 201 true. The call ' +
22
+ 'also never re-indexes, so even a correct write stays invisible to ' +
23
+ 'AdminProductsController_findAll. Setting statusId through ' +
24
+ 'AdminProductsController_update is the route that works today.',
25
+ verifyWith: {
26
+ opId: 'AdminProductsController_findOne',
27
+ check: 'statusId',
28
+ why: 'the call answers 201 true whether or not any row changed',
29
+ },
30
+ },
31
+ AdminAttributesSetsController_create: {
32
+ note: 'Inside an attribute, "validators", "localizeInfos" and "listTitles" are keyed by ' +
33
+ 'locale first: validators.en_US.requiredValidator, not validators.requiredValidator. ' +
34
+ 'A flat map is stored verbatim and read by nobody.',
35
+ verifyWith: {
36
+ opId: 'AdminAttributesSetsController_findOne',
37
+ check: 'schema[].validators.<locale>',
38
+ why: 'the raw set shows exactly what you wrote, including a flat map that no consumer reads',
39
+ },
40
+ },
41
+ AdminAttributesSetsController_update: {
42
+ note: 'Inside an attribute, "validators", "localizeInfos" and "listTitles" are keyed by ' +
43
+ 'locale first. A flat map is accepted and stored where nothing reads it.',
44
+ verifyWith: {
45
+ opId: 'AdminAttributesSetsController_findOne',
46
+ check: 'schema[].validators.<locale>',
47
+ why: 'the raw set shows what you wrote; the projection a site reads shows what it gets',
48
+ },
49
+ },
50
+ AdminAttributesSetsController_updateSchema: {
51
+ note: 'The body is the schema object itself, never wrapped as { "schema": … }. The wrapped ' +
52
+ 'form answers 200 and replaces the set with a single attribute called "schema". ' +
53
+ 'Locale-keyed rules apply here too.',
54
+ verifyWith: {
55
+ opId: 'AdminAttributesSetsController_findOne',
56
+ check: 'schema[].validators.<locale>',
57
+ why: 'a wrapped or flat body answers 200 and destroys or discards what you sent',
58
+ },
59
+ },
60
+ AdminFileUploadController_uploadFiles: {
61
+ note: 'The "template" query parameter is the NUMERIC id of a /template-previews record, not ' +
62
+ 'a boolean flag. A fresh instance has no such records, and an upload without a valid ' +
63
+ 'template id stores the file with no preview and reports no error.',
64
+ },
65
+ AdminMenusController_create: {
66
+ note: 'Create the menu with an empty pagesIds, then attach pages with AdminMenusController_update. ' +
67
+ 'A non-empty pagesIds on create answers 500 (null value in column "page_id"). That 500 is ' +
68
+ 'known — do not report it as an unexplained server failure.',
69
+ },
70
+ AdminFormsController_create: {
71
+ note: 'Send the payload wrapped under "newForm". The form "type" is missing from the schema but ' +
72
+ 'is accepted and persisted: order | sign_in_up | collection | data | rating. A contact ' +
73
+ 'form is "data". Omit it and the form is created with type null.',
74
+ verifyWith: {
75
+ opId: 'AdminFormsController_findAll',
76
+ check: 'type',
77
+ why: 'the field is absent from the schema, so an omitted type is not reported as missing',
78
+ },
79
+ },
80
+ AdminFormsController_update: {
81
+ note: '"formModuleConfigs" is a full replacement list, not a patch. Omitting it deletes every ' +
82
+ 'module binding of the form AND the submissions recorded against those bindings, and the ' +
83
+ 'call still answers 200 true. Read the form first and send its current formModuleConfigs ' +
84
+ 'back unless changing them is the point. This is also the only operation that creates a ' +
85
+ 'binding: an entry with formId, moduleId and either isGlobal or entityIdentifiers.',
86
+ verifyWith: {
87
+ opId: 'AdminFormsController_findOne',
88
+ check: 'formModuleConfigs',
89
+ why: 'an omitted formModuleConfigs is applied as "unbind everything", submissions included',
90
+ },
91
+ },
92
+ AdminFormDataController_create: {
93
+ note: 'A submission needs formIdentifier, formModuleConfigId, moduleEntityIdentifier and ' +
94
+ 'locale-keyed formData. formModuleConfigId is the id of a module binding, which only ' +
95
+ 'AdminFormsController_update creates and only AdminFormsController_findOne reports, under ' +
96
+ 'formModuleConfigs[].id — a freshly created form has none and accepts nothing. The server ' +
97
+ 'joins the config back to its form and compares identifiers, so a config id belonging to ' +
98
+ 'another form, or to no form, answers 400 "Incorrect formIdentifier for provided config": ' +
99
+ 'the message names formIdentifier, the wrong field is usually the config id. Checks run ' +
100
+ 'fields first, then the form type, then the config, so a field error arriving first does ' +
101
+ 'not mean the config is optional. A form with type null fails earlier with "Form has ' +
102
+ 'incorrect type". Field validation is wired into the Content API only: through the Admin ' +
103
+ 'API a missing required field is stored rather than rejected, so a submission accepted ' +
104
+ 'here does not prove a visitor\'s submission would pass.',
105
+ verifyWith: {
106
+ opId: 'AdminFormDataController_findByFormMarker',
107
+ check: 'the submission you sent',
108
+ why: 'the stored submission is the only proof the binding it names is the intended one',
109
+ },
110
+ },
111
+ AdminPagesController_update: {
112
+ note: 'Omitting parentId does not leave the parent alone — it moves the page to the root and ' +
113
+ 'decrements the former parent\'s childrenCount. Read the page first and send parentId ' +
114
+ 'back unchanged unless you mean to re-parent it.',
115
+ verifyWith: {
116
+ opId: 'AdminPagesController_findOne',
117
+ check: 'parentId',
118
+ why: 'an omitted parentId is applied as "move to root", and the update still answers 200',
119
+ },
120
+ },
121
+ AdminBlocksController_update: {
122
+ note: 'Omitting blockPages detaches the block from every page it was on. Read the block first ' +
123
+ 'and send its current page list back unless you mean to change it.',
124
+ verifyWith: {
125
+ opId: 'AdminBlocksController_findOne',
126
+ check: 'blockPages',
127
+ why: 'an omitted blockPages is applied as "detach everything", and the update answers 200',
128
+ },
129
+ },
130
+ AdminProductsController_countAll: { readOnly: true },
131
+ AdminProductsController_findByIds: { readOnly: true },
132
+ AdminProductsController_findAllByWithOutCategory: { readOnly: true },
133
+ AdminProductsController_findAllByCategoryIdForAdmin: { readOnly: true },
134
+ AdminProductsController_countByCategoryId: { readOnly: true },
135
+ AdminProductsController_countByCategoryMarker: { readOnly: true },
136
+ AdminUsersController_findAllByConditions: { readOnly: true },
137
+ AdminUsersController_search: { readOnly: true },
138
+ AdminFormDataController_findByFormMarker: { readOnly: true },
139
+ AdminBlocksController_findCartComplementProductsByBody: { readOnly: true },
140
+ AdminBlocksController_findCartSimilarProductsByBody: { readOnly: true },
141
+ AdminBlocksController_findWishlistSimilarProductsByBody: { readOnly: true },
142
+ AdminUserGroupsController_getGroupRoutesWithPermissions: { readOnly: true },
143
+ };
144
+ export const readOnlyOpIds = () => Object.entries(OPERATION_NOTES)
145
+ .filter(([, note]) => note.readOnly === true)
146
+ .map(([opId]) => opId);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/api/policy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAO7C;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0D;IAEjF,OAAO,CAAC,MAAM,CAAC,IAAI;IAMnB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,MAAM;IAU5D;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,OAAO;IAS7E,8EAA8E;IAC9E,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,OAAO;IAU9E,OAAO,CAAC,KAAK;CAOd;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,GACrB,WAAW,SAAS,EACpB,OAAO,UAAU,KAChB,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAY9C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;CACvB,KAAG,cAoCH,CAAC"}