velocious 1.0.661 → 1.0.662

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 (41) hide show
  1. package/README.md +11 -0
  2. package/build/application.js +1 -1
  3. package/build/configuration-types.js +3 -1
  4. package/build/configuration.js +33 -0
  5. package/build/http-server/client/errors.js +27 -0
  6. package/build/http-server/client/index.js +26 -1
  7. package/build/http-server/client/request-buffer/index.js +38 -6
  8. package/build/http-server/client/request-runner.js +8 -1
  9. package/build/http-server/client/response.js +11 -0
  10. package/build/routes/resolver.js +1 -1
  11. package/build/src/application.js +2 -2
  12. package/build/src/configuration-types.d.ts +13 -3
  13. package/build/src/configuration-types.d.ts.map +1 -1
  14. package/build/src/configuration-types.js +4 -2
  15. package/build/src/configuration.d.ts +14 -2
  16. package/build/src/configuration.d.ts.map +1 -1
  17. package/build/src/configuration.js +31 -1
  18. package/build/src/http-server/client/errors.d.ts +25 -0
  19. package/build/src/http-server/client/errors.d.ts.map +1 -0
  20. package/build/src/http-server/client/errors.js +26 -0
  21. package/build/src/http-server/client/index.d.ts +5 -0
  22. package/build/src/http-server/client/index.d.ts.map +1 -1
  23. package/build/src/http-server/client/index.js +26 -2
  24. package/build/src/http-server/client/request-buffer/index.d.ts +13 -0
  25. package/build/src/http-server/client/request-buffer/index.d.ts.map +1 -1
  26. package/build/src/http-server/client/request-buffer/index.js +34 -8
  27. package/build/src/http-server/client/request-runner.d.ts.map +1 -1
  28. package/build/src/http-server/client/request-runner.js +10 -2
  29. package/build/src/http-server/client/response.d.ts.map +1 -1
  30. package/build/src/http-server/client/response.js +8 -1
  31. package/build/src/routes/resolver.js +2 -2
  32. package/package.json +1 -1
  33. package/src/application.js +1 -1
  34. package/src/configuration-types.js +3 -1
  35. package/src/configuration.js +33 -0
  36. package/src/http-server/client/errors.js +27 -0
  37. package/src/http-server/client/index.js +26 -1
  38. package/src/http-server/client/request-buffer/index.js +38 -6
  39. package/src/http-server/client/request-runner.js +8 -1
  40. package/src/http-server/client/response.js +11 -0
  41. package/src/routes/resolver.js +1 -1
package/README.md CHANGED
@@ -34,6 +34,7 @@
34
34
  * Cross-process broadcast bus for `broadcastToChannel` via `velocious beacon`, including background job runner processes (see [docs/beacon.md](docs/beacon.md))
35
35
  * Rails-style application process initializer teardown with immutable process identity, reverse idempotent shutdown, and explicit HTTP/background-job ownership (see [docs/application-process-lifecycle.md](docs/application-process-lifecycle.md))
36
36
  * Configurable HTTP server worker handlers plus backpressured, descriptor-only file responses with completion callbacks (see [docs/http-server.md](docs/http-server.md))
