@classytic/arc 2.18.5 → 2.20.0

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 (92) hide show
  1. package/README.md +1 -1
  2. package/bin/arc.js +37 -0
  3. package/dist/{BaseController-Dy6EQHjM.mjs → BaseController-D-MHZ27_.mjs} +4 -4
  4. package/dist/{ResourceRegistry-5fKZwhK_.mjs → ResourceRegistry-7RnrEWNP.mjs} +1 -1
  5. package/dist/{actionPermissions-h7DYDNMg.mjs → actionPermissions-C9RMiIpc.mjs} +2 -1
  6. package/dist/audit/index.mjs +1 -1
  7. package/dist/auth/index.d.mts +1 -1
  8. package/dist/auth/index.mjs +17 -6
  9. package/dist/{buildHandler-B0qvAguf.mjs → buildHandler-D_2ULWxZ.mjs} +3 -3
  10. package/dist/cache/index.mjs +2 -2
  11. package/dist/cli/commands/describe.d.mts +1 -1
  12. package/dist/cli/commands/describe.mjs +2 -2
  13. package/dist/cli/commands/docs.mjs +2 -2
  14. package/dist/cli/commands/generate.mjs +1 -1
  15. package/dist/cli/commands/init.mjs +1 -1
  16. package/dist/cli/commands/introspect.mjs +4 -13
  17. package/dist/cli/index.mjs +2 -2
  18. package/dist/{constants-gaEeMlz-.mjs → constants-DNre0wRg.mjs} +1 -1
  19. package/dist/core/index.d.mts +2 -2
  20. package/dist/core/index.mjs +4 -4
  21. package/dist/{core-ZnQBa5rh.mjs → core-CWhyGkiM.mjs} +136 -59
  22. package/dist/{createActionRouter-CagItpxI.mjs → createActionRouter-HlQso0jO.mjs} +8 -7
  23. package/dist/{createAggregationRouter-DVKroXhC.mjs → createAggregationRouter-5LzPzgw1.mjs} +5 -4
  24. package/dist/{createApp--703hQE1.mjs → createApp-D6uwzCKu.mjs} +210 -17
  25. package/dist/docs/index.d.mts +1 -1
  26. package/dist/docs/index.mjs +1 -1
  27. package/dist/encryption/index.d.mts +222 -0
  28. package/dist/encryption/index.mjs +270 -0
  29. package/dist/events/index.mjs +9 -6
  30. package/dist/factory/index.d.mts +3 -2
  31. package/dist/factory/index.mjs +2 -2
  32. package/dist/{fastify-augmentation-Cxb0ROIw.d.mts → fastify-augmentation-CCQJEDgh.d.mts} +12 -1
  33. package/dist/{generate-Brans3fW.mjs → generate-usRSdQmP.mjs} +4 -3
  34. package/dist/hooks/index.d.mts +1 -1
  35. package/dist/idempotency/index.mjs +1 -1
  36. package/dist/{index-CRKiiP5o.d.mts → index-CdFkIMEd.d.mts} +5 -0
  37. package/dist/{index-Dh0_RSTd.d.mts → index-DUa8WHz3.d.mts} +7 -7
  38. package/dist/{index-CHNQIhcb.d.mts → index-_--GyzcO.d.mts} +111 -2
  39. package/dist/index.d.mts +3 -3
  40. package/dist/index.mjs +6 -6
  41. package/dist/{init-Bqpt1Hxf.mjs → init-YH_nslQR.mjs} +87 -5
  42. package/dist/integrations/index.d.mts +1 -1
  43. package/dist/integrations/mcp/index.d.mts +2 -2
  44. package/dist/integrations/mcp/index.mjs +1 -1
  45. package/dist/integrations/mcp/testing.d.mts +1 -1
  46. package/dist/integrations/mcp/testing.mjs +1 -1
  47. package/dist/integrations/streamline.d.mts +17 -5
  48. package/dist/integrations/streamline.mjs +9 -5
  49. package/dist/{loadResourcesFromEntry-BTlFEx05.mjs → loadResourcesFromEntry-OMCvIEE7.mjs} +1 -1
  50. package/dist/{mcpPlugin-D1wuRD2c.mjs → mcpPlugin-CuW6L_uD.mjs} +148 -49
  51. package/dist/middleware/index.d.mts +1 -1
  52. package/dist/middleware/index.mjs +1 -1
  53. package/dist/module-JYH9V0I8.d.mts +384 -0
  54. package/dist/{openapi-xVJibapr.mjs → openapi-Dq6RbEGK.mjs} +3 -3
  55. package/dist/permissions/index.d.mts +1 -1
  56. package/dist/permissions/index.mjs +1 -1
  57. package/dist/{permissions-BPB1xqGf.mjs → permissions-CgbOLJZG.mjs} +10 -2
  58. package/dist/pipeline/index.d.mts +1 -1
  59. package/dist/plugins/index.d.mts +10 -5
  60. package/dist/plugins/index.mjs +3 -3
  61. package/dist/plugins/tracing-entry.mjs +1 -1
  62. package/dist/{pluralize-DccFV9R7.mjs → pluralize-BhrgwZb9.mjs} +3 -3
  63. package/dist/presets/filesUpload.d.mts +1 -1
  64. package/dist/presets/filesUpload.mjs +1 -1
  65. package/dist/presets/index.d.mts +16 -2
  66. package/dist/presets/index.mjs +1 -1
  67. package/dist/presets/multiTenant.d.mts +1 -1
  68. package/dist/presets/multiTenant.mjs +1 -1
  69. package/dist/presets/search.d.mts +1 -1
  70. package/dist/presets/search.mjs +3 -2
  71. package/dist/{presets-BtyFwTO4.mjs → presets-DWsYQdbV.mjs} +1 -1
  72. package/dist/{queryCachePlugin-emHb0CuX.mjs → queryCachePlugin-DzqLN904.mjs} +2 -2
  73. package/dist/{registerRoute-CPmdkZGu.mjs → registerRoute-DGSREwPw.mjs} +20 -2
  74. package/dist/registry/index.d.mts +1 -1
  75. package/dist/registry/index.mjs +2 -2
  76. package/dist/{registry-Bm9LjWKs.mjs → registry-vcOCtPij.mjs} +1 -1
  77. package/dist/{schemaIR-D1MJwqmp.mjs → schemaIR-ajetw3Fv.mjs} +1 -42
  78. package/dist/scim/index.mjs +2 -2
  79. package/dist/sync/changelog.d.mts +2 -0
  80. package/dist/sync/changelog.mjs +2 -0
  81. package/dist/testing/index.d.mts +2 -2
  82. package/dist/testing/index.mjs +2 -2
  83. package/dist/types/index.d.mts +2 -2
  84. package/dist/{types-CmkknLzI.d.mts → types-BHMKlMBU.d.mts} +53 -195
  85. package/dist/{types-D60PFwfG.d.mts → types-C9b2HR5W.d.mts} +1 -1
  86. package/dist/utils/index.d.mts +1 -1
  87. package/dist/utils/index.mjs +1 -1
  88. package/dist/{utils-C6QQ9-hd.mjs → utils-ChjYQpjn.mjs} +1400 -1400
  89. package/dist/{validate-CRcaWzp2.mjs → validate-C2mGgSXg.mjs} +3 -3
  90. package/package.json +22 -8
  91. package/skills/arc/SKILL.md +10 -0
  92. package/skills/arc/references/mcp.md +2 -0
@@ -316,14 +316,14 @@ function validateTopNConfig(resource, aggregation, topN, groupBy, measures, buck
316
316
  if (!topN.sortBy || Object.keys(topN.sortBy).length === 0) throw new ArcAggregationConfigError(`Resource "${resource}" aggregation "${aggregation}" topN.sortBy must declare at least one ranking field.`);
317
317
  const partitionList = Array.isArray(topN.partitionBy) ? topN.partitionBy : [topN.partitionBy];
318
318
  if (partitionList.length === 0) throw new ArcAggregationConfigError(`Resource "${resource}" aggregation "${aggregation}" topN.partitionBy must declare at least one partition column.`);
319
- const validKeys = new Set([
319
+ const validKeys = /* @__PURE__ */ new Set([
320
320
  ...groupBy,
321
321
  ...bucketAliases,
322
322
  ...Object.keys(measures)
323
323
  ]);
324
324
  for (const key of partitionList) if (!validKeys.has(key)) throw new ArcAggregationConfigError(`Resource "${resource}" aggregation "${aggregation}" topN.partitionBy "${key}" is not a groupBy field, dateBucket alias, or measure alias. Available: ${[...validKeys].join(", ") || "(none — declare groupBy, dateBuckets, or measures)"}.`);
325
325
  }
326
- const VALID_BUCKET_UNITS = new Set([
326
+ const VALID_BUCKET_UNITS = /* @__PURE__ */ new Set([
327
327
  "minute",
328
328
  "hour",
329
329
  "day",
@@ -332,7 +332,7 @@ const VALID_BUCKET_UNITS = new Set([
332
332
  "quarter",
333
333
  "year"
334
334
  ]);
335
- const CUSTOM_BIN_UNIT_BLOCKLIST = new Set(["quarter", "year"]);
335
+ const CUSTOM_BIN_UNIT_BLOCKLIST = /* @__PURE__ */ new Set(["quarter", "year"]);
336
336
  /**
337
337
  * Validate `dateBuckets`. Catches the two classes of misconfig kits
338
338
  * already throw on at runtime — alias collisions and field-rule
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/arc",
3
- "version": "2.18.5",
3
+ "version": "2.20.0",
4
4
  "description": "Resource-oriented backend framework for Fastify - clean, minimal, powerful, tree-shakable",
5
5
  "type": "module",
6
6
  "exports": {
@@ -96,6 +96,10 @@
96
96
  "types": "./dist/docs/index.d.mts",
97
97
  "default": "./dist/docs/index.mjs"
98
98
  },
99
+ "./encryption": {
100
+ "types": "./dist/encryption/index.d.mts",
101
+ "default": "./dist/encryption/index.mjs"
102
+ },
99
103
  "./idempotency": {
100
104
  "types": "./dist/idempotency/index.d.mts",
101
105
  "default": "./dist/idempotency/index.mjs"
@@ -199,6 +203,10 @@
199
203
  "./auth/audit": {
200
204
  "types": "./dist/auth/audit.d.mts",
201
205
  "default": "./dist/auth/audit.mjs"
206
+ },
207
+ "./sync": {
208
+ "types": "./dist/sync/changelog.d.mts",
209
+ "default": "./dist/sync/changelog.mjs"
202
210
  }
203
211
  },
204
212
  "main": "./dist/index.mjs",
@@ -238,15 +246,16 @@
238
246
  "push": "classytic-push",
239
247
  "release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
240
248
  "release": "npm run push -- main && npm run release:tag && npm publish",
241
- "prepublishOnly": "npm run typecheck && npm run lint && npm run build && npm run test:ci && npm run smoke"
249
+ "check:peer-skew": "node scripts/check-peer-skew.mjs",
250
+ "prepublishOnly": "npm run check:peer-skew && npm run typecheck && npm run lint && npm run build && npm run test:ci && npm run smoke"
242
251
  },
243
252
  "engines": {
244
253
  "node": ">=22"
245
254
  },
246
255
  "peerDependencies": {
247
- "@classytic/primitives": ">=0.6.0",
248
- "@classytic/repo-core": ">=0.5.0",
249
- "@classytic/streamline": ">=2.3.3",
256
+ "@classytic/primitives": ">=0.9.0",
257
+ "@classytic/repo-core": ">=0.7.0",
258
+ "@classytic/streamline": ">=2.7.0",
250
259
  "@fastify/cors": ">=11.0.0",
251
260
  "@fastify/helmet": ">=13.0.0",
252
261
  "@fastify/jwt": ">=10.0.0",
@@ -270,6 +279,7 @@
270
279
  "fastify-raw-body": ">=5.0.0",
271
280
  "h3-js": ">=4.0.0",
272
281
  "ioredis": ">=5.0.0",
282
+ "jose": ">=5.0.0",
273
283
  "pino-pretty": ">=13.0.0",
274
284
  "zod": ">=4.0.0"
275
285
  },
@@ -331,6 +341,9 @@
331
341
  "ioredis": {
332
342
  "optional": true
333
343
  },
344
+ "jose": {
345
+ "optional": true
346
+ },
334
347
  "@sinclair/typebox": {
335
348
  "optional": true
336
349
  },
@@ -361,10 +374,10 @@
361
374
  "@biomejs/biome": "^2.5.0",
362
375
  "@classytic/dev-tools": "^0.2.0",
363
376
  "@classytic/mongokit": "^3.16.1",
364
- "@classytic/primitives": "^0.7.2",
365
- "@classytic/repo-core": "^0.6.0",
377
+ "@classytic/primitives": "^0.9.1",
378
+ "@classytic/repo-core": "^0.7.0",
366
379
  "@classytic/sqlitekit": "^0.6.0",
367
- "@classytic/streamline": "^2.6.0",
380
+ "@classytic/streamline": "^2.7.0",
368
381
  "@fastify/cors": "^11.2.0",
369
382
  "@fastify/helmet": "^13.0.2",
370
383
  "@fastify/jwt": "^10.1.0",
@@ -391,6 +404,7 @@
391
404
  "fastify-raw-body": "^5.0.0",
392
405
  "h3-js": "^4.4.0",
393
406
  "ioredis": "^5.11.1",
407
+ "jose": "^6.2.3",
394
408
  "jsonwebtoken": "^9.0.3",
395
409
  "knip": "^6.17.1",
396
410
  "mongodb": "^7.3.0",
@@ -706,6 +706,16 @@ routes: [
706
706
  { method: 'GET', path: '/stream', raw: true, handler: async (req, reply) => reply.send(stream) },
707
707
  ]
708
708
 
709
+ // Per-route rate limit (2.20) — overrides the resource/app default for ONE endpoint.
710
+ // `false` = never throttle, object = tighten, omit = inherit. Custom routes only;
711
+ // actions share one POST /:id/action mount, so throttle an action by making it a route.
712
+ routes: [
713
+ { method: 'POST', path: '/export', handler: 'export', permissions: requireAuth(),
714
+ rateLimit: { max: 5, timeWindow: '1 minute' } },
715
+ { method: 'GET', path: '/health', handler: 'health', permissions: allowPublic(),
716
+ rateLimit: false },
717
+ ]
718
+
709
719
  // Per-resource opt-out of resourcePrefix (webhooks / admin routes)
710
720
  defineResource({ name: 'webhook', prefix: '/hooks', skipGlobalPrefix: true });
711
721
 
@@ -50,6 +50,8 @@ Resource `actions` (v2.8) also auto-generate MCP tools — each action becomes a
50
50
 
51
51
  Tool handlers call `BaseController` — same pipeline as REST (auth, org-scoping, hooks, field permissions, cache).
52
52
 
53
+ **Query params on generated tools (2.20):** `list_*` accepts `page`/`limit` (offset) **and** `cursor` (keyset, stable under concurrent inserts — when set, `page` is ignored), plus `sort`/`search`/`select`/`populate`. `get_*` accepts `select` for field projection alongside `id`. Both mirror REST exactly (same `QueryResolver`).
54
+
53
55
  ### McpPluginOptions
54
56
 
55
57
  | Option | Type | Default | Description |