1+ import { Buffer } from 'node:buffer' ;
12import { Socket } from 'node:net' ;
23import process from 'node:process' ;
34
4- import { JsonRpcError , type SuccessObject } from 'jsonrpc-lite' ;
5-
6- import * as Messenger from './lib/messenger' ;
5+ // Deno consumes the base as TypeScript source through the import map: ESM
6+ // imports honor the map (`@rocket.chat/apps/` → `../`), so bare specifiers and
7+ // `@rocket.chat/apps/*` resolve to allowed paths. Importing the compiled `dist`
8+ // instead would run the base as CommonJS, whose `require()` bypasses the import
9+ // map and falls back to node_modules — outside the subprocess read allowlist.
710import { stdoutTransport } from './lib/transports/stdoutTransport' ;
8- import { decoder } from './lib/codec' ;
9- import { Logger } from './lib/logger' ;
10- import slashcommandHandler from './handlers/slashcommand-handler' ;
11- import videoConferenceHandler from './handlers/videoconference-handler' ;
12- import apiHandler from './handlers/api-handler' ;
11+ import { setTransport } from './lib/messenger' ;
12+
1313import { setSandboxGlobals , setSandboxRequire } from './handlers/app/construct' ;
14- import handleApp from './handlers/app/handler' ;
15- import handleScheduler from './handlers/scheduler-handler' ;
1614import registerErrorListeners from './error-handlers' ;
17- import { sendMetrics } from './lib/metricsCollector' ;
18- import outboundMessageHandler from './handlers/outboundcomms-handler' ;
19- import { RequestContext } from './lib/requestContext' ;
15+ import { require } from './lib/require' ;
16+ import { startMainLoop } from './mainLoop' ;
2017
2118if ( ! process . argv . includes ( '--subprocess' ) ) {
2219 process . stderr . write ( `
@@ -26,108 +23,6 @@ if (!process.argv.includes('--subprocess')) {
2623 process . exit ( 1001 ) ;
2724}
2825
29- type Handlers = {
30- app : typeof handleApp ;
31- api : typeof apiHandler ;
32- slashcommand : typeof slashcommandHandler ;
33- videoconference : typeof videoConferenceHandler ;
34- outboundCommunication : typeof outboundMessageHandler ;
35- scheduler : typeof handleScheduler ;
36- ping : ( request : RequestContext ) => 'pong' ;
37- } ;
38-
39- const COMMAND_PING = '_zPING' ;
40-
41- async function requestRouter ( { type, payload } : Messenger . JsonRpcRequest ) : Promise < void > {
42- const methodHandlers : Handlers = {
43- app : handleApp ,
44- api : apiHandler ,
45- slashcommand : slashcommandHandler ,
46- videoconference : videoConferenceHandler ,
47- outboundCommunication : outboundMessageHandler ,
48- scheduler : handleScheduler ,
49- ping : ( _request ) => 'pong' ,
50- } ;
51-
52- // We're not handling notifications at the moment
53- if ( type === 'notification' ) {
54- return Messenger . sendInvalidRequestError ( ) ;
55- }
56-
57- const { id, method } = payload ;
58-
59- const logger = new Logger ( method ) ;
60-
61- const context : RequestContext = Object . assign ( payload , {
62- context : { logger } ,
63- } ) ;
64-
65- const [ methodPrefix ] = method . split ( ':' ) as [ keyof Handlers ] ;
66- const handler = methodHandlers [ methodPrefix ] ;
67-
68- if ( ! handler ) {
69- return Messenger . errorResponse (
70- {
71- error : { message : 'Method not found' , code : - 32601 } ,
72- id,
73- } ,
74- context ,
75- ) ;
76- }
77-
78- const result = await handler ( context ) ;
79-
80- if ( result instanceof JsonRpcError ) {
81- return Messenger . errorResponse ( { id, error : result } , context ) ;
82- }
83-
84- return Messenger . successResponse ( { id, result } , context ) ;
85- }
86-
87- function handleResponse ( response : Messenger . JsonRpcResponse ) : void {
88- let payload : { error : Error } | { detail : SuccessObject } ;
89-
90- if ( Messenger . isErrorResponse ( response . payload ) ) {
91- payload = { error : new Error ( response . payload . error . message ) } ;
92- } else {
93- payload = { detail : response . payload } ;
94- }
95-
96- Messenger . RPCResponseObserver . emit ( `response:${ response . payload . id } ` , payload ) ;
97- }
98-
99- async function main ( ) {
100- Messenger . sendNotification ( { method : 'ready' } ) ;
101-
102- for await ( const message of decoder . decodeStream ( process . stdin ) ) {
103- try {
104- // Process PING command first as it is not JSON RPC
105- if ( message === COMMAND_PING ) {
106- void Messenger . pongResponse ( ) ;
107- void sendMetrics ( ) ;
108- continue ;
109- }
110-
111- const JSONRPCMessage = Messenger . parseMessage ( message as Record < string , unknown > ) ;
112-
113- if ( Messenger . isRequest ( JSONRPCMessage ) ) {
114- void requestRouter ( JSONRPCMessage ) ;
115- continue ;
116- }
117-
118- if ( Messenger . isResponse ( JSONRPCMessage ) ) {
119- handleResponse ( JSONRPCMessage ) ;
120- }
121- } catch ( error ) {
122- if ( Messenger . isErrorResponse ( error ) ) {
123- await Messenger . errorResponse ( error ) ;
124- } else {
125- await Messenger . sendParseError ( ) ;
126- }
127- }
128- }
129- }
130-
13126function prepareEnvironment ( ) {
13227 // Deno does not behave equally to Node when it comes to piping content to a socket
13328 // So we intervene here
@@ -142,7 +37,7 @@ function prepareEnvironment() {
14237}
14338
14439// This runtime communicates with the Apps-Engine host through stdout
145- Messenger . setTransport ( stdoutTransport ) ;
40+ setTransport ( stdoutTransport ) ;
14641
14742// Deno's sandbox `require` is a createRequire shim that resolves compiled
14843// apps-engine paths; the eval shell additionally needs a `Buffer` and a
@@ -155,4 +50,4 @@ registerErrorListeners();
15550// Process-global side effect; doing it once at startup is cleaner than inside construct
15651prepareEnvironment ( ) ;
15752
158- main ( ) ;
53+ startMainLoop ( ) ;
0 commit comments