37
+ * Explicit database-free in-process HTTP applications with optional request and buffered-response byte limits (see [docs/http-server.md](docs/http-server.md#database-free-applications))
37
38
  * Default-on buffered HTTP response compression with Brotli/gzip content negotiation, global and per-response opt-outs, and HEAD-correct representation headers (see [docs/http-server.md](docs/http-server.md#response-compression))
38
39
  * Background jobs with Node SQL/TCP workers plus a Browser/Expo local SQLite store and in-process dispatcher, including failure events, authorized database-scoped dashboard counts, and an opt-in release-scoped main/worker generation protocol with acknowledged activation, asynchronous retirement, and retired-main recovery. Production compliance additionally requires downstream supervisor retention/activation ordering and release pins (see [docs/background-jobs.md](docs/background-jobs.md), [docs/local-background-jobs.md](docs/local-background-jobs.md), and [docs/background-jobs-dashboard.md](docs/background-jobs-dashboard.md))
39
40
  * Durable one-off background-job scheduling with exact epoch timestamps (see [docs/scheduled-background-job-enqueue.md](docs/scheduled-background-job-enqueue.md))
@@ -2907,6 +2908,16 @@ When the server runs in the `development` environment, Velocious watches applica
2907
2908
 
2908
2909
  Starting the HTTP server creates `tmp/server.lock` under the configured application directory before Beacon, workers, or the TCP listener start. A second server for the same app fails fast with the lock owner details instead of partially starting. Normal shutdown removes the lock; stale locks with a dead local PID are reclaimed automatically, while locks from another host or unreadable metadata should be removed manually only after confirming no server is running. See [docs/http-server.md](docs/http-server.md#server-lock).
2909
2910
 
2911
+ Set `database: false` for an explicitly database-free application; its HTTP and
2912
+ initializer lifecycle remains intact without creating a default pool or an
2913
+ implicit route connection checkout. Optional
2914
+ `httpServer.maxRequestBodyBytes` and
2915
+ `httpServer.maxBufferedResponseBodyBytes` positive byte limits reject oversized
2916
+ request bodies with a connection-closing `413` and oversized buffered responses
2917
+ with a reported, empty `500`. Both remain unbounded when omitted, and streamed
2918
+ `sendFile` responses are unaffected. The request limit is enforced while
2919
+ unframed multipart bodies accumulate. See [docs/http-server.md](docs/http-server.md#database-free-applications).
2920
+
2910
2921
  Buffered string and `Uint8Array` responses are compressed with Brotli (`br`) or gzip by default whenever request negotiation and response eligibility allow — no opt-in is required. Disable compression globally with `httpServer.compression: false` or `httpServer.compression: {enabled: false}`, and tune it with `threshold`/`brotliQuality`/`gzipLevel` overrides. Negotiation honors `Accept-Encoding` q-values, wildcards, and identity semantics (empty `406` when no acceptable representation exists), combines repeated `Accept-Encoding` header fields in wire order, and advertises a framework-owned `Vary: Accept-Encoding` on every framework-selected representation (transformed, identity, `406`, and file) so caches key on the field. Streamed `sendFile` responses are never buffered or re-encoded: they are sent identity, so when the client forbids identity the server answers with the same empty `406` without opening or streaming the file. Transformation also skips already-encoded or `no-transform` responses, server-sent events, partial/range responses, bodyless statuses, and non-allowlisted content types. Transformation is additionally excluded automatically for credentialed traffic and validator-carrying responses — requests with `Authorization`/`Cookie` and responses with `Set-Cookie`, `ETag`, `Digest`, or `Content-Digest` are never compressed (compression-oracle protection, and validators stay application-owned). Controllers opt out per response with `response.disableCompression()`, and HEAD requests compute GET-equivalent representation headers without emitting a body. See [docs/http-server.md](docs/http-server.md#response-compression).
2911
2922
 
2912
2923
  # Authorization (CanCan-style)
@@ -66,7 +66,7 @@ export default class VelociousApplication {
66
66
 
67
67
  this.configuration.setRoutes(routes)
68
68
 
69
- if (!this.configuration.isDatabasePoolInitialized()) {
69
+ if (this.configuration.database !== false && !this.configuration.isDatabasePoolInitialized()) {
70
70
  await this.configuration.initializeDatabasePool()
71
71
  }
72
72
 
@@ -293,6 +293,8 @@
293
293
  * @property {boolean | HttpCompressionConfiguration} [compression] - Buffered response compression. Enabled with documented defaults when absent; false or {enabled: false} disables it globally.
294
294
  * @property {string} [host] - Hostname to bind the HTTP server to.
295
295
  * @property {boolean} [inProcess] - Run HTTP handlers in the main thread instead of worker threads.
296
+ * @property {number} [maxBufferedResponseBodyBytes] - Maximum UTF-8/binary byte length accepted by buffered response bodies. Unbounded when absent; streamed file responses are unaffected.
297
+ * @property {number} [maxRequestBodyBytes] - Maximum decoded request-body bytes accepted before routing. Unbounded when absent.
296
298
  * @property {number} [maxWorkers] - Backward-compatible alias for workers.
297
299
  * @property {number} [port] - Port to bind the HTTP server to.
298
300
  * @property {{maxPendingBytes?: number, maxPendingMessages?: number}} [websocketInboundQueue] - Per-session retained inbound WebSocket message limits.
@@ -735,7 +737,7 @@
735
737
  * @property {AttachmentsConfiguration} [attachments] - Attachment storage configuration.
736
738
  * @property {BackendProjectConfiguration[]} [backendProjects] - Backend project definitions used for frontend model generation.
737
739
  * @property {VelociousPackageConfiguration[]} [packages] - External Velocious packages that contribute models, frontend-model resources and migrations.
738
- * @property {{[key: string]: {[key: string]: DatabaseConfigurationType}}} database - Database configurations keyed by environment and identifier.
740
+ * @property {false | {[key: string]: {[key: string]: DatabaseConfigurationType}}} [database] - Database configurations keyed by environment and identifier, or false for an explicitly database-free application.
739
741
  * @property {boolean} [debug] - Enable debug logging.
740
742
  * @property {boolean | DebugEndpointConfiguration} [debugEndpoint] - Enable the built-in debug endpoint. Defaults to false.
741
743
  * @property {boolean | ApiManifestConfiguration} [apiManifest] - Enable the built-in API manifest endpoint. Defaults to false.
@@ -155,6 +155,21 @@ function positiveSafeInteger(value, name, defaultValue) {
155
155
  return value
156
156
  }
157
157
 
158
+ /**
159
+ * Validates an optional positive safe integer configuration value.
160
+ * @param {ReturnType<typeof JSON.parse>} value - Configured positive safe integer.
161
+ * @param {string} name - Configuration key.
162
+ * @returns {number | undefined} - Validated configured value.
163
+ */
164
+ function optionalPositiveSafeInteger(value, name) {
165
+ if (value === undefined) return undefined
166
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
167
+ throw new TypeError(`${name} must be a positive safe integer`)
168
+ }
169
+
170
+ return value
171
+ }
172
+
158
173
  /**
159
174
  * Validates an integer configuration value inside an inclusive range.
160
175
  * @param {ReturnType<typeof JSON.parse>} value - Configured integer.
@@ -347,6 +362,8 @@ export default class VelociousConfiguration {
347
362
  this.httpServer = {
348
363
  ...(httpServer || {}),
349
364
  compression: normalizeHttpCompression(httpServer?.compression),
365
+ maxBufferedResponseBodyBytes: optionalPositiveSafeInteger(httpServer?.maxBufferedResponseBodyBytes, "httpServer.maxBufferedResponseBodyBytes"),
366
+ maxRequestBodyBytes: optionalPositiveSafeInteger(httpServer?.maxRequestBodyBytes, "httpServer.maxRequestBodyBytes"),
350
367
  websocketInboundQueue: {
351
368
  maxPendingBytes: positiveSafeInteger(websocketInboundQueue?.maxPendingBytes, "httpServer.websocketInboundQueue.maxPendingBytes", DEFAULT_WEBSOCKET_INBOUND_MAX_PENDING_BYTES),
352
369
  maxPendingMessages: positiveSafeInteger(websocketInboundQueue?.maxPendingMessages, "httpServer.websocketInboundQueue.maxPendingMessages", DEFAULT_WEBSOCKET_INBOUND_MAX_PENDING_MESSAGES)
@@ -644,6 +661,22 @@ export default class VelociousConfiguration {
644
661
  return this.httpServer.compression
645
662
  }
646
663
 
664
+ /**
665
+ * Runs get maximum buffered response body bytes.
666
+ * @returns {number | undefined} - Configured byte limit, or undefined when unbounded.
667
+ */
668
+ getHttpServerMaxBufferedResponseBodyBytes() {
669
+ return this.httpServer.maxBufferedResponseBodyBytes
670
+ }
671
+
672
+ /**
673
+ * Runs get maximum request body bytes.
674
+ * @returns {number | undefined} - Configured byte limit, or undefined when unbounded.
675
+ */
676
+ getHttpServerMaxRequestBodyBytes() {
677
+ return this.httpServer.maxRequestBodyBytes
678
+ }
679
+
647
680
  /**
648
681
  * Runs get cookie secret.
649
682
  * @returns {string | undefined} - Cookie secret.
@@ -0,0 +1,27 @@
1
+ // @ts-check
2
+
3
+ export class HttpRequestBodyTooLargeError extends Error {
4
+ /**
5
+ * Creates a request-body limit error.
6
+ * @param {object} args - Size details.
7
+ * @param {number} args.actualBytes - Declared or accumulated body size.
8
+ * @param {number} args.maxBytes - Configured maximum body size.
9
+ */
10
+ constructor({actualBytes, maxBytes}) {
11
+ super(`HTTP request body exceeds ${maxBytes} bytes (received or declared ${actualBytes})`)
12
+ this.name = "HttpRequestBodyTooLargeError"
13
+ }
14
+ }
15
+
16
+ export class HttpResponseBodyTooLargeError extends Error {
17
+ /**
18
+ * Creates a buffered-response limit error.
19
+ * @param {object} args - Size details.
20
+ * @param {number} args.actualBytes - Buffered response body size.
21
+ * @param {number} args.maxBytes - Configured maximum body size.
22
+ */
23
+ constructor({actualBytes, maxBytes}) {
24
+ super(`Buffered HTTP response body exceeds ${maxBytes} bytes (received ${actualBytes})`)
25
+ this.name = "HttpResponseBodyTooLargeError"
26
+ }
27
+ }
@@ -5,6 +5,7 @@ import fs from "node:fs/promises"
5
5
  import {digg} from "diggerize"
6
6
  import {ensureError} from "typanic"
7
7
  import EventEmitter from "../../utils/event-emitter.js"
8
+ import {HttpRequestBodyTooLargeError} from "./errors.js"
8
9
  import Logger from "../../logger.js"
9
10
  import Request from "./request.js"
10
11
  import RequestRunner from "./request-runner.js"
@@ -104,6 +105,26 @@ export default class VeoliciousHttpServerClient {
104
105
  this.events.emit("close")
105
106
  }
106
107
 
108
+ /**
109
+ * Sends a deterministic request-body limit response and closes the connection.
110
+ * @returns {void} - No return value.
111
+ */
112
+ _sendPayloadTooLargeResponse() {
113
+ const httpVersion = this.currentRequest?.httpVersion() || "1.1"
114
+ const body = "Payload Too Large\n"
115
+ const headers = [
116
+ `HTTP/${httpVersion} 413 Payload Too Large`,
117
+ "Connection: Close",
118
+ "Content-Type: text/plain; charset=UTF-8",
119
+ `Content-Length: ${Buffer.byteLength(body, "utf8")}`,
120
+ "",
121
+ body
122
+ ].join("\r\n")
123
+
124
+ this.events.emit("output", headers)
125
+ this.events.emit("close")
126
+ }
127
+
107
128
  /**
108
129
  * Runs handle bad request.
109
130
  * @param {Error} error - Error instance.
@@ -121,7 +142,11 @@ export default class VeoliciousHttpServerClient {
121
142
  this.currentRequest = undefined
122
143
  this.state = "initial"
123
144
 
124
- this._sendBadRequestResponse("Bad Request")
145
+ if (error instanceof HttpRequestBodyTooLargeError) {
146
+ this._sendPayloadTooLargeResponse()
147
+ } else {
148
+ this._sendBadRequestResponse("Bad Request")
149
+ }
125
150
  }
126
151
 
127
152
  executeCurrentRequest = () => {
@@ -3,6 +3,7 @@
3
3
  import EventEmitter from "../../../utils/event-emitter.js"
4
4
  import FormDataPart from "./form-data-part.js"
5
5
  import Header from "./header.js"
6
+ import {HttpRequestBodyTooLargeError} from "../errors.js"
6
7
  import {incorporate} from "incorporator"
7
8
  import Logger from "../../../logger.js"
8
9
  import ParamsToObject from "../params-to-object.js"
@@ -66,6 +67,31 @@ export default class RequestBuffer {
66
67
  this.logger = new Logger(this, {debug: false})
67
68
  }
68
69
 
70
+ /**
71
+ * Raises before buffering a request body beyond the configured bound.
72
+ * @param {number} actualBytes - Declared or accumulated decoded body bytes.
73
+ * @returns {void}
74
+ */
75
+ assertRequestBodySize(actualBytes) {
76
+ const maxBytes = this.configuration.getHttpServerMaxRequestBodyBytes()
77
+
78
+ if (maxBytes !== undefined && actualBytes > maxBytes) {
79
+ throw new HttpRequestBodyTooLargeError({actualBytes, maxBytes})
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Records bytes consumed after request headers. Multipart parsing can accept
85
+ * an unframed body, so enforce its configured bound during accumulation.
86
+ * @param {number} bytes - Newly consumed body bytes.
87
+ * @returns {void}
88
+ */
89
+ recordBodyBytes(bytes) {
90
+ this.bodyLength += bytes
91
+
92
+ if (this.multiPartyFormData) this.assertRequestBodySize(this.bodyLength)
93
+ }
94
+
69
95
  destroy() {
70
96
  // Do nothing for now...
71
97
  }
@@ -113,7 +139,7 @@ export default class RequestBuffer {
113
139
  const newlineIndex = data.indexOf(10, index)
114
140
 
115
141
  if (newlineIndex === -1) {
116
- if (this.readingBody) this.bodyLength += data.length - index
142
+ if (this.readingBody) this.recordBodyBytes(data.length - index)
117
143
 
118
144
  for (let dataIndex = index; dataIndex < data.length; dataIndex += 1) {
119
145
  this.data.push(data[dataIndex])
@@ -122,7 +148,7 @@ export default class RequestBuffer {
122
148
  return data.length
123
149
  }
124
150
 
125
- if (this.readingBody) this.bodyLength += newlineIndex + 1 - index
151
+ if (this.readingBody) this.recordBodyBytes(newlineIndex + 1 - index)
126
152
 
127
153
  let line
128
154
 
@@ -157,7 +183,7 @@ export default class RequestBuffer {
157
183
  const endIndex = Math.min(data.length, index + remainingBodyBytes)
158
184
 
159
185
  this.postBodyBuffers.push(data.subarray(index, endIndex))
160
- this.bodyLength += endIndex - index
186
+ this.recordBodyBytes(endIndex - index)
161
187
 
162
188
  if (this.contentLength && this.bodyLength >= this.contentLength) {
163
189
  this.postRequestDone()
@@ -175,7 +201,7 @@ export default class RequestBuffer {
175
201
  feedByte(data, index) {
176
202
  const char = data[index]
177
203
 
178
- if (this.readingBody) this.bodyLength += 1
204
+ if (this.readingBody) this.recordBodyBytes(1)
179
205
 
180
206
  switch(this.state) {
181
207
  case "chunked-data": {
@@ -414,6 +440,12 @@ export default class RequestBuffer {
414
440
  this.readingBody = true
415
441
  this.bodyLength = 0
416
442
 
443
+ if (this.contentLength !== undefined) {
444
+ if (Number.isNaN(this.contentLength)) throw new Error("Content length is invalid")
445
+
446
+ this.assertRequestBodySize(this.contentLength)
447
+ }
448
+
417
449
  const match = this.getHeader("content-type")?.value?.match(/^multipart\/form-data;\s*boundary=(.+)$/i)
418
450
 
419
451
  if (match) {
@@ -425,8 +457,6 @@ export default class RequestBuffer {
425
457
  this.setState("multi-part-form-data")
426
458
  } else if (this.contentLength === 0 || this.contentLength === undefined) {
427
459
  this.completeRequest()
428
- } else if (Number.isNaN(this.contentLength)) {
429
- throw new Error("Content length is invalid")
430
460
  } else {
431
461
  /**
432
462
  * Narrows the runtime value to the documented type.
@@ -521,6 +551,8 @@ export default class RequestBuffer {
521
551
  return
522
552
  }
523
553
 
554
+ this.assertRequestBodySize((this.chunkedBodyChars?.length || 0) + size)
555
+
524
556
  this.currentChunkSize = size
525
557
  this.currentChunkBytesRead = 0
526
558
  this.setState("chunked-data")
@@ -3,6 +3,7 @@
3
3
  import {ensureError} from "typanic"
4
4
  import BacktraceCleaner from "../../utils/backtrace-cleaner-node.js"
5
5
  import EventEmitter from "../../utils/event-emitter.js"
6
+ import {HttpResponseBodyTooLargeError} from "./errors.js"
6
7
  import Logger from "../../logger.js"
7
8
  import RequestTiming from "./request-timing.js"
8
9
  import Response from "./response.js"
@@ -304,7 +305,13 @@ export default class VelociousHttpServerClientRequestRunner {
304
305
  })
305
306
 
306
307
  response.setStatus(500)
307
- response.setErrorBody(error)
308
+ try {
309
+ response.setErrorBody(error)
310
+ } catch (responseError) {
311
+ if (!(responseError instanceof HttpResponseBodyTooLargeError)) throw responseError
312
+
313
+ response.setBody("")
314
+ }
308
315
  }
309
316
 
310
317
  await this.logger.debug(() => ["Request runner done", {
@@ -1,5 +1,7 @@
1
1
  // @ts-check
2
2
 
3
+ import {HttpResponseBodyTooLargeError} from "./errors.js"
4
+
3
5
  /**
4
6
  * Named status aliases.
5
7
  * @type {Record<string, number>} */
@@ -226,6 +228,15 @@ export default class VelociousHttpServerClientResponse {
226
228
  setBody(value) {
227
229
  this.filePath = null
228
230
  this.fileOnFinished = null
231
+
232
+ const actualBytes = typeof value === "string" ? Buffer.byteLength(value, "utf8") : value.byteLength
233
+ const maxBytes = this.configuration.getHttpServerMaxBufferedResponseBodyBytes()
234
+
235
+ if (maxBytes !== undefined && actualBytes > maxBytes) {
236
+ this.body = ""
237
+ throw new HttpResponseBodyTooLargeError({actualBytes, maxBytes})
238
+ }
239
+
229
240
  this.body = value
230
241
  }
231
242
 
@@ -92,7 +92,7 @@ export default class VelociousRoutesResolver {
92
92
  }
93
93
 
94
94
  const routeResolverHookMatch = await this.resolveRouteResolverHooks(currentPath, {hasMatchingCustomRoute})
95
- let skipControllerConnections = routeResolverHookMatch?.skipControllerConnections === true
95
+ let skipControllerConnections = this.configuration.database === false || routeResolverHookMatch?.skipControllerConnections === true
96
96
  let skipAbilityResolution = routeResolverHookMatch?.skipAbilityResolution === true
97
97
  let skipTenantResolution = routeResolverHookMatch?.skipTenantResolution === true
98
98
  const matchResult = routeResolverHookMatch || !currentRoute ? undefined : this.matchPathWithRoutes(currentRoute, currentPath)
@@ -54,7 +54,7 @@ export default class VelociousApplication {
54
54
  SyncWebsocketChannel.registerFromConfiguration(this.configuration);
55
55
  await SyncPublisher.startFromConfiguration(this.configuration);
56
56
  this.configuration.setRoutes(routes);
57
- if (!this.configuration.isDatabasePoolInitialized()) {
57
+ if (this.configuration.database !== false && !this.configuration.isDatabasePoolInitialized()) {
58
58
  await this.configuration.initializeDatabasePool();
59
59
  }
60
60
  }
@@ -223,4 +223,4 @@ export default class VelociousApplication {
223
223
  });
224
224
  }
225
225
  }
226
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBwbGljYXRpb24uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sU0FBUyxNQUFNLHdCQUF3QixDQUFBO0FBQzlDLE9BQU8sTUFBTSxNQUFNLGFBQWEsQ0FBQTtBQUNoQyxPQUFPLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQTtBQUMvQyxPQUFPLGNBQWMsTUFBTSw4QkFBOEIsQ0FBQTtBQUN6RCxPQUFPLGlCQUFpQixNQUFNLCtCQUErQixDQUFBO0FBQzdELE9BQU8sYUFBYSxNQUFNLDBCQUEwQixDQUFBO0FBQ3BELE9BQU8sb0JBQW9CLE1BQU0sa0NBQWtDLENBQUE7QUFDbkUsT0FBTyxtQkFBbUIsTUFBTSx3Q0FBd0MsQ0FBQTtBQUN4RSxPQUFPLGFBQWEsTUFBTSw0QkFBNEIsQ0FBQTtBQUN0RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQTtBQUVoRTs7bUdBRW1HO0FBRW5HLE1BQU0sQ0FBQyxPQUFPLE9BQU8sb0JBQW9CO0lBQ3ZDOzs7Ozs7T0FNRztJQUNILFlBQVksRUFBQyxhQUFhLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxHQUFHLFFBQVEsRUFBQztRQUN4RCxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUE7UUFFdkIsSUFBSSxDQUFDLGFBQWE7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUE7UUFFaEUsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFFbEM7OzZDQUVxQztRQUNyQyxJQUFJLENBQUMsdUJBQXVCLEdBQUcsVUFBVSxJQUFJLEVBQUUsQ0FBQTtRQUUvQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzlCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFBO1FBQ2pCOztnREFFd0M7UUFDeEMsSUFB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QUFDLHFCQUFxQixFQUFFO2FBQy9DO1NBQ0YsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxxQkFBcUI7UUFDekIsTUFBTSxFQUFDLGNBQWMsRUFBQyxHQUFHLElBQUksQ0FBQTtRQUU3QixJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQTtRQUMvQixJQUFJLGNBQWM7WUFBRSxNQUFNLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtJQUNwRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCLEdBQUcsR0FBRyxFQUFFO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLG9CQUFvQixDQUFDLENBQUE7UUFFdkMsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFBO1FBQ3BCLENBQUM7SUFDSCxDQUFDLENBQUE7SUFFRDs7O09BR0c7SUFDSCxJQUFJO1FBQ0YsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQzdCLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFBO1FBQzVCLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCBBcHBSb3V0ZXMgZnJvbSBcIi4vcm91dGVzL2FwcC1yb3V0ZXMuanNcIlxuaW1wb3J0IExvZ2dlciBmcm9tIFwiLi9sb2dnZXIuanNcIlxuaW1wb3J0IEh0dHBTZXJ2ZXIgZnJvbSBcIi4vaHR0cC1zZXJ2ZXIvaW5kZXguanNcIlxuaW1wb3J0IEh0dHBTZXJ2ZXJMb2NrIGZyb20gXCIuL2h0dHAtc2VydmVyL3NlcnZlci1sb2NrLmpzXCJcbmltcG9ydCBTeW5jQXBpQ29udHJvbGxlciBmcm9tIFwiLi9zeW5jL3N5bmMtYXBpLWNvbnRyb2xsZXIuanNcIlxuaW1wb3J0IFN5bmNQdWJsaXNoZXIgZnJvbSBcIi4vc3luYy9zeW5jLXB1Ymxpc2hlci5qc1wiXG5pbXBvcnQgU3luY1dlYnNvY2tldENoYW5uZWwgZnJvbSBcIi4vc3luYy9zeW5jLXdlYnNvY2tldC1jaGFubmVsLmpzXCJcbmltcG9ydCB3ZWJzb2NrZXRFdmVudHNIb3N0IGZyb20gXCIuL2h0dHAtc2VydmVyL3dlYnNvY2tldC1ldmVudHMtaG9zdC5qc1wiXG5pbXBvcnQgcmVzdEFyZ3NFcnJvciBmcm9tIFwiLi91dGlscy9yZXN0LWFyZ3MtZXJyb3IuanNcIlxuaW1wb3J0IHsgcnVuU2h1dGRvd25TdGVwcyB9IGZyb20gXCIuL3V0aWxzL3NodXRkb3duLWxpZmVjeWNsZS5qc1wiXG5cbi8qKlxuICogSHR0cFNlcnZlckNvbmZpZ3VyYXRpb24gdHlwZS5cbiAqIEB0eXBlZGVmIHtpbXBvcnQoXCIuL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuSHR0cFNlcnZlckNvbmZpZ3VyYXRpb259IEh0dHBTZXJ2ZXJDb25maWd1cmF0aW9uICovXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0FwcGxpY2F0aW9uIHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGFyZ3MuY29uZmlndXJhdGlvbiAtIENvbmZpZ3VyYXRpb24gaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7SHR0cFNlcnZlckNvbmZpZ3VyYXRpb259IFthcmdzLmh0dHBTZXJ2ZXJdIC0gSHR0cCBzZXJ2ZXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLnR5cGUgLSBUeXBlIGlkZW50aWZpZXIuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29uZmlndXJhdGlvbiwgaHR0cFNlcnZlciwgdHlwZSwgLi4ucmVzdEFyZ3N9KSB7XG4gICAgcmVzdEFyZ3NFcnJvcihyZXN0QXJncylcblxuICAgIGlmICghY29uZmlndXJhdGlvbikgdGhyb3cgbmV3IEVycm9yKFwiY29uZmlndXJhdGlvbiBpcyByZXF1aXJlZFwiKVxuXG4gICAgdGhpcy5jb25maWd1cmF0aW9uID0gY29uZmlndXJhdGlvblxuXG4gICAgLyoqXG4gICAgICogU3RvcmVzIHRoZSBodHRwIHNlcnZlciBjb25maWd1cmF0aW9uIHZhbHVlLlxuICAgICAqIEB0eXBlIHtIdHRwU2VydmVyQ29uZmlndXJhdGlvbn0gKi9cbiAgICB0aGlzLmh0dHBTZXJ2ZXJDb25maWd1cmF0aW9uID0gaHR0cFNlcnZlciA/PyB7fVxuXG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgTG9nZ2VyKHRoaXMpXG4gICAgdGhpcy5fdHlwZSA9IHR5cGVcbiAgICAvKipcbiAgICAgKiBTdG9yZXMgdGhlIGh0dHAgc2VydmVyIGxvY2sgdmFsdWUuXG4gICAgICogQHR5cGUge0h0dHBTZXJ2ZXJMb2NrIHwgdW5kZWZpbmVkfSAqL1xuICAgIHRoaXMuaHR0cFNlcnZlckxvY2sgPSB1bmRlZmluZWRcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCB1bmRlZmluZWR9ICovXG4gICAgdGhpcy5fc3RvcFByb21pc2UgPSB1bmRlZmluZWRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGdldCB0eXBlLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSB0eXBlLlxuICAgKi9cbiAgZ2V0VHlwZSgpIHsgcmV0dXJuIHRoaXMuX3R5cGUgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGluaXRpYWxpemUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gY29tcGxldGUuXG4gICAqL1xuICBhc3luYyBpbml0aWFsaXplKCkge1xuICAgIGNvbnN0IHJvdXRlcyA9IGF3YWl0IEFwcFJvdXRlcy5nZXRSb3V0ZXModGhpcy5jb25maWd1cmF0aW9uKVxuXG4gICAgYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXRpYWxpemUoe3R5cGU6IHRoaXMuZ2V0VHlwZSgpfSlcblxuICAgIFN5bmNBcGlDb250cm9sbGVyLm1vdW50RnJvbUNvbmZpZ3VyYXRpb24odGhpcy5jb25maWd1cmF0aW9uKVxuICAgIFN5bmNXZWJzb2NrZXRDaGFubmVsLnJlZ2lzdGVyRnJvbUNvbmZpZ3VyYXRpb24odGhpcy5jb25maWd1cmF0aW9uKVxuICAgIGF3YWl0IFN5bmNQdWJsaXNoZXIuc3RhcnRGcm9tQ29uZmlndXJhdGlvbih0aGlzLmNvbmZpZ3VyYXRpb24pXG5cbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24uc2V0Um91dGVzKHJvdXRlcylcblxuICAgIGlmICghdGhpcy5jb25maWd1cmF0aW9uLmlzRGF0YWJhc2VQb29sSW5pdGlhbGl6ZWQoKSkge1xuICAgICAgYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXRpYWxpemVEYXRhYmFzZVBvb2woKVxuICAgIH1cblxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgaXMgYWN0aXZlLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIGFjdGl2ZS5cbiAgICovXG4gIGlzQWN0aXZlKCkge1xuICAgIGlmICh0aGlzLmh0dHBTZXJ2ZXIpIHtcbiAgICAgIHJldHVybiB0aGlzLmh0dHBTZXJ2ZXI/LmlzQWN0aXZlKClcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJ1bi5cbiAgICogQHBhcmFtIHsoKSA9PiB2b2lkfSBjYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgcnVuKGNhbGxiYWNrKSB7XG4gICAgYXdhaXQgdGhpcy5zdGFydEh0dHBTZXJ2ZXIoKVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNhbGxiYWNrKClcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgdGhpcy5zdG9wKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBzdGFydCBodHRwIHNlcnZlci5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIHN0YXJ0SHR0cFNlcnZlcigpIHtcbiAgICBjb25zdCB7Y29uZmlndXJhdGlvbn0gPSB0aGlzXG4gICAgY29uc3QgaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24gPSB7XG4gICAgICAuLi5jb25maWd1cmF0aW9uLmh0dHBTZXJ2ZXIsXG4gICAgICAuLi50aGlzLmh0dHBTZXJ2ZXJDb25maWd1cmF0aW9uXG4gICAgfVxuICAgIGNvbnN0IHBvcnQgPSBodHRwU2VydmVyQ29uZmlndXJhdGlvbi5wb3J0ID8/IDMwMDZcbiAgICBjb25zdCBob3N0ID0gaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24uaG9zdFxuXG4gICAgYXdhaXQgdGhpcy5sb2dnZXIuZGVidWcoYFN0YXJ0aW5nIHNlcnZlciBvbiBwb3J0ICR7cG9ydH1gKVxuICAgIGF3YWl0IHRoaXMuYWNxdWlyZUh0dHBTZXJ2ZXJMb2NrKHtjb25maWd1cmF0aW9uLCBob3N0OiBob3N0ID8/IFwiMC4wLjAuMFwiLCBwb3J0fSlcbiAgICBhd2FpdCB0aGlzLnN0YXJ0TG9ja2VkSHR0cFNlcnZlcih7Y29uZmlndXJhdGlvbiwgaG9zdCwgaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24sIHBvcnR9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3RhcnQgbG9ja2VkIGh0dHAgc2VydmVyLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEhUVFAgc2VydmVyIHN0YXJ0dXAgYXJndW1lbnRzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuaG9zdF0gLSBIVFRQIHNlcnZlciBob3N0LlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gYXJncy5odHRwU2VydmVyQ29uZmlndXJhdGlvbiAtIE1lcmdlZCBIVFRQIHNlcnZlciBjb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge251bWJlcn0gYXJncy5wb3J0IC0gSFRUUCBzZXJ2ZXIgcG9ydC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgdGhlIEhUVFAgc2VydmVyIGhhcyBzdGFydGVkLlxuICAgKi9cbiAgYXN5bmMgc3RhcnRMb2NrZWRIdHRwU2VydmVyKHtjb25maWd1cmF0aW9uLCBob3N0LCBodHRwU2VydmVyQ29uZmlndXJhdGlvbiwgcG9ydH0pIHtcbiAgICB0cnkge1xuICAgICAgaWYgKCFjb25maWd1cmF0aW9uLmdldFdlYnNvY2tldEV2ZW50cygpKSB7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24uc2V0V2Vic29ja2V0RXZlbnRzKC8qKiBAdHlwZSB7UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59ICovICh3ZWJzb2NrZXRFdmVudHNIb3N0KSlcbiAgICAgIH1cblxuICAgICAgYXdhaXQgY29uZmlndXJhdGlvbi5jb25uZWN0QmVhY29uKHtwZWVyVHlwZTogXCJzZXJ2ZXJcIn0pXG5cbiAgICAgIHRoaXMuaHR0cFNlcnZlciA9IHRoaXMuY3JlYXRlSHR0cFNlcnZlcih7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXG4gICAgICAgIGhvc3QsXG4gICAgICAgIGluUHJvY2VzczogaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24uaW5Qcm9jZXNzLFxuICAgICAgICBtYXhXb3JrZXJzOiBodHRwU2VydmVyQ29uZmlndXJhdGlvbi5tYXhXb3JrZXJzLFxuICAgICAgICBwb3J0LFxuICAgICAgICB3b3JrZXJzOiBodHRwU2VydmVyQ29uZmlndXJhdGlvbi53b3JrZXJzXG4gICAgICB9KVxuICAgICAgdGhpcy5odHRwU2VydmVyLmV2ZW50cy5vbihcImNsb3NlXCIsIHRoaXMub25IdHRwU2VydmVyQ2xvc2UpXG4gICAgICBjb25maWd1cmF0aW9uLl9odHRwU2VydmVySW5zdGFuY2UgPSB0aGlzLmh0dHBTZXJ2ZXJcblxuICAgICAgYXdhaXQgdGhpcy5odHRwU2VydmVyLnN0YXJ0KClcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgYXdhaXQgdGhpcy5yZWxlYXNlSHR0cFNlcnZlckxvY2soKVxuICAgICAgY29uZmlndXJhdGlvbi5faHR0cFNlcnZlckluc3RhbmNlID0gdW5kZWZpbmVkXG5cbiAgICAgIHRocm93IGVycm9yXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYWNxdWlyZSBodHRwIHNlcnZlciBsb2NrLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIExvY2sgYWNxdWlzaXRpb24gYXJndW1lbnRzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5ob3N0IC0gSFRUUCBzZXJ2ZXIgaG9zdC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGFyZ3MucG9ydCAtIEhUVFAgc2VydmVyIHBvcnQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIGFjcXVpcmluZyB0aGUgc2VydmVyIGxvY2sgd2hlbiBuZWVkZWQuXG4gICAqL1xuICBhc3luYyBhY3F1aXJlSHR0cFNlcnZlckxvY2soe2NvbmZpZ3VyYXRpb24sIGhvc3QsIHBvcnR9KSB7XG4gICAgaWYgKHRoaXMuZ2V0VHlwZSgpID09PSBcInRlc3QtcnVubmVyXCIpIHJldHVyblxuXG4gICAgY29uc3QgaHR0cFNlcnZlckxvY2sgPSBuZXcgSHR0cFNlcnZlckxvY2soe2NvbmZpZ3VyYXRpb24sIGhvc3QsIHBvcnR9KVxuICAgIGF3YWl0IGh0dHBTZXJ2ZXJMb2NrLmFjcXVpcmUoKVxuICAgIHRoaXMuaHR0cFNlcnZlckxvY2sgPSBodHRwU2VydmVyTG9ja1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY3JlYXRlIGh0dHAgc2VydmVyLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEhUVFAgc2VydmVyIGFyZ3VtZW50cy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gYXJncy5jb25maWd1cmF0aW9uIC0gQ29uZmlndXJhdGlvbiBpbnN0YW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmhvc3RdIC0gSG9zdC5cbiAgICogQHBhcmFtIHtib29sZWFufSBbYXJncy5pblByb2Nlc3NdIC0gUnVuIEhUVFAgaGFuZGxlcnMgaW4gdGhlIG1haW4gdGhyZWFkLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MubWF4V29ya2Vyc10gLSBNYXggd29ya2Vycy5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGFyZ3MucG9ydCAtIFBvcnQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy53b3JrZXJzXSAtIFdvcmtlciBjb3VudC5cbiAgICogQHJldHVybnMge0h0dHBTZXJ2ZXJ9IC0gSFRUUCBzZXJ2ZXIgaW5zdGFuY2UuXG4gICAqL1xuICBjcmVhdGVIdHRwU2VydmVyKHtjb25maWd1cmF0aW9uLCBob3N0LCBpblByb2Nlc3MsIG1heFdvcmtlcnMsIHBvcnQsIHdvcmtlcnN9KSB7XG4gICAgcmV0dXJuIG5ldyBIdHRwU2VydmVyKHtjb25maWd1cmF0aW9uLCBob3N0LCBpblByb2Nlc3MsIG1heFdvcmtlcnMsIHBvcnQsIHdvcmtlcnN9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3RvcC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIHN0b3AoKSB7XG4gICAgaWYgKCF0aGlzLl9zdG9wUHJvbWlzZSkgdGhpcy5fc3RvcFByb21pc2UgPSB0aGlzLl9zdG9wKClcblxuICAgIHJldHVybiB0aGlzLl9zdG9wUHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIFN0b3BzIGFwcGxpY2F0aW9uIGFuZCBmcmFtZXdvcmsgcmVzb3VyY2VzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciBldmVyeSBhcHBsaWNhdGlvbiBhbmQgZnJhbWV3b3JrIGNsb3NlIHN1Y2NlZWRzLlxuICAgKi9cbiAgYXN5bmMgX3N0b3AoKSB7XG4gICAgYXdhaXQgcnVuU2h1dGRvd25TdGVwcyh7XG4gICAgICBtZXNzYWdlOiBcIkFwcGxpY2F0aW9uIGFuZCBmcmFtZXdvcmsgc2h1dGRvd24gZmFpbGVkXCIsXG4gICAgICBzdGVwczogW1xuICAgICAgICBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlN0b3BwaW5nIHNlcnZlclwiKSxcbiAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmh0dHBTZXJ2ZXI/LnN0b3AoKVxuICAgICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24uX2h0dHBTZXJ2ZXJJbnN0YW5jZSA9IHVuZGVmaW5lZFxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLnNodXRkb3duKCksXG4gICAgICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMuY29uZmlndXJhdGlvbi5kaXNjb25uZWN0QmVhY29uKCksXG4gICAgICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMuY29uZmlndXJhdGlvbi5jbG9zZURhdGFiYXNlQ29ubmVjdGlvbnMoKSxcbiAgICAgICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy5yZWxlYXNlSHR0cFNlcnZlckxvY2soKVxuICAgICAgXVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyByZWxlYXNlIGh0dHAgc2VydmVyIGxvY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHRoZSBIVFRQIHNlcnZlciBsb2NrIGhhcyBiZWVuIHJlbGVhc2VkLlxuICAgKi9cbiAgYXN5bmMgcmVsZWFzZUh0dHBTZXJ2ZXJMb2NrKCkge1xuICAgIGNvbnN0IHtodHRwU2VydmVyTG9ja30gPSB0aGlzXG5cbiAgICB0aGlzLmh0dHBTZXJ2ZXJMb2NrID0gdW5kZWZpbmVkXG4gICAgaWYgKGh0dHBTZXJ2ZXJMb2NrKSBhd2FpdCBodHRwU2VydmVyTG9jay5yZWxlYXNlKClcbiAgfVxuXG4gIC8qKlxuICAgKiBPbiBodHRwIHNlcnZlciBjbG9zZS5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgb25IdHRwU2VydmVyQ2xvc2UgPSAoKSA9PiB7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXCJIVFRQIHNlcnZlciBjbG9zZWRcIilcblxuICAgIGlmICh0aGlzLndhaXRSZXNvbHZlKSB7XG4gICAgICB0aGlzLndhaXRSZXNvbHZlKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyB3YWl0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgd2FpdCgpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIHRoaXMud2FpdFJlc29sdmUgPSByZXNvbHZlXG4gICAgfSlcbiAgfVxufVxuIl19
226
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBwbGljYXRpb24uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sU0FBUyxNQUFNLHdCQUF3QixDQUFBO0FBQzlDLE9BQU8sTUFBTSxNQUFNLGFBQWEsQ0FBQTtBQUNoQyxPQUFPLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQTtBQUMvQyxPQUFPLGNBQWMsTUFBTSw4QkFBOEIsQ0FBQTtBQUN6RCxPQUFPLGlCQUFpQixNQUFNLCtCQUErQixDQUFBO0FBQzdELE9BQU8sYUFBYSxNQUFNLDBCQUEwQixDQUFBO0FBQ3BELE9BQU8sb0JBQW9CLE1BQU0sa0NBQWtDLENBQUE7QUFDbkUsT0FBTyxtQkFBbUIsTUFBTSx3Q0FBd0MsQ0FBQTtBQUN4RSxPQUFPLGFBQWEsTUFBTSw0QkFBNEIsQ0FBQTtBQUN0RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQTtBQUVoRTs7bUdBRW1HO0FBRW5HLE1BQU0sQ0FBQyxPQUFPLE9BQU8sb0JBQW9CO0lBQ3ZDOzs7Ozs7T0FNRztJQUNILFlBQVksRUFBQyxhQUFhLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxHQUFHLFFBQVEsRUFBQztRQUN4RCxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUE7UUFFdkIsSUFBSSxDQUFDLGFBQWE7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUE7UUFFaEUsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUE7UUFFbEM7OzZDQUVxQztRQUNyQyxJQUFJLENBQUMsdUJBQXVCLEdBQUcsVUFBVSxJQUFJLEVBQUUsQ0FBQTtRQUUvQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzlCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFBO1FBQ2pCOztnREFFd0M7UUFDeEMsSUFB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RTtnQkFDL0QsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLElBQUksQ0FBQyxxQkFBcUIsRUFBRTthQUMvQztTQUNGLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMscUJBQXFCO1FBQ3pCLE1BQU0sRUFBQyxjQUFjLEVBQUMsR0FBRyxJQUFJLENBQUE7UUFFN0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxTQUFTLENBQUE7UUFDL0IsSUFBSSxjQUFjO1lBQUUsTUFBTSxjQUFjLENBQUMsT0FBTyxFQUFFLENBQUE7SUFDcEQsQ0FBQztJQUVEOzs7T0FHRztJQUNILGlCQUFpQixHQUFHLEdBQUcsRUFBRTtRQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFBO1FBRXZDLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3JCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQTtRQUNwQixDQUFDO0lBQ0gsQ0FBQyxDQUFBO0lBRUQ7OztPQUdHO0lBQ0gsSUFBSTtRQUNGLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQTtRQUM1QixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQXBwUm91dGVzIGZyb20gXCIuL3JvdXRlcy9hcHAtcm91dGVzLmpzXCJcbmltcG9ydCBMb2dnZXIgZnJvbSBcIi4vbG9nZ2VyLmpzXCJcbmltcG9ydCBIdHRwU2VydmVyIGZyb20gXCIuL2h0dHAtc2VydmVyL2luZGV4LmpzXCJcbmltcG9ydCBIdHRwU2VydmVyTG9jayBmcm9tIFwiLi9odHRwLXNlcnZlci9zZXJ2ZXItbG9jay5qc1wiXG5pbXBvcnQgU3luY0FwaUNvbnRyb2xsZXIgZnJvbSBcIi4vc3luYy9zeW5jLWFwaS1jb250cm9sbGVyLmpzXCJcbmltcG9ydCBTeW5jUHVibGlzaGVyIGZyb20gXCIuL3N5bmMvc3luYy1wdWJsaXNoZXIuanNcIlxuaW1wb3J0IFN5bmNXZWJzb2NrZXRDaGFubmVsIGZyb20gXCIuL3N5bmMvc3luYy13ZWJzb2NrZXQtY2hhbm5lbC5qc1wiXG5pbXBvcnQgd2Vic29ja2V0RXZlbnRzSG9zdCBmcm9tIFwiLi9odHRwLXNlcnZlci93ZWJzb2NrZXQtZXZlbnRzLWhvc3QuanNcIlxuaW1wb3J0IHJlc3RBcmdzRXJyb3IgZnJvbSBcIi4vdXRpbHMvcmVzdC1hcmdzLWVycm9yLmpzXCJcbmltcG9ydCB7IHJ1blNodXRkb3duU3RlcHMgfSBmcm9tIFwiLi91dGlscy9zaHV0ZG93bi1saWZlY3ljbGUuanNcIlxuXG4vKipcbiAqIEh0dHBTZXJ2ZXJDb25maWd1cmF0aW9uIHR5cGUuXG4gKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkh0dHBTZXJ2ZXJDb25maWd1cmF0aW9ufSBIdHRwU2VydmVyQ29uZmlndXJhdGlvbiAqL1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZWxvY2lvdXNBcHBsaWNhdGlvbiB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMgb2JqZWN0LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge0h0dHBTZXJ2ZXJDb25maWd1cmF0aW9ufSBbYXJncy5odHRwU2VydmVyXSAtIEh0dHAgc2VydmVyLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy50eXBlIC0gVHlwZSBpZGVudGlmaWVyLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe2NvbmZpZ3VyYXRpb24sIGh0dHBTZXJ2ZXIsIHR5cGUsIC4uLnJlc3RBcmdzfSkge1xuICAgIHJlc3RBcmdzRXJyb3IocmVzdEFyZ3MpXG5cbiAgICBpZiAoIWNvbmZpZ3VyYXRpb24pIHRocm93IG5ldyBFcnJvcihcImNvbmZpZ3VyYXRpb24gaXMgcmVxdWlyZWRcIilcblxuICAgIHRoaXMuY29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb25cblxuICAgIC8qKlxuICAgICAqIFN0b3JlcyB0aGUgaHR0cCBzZXJ2ZXIgY29uZmlndXJhdGlvbiB2YWx1ZS5cbiAgICAgKiBAdHlwZSB7SHR0cFNlcnZlckNvbmZpZ3VyYXRpb259ICovXG4gICAgdGhpcy5odHRwU2VydmVyQ29uZmlndXJhdGlvbiA9IGh0dHBTZXJ2ZXIgPz8ge31cblxuICAgIHRoaXMubG9nZ2VyID0gbmV3IExvZ2dlcih0aGlzKVxuICAgIHRoaXMuX3R5cGUgPSB0eXBlXG4gICAgLyoqXG4gICAgICogU3RvcmVzIHRoZSBodHRwIHNlcnZlciBsb2NrIHZhbHVlLlxuICAgICAqIEB0eXBlIHtIdHRwU2VydmVyTG9jayB8IHVuZGVmaW5lZH0gKi9cbiAgICB0aGlzLmh0dHBTZXJ2ZXJMb2NrID0gdW5kZWZpbmVkXG4gICAgLyoqIEB0eXBlIHtQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkfSAqL1xuICAgIHRoaXMuX3N0b3BQcm9taXNlID0gdW5kZWZpbmVkXG4gIH1cblxuICAvKipcbiAgICogUnVucyBnZXQgdHlwZS5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgdHlwZS5cbiAgICovXG4gIGdldFR5cGUoKSB7IHJldHVybiB0aGlzLl90eXBlIH1cblxuICAvKipcbiAgICogUnVucyBpbml0aWFsaXplLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgaW5pdGlhbGl6ZSgpIHtcbiAgICBjb25zdCByb3V0ZXMgPSBhd2FpdCBBcHBSb3V0ZXMuZ2V0Um91dGVzKHRoaXMuY29uZmlndXJhdGlvbilcblxuICAgIGF3YWl0IHRoaXMuY29uZmlndXJhdGlvbi5pbml0aWFsaXplKHt0eXBlOiB0aGlzLmdldFR5cGUoKX0pXG5cbiAgICBTeW5jQXBpQ29udHJvbGxlci5tb3VudEZyb21Db25maWd1cmF0aW9uKHRoaXMuY29uZmlndXJhdGlvbilcbiAgICBTeW5jV2Vic29ja2V0Q2hhbm5lbC5yZWdpc3RlckZyb21Db25maWd1cmF0aW9uKHRoaXMuY29uZmlndXJhdGlvbilcbiAgICBhd2FpdCBTeW5jUHVibGlzaGVyLnN0YXJ0RnJvbUNvbmZpZ3VyYXRpb24odGhpcy5jb25maWd1cmF0aW9uKVxuXG4gICAgdGhpcy5jb25maWd1cmF0aW9uLnNldFJvdXRlcyhyb3V0ZXMpXG5cbiAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uLmRhdGFiYXNlICE9PSBmYWxzZSAmJiAhdGhpcy5jb25maWd1cmF0aW9uLmlzRGF0YWJhc2VQb29sSW5pdGlhbGl6ZWQoKSkge1xuICAgICAgYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXRpYWxpemVEYXRhYmFzZVBvb2woKVxuICAgIH1cblxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgaXMgYWN0aXZlLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIGFjdGl2ZS5cbiAgICovXG4gIGlzQWN0aXZlKCkge1xuICAgIGlmICh0aGlzLmh0dHBTZXJ2ZXIpIHtcbiAgICAgIHJldHVybiB0aGlzLmh0dHBTZXJ2ZXI/LmlzQWN0aXZlKClcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJ1bi5cbiAgICogQHBhcmFtIHsoKSA9PiB2b2lkfSBjYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgYXN5bmMgcnVuKGNhbGxiYWNrKSB7XG4gICAgYXdhaXQgdGhpcy5zdGFydEh0dHBTZXJ2ZXIoKVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNhbGxiYWNrKClcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgdGhpcy5zdG9wKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBzdGFydCBodHRwIHNlcnZlci5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIGFzeW5jIHN0YXJ0SHR0cFNlcnZlcigpIHtcbiAgICBjb25zdCB7Y29uZmlndXJhdGlvbn0gPSB0aGlzXG4gICAgY29uc3QgaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24gPSB7XG4gICAgICAuLi5jb25maWd1cmF0aW9uLmh0dHBTZXJ2ZXIsXG4gICAgICAuLi50aGlzLmh0dHBTZXJ2ZXJDb25maWd1cmF0aW9uXG4gICAgfVxuICAgIGNvbnN0IHBvcnQgPSBodHRwU2VydmVyQ29uZmlndXJhdGlvbi5wb3J0ID8/IDMwMDZcbiAgICBjb25zdCBob3N0ID0gaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24uaG9zdFxuXG4gICAgYXdhaXQgdGhpcy5sb2dnZXIuZGVidWcoYFN0YXJ0aW5nIHNlcnZlciBvbiBwb3J0ICR7cG9ydH1gKVxuICAgIGF3YWl0IHRoaXMuYWNxdWlyZUh0dHBTZXJ2ZXJMb2NrKHtjb25maWd1cmF0aW9uLCBob3N0OiBob3N0ID8/IFwiMC4wLjAuMFwiLCBwb3J0fSlcbiAgICBhd2FpdCB0aGlzLnN0YXJ0TG9ja2VkSHR0cFNlcnZlcih7Y29uZmlndXJhdGlvbiwgaG9zdCwgaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24sIHBvcnR9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3RhcnQgbG9ja2VkIGh0dHAgc2VydmVyLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEhUVFAgc2VydmVyIHN0YXJ0dXAgYXJndW1lbnRzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuaG9zdF0gLSBIVFRQIHNlcnZlciBob3N0LlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gYXJncy5odHRwU2VydmVyQ29uZmlndXJhdGlvbiAtIE1lcmdlZCBIVFRQIHNlcnZlciBjb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge251bWJlcn0gYXJncy5wb3J0IC0gSFRUUCBzZXJ2ZXIgcG9ydC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgdGhlIEhUVFAgc2VydmVyIGhhcyBzdGFydGVkLlxuICAgKi9cbiAgYXN5bmMgc3RhcnRMb2NrZWRIdHRwU2VydmVyKHtjb25maWd1cmF0aW9uLCBob3N0LCBodHRwU2VydmVyQ29uZmlndXJhdGlvbiwgcG9ydH0pIHtcbiAgICB0cnkge1xuICAgICAgaWYgKCFjb25maWd1cmF0aW9uLmdldFdlYnNvY2tldEV2ZW50cygpKSB7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24uc2V0V2Vic29ja2V0RXZlbnRzKC8qKiBAdHlwZSB7UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59ICovICh3ZWJzb2NrZXRFdmVudHNIb3N0KSlcbiAgICAgIH1cblxuICAgICAgYXdhaXQgY29uZmlndXJhdGlvbi5jb25uZWN0QmVhY29uKHtwZWVyVHlwZTogXCJzZXJ2ZXJcIn0pXG5cbiAgICAgIHRoaXMuaHR0cFNlcnZlciA9IHRoaXMuY3JlYXRlSHR0cFNlcnZlcih7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXG4gICAgICAgIGhvc3QsXG4gICAgICAgIGluUHJvY2VzczogaHR0cFNlcnZlckNvbmZpZ3VyYXRpb24uaW5Qcm9jZXNzLFxuICAgICAgICBtYXhXb3JrZXJzOiBodHRwU2VydmVyQ29uZmlndXJhdGlvbi5tYXhXb3JrZXJzLFxuICAgICAgICBwb3J0LFxuICAgICAgICB3b3JrZXJzOiBodHRwU2VydmVyQ29uZmlndXJhdGlvbi53b3JrZXJzXG4gICAgICB9KVxuICAgICAgdGhpcy5odHRwU2VydmVyLmV2ZW50cy5vbihcImNsb3NlXCIsIHRoaXMub25IdHRwU2VydmVyQ2xvc2UpXG4gICAgICBjb25maWd1cmF0aW9uLl9odHRwU2VydmVySW5zdGFuY2UgPSB0aGlzLmh0dHBTZXJ2ZXJcblxuICAgICAgYXdhaXQgdGhpcy5odHRwU2VydmVyLnN0YXJ0KClcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgYXdhaXQgdGhpcy5yZWxlYXNlSHR0cFNlcnZlckxvY2soKVxuICAgICAgY29uZmlndXJhdGlvbi5faHR0cFNlcnZlckluc3RhbmNlID0gdW5kZWZpbmVkXG5cbiAgICAgIHRocm93IGVycm9yXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYWNxdWlyZSBodHRwIHNlcnZlciBsb2NrLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIExvY2sgYWNxdWlzaXRpb24gYXJndW1lbnRzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5ob3N0IC0gSFRUUCBzZXJ2ZXIgaG9zdC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGFyZ3MucG9ydCAtIEhUVFAgc2VydmVyIHBvcnQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIGFjcXVpcmluZyB0aGUgc2VydmVyIGxvY2sgd2hlbiBuZWVkZWQuXG4gICAqL1xuICBhc3luYyBhY3F1aXJlSHR0cFNlcnZlckxvY2soe2NvbmZpZ3VyYXRpb24sIGhvc3QsIHBvcnR9KSB7XG4gICAgaWYgKHRoaXMuZ2V0VHlwZSgpID09PSBcInRlc3QtcnVubmVyXCIpIHJldHVyblxuXG4gICAgY29uc3QgaHR0cFNlcnZlckxvY2sgPSBuZXcgSHR0cFNlcnZlckxvY2soe2NvbmZpZ3VyYXRpb24sIGhvc3QsIHBvcnR9KVxuICAgIGF3YWl0IGh0dHBTZXJ2ZXJMb2NrLmFjcXVpcmUoKVxuICAgIHRoaXMuaHR0cFNlcnZlckxvY2sgPSBodHRwU2VydmVyTG9ja1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY3JlYXRlIGh0dHAgc2VydmVyLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEhUVFAgc2VydmVyIGFyZ3VtZW50cy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gYXJncy5jb25maWd1cmF0aW9uIC0gQ29uZmlndXJhdGlvbiBpbnN0YW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmhvc3RdIC0gSG9zdC5cbiAgICogQHBhcmFtIHtib29sZWFufSBbYXJncy5pblByb2Nlc3NdIC0gUnVuIEhUVFAgaGFuZGxlcnMgaW4gdGhlIG1haW4gdGhyZWFkLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MubWF4V29ya2Vyc10gLSBNYXggd29ya2Vycy5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGFyZ3MucG9ydCAtIFBvcnQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy53b3JrZXJzXSAtIFdvcmtlciBjb3VudC5cbiAgICogQHJldHVybnMge0h0dHBTZXJ2ZXJ9IC0gSFRUUCBzZXJ2ZXIgaW5zdGFuY2UuXG4gICAqL1xuICBjcmVhdGVIdHRwU2VydmVyKHtjb25maWd1cmF0aW9uLCBob3N0LCBpblByb2Nlc3MsIG1heFdvcmtlcnMsIHBvcnQsIHdvcmtlcnN9KSB7XG4gICAgcmV0dXJuIG5ldyBIdHRwU2VydmVyKHtjb25maWd1cmF0aW9uLCBob3N0LCBpblByb2Nlc3MsIG1heFdvcmtlcnMsIHBvcnQsIHdvcmtlcnN9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgc3RvcC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgd2hlbiBjb21wbGV0ZS5cbiAgICovXG4gIHN0b3AoKSB7XG4gICAgaWYgKCF0aGlzLl9zdG9wUHJvbWlzZSkgdGhpcy5fc3RvcFByb21pc2UgPSB0aGlzLl9zdG9wKClcblxuICAgIHJldHVybiB0aGlzLl9zdG9wUHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIFN0b3BzIGFwcGxpY2F0aW9uIGFuZCBmcmFtZXdvcmsgcmVzb3VyY2VzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciBldmVyeSBhcHBsaWNhdGlvbiBhbmQgZnJhbWV3b3JrIGNsb3NlIHN1Y2NlZWRzLlxuICAgKi9cbiAgYXN5bmMgX3N0b3AoKSB7XG4gICAgYXdhaXQgcnVuU2h1dGRvd25TdGVwcyh7XG4gICAgICBtZXNzYWdlOiBcIkFwcGxpY2F0aW9uIGFuZCBmcmFtZXdvcmsgc2h1dGRvd24gZmFpbGVkXCIsXG4gICAgICBzdGVwczogW1xuICAgICAgICBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLmxvZ2dlci5kZWJ1ZyhcIlN0b3BwaW5nIHNlcnZlclwiKSxcbiAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmh0dHBTZXJ2ZXI/LnN0b3AoKVxuICAgICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24uX2h0dHBTZXJ2ZXJJbnN0YW5jZSA9IHVuZGVmaW5lZFxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLnNodXRkb3duKCksXG4gICAgICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMuY29uZmlndXJhdGlvbi5kaXNjb25uZWN0QmVhY29uKCksXG4gICAgICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMuY29uZmlndXJhdGlvbi5jbG9zZURhdGFiYXNlQ29ubmVjdGlvbnMoKSxcbiAgICAgICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy5yZWxlYXNlSHR0cFNlcnZlckxvY2soKVxuICAgICAgXVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyByZWxlYXNlIGh0dHAgc2VydmVyIGxvY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHRoZSBIVFRQIHNlcnZlciBsb2NrIGhhcyBiZWVuIHJlbGVhc2VkLlxuICAgKi9cbiAgYXN5bmMgcmVsZWFzZUh0dHBTZXJ2ZXJMb2NrKCkge1xuICAgIGNvbnN0IHtodHRwU2VydmVyTG9ja30gPSB0aGlzXG5cbiAgICB0aGlzLmh0dHBTZXJ2ZXJMb2NrID0gdW5kZWZpbmVkXG4gICAgaWYgKGh0dHBTZXJ2ZXJMb2NrKSBhd2FpdCBodHRwU2VydmVyTG9jay5yZWxlYXNlKClcbiAgfVxuXG4gIC8qKlxuICAgKiBPbiBodHRwIHNlcnZlciBjbG9zZS5cbiAgICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICAgKi9cbiAgb25IdHRwU2VydmVyQ2xvc2UgPSAoKSA9PiB7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXCJIVFRQIHNlcnZlciBjbG9zZWRcIilcblxuICAgIGlmICh0aGlzLndhaXRSZXNvbHZlKSB7XG4gICAgICB0aGlzLndhaXRSZXNvbHZlKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyB3YWl0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGNvbXBsZXRlLlxuICAgKi9cbiAgd2FpdCgpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIHRoaXMud2FpdFJlc29sdmUgPSByZXNvbHZlXG4gICAgfSlcbiAgfVxufVxuIl19
@@ -600,6 +600,14 @@ export type HttpServerConfiguration = {
600
600
  * - Run HTTP handlers in the main thread instead of worker threads.
601
601
  */
602
602
  inProcess?: boolean;
603
+ /**
604
+ * - Maximum UTF-8/binary byte length accepted by buffered response bodies. Unbounded when absent; streamed file responses are unaffected.
605
+ */
606
+ maxBufferedResponseBodyBytes?: number;
607
+ /**
608
+ * - Maximum decoded request-body bytes accepted before routing. Unbounded when absent.
609
+ */
610
+ maxRequestBodyBytes?: number;
603
611
  /**
604
612
  * - Backward-compatible alias for workers.
605
613
  */
@@ -1547,9 +1555,9 @@ export type ConfigurationArgsType = {
1547
1555
  */
1548
1556
  packages?: VelociousPackageConfiguration[];
1549
1557
  /**
1550
- * - Database configurations keyed by environment and identifier.
1558
+ * - Database configurations keyed by environment and identifier, or false for an explicitly database-free application.
1551
1559
  */
1552
- database: {
1560
+ database?: false | {
1553
1561
  [key: string]: {
1554
1562
  [key: string]: DatabaseConfigurationType;
1555
1563
  };
@@ -1965,6 +1973,8 @@ export type ConfigurationArgsType = {
1965
1973
  * @property {boolean | HttpCompressionConfiguration} [compression] - Buffered response compression. Enabled with documented defaults when absent; false or {enabled: false} disables it globally.
1966
1974
  * @property {string} [host] - Hostname to bind the HTTP server to.
1967
1975
  * @property {boolean} [inProcess] - Run HTTP handlers in the main thread instead of worker threads.
1976
+ * @property {number} [maxBufferedResponseBodyBytes] - Maximum UTF-8/binary byte length accepted by buffered response bodies. Unbounded when absent; streamed file responses are unaffected.
1977
+ * @property {number} [maxRequestBodyBytes] - Maximum decoded request-body bytes accepted before routing. Unbounded when absent.
1968
1978
  * @property {number} [maxWorkers] - Backward-compatible alias for workers.
1969
1979
  * @property {number} [port] - Port to bind the HTTP server to.
1970
1980
  * @property {{maxPendingBytes?: number, maxPendingMessages?: number}} [websocketInboundQueue] - Per-session retained inbound WebSocket message limits.
@@ -2351,7 +2361,7 @@ export type ConfigurationArgsType = {
2351
2361
  * @property {AttachmentsConfiguration} [attachments] - Attachment storage configuration.
2352
2362
  * @property {BackendProjectConfiguration[]} [backendProjects] - Backend project definitions used for frontend model generation.
2353
2363
  * @property {VelociousPackageConfiguration[]} [packages] - External Velocious packages that contribute models, frontend-model resources and migrations.
2354
- * @property {{[key: string]: {[key: string]: DatabaseConfigurationType}}} database - Database configurations keyed by environment and identifier.
2364
+ * @property {false | {[key: string]: {[key: string]: DatabaseConfigurationType}}} [database] - Database configurations keyed by environment and identifier, or false for an explicitly database-free application.
2355
2365
  * @property {boolean} [debug] - Enable debug logging.
2356
2366
  * @property {boolean | DebugEndpointConfiguration} [debugEndpoint] - Enable the built-in debug endpoint. Defaults to false.
2357
2367
  * @property {boolean | ApiManifestConfiguration} [apiManifest] - Enable the built-in API manifest endpoint. Defaults to false.