@naanlang/naan 1.0.4 → 1.0.5

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 (39) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +8 -6
  3. package/bin/index.js +2 -2
  4. package/dist/env_web.js +25 -5
  5. package/dist/naan.min.js +4 -4
  6. package/frameworks/browser/https_request.nlg +120 -0
  7. package/frameworks/browser/sworker.js +19 -19
  8. package/frameworks/browser/terminals.nlg +5 -3
  9. package/frameworks/browser/workers.nlg +1 -0
  10. package/frameworks/client/psm_client.nlg +7 -1
  11. package/frameworks/common/common.nlg +95 -25
  12. package/frameworks/common/preferences.nlg +1 -0
  13. package/frameworks/common/watching.nlg +1 -0
  14. package/frameworks/node/https_request.nlg +119 -0
  15. package/frameworks/node/node.nlg +1 -0
  16. package/frameworks/project/proj_cliser.nlg +11 -3
  17. package/frameworks/project/proj_console.nlg +13 -4
  18. package/frameworks/project/proj_folder.nlg +10 -1
  19. package/frameworks/project/proj_lambda.nlg +13 -4
  20. package/frameworks/project/proj_static.nlg +11 -3
  21. package/frameworks/project/projects.nlg +80 -15
  22. package/frameworks/running/executors.nlg +1 -0
  23. package/lib/browser/env_web.js +27 -7
  24. package/lib/core/naanlib.js +4 -4
  25. package/package.json +1 -1
  26. package/plugins/serviceAws/aws/aws-sdk-node.min.js +2 -0
  27. package/plugins/serviceAws/aws/aws-sdk.min.js +2 -88
  28. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +7 -6
  29. package/plugins/serviceAws/aws_dynamo.nlg +127 -44
  30. package/plugins/serviceAws/aws_lambda.nlg +11 -4
  31. package/plugins/serviceAws/aws_s3.nlg +44 -14
  32. package/plugins/serviceAws/dbt_aws.nlg +29 -36
  33. package/plugins/serviceAws/psm_aws.nlg +21 -16
  34. package/plugins/serviceAws/serviceAws.nlg +6 -4
  35. package/test/harness.nlg +3 -1
  36. package/test/test_01_core.nlg +5 -5
  37. package/test/test_02_context.nlg +4 -4
  38. package/test/test_03_jsinterop.nlg +9 -3
  39. package/plugins/serviceAws/aws_cognito.nlg +0 -76
@@ -0,0 +1,120 @@
1
+ /*
2
+ * https_browser.nlg
3
+ *
4
+ * Https operations for the browser.
5
+ *
6
+ * column positioning: // // !
7
+ *
8
+ * Copyright (c) 2021-2022 by Richard C. Zulch
9
+ *
10
+ */
11
+
12
+
13
+ /*
14
+ * HttpsApiRequest
15
+ *
16
+ * Perform an API request from the browser. This operates the same as HttpsApiRequest for NodeJS.
17
+ *
18
+ * Options:
19
+ * {
20
+ * method: <string> // HTTP method (defaults to GET/PUT)
21
+ * query: <dictionary> // query variables added to the URL
22
+ * putdata: <data> // data to put
23
+ * contentType: <string> // sets Content-Type header, otherwise auto-determined
24
+ * encoding: <string> // "binary" to receive binary data as arrayBuffer
25
+ * range: <string> // sets range header
26
+ * headers: [`(key, value)] // add header(s) to the request, overriding defaults
27
+ * }
28
+ *
29
+ */
30
+
31
+ closure HttpsApiRequest(url, options,
32
+ local urlq, fetchOptions, putdata, error, response, contentType, content) {
33
+ if !options
34
+ options = { }
35
+ if options.query
36
+ urlq = url.concat(EncodeQuery("?", options.query))
37
+ else
38
+ urlq = url
39
+ putdata = options.putdata
40
+ fetchOptions = {
41
+ mode: 'cors'
42
+ cache: 'no-cache'
43
+ credentials: 'same-origin'
44
+ headers: { }
45
+ redirect: 'follow'
46
+ referrerPolicy: 'no-referrer'
47
+ }
48
+ if options.method
49
+ fetchOptions.method = options.method
50
+ else if putdata
51
+ fetchOptions.method = "POST"
52
+ else
53
+ fetchOptions.method = "GET"
54
+ if putdata {
55
+ if options.contentType
56
+ fetchOptions.headers['Content-Type'] = options.contentType
57
+ else if jsTypedArray(options.putdata)
58
+ fetchOptions.headers['Content-Type'] = "application/octet-stream"
59
+ else if member(typeof(options.putdata), `(dictionary, array, xobject)) {
60
+ fetchOptions.headers['Content-Type'] = "application/json"
61
+ `(error, putdata) = JsonStringify(options.putdata)
62
+ if error
63
+ return (list(Error("HttpsApiRequest encode:", url)))
64
+ }
65
+ fetchOptions.body = putdata
66
+ }
67
+ if options.range
68
+ fetchOptions.headers.Range = options.range
69
+ if array(options.headers)
70
+ for item in options.headers
71
+ fetchOptions.headers[item.0] = item.1
72
+ //
73
+ // perform the fetch and return when complete
74
+ //
75
+ `(error, response) = await(js.w.fetch(urlq, fetchOptions))
76
+ if error
77
+ return (list(Error("HttpsApiRequest fetch failed:", error, url)))
78
+ contentType = response.headers.get("content-type")
79
+ if response.status < 200 || response.status >= 300
80
+ return (list(Error("HttpsApiRequest status:", url, response.status, {
81
+ status: response.status
82
+ })))
83
+ if contentType.startsWith("application/json") {
84
+ `(error, content) = await(response.text())
85
+ if !error
86
+ `(error, content) = JsonParse(content)
87
+ if error
88
+ error = Error("HttpsApiRequest decode:", url, error)
89
+ else
90
+ content = new(content)
91
+ if array(content) { // deencapsulate to get API result
92
+ content = totuple(content)
93
+ error = content.0
94
+ content = content.1
95
+ }
96
+ }
97
+ else if options.encoding == "binary"
98
+ `(error, content) = await(response.arrayBuffer())
99
+ else
100
+ `(error, content) = await(response.text())
101
+ list(error, content)
102
+ };
103
+
104
+
105
+ /*
106
+ * https_browserInit
107
+ *
108
+ * Initialize HTTPS request operations for browsers.
109
+ *
110
+ */
111
+
112
+ function https_browserInit(local manifest) {
113
+ manifest = `(HttpsApiRequest, https_browserInit)
114
+
115
+ Naan.module.build(module.id, "https_request", function(modobj, compobj) {
116
+ require("./browser.nlg")
117
+ compobj.manifest = manifest
118
+ modobj.exports.HttpsApiRequest = HttpsApiRequest
119
+ })
120
+ }();
@@ -36,7 +36,7 @@
36
36
  *
37
37
  */
38
38
 
39
- var CurrentCacheName = "Naanlang-1.0.4-2";
39
+ var CurrentCacheName = "Naanlang-1.0.5-2";
40
40
 
41
41
 
42
42
  //
@@ -74,8 +74,8 @@ var waitingForInit = []; // initialization functions, or
74
74
  return; // already done
75
75
  var waiters = waitingForInit;
76
76
  waitingForInit = false; // no more waiters allowed
77
- for (var waiter in waiters)
78
- waiter(); // call each waiter
77
+ for (var wdex in waiters)
78
+ waiters[wdex](); // call each waiter
79
79
  }
80
80
 
81
81
  // self.onmessage events
@@ -89,11 +89,11 @@ var waitingForInit = []; // initialization functions, or
89
89
  var pubVersion = event.data.hereIsMyVersion;
90
90
  var sourceId = event.source.id; // client id of sender of message
91
91
  msgPorts[sourceId] = msgport;
92
- console.log("[1.0.4-2] received new msgport for", sourceId, pubID, "-", pubVersion);
93
- if (pubVersion != "1.0.4-2")
92
+ console.log("[1.0.5-2] received new msgport for", sourceId, pubID, "-", pubVersion);
93
+ if (pubVersion != "1.0.5-2")
94
94
  msgport.postMessage({ // notify new version available
95
95
  id: "upgrade",
96
- version: "1.0.4-2"
96
+ version: "1.0.5-2"
97
97
  });
98
98
  Reaper(); // clean up obsolete info
99
99
 
@@ -107,7 +107,7 @@ var waitingForInit = []; // initialization functions, or
107
107
  if (msg.id == "response")
108
108
  processResponse(msg);
109
109
  else if (msg.id == "text")
110
- console.log("[1.0.4-2] msg received:", msg.text);
110
+ console.log("[1.0.5-2] msg received:", msg.text);
111
111
  };
112
112
 
113
113
  // send text to IDE log
@@ -118,7 +118,7 @@ var waitingForInit = []; // initialization functions, or
118
118
  // don't clutter the log
119
119
  msgport.postMessage({
120
120
  id: "text",
121
- text: "port received by 1.0.4-2",
121
+ text: "port received by 1.0.5-2",
122
122
  });
123
123
  */
124
124
  if (--pending === 0)
@@ -135,13 +135,13 @@ var waitingForInit = []; // initialization functions, or
135
135
  includeUncontrolled: true
136
136
  }).then(function(clientList) {
137
137
  clientList.every(function(client) {
138
- console.log("[1.0.4-2] requesting new msgport for", client.id);
138
+ console.log("[1.0.5-2] requesting new msgport for", client.id);
139
139
  ++pending;
140
140
  client.postMessage({ // tell client(s) we need this fetch source
141
141
  msg: "Naan_need_fetch_port",
142
142
  });
143
143
  });
144
- setTimeout(doneInit, 1000); // release fetches
144
+ setTimeout(doneInit, 10000); // release fetches
145
145
  });
146
146
 
147
147
  // processResponse
@@ -181,12 +181,12 @@ function Reaper() {
181
181
  clients[clientList[clidex].id] = clientList[clidex];
182
182
  for (var sourceId in msgPorts)
183
183
  if (!clients[sourceId]) {
184
- console.log("[1.0.4-2] source gone:", sourceId);
184
+ console.log("[1.0.5-2] source gone:", sourceId);
185
185
  delete msgPorts[sourceId]; // no longer a source
186
186
  }
187
187
  for (var clientId in fetchPorts)
188
188
  if (!clients[clientId]) {
189
- console.log("[1.0.4-2] client gone:", clientId);
189
+ console.log("[1.0.5-2] client gone:", clientId);
190
190
  delete fetchPorts[clientId]; // no longer a client
191
191
  }
192
192
  for (var fqdex = 0; fqdex < fetchQueue.length; ++fqdex) {
@@ -220,13 +220,13 @@ function ClearCaches() {
220
220
  return (Promise.all(
221
221
  cacheNames.map(function(cacheName) {
222
222
  if (cacheName != CurrentCacheName) {
223
- console.log('[1.0.4-2] deleting old cache:', cacheName);
223
+ console.log('[1.0.5-2] deleting old cache:', cacheName);
224
224
  return (caches.delete(cacheName));
225
225
  }
226
226
  })
227
227
  ));
228
228
  }).then(function() { // claim all clients
229
- console.log('[1.0.4-2] claiming clients');
229
+ console.log('[1.0.5-2] claiming clients');
230
230
  return (self.clients.claim());
231
231
  });
232
232
  return (promise);
@@ -269,7 +269,7 @@ function GetClientResponse(event, urlpath) {
269
269
  msgport.postMessage({
270
270
  id: "fetch",
271
271
  seq: seqno,
272
- version: "1.0.4-2",
272
+ version: "1.0.5-2",
273
273
  request: {
274
274
  method: event.request.method,
275
275
  url: event.request.url
@@ -317,7 +317,7 @@ function GetClientResponse(event, urlpath) {
317
317
  */
318
318
 
319
319
  self.addEventListener('install', function(event) {
320
- console.log("[1.0.4-2] install");
320
+ console.log("[1.0.5-2] install");
321
321
  self.skipWaiting();
322
322
  });
323
323
 
@@ -356,7 +356,7 @@ self.addEventListener('fetch', function(event) {
356
356
  }
357
357
  else
358
358
  promise = fetch(event.request).catch(function (e) {
359
- console.log("[1.0.4-2] fetch failed", e);
359
+ console.log("[1.0.5-2] fetch failed", e);
360
360
  return (new Response(undefined, {
361
361
  status: 404,
362
362
  statusText: "Fetch Failed"
@@ -385,14 +385,14 @@ self.addEventListener('fetch', function(event) {
385
385
  */
386
386
 
387
387
  self.addEventListener('activate', function(event) {
388
- console.log("[1.0.4-2] activate");
388
+ console.log("[1.0.5-2] activate");
389
389
  self.clients.matchAll({ // for debugging, list controlled clients
390
390
  includeUncontrolled: true
391
391
  }).then(function(clientList) {
392
392
  var urls = clientList.map(function(client) {
393
393
  return (client.url);
394
394
  });
395
- console.log('[1.0.4-2] matching clients:', urls.join(', '));
395
+ console.log('[1.0.5-2] matching clients:', urls.join(', '));
396
396
  });
397
397
  var promise = ClearCaches();
398
398
  if (event.waitUntil)
@@ -602,14 +602,17 @@ closure findIDEtarget(track, name, workerID, naancont, local target) {
602
602
  *
603
603
  */
604
604
 
605
- closure termIDE(track, name, workerID, naancont, local target, connected) {
605
+ closure termIDE(track, name, workerID, naancont, title, local target, connected) {
606
606
  target = findIDEtarget(track, name, workerID, naancont)
607
607
  if target { // new naancont on existing target
608
608
  target.updateController(naancont)
609
+ target.title = title
610
+ track.update(target)
609
611
  return (target)
610
612
  }
611
613
  target = runningExecutors.ExecutorBase(track, "Local", name)
612
614
  target.name = name
615
+ target.title = title
613
616
  target.workerID = workerID
614
617
  target.naancont = naancont
615
618
  connected = []
@@ -756,7 +759,6 @@ closure termIDE(track, name, workerID, naancont, local target, connected) {
756
759
  /*
757
760
  * termInstallVirtualWatcher
758
761
  *
759
- * column positioning: // // !
760
762
  * Install a persistent watcher to note when virtual terminals come and go, and manage their
761
763
  * execution target lifetimes.
762
764
  *
@@ -766,7 +768,7 @@ closure termInstallVirtualWatcher(track, naancont) {
766
768
 
767
769
  function watchVsites(msg, local error, target) {
768
770
  if msg.op == "VsiteOpen" {
769
- `(error, target) = termIDE(track, msg.name, "NaanVsite", msg.naancont)
771
+ `(error, target) = termIDE(track, msg.name, "NaanVsite", msg.naancont, msg.title)
770
772
  target.attention()
771
773
  }
772
774
  else if msg.op == "VsiteClose" {
@@ -314,6 +314,7 @@ closure TrackedScope(track, scope, fs, rootpath, local trope, result) {
314
314
  mimeType = {
315
315
  "css": "text/css",
316
316
  "csv": "text/csv",
317
+ "gif": "image/gif",
317
318
  "htm": "text/html",
318
319
  "html": "text/html",
319
320
  "ico": "image/x-icon",
@@ -39,7 +39,13 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
39
39
  depthlimit: 0
40
40
  }
41
41
  api.psmRemote(params, false, function(error, tree) {
42
- view.fsdata = tree.data
42
+ if error
43
+ debuglog("psmcFsView.data: can't get initial filesystem data:", ErrorString(error))
44
+ else {
45
+ view.fsdata = tree.data
46
+ if rootpath == ""
47
+ rootpath = tree.data.pathsep
48
+ }
43
49
  callback(error, tree.data)
44
50
  })
45
51
  }
@@ -30,6 +30,49 @@ function EncodeQuery(prefix, items, local result, item) {
30
30
  };
31
31
 
32
32
 
33
+ /*
34
+ * ContentTypeFromFileExt
35
+ *
36
+ * Given a filename with extension, return a tuple of the recommended contentType and encoding
37
+ * for that type of data: `(contentType, encoding). Currently the encoding is false for text and
38
+ * "binary" for everything else.
39
+ *
40
+ */
41
+
42
+ function ContentTypeFromFileExt(filepath, local mimeType, encoding) {
43
+ mimeType = {
44
+ "css": "text/css",
45
+ "csv": "text/csv",
46
+ "gif": "image/gif",
47
+ "htm": "text/html",
48
+ "html": "text/html",
49
+ "ico": "image/x-icon",
50
+ "ics": "application/octet-stream",
51
+ "jpeg": "image/jpeg",
52
+ "jpg": "image/jpeg",
53
+ "js": "text/javascript",
54
+ "json": "application/json",
55
+ "mov": "video/mp4",
56
+ "mp3": "audio/mpeg",
57
+ "mp4": "video/mp4",
58
+ "nlg": "text/plain",
59
+ "npk": "application/json",
60
+ "ogg": "video/ogg",
61
+ "svg": "image/svg+xml",
62
+ "text": "text/plain",
63
+ "txt": "text/plain",
64
+ "zip": "application/octet-stream"
65
+ }[JSpath.extname(filepath).substring(1)]
66
+ if !mimeType
67
+ mimeType = "application/octet-stream"
68
+ if mimeType.startsWith("text/")
69
+ mimeType = mimeType.concat("; charset=UTF-8")
70
+ else
71
+ encoding = "binary"
72
+ list(mimeType, encoding)
73
+ };
74
+
75
+
33
76
  /*
34
77
  * UUID
35
78
  *
@@ -125,11 +168,8 @@ function JsLoadScript(libpath, globalID, local scriptTag, fpath) {
125
168
  }
126
169
  js.w.document.body.appendChild(scriptTag)
127
170
  pending.wait()
128
- } else if js.g {
129
- if !libpath.startsWith("/")
130
- fpath = "./".concat(libpath)
131
- jsScripts[libpath] = js.r(fpath) // load in NodeJS context
132
- }
171
+ } else if js.g
172
+ jsScripts[libpath] = js.r(libpath) // load in NodeJS context
133
173
  jsScripts[libpath]
134
174
  };
135
175
 
@@ -260,13 +300,15 @@ EncodeBase64 = false;
260
300
  DecodeBase64 = false;
261
301
  JSONstringify = false;
262
302
  JSONparse = false;
303
+ Uint8ArrayFromString = false;
263
304
 
264
305
  function comrInit(local manifest) {
265
- manifest = `(EncodeQuery, UUID, JsLoadScript, LoadComponentOnDemand, LiveExport, comrInit)
306
+ manifest = `(EncodeQuery, ContentTypeFromFileExt, UUID, JsLoadScript, LoadComponentOnDemand, LiveExport, comrInit)
266
307
 
267
- Naan.module.build(module.id, "nideCommon", closure(modobj, compobj) {
308
+ Naan.module.build(module.id, "common", closure(modobj, compobj) {
268
309
  compobj.manifest = manifest
269
310
  modobj.exports.EncodeQuery = EncodeQuery
311
+ modobj.exports.ContentTypeFromFileExt = ContentTypeFromFileExt
270
312
  modobj.exports.UUID = UUID
271
313
  modobj.exports.JsLoadScript = JsLoadScript
272
314
  modobj.exports.LoadComponentOnDemand = LoadComponentOnDemand
@@ -291,14 +333,18 @@ function comrInit(local manifest) {
291
333
  EncodeURIComponent = wsg.encodeURIComponent
292
334
  DecodeURIComponent = wsg.decodeURIComponent
293
335
  //
294
- // everywhere: Base65
295
- EncodeBase64 = wsg.btoa
296
- DecodeBase64 = wsg.atob
297
- //
298
336
  // everywhere: JSON
299
337
  JSONstringify = wsg.JSON.stringify
300
338
  JSONparse = wsg.JSON.parse
301
339
  //
340
+ // everywhere: Uint8ArrayFromString
341
+ //
342
+ Uint8ArrayFromString = function uint8ArrayFromString(data) {
343
+ wsg.Uint8Array.from(Array.from(data).map(function(letter) {
344
+ letter.charCodeAt(0)
345
+ }))
346
+ }
347
+ //
302
348
  // binaryFrom - convert arbitrary item to binary buffer or text.
303
349
  //
304
350
  function binaryFrom(data) {
@@ -327,18 +373,6 @@ function comrInit(local manifest) {
327
373
  result
328
374
  }
329
375
  //
330
- // base64Format - create base 64 string from binary array
331
- //
332
- function base64Format(data, local blob, reader, pending, result) {
333
- blob = xnew(wsg.Blob, [data])
334
- reader = xnew(wsg.FileReader)
335
- pending = new(nonce)
336
- reader.onload = function(event) { pending.signal(event.target.result) }
337
- reader.readAsDataURL(blob)
338
- result = pending.wait()
339
- result.slice(37)
340
- }
341
- //
342
376
  // DecodeBase64url - decode base64url to original string
343
377
  // See https://en.wikipedia.org/wiki/Base64 for details on variants
344
378
  //
@@ -350,6 +384,31 @@ function comrInit(local manifest) {
350
384
  // For browser windows and web workers
351
385
  //
352
386
  if js.w || js.s {
387
+ //
388
+ // base64Format - create base 64 string from binary array
389
+ //
390
+ function browserBase64Format(data, local blob, reader, pending, result) {
391
+ blob = xnew(wsg.Blob, [data])
392
+ reader = xnew(wsg.FileReader)
393
+ pending = new(nonce)
394
+ reader.onload = function(event) { pending.signal(event.target.result) }
395
+ reader.readAsDataURL(blob)
396
+ result = pending.wait()
397
+ result.slice(37)
398
+ }
399
+ //
400
+ // binary to Base64
401
+ EncodeBase64 = function browserEncodeBase64(data) {
402
+ if xobject(data)
403
+ browserBase64Format(data)
404
+ else
405
+ wsg.btoa(data)
406
+ }
407
+ //
408
+ // Base64 to binary
409
+ DecodeBase64 = function browserDecodeBase64(data) {
410
+ wsg.atob(data)
411
+ }
353
412
  //
354
413
  // MD5 functions
355
414
  JsLoadScript("frameworks/browser/spark-md5/spark-md5.min.js", "SparkMD5")
@@ -373,7 +432,7 @@ function comrInit(local manifest) {
373
432
  throw(Error("crypto functions unavailable"))
374
433
  data = binaryFrom(data)
375
434
  if string(data)
376
- data = xnew(TextEncoder).encode(data)
435
+ data = Uint8ArrayFromString(data)
377
436
  `(error, result) = await(wsg.crypto.subtle.digest(algo, data))
378
437
  if error
379
438
  throw(Error("crypto digest failed", error))
@@ -392,7 +451,7 @@ function comrInit(local manifest) {
392
451
  //
393
452
  // HashSHA-256 in base64
394
453
  HashSHA256_base64 = function browserSHA256_base64(data) {
395
- base64Format(browserDigest(data, "SHA-256"))
454
+ browserBase64Format(browserDigest(data, "SHA-256"))
396
455
  }
397
456
  //
398
457
  // random bytes as UInt8Array - use toint() for integer
@@ -405,6 +464,16 @@ function comrInit(local manifest) {
405
464
  // For NodeJS
406
465
  //
407
466
  if js.g {
467
+ //
468
+ // binary to Base64
469
+ EncodeBase64 = function nodejsEncodeBase64(data) {
470
+ wsg.Buffer.from(data, "binary").toString("base64")
471
+ }
472
+ //
473
+ // Base64 to binary
474
+ DecodeBase64 = function nodejsDecodeBase64(data) {
475
+ wsg.Buffer.from(data, "base64").toString("binary")
476
+ }
408
477
  if !crypto
409
478
  crypto = js.r("crypto")
410
479
  if crypto {
@@ -456,6 +525,7 @@ function comrInit(local manifest) {
456
525
  modobj.exports.JSONparse = JSONparse
457
526
  modobj.exports.JsonStringify = JsonStringify
458
527
  modobj.exports.JsonParse = JsonParse
528
+ modobj.exports.Uint8ArrayFromString = Uint8ArrayFromString
459
529
  modobj.exports.DecodeBase64url = DecodeBase64url
460
530
  modobj.exports.HashMD5 = HashMD5
461
531
  modobj.exports.HashMD5_base64 = HashMD5_base64
@@ -125,6 +125,7 @@ function prefsInit(local manifest) {
125
125
  Naan.module.build(module.id, "preferences", function(modobj, compobj) {
126
126
  require("../common/common.nlg")
127
127
  compobj.manifest = manifest
128
+ updateExports()
128
129
  })
129
130
 
130
131
  module.exports.Preferences = Preferences
@@ -93,5 +93,6 @@ function wachInit(local manifest) {
93
93
  require("./common.nlg")
94
94
  compobj.manifest = manifest
95
95
  module.exports.Watchable = Watchable
96
+ updateExports()
96
97
  })
97
98
  } ();
@@ -0,0 +1,119 @@
1
+ /*
2
+ * https_node.nlg
3
+ *
4
+ * Https operations for NodeJS.
5
+ *
6
+ * column positioning: // // !
7
+ *
8
+ * Copyright (c) 2021-2022 by Richard C. Zulch
9
+ *
10
+ */
11
+
12
+
13
+ /*
14
+ * HttpsApiRequest
15
+ *
16
+ * Perform an API request from in NodeJS. This operates the same as HttpsApiRequest for browsers.
17
+ *
18
+ * Options:
19
+ * {
20
+ * method: <string> // HTTP method (defaults to GET/PUT)
21
+ * query: <dictionary> // query variables added to the URL
22
+ * putdata: <data> // data to put
23
+ * contentType: <string> // sets Content-Type header, otherwise auto-determined
24
+ * range: <string> // sets range header
25
+ * headers: [`(key, value)] // add header(s) to the request, overriding defaults
26
+ * }
27
+ *
28
+ */
29
+
30
+ closure HttpsApiRequest(url, options, local urlq, reqOptions, putdata, item, pending, chunks, request) {
31
+ if options.query
32
+ urlq = url.concat(EncodeQuery("?", options.query))
33
+ else
34
+ urlq = url
35
+ putdata = options.putdata
36
+ reqOptions = { }
37
+ if options.method
38
+ reqOptions.method = options.method
39
+ else if putdata
40
+ reqOptions.method = "POST"
41
+ else
42
+ reqOptions.method = "GET"
43
+ reqOptions.headers = { }
44
+ if putdata {
45
+ if options.contentType
46
+ reqOptions.headers['Content-Type'] = options.contentType
47
+ else if jsTypedArray(options.putdata)
48
+ reqOptions.headers['Content-Type'] = "application/octet-stream"
49
+ else if member(typeof(options.putdata), `(dictionary, array, xobject)) {
50
+ reqOptions.headers['Content-Type'] = "application/json"
51
+ `(error, putdata) = JsonStringify(options.putdata)
52
+ if error
53
+ return (list(Error("HttpsApiRequest encode:", url)))
54
+ }
55
+ fetchOptions.body = putdata
56
+ }
57
+ if array(options.headers)
58
+ for item in options.headers
59
+ reqOptions.headers[item.0] = item.1
60
+ pending = new(nonce)
61
+ chunks = []
62
+ request = nodeHttps.request(url, reqOptions, function (response) {
63
+ if response.statusCode < 200 || response.statusCode >= 300 {
64
+ pending.signal(list(Error("HttpsApiRequest statusCode:", url, response.statusCode, {
65
+ status: response.statusCode
66
+ })))
67
+ return
68
+ }
69
+ response.on("data", function (chunk) {
70
+ chunks.push(chunk)
71
+ })
72
+ response.on("end", function (local content, error) {
73
+ content = Buffer.concat(chunks)
74
+ if response.complete {
75
+ if response.headers["content-type"].startsWith("application/json") {
76
+ `(error, content) = JsonParse(content.toString())
77
+ if error
78
+ error = Error("HttpsApiRequest decode:", url, error)
79
+ else
80
+ content = new(content)
81
+ if array(content) { // deencapsulate to get API result
82
+ content = totuple(content)
83
+ error = content.0
84
+ content = content.1
85
+ }
86
+ }
87
+ }
88
+ else
89
+ error = Error("HttpsApiRequest terminated prematurely:", url)
90
+ pending.signal(list(error, content))
91
+ })
92
+ })
93
+ request.on("error", function(error) {
94
+ error = Error("HttpsApiRequest failed:", url, error)
95
+ pending.signal(list(error))
96
+ })
97
+ if data
98
+ request.write(data)
99
+ request.end()
100
+ pending.wait()
101
+ };
102
+
103
+
104
+ /*
105
+ * https_nodeInit
106
+ *
107
+ * Initialize HTTPS request operations for NodeJS.
108
+ *
109
+ */
110
+
111
+ function https_nodeInit(local manifest) {
112
+ manifest = `(HttpsGetJson, HttpsPutJson, https_nodeInit)
113
+
114
+ Naan.module.build(module.id, "https_request", function(modobj, compobj) {
115
+ require("./node.nlg")
116
+ compobj.manifest = manifest
117
+ modobj.exports.HttpsApiRequest = HttpsApiRequest
118
+ })
119
+ }();
@@ -75,6 +75,7 @@ function nodrInit(local manifest) {
75
75
  fs = js.r("fs")
76
76
  os = js.r("os")
77
77
  stream = js.r("stream")
78
+ nodeHttps = js.r("https")
78
79
  }()
79
80
  module.reload = nodrReload
80
81
  })