@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.
- package/LICENSE.md +1 -1
- package/README.md +8 -6
- package/bin/index.js +2 -2
- package/dist/env_web.js +25 -5
- package/dist/naan.min.js +4 -4
- package/frameworks/browser/https_request.nlg +120 -0
- package/frameworks/browser/sworker.js +19 -19
- package/frameworks/browser/terminals.nlg +5 -3
- package/frameworks/browser/workers.nlg +1 -0
- package/frameworks/client/psm_client.nlg +7 -1
- package/frameworks/common/common.nlg +95 -25
- package/frameworks/common/preferences.nlg +1 -0
- package/frameworks/common/watching.nlg +1 -0
- package/frameworks/node/https_request.nlg +119 -0
- package/frameworks/node/node.nlg +1 -0
- package/frameworks/project/proj_cliser.nlg +11 -3
- package/frameworks/project/proj_console.nlg +13 -4
- package/frameworks/project/proj_folder.nlg +10 -1
- package/frameworks/project/proj_lambda.nlg +13 -4
- package/frameworks/project/proj_static.nlg +11 -3
- package/frameworks/project/projects.nlg +80 -15
- package/frameworks/running/executors.nlg +1 -0
- package/lib/browser/env_web.js +27 -7
- package/lib/core/naanlib.js +4 -4
- package/package.json +1 -1
- package/plugins/serviceAws/aws/aws-sdk-node.min.js +2 -0
- package/plugins/serviceAws/aws/aws-sdk.min.js +2 -88
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +7 -6
- package/plugins/serviceAws/aws_dynamo.nlg +127 -44
- package/plugins/serviceAws/aws_lambda.nlg +11 -4
- package/plugins/serviceAws/aws_s3.nlg +44 -14
- package/plugins/serviceAws/dbt_aws.nlg +29 -36
- package/plugins/serviceAws/psm_aws.nlg +21 -16
- package/plugins/serviceAws/serviceAws.nlg +6 -4
- package/test/harness.nlg +3 -1
- package/test/test_01_core.nlg +5 -5
- package/test/test_02_context.nlg +4 -4
- package/test/test_03_jsinterop.nlg +9 -3
- 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.
|
|
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
|
|
78
|
-
|
|
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.
|
|
93
|
-
if (pubVersion != "1.0.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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" {
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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, "
|
|
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 =
|
|
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
|
-
|
|
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
|
|
@@ -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
|
+
}();
|