@mastra/deployer 0.16.3 → 0.16.4-alpha.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @mastra/deployer
2
2
 
3
+ ## 0.16.4-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`547c621`](https://github.com/mastra-ai/mastra/commit/547c62104af3f7a551b3754e9cbdf0a3fbba15e4)]:
8
+ - @mastra/core@0.16.4-alpha.1
9
+ - @mastra/server@0.16.4-alpha.1
10
+
11
+ ## 0.16.4-alpha.0
12
+
13
+ ### Patch Changes
14
+
15
+ - feat: add requiresAuth option for custom API routes ([#7703](https://github.com/mastra-ai/mastra/pull/7703))
16
+
17
+ Added a new `requiresAuth` option to the `ApiRoute` type that allows users to explicitly control authentication requirements for custom endpoints.
18
+ - By default, all custom routes require authentication (`requiresAuth: true`)
19
+ - Set `requiresAuth: false` to make a route publicly accessible without authentication
20
+ - The auth middleware now checks this configuration before applying authentication
21
+
22
+ Example usage:
23
+
24
+ ```typescript
25
+ const customRoutes: ApiRoute[] = [
26
+ {
27
+ path: '/api/public-endpoint',
28
+ method: 'GET',
29
+ requiresAuth: false, // No authentication required
30
+ handler: async c => c.json({ message: 'Public access' }),
31
+ },
32
+ {
33
+ path: '/api/protected-endpoint',
34
+ method: 'GET',
35
+ requiresAuth: true, // Authentication required (default)
36
+ handler: async c => c.json({ message: 'Protected access' }),
37
+ },
38
+ ];
39
+ ```
40
+
41
+ This addresses issue #7674 where custom endpoints were not being protected by the authentication system.
42
+
43
+ - Playground ui -pass runtimeContext to client SDK get methods ([#7767](https://github.com/mastra-ai/mastra/pull/7767))
44
+
45
+ - Updated dependencies [[`5802bf5`](https://github.com/mastra-ai/mastra/commit/5802bf57f6182e4b67c28d7d91abed349a8d14f3), [`5bda53a`](https://github.com/mastra-ai/mastra/commit/5bda53a9747bfa7d876d754fc92c83a06e503f62), [`f26a8fd`](https://github.com/mastra-ai/mastra/commit/f26a8fd99fcb0497a5d86c28324430d7f6a5fb83), [`b6688b7`](https://github.com/mastra-ai/mastra/commit/b6688b75e49a4286d612aa2098e39c6118db2d07), [`1a1fbe6`](https://github.com/mastra-ai/mastra/commit/1a1fbe66efb7d94abc373ed0dd9676adb8122454), [`36f39c0`](https://github.com/mastra-ai/mastra/commit/36f39c00dc794952dc3c11aab91c2fa8bca74b11)]:
46
+ - @mastra/core@0.16.4-alpha.0
47
+ - @mastra/server@0.16.4-alpha.0
48
+
3
49
  ## 0.16.3
4
50
 
5
51
  ### Patch Changes
@@ -1,6 +1,7 @@
1
1
  import type { MastraAuthConfig } from '@mastra/core/server';
2
2
  import type { HonoRequest } from 'hono';
3
3
  export declare const isDevPlaygroundRequest: (req: HonoRequest) => boolean;
4
+ export declare const isCustomRoutePublic: (path: string, method: string, customRouteAuthConfig?: Map<string, boolean>) => boolean;
4
5
  export declare const isProtectedPath: (path: string, method: string, authConfig: MastraAuthConfig) => boolean;
5
6
  export declare const canAccessPublicly: (path: string, method: string, authConfig: MastraAuthConfig) => boolean;
6
7
  export declare const pathMatchesPattern: (path: string, pattern: string) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/auth/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAGxC,eAAO,MAAM,sBAAsB,GAAI,KAAK,WAAW,KAAG,OAEzD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,YAAY,gBAAgB,KAAG,OAG5F,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,YAAY,gBAAgB,KAAG,OAK9F,CAAC;AAiCF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,OAQlE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,UAAU,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAG,OAiBhG,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,MAAM,KAAG,OAU5E,CAAC;AAGF,eAAO,MAAM,UAAU,GACrB,OAAO,gBAAgB,CAAC,OAAO,CAAC,EAChC,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,MAAM,OAAO,KACZ,OAAO,CAAC,OAAO,CA+BjB,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/auth/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAGxC,eAAO,MAAM,sBAAsB,GAAI,KAAK,WAAW,KAAG,OAEzD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,wBAAwB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3C,OAkBF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,YAAY,gBAAgB,KAAG,OAG5F,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,YAAY,gBAAgB,KAAG,OAK9F,CAAC;AAiCF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,OAQlE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,UAAU,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAG,OAiBhG,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,MAAM,KAAG,OAU5E,CAAC;AAGF,eAAO,MAAM,UAAU,GACrB,OAAO,gBAAgB,CAAC,OAAO,CAAC,EAChC,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,MAAM,OAAO,KACZ,OAAO,CAAC,OAAO,CA+BjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAIjC,eAAO,MAAM,wBAAwB,GAAU,GAAG,iBAAiB,EAAE,MAAM,IAAI;;iBA2D9E,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,GAAG,iBAAiB,EAAE,MAAM,IAAI;;;;iBAgF7E,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAIjC,eAAO,MAAM,wBAAwB,GAAU,GAAG,iBAAiB,EAAE,MAAM,IAAI;;iBAiE9E,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,GAAG,iBAAiB,EAAE,MAAM,IAAI;;;;iBAsF7E,CAAC"}
@@ -72,8 +72,7 @@ var Request = class extends GlobalRequest {
72
72
  super(input, options);
73
73
  }
74
74
  };
75
- var wrapBodyStream = Symbol("wrapBodyStream");
76
- var newRequestFromIncoming = (method, url, incoming, abortController) => {
75
+ var newHeadersFromIncoming = (incoming) => {
77
76
  const headerRecord = [];
78
77
  const rawHeaders = incoming.rawHeaders;
79
78
  for (let i2 = 0; i2 < rawHeaders.length; i2 += 2) {
@@ -83,9 +82,13 @@ var newRequestFromIncoming = (method, url, incoming, abortController) => {
83
82
  headerRecord.push([key, value]);
84
83
  }
85
84
  }
85
+ return new Headers(headerRecord);
86
+ };
87
+ var wrapBodyStream = Symbol("wrapBodyStream");
88
+ var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
86
89
  const init = {
87
90
  method,
88
- headers: headerRecord,
91
+ headers,
89
92
  signal: abortController.signal
90
93
  };
91
94
  if (method === "TRACE") {
@@ -133,6 +136,7 @@ var getRequestCache = Symbol("getRequestCache");
133
136
  var requestCache = Symbol("requestCache");
134
137
  var incomingKey = Symbol("incomingKey");
135
138
  var urlKey = Symbol("urlKey");
139
+ var headersKey = Symbol("headersKey");
136
140
  var abortControllerKey = Symbol("abortControllerKey");
137
141
  var getAbortController = Symbol("getAbortController");
138
142
  var requestPrototype = {
@@ -142,6 +146,9 @@ var requestPrototype = {
142
146
  get url() {
143
147
  return this[urlKey];
144
148
  },
149
+ get headers() {
150
+ return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
151
+ },
145
152
  [getAbortController]() {
146
153
  this[getRequestCache]();
147
154
  return this[abortControllerKey];
@@ -151,6 +158,7 @@ var requestPrototype = {
151
158
  return this[requestCache] ||= newRequestFromIncoming(
152
159
  this.method,
153
160
  this[urlKey],
161
+ this.headers,
154
162
  this[incomingKey],
155
163
  this[abortControllerKey]
156
164
  );
@@ -162,7 +170,6 @@ var requestPrototype = {
162
170
  "cache",
163
171
  "credentials",
164
172
  "destination",
165
- "headers",
166
173
  "integrity",
167
174
  "mode",
168
175
  "redirect",
@@ -288,17 +295,14 @@ var Response2 = class _Response {
288
295
  });
289
296
  Object.setPrototypeOf(Response2, GlobalResponse);
290
297
  Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
291
- function writeFromReadableStream(stream7, writable) {
292
- if (stream7.locked) {
293
- throw new TypeError("ReadableStream is locked.");
294
- } else if (writable.destroyed) {
295
- return;
296
- }
297
- const reader = stream7.getReader();
298
+ async function readWithoutBlocking(readPromise) {
299
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
300
+ }
301
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
298
302
  const handleError2 = () => {
299
303
  };
300
304
  writable.on("error", handleError2);
301
- reader.read().then(flow, handleStreamError);
305
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
302
306
  return reader.closed.finally(() => {
303
307
  writable.off("error", handleError2);
304
308
  });
@@ -324,6 +328,14 @@ function writeFromReadableStream(stream7, writable) {
324
328
  }
325
329
  }
326
330
  }
331
+ function writeFromReadableStream(stream7, writable) {
332
+ if (stream7.locked) {
333
+ throw new TypeError("ReadableStream is locked.");
334
+ } else if (writable.destroyed) {
335
+ return;
336
+ }
337
+ return writeFromReadableStreamDefaultReader(stream7.getReader(), writable);
338
+ }
327
339
  var buildOutgoingHttpHeaders = (headers) => {
328
340
  const res = {};
329
341
  if (!(headers instanceof Headers)) {
@@ -358,8 +370,6 @@ global.fetch = (info, init) => {
358
370
  return webFetch(info, init);
359
371
  };
360
372
  var outgoingEnded = Symbol("outgoingEnded");
361
- var regBuffer = /^no$/i;
362
- var regContentType = /^(application\/json\b|text\/(?!event-stream\b))/i;
363
373
  var handleRequestError = () => new Response(null, {
364
374
  status: 400
365
375
  });
@@ -430,23 +440,50 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
430
440
  }
431
441
  const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
432
442
  if (res.body) {
433
- const {
434
- "transfer-encoding": transferEncoding,
435
- "content-encoding": contentEncoding,
436
- "content-length": contentLength,
437
- "x-accel-buffering": accelBuffering,
438
- "content-type": contentType
439
- } = resHeaderRecord;
440
- if (transferEncoding || contentEncoding || contentLength || // nginx buffering variant
441
- accelBuffering && regBuffer.test(accelBuffering) || !regContentType.test(contentType)) {
442
- outgoing.writeHead(res.status, resHeaderRecord);
443
- flushHeaders(outgoing);
444
- await writeFromReadableStream(res.body, outgoing);
443
+ const reader = res.body.getReader();
444
+ const values = [];
445
+ let done = false;
446
+ let currentReadPromise = void 0;
447
+ if (resHeaderRecord["transfer-encoding"] !== "chunked") {
448
+ let maxReadCount = 2;
449
+ for (let i2 = 0; i2 < maxReadCount; i2++) {
450
+ currentReadPromise ||= reader.read();
451
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e2) => {
452
+ console.error(e2);
453
+ done = true;
454
+ });
455
+ if (!chunk) {
456
+ if (i2 === 1) {
457
+ await new Promise((resolve) => setTimeout(resolve));
458
+ maxReadCount = 3;
459
+ continue;
460
+ }
461
+ break;
462
+ }
463
+ currentReadPromise = void 0;
464
+ if (chunk.value) {
465
+ values.push(chunk.value);
466
+ }
467
+ if (chunk.done) {
468
+ done = true;
469
+ break;
470
+ }
471
+ }
472
+ if (done && !("content-length" in resHeaderRecord)) {
473
+ resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
474
+ }
475
+ }
476
+ outgoing.writeHead(res.status, resHeaderRecord);
477
+ values.forEach((value) => {
478
+ outgoing.write(value);
479
+ });
480
+ if (done) {
481
+ outgoing.end();
445
482
  } else {
446
- const buffer = await res.arrayBuffer();
447
- resHeaderRecord["content-length"] = buffer.byteLength;
448
- outgoing.writeHead(res.status, resHeaderRecord);
449
- outgoing.end(new Uint8Array(buffer));
483
+ if (values.length === 0) {
484
+ flushHeaders(outgoing);
485
+ }
486
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
450
487
  }
451
488
  } else if (resHeaderRecord[X_ALREADY_SENT]) ; else {
452
489
  outgoing.writeHead(res.status, resHeaderRecord);
@@ -588,6 +625,9 @@ var getStats = (path) => {
588
625
  var serveStatic = (options = { root: "" }) => {
589
626
  const root = options.root || "";
590
627
  const optionPath = options.path;
628
+ if (root !== "" && !fs.existsSync(root)) {
629
+ console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
630
+ }
591
631
  return async (c2, next) => {
592
632
  if (c2.finalized) {
593
633
  return next();
@@ -655,8 +695,8 @@ var serveStatic = (options = { root: "" }) => {
655
695
  c2.header("Accept-Ranges", "bytes");
656
696
  c2.header("Date", stats.birthtime.toUTCString());
657
697
  const parts = range.replace(/bytes=/, "").split("-", 2);
658
- const start = parts[0] ? parseInt(parts[0], 10) : 0;
659
- let end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
698
+ const start = parseInt(parts[0], 10) || 0;
699
+ let end = parseInt(parts[1], 10) || size - 1;
660
700
  if (size < end - start + 1) {
661
701
  end = size - 1;
662
702
  }
@@ -1011,6 +1051,20 @@ var defaultAuthConfig = {
1011
1051
  var isDevPlaygroundRequest = (req) => {
1012
1052
  return req.header("x-mastra-dev-playground") === "true" && process.env.MASTRA_DEV === "true";
1013
1053
  };
1054
+ var isCustomRoutePublic = (path, method, customRouteAuthConfig) => {
1055
+ if (!customRouteAuthConfig) {
1056
+ return false;
1057
+ }
1058
+ const routeKey = `${method}:${path}`;
1059
+ if (customRouteAuthConfig.has(routeKey)) {
1060
+ return !customRouteAuthConfig.get(routeKey);
1061
+ }
1062
+ const allRouteKey = `ALL:${path}`;
1063
+ if (customRouteAuthConfig.has(allRouteKey)) {
1064
+ return !customRouteAuthConfig.get(allRouteKey);
1065
+ }
1066
+ return false;
1067
+ };
1014
1068
  var isProtectedPath = (path, method, authConfig) => {
1015
1069
  const protectedAccess = [...defaultAuthConfig.protected || [], ...authConfig.protected || []];
1016
1070
  return isAnyMatch(path, method, protectedAccess);
@@ -1097,12 +1151,16 @@ var checkRules = async (rules, path, method, user) => {
1097
1151
  var authenticationMiddleware = async (c2, next) => {
1098
1152
  const mastra = c2.get("mastra");
1099
1153
  const authConfig = mastra.getServer()?.experimental_auth;
1154
+ const customRouteAuthConfig = c2.get("customRouteAuthConfig");
1100
1155
  if (!authConfig) {
1101
1156
  return next();
1102
1157
  }
1103
1158
  if (isDevPlaygroundRequest(c2.req)) {
1104
1159
  return next();
1105
1160
  }
1161
+ if (isCustomRoutePublic(c2.req.path, c2.req.method, customRouteAuthConfig)) {
1162
+ return next();
1163
+ }
1106
1164
  if (!isProtectedPath(c2.req.path, c2.req.method, authConfig)) {
1107
1165
  return next();
1108
1166
  }
@@ -1137,6 +1195,7 @@ var authenticationMiddleware = async (c2, next) => {
1137
1195
  var authorizationMiddleware = async (c2, next) => {
1138
1196
  const mastra = c2.get("mastra");
1139
1197
  const authConfig = mastra.getServer()?.experimental_auth;
1198
+ const customRouteAuthConfig = c2.get("customRouteAuthConfig");
1140
1199
  if (!authConfig) {
1141
1200
  return next();
1142
1201
  }
@@ -1145,6 +1204,9 @@ var authorizationMiddleware = async (c2, next) => {
1145
1204
  if (isDevPlaygroundRequest(c2.req)) {
1146
1205
  return next();
1147
1206
  }
1207
+ if (isCustomRoutePublic(path, method, customRouteAuthConfig)) {
1208
+ return next();
1209
+ }
1148
1210
  if (!isProtectedPath(c2.req.path, c2.req.method, authConfig)) {
1149
1211
  return next();
1150
1212
  }
@@ -10978,6 +11040,15 @@ async function createHonoServer(mastra, options = {
10978
11040
  const app = new hono.Hono();
10979
11041
  const server = mastra.getServer();
10980
11042
  const a2aTaskStore = new store.InMemoryTaskStore();
11043
+ const routes = server?.apiRoutes;
11044
+ const customRouteAuthConfig = /* @__PURE__ */ new Map();
11045
+ if (routes) {
11046
+ for (const route of routes) {
11047
+ const requiresAuth = route.requiresAuth !== false;
11048
+ const routeKey = `${route.method}:${route.path}`;
11049
+ customRouteAuthConfig.set(routeKey, requiresAuth);
11050
+ }
11051
+ }
10981
11052
  app.use("*", async function setTelemetryInfo(c2, next) {
10982
11053
  const requestId = c2.req.header("x-request-id") ?? crypto.randomUUID();
10983
11054
  const span = telemetry.Telemetry.getActiveSpan();
@@ -11040,6 +11111,7 @@ async function createHonoServer(mastra, options = {
11040
11111
  c2.set("taskStore", a2aTaskStore);
11041
11112
  c2.set("playground", options.playground === true);
11042
11113
  c2.set("isDev", options.isDev === true);
11114
+ c2.set("customRouteAuthConfig", customRouteAuthConfig);
11043
11115
  return next();
11044
11116
  });
11045
11117
  const serverMiddleware = mastra.getServerMiddleware?.();
@@ -11069,7 +11141,6 @@ async function createHonoServer(mastra, options = {
11069
11141
  // 4.5 MB,
11070
11142
  onError: (c2) => c2.json({ error: "Request body too large" }, 413)
11071
11143
  };
11072
- const routes = server?.apiRoutes;
11073
11144
  if (server?.middleware) {
11074
11145
  const normalizedMiddlewares = Array.isArray(server.middleware) ? server.middleware : [server.middleware];
11075
11146
  const middlewares = normalizedMiddlewares.map((middleware2) => {