@naanlang/naan 1.4.3 → 1.5.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 (50) hide show
  1. package/LICENSE.md +2 -2
  2. package/README.md +4 -4
  3. package/bin/index.js +22 -3
  4. package/dist/env_web.js +2 -2
  5. package/dist/naan.min.js +6 -6
  6. package/frameworks/browser/browser.nlg +2 -2
  7. package/frameworks/browser/https_request.nlg +39 -10
  8. package/frameworks/browser/sworker.js +23 -23
  9. package/frameworks/browser/terminals.nlg +33 -24
  10. package/frameworks/client/apiclient.nlg +31 -18
  11. package/frameworks/client/client.nlg +22 -2
  12. package/frameworks/client/psm_client.nlg +12 -3
  13. package/frameworks/node/filesystem.nlg +9 -7
  14. package/frameworks/node/gitter.nlg +9 -7
  15. package/frameworks/node/http_request.nlg +103 -0
  16. package/frameworks/node/https_request.nlg +42 -9
  17. package/frameworks/node/node.nlg +1 -0
  18. package/frameworks/node/shell.nlg +4 -4
  19. package/frameworks/node/worker.nlg +1 -0
  20. package/frameworks/project/projects.nlg +2 -1
  21. package/frameworks/running/executors.nlg +26 -7
  22. package/frameworks/running/taskexec.nlg +48 -14
  23. package/frameworks/storage/dbt_pouch.nlg +26 -13
  24. package/frameworks/storage/psm.nlg +39 -5
  25. package/frameworks/storage/psm_dbtables.nlg +10 -2
  26. package/lib/browser/env_web.js +9 -9
  27. package/lib/browser/env_webworker.js +1 -2
  28. package/lib/core/naanlib.js +6 -6
  29. package/lib/env_node.js +9 -3
  30. package/lib/node_repl_init.nlg +2 -2
  31. package/package.json +1 -1
  32. package/plugins/nodeLib/node_util.nlg +14 -7
  33. package/plugins/openSearch/os_dynamo.nlg +5 -5
  34. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +2 -1
  35. package/plugins/serviceAws/aws_dynamo.nlg +26 -8
  36. package/plugins/serviceAws/aws_s3.nlg +3 -3
  37. package/plugins/serviceAws/aws_sqs.nlg +3 -1
  38. package/plugins/serviceAws/aws_utils.nlg +3 -1
  39. package/plugins/serviceAws/aws_vm.nlg +198 -0
  40. package/plugins/serviceAws/dbt_aws.nlg +22 -20
  41. package/plugins/serviceAws/psm_aws.nlg +2 -1
  42. package/plugins/serviceGC/gc_api.nlg +1 -0
  43. package/plugins/serviceNexara/serviceNexara.nlg +32 -0
  44. package/plugins/serviceNexara/speechrec.nlg +160 -0
  45. package/plugins/serviceYC/serviceYC.nlg +2 -3
  46. package/plugins/serviceYC/yc_speechrec.nlg +4 -3
  47. package/plugins/serviceYC/yc_vm.nlg +44 -54
  48. package/test/test_01_core.nlg +42 -33
  49. package/test/test_03_jsinterop.nlg +35 -6
  50. package/plugins/serviceGC/russian_trusted_root_ca_pem.crt +0 -33
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2023 by Richard C. Zulch
9
+ * Copyright (c) 2020-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -33,7 +33,7 @@ closure FileReader(file, progress, local pending, freader, result) {
33
33
  freader.addEventListener("error", function(error) {
34
34
  pending.signal(list(error))
35
35
  })
36
- freader.AddEventListener("progress", function(event) {
36
+ freader.addEventListener("progress", function(event) {
37
37
  if event.lengthComputable && event.total
38
38
  progress(toint((event.loaded * 100) / event.total))
39
39
  else
@@ -25,6 +25,7 @@
25
25
  * range: <string> // sets range header
26
26
  * headers: [`(key, value)] // add header(s) to the request, overriding defaults
27
27
  * keepalive: <boolean> // true to send data at unload
28
+ * retrier: <function> // retry selected failures
28
29
  * debug: <boolean> // log errors and status results
29
30
  * }
30
31
  *
@@ -39,11 +40,35 @@
39
40
  */
40
41
 
41
42
  closure HttpsApiRequest(url, options,
42
- local urlq, fetchOptions, putdata, item, error, response,
43
+ local delayf, urlq, fetchOptions, putdata, item, error, response,
43
44
  contentType, content, headers) {
44
- global(window)
45
- if !options
46
- options = { }
45
+ global(window, common)
46
+ //
47
+ // defRetrier -- backoff and retry selected errors
48
+ //
49
+ function defRetrier(error, headers, local retryAfter, retryms, waitms) {
50
+ if member(error.status, `(408, 500, 502, 503, 504)) { // retriable errors
51
+ retryAfter = headers["retry-after"]
52
+ if retryAfter {
53
+ retryms = toint(retryAfter) * 1000
54
+ if !retryms
55
+ retryms = Date(retryAfter).getTime() - Date.now()
56
+ if retryms < 0
57
+ retryms = false
58
+ }
59
+ if !delayf
60
+ delayf = common.ExbackFactory(12,30) // 12s max backoff, 30s deadline
61
+ waitms = delayf()
62
+ if !waitms || waitms < retryms
63
+ waitms = retryms
64
+ if options.debug
65
+ debuglog("HttpsApiRequest.defRetrier: wait ${waitms} msec using retry-after ${retryAfter}")
66
+ if waitms // return false to give up
67
+ sleep(waitms) // return true from sleep to retry
68
+ }
69
+ }
70
+
71
+ options = merge({ retrier: defRetrier }, options)
47
72
  if options.query
48
73
  urlq = url.concat(EncodeQuery("?", options.query))
49
74
  else
@@ -92,16 +117,23 @@ closure HttpsApiRequest(url, options,
92
117
  debuglog("HttpsApiRequest error:", url, "error:", error)
93
118
  return (list(Error("HttpsApiRequest fetch failed:", error, url)))
94
119
  }
120
+ headers = { }
121
+ response.headers.forEach(function(value, key) {
122
+ headers[key.toLowerCase()] = value
123
+ })
95
124
  if response.status < 200 || response.status >= 299 { // 299 is "cancelled"
96
125
  if options.debug
97
126
  debuglog("HttpsApiRequest status:", url, response.statusCode)
98
127
  error = Error("HttpsApiRequest status:", url, response.status, {
99
128
  status: response.status
100
129
  })
101
- if options.retrier(error)
130
+ if options.retrier(error, headers)
102
131
  continue // optional retry/delay logic
103
132
  else
104
- return (list(error, false, { status: response.status }))
133
+ return (list(error, false, {
134
+ headers: headers
135
+ status: response.status
136
+ }))
105
137
  } else
106
138
  break
107
139
  }
@@ -125,10 +157,6 @@ closure HttpsApiRequest(url, options,
125
157
  `(error, content) = await(response.arrayBuffer())
126
158
  else
127
159
  `(error, content) = await(response.text())
128
- headers = { }
129
- response.headers.forEach(function(value, key) {
130
- headers[key.toLowerCase()] = value
131
- })
132
160
  list(error, content, {
133
161
  headers: headers
134
162
  status: response.status
@@ -149,6 +177,7 @@ function https_browserInit(local manifest) {
149
177
 
150
178
  Naan.module.build(module.id, "https_request", function(modobj, compobj) {
151
179
  require("browser.nlg")
180
+ common = require("../common/utils.nlg")
152
181
  compobj.manifest = manifest
153
182
  modobj.exports.HttpsApiRequest = HttpsApiRequest
154
183
  })
@@ -36,7 +36,7 @@
36
36
  *
37
37
  */
38
38
 
39
- var CurrentCacheName = "Naanlang-1.4.3+1";
39
+ var CurrentCacheName = "Naanlang-1.5.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.4.3+1] received new msgport for", sourceId, pubID, "-", pubVersion);
96
- if (pubVersion != "1.4.3+1") {
95
+ console.log("[1.5.0+1] received new msgport for", sourceId, pubID, "-", pubVersion);
96
+ if (pubVersion != "1.5.0+1") {
97
97
  if (upgradeMsgPorts) { // if not activated
98
- console.log("[1.4.3+1] update pending for", sourceId);
98
+ console.log("[1.5.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.4.3+1"
104
+ version: "1.5.0+1"
105
105
  });
106
- console.log("[1.4.3+1] update sent for:", sourceId);
106
+ console.log("[1.5.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.4.3+1] attempting skipWaiting");
137
+ console.log("[1.5.0+1] attempting skipWaiting");
138
138
  self.skipWaiting();
139
139
  } else if (msg.id == "terminate") { // termiante this SW now
140
- console.log("[1.4.3+1] terminated");
140
+ console.log("[1.5.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.4.3+1] msg received:", msg.text);
153
+ console.log("[1.5.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.4.3+1",
164
+ text: "port received by 1.5.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.4.3+1] requesting new msgport for", client.id);
181
+ console.log("[1.5.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.4.3+1] source gone:", sourceId);
227
+ console.log("[1.5.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.4.3+1] client gone:", clientId);
232
+ console.log("[1.5.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.4.3+1] deleting old cache:', cacheName);
266
+ console.log('[1.5.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.4.3+1] claiming clients');
272
+ console.log('[1.5.0+1] claiming clients');
273
273
  return (self.clients.claim());
274
274
  }).then(function() {
275
- console.log('[1.4.3+1] clients claimed');
275
+ console.log('[1.5.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.4.3+1",
318
+ version: "1.5.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.4.3+1] install");
366
+ console.log("[1.5.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.4.3+1] activate");
379
+ console.log("[1.5.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.4.3+1] matching clients:', urls.join(', '));
386
+ console.log('[1.5.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.4.3+1"
392
+ version: "1.5.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") !== "3b6364f71856e32f6cb8edae0e67bbc2"
424
+ || url.search.length !== 0 && url.searchParams.get("naanver") !== "1df9163d801364d0cae89b149cc24ef5"
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.4.3+1] fetch failed", request.url, e);
458
+ console.log("[1.5.0+1] fetch failed", request.url, e);
459
459
  return (new Response(undefined, {
460
460
  status: 404,
461
461
  statusText: "Fetch Failed"
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2019-2024 by Richard C. Zulch
9
+ * Copyright (c) 2019-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -48,8 +48,8 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
48
48
  nlregex = RegExp("\\n", "g")
49
49
  target.workerID = options.workerID
50
50
  target.msgQueue = []
51
- target.dispatcher = call(options.dispatcher, function(reply) { reply })
52
-
51
+ target.dispatcher = call(options.dispatcher)
52
+
53
53
  // findWorker
54
54
  //
55
55
  function findWorker(testID, local instance) {
@@ -135,19 +135,20 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
135
135
 
136
136
  // dispatcher
137
137
  // Respond to a host request while preserving context to permit reply routing
138
- closure dispatcher(message, local reply) {
139
- reply = target.dispatcher(message.payload.data)
140
- target.ws.send(window.JSON.stringify({
141
- guid: api.guid
142
- clientID: message.clientID
143
- serverID: message.serverID
144
- workerID: message.workerID
145
- respOp: "msgout"
146
- payload: {
147
- id: "targetout",
148
- data: reply
149
- }
150
- }))
138
+ closure dispatcher(message) {
139
+ target.dispatcher(message.payload.data, function(reply) {
140
+ target.ws.send(window.JSON.stringify({
141
+ guid: api.guid
142
+ clientID: message.clientID
143
+ serverID: message.serverID
144
+ workerID: message.workerID
145
+ respOp: "msgout"
146
+ payload: {
147
+ id: "targetout",
148
+ data: reply
149
+ }
150
+ }))
151
+ })
151
152
  }
152
153
 
153
154
  // onerror
@@ -334,6 +335,7 @@ closure TermHost(track, api, name, options, local target, nlregex, xtarg)
334
335
  //
335
336
 
336
337
  target.debugWrite = function(text, level) {
338
+ text = text.replaceAll("\n", "\r\n")
337
339
  if (level >= 5)
338
340
  target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
339
341
  else if (level >= 4)
@@ -560,7 +562,7 @@ closure TermLocal(track, name, options, local target, nlregex, listener)
560
562
  msg.data._guid = target.guid
561
563
  js.t.DispatchMessage(msg.data)
562
564
  }
563
- }
565
+ }
564
566
 
565
567
  //
566
568
  // target.DebugCmd
@@ -596,6 +598,7 @@ closure TermLocal(track, name, options, local target, nlregex, listener)
596
598
  //
597
599
 
598
600
  target.debugWrite = function(text, level) {
601
+ text = text.replaceAll("\n", "\r\n")
599
602
  if (level >= 5)
600
603
  target.term.WriteLn(text, target.term.Cyan) // cyan for builtin logging
601
604
  else if (level >= 4)
@@ -761,14 +764,18 @@ closure WorkerToMain(local nideRunning, track) {
761
764
  /*
762
765
  * findIDEtarget
763
766
  *
764
- * Find a target for our IDE that matches the specified name, workerID, and naancont.
767
+ * Find a target for our IDE that matches the specified name, workerID, and naancont. Either the
768
+ * title or the naancont must match. The title will match but not the naancont if the window was
769
+ * closed/reloaded but we didn't get notified because browsers are annoying that way. Alternatively
770
+ * the naancont will match but not the title if we have updated the version.
765
771
  *
766
772
  */
767
773
 
768
- closure findIDEtarget(track, name, workerID, naancont, local target) {
774
+ closure findIDEtarget(track, name, workerID, title, naancont, local target) {
769
775
  global()
770
776
  for target in track.enumlist()
771
- if target.name == name && target.workerID == workerID && (!target.naancont || target.naancont === naancont)
777
+ if target.name == name && target.workerID == workerID
778
+ && (target.title == title || !target.naancont || target.naancont === naancont)
772
779
  return (target)
773
780
  false
774
781
  };
@@ -785,8 +792,10 @@ closure findIDEtarget(track, name, workerID, naancont, local target) {
785
792
 
786
793
  closure termIDE(track, name, workerID, naancont, title, local target, connected) {
787
794
  global(js, gWorkers)
788
- target = findIDEtarget(track, name, workerID, naancont)
795
+ target = findIDEtarget(track, name, workerID, title, naancont)
789
796
  if target { // new naancont on existing target
797
+ if target.naancont && naancont !== target.naancont
798
+ target.targetClose()
790
799
  target.updateController(naancont)
791
800
  target.title = title
792
801
  track.update(target)
@@ -931,7 +940,7 @@ closure termIDE(track, name, workerID, naancont, title, local target, connected)
931
940
  //
932
941
  // Mark the target window as closed.
933
942
  //
934
- function targetClose(local conn) {
943
+ target.targetClose = function targetClose(local conn) {
935
944
  for conn in connected {
936
945
  conn.db.detach(target)
937
946
  conn.WriteLn("\x1b[90m\x1b[3m".concat("\ntarget closed", "\x1b[0m"))
@@ -1009,12 +1018,12 @@ closure termInstallVirtualWatcher(track, naancont) {
1009
1018
  target.attention()
1010
1019
  }
1011
1020
  else if msg.op == "VsiteClose" {
1012
- target = findIDEtarget(track, msg.name, "NaanVsite", msg.naancont)
1021
+ target = findIDEtarget(track, msg.name, "NaanVsite", msg.title, msg.naancont)
1013
1022
  if target
1014
1023
  target.updateController()
1015
1024
  }
1016
1025
  else if msg.op == "VsiteVisibilityChange" {
1017
- target = findIDEtarget(track, msg.name, "NaanVsite", msg.naancont)
1026
+ target = findIDEtarget(track, msg.name, "NaanVsite", msg.title, msg.naancont)
1018
1027
  if target
1019
1028
  target.setCheckStatus(msg.hidden, msg.window)
1020
1029
  }
@@ -2,41 +2,50 @@
2
2
  * apiclient.nlg
3
3
  * Naanlib/frameworks/client
4
4
  *
5
- * Access to Nide API with browser HTTP client.
5
+ * Access to Nide API with specified HTTP client.
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2024 by Richard C. Zulch
9
+ * Copyright (c) 2017-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
13
13
 
14
14
  /*
15
- * NideAPIclient
15
+ * APIClient
16
16
  *
17
- * Make an API client object for browsers.
17
+ * Make an API client object.
18
+ *
19
+ * Options:
20
+ * {
21
+ * url: <string> // hostname or URL of the remote server
22
+ * guid: <string> // shared secret for access to remote server
23
+ * instanceID: <string> // optional UUID for our client; can be persisted by caller
24
+ * }
18
25
  *
19
26
  */
20
27
 
21
- closure NideAPIclient(url, guid, apiRequester, local client) {
22
- global()
28
+ closure APIClient(options, local client, url, guid) {
29
+ global(App)
23
30
  client = new(object, this)
31
+ url = options.url
24
32
  if !url.match(RegExp("^https?:\/\/", "i"))
25
33
  url = "http://${url}" // a protocol is required
26
34
  if url.slice(-1) != "/"
27
35
  url = url.concat("/") // must end in "/"
28
36
  client.url = url
29
- client.guid = guid
37
+ client.guid = options.guid
38
+ client.instanceID = options.instanceID || UUID() // our client's unique ID
30
39
  client.notifyAfter = 0
31
- client.instanceID = UUID() // our client's unique ID
40
+ client.requester = clirRequester()
32
41
 
33
42
  // clientRequest() - append our guid to the headers
34
43
 
35
- closure clientRequest(url, options) {
36
- options = merge(options)
37
- if guid
38
- options.headers = [list("x-naanlang-api-guid", guid)]
39
- apiRequester(url, options)
44
+ closure clientRequest(url, reqops) {
45
+ reqops = merge(reqops)
46
+ if options.guid
47
+ reqops.headers = [list("x-naanlang-api-guid", options.guid)]
48
+ client.requester(url, reqops)
40
49
  }
41
50
 
42
51
  //
@@ -57,7 +66,7 @@ closure NideAPIclient(url, guid, apiRequester, local client) {
57
66
  timeout: timeoutms
58
67
  after: client.notifyAfter
59
68
  })
60
- `(error, content, extra) = clientRequest(url.concat(query))
69
+ `(error, content, extra) = clientRequest(url.concat(query), { retrier: false }) // don't retry inside
61
70
  if (error || extra.status != 200)
62
71
  cbStatus()
63
72
  else if (length(content) == 0)
@@ -76,8 +85,12 @@ closure NideAPIclient(url, guid, apiRequester, local client) {
76
85
  // get
77
86
  //
78
87
 
79
- client.get = closure get(path, options, local error, content, extra) {
80
- `(error, content, extra) = clientRequest(url.concat(path))
88
+ client.get = closure get(path, options, local requrl, error, content, extra) {
89
+ if App.cache
90
+ requrl = url.concat(EncodeQuery(path.concat("?"), { naanver: App.cache }))
91
+ else
92
+ requrl = url.concat(path)
93
+ `(error, content, extra) = clientRequest(requrl)
81
94
  if !error && extra.status != 200
82
95
  error = Error("readFile failed: ".concat(extra.status), {
83
96
  status: extra.status
@@ -153,12 +166,12 @@ closure NideAPIclient(url, guid, apiRequester, local client) {
153
166
 
154
167
  function apicInit(local manifest) {
155
168
 
156
- manifest = `(NideAPIclient, apicInit)
169
+ manifest = `(APIClient, apicInit)
157
170
 
158
171
  Naan.module.build(module.id, "apiclient", function(modobj, compobj) {
159
172
  Naan.module.require("./client.nlg")
160
173
  compobj.manifest = manifest
161
- modobj.exports.NideAPIclient = NideAPIclient
174
+ modobj.exports.APIClient = APIClient
162
175
  })
163
176
 
164
177
  } ();
@@ -6,11 +6,31 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2021 by Richard C. Zulch
9
+ * Copyright (c) 2020-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
13
13
 
14
+ /*
15
+ * clirRequester
16
+ *
17
+ * Return an appropriate HttpsRequestApi client based on our environment.
18
+ *
19
+ */
20
+
21
+ clirRequestApi = false;
22
+
23
+ function clirRequester() {
24
+ if !clirRequestApi {
25
+ if js.w
26
+ clirRequestApi = require("naanlib:frameworks/browser/https_request.nlg").HttpsApiRequest
27
+ else
28
+ clirRequestApi = require("naanlib:frameworks/node/https_request.nlg").HttpsApiRequest
29
+ }
30
+ clirRequestApi
31
+ };
32
+
33
+
14
34
  /*
15
35
  * clirInit
16
36
  *
@@ -20,7 +40,7 @@
20
40
  */
21
41
 
22
42
  function clirInit(local manifest) {
23
- manifest = `(clirInit)
43
+ manifest = `(clirRequester, clirInit)
24
44
 
25
45
  Naan.module.build(module.id, "client", function(modobj, compobj) {
26
46
  require("../common/").LiveImport()
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2019-2024 by Richard C. Zulch
9
+ * Copyright (c) 2019-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -633,8 +633,17 @@ closure psmcFsConnector(psm, api, local connClassID, connector, watch) {
633
633
  api = connector.apis[creds]
634
634
  else {
635
635
  api = connector.apis[creds.urlName]
636
- if !api // get API to remote server
637
- connector.apis[creds.urlName] = api = NideAPIclient(creds.urlName, creds.authSecret)
636
+ if !api { // create API to remote server
637
+ connector.apis[creds.urlName] = api = APIClient({
638
+ url: creds.urlName
639
+ guid: creds.authSecret
640
+ instanceID: creds.instanceID
641
+ })
642
+ if creds.instanceID != api.instanceID { // update our client instanceID
643
+ creds.instanceID = api.instanceID
644
+ `(error) = connector.vault.updateResource(resID, creds)
645
+ }
646
+ }
638
647
  }
639
648
  }
640
649
  if error
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2022 by Richard C. Zulch
9
+ * Copyright (c) 2017-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -1041,6 +1041,8 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
1041
1041
  cmdargs.push(options.pattern)
1042
1042
  cmdargs.push(JSpath.resolve(rootpath, localpath))
1043
1043
  execOptions = { cmdargs: cmdargs }
1044
+ if js.g.process.platform == "win32" // to make "-i" work on Windows
1045
+ execOptions.spawnops = { env: merge(js.g.process.env, { LC_ALL: 'en_US.UTF-8' }) }
1044
1046
  result = []
1045
1047
  lineRE = RegExp("([^:]*):([0-9]+):(.*)$") // <path>:<line-number>:<matching-text-line>
1046
1048
  if integer(options.maxCount)
@@ -1075,7 +1077,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
1075
1077
  // has completed. Options are:
1076
1078
  // {
1077
1079
  // cmdargs: -- array of string arguments to the command (see below)
1078
- // execops: -- optional exec options like cwd
1080
+ // spawnops: -- optional spawn options like cwd
1079
1081
  // errproc: -- callback for stderr output lines, or false
1080
1082
  // errLE: -- string or RegExp for stderr line ending
1081
1083
  // outproc: -- optional callback for stdout output lines
@@ -1100,7 +1102,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
1100
1102
  //
1101
1103
 
1102
1104
  files.execLines = closure execLines(cmdname, options, callback,
1103
- local output, execops, spawn, linerErr, linerOut) {
1105
+ local output, spawnops, spawn, linerErr, linerOut) {
1104
1106
  if !callback
1105
1107
  return (syncAdapter(execLines, cmdname, options))
1106
1108
  if !string(cmdname) || cmdname == ""
@@ -1109,11 +1111,11 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
1109
1111
  output = options.output
1110
1112
  else
1111
1113
  output = {}
1112
- if options.execops
1113
- execops = options.execops
1114
+ if options.spawnops
1115
+ spawnops = options.spawnops
1114
1116
  else
1115
- execops = { }
1116
- spawn = nodecp.spawn(cmdname, options.cmdargs, execops)
1117
+ spawnops = { }
1118
+ spawn = nodecp.spawn(cmdname, options.cmdargs, spawnops)
1117
1119
 
1118
1120
  // completed
1119
1121
  // execute callback only once