@tumbaland/backend-core 1.46.0 → 1.48.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/dist/app/shutdown.d.ts +3 -3
- package/dist/app/shutdown.d.ts.map +1 -1
- package/dist/app/shutdown.js +6 -3
- package/dist/app/shutdown.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/sse/index.d.ts +3 -0
- package/dist/sse/index.d.ts.map +1 -0
- package/dist/sse/index.js +11 -0
- package/dist/sse/index.js.map +1 -0
- package/dist/sse/sseStream.d.ts +57 -0
- package/dist/sse/sseStream.d.ts.map +1 -0
- package/dist/sse/sseStream.js +143 -0
- package/dist/sse/sseStream.js.map +1 -0
- package/package.json +2 -2
package/dist/app/shutdown.d.ts
CHANGED
|
@@ -19,9 +19,9 @@ export interface RegisterShutdownOptions {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Registers `SIGINT` and `SIGTERM` handlers that drain the service before the
|
|
22
|
-
* process exits: run the optional cleanup hook,
|
|
23
|
-
* connections, then close the MongoDB connection.
|
|
24
|
-
* it's the signal Docker/Kubernetes send on stop and rollout, and without a
|
|
22
|
+
* process exits: end any open event streams, run the optional cleanup hook,
|
|
23
|
+
* stop accepting new HTTP connections, then close the MongoDB connection.
|
|
24
|
+
* `SIGTERM` matters most — it's the signal Docker/Kubernetes send on stop and rollout, and without a
|
|
25
25
|
* handler the process is force-killed with its DB connection still open.
|
|
26
26
|
*
|
|
27
27
|
* The handler is idempotent (a second signal while shutting down is ignored)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/app/shutdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/app/shutdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAKnC,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,2EAM9B,uBAAuB,KAAG,IA2C5B,CAAC"}
|
package/dist/app/shutdown.js
CHANGED
|
@@ -6,11 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.registerShutdown = void 0;
|
|
7
7
|
const logger_1 = __importDefault(require("../logging/logger"));
|
|
8
8
|
const connection_1 = require("../database/connection");
|
|
9
|
+
const sseStream_1 = require("../sse/sseStream");
|
|
9
10
|
/**
|
|
10
11
|
* Registers `SIGINT` and `SIGTERM` handlers that drain the service before the
|
|
11
|
-
* process exits: run the optional cleanup hook,
|
|
12
|
-
* connections, then close the MongoDB connection.
|
|
13
|
-
* it's the signal Docker/Kubernetes send on stop and rollout, and without a
|
|
12
|
+
* process exits: end any open event streams, run the optional cleanup hook,
|
|
13
|
+
* stop accepting new HTTP connections, then close the MongoDB connection.
|
|
14
|
+
* `SIGTERM` matters most — it's the signal Docker/Kubernetes send on stop and rollout, and without a
|
|
14
15
|
* handler the process is force-killed with its DB connection still open.
|
|
15
16
|
*
|
|
16
17
|
* The handler is idempotent (a second signal while shutting down is ignored)
|
|
@@ -30,6 +31,8 @@ const registerShutdown = ({ serviceName, server, disconnectDatabase = true, onSh
|
|
|
30
31
|
// Don't let the timer itself keep the event loop alive.
|
|
31
32
|
forceExit.unref?.();
|
|
32
33
|
try {
|
|
34
|
+
// An event stream never finishes by itself, and server.close() waits for it.
|
|
35
|
+
(0, sseStream_1.closeAllSseStreams)();
|
|
33
36
|
if (onShutdown)
|
|
34
37
|
await onShutdown();
|
|
35
38
|
if (server) {
|
package/dist/app/shutdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/app/shutdown.ts"],"names":[],"mappings":";;;;;;AACA,+DAAuC;AACvC,uDAAsD;AAqBtD;;;;;;;;;GASG;AACI,MAAM,gBAAgB,GAAG,CAAC,EAC/B,WAAW,EACX,MAAM,EACN,kBAAkB,GAAG,IAAI,EACzB,UAAU,EACV,gBAAgB,GAAG,MAAM,EACD,EAAQ,EAAE;IAClC,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QAEpB,gBAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;QAE9F,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,gBAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACrB,wDAAwD;QACxD,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAEpB,IAAI,CAAC;YACH,IAAI,UAAU;gBAAE,MAAM,UAAU,EAAE,CAAC;YAEnC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBAC1C,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACzD,CAAC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,kBAAkB;gBAAE,MAAM,IAAA,yBAAY,EAAC,WAAW,CAAC,CAAC;YAExD,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,gBAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;gBAC7C,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAG,KAAe,EAAE,OAAO;aACjC,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/app/shutdown.ts"],"names":[],"mappings":";;;;;;AACA,+DAAuC;AACvC,uDAAsD;AACtD,gDAAsD;AAqBtD;;;;;;;;;GASG;AACI,MAAM,gBAAgB,GAAG,CAAC,EAC/B,WAAW,EACX,MAAM,EACN,kBAAkB,GAAG,IAAI,EACzB,UAAU,EACV,gBAAgB,GAAG,MAAM,EACD,EAAQ,EAAE;IAClC,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QAEpB,gBAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;QAE9F,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,gBAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACrB,wDAAwD;QACxD,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAEpB,IAAI,CAAC;YACH,6EAA6E;YAC7E,IAAA,8BAAkB,GAAE,CAAC;YACrB,IAAI,UAAU;gBAAE,MAAM,UAAU,EAAE,CAAC;YAEnC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBAC1C,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACzD,CAAC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,kBAAkB;gBAAE,MAAM,IAAA,yBAAY,EAAC,WAAW,CAAC,CAAC;YAExD,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,gBAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;gBAC7C,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAG,KAAe,EAAE,OAAO;aACjC,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;AAjDW,QAAA,gBAAgB,oBAiD3B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from './apiKeys';
|
|
|
16
16
|
export * from './fileService';
|
|
17
17
|
export * from './oauth';
|
|
18
18
|
export * from './audit';
|
|
19
|
+
export * from './sse';
|
|
19
20
|
export { authenticateToken, optionalAuth } from './middleware/authMiddleware';
|
|
20
21
|
export { USER_SESSIONS_COLLECTION, isCurrentSession, isLegacySessionlessToken } from './auth/session';
|
|
21
22
|
export { requireInternalServiceToken, internalServiceTokenBypass, allowUserOrInternalService, verifyInternalToken, INTERNAL_TOKEN_HEADER, SERVICE_ID_HEADER } from './middleware/internalServiceAuth';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC7K,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,cAAc,gBAAgB,CAAC;AAG/B,cAAc,UAAU,CAAC;AAGzB,cAAc,WAAW,CAAC;AAG1B,cAAc,eAAe,CAAC;AAG9B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACnH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACT,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EACnB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC7K,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,cAAc,gBAAgB,CAAC;AAG/B,cAAc,UAAU,CAAC;AAGzB,cAAc,WAAW,CAAC;AAG1B,cAAc,eAAe,CAAC;AAG9B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AAGxB,cAAc,OAAO,CAAC;AAGtB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACnH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACT,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EACnB,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,8 @@ __exportStar(require("./fileService"), exports);
|
|
|
63
63
|
// OAuth 2.1 authorization server, for assistants connecting over MCP
|
|
64
64
|
__exportStar(require("./oauth"), exports);
|
|
65
65
|
__exportStar(require("./audit"), exports);
|
|
66
|
+
// Server-Sent Events streams (headers, heartbeat, lifetime, shutdown)
|
|
67
|
+
__exportStar(require("./sse"), exports);
|
|
66
68
|
// Middleware
|
|
67
69
|
var authMiddleware_1 = require("./middleware/authMiddleware");
|
|
68
70
|
Object.defineProperty(exports, "authenticateToken", { enumerable: true, get: function () { return authMiddleware_1.authenticateToken; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,qFAAqF;;;;;;;;;;;;;;;;;;;;;AAErF,gBAAgB;AAChB,qDAAoD;AAA3C,8GAAA,aAAa,OAAA;AAEtB,2CAAkD;AAAzC,4GAAA,gBAAgB,OAAA;AAGzB,UAAU;AACV,2CAAqD;AAA5C,iHAAA,OAAO,OAAU;AAE1B,gBAAgB;AAChB,8DAAoF;AAA3E,+GAAA,WAAW,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,kHAAA,cAAc,OAAA;AAChD,gEAA+D;AAAtD,sHAAA,iBAAiB,OAAA;AAG1B,WAAW;AACX,oDAAgE;AAAvD,uGAAA,SAAS,OAAA;AAAE,0GAAA,YAAY,OAAA;AAEhC,SAAS;AACT,oCAA0C;AAAjC,iGAAA,UAAU,OAAA;AAEnB,SAAS;AACT,gDAA6K;AAApK,sGAAA,SAAS,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAGhJ,wDAAwD;AACxD,iDAA+B;AAE/B,0DAA0D;AAC1D,2CAAyB;AAEzB,+DAA+D;AAC/D,4CAA0B;AAE1B,+EAA+E;AAC/E,gDAA8B;AAE9B,qEAAqE;AACrE,0CAAwB;AACxB,0CAAwB;AAExB,aAAa;AACb,8DAA8E;AAArE,mHAAA,iBAAiB,OAAA;AAAE,8GAAA,YAAY,OAAA;AACxC,0CAAsG;AAA7F,mHAAA,wBAAwB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAAE,mHAAA,wBAAwB,OAAA;AAC7E,wEAO0C;AANxC,kIAAA,2BAA2B,OAAA;AAC3B,iIAAA,0BAA0B,OAAA;AAC1B,iIAAA,0BAA0B,OAAA;AAC1B,0HAAA,mBAAmB,OAAA;AACnB,4HAAA,qBAAqB,OAAA;AACrB,wHAAA,iBAAiB,OAAA;AAEnB,8DAAmE;AAA1D,sHAAA,oBAAoB,OAAA;AAC7B,0DAAyD;AAAhD,4GAAA,YAAY,OAAA;AACrB,4DAA0G;AAAjG,8GAAA,aAAa,OAAA;AAAE,yHAAA,wBAAwB,OAAA;AAAE,oHAAA,mBAAmB,OAAA;AACrE,kDAAmH;AAA1G,2GAAA,eAAe,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AACnF,kDAAiD;AAAxC,oGAAA,QAAQ,OAAA;AAKjB,QAAQ;AACR,mDAAmF;AAA1E,oHAAA,qBAAqB,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AACrD,6CAA6E;AAApE,6GAAA,iBAAiB,OAAA;AAAE,uGAAA,WAAW,OAAA;AAAE,qGAAA,SAAS,OAAA;AAElD,2DAA8E;AAArE,mHAAA,gBAAgB,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC5C,mDAAkD;AAAzC,0GAAA,WAAW,OAAA;AAEpB,UAAU;AACV,qCAQmB;AAPjB,4GAAA,iBAAiB,OAAA;AACjB,8GAAA,mBAAmB,OAAA;AACnB,4GAAA,iBAAiB,OAAA;AACjB,gHAAA,qBAAqB,OAAA;AACrB,+GAAA,oBAAoB,OAAA;AACpB,0GAAA,eAAe,OAAA;AACf,mGAAA,QAAQ,OAAA;AAGV,UAAU;AACV,qCAUmB;AATjB,qGAAA,UAAU,OAAA;AACV,oGAAA,SAAS,OAAA;AACT,oGAAA,SAAS,OAAA;AACT,4GAAA,iBAAiB,OAAA;AACjB,0GAAA,eAAe,OAAA;AACf,oGAAA,SAAS,OAAA;AACT,qGAAA,UAAU,OAAA;AACV,wGAAA,aAAa,OAAA;AACb,6GAAA,kBAAkB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sse/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.closeAllSseStreams = exports.openSseStreamCount = exports.openSseStream = exports.formatSseFrame = exports.SSE_MAX_STREAM_AGE_MS = exports.SSE_HEARTBEAT_MS = void 0;
|
|
4
|
+
var sseStream_1 = require("./sseStream");
|
|
5
|
+
Object.defineProperty(exports, "SSE_HEARTBEAT_MS", { enumerable: true, get: function () { return sseStream_1.SSE_HEARTBEAT_MS; } });
|
|
6
|
+
Object.defineProperty(exports, "SSE_MAX_STREAM_AGE_MS", { enumerable: true, get: function () { return sseStream_1.SSE_MAX_STREAM_AGE_MS; } });
|
|
7
|
+
Object.defineProperty(exports, "formatSseFrame", { enumerable: true, get: function () { return sseStream_1.formatSseFrame; } });
|
|
8
|
+
Object.defineProperty(exports, "openSseStream", { enumerable: true, get: function () { return sseStream_1.openSseStream; } });
|
|
9
|
+
Object.defineProperty(exports, "openSseStreamCount", { enumerable: true, get: function () { return sseStream_1.openSseStreamCount; } });
|
|
10
|
+
Object.defineProperty(exports, "closeAllSseStreams", { enumerable: true, get: function () { return sseStream_1.closeAllSseStreams; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sse/index.ts"],"names":[],"mappings":";;;AAAA,yCAOqB;AANnB,6GAAA,gBAAgB,OAAA;AAChB,kHAAA,qBAAqB,OAAA;AACrB,2GAAA,cAAc,OAAA;AACd,0GAAA,aAAa,OAAA;AACb,+GAAA,kBAAkB,OAAA;AAClB,+GAAA,kBAAkB,OAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Response } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* The plumbing of a Server-Sent Events response: headers, heartbeat, a bounded
|
|
4
|
+
* lifetime, cleanup when the client goes, and closing everything at shutdown.
|
|
5
|
+
* What goes down the stream, and to whom, stays with the service.
|
|
6
|
+
*
|
|
7
|
+
* Three things here are not optional:
|
|
8
|
+
*
|
|
9
|
+
* - `X-Accel-Buffering: no` plus `flushHeaders()`. Without them nginx holds the
|
|
10
|
+
* response in its buffer and the client sees an open connection that never
|
|
11
|
+
* delivers anything, which looks exactly like a broken server.
|
|
12
|
+
* - The heartbeat. The proxy closes an idle connection at `proxy_read_timeout`,
|
|
13
|
+
* and a client reconnecting every time looks like a reconnect loop.
|
|
14
|
+
* - The lifetime. Access is checked when a stream opens, and a stream carries
|
|
15
|
+
* that answer for as long as it runs. Recycling it bounds how long someone
|
|
16
|
+
* taken out of a group could keep receiving; EventSource reconnects on its
|
|
17
|
+
* own, re-authenticates, and the client sees nothing.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Heartbeat interval. A named event rather than a comment line: comments are
|
|
21
|
+
* invisible to browser JavaScript, and the client's watchdog needs to see it.
|
|
22
|
+
* iOS suspends a backgrounded EventSource without closing it, so a client that
|
|
23
|
+
* waits for an error event waits forever.
|
|
24
|
+
*/
|
|
25
|
+
export declare const SSE_HEARTBEAT_MS = 25000;
|
|
26
|
+
/** How long one stream runs before the server closes it and the client reconnects. */
|
|
27
|
+
export declare const SSE_MAX_STREAM_AGE_MS: number;
|
|
28
|
+
export interface SseStream {
|
|
29
|
+
/** Writes a frame. False once the stream is closed, or if the write failed (which closes it). */
|
|
30
|
+
send(frame: string): boolean;
|
|
31
|
+
/** Ends the response, after one last frame if given. */
|
|
32
|
+
end(lastFrame?: string): void;
|
|
33
|
+
/** Runs once when the stream closes, for whatever reason. At once if it already has. */
|
|
34
|
+
onClose(handler: () => void): void;
|
|
35
|
+
readonly closed: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface OpenSseStreamOptions {
|
|
38
|
+
heartbeatMs?: number;
|
|
39
|
+
maxAgeMs?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Serialises one event in the SSE wire format. */
|
|
42
|
+
export declare function formatSseFrame(event: string, data: unknown, id?: string | number): string;
|
|
43
|
+
/**
|
|
44
|
+
* Turns a response into an event stream. Check access before calling it: once
|
|
45
|
+
* the headers are out, an error can no longer be a status code, only a frame.
|
|
46
|
+
*/
|
|
47
|
+
export declare function openSseStream(res: Response, options?: OpenSseStreamOptions): SseStream;
|
|
48
|
+
/** Open stream count, for `/metrics` and tests. */
|
|
49
|
+
export declare function openSseStreamCount(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Ends every open stream, for shutdown. `server.close()` waits for in-flight
|
|
52
|
+
* responses and an event stream never finishes by itself, so without this a
|
|
53
|
+
* rollout times out and force-exits. The browsers reconnect to the new
|
|
54
|
+
* container on their own. `registerShutdown` calls it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function closeAllSseStreams(): void;
|
|
57
|
+
//# sourceMappingURL=sseStream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sseStream.d.ts","sourceRoot":"","sources":["../../src/sse/sseStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,QAAiB,CAAC;AAIpD,MAAM,WAAW,SAAS;IACxB,iGAAiG;IACjG,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,wDAAwD;IACxD,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wFAAwF;IACxF,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAGzF;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,GAAE,oBAAyB,GAAG,SAAS,CA+E1F;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SSE_MAX_STREAM_AGE_MS = exports.SSE_HEARTBEAT_MS = void 0;
|
|
7
|
+
exports.formatSseFrame = formatSseFrame;
|
|
8
|
+
exports.openSseStream = openSseStream;
|
|
9
|
+
exports.openSseStreamCount = openSseStreamCount;
|
|
10
|
+
exports.closeAllSseStreams = closeAllSseStreams;
|
|
11
|
+
const logger_1 = __importDefault(require("../logging/logger"));
|
|
12
|
+
/**
|
|
13
|
+
* The plumbing of a Server-Sent Events response: headers, heartbeat, a bounded
|
|
14
|
+
* lifetime, cleanup when the client goes, and closing everything at shutdown.
|
|
15
|
+
* What goes down the stream, and to whom, stays with the service.
|
|
16
|
+
*
|
|
17
|
+
* Three things here are not optional:
|
|
18
|
+
*
|
|
19
|
+
* - `X-Accel-Buffering: no` plus `flushHeaders()`. Without them nginx holds the
|
|
20
|
+
* response in its buffer and the client sees an open connection that never
|
|
21
|
+
* delivers anything, which looks exactly like a broken server.
|
|
22
|
+
* - The heartbeat. The proxy closes an idle connection at `proxy_read_timeout`,
|
|
23
|
+
* and a client reconnecting every time looks like a reconnect loop.
|
|
24
|
+
* - The lifetime. Access is checked when a stream opens, and a stream carries
|
|
25
|
+
* that answer for as long as it runs. Recycling it bounds how long someone
|
|
26
|
+
* taken out of a group could keep receiving; EventSource reconnects on its
|
|
27
|
+
* own, re-authenticates, and the client sees nothing.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Heartbeat interval. A named event rather than a comment line: comments are
|
|
31
|
+
* invisible to browser JavaScript, and the client's watchdog needs to see it.
|
|
32
|
+
* iOS suspends a backgrounded EventSource without closing it, so a client that
|
|
33
|
+
* waits for an error event waits forever.
|
|
34
|
+
*/
|
|
35
|
+
exports.SSE_HEARTBEAT_MS = 25_000;
|
|
36
|
+
/** How long one stream runs before the server closes it and the client reconnects. */
|
|
37
|
+
exports.SSE_MAX_STREAM_AGE_MS = 30 * 60 * 1000;
|
|
38
|
+
const HEARTBEAT_FRAME = 'event: heartbeat\ndata: {}\n\n';
|
|
39
|
+
/** Serialises one event in the SSE wire format. */
|
|
40
|
+
function formatSseFrame(event, data, id) {
|
|
41
|
+
const idLine = id === undefined ? '' : `id: ${id}\n`;
|
|
42
|
+
return `${idLine}event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
43
|
+
}
|
|
44
|
+
const open = new Set();
|
|
45
|
+
/**
|
|
46
|
+
* Turns a response into an event stream. Check access before calling it: once
|
|
47
|
+
* the headers are out, an error can no longer be a status code, only a frame.
|
|
48
|
+
*/
|
|
49
|
+
function openSseStream(res, options = {}) {
|
|
50
|
+
const { heartbeatMs = exports.SSE_HEARTBEAT_MS, maxAgeMs = exports.SSE_MAX_STREAM_AGE_MS } = options;
|
|
51
|
+
res.writeHead(200, {
|
|
52
|
+
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
53
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
54
|
+
Connection: 'keep-alive',
|
|
55
|
+
'X-Accel-Buffering': 'no'
|
|
56
|
+
});
|
|
57
|
+
res.flushHeaders?.();
|
|
58
|
+
let closed = false;
|
|
59
|
+
const handlers = [];
|
|
60
|
+
const runHandler = (handler) => {
|
|
61
|
+
try {
|
|
62
|
+
handler();
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// One failing cleanup must not skip the others.
|
|
66
|
+
logger_1.default.warn('SSE close handler failed', { error: error.message });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const close = () => {
|
|
70
|
+
if (closed)
|
|
71
|
+
return;
|
|
72
|
+
closed = true;
|
|
73
|
+
clearInterval(heartbeat);
|
|
74
|
+
clearTimeout(recycle);
|
|
75
|
+
open.delete(stream);
|
|
76
|
+
for (const handler of handlers.splice(0))
|
|
77
|
+
runHandler(handler);
|
|
78
|
+
};
|
|
79
|
+
const send = (frame) => {
|
|
80
|
+
if (closed)
|
|
81
|
+
return false;
|
|
82
|
+
try {
|
|
83
|
+
res.write(frame);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// A half-closed socket throws rather than returning an error.
|
|
88
|
+
logger_1.default.warn('Closing SSE stream after a failed write', { error: error.message });
|
|
89
|
+
close();
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const end = (lastFrame) => {
|
|
94
|
+
if (closed)
|
|
95
|
+
return;
|
|
96
|
+
if (lastFrame)
|
|
97
|
+
send(lastFrame);
|
|
98
|
+
try {
|
|
99
|
+
res.end();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Already gone.
|
|
103
|
+
}
|
|
104
|
+
close();
|
|
105
|
+
};
|
|
106
|
+
const heartbeat = setInterval(() => send(HEARTBEAT_FRAME), heartbeatMs);
|
|
107
|
+
// `retry:` tells the browser how soon to reconnect.
|
|
108
|
+
const recycle = setTimeout(() => end('retry: 1000\n\n'), maxAgeMs);
|
|
109
|
+
const stream = {
|
|
110
|
+
send,
|
|
111
|
+
end,
|
|
112
|
+
onClose(handler) {
|
|
113
|
+
if (closed)
|
|
114
|
+
runHandler(handler);
|
|
115
|
+
else
|
|
116
|
+
handlers.push(handler);
|
|
117
|
+
},
|
|
118
|
+
get closed() {
|
|
119
|
+
return closed;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
open.add(stream);
|
|
123
|
+
// The response, not the request: a GET's request side can report closed as
|
|
124
|
+
// soon as its empty body has been read.
|
|
125
|
+
res.on('close', close);
|
|
126
|
+
res.on('error', close);
|
|
127
|
+
return stream;
|
|
128
|
+
}
|
|
129
|
+
/** Open stream count, for `/metrics` and tests. */
|
|
130
|
+
function openSseStreamCount() {
|
|
131
|
+
return open.size;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Ends every open stream, for shutdown. `server.close()` waits for in-flight
|
|
135
|
+
* responses and an event stream never finishes by itself, so without this a
|
|
136
|
+
* rollout times out and force-exits. The browsers reconnect to the new
|
|
137
|
+
* container on their own. `registerShutdown` calls it.
|
|
138
|
+
*/
|
|
139
|
+
function closeAllSseStreams() {
|
|
140
|
+
for (const stream of [...open])
|
|
141
|
+
stream.end('retry: 2000\n\n');
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=sseStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sseStream.js","sourceRoot":"","sources":["../../src/sse/sseStream.ts"],"names":[],"mappings":";;;;;;AAkDA,wCAGC;AAQD,sCA+EC;AAGD,gDAEC;AAQD,gDAEC;AA1JD,+DAAuC;AAEvC;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;GAKG;AACU,QAAA,gBAAgB,GAAG,MAAM,CAAC;AAEvC,sFAAsF;AACzE,QAAA,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEpD,MAAM,eAAe,GAAG,gCAAgC,CAAC;AAiBzD,mDAAmD;AACnD,SAAgB,cAAc,CAAC,KAAa,EAAE,IAAa,EAAE,EAAoB;IAC/E,MAAM,MAAM,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC;IACrD,OAAO,GAAG,MAAM,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;AACvE,CAAC;AAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAa,CAAC;AAElC;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAa,EAAE,UAAgC,EAAE;IAC7E,MAAM,EAAE,WAAW,GAAG,wBAAgB,EAAE,QAAQ,GAAG,6BAAqB,EAAE,GAAG,OAAO,CAAC;IAErF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,kCAAkC;QAClD,eAAe,EAAE,wBAAwB;QACzC,UAAU,EAAE,YAAY;QACxB,mBAAmB,EAAE,IAAI;KAC1B,CAAC,CAAC;IACH,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;IAErB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,MAAM,QAAQ,GAAsB,EAAE,CAAC;IAEvC,MAAM,UAAU,GAAG,CAAC,OAAmB,EAAQ,EAAE;QAC/C,IAAI,CAAC;YACH,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gDAAgD;YAChD,gBAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpB,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,CAAC,KAAa,EAAW,EAAE;QACtC,IAAI,MAAM;YAAE,OAAO,KAAK,CAAC;QACzB,IAAI,CAAC;YACH,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,8DAA8D;YAC9D,gBAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5F,KAAK,EAAE,CAAC;YACR,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,GAAG,GAAG,CAAC,SAAkB,EAAQ,EAAE;QACvC,IAAI,MAAM;YAAE,OAAO;QACnB,IAAI,SAAS;YAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QACD,KAAK,EAAE,CAAC;IACV,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,CAAC;IACxE,oDAAoD;IACpD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEnE,MAAM,MAAM,GAAc;QACxB,IAAI;QACJ,GAAG;QACH,OAAO,CAAC,OAAO;YACb,IAAI,MAAM;gBAAE,UAAU,CAAC,OAAO,CAAC,CAAC;;gBAC3B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,MAAM;YACR,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEjB,2EAA2E;IAC3E,wCAAwC;IACxC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACvB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAEvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mDAAmD;AACnD,SAAgB,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB;IAChC,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAChE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tumbaland/backend-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"description": "Core shared functionality for Tumbaland backend services",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"release:beta": "commit-and-tag-version --prerelease beta && npm run build && npm publish --access public --tag beta",
|
|
18
18
|
"test": "jest",
|
|
19
19
|
"test:coverage": "jest --coverage",
|
|
20
|
-
"lint": "
|
|
20
|
+
"lint": "vp lint .",
|
|
21
21
|
"typecheck": "tsc --noEmit"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|