@naanlang/naan 1.4.4 → 1.6.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 (61) hide show
  1. package/LICENSE.md +2 -2
  2. package/README.md +4 -4
  3. package/bin/index.js +25 -3
  4. package/dist/env_web.js +164 -22
  5. package/dist/naan.min.js +5 -5
  6. package/frameworks/browser/browser.nlg +2 -2
  7. package/frameworks/browser/https_request.nlg +2 -2
  8. package/frameworks/browser/sworker.js +28 -26
  9. package/frameworks/browser/terminals.nlg +342 -700
  10. package/frameworks/browser/worker.nlg +255 -0
  11. package/frameworks/browser/workers.nlg +5 -5
  12. package/frameworks/browser/ws_client.nlg +15 -10
  13. package/frameworks/client/apiclient.nlg +204 -19
  14. package/frameworks/client/client.nlg +22 -2
  15. package/frameworks/client/psm_client.nlg +12 -3
  16. package/frameworks/client/relaycon.nlg +87 -161
  17. package/frameworks/common/events.nlg +101 -0
  18. package/frameworks/common/repltools.nlg +80 -1
  19. package/frameworks/node/apiserver.nlg +39 -246
  20. package/frameworks/node/filesystem.nlg +39 -12
  21. package/frameworks/node/gitter.nlg +9 -7
  22. package/frameworks/node/http_request.nlg +34 -13
  23. package/frameworks/node/https_request.nlg +8 -3
  24. package/frameworks/node/node.nlg +2 -0
  25. package/frameworks/node/pty.nlg +346 -0
  26. package/frameworks/node/shell.nlg +4 -4
  27. package/frameworks/node/worker.nlg +409 -539
  28. package/frameworks/node/ws_client.nlg +2 -2
  29. package/frameworks/project/build.nlg +1 -1
  30. package/frameworks/project/projects.nlg +2 -1
  31. package/frameworks/running/debugnub.nlg +17 -4
  32. package/frameworks/running/executors.nlg +27 -274
  33. package/frameworks/running/instances.nlg +393 -0
  34. package/frameworks/running/remote_req.nlg +143 -0
  35. package/frameworks/running/remote_res.nlg +89 -0
  36. package/frameworks/running/taskexec.nlg +2 -2
  37. package/frameworks/service/imp.nlg +736 -0
  38. package/frameworks/service/model.nlg +71 -0
  39. package/frameworks/service/nubnode.nlg +105 -0
  40. package/frameworks/service/nubweb.nlg +106 -0
  41. package/frameworks/service/service.nlg +28 -0
  42. package/frameworks/storage/dbt_pouch.nlg +26 -13
  43. package/frameworks/storage/psm.nlg +39 -5
  44. package/frameworks/storage/psm_dbtables.nlg +10 -2
  45. package/lib/browser/env_web.js +171 -29
  46. package/lib/browser/env_webworker.js +91 -5
  47. package/lib/core/naanlib.js +5 -5
  48. package/lib/env_node.js +184 -8
  49. package/lib/env_nodeworker.js +74 -1
  50. package/package.json +1 -1
  51. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +2 -1
  52. package/plugins/serviceAws/aws_dynamo.nlg +1 -0
  53. package/plugins/serviceAws/aws_s3.nlg +3 -3
  54. package/plugins/serviceAws/aws_sqs.nlg +3 -1
  55. package/plugins/serviceAws/aws_utils.nlg +3 -1
  56. package/plugins/serviceAws/dbt_aws.nlg +22 -20
  57. package/plugins/serviceAws/psm_aws.nlg +2 -1
  58. package/plugins/serviceNexara/speechrec.nlg +10 -6
  59. package/test/test_02_context.nlg +24 -1
  60. package/test/test_03_jsinterop.nlg +32 -3
  61. package/plugins/serviceGC/russian_trusted_root_ca_pem.crt +0 -33
package/lib/env_node.js CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2024 by Richard C. Zulch
9
+ * Copyright (c) 2017-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -49,6 +49,7 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
49
49
  if (typeof(options) != 'object')
50
50
  options = { };
51
51
  var repl = require('repl');
52
+ const { Transform } = require('node:stream');
52
53
  var replServer;
53
54
  var process = require('process');
54
55
  var Naan = require('./core/naanlib');
@@ -62,8 +63,16 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
62
63
  if (outEnable && process.env["RUNKIT_ENDPOINT_URL"])
63
64
  useConsoleOut = true; // use console.log for output in RunKit
64
65
  var dontSaveUntilWorking; // true when state loaded, must be reset to save state again
66
+ var dontSave; // true to avoid saving, i.e. in debugger
65
67
  var prefs = { };
66
68
 
69
+ // kpMode
70
+ // 0: normal (readline & echo)
71
+ // 1: readline, but echo CR only
72
+ // 2: readline, but don't echo
73
+ // 3: raw, no echo or readline, but key-events
74
+ var kpMode = 0;
75
+
67
76
  //==========================================================================
68
77
  // API
69
78
  //--------------------------------------------------------------------------
@@ -112,7 +121,27 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
112
121
 
113
122
  if (process.stdin.isTTY)
114
123
  { // must have TTY for local REPL
115
- replServer = repl.start({ prompt: '', eval: myEval});
124
+ const replOutputStream = new Transform({
125
+ writableObjectMode: true,
126
+ readableObjectMode: true,
127
+ transform(chunk, encoding, callback) {
128
+ if (kpMode > 0) {
129
+ const str = chunk.toString();
130
+ if (kpMode != 1 || str != "\r\n")
131
+ return callback(); // output goes to the bit bucket
132
+ }
133
+ return callback(null, chunk); // normal output
134
+ }
135
+ });
136
+ replOutputStream.pipe(process.stdout); // output filter for raw and no-echo
137
+
138
+ replServer = repl.start({
139
+ prompt: '',
140
+ eval: myEval,
141
+ input: process.stdin,
142
+ output: replOutputStream,
143
+ terminal: true
144
+ });
116
145
 
117
146
  replServer.on('line', function(cmd) { // process raw command line
118
147
  if (options.replDisable)
@@ -122,7 +151,21 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
122
151
  naanlib.textLine(cmd + "\n");
123
152
  }
124
153
  });
125
-
154
+
155
+ const origListenersData = process.stdin.listeners('data');
156
+ process.stdin.removeAllListeners('data');
157
+
158
+ process.stdin.on('data', (data) => {
159
+ if (kpMode == 3) {
160
+ servSelf.ioctl_event("raw-key", { // raw mode
161
+ key: data.toString(),
162
+ origin: 0 // assume keystroke
163
+ });
164
+ return;
165
+ }
166
+ origListenersData.forEach(listener => listener(data));
167
+ });
168
+
126
169
  //
127
170
  // Hook the ^C interrupt
128
171
  //
@@ -131,8 +174,10 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
131
174
  if (options.replDisable) {
132
175
  console.log("^C");
133
176
  process.exit();
134
- } else
177
+ } else {
178
+ setKpMode(0);
135
179
  naanlib.escape();
180
+ }
136
181
  };
137
182
 
138
183
  //
@@ -142,6 +187,17 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
142
187
  replServer.on('exit', function() {
143
188
  process.exit();
144
189
  });
190
+
191
+ //
192
+ // Process resize notifications
193
+ //
194
+
195
+ process.stdout.on('resize', () => {
196
+ servSelf.ioctl_event("term-resize", {
197
+ cols: process.stdout.columns,
198
+ rows: process.stdout.rows
199
+ });
200
+ });
145
201
  }
146
202
 
147
203
  //
@@ -177,6 +233,43 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
177
233
  textToRemoteTerm(text);
178
234
  }
179
235
  });
236
+
237
+ //
238
+ // setKpMode
239
+ //
240
+
241
+ function setKpMode(mode) {
242
+ if (!replServer)
243
+ return;
244
+ kpMode = mode;
245
+ process.stdin.resume();
246
+ }
247
+
248
+ //
249
+ // repl_keystroke
250
+ //
251
+
252
+ function repl_keystroke(str) {
253
+ if (replServer)
254
+ replServer.write(str, null);
255
+ }
256
+
257
+ //
258
+ // repl_ioctl
259
+ //
260
+
261
+ this.repl_ioctl = function repl_ioctl(op, arg) {
262
+ if (op == "sane")
263
+ setKpMode(0);
264
+ else if (op == "raw")
265
+ setKpMode(arg ? 3 : 0);
266
+ else if (op == "keystroke")
267
+ repl_keystroke(arg);
268
+ else if (op == "echo") {
269
+ if (arg >= 0 && arg <= 2)
270
+ setKpMode(arg);
271
+ }
272
+ };
180
273
 
181
274
 
182
275
  //==========================================================================
@@ -196,7 +289,7 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
196
289
  //
197
290
  // Detach
198
291
  //
199
- // Detach the terminal from the interpreter.
292
+ // Detach the terminal from our interpreter.
200
293
  //
201
294
 
202
295
  this.Detach = function(tops) {
@@ -226,7 +319,8 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
226
319
  if (termops)
227
320
  {
228
321
  setTimeout(function () {
229
- termops.messageout(data);
322
+ if (termops)
323
+ termops.messageout(data);
230
324
  }, 1);
231
325
  }
232
326
  return (data);
@@ -242,7 +336,8 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
242
336
  if (termops)
243
337
  {
244
338
  setTimeout(function () {
245
- termops.debugout(data);
339
+ if (termops)
340
+ termops.debugout(data);
246
341
  }, 1);
247
342
  }
248
343
  return (data);
@@ -277,6 +372,10 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
277
372
  naanlib.textLine(msg.text); // keyboard text from terminal
278
373
  }, 1);
279
374
  }
375
+ else if (msg.id == "typed")
376
+ {
377
+ echoTyped(msg.text);
378
+ }
280
379
  else if (msg.id == "targetin")
281
380
  {
282
381
  setTimeout(function () {
@@ -291,6 +390,8 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
291
390
  debugListener(msg.data); // received a debugger message
292
391
  }, 1);
293
392
  }
393
+ else if (msg.id == "ioctl-event")
394
+ this.ioctl_event(msg.msg, msg.arg);
294
395
  };
295
396
 
296
397
  // textToRemoteTerm
@@ -301,7 +402,8 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
301
402
  if (termops)
302
403
  {
303
404
  setTimeout(function () {
304
- termops.textout(text);
405
+ if (termops)
406
+ termops.textout(text);
305
407
  }, 1);
306
408
  }
307
409
  }
@@ -323,6 +425,68 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
323
425
  }
324
426
  }, 1000);
325
427
 
428
+ //==========================================================================
429
+ // ioctl terminal control
430
+ //--------------------------------------------------------------------------
431
+
432
+ //
433
+ // ioctl_event
434
+ //
435
+ // Events incoming from terminal.
436
+ //
437
+
438
+ this.ioctl_event = function ioctl_event(msg, arg) {
439
+ if (listeners[msg])
440
+ listeners[msg].forEach(function(proc) {
441
+ setTimeout(function () {
442
+ proc(msg, arg);
443
+ }, 1);
444
+ });
445
+ };
446
+
447
+ //
448
+ // ioctl_add_listener
449
+ // ioctl_remove_listener
450
+ //
451
+ // Add a listener for a terminal event.
452
+ //
453
+
454
+ var listeners = { };
455
+
456
+ this.ioctl_add_listener = function ioctl_add_listener(msg, proc) {
457
+ if (typeof(msg) != "string" || typeof(proc) != "function")
458
+ return (false);
459
+ this.ioctl_remove_listener(msg, proc);
460
+ if (!listeners[msg])
461
+ listeners[msg] = [];
462
+ listeners[msg].push(proc);
463
+ return (true);
464
+ };
465
+
466
+ this.ioctl_remove_listener = function ioctl_remove_listener(msg, proc) {
467
+ if (typeof(msg) != "string" || typeof(proc) != "function")
468
+ return (false);
469
+ if (listeners[msg]) {
470
+ var index = listeners[msg].indexOf(proc);
471
+ if (index >= 0)
472
+ listeners[msg].splice(index, 1);
473
+ }
474
+ return (true);
475
+ };
476
+
477
+ //
478
+ // ioctl
479
+ //
480
+ // Control of terminals (and their controller.)
481
+ //
482
+
483
+ this.ioctl = function ioctl(op, arg) {
484
+ setTimeout(function () {
485
+ servSelf.repl_ioctl(op, arg);
486
+ if (termops)
487
+ termops.ioctl(op, arg);
488
+ }, 1);
489
+ };
326
490
 
327
491
  //==========================================================================
328
492
  // State load/save
@@ -352,6 +516,16 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
352
516
  dontSaveUntilWorking = false;
353
517
  };
354
518
 
519
+ //
520
+ // Saving
521
+ //
522
+ // Turn state saving on or off; on by default.
523
+ //
524
+
525
+ this.Saving = function Saving(onOff) {
526
+ dontSave = !onOff;
527
+ };
528
+
355
529
  // MakeState
356
530
  //
357
531
  // Save our state into a new object.
@@ -359,6 +533,8 @@ exports.NaanNodeREPL = function NaanNodeREPL(options) {
359
533
  this.MakeState = function MakeState() {
360
534
  if (dontSaveUntilWorking)
361
535
  return (false); // didn't get far enough to call Working()
536
+ if (dontSave)
537
+ return (false); // not saving right now
362
538
  var statedoc = {};
363
539
  statedoc.curversion = kStateCurrentVersion;
364
540
  statedoc.firstver = kStateFirstVersion;
@@ -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-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -63,6 +63,7 @@ exports.NaanWorkerActivate = function NaanWorkerActivate(cbReady) {
63
63
  workSelf.anaan = naanlib.js.n;
64
64
  naanlib.js.t = workSelf;
65
65
  naanlib.js.k = threads;
66
+ var workerMetadata = { };
66
67
 
67
68
 
68
69
  //==========================================================================
@@ -84,7 +85,74 @@ exports.NaanWorkerActivate = function NaanWorkerActivate(cbReady) {
84
85
  this.textCommand = function textCommand(cmd) { // send a command
85
86
  naanlib.textLine(cmd);
86
87
  };
88
+
89
+ this.metadata = function metadata() { // our creation metadata
90
+ return (workerMetadata);
91
+ };
92
+
93
+ this.msgPort = msgPort; // our msgPort
94
+
95
+ //==========================================================================
96
+ // ioctl terminal control
97
+ //--------------------------------------------------------------------------
98
+
99
+ //
100
+ // ioctl_event
101
+ //
102
+ // Events incoming from terminal.
103
+ //
104
+
105
+ workSelf.ioctl_event = function ioctl_event(msg, arg) {
106
+ if (listeners[msg])
107
+ listeners[msg].forEach(function(proc) {
108
+ proc(msg, arg);
109
+ });
110
+ };
111
+
112
+ //
113
+ // ioctl_add_listener
114
+ // ioctl_remove_listener
115
+ //
116
+ // Add a listener for a terminal event.
117
+ //
118
+
119
+ var listeners = { };
120
+
121
+ workSelf.ioctl_add_listener = function ioctl_add_listener(msg, proc) {
122
+ if (typeof(msg) != "string" || typeof(proc) != "function")
123
+ return (false);
124
+ workSelf.ioctl_remove_listener(msg, proc);
125
+ if (!listeners[msg])
126
+ listeners[msg] = [];
127
+ listeners[msg].push(proc);
128
+ return (true);
129
+ };
130
+
131
+ workSelf.ioctl_remove_listener = function ioctl_remove_listener(msg, proc) {
132
+ if (typeof(msg) != "string" || typeof(proc) != "function")
133
+ return (false);
134
+ if (listeners[msg]) {
135
+ var index = listeners[msg].indexOf(proc);
136
+ if (index >= 0)
137
+ listeners[msg].splice(index, 1);
138
+ }
139
+ return (true);
140
+ };
87
141
 
142
+ //
143
+ // ioctl
144
+ //
145
+ // Control of terminals (and their controller.)
146
+ //
147
+
148
+ workSelf.ioctl = function ioctl(op, arg) {
149
+ msgPort.postMessage({
150
+ id: "ioctl",
151
+ op: op,
152
+ arg: arg
153
+ });
154
+ return (undefined);
155
+ };
88
156
 
89
157
  //==========================================================================
90
158
  // NodeJS Worker Terminal Interface
@@ -162,10 +230,13 @@ exports.NaanWorkerActivate = function NaanWorkerActivate(cbReady) {
162
230
  naanlib.escape(); // interrupt request from terminal
163
231
  else if (msg.id == "keyline")
164
232
  naanlib.textLine(msg.text); // keyboard text from terminal
233
+ else if (msg.id == "typed")
234
+ echoTyped(msg.text);
165
235
  else if (msg.id == "start")
166
236
  { // start execution with optional state
167
237
  workSelf.workerID = msg.workerID;
168
238
  workSelf.workerGUID = msg.workerGUID;
239
+ workerMetadata = msg.metadata || { };
169
240
  if (typeof(__dirname) !== "undefined")
170
241
  naanlib.js.h = naanlib.js.d; // set host directory path
171
242
  if (msg.dirpath)
@@ -197,6 +268,8 @@ exports.NaanWorkerActivate = function NaanWorkerActivate(cbReady) {
197
268
  if (targetReceiver)
198
269
  targetReceiver(msg.data);
199
270
  }
271
+ else if (msg.id == "ioctl-event")
272
+ workSelf.ioctl_event(msg.msg, msg.arg);
200
273
  });
201
274
 
202
275
  naanlib.banner();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naanlang/naan",
3
- "version": "1.4.4",
3
+ "version": "1.6.0",
4
4
  "author": "Richard C. Zulch",
5
5
  "description": "Naan™ software platform",
6
6
  "main": "./lib/core/naanlib.js",
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2021-2023 by Richard C. Zulch
9
+ * Copyright (c) 2021-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -19,6 +19,7 @@
19
19
  */
20
20
 
21
21
  closure CloudWatchLogs(local cwlogs) {
22
+ global(awsSDK)
22
23
  cwlogs = new(object, this)
23
24
 
24
25
  //
@@ -1040,6 +1040,7 @@ closure DynaTable(dyna, tablename, options, local table) {
1040
1040
  params = {
1041
1041
  TableName: tablename
1042
1042
  }
1043
+ output = []
1043
1044
  if options.index
1044
1045
  params.IndexName = options.index
1045
1046
  if options.filter {
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2024 by Richard C. Zulch
9
+ * Copyright (c) 2020-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -22,6 +22,7 @@
22
22
  */
23
23
 
24
24
  closure S3bucket(s3, name, bucketOptions, local bucket) {
25
+ global()
25
26
  bucket = new(object, this)
26
27
  bucket.name = name
27
28
 
@@ -83,8 +84,6 @@ closure S3bucket(s3, name, bucketOptions, local bucket) {
83
84
  // }
84
85
  //
85
86
  bucket.put = closure put(key, data, options, local params, pending) {
86
- if !contentType
87
- contentType = "application/octet-stream"
88
87
  params = {
89
88
  Bucket: bucket.name
90
89
  Key: key
@@ -246,6 +245,7 @@ closure S3bucket(s3, name, bucketOptions, local bucket) {
246
245
  */
247
246
 
248
247
  closure S3(local s3) {
248
+ global(awsSDK)
249
249
  s3 = new(object, this)
250
250
 
251
251
  //
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2023 by Richard C. Zulch
9
+ * Copyright (c) 2023-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -19,6 +19,7 @@
19
19
  */
20
20
 
21
21
  closure SqsMQ(sqs, queueUrl, local sqsq) {
22
+ global()
22
23
  sqsq = new(object, this)
23
24
 
24
25
  //
@@ -55,6 +56,7 @@ closure SqsMQ(sqs, queueUrl, local sqsq) {
55
56
  */
56
57
 
57
58
  closure SQS(local sqs) {
59
+ global(awsSDK)
58
60
  sqs = new(object, this)
59
61
 
60
62
  //
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2021 by Richard C. Zulch
9
+ * Copyright (c) 2021-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -22,6 +22,7 @@
22
22
  */
23
23
 
24
24
  closure queryPager(apiobject, procname, params, xargs, doneCB, local pending, looping, result) {
25
+ global()
25
26
  if !apiobject[procname]
26
27
  return (list(Error("queryPager method undefined:", procname)))
27
28
  pending = new(nonce)
@@ -55,6 +56,7 @@ closure queryPager(apiobject, procname, params, xargs, doneCB, local pending, lo
55
56
  */
56
57
 
57
58
  function QueryPager args {
59
+ global()
58
60
  closure(local apiobject, procname, params, xargs, doneCB) {
59
61
  apiobject = pop(args)
60
62
  procname = pop(args)
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2024 by Richard C. Zulch
9
+ * Copyright (c) 2020-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -22,6 +22,7 @@
22
22
  */
23
23
 
24
24
  closure dawsBucket(s3b, local bucket, s3) {
25
+ global(JSpath)
25
26
  bucket = new(object, this)
26
27
  s3 = s3b.s3
27
28
  bucket.name = s3b.bucketName
@@ -311,6 +312,7 @@ closure dawsBucket(s3b, local bucket, s3) {
311
312
  */
312
313
 
313
314
  closure dawsTable(database, path, tableOptions, local table) {
315
+ global(js, TextDecoder)
314
316
  table = new(object, this)
315
317
  table.type = database.type
316
318
  table.db = database
@@ -411,9 +413,10 @@ closure dawsTable(database, path, tableOptions, local table) {
411
413
 
412
414
  // add
413
415
  //
414
- // Add a new record to the table with optional metadata. This will fail if the key already
415
- // exists. The metadata is stored with the record and cannot be changed without calling update.
416
- // Metadata keys cannot begin with underscore ("_").
416
+ // Add a new record to the table with options. This will fail if the key already exists. Optional
417
+ // metadata is stored with the record and cannot be changed without calling update. Metadata keys
418
+ // cannot begin with underscore ("_"). If optional cacheControl is not specified then the default
419
+ // tableOptions.cacheControl is used.
417
420
  //
418
421
  // The returned document, which can be used with update, has the following keys:
419
422
  // key - the key name of the record
@@ -421,26 +424,25 @@ closure dawsTable(database, path, tableOptions, local table) {
421
424
  // md5 - the MD5 hash of the content
422
425
  // <...> - the various metadata keys
423
426
 
424
- table.add = closure add(key, content, metadata, callback, local id, doc) {
427
+ table.add = closure add(key, content, options, callback, local id, doc) {
425
428
  if !callback
426
- return (syncAdapter(add, key, content, metadata))
429
+ return (syncAdapter(add, key, content, options))
427
430
  id = makeID(key)
428
431
  if !string(id)
429
- return (asyncResult(callback, id)) // error from makeID
430
- if metadata && !dictionary(metadata)
432
+ return (asyncResult(callback, id)) // error from makeID
433
+ if options.metadata && !dictionary(options.metadata)
431
434
  return (asyncResult(callback, Error("invalid arguments")))
432
- if metadata
433
- doc = new(metadata) // start with metadata
435
+ if options.metadata
436
+ doc = new(options.metadata) // start with metadata
434
437
  else
435
438
  doc = { }
436
439
  doc.key = key
437
440
  doc.id = id
438
441
  if content
439
442
  doc.content = content
440
- metadata = metadata2s3(metadata) // filter out any invalid metadata
441
443
  database.bucket.put(id, content, {
442
- metadata: metadata
443
- cacheControl: tableOptions.cacheControl
444
+ metadata: metadata2s3(options.metadata) // filter metadata for s3
445
+ cacheControl: options.cacheControl || tableOptions.cacheControl
444
446
  }, function(error, resp) {
445
447
  if error
446
448
  error = Error("add failed", error, id, { status: error.status })
@@ -453,17 +455,17 @@ closure dawsTable(database, path, tableOptions, local table) {
453
455
 
454
456
  // update
455
457
  //
456
- // Update a record in the table using the document previously returned by add or get.
458
+ // Update a record in the table using the document previously returned by add or get. Specify
459
+ // options to update those values, otherwise existing/default values are used.
457
460
 
458
- table.update = closure update(doc, callback, local metadata) {
461
+ table.update = closure update(doc, options, callback) {
459
462
  if !callback
460
- return (syncAdapter(update, doc))
463
+ return (syncAdapter(update, doc, options))
461
464
  if !doc._id || !doc._id.startsWith(table.s3prefix) || !doc._md5
462
465
  return (asyncResult(callback, Error("invalid argument")))
463
- metadata = metadata2s3(doc)
464
466
  database.bucket.put(doc._id, doc.content, {
465
- metadata: metadata
466
- cacheControl: tableOptions.cacheControl
467
+ metadata: metadata2s3(options.metadata || doc)
468
+ cacheControl: options.cacheControl || tableOptions.cacheControl
467
469
  }, function(error, resp) {
468
470
  if error
469
471
  error = Error("update failed", error, doc._id, { status: error.status })
@@ -519,7 +521,7 @@ closure dawsTable(database, path, tableOptions, local table) {
519
521
  resp.content = readableStreamToArrayBuffer(resp.content)
520
522
  else if jsTypedArray(resp.content)
521
523
  resp.content = xnew(TextDecoder, "utf-8").decode(resp.content)
522
- else if jsInstanceOf(resp.content, js.w.ReadableStream)
524
+ else if jsInstanceOf(resp.content, js.w.ReadableStream) // for browsers only
523
525
  resp.content = xnew(TextDecoder, "utf-8").decode(readableStreamToArrayBuffer(resp.content))
524
526
  resp._id = id }
525
527
  callback(error, resp)
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2020-2024 by Richard C. Zulch
9
+ * Copyright (c) 2020-2025 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -19,6 +19,7 @@
19
19
  */
20
20
 
21
21
  closure psmaConnector(psm, local connClassID, connector, watch) {
22
+ global(awsSDK)
22
23
  connClassID = "S3DB"
23
24
  require("./dbt_aws.nlg")
24
25
  connector = new(object, this)