@naanlang/naan 1.5.0 → 1.7.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.
Files changed (62) hide show
  1. package/LICENSE.md +2 -2
  2. package/README.md +2 -2
  3. package/bin/index.js +7 -3
  4. package/dist/env_web.js +162 -48
  5. package/dist/naan.min.js +11 -11
  6. package/frameworks/browser/https_request.nlg +2 -2
  7. package/frameworks/browser/sworker.js +28 -26
  8. package/frameworks/browser/terminals.nlg +295 -737
  9. package/frameworks/browser/worker.nlg +295 -0
  10. package/frameworks/browser/workers.nlg +6 -6
  11. package/frameworks/browser/ws_client.nlg +15 -10
  12. package/frameworks/client/apiclient.nlg +211 -9
  13. package/frameworks/client/psm_client.nlg +10 -14
  14. package/frameworks/client/relaycon.nlg +87 -161
  15. package/frameworks/common/common.nlg +2 -0
  16. package/frameworks/common/events.nlg +101 -0
  17. package/frameworks/common/repltools.nlg +80 -1
  18. package/frameworks/node/apiserver.nlg +38 -246
  19. package/frameworks/node/filesystem.nlg +31 -6
  20. package/frameworks/node/http_request.nlg +34 -13
  21. package/frameworks/node/https_request.nlg +8 -3
  22. package/frameworks/node/node.nlg +3 -0
  23. package/frameworks/node/pty.nlg +346 -0
  24. package/frameworks/node/shell.nlg +26 -3
  25. package/frameworks/node/worker.nlg +504 -560
  26. package/frameworks/node/ws_client.nlg +2 -2
  27. package/frameworks/project/build.nlg +56 -14
  28. package/frameworks/project/projects.nlg +1 -1
  29. package/frameworks/running/debugcom.nlg +20 -3
  30. package/frameworks/running/debugnub.nlg +33 -11
  31. package/frameworks/running/executors.nlg +40 -285
  32. package/frameworks/running/instances.nlg +394 -0
  33. package/frameworks/running/remote_req.nlg +139 -0
  34. package/frameworks/running/remote_res.nlg +89 -0
  35. package/frameworks/running/sourcecode.nlg +3 -2
  36. package/frameworks/running/taskexec.nlg +16 -59
  37. package/frameworks/service/imp.nlg +751 -0
  38. package/frameworks/service/model.nlg +71 -0
  39. package/frameworks/service/nubnode.nlg +136 -0
  40. package/frameworks/service/nubweb.nlg +124 -0
  41. package/frameworks/service/service.nlg +28 -0
  42. package/frameworks/storage/file_manager.nlg +3 -2
  43. package/lib/browser/env_web.js +169 -55
  44. package/lib/browser/env_webworker.js +89 -31
  45. package/lib/core/naanlib.js +11 -11
  46. package/lib/env_node.js +186 -27
  47. package/lib/env_nodeworker.js +82 -44
  48. package/lib/node_server_init.nlg +149 -0
  49. package/lib/node_worker.js +36 -0
  50. package/lib/node_worker_init.nlg +43 -0
  51. package/package.json +1 -1
  52. package/plugins/openSearch/openSearch.nlg +3 -2
  53. package/plugins/openSearch/os_dynamo.nlg +3 -2
  54. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +44 -2
  55. package/plugins/serviceAws/aws_dynamo.nlg +144 -63
  56. package/plugins/serviceAws/aws_utils.nlg +6 -11
  57. package/plugins/serviceAws/serviceAws.nlg +3 -2
  58. package/plugins/serviceNexara/speechrec.nlg +10 -6
  59. package/test/test_01_core.nlg +2 -2
  60. package/test/test_02_context.nlg +32 -9
  61. package/test/test_03_jsinterop.nlg +3 -3
  62. package/test/test_07_lingo.nlg +1 -1
@@ -6,11 +6,16 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2024 by Richard C. Zulch
9
+ * Copyright (c) 2017-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
13
13
 
14
+ // Globals
15
+
16
+ serviceMod;;
17
+
18
+
14
19
  /*
15
20
  * APIServer
16
21
  *
@@ -25,18 +30,21 @@
25
30
  * basePort: <number> // starting point for search
26
31
  * gateway: <string> // websocket gateway URL
27
32
  * statics: [<string>, ...] // search paths for static content
33
+ * debug: <boolean> // verbose logging
28
34
  * }
29
35
  *
30
36
  */
31
37
 
32
38
  closure APIServer(options, local server, chroot) {
33
- global(App, JSpath, js, bodyParser, express, psmServerMod, workerMod)
39
+ global(App, serviceMod, JSpath, js, bodyParser, express, psmServerMod, workerMod)
34
40
  apisLoadLibs()
35
41
  server = new(object, this)
42
+ server.imp = App.imp
36
43
  server.app = express()
37
44
  server.guid = options.guid
38
45
  server.notifyq = []
39
46
  server.responseq = []
47
+ server.instanceID = UUID()
40
48
  options = merge({
41
49
  relpath: ""
42
50
  name: "NaanServer"
@@ -94,6 +102,7 @@ closure APIServer(options, local server, chroot) {
94
102
  return (result)
95
103
  }
96
104
  updatePort(port)
105
+
97
106
  if server.guid
98
107
  server.oururl = server.oururl.concat("?guid=", server.guid)
99
108
  App.api = server // used remotely by client/relaycon.nlg
@@ -107,6 +116,7 @@ closure APIServer(options, local server, chroot) {
107
116
  }
108
117
  } else // default is native websocket protocols
109
118
  server.ws = WebSocketServer(server)
119
+
110
120
  WesRelay(server) // registers as subsystem
111
121
  server.psm = psmServerMod.MakeServerPSM(server, options.name)
112
122
  `(error, hostfs) = server.psm.conns.NodeFS.connect("Host", "NideFS", list(""))
@@ -116,7 +126,8 @@ closure APIServer(options, local server, chroot) {
116
126
  return (list(error))
117
127
  }
118
128
  server.hostfs = hostfs
119
- server.workco = workerMod.WorkerController(server)
129
+ server.Register(server.workco.serverID, server.workco)
130
+
120
131
  list(false, port)
121
132
  }
122
133
 
@@ -431,15 +442,8 @@ closure WebSocketConn(wsgate, connID, local wsconn) {
431
442
  wsconn.msgin = closure msgin(message, local error) {
432
443
  if wsgate.guid && message.guid != wsgate.guid
433
444
  error = Error("unauthorized")
434
- else if message.init {
435
- if message.init.destID {
436
- wsconn.relay = true
437
- wsgate.subsystems.Relay.wsChangeDestID(conn, wsconn.info.destID, message.init.destID)
438
- }
445
+ else if message.init
439
446
  wsconn.info = merge(wsconn.info, message.init)
440
- }
441
- else if message.respOp && wsgate.subsystems.Relay
442
- wsgate.subsystems.Relay.wsReceive(message, wsconn) // with respOp, must be a relay
443
447
  else if message.clientID && wsgate.subsystems[message.serverID]
444
448
  wsgate.subsystems[message.serverID].wsReceive(message, wsconn)
445
449
  else
@@ -510,11 +514,11 @@ closure WebSocketServer(server, local websocks) {
510
514
  websocks.subsystems[serverID].wsOpen(conn) // notify of our openings
511
515
  })
512
516
 
513
- server.wss.on("error", function(error) {
517
+ websocks.wss.on("error", function(error) {
514
518
  ErrorDebuglog(Error("WebSocketServer: connection error", error))
515
519
  })
516
520
 
517
- server.wss.on("close", function() {
521
+ websocks.wss.on("close", function() {
518
522
  debuglog("WebSocketServer has closed")
519
523
  websocks.closed = true // note that we are closed
520
524
  })
@@ -557,37 +561,31 @@ closure WesCon(server, websocks, socket, request, local wescon) {
557
561
  destID: UUID()
558
562
  address: new(socket._socket.address())
559
563
  }
564
+
565
+ wescon.impconn = server.imp.responder(function(data) {
566
+ if wescon.closed
567
+ return
568
+ socket.send(JSONstringify(data)),
569
+ list(false, { sent: true })
570
+ }, {
571
+ secret: server.guid
572
+ label: "api-client"
573
+ })
560
574
 
561
575
  // on message
562
576
  //
563
577
  // Incoming data.
564
578
  //
565
- socket.on("message", closure onmessage(text, local message, error) {
566
- try {
567
- message = new(js.g.JSON.parse(text))
568
- if server.guid && message.guid != server.guid
569
- error = Error("unauthorized")
570
- else if message.init {
571
- if message.init.destID {
572
- wescon.relay = true
573
- websocks.subsystems.Relay.wsChangeDestID(wescon, wescon.info.destID, message.init.destID)
574
- }
575
- wescon.info = merge(wescon.info, message.init)
576
- }
577
- else if message.respOp && websocks.subsystems.Relay
578
- websocks.subsystems.Relay.wsReceive(message, wescon) // with respOp, must be a relay
579
- else if message.clientID && websocks.subsystems[message.serverID]
580
- websocks.subsystems[message.serverID].wsReceive(message, wescon)
581
- else
582
- error = Error("can't route message")
583
- } catch {
584
- if true
585
- error = Error("can't decode message JSON", exception)
579
+ socket.on("message", closure(text, local error, message) {
580
+ `(error, message) = JsonParse(text)
581
+ if !error {
582
+ message = new(message)
583
+ if wescon.impconn.dispatch(message)
584
+ return
586
585
  }
587
- if error
588
- socket.send(JSONstringify([error]))
586
+ debuglog("socket message:", text)
589
587
  })
590
-
588
+
591
589
  // on error
592
590
  //
593
591
  // Error has occurred on this connection.
@@ -607,222 +605,15 @@ closure WesCon(server, websocks, socket, request, local wescon) {
607
605
  code: code
608
606
  reason: reason
609
607
  }
608
+ wescon.impconn.destroy()
610
609
  websocks.closeConn(wescon)
611
610
  })
612
-
613
- // send
614
- //
615
- // Send a dictionary, which must have a clientID defined.
616
- //
617
- wescon.send = function send(message) {
618
- if !message.clientID || !message.serverID
619
- throw("Wescon.send: client and server IDs required")
620
- if wescon.closed
621
- list(Error("Socket connection closed", wescon.closed))
622
- socket.send(JSONstringify(message)),
623
- [false, {ok: true}]
624
- }
625
611
 
626
612
  // finis
627
613
  wescon
628
614
  };
629
615
 
630
616
 
631
- /*
632
- * WesRelay
633
- *
634
- * Web socket relay controller. This allows apiserver clients to discover each other and connect
635
- * for remote evaluation, etc. A source connection makes a request of a destination connection, and
636
- * the response is routed back to the original connection.
637
- *
638
- * This uses the following message fields for the requesting source:
639
- * guid: security token
640
- * clientID: defined by the source, this string defines where replies should be sent
641
- * serverID: "Relay"
642
- * destID: the destination connection
643
- * endServerID: the serverID to use at the destination
644
- * The message is modified with a virtual clientID to send to the destination, and then changed back
645
- * for return to the requester.
646
- *
647
- * To discover the available destination connections a source should use:
648
- * clientID: requester
649
- * serverID: "Relay"
650
- * relayOp: "getdests"
651
- * which returns:
652
- * relayOp: "destlist"
653
- * destinations: [
654
- * destID: guid for the connection
655
- * address: socket port / family / ip address
656
- * name: <string>
657
- * workerID: id of destination worker
658
- * ]
659
- * New and closed destinations are sent asynchronously to each source:
660
- * relayOp: "opened" / "closed"
661
- * info: {
662
- * destID: guid for the connection
663
- * address: socket port / family / ip address
664
- * name: <string>
665
- * workerID: id of destination worker
666
- * }
667
- *
668
- */
669
-
670
- closure WesRelay(server, local welay) {
671
- global()
672
- welay = new(object, this)
673
- welay.serverID = "Relay" // our serverID as a subsystem
674
- welay.destIDs = { } // destination conns index
675
- welay.virtualIDs = { } // virtual clientID index
676
- welay.links = new(weakmap) // source and dest connections
677
- server.Register(welay.serverID, welay)
678
-
679
- // getVirtualID
680
- // Return the virtual clientID for a requesting source/clientID and destination.
681
- function getVirtualID(sconn, clientID, dconn, local sdict, ddict, vid) {
682
- sdict = welay.links[sconn]
683
- if !sdict
684
- welay.links[sconn] = sdict = {
685
- virtualIDs: { }
686
- }
687
- ddict = welay.links[dconn]
688
- if !ddict
689
- welay.links[dconn] = ddict = {
690
- virtualIDs: { }
691
- }
692
- vid = ddict.virtualIDs[clientID]
693
- if !vid {
694
- sdict.virtualIDs[clientID] = vid = UUID()
695
- welay.virtualIDs[vid] = {
696
- sconn: sconn
697
- dconn: dconn
698
- clientID: clientID
699
- }
700
- }
701
- vid
702
- }
703
-
704
- // addConnection
705
- // Record a new connection as a possible destination.
706
- function addConnection(conn) {
707
- welay.destIDs[conn.info.destID] = conn
708
- }
709
-
710
- // removeConnection
711
- // Cleanup for a closed connection, be it source or destination or both.
712
- function removeConnection(conn, local vid, cdict, did, dconn) {
713
- welay.links[conn] = undefined
714
- for `(vid, cdict) in welay.virtualIDs
715
- if cdict.sconn === conn || cdict.dconn === conn
716
- welay.virtualIDs[vid] = undefined
717
- for `(did, dconn) in welay.destIDs
718
- if dconn === conn
719
- welay.destIDs[did] = undefined
720
- }
721
-
722
- // destList
723
- // Make an array of destination connections, excluding the specified one.
724
- //
725
- welay.destList = function destList(conn, local output, did, dconn) {
726
- output = []
727
- for `(did, dconn) in welay.destIDs
728
- if dconn !== conn && dconn.relay
729
- output.push(dconn.info)
730
- output
731
- }
732
-
733
- // wsReceive
734
- //
735
- // Process a message from the websocket API.
736
- //
737
- welay.wsReceive = function wsReceive(message, sconn, local dconn, error, cdict) {
738
- if message.relayOp == "getdests" { // get destination list
739
- message.relayOp = "destlist"
740
- message.destinations = destList(sconn)
741
- sconn.send(message)
742
- return
743
- }
744
- else if message.destID && message.endServerID { // request from a source
745
- dconn = welay.destIDs[message.destID]
746
- if !dconn
747
- error = Error("destID or endServerID invalid", message.relayOp)
748
- else {
749
- message.serverID = message.endServerID
750
- message.clientID = getVirtualID(sconn, message.clientID, dconn)
751
- message.endServerID = undefined
752
- message.destID = undefined
753
- dconn.send(message)
754
- return
755
- }
756
- }
757
- else { // response from a destination
758
- cdict = welay.virtualIDs[message.clientID]
759
- dconn = cdict.sconn // this is original source
760
- if !cdict || !dconn
761
- error = Error("cannot route reply", message.relayOp)
762
- else {
763
- message.endServerID = message.serverID
764
- message.serverID = welay.serverID
765
- message.clientID = cdict.clientID
766
- message.destID = dconn.info.destID
767
- dconn.send(message)
768
- return
769
- }
770
- }
771
- sconn.send({
772
- serverID: message.serverID
773
- clientID: message.clientID
774
- respOp: "error"
775
- payload: [error]
776
- })
777
- }
778
-
779
- // wsOpen
780
- //
781
- // Note that a new connection was opened.
782
- //
783
- welay.wsOpen = function wsOpen(conn) {
784
- addConnection(conn)
785
- }
786
-
787
- // wsClose
788
- //
789
- // Note that an existing connection was closed.
790
- //
791
- welay.wsClose = function wsClose(conn, local destID, sconn) {
792
- removeConnection(conn)
793
- if conn.relay
794
- for `(destID, sconn) in welay.destIDs
795
- sconn.send({
796
- serverID: welay.serverID
797
- clientID: "*"
798
- relayOp: "closed"
799
- info: conn.info
800
- })
801
- }
802
-
803
- // wsChangeDestID
804
- //
805
- // The destID has changed (via the client init message.)
806
- //
807
- welay.wsChangeDestID = function wsChangeDestID(conn, prevID, newID, local destID, sconn) {
808
- welay.destIDs[prevID] = undefined
809
- welay.destIDs[newID] = conn
810
- conn.info.destID = newID
811
- for `(destID, sconn) in welay.destIDs
812
- if destID != newID
813
- sconn.send({
814
- serverID: welay.serverID
815
- clientID: "*"
816
- relayOp: "opened"
817
- info: conn.info
818
- })
819
- }
820
-
821
- // finis
822
- welay
823
- };
824
-
825
-
826
617
  /*
827
618
  * ApisInit
828
619
  *
@@ -840,7 +631,7 @@ function apisLoadLibs() {
840
631
  };
841
632
 
842
633
  function ApisInit(local manifest) {
843
- manifest = `(APIServer, WebSocketGatewayServer, WebSocketConn, WebSocketServer, WesCon, WesRelay,
634
+ manifest = `(APIServer, WebSocketGatewayServer, WebSocketConn, WebSocketServer, WesCon,
844
635
  apisLoadLibs, ApisInit)
845
636
 
846
637
  Naan.module.build(module.id, "apiserver", function(modobj, compobj) {
@@ -851,4 +642,5 @@ function ApisInit(local manifest) {
851
642
  require("./filesystem.nlg")
852
643
  psmServerMod = require("./psm_server.nlg")
853
644
  workerMod = require("./worker.nlg")
645
+ serviceMod = require("naanlib:frameworks/service/imp.nlg")
854
646
  }();
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2025 by Richard C. Zulch
9
+ * Copyright (c) 2017-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -977,16 +977,41 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
977
977
  //
978
978
  // shellOpen
979
979
  //
980
- // Execute the MacOS open utility, returning a standard tuple: `(error, result)
980
+ // Execute the platform's open utility, returning a standard tuple: `(error, result) which opens
981
+ // the specified path as a browser URL or invokes a shell script. This is used by the NaaN build
982
+ // system's "run" function.
983
+ // The args option has a dictionary that can override the "runner" utility and set arguments
984
+ // for specific platform(s):
985
+ // {
986
+ // darwin: {
987
+ // runner: "open" // default for platforms not mentioned
988
+ // // args: ["--args", <prog arg>] // program arguments if desired
989
+ // }
990
+ // linux / android: {
991
+ // runner: "bash" // for <path>.sh or <path>.tool
992
+ // runner: "xdg-open" // all other types
993
+ // }
994
+ // }
981
995
  //
982
- files.shellOpen = closure shellOpen(path, args, callback) {
996
+ files.shellOpen = closure shellOpen(path, args, callback, local platform, runner) {
983
997
  if !callback
984
998
  return (syncAdapter(shellOpen, path, args))
985
- if args
986
- args = [path].concat("--args", args) // only add target args if specified
999
+ platform = js.g.process.platform
1000
+ runner = args[platform].runner
1001
+ if runner
1002
+ { } // explicit runner
1003
+ else if platform == "linux" || platform == "android" {
1004
+ if RegExp("[.]((sh)|(tool))$").test(path)
1005
+ runner = "bash" // execute scripts
1006
+ else
1007
+ runner = "xdg-open" // "open" other things
1008
+ } else
1009
+ runner = "open" // default runner
1010
+ if args[platform]
1011
+ args = [path].concat(args[platform]) // has custom args
987
1012
  else
988
1013
  args = [path]
989
- nodecp.execFile("open",
1014
+ nodecp.execFile(runner,
990
1015
  args, // command line args to open
991
1016
  { }, // execution options
992
1017
  function(err, stdout, stderr) {
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * column positioning: // // !
7
7
  *
8
- * Copyright (c) 2024-2025 by Richard C. Zulch
8
+ * Copyright (c) 2024-2026 by Richard C. Zulch
9
9
  *
10
10
  */
11
11
 
@@ -19,8 +19,9 @@
19
19
  * {
20
20
  * method: <string> // HTTP method (defaults to GET)
21
21
  * headers: <dictionary> // key/data pairs
22
- * putdata: <data> // data to put
22
+ * putdata: <data> // data to put, either string or JSON
23
23
  * json: <boolean> // ignore content-type of return and decode JSON
24
+ * debug: <boolean> // log errors and status results
24
25
  * }
25
26
  *
26
27
  * The return is a result tuple comprising:
@@ -34,13 +35,31 @@
34
35
  */
35
36
 
36
37
  closure HttpRequest(url, options,
37
- local pending, chunks, params, request) {
38
+ local host, pending, chunks, params, request, headers, putdata) {
38
39
  global(js, nodeHttp)
40
+ try {
41
+ host = xnew(js.g.URL, url).host
42
+ if host.length < 3
43
+ return (Error("httpRequest: host empty"))
44
+ } catch {
45
+ return (Error("httpRequest:", exception))
46
+ }
39
47
  pending = new(nonce)
40
48
  chunks = []
49
+ headers = new(options.headers || []) // modifiable copy or false
50
+ headers.push(list("Host", host))
51
+ putdata = options.putdata
52
+ if putdata {
53
+ if !string(putdata) {
54
+ putdata = JSONstringify(putdata)
55
+ headers.push(list('Content-Type', 'application/json'))
56
+ }
57
+ // set explicit content-length to avoid default chunked encoding
58
+ headers.push(list('Content-Length', putdata.length))
59
+ }
41
60
  params = {
42
61
  method: options.method || undefined
43
- headers: options.headers || undefined
62
+ headers: headers || undefined
44
63
  }
45
64
  request = nodeHttp.request(url, params, closure (response) {
46
65
  response.on("data", function (chunk) {
@@ -49,7 +68,12 @@ closure HttpRequest(url, options,
49
68
  response.on("end", function (local content, error) {
50
69
  content = js.g.Buffer.concat(chunks)
51
70
  if response.statusCode < 200 || response.statusCode >= 299 { // 299 is "cancelled"
52
- debuglog("httpRequest status:", url, response.statusCode, "message:", content)
71
+ if options.debug {
72
+ debuglog("httpRequest status:", url, response.statusCode, "message:", response.statusMessage)
73
+ if string(putdata)
74
+ putdata = putdata.substr(0,250)
75
+ debuglog("httpRequest putdata:", putdata)
76
+ }
53
77
  pending.signal(list(Error("httpRequest statusCode:", url, response.statusCode, {
54
78
  status: response.statusCode
55
79
  }), false, { status: response.statusCode }))
@@ -63,23 +87,20 @@ closure HttpRequest(url, options,
63
87
  else
64
88
  error = Error("httpRequest terminated prematurely:", url, response.statusCode)
65
89
  pending.signal(list(error, content, {
66
- headers: response.headers
90
+ headers: new(response.headers)
67
91
  status: response.statusCode
68
92
  contentType: response.headers["content-type"]
69
93
  }))
70
94
  })
71
95
  })
72
96
  request.on("error", function hre(error) {
73
- debuglog("httpRequest error:", url, "error:", error)
97
+ if options.debug
98
+ debuglog("httpRequest error:", url, "error:", error)
74
99
  error = Error("httpRequest failed:", url, error)
75
100
  pending.signal(list(error))
76
101
  })
77
- if options.putdata {
78
- if string(options.putdata)
79
- request.write(options.putdata)
80
- else
81
- request.write(JSONstringify(options.putdata))
82
- }
102
+ if putdata
103
+ request.write(putdata)
83
104
  request.end()
84
105
  pending.wait()
85
106
  };
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * column positioning: // // !
7
7
  *
8
- * Copyright (c) 2021-2024 by Richard C. Zulch
8
+ * Copyright (c) 2021-2026 by Richard C. Zulch
9
9
  *
10
10
  */
11
11
 
@@ -123,12 +123,17 @@ closure httpsApiReqOnce(url, options,
123
123
  else
124
124
  content = js.g.Buffer.concat(chunks)
125
125
  if response.statusCode < 200 || response.statusCode >= 299 { // 299 is "cancelled"
126
- if options.debug
126
+ if options.debug {
127
+ content = content.toString()
127
128
  debuglog("HttpsApiRequest status:", url, response.statusCode, "message:", content)
129
+ if string(putdata)
130
+ putdata = putdata.substr(0,250)
131
+ debuglog("HttpsApiRequest putdata:", putdata)
132
+ }
128
133
  pending.signal(list(Error("HttpsApiRequest statusCode:", url, response.statusCode, {
129
134
  status: response.statusCode
130
135
  }), false, {
131
- headers: response.headers
136
+ headers: new(response.headers)
132
137
  status: response.statusCode
133
138
  }))
134
139
  return
@@ -124,6 +124,8 @@ function nodrInit(local manifest) {
124
124
  throw("module frameworks/node cannot be used from a browser")
125
125
  Naan.module.build(module.id, "node", function(modobj, compobj) {
126
126
  require("../common/").LiveImport()
127
+ require("../common/events.nlg")
128
+ commonWatching = require("../common/watching.nlg")
127
129
  compobj.manifest = manifest
128
130
  function nodrReload() {
129
131
  nodecp = js.r("child_process")
@@ -139,5 +141,6 @@ function nodrInit(local manifest) {
139
141
  module.reload = nodrReload
140
142
  module.exports.NaanlangDir = NaanlangDir
141
143
  module.exports.NaanlangRC = NaanlangRC
144
+ module.exports.NodeStreamLiner = NodeStreamLiner
142
145
  })
143
146
  } ();