This is an automated email from the ASF dual-hosted git repository.

ronny pushed a commit to branch add-sm-v140
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 677566d1069c6f53566013cab14e72bd6070a702
Author: Jiahui Li <lijiahui...@gmail.com>
AuthorDate: Wed Sep 24 08:06:12 2025 -0500

    Fix config options (#5642)
    
    * Config: `secret` was moved to `[chttpd_auth]` session
    
    * Docs: `changes_timeout` is applicable for `_changes?feed=eventsource`
    
    * [couchdb]: Add `delete_after_rename = true` option
    
    - Update comments for `enable_database_recovery = false`.
    - Add `delete_after_rename = true` option:
      - No ops when `enable_database_recovery = true`.
      - If `true`, delete the database shard files from the `data` directory.
      - If `false`, rename the database shard files and move them to the 
`.delete` directory.
    
    * [fabric]: `attachments_timeout` default should be `600000`
    
    * [view_updater]: Add `queue_memory_cap` and `queue_item_cap`
    
    * [fabric]: Make `all_docs_view_permsg_timeout = 5000` configurable
    
    * Fix typos
---
 rel/overlay/etc/default.ini               |  47 ++--
 src/couch/priv/couch_js/140/help.h        |  80 +++++++
 src/couch/priv/couch_js/140/main.cpp      | 337 ++++++++++++++++++++++++++
 src/couch/priv/couch_js/140/util.cpp      | 380 ++++++++++++++++++++++++++++++
 src/couch/priv/couch_js/140/util.h        |  43 ++++
 src/couch/rebar.config.script             |  15 +-
 src/docs/src/api/database/changes.rst     |   5 +-
 src/dreyfus/src/dreyfus_fabric_group1.erl |   4 +-
 src/dreyfus/src/dreyfus_fabric_group2.erl |   4 +-
 src/fabric/src/fabric_view_all_docs.erl   |   2 +-
 src/fabric/src/fabric_view_changes.erl    |   2 +-
 src/setup/test/t-frontend-setup.sh        |   4 +-
 12 files changed, 893 insertions(+), 30 deletions(-)

diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 63db3f854..db4d37f3e 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -71,11 +71,18 @@ view_index_dir = {{view_index_dir}}
 ;default_engine = couch
 
 ; Enable this to only "soft-delete" databases when DELETE /{db} requests are
-; made. This will place a .recovery directory in your data directory and
-; move deleted databases/shards there instead. You can then manually delete
-; these files later, as desired.
+; made. This will add `.deleted.couch` extension to the database shard files
+; in the data directory. You can then manually delete these files later, as
+; desired.
 ;enable_database_recovery = false
 
+; Applies only when `enable_database_recovery = false`.
+; When DELETE /{db} requests are made:
+; - If `true`, delete the database shard files from the `data` directory.
+; - If `false`, rename the database shard files and move them to the `.delete`
+; directory.
+;delete_after_rename = true
+
 ; Set the maximum size allowed for a partition. This helps users avoid
 ; inadvertently abusing partitions resulting in hot shards. The default
 ; is 10GiB. A value of 0 or less will disable partition size checks.
@@ -116,7 +123,7 @@ view_index_dir = {{view_index_dir}}
 ; When enabled, use cfile parallel reads for all the requests. By default the
 ; setting is "false", so only requests which are configured to bypass the IOQ
 ; would use the cfile parallel reads. If there is enough RAM available for a
-; large file cache and the disks have enough IO bandwith, consider enabling
+; large file cache and the disks have enough IO bandwidth, consider enabling
 ; this setting.
 ;cfile_skip_ioq = false
 
@@ -257,7 +264,7 @@ bind_address = 127.0.0.1
 
 ; Set to false to revert to a previous _bulk_get implementation using single
 ; doc fetches internally. Using batches should be faster, however there may be
-; bugs in the new new implemention, so expose this option to allow reverting to
+; bugs in the new implementation, so expose this option to allow reverting to
 ; the old behavior.
 ;bulk_get_use_batches = true
 
@@ -441,7 +448,8 @@ hash_algorithms = sha256, sha
 ;uuid_prefix_len = 7
 ;request_timeout = 60000
 ;all_docs_timeout = 10000
-;attachments_timeout = 60000
+;all_docs_view_permsg_timeout = 5000
+;attachments_timeout = 600000
 ;view_timeout = infinity
 ;view_permsg_timeout = 3600000
 ;partition_view_timeout = infinity
@@ -468,6 +476,16 @@ hash_algorithms = sha256, sha
 ;update_db = true
 
 ;[view_updater]
+; Configure the queue capacity used during indexing. These settings apply to
+; both the queue between the changes feed and the JS mapper, and between the
+; JS mapper and the disk writer.
+; Whichever limit happens to be hit first is the one that takes effect.
+
+; The maximum queue memory size
+;queue_memory_cap = 100000
+; The maximum queue length
+;queue_item_cap = 500
+
 ;min_writer_items = 100
 ;min_writer_size = 16777216
 
@@ -711,7 +729,7 @@ partitioned||* = true
 ; How much time to wait before retrying after a missing doc exception. This
 ; exception happens if the document was seen in the changes feed, but internal
 ; replication hasn't caught up yet, and fetching document's revisions
-; fails. This a common scenario when source is updated while continuous
+; fails. This is a common scenario when source is updated while continuous
 ; replication is running. The retry period would depend on how quickly internal
 ; replication is expected to catch up. In general this is an optimisation to
 ; avoid crashing the whole replication job, which would consume more resources
@@ -730,7 +748,7 @@ partitioned||* = true
 ;   couch_replicator_auth_session - use _session cookie authentication
 ;   couch_replicator_auth_noop - use basic authentication (previous default)
 ; Currently, the new _session cookie authentication is tried first, before
-; falling back to the old basic authenticaion default:
+; falling back to the old basic authentication default:
 ;auth_plugins = couch_replicator_auth_session,couch_replicator_auth_noop
 
 ; To restore the old behaviour, use the following value:
@@ -758,7 +776,7 @@ partitioned||* = true
 ; priority 0, and would render this algorithm useless. The default value of
 ; 0.98 is picked such that if a job ran for one scheduler cycle, then didn't
 ; get to run for 7 hours, it would still have priority > 0. 7 hours was picked
-; as it was close enought to 8 hours which is the default maximum error backoff
+; as it was close enough to 8 hours which is the default maximum error backoff
 ; interval.
 ;priority_coeff = 0.98
 
@@ -971,12 +989,11 @@ port = {{prometheus_port}}
 
 [custodian]
 ; When set to `true`, force using `[cluster] n` values as the expected n value
-; of of shard copies. In cases where the application prevents creating
-; non-default n databases, this could help detect case where the shard map was
-; altered by hand, or via an external tools, such that it doesn't have the
-; necessary number of copies for some ranges. By default, when the setting is
-; `false`, the expected n value is based on the number of available copies in
-; the shard map.
+; of shard copies. In cases where the application prevents creating non-default
+; n databases, this could help detect case where the shard map was altered by
+; hand, or via an external tools, such that it doesn't have the necessary 
number
+; of copies for some ranges. By default, when the setting is `false`, the
+; expected n value is based on the number of available copies in the shard map.
 ;use_cluster_n_as_expected_n = false
 
 [nouveau]
diff --git a/src/couch/priv/couch_js/140/help.h 
b/src/couch/priv/couch_js/140/help.h
new file mode 100644
index 000000000..28a2f6455
--- /dev/null
+++ b/src/couch/priv/couch_js/140/help.h
@@ -0,0 +1,80 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+#ifndef COUCHJS_HELP_H
+#define COUCHJS_HELP_H
+
+#include "config.h"
+
+static const char VERSION_TEMPLATE[] =
+    "%s - %s (SpiderMonkey %s)\n"
+    "\n"
+    "Licensed under the Apache License, Version 2.0 (the \"License\"); you may 
"
+        "not use\n"
+    "this file except in compliance with the License. You may obtain a copy of"
+        "the\n"
+    "License at\n"
+    "\n"
+    "  http://www.apache.org/licenses/LICENSE-2.0\n";
+    "\n"
+    "Unless required by applicable law or agreed to in writing, software "
+        "distributed\n"
+    "under the License is distributed on an \"AS IS\" BASIS, WITHOUT "
+        "WARRANTIES OR\n"
+    "CONDITIONS OF ANY KIND, either express or implied. See the License "
+        "for the\n"
+    "specific language governing permissions and limitations under the "
+        "License.\n";
+
+static const char USAGE_TEMPLATE[] =
+    "Usage: %s [FILE]\n"
+    "\n"
+    "The %s command runs the %s JavaScript interpreter.\n"
+    "\n"
+    "The exit status is 0 for success or 1 for failure.\n"
+    "\n"
+    "Options:\n"
+    "\n"
+    "  -h          display a short help message and exit\n"
+    "  -V          display version information and exit\n"
+    "  -S SIZE     specify that the runtime should allow at\n"
+    "              most SIZE bytes of memory to be allocated\n"
+    "              default is 64 MiB\n"
+    "  --eval      Enable runtime code evaluation (dangerous!)\n"
+    "\n"
+    "Report bugs at <%s>.\n";
+
+#define BASENAME COUCHJS_NAME
+
+#define couch_version(basename)  \
+    fprintf(                     \
+            stdout,              \
+            VERSION_TEMPLATE,    \
+            basename,            \
+            PACKAGE_STRING,      \
+            get_spidermonkey_version())
+
+#define DISPLAY_VERSION couch_version(BASENAME)
+
+
+#define couch_usage(basename) \
+    fprintf(                                    \
+            stdout,                             \
+            USAGE_TEMPLATE,                     \
+            basename,                           \
+            basename,                           \
+            PACKAGE_NAME,                       \
+            PACKAGE_BUGREPORT)
+
+#define DISPLAY_USAGE couch_usage(BASENAME)
+
+#endif // Included help.h
diff --git a/src/couch/priv/couch_js/140/main.cpp 
b/src/couch/priv/couch_js/140/main.cpp
new file mode 100644
index 000000000..e238654c9
--- /dev/null
+++ b/src/couch/priv/couch_js/140/main.cpp
@@ -0,0 +1,337 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef XP_WIN
+#define NOMINMAX
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <jsapi.h>
+#include <js/CompilationAndEvaluation.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/SourceText.h>
+#include <js/StableStringChars.h>
+#include <js/Warnings.h>
+#include <js/Wrapper.h>
+
+#include "config.h"
+#include "util.h"
+
+static bool enableSharedMemory = true;
+static bool enableToSource = true;
+
+/* The class of the global object. */
+static JSClass global_class = {
+    "global",
+    JSCLASS_GLOBAL_FLAGS,
+    &JS::DefaultGlobalClassOps
+};
+
+static JSObject*
+NewSandbox(JSContext* cx, bool lazy)
+{
+    JS::RealmOptions options;
+    
options.creationOptions().setSharedMemoryAndAtomicsEnabled(enableSharedMemory);
+    options.creationOptions().setNewCompartmentAndZone();
+    // we need this in the query server error handling
+    options.creationOptions().setToSourceEnabled(enableToSource);
+    JS::RootedObject obj(cx, JS_NewGlobalObject(cx, &global_class, nullptr,
+                                            JS::DontFireOnNewGlobalHook, 
options));
+    if (!obj)
+        return nullptr;
+
+    {
+        JSAutoRealm ac(cx, obj);
+        if (!lazy && !JS::InitRealmStandardClasses(cx))
+            return nullptr;
+
+        JS::RootedValue value(cx, JS::BooleanValue(lazy));
+        if (!JS_DefineProperty(cx, obj, "lazy", value, JSPROP_PERMANENT | 
JSPROP_READONLY))
+            return nullptr;
+
+        JS_FireOnNewGlobalObject(cx, obj);
+    }
+
+    if (!JS_WrapObject(cx, &obj))
+        return nullptr;
+    return obj;
+}
+
+static bool
+evalcx(JSContext *cx, unsigned int argc, JS::Value* vp)
+{
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    bool ret = false;
+
+    JS::RootedString str(cx, args[0].toString());
+    if (!str)
+        return false;
+
+    JS::RootedObject sandbox(cx);
+    if (args.hasDefined(1)) {
+        sandbox = JS::ToObject(cx, args[1]);
+        if (!sandbox)
+            return false;
+    }
+
+    if (!sandbox) {
+        sandbox = NewSandbox(cx, false);
+        if (!sandbox)
+            return false;
+    }
+
+    JS::AutoStableStringChars strChars(cx);
+    if (!strChars.initTwoByte(cx, str))
+        return false;
+
+    mozilla::Range<const char16_t> chars = strChars.twoByteRange();
+    JS::SourceText<char16_t> srcBuf;
+    if (!srcBuf.init(cx, chars.begin().get(), chars.length(),
+                     JS::SourceOwnership::Borrowed)) {
+        return false;
+    }
+
+    if(srcBuf.length() == 0) {
+        args.rval().setObject(*sandbox);
+    } else {
+        mozilla::Maybe<JSAutoRealm> ar;
+        unsigned flags;
+        JSObject* unwrapped = UncheckedUnwrap(sandbox, true, &flags);
+        if (flags & js::Wrapper::CROSS_COMPARTMENT) {
+            sandbox = unwrapped;
+            ar.emplace(cx, sandbox);
+        }
+
+        JS::CompileOptions opts(cx);
+        JS::RootedValue rval(cx);
+        opts.setFileAndLine("<unknown>", 1);
+
+        if (!JS::Evaluate(cx, opts, srcBuf, args.rval())) {
+             return false;
+         }
+    }
+    ret = true;
+    if (!JS_WrapValue(cx, args.rval()))
+        return false;
+
+    return ret;
+}
+
+
+static bool
+gc(JSContext* cx, unsigned int argc, JS::Value* vp)
+{
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    JS_GC(cx);
+    args.rval().setUndefined();
+    return true;
+}
+
+
+static bool
+print(JSContext* cx, unsigned int argc, JS::Value* vp)
+{
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+    bool use_stderr = false;
+    if(argc > 1 && args[1].isTrue()) {
+        use_stderr = true;
+    }
+
+    if(!args[0].isString()) {
+        JS_ReportErrorUTF8(cx, "Unable to print non-string value.");
+        return false;
+    }
+
+    couch_print(cx, args[0], use_stderr);
+
+    args.rval().setUndefined();
+    return true;
+}
+
+
+static bool
+quit(JSContext* cx, unsigned int argc, JS::Value* vp)
+{
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+    int exit_code = args[0].toInt32();;
+    JS_DestroyContext(cx);
+    JS_ShutDown();
+    exit(exit_code);
+}
+
+
+static bool
+readline(JSContext* cx, unsigned int argc, JS::Value* vp)
+{
+    JSString* line;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+    /* GC Occasionally */
+    JS_MaybeGC(cx);
+
+    line = couch_readline(cx, stdin);
+    if(line == NULL) return false;
+
+    // return with JSString* instead of JSValue in the past
+    args.rval().setString(line);
+    return true;
+}
+
+
+static bool
+seal(JSContext* cx, unsigned int argc, JS::Value* vp)
+{
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    JS::RootedObject target(cx);
+    target = JS::ToObject(cx, args[0]);
+    if (!target) {
+        args.rval().setUndefined();
+        return true;
+    }
+    bool deep = false;
+    deep = args[1].toBoolean();
+    bool ret = deep ? JS_DeepFreezeObject(cx, target) : JS_FreezeObject(cx, 
target);
+    args.rval().setUndefined();
+    return ret;
+}
+
+
+static JSFunctionSpec global_functions[] = {
+    JS_FN("evalcx", evalcx, 0, 0),
+    JS_FN("gc", gc, 0, 0),
+    JS_FN("print", print, 0, 0),
+    JS_FN("quit", quit, 0, 0),
+    JS_FN("readline", readline, 0, 0),
+    JS_FN("seal", seal, 0, 0),
+    JS_FS_END
+};
+
+
+static bool
+csp_allows(JSContext* cx,
+    JS::RuntimeCode kind, JS::Handle<JSString*> codeString,
+    JS::CompilationType compilationType,
+    JS::Handle<JS::StackGCVector<JSString*>> parameterStrings,
+    JS::Handle<JSString*> bodyString,
+    JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs,
+    JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings)
+{
+    couch_args* args = static_cast<couch_args*>(JS_GetContextPrivate(cx));
+    if(args->eval) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+static JSSecurityCallbacks security_callbacks = {
+    csp_allows,     //JSCSPEvalChecker contentSecurityPolicyAllows;
+    nullptr,        //JSCodeForEvalOp codeForEvalGets;
+    nullptr         //JSSubsumesOp subsumes;
+};
+
+int runWithContext(JSContext* cx, couch_args* args) {
+    JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_BASELINE_ENABLE, 0);
+    JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_ENABLE, 0);
+
+    if (!JS::InitSelfHostedCode(cx))
+        return 1;
+
+    JS::SetWarningReporter(cx, couch_error);
+    JS::SetOutOfMemoryCallback(cx, couch_oom, NULL);
+    JS_SetContextPrivate(cx, args);
+    JS_SetSecurityCallbacks(cx, &security_callbacks);
+
+    JS::RealmOptions options;
+    // we need this in the query server error handling
+    options.creationOptions().setToSourceEnabled(enableToSource);
+    JS::RootedObject global(cx, JS_NewGlobalObject(cx, &global_class, nullptr,
+                                                   JS::FireOnNewGlobalHook, 
options));
+    if (!global)
+        return 1;
+
+    JSAutoRealm ar(cx, global);
+
+    if(!JS::InitRealmStandardClasses(cx))
+        return 1;
+
+    if(couch_load_funcs(cx, global, global_functions) != true)
+        return 1;
+
+    for(int i = 0 ; args->scripts[i] ; i++) {
+        const char* filename = args->scripts[i];
+
+        // Compile and run
+        JS::CompileOptions options(cx);
+        JS::RootedScript script(cx);
+
+        script = JS::CompileUtf8Path(cx, options, filename);
+        if (!script) {
+            JS::RootedValue exc(cx);
+            if(!JS_GetPendingException(cx, &exc)) {
+                fprintf(stderr, "Failed to compile file: %s\n", filename);
+            } else {
+                JS::RootedObject exc_obj(cx, &exc.toObject());
+                JSErrorReport* report = JS_ErrorFromException(cx, exc_obj);
+                couch_error(cx, report);
+            }
+            return 1;
+        }
+
+        JS::RootedValue result(cx);
+        if(JS_ExecuteScript(cx, script, &result) != true) {
+            JS::RootedValue exc(cx);
+            if(!JS_GetPendingException(cx, &exc)) {
+                fprintf(stderr, "Failed to execute script.\n");
+            } else {
+                JS::RootedObject exc_obj(cx, &exc.toObject());
+                JSErrorReport* report = JS_ErrorFromException(cx, exc_obj);
+                couch_error(cx, report);
+            }
+        }
+
+        // Give the GC a chance to run.
+        JS_MaybeGC(cx);
+    }
+    return 0;
+}
+
+int
+main(int argc, const char* argv[])
+{
+    JSContext* cx = NULL;
+    int ret;
+
+    couch_args* args = couch_parse_args(argc, argv);
+
+    JS_Init();
+    cx = JS_NewContext(args->stack_size);
+    if(cx == NULL) {
+        JS_ShutDown();
+        return 1;
+    }
+    ret = runWithContext(cx, args);
+    JS_DestroyContext(cx);
+    JS_ShutDown();
+
+    return ret;
+}
diff --git a/src/couch/priv/couch_js/140/util.cpp 
b/src/couch/priv/couch_js/140/util.cpp
new file mode 100644
index 000000000..d2381cedb
--- /dev/null
+++ b/src/couch/priv/couch_js/140/util.cpp
@@ -0,0 +1,380 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+
+#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
+#include <js/Conversions.h>
+#include <js/Initialization.h>
+#include <js/MemoryFunctions.h>
+#include <js/RegExp.h>
+
+#include "help.h"
+#include "util.h"
+
+const char*
+get_spidermonkey_version() {
+    const char *JAVASCRIPT = "JavaScript-C";
+    int js_len = strlen(JAVASCRIPT);
+
+    // JS_GetImplementationVersion()
+    // returns "JavaScript-CMAJOR.MINOR.PATCH"
+    const char *FULLVERSION = JS_GetImplementationVersion();
+    int fv_len = strlen(FULLVERSION);
+
+    const char* foundJSString = strstr(FULLVERSION,JAVASCRIPT);
+    if (foundJSString != NULL) {
+        //trim off "JavaScript-C",
+        char *buf = (char*) malloc((fv_len - js_len + 1) * sizeof(char));
+        strncpy(buf, &FULLVERSION[js_len], fv_len - js_len);
+        buf[fv_len - js_len] = '\0';
+        return buf;
+    } else {
+        //something changed in JS_GetImplementationVersion(), return original
+        return FULLVERSION;
+    }
+}
+
+std::string
+js_to_string(JSContext* cx, JS::HandleValue val)
+{
+    JS::AutoSaveExceptionState exc_state(cx);
+    JS::RootedString sval(cx);
+    sval = val.toString();
+
+    JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
+    if(!chars) {
+        JS_ClearPendingException(cx);
+        return std::string();
+    }
+
+    return chars.get();
+}
+
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
+{
+    if(!val.isString()) {
+        return false;
+    }
+
+    if(JS_GetStringLength(val.toString()) == 0) {
+        str = "";
+        return true;
+    }
+
+    std::string conv = js_to_string(cx, val);
+    if(!conv.size()) {
+        return false;
+    }
+
+    str = conv;
+    return true;
+}
+
+JSString*
+string_to_js(JSContext* cx, const std::string& raw)
+{
+    JS::UTF8Chars utf8(raw.c_str(), raw.size());
+    JS::UniqueTwoByteChars utf16;
+    size_t len;
+
+    utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, 
js::MallocArena).get());
+    if(!utf16) {
+        return nullptr;
+    }
+
+    return JS_NewUCString(cx, std::move(utf16), len);
+}
+
+size_t
+couch_readfile(const char* file, char** outbuf_p)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char *buf = NULL;
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buf = new char[nread + 1];
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, nread);
+        } else {
+            tmp = new char[buflen + nread + 1];
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            delete buf;
+            buf = tmp;
+        }
+        buflen += nread;
+        buf[buflen] = '\0';
+    }
+    *outbuf_p = buf;
+    return buflen ;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = new couch_args();
+    if(args == NULL)
+        return NULL;
+
+    args->eval = 0;
+    args->stack_size = 64L * 1024L * 1024L;
+    args->scripts = nullptr;
+
+    while(i < argc) {
+        if(strcmp("-h", argv[i]) == 0) {
+            DISPLAY_USAGE;
+            exit(0);
+        } else if(strcmp("-V", argv[i]) == 0) {
+            DISPLAY_VERSION;
+            exit(0);
+        } else if(strcmp("-S", argv[i]) == 0) {
+            args->stack_size = atoi(argv[++i]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else if(strcmp("--eval", argv[i]) == 0) {
+            args->eval = 1;
+        } else if(strcmp("--", argv[i]) == 0) {
+            i++;
+            break;
+        } else {
+            break;
+        }
+        i++;
+    }
+
+    if(i >= argc) {
+        DISPLAY_USAGE;
+        exit(3);
+    }
+    args->scripts = argv + i;
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    char* bytes = NULL;
+    char* tmp = NULL;
+    size_t used = 0;
+    size_t byteslen = 256;
+    size_t oldbyteslen = 256;
+    size_t readlen = 0;
+
+    bytes = static_cast<char*>(JS_malloc(cx, byteslen));
+    if(bytes == NULL) return NULL;
+
+    while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
+        used += readlen;
+
+        if(bytes[used-1] == '\n') {
+            bytes[used-1] = '\0';
+            break;
+        }
+
+        // Double our buffer and read more.
+        oldbyteslen = byteslen;
+        byteslen *= 2;
+        tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+        if(!tmp) {
+            JS_free(cx, bytes);
+            return NULL;
+        }
+
+        bytes = tmp;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JS_NewStringCopyZ(cx, nullptr);
+    }
+
+    // Shrink the buffer to the actual data size
+    tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = string_to_js(cx, std::string(tmp));
+    JS_free(cx, bytes);
+    return str;
+}
+
+
+void
+couch_print(JSContext* cx, JS::HandleValue obj, bool use_stderr)
+{
+    FILE *stream = stdout;
+
+    if (use_stderr) {
+        stream = stderr;
+    }
+    std::string val = js_to_string(cx, obj);
+    fprintf(stream, "%s\n", val.c_str());
+    fflush(stream);
+}
+
+
+void
+couch_error(JSContext* cx, JSErrorReport* report)
+{
+    if(!report) {
+        return;
+    }
+
+    if(report->isWarning()) {
+        return;
+    }
+
+    std::ostringstream msg;
+    msg << "error: " << report->message().c_str();
+
+    mozilla::Maybe<JSAutoRealm> ar;
+    JS::RootedValue exc(cx);
+    JS::RootedObject exc_obj(cx);
+    JS::RootedObject stack_obj(cx);
+    JS::RootedString stack_str(cx);
+    JS::RootedValue stack_val(cx);
+    JSPrincipals* principals = GetRealmPrincipals(js::GetContextRealm(cx));
+
+    if(!JS_GetPendingException(cx, &exc)) {
+        goto done;
+    }
+
+    // Clear the exception before an JS method calls or the result is
+    // infinite, recursive error report generation.
+    JS_ClearPendingException(cx);
+
+    exc_obj.set(exc.toObjectOrNull());
+    stack_obj.set(JS::ExceptionStackOrNull(exc_obj));
+
+    if(!stack_obj) {
+        // Compilation errors don't have a stack
+
+        msg << " at ";
+
+        if(report->filename) {
+#if MOZJS_MAJOR_VERSION < 128
+            msg << report->filename;
+#else  // MOZJS_MAJOR_VERSION >= 128
+            msg << report->filename.c_str();
+#endif
+        } else {
+            msg << "<unknown>";
+        }
+
+        if(report->lineno) {
+#if MOZJS_MAJOR_VERSION < 128
+            msg << ':' << report->lineno << ':' << report->column;
+#else  // MOZJS_MAJOR_VERSION >= 128
+            msg << ':' << report->lineno << ':' <<
+                report->column.oneOriginValue();
+#endif
+        }
+
+        goto done;
+    }
+
+    if(!JS::BuildStackString(cx, principals, stack_obj, &stack_str, 2)) {
+        goto done;
+    }
+
+    stack_val.set(JS::StringValue(stack_str));
+    msg << std::endl << std::endl << js_to_string(cx, stack_val).c_str();
+
+done:
+    msg << std::endl;
+    fprintf(stderr, "%s", msg.str().c_str());
+}
+
+
+void
+couch_oom(JSContext* cx, void* data)
+{
+    fprintf(stderr, "out of memory\n");
+    _Exit(1);
+}
+
+
+bool
+couch_load_funcs(JSContext* cx, JS::HandleObject obj, JSFunctionSpec* funcs)
+{
+    JSFunctionSpec* f;
+    for(f = funcs; f->name; f++) {
+        if(!JS_DefineFunction(cx, obj, f->name.string(), f->call.op, f->nargs, 
f->flags)) {
+            fprintf(stderr, "Failed to create function: %s\n", 
f->name.string());
+            return false;
+        }
+    }
+    return true;
+}
diff --git a/src/couch/priv/couch_js/140/util.h 
b/src/couch/priv/couch_js/140/util.h
new file mode 100644
index 000000000..28d44f4ba
--- /dev/null
+++ b/src/couch/priv/couch_js/140/util.h
@@ -0,0 +1,43 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+#ifndef COUCHJS_UTIL_H
+#define COUCHJS_UTIL_H
+
+#include <jsapi.h>
+
+typedef struct {
+    int          eval;
+    int          use_http;
+    int          use_test_funs;
+    int          stack_size;
+    const char** scripts;
+    const char*  uri_file;
+    JSString*    uri;
+} couch_args;
+
+const char* get_spidermonkey_version();
+
+std::string js_to_string(JSContext* cx, JS::HandleValue val);
+bool js_to_string(JSContext* cx, JS::HandleValue val, std::string& str);
+JSString* string_to_js(JSContext* cx, const std::string& s);
+
+couch_args* couch_parse_args(int argc, const char* argv[]);
+int couch_fgets(char* buf, int size, FILE* fp);
+JSString* couch_readline(JSContext* cx, FILE* fp);
+size_t couch_readfile(const char* file, char** outbuf_p);
+void couch_print(JSContext* cx, JS::HandleValue str, bool use_stderr);
+void couch_error(JSContext* cx, JSErrorReport* report);
+void couch_oom(JSContext* cx, void* data);
+bool couch_load_funcs(JSContext* cx, JS::HandleObject obj, JSFunctionSpec* 
funcs);
+
+#endif // Included util.h
diff --git a/src/couch/rebar.config.script b/src/couch/rebar.config.script
index 1c9809902..abfab31bd 100644
--- a/src/couch/rebar.config.script
+++ b/src/couch/rebar.config.script
@@ -97,13 +97,15 @@ SMVsn = case lists:keyfind(spidermonkey_version, 1, 
CouchConfig) of
         "115";
     {_, "128"} ->
         "128";
+    {_, "140"} ->
+        "140";
     undefined ->
-        "91";
+        "140";
     {_, Unsupported} ->
         io:format(standard_error, "Unsupported SpiderMonkey version: ~s~n", 
[Unsupported]),
         erlang:halt(1);
     false ->
-        "91"
+        "140"
 end.
 
 ConfigH = [
@@ -129,6 +131,8 @@ CouchJSConfig = case SMVsn of
         "priv/couch_js/102/config.h";
     "128" ->
         "priv/couch_js/102/config.h";
+    "140" ->
+        "priv/couch_js/140/config.h";
     _ ->
         "priv/couch_js/" ++ SMVsn ++ "/config.h"
 end.
@@ -214,7 +218,7 @@ end.
             "-DXP_UNIX -I/usr/include/mozjs-86 -I/usr/local/include/mozjs-86 
-I/opt/homebrew/include/mozjs-86/ -std=c++17 -Wno-invalid-offsetof",
             "-L/usr/local/lib -L /opt/homebrew/lib/ -std=c++17 -lmozjs-86 -lm"
         };
-    {unix, _} when SMVsn == "91"; SMVsn == "102"; SMVsn == "115"; SMVsn == 
"128" ->
+    {unix, _} when SMVsn == "91"; SMVsn == "102"; SMVsn == "115"; SMVsn == 
"128"; SMVsn == "140"  ->
         {
             "$CFLAGS -DXP_UNIX " ++ MozJSIncludePath ++ " -std=c++17 
-Wno-invalid-offsetof",
             "$LDFLAGS " ++ MozJSLibPath ++ " -std=c++17 -lm -lmozjs-" ++ SMVsn
@@ -224,7 +228,7 @@ end.
             "/std:c++17 /DXP_WIN",
             "$LDFLAGS mozjs-91.lib"
         };
-    {win32, _} when SMVsn == "102"; SMVsn == "115"; SMVsn == "128" ->
+    {win32, _} when SMVsn == "102"; SMVsn == "115"; SMVsn == "128"; SMVsn == 
"140"  ->
         {
             "/std:c++17 /DXP_WIN /Zc:preprocessor /utf-8",
             "$LDFLAGS mozjs-" ++ SMVsn ++ ".lib"
@@ -240,7 +244,8 @@ CouchJSSrc = case SMVsn of
     "91" -> ["priv/couch_js/86/*.cpp"];
     "102" -> ["priv/couch_js/102/*.cpp"];
     "115" -> ["priv/couch_js/102/*.cpp"];
-    "128" -> ["priv/couch_js/102/*.cpp"]
+    "128" -> ["priv/couch_js/102/*.cpp"];
+    "140" -> ["priv/couch_js/140/*.cpp"]
 end.
 
 CouchJSEnv = case SMVsn of
diff --git a/src/docs/src/api/database/changes.rst 
b/src/docs/src/api/database/changes.rst
index cbf47b6fb..812e3b5db 100644
--- a/src/docs/src/api/database/changes.rst
+++ b/src/docs/src/api/database/changes.rst
@@ -115,8 +115,9 @@
         the filtering criteria.
     :query number timeout: Maximum period in *milliseconds* to wait for a 
change
         before the response is sent, even if there are no results.
-        Only applicable for :ref:`longpoll <changes/longpoll>` or
-        :ref:`continuous <changes/continuous>` feeds.
+        Only applicable for :ref:`longpoll <changes/longpoll>`,
+        :ref:`continuous <changes/continuous>` or
+        :ref:`eventsource <changes/eventsource>` feeds.
         Default value is specified by :config:option:`chttpd/changes_timeout`
         configuration option. Note that ``60000`` value is also the default
         maximum timeout to prevent undetected dead connections.
diff --git a/src/dreyfus/src/dreyfus_fabric_group1.erl 
b/src/dreyfus/src/dreyfus_fabric_group1.erl
index 9b08a94eb..990d6d24e 100644
--- a/src/dreyfus/src/dreyfus_fabric_group1.erl
+++ b/src/dreyfus/src/dreyfus_fabric_group1.erl
@@ -63,8 +63,8 @@ go(DbName, DDoc, IndexName, #index_query_args{} = QueryArgs) 
->
             #shard.ref,
             fun handle_message/3,
             State,
-            infinity,
-            1000 * 60 * 60
+            fabric_util:timeout("search", "infinity"),
+            fabric_util:timeout("search_permsg", "3600000")
         )
     after
         rexi_monitor:stop(RexiMon),
diff --git a/src/dreyfus/src/dreyfus_fabric_group2.erl 
b/src/dreyfus/src/dreyfus_fabric_group2.erl
index 3059aa30e..613ac6555 100644
--- a/src/dreyfus/src/dreyfus_fabric_group2.erl
+++ b/src/dreyfus/src/dreyfus_fabric_group2.erl
@@ -68,8 +68,8 @@ go(DbName, DDoc, IndexName, #index_query_args{} = QueryArgs) 
->
             #shard.ref,
             fun handle_message/3,
             State,
-            infinity,
-            1000 * 60 * 60
+            fabric_util:timeout("search", "infinity"),
+            fabric_util:timeout("search_permsg", "3600000")
         )
     after
         rexi_monitor:stop(RexiMon),
diff --git a/src/fabric/src/fabric_view_all_docs.erl 
b/src/fabric/src/fabric_view_all_docs.erl
index 2d0133acb..17f522a2b 100644
--- a/src/fabric/src/fabric_view_all_docs.erl
+++ b/src/fabric/src/fabric_view_all_docs.erl
@@ -144,7 +144,7 @@ go(DbName, _Options, Workers, QueryArgs, Callback, Acc0) ->
             fun handle_message/3,
             State,
             fabric_util:view_timeout(QueryArgs),
-            5000
+            fabric_util:timeout("all_docs_view_permsg", "5000")
         )
     of
         {ok, NewState} ->
diff --git a/src/fabric/src/fabric_view_changes.erl 
b/src/fabric/src/fabric_view_changes.erl
index df958b6b4..dd2386f5e 100644
--- a/src/fabric/src/fabric_view_changes.erl
+++ b/src/fabric/src/fabric_view_changes.erl
@@ -543,7 +543,7 @@ get_old_seq(#shard{range = R} = Shard, SinceSeqs) ->
 
 get_db_uuid_shards(DbName) ->
     % Need to use an isolated process as we are performing a fabric call from
-    % another fabric call and there is a good chance we'd polute the mailbox
+    % another fabric call and there is a good chance we'd pollute the mailbox
     % with returned messages
     Timeout = fabric_util:request_timeout(),
     IsolatedFun = fun() -> fabric:db_uuids(DbName) end,
diff --git a/src/setup/test/t-frontend-setup.sh 
b/src/setup/test/t-frontend-setup.sh
index e025cfba2..106312dec 100755
--- a/src/setup/test/t-frontend-setup.sh
+++ b/src/setup/test/t-frontend-setup.sh
@@ -64,8 +64,8 @@ curl 
a:b@127.0.0.1:25984/_node/node2@127.0.0.1/_config/cluster/n
 curl a:b@127.0.0.1:15984/_node/node1@127.0.0.1/_config/couchdb/uuid
 curl a:b@127.0.0.1:15984/_node/node2@127.0.0.1/_config/couchdb/uuid
 
-curl a:b@127.0.0.1:15984/_node/node1@127.0.0.1/_config/couch_httpd_auth/secret
-curl a:b@127.0.0.1:15984/_node/node2@127.0.0.1/_config/couch_httpd_auth/secret
+curl a:b@127.0.0.1:15984/_node/node1@127.0.0.1/_config/chttpd_auth/secret
+curl a:b@127.0.0.1:15984/_node/node2@127.0.0.1/_config/chttpd_auth/secret
 
 
 echo "YAY ALL GOOD"


Reply via email to