@mastra/server-adapters-test-suite 0.1.1 → 0.1.2-alpha.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @mastra/server-adapters-test-suite
2
2
 
3
+ ## 0.1.2-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Added coverage for reserved field and parameter names in shared adapter request parsing tests ([#26683](https://github.com/mastra-ai/mastra/pull/26683))
8
+
9
+ - Updated dependencies [[`a65d0c7`](https://github.com/mastra-ai/mastra/commit/a65d0c788824081f36ccd95078a8d1214ff687c4), [`cb0201a`](https://github.com/mastra-ai/mastra/commit/cb0201ab41c36723b9f6e331464e5c74326865ed), [`e89310a`](https://github.com/mastra-ai/mastra/commit/e89310a8db29a663a85c6a31a8c376cc8f59c129), [`590d6ca`](https://github.com/mastra-ai/mastra/commit/590d6ca9fa6ccf8b55dcf2e98da080ee1a348f67)]:
10
+ - @mastra/core@1.76.0-alpha.9
11
+ - @mastra/server@1.76.0-alpha.9
12
+
3
13
  ## 0.1.1
4
14
 
5
15
  ### Patch Changes
package/dist/index.js CHANGED
@@ -927,7 +927,8 @@ async function createDefaultTestContext() {
927
927
  "trace-query",
928
928
  "trace-query-discovery",
929
929
  "trace-aggregate",
930
- "thread-query"
930
+ "thread-query",
931
+ "span-query"
931
932
  ]);
932
933
  vi.spyOn(observability, "queryTraces").mockResolvedValue({
933
934
  traces: [],
@@ -949,6 +950,10 @@ async function createDefaultTestContext() {
949
950
  threads: [],
950
951
  page: { next: null }
951
952
  });
953
+ vi.spyOn(observability, "querySpans").mockResolvedValue({
954
+ spans: [],
955
+ page: { next: null }
956
+ });
952
957
  await observability.createSpan({ span: {
953
958
  spanId: "test-span",
954
959
  traceId: "test-trace",
@@ -1764,6 +1769,48 @@ function createRouteAdapterTestSuite(config) {
1764
1769
  expect(response.status).toBe(200);
1765
1770
  expect(response.data).toEqual({ userId: "query-user-123" });
1766
1771
  });
1772
+ it("ignores special object keys in query params while preserving legitimate params", async () => {
1773
+ await setup.adapter.registerRoute(app, {
1774
+ method: "GET",
1775
+ path: "/test/query-special-keys",
1776
+ responseType: "json",
1777
+ handler: async (params) => ({
1778
+ filter: typeof params.filter === "string" ? JSON.parse(params.filter) : null,
1779
+ tag: params.tag ?? null,
1780
+ keys: Object.keys(params).filter((k) => ![
1781
+ "mastra",
1782
+ "requestContext",
1783
+ "tools",
1784
+ "taskStore",
1785
+ "abortSignal",
1786
+ "registeredTools",
1787
+ "routePrefix",
1788
+ "request"
1789
+ ].includes(k))
1790
+ })
1791
+ });
1792
+ const response = await executeHttpRequest(app, {
1793
+ method: "GET",
1794
+ path: "/api/test/query-special-keys",
1795
+ query: Object.fromEntries([
1796
+ ["__proto__[polluted]", "yes"],
1797
+ ["constructor[prototype]", "yes"],
1798
+ ["prototype[x]", "yes"],
1799
+ ["filter[__proto__]", "yes"],
1800
+ ["filter[status]", "active"],
1801
+ ["tag", ["a", "b"]],
1802
+ ["page", "2"]
1803
+ ])
1804
+ });
1805
+ expect(response.status).toBe(200);
1806
+ const data = response.data;
1807
+ expect(data.filter).toEqual({ status: "active" });
1808
+ expect(Array.isArray(data.tag) ? data.tag : [data.tag]).toContain("b");
1809
+ expect(data.keys).not.toContain("__proto__");
1810
+ expect(data.keys).not.toContain("constructor");
1811
+ expect(data.keys).not.toContain("prototype");
1812
+ expect({}.polluted).toBeUndefined();
1813
+ });
1767
1814
  describe.each([{
1768
1815
  version: "v3",
1769
1816
  recordSchema: z$1.record(z$1.string(), z$1.string()),
@@ -3488,6 +3535,59 @@ function createMultipartTestSuite(config) {
3488
3535
  message: "Hello, World!"
3489
3536
  });
3490
3537
  });
3538
+ it("should ignore form fields named with special object keys", async () => {
3539
+ const { adapter, app } = await setupAdapter(context);
3540
+ const testRoute = {
3541
+ method: "POST",
3542
+ path: "/test/upload-special-keys",
3543
+ responseType: "json",
3544
+ handler: async (params) => {
3545
+ return {
3546
+ success: true,
3547
+ name: params.name ?? null,
3548
+ options: params.options ?? null,
3549
+ inheritedIsAdmin: params.isAdmin ?? null,
3550
+ bodyKeys: Object.keys(params).filter((k) => ![
3551
+ "mastra",
3552
+ "requestContext",
3553
+ "tools",
3554
+ "taskStore",
3555
+ "abortSignal",
3556
+ "registeredTools",
3557
+ "routePrefix",
3558
+ "request"
3559
+ ].includes(k))
3560
+ };
3561
+ }
3562
+ };
3563
+ applyMiddleware(app, getContextMiddleware(adapter));
3564
+ await registerRoute(adapter, app, testRoute, { prefix: "" });
3565
+ serverInfo = await startServer(app);
3566
+ const formData = new FormData();
3567
+ formData.append("__proto__", JSON.stringify({ isAdmin: true }));
3568
+ formData.append("constructor", JSON.stringify({ prototype: { isAdmin: true } }));
3569
+ const fileBlob = new Blob([new Uint8Array([
3570
+ 1,
3571
+ 2,
3572
+ 3
3573
+ ])], { type: "application/octet-stream" });
3574
+ formData.append("prototype", fileBlob, "payload.bin");
3575
+ formData.append("name", "legit-recording");
3576
+ formData.append("options", JSON.stringify({ language: "en" }));
3577
+ const response = await fetch(`${serverInfo.baseUrl}/test/upload-special-keys`, {
3578
+ method: "POST",
3579
+ body: formData
3580
+ });
3581
+ expect(response.status).toBe(200);
3582
+ const result = await response.json();
3583
+ expect(result.name).toBe("legit-recording");
3584
+ expect(result.options).toMatchObject({ language: "en" });
3585
+ expect(result.inheritedIsAdmin).toBeNull();
3586
+ expect(result.bodyKeys).not.toContain("__proto__");
3587
+ expect(result.bodyKeys).not.toContain("constructor");
3588
+ expect(result.bodyKeys).not.toContain("prototype");
3589
+ expect({}.isAdmin).toBeUndefined();
3590
+ });
3491
3591
  });
3492
3592
  }
3493
3593
  //#endregion