@naanlang/naan 1.1.0 → 1.2.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.
@@ -90,7 +90,7 @@ closure HttpsApiRequest(url, options,
90
90
  debuglog("HttpsApiRequest error:", url, "error:", error)
91
91
  return (list(Error("HttpsApiRequest fetch failed:", error, url)))
92
92
  }
93
- if response.status < 200 || response.status >= 300 {
93
+ if response.status < 200 || response.status >= 299 { // 299 is "cancelled"
94
94
  if options.debug
95
95
  debuglog("HttpsApiRequest status:", url, response.statusCode)
96
96
  error = Error("HttpsApiRequest status:", url, response.status, {
@@ -104,7 +104,8 @@ closure HttpsApiRequest(url, options,
104
104
  break
105
105
  }
106
106
  contentType = response.headers.get("content-type")
107
- if contentType.startsWith("application/json") {
107
+ if contentType.startsWith("application/json")
108
+ || contentType.startsWith("application/octet-stream") && options.encoding == "json" {
108
109
  `(error, content) = await(response.text())
109
110
  if !error
110
111
  `(error, content) = JsonParse(content)
@@ -129,6 +130,7 @@ closure HttpsApiRequest(url, options,
129
130
  list(error, content, {
130
131
  headers: headers
131
132
  status: response.status
133
+ contentType: contentType
132
134
  })
133
135
  };
134
136
 
@@ -36,7 +36,7 @@
36
36
  *
37
37
  */
38
38
 
39
- var CurrentCacheName = "Naanlang-1.1.0+1";
39
+ var CurrentCacheName = "Naanlang-1.2.0+1";
40
40
 
41
41
 
42
42
  //
@@ -92,18 +92,18 @@ var terminated; // flag that this service worker
92
92
  var pubVersion = event.data.hereIsMyVersion;
93
93
  var sourceId = event.source.id; // client id of sender of message
94
94
  msgPorts[sourceId] = msgport;
95
- console.log("[1.1.0+1] received new msgport for", sourceId, pubID, "-", pubVersion);
96
- if (pubVersion != "1.1.0+1") {
95
+ console.log("[1.2.0+1] received new msgport for", sourceId, pubID, "-", pubVersion);
96
+ if (pubVersion != "1.2.0+1") {
97
97
  if (upgradeMsgPorts) { // if not activated
98
- console.log("[1.1.0+1] update pending for", sourceId);
98
+ console.log("[1.2.0+1] update pending for", sourceId);
99
99
  upgradeMsgPorts[sourceId] = msgport;
100
100
  }
101
101
  else {
102
102
  msgport.postMessage({ // notify new version available
103
103
  id: "upgrade",
104
- version: "1.1.0+1"
104
+ version: "1.2.0+1"
105
105
  });
106
- console.log("[1.1.0+1] update sent for:", sourceId);
106
+ console.log("[1.2.0+1] update sent for:", sourceId);
107
107
  }
108
108
  }
109
109
  Reaper(); // clean up obsolete info
@@ -134,10 +134,10 @@ var terminated; // flag that this service worker
134
134
  msgport.onmessage = function(msg) {
135
135
  msg = msg.data;
136
136
  if (msg.id == "skipWaiting") { // try to activate this SW now
137
- console.log("[1.1.0+1] attempting skipWaiting");
137
+ console.log("[1.2.0+1] attempting skipWaiting");
138
138
  self.skipWaiting();
139
139
  } else if (msg.id == "terminate") { // termiante this SW now
140
- console.log("[1.1.0+1] terminated");
140
+ console.log("[1.2.0+1] terminated");
141
141
  terminate();
142
142
  } else if (msg.id == "abortURL") { // abort an I/O transaction
143
143
  var href = new URL(msg.url).href;
@@ -150,7 +150,7 @@ var terminated; // flag that this service worker
150
150
  } else if (msg.id == "response") // response from fetch request
151
151
  processResponse(msg);
152
152
  else if (msg.id == "text") // just log some text
153
- console.log("[1.1.0+1] msg received:", msg.text);
153
+ console.log("[1.2.0+1] msg received:", msg.text);
154
154
  };
155
155
 
156
156
  // send text to IDE log
@@ -161,7 +161,7 @@ var terminated; // flag that this service worker
161
161
  // don't clutter the log
162
162
  msgport.postMessage({
163
163
  id: "text",
164
- text: "port received by 1.1.0+1",
164
+ text: "port received by 1.2.0+1",
165
165
  });
166
166
  */
167
167
  if (--pending === 0)
@@ -178,7 +178,7 @@ var terminated; // flag that this service worker
178
178
  includeUncontrolled: true
179
179
  }).then(function(clientList) {
180
180
  clientList.every(function(client) {
181
- console.log("[1.1.0+1] requesting new msgport for", client.id);
181
+ console.log("[1.2.0+1] requesting new msgport for", client.id);
182
182
  ++pending;
183
183
  client.postMessage({ // tell client(s) we need this fetch source
184
184
  msg: "Naan_need_fetch_port",
@@ -224,12 +224,12 @@ function Reaper() {
224
224
  clients[clientList[clidex].id] = clientList[clidex];
225
225
  for (var sourceId in msgPorts)
226
226
  if (!clients[sourceId]) {
227
- console.log("[1.1.0+1] source gone:", sourceId);
227
+ console.log("[1.2.0+1] source gone:", sourceId);
228
228
  delete msgPorts[sourceId]; // no longer a source
229
229
  }
230
230
  for (var clientId in fetchPorts)
231
231
  if (!clients[clientId]) {
232
- console.log("[1.1.0+1] client gone:", clientId);
232
+ console.log("[1.2.0+1] client gone:", clientId);
233
233
  delete fetchPorts[clientId]; // no longer a client
234
234
  }
235
235
  for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
@@ -263,16 +263,16 @@ function ClearCaches() {
263
263
  return (Promise.all(
264
264
  cacheNames.map(function(cacheName) {
265
265
  if (cacheName != CurrentCacheName) {
266
- console.log('[1.1.0+1] deleting old cache:', cacheName);
266
+ console.log('[1.2.0+1] deleting old cache:', cacheName);
267
267
  return (caches.delete(cacheName));
268
268
  }
269
269
  })
270
270
  ));
271
271
  }).then(function() { // claim all clients
272
- console.log('[1.1.0+1] claiming clients');
272
+ console.log('[1.2.0+1] claiming clients');
273
273
  return (self.clients.claim());
274
274
  }).then(function() {
275
- console.log('[1.1.0+1] clients claimed');
275
+ console.log('[1.2.0+1] clients claimed');
276
276
  return (Promise.resolve(true));
277
277
  });
278
278
  return (promise);
@@ -315,7 +315,7 @@ function GetClientResponse(event, urlpath) {
315
315
  msgport.postMessage({
316
316
  id: "fetch",
317
317
  seq: seqno,
318
- version: "1.1.0+1",
318
+ version: "1.2.0+1",
319
319
  request: {
320
320
  method: event.request.method,
321
321
  url: event.request.url
@@ -363,7 +363,7 @@ function GetClientResponse(event, urlpath) {
363
363
  */
364
364
 
365
365
  self.addEventListener('install', function(event) {
366
- console.log("[1.1.0+1] install");
366
+ console.log("[1.2.0+1] install");
367
367
  self.skipWaiting();
368
368
  });
369
369
 
@@ -376,20 +376,20 @@ self.addEventListener('install', function(event) {
376
376
  */
377
377
 
378
378
  self.addEventListener('activate', function(event) {
379
- console.log("[1.1.0+1] activate");
379
+ console.log("[1.2.0+1] activate");
380
380
  self.clients.matchAll({ // for debugging, list controlled clients
381
381
  includeUncontrolled: true
382
382
  }).then(function(clientList) {
383
383
  var urls = clientList.map(function(client) {
384
384
  return (client.url);
385
385
  });
386
- console.log('[1.1.0+1] matching clients:', urls.join(', '));
386
+ console.log('[1.2.0+1] matching clients:', urls.join(', '));
387
387
  });
388
388
  var promise = ClearCaches().then(function() {
389
389
  for (var sourceId in upgradeMsgPorts) {
390
390
  upgradeMsgPorts[sourceId].postMessage({ // notify new version available
391
391
  id: "upgrade",
392
- version: "1.1.0+1"
392
+ version: "1.2.0+1"
393
393
  });
394
394
  }
395
395
  upgradeMsgPorts = false;
@@ -421,7 +421,7 @@ self.addEventListener('fetch', function(event) {
421
421
  var promise;
422
422
  var url = new URL(request.url);
423
423
  var nocache = request.method != "GET"
424
- || url.search.length !== 0 && url.searchParams.get("naanver") !== "0edbbbd718a57553ff0a5c178f4dd389"
424
+ || url.search.length !== 0 && url.searchParams.get("naanver") !== "d20959c47030d94a5b0694e7b9df2dc1"
425
425
  || request.headers.get('range');
426
426
  if (url.pathname.startsWith("/run/")) {
427
427
  nocache = true;
@@ -455,7 +455,7 @@ self.addEventListener('fetch', function(event) {
455
455
  statusText: "Request Cancelled"
456
456
  }));
457
457
  }
458
- console.log("[1.1.0+1] fetch failed", request.url, e);
458
+ console.log("[1.2.0+1] fetch failed", request.url, e);
459
459
  return (new Response(undefined, {
460
460
  status: 404,
461
461
  statusText: "Fetch Failed"
@@ -14,30 +14,54 @@
14
14
  /*
15
15
  * TermHost
16
16
  *
17
- * Make a host debugger target.
17
+ * Make an Nide API Server debugger target.
18
+ *
19
+ * Options:
20
+ * {
21
+ * type: <string> // target category, e.g. "Host", "api.yyy.com"
22
+ * workerID: <string> // kind of worker in server subsystem
23
+ * dispatcher: <tuple> // dispatcher function for incoming messages
24
+ * startup: <dictionary> // startup options
25
+ * clientID: <string> // (rare) our identification on client
26
+ * serverID: <string> // (rare) server subsystem for us
27
+ * }
18
28
  *
19
29
  */
20
30
 
21
- closure TermHost(track, api, name, workerID, options,
22
- local target, nlregex, clientID, serverID)
31
+ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
23
32
  {
24
33
  global(window)
25
- target = require("../running/executors.nlg").ExecutorBase(track, "Host", name)
26
- clientID = "DebugWorkers"
27
- serverID = "Workers"
34
+ options = merge({
35
+ type: "Host"
36
+ workerID: "myDebugWorker"
37
+ clientID: "DebugWorkers"
38
+ serverID: "Workers"
39
+ }, options)
40
+ target = require("../running/executors.nlg").ExecutorBase(track, options.type, name)
28
41
  nlregex = RegExp("\\n", "g")
29
- if !workerID
30
- workerID = "myDebugWorker"
31
- target.workerID = workerID
42
+ target.workerID = options.workerID
32
43
  target.msgQueue = []
33
44
  target.dispatcher = call(options.dispatcher, function(reply) { reply })
34
-
45
+
46
+ // findWorker
47
+ //
48
+ function findWorker(testID, local instance) {
49
+ for instance in track.instances {
50
+ if instance.executor.hostWorkerMatch(api, testID)
51
+ return (instance.executor)
52
+ }
53
+ false
54
+ }
55
+
35
56
  // connect
36
57
  // Connect with the host if not already connected.
37
- closure connect(local pending) {
58
+ closure connect(local host, pending) {
38
59
  if target.ws
39
- return
40
- target.ws = xnew(window.WebSocket,"ws://${window.location.host}")
60
+ return(list(false, { connected: true }))
61
+ host = xnew(window.URL, api.url).host
62
+ if !host || host == ""
63
+ return(list(Error("invalid URL ${api.url}")))
64
+ target.ws = xnew(window.WebSocket,"ws://${host}")
41
65
  pending = new(nonce)
42
66
 
43
67
  // onopen
@@ -45,7 +69,7 @@ closure TermHost(track, api, name, workerID, options,
45
69
  target.ws.onopen = function onopen(e, local info, spawner) {
46
70
  info = {
47
71
  name: name
48
- workerID: workerID
72
+ workerID: target.workerID
49
73
  }
50
74
  if options.dispatcher
51
75
  info.destID = api.instanceID // valid destination for relay
@@ -61,7 +85,6 @@ closure TermHost(track, api, name, workerID, options,
61
85
 
62
86
  // onmessage
63
87
  // A message was received from the worker via WebSockets.
64
-
65
88
  target.ws.onmessage = function onmessage(e, message, local msg) {
66
89
  try {
67
90
  message = new(window.JSON.parse(e.data))
@@ -137,27 +160,16 @@ closure TermHost(track, api, name, workerID, options,
137
160
  // New workers created/discovered on this host.
138
161
  //
139
162
  function hostWorkerUpdate(msg, local localID, worker) {
140
-
141
- // findWorker
142
- //
143
- function findWorker(testID, local instance) {
144
- for instance in track.instances {
145
- if instance.executor.hostWorkerMatch(api, testID)
146
- return (instance.executor)
147
- }
148
- false
149
- }
150
-
151
163
  if msg.id == "spawned" {
152
164
  if !findWorker(msg.workerID)
153
- TermHost(track, api, msg.name, msg.workerID)
165
+ TermHost(track, api, msg.name, { type: options.type, workerID: msg.workerID })
154
166
  }
155
167
  else if msg.id == "termination"
156
168
  track.delete(findWorker(msg.workerID))
157
- else {
169
+ else if msg.id == "workerlist" {
158
170
  for `(localID, worker) in msg.workers
159
171
  if !findWorker(localID)
160
- TermHost(track, api, worker.name, localID)
172
+ TermHost(track, api, worker.name, { type: options.type, workerID: localID })
161
173
  }
162
174
  }
163
175
 
@@ -167,7 +179,7 @@ closure TermHost(track, api, name, workerID, options,
167
179
  // True iff the specified information matches us.
168
180
  //
169
181
  target.hostWorkerMatch = function hostWorkerMatch(testApi, testID) {
170
- testApi === api && testID == workerID
182
+ testApi === api && testID == target.workerID
171
183
  }
172
184
 
173
185
  //
@@ -203,8 +215,8 @@ closure TermHost(track, api, name, workerID, options,
203
215
  target.sendControl = function sendControl(workerOp, payload) {
204
216
  target.ws.send(window.JSON.stringify({
205
217
  guid: api.guid
206
- clientID: clientID
207
- serverID: serverID
218
+ clientID: options.clientID
219
+ serverID: options.serverID
208
220
  workerID: target.workerID
209
221
  workerOp: workerOp
210
222
  payload: payload
@@ -374,6 +386,9 @@ closure TermHost(track, api, name, workerID, options,
374
386
  target.ws.close(1000) // 1000: normal close
375
387
  }
376
388
 
389
+ xtarg = findWorker(target.workerID)
390
+ if xtarg
391
+ return (list(false, xtarg)) // already exists
377
392
  track.add(target)
378
393
  connect() // connect right away to start receiving messages
379
394
 
@@ -388,27 +403,34 @@ closure TermHost(track, api, name, workerID, options,
388
403
  *
389
404
  * Make a local debugger target, returning a standard (error, object) tuple.
390
405
  *
406
+ * Options:
407
+ * {
408
+ * workerID: <string> // kind of worker in server subsystem
409
+ * // "NaanIDE" for local IDE
410
+ * // "NaanIDE-Debug" for browser debug target
411
+ * startup: <dictionary> // startup options
412
+ * type: <string> // (rare) target category, e.g. "Local"
413
+ * }
414
+ *
391
415
  */
392
416
 
393
- closure TermLocal(track, name, workerID, options,
394
- local target, nlregex, listener)
417
+ closure TermLocal(track, name, options, local target, nlregex, listener)
395
418
  {
396
419
  global(js, window)
397
- if workerID == "NaanIDE" {
420
+ options = merge({
421
+ type: "Local"
422
+ }, options)
423
+ if options.workerID == "NaanIDE" {
398
424
  if !js.t
399
425
  return (list(Error("Cannot access Local IDE executor")))
400
426
  termInstallVirtualWatcher(track, js.t)
401
- return (termIDE(track, name, workerID, js.t)) // connect to IDE execution instance itself
427
+ return (termIDE(track, name, options.workerID, js.t)) // connect to IDE execution instance itself
402
428
  }
403
- if dictionary(options)
404
- options = new(options)
405
- else
406
- options = { }
407
- target = require("../running/executors.nlg").ExecutorBase(track, "Local", name)
429
+ target = require("../running/executors.nlg").ExecutorBase(track, options.type, name)
408
430
  nlregex = RegExp("\\n", "g")
409
- target.workerID = workerID
431
+ target.workerID = options.workerID
410
432
  target.msgQueue = []
411
- if workerID == "NaanIDE-Debug" {
433
+ if options.workerID == "NaanIDE-Debug" {
412
434
  target.worker = window.open(window.location.href, "_blank")
413
435
  target.worker.addEventListener("beforeunload", function(e) { // our target is closing
414
436
  destroy()
@@ -6,171 +6,136 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2023 by Richard C. Zulch
9
+ * Copyright (c) 2017-2024 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
13
13
 
14
14
  /*
15
- * MakeNideAPIclient
16
- *
17
- * Make a DAS API client object for browsers. This client API handles a single project at a
18
- * time, from load() to close().
15
+ * NideAPIclient
19
16
  *
17
+ * Make an API client object for browsers.
20
18
  *
21
19
  */
22
20
 
23
- closure MakeNideAPIclient(url, guid, local client) {
21
+ closure NideAPIclient(url, guid, apiRequester, local client) {
22
+ global()
24
23
  client = new(object, this)
24
+ if !url.match(RegExp("^https?:\/\/", "i"))
25
+ url = "http://${url}"
25
26
  client.url = url
26
27
  client.guid = guid
27
28
  client.notifyAfter = 0
28
29
  client.instanceID = UUID() // our client's unique ID
29
30
 
30
- // clientRequest() - general request routine
31
-
32
- closure clientRequest(method, path, options, cbReq, local request) {
33
- request = xnew(js.w.XMLHttpRequest)
34
- request.addEventListener("load", function (event) {
35
- cbReq(false, request, event)
36
- })
37
-
38
- request.addEventListener("error", function reqFailed(event, local errtext) {
39
- if request.status == 0
40
- errtext = "connectivity"
41
- else
42
- errtext = "request failed"
43
- error = Error(errtext, {
44
- status: request.status
45
- method: method
46
- path: path
47
- })
48
- cbReq(error, request, event)
49
- })
31
+ // clientRequest() - append our guid to the headers
50
32
 
51
- request.open(method, path)
52
- if options.responseType
53
- request.responseType = options.responseType
54
- if options.contentType
55
- request.setRequestHeader("Content-Type", options.contentType)
33
+ closure clientRequest(url, options) {
34
+ options = merge(options)
56
35
  if guid
57
- request.setRequestHeader("x-naanlang-api-guid", guid)
58
- request.send(options.putdata)
36
+ options.headers = [list("x-naanlang-api-guid", guid)]
37
+ apiRequester(url, options)
59
38
  }
60
39
 
61
40
  //
62
41
  // docs()
63
42
  //
64
43
 
65
- client.docs = closure docs() {
66
- clientRequest("GET", url.concat("/"), false, function (error, req, event) {
67
- printline(req.responseText)
68
- })
44
+ client.docs = closure docs(local error, content, extra) {
45
+ `(error, content, extra) = clientRequest(url.concat("/"))
46
+ printline(content)
69
47
  }
70
48
 
71
49
  //
72
50
  // status(callback, timeoutMS)
73
51
  //
74
52
 
75
- client.status = closure status(cbStatus, timeoutms, local query, options, queued) {
76
- options = new(dictionary)
77
- options.timeout = timeoutms
78
- options.after = client.notifyAfter
79
- query = EncodeQuery("/status/?", options)
80
- clientRequest("GET", url.concat(query), false, function (error, req, event) {
81
- if (error || req.status != 200)
82
- cbStatus()
83
- else if (length(req.responseText) == 0)
84
- cbStatus([])
85
- else {
86
- queued = new(JSONparse(req.responseText))
87
- queued.forEach(function(item,index,array) {
88
- if client.notifyAfter < item.stamp
89
- client.notifyAfter = item.stamp
90
- })
91
- cbStatus(queued)
92
- }
53
+ client.status = closure status(cbStatus, timeoutms, local query, error, content, extra, queued) {
54
+ query = EncodeQuery("/status/?", {
55
+ timeout: timeoutms
56
+ after: client.notifyAfter
93
57
  })
58
+ `(error, content, extra) = clientRequest(url.concat(query))
59
+ if (error || extra.status != 200)
60
+ cbStatus()
61
+ else if (length(content) == 0)
62
+ cbStatus([])
63
+ else {
64
+ queued = new(content)
65
+ queued.forEach(function(item, index, array) {
66
+ if client.notifyAfter < item.stamp
67
+ client.notifyAfter = item.stamp
68
+ })
69
+ cbStatus(queued)
70
+ }
94
71
  }
95
72
 
96
73
  //
97
74
  // get
98
75
  //
99
76
 
100
- client.get = closure get(path, cbRead) {
101
- options.path = filepath
102
- clientRequest("GET", url.concat("/", path), false, cbRead)
77
+ client.get = closure get(path, options, local error, content, extra) {
78
+ `(error, content, extra) = clientRequest(url.concat("/", path))
79
+ if !error && extra.status != 200
80
+ error = Error("readFile failed: ".concat(extra.status), {
81
+ status: extra.status
82
+ })
83
+ if error
84
+ list(error)
85
+ else
86
+ list(error, content, extra)
103
87
  }
104
88
 
105
89
  //
106
- // readFile(filepath, cbRead)
90
+ // readFile(filepath, options)
107
91
  //
108
92
 
109
- client.readFile = closure readFile(filepath, cbRead, local query, options) {
110
- options = new(dictionary)
111
- options.path = filepath
112
- query = EncodeQuery("/readfile/?", options)
113
- clientRequest("GET", url.concat(query), false, cbRead)
93
+ client.readFile = closure readFile(filepath, options, local query, error, content, extra) {
94
+ query = EncodeQuery("/readfile/?", {
95
+ path: filepath
96
+ })
97
+ `(error, content, extra) = clientRequest(url.concat(query), options)
98
+ if !error && extra.status != 200
99
+ error = Error("readFile failed: ".concat(extra.status), {
100
+ status: extra.status
101
+ })
102
+ if error
103
+ list(error)
104
+ else
105
+ list(error, content, extra)
114
106
  }
115
107
 
116
108
  //
117
109
  // psmRemote(options, data, callback)
118
110
  //
119
- // Perform an operation and call back when done. If the communication works then the result is:
120
- // callback(false, (remote_error, remote_data)).
121
- // Otherwise if communication failed then the result is:
122
- // callback(<error>).
111
+ // Perform an operation and call back when done.
123
112
 
124
- client.psmRemote = closure psmRemote(options, data, callback, local query, method, reqOptions, error) {
113
+ client.psmRemote = closure psmRemote(options, data, callback,
114
+ local query, reqOptions, error, content, extra) {
125
115
  query = EncodeQuery("/psm/?", options)
126
- if data
127
- method = "PUT"
128
- else
129
- method = "GET"
130
116
  reqOptions = {
131
117
  putdata: data
132
118
  }
133
- if options.encoding == "binary" {
134
- if data
135
- reqOptions.contentType = "application/octet-stream" // we are sending binary data
136
- else
137
- reqOptions.responseType = "arraybuffer" // we are requesting binary data
138
- } else if options.encoding == "json" {
139
- if data {
140
- reqOptions.contentType = "application/json;charset=UTF-8" // we are sending JSON
141
- `(error, data) = JsonStringify(data)
142
- if error
143
- return (callback(Error("psmRemote failed:", error)))
144
- reqOptions.putdata = data
145
- }
146
- else
147
- reqOptions.responseType = "application/json" // we are requesting JSON
148
- }
149
- clientRequest(method, url.concat(query), reqOptions, function (error, req, event, local data) {
150
- if !error && req.status != 200
151
- error = Error("NodeFS request failed: ".concat(req.status), {
152
- status: req.status
153
- method: method
154
- query: query
155
- })
119
+ if !data
120
+ reqOptions.encoding = options.encoding // expected response format
121
+ else if options.encoding == "binary"
122
+ reqOptions.contentType = "application/octet-stream" // we are sending binary data
123
+ else if options.encoding == "json" {
124
+ reqOptions.contentType = "application/json;charset=UTF-8" // we are sending JSON
125
+ `(error, data) = JsonStringify(data)
156
126
  if error
157
- callback(error)
158
- else {
159
- if req.getResponseHeader("content-type").startsWith("application/json")
160
- try { // attempt to decode JSON response
161
- data = new(JSONparse(req.responseText))
162
- if array(data) {
163
- data = totuple(data)
164
- error = data.0
165
- data = data.1 }
166
- } catch {
167
- if true
168
- data = req.responseText // just return text on failure
169
- }
170
- else
171
- data = req.response // e.g. when reading binary content
172
- callback(error, data) }
173
- })
127
+ return (callback(Error("psmRemote encoding failed:", error)))
128
+ reqOptions.putdata = data
129
+ }
130
+ `(error, content, extra) = clientRequest(url.concat(query), reqOptions)
131
+ if !error && extra.status != 200
132
+ error = Error("NodeFS request failed: ".concat(extra.status), {
133
+ status: extra.status
134
+ })
135
+ if error
136
+ callback(error)
137
+ else
138
+ callback(error, content)
174
139
  }
175
140
 
176
141
  client
@@ -186,12 +151,12 @@ closure MakeNideAPIclient(url, guid, local client) {
186
151
 
187
152
  function apicInit(local manifest) {
188
153
 
189
- manifest = `(MakeNideAPIclient, apicInit)
154
+ manifest = `(NideAPIclient, apicInit)
190
155
 
191
156
  Naan.module.build(module.id, "apiclient", function(modobj, compobj) {
192
157
  Naan.module.require("./client.nlg")
193
158
  compobj.manifest = manifest
194
- modobj.exports.MakeNideAPIclient = MakeNideAPIclient
159
+ modobj.exports.NideAPIclient = NideAPIclient
195
160
  })
196
161
 
197
162
  } ();