# API

### Runtime RevDeBug API

RevDeBug exposes its runtime API from a global reachable object named `revdebug`:

| **Method**                  |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `revdebug.exception(error)` | <p>Signal an unhandled exception to be recorded and sent to RevDeBug server.<br>Useful when errors are caught in the code and should still be recorded as such by RevDeBug.</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `snapshot(name)`            | Send a snapshot of the current thread execution recording, `name` is optional and will be an automatically generated increasing sequence name if not provided. Recording will be available on the "Recording" tab inside the application section of top-level "Monitor" section of RevDeBug server.                                                                                                                                                                                                                                                                                                                                             |
| `setRecMode(mode)`          | Set the current recording mode to Continuous / Live, OnEvent / Crash or Off. The recording mode can only be set as high as the server allows, so if the server does not allow continuous recording then that will not happen and only unhandled exceptions will be sent to the server. The available recording modes are `revdebug.Off`, `revdebug.Continuous,` `revdebug.Live`, `revdebug.OnEvent` and `revdebug.Crash`. Continuous and Live are aliases as are `OnEvent` and `Crash`.                                                                                                                                                         |
| `str(obj)`                  | Convert object to a string using standard RevDeBug stringification. Intended for use in custom user `__revdrec()` stringification functions for stringifying subobjects. Enforces maximum depth and protects against circular reference cycles. This function will return an incorrect depth recursion level for objects ourside of a `__revdrec()` function. For a correct depth there use `strd()`.                                                                                                                                                                                                                                           |
| `strd(obj[, depth])`        | The way object recursion depth is tracked in stringification necessitates a separate function to be able to get the same recursion depth level for an object outside of `__revdrec()` custom stringification handlers as inside. Calling this function without a `depth` parameter anywhere will return an object recursed to the default depth level set for the project, regardless of how many nested stringification levels down the code currently is. You can also specify an explicit `depth` level for this call, also regardless of current nesting level. Like `str()` this function also protexts against circular reference cycles. |

### Custom JavaScript project layouts

The RevDeBug runtime code can be incorporated into your project in one of several ways, direct `inject` into your source or index.html files, `local` import or `global` import or separate script load in the case of `web` projects.

For `inject`, the injection can be either into a Javascript source file or an HTML-ish index file. For a Javascript injection, a `main` file must be specified and the RevDeBug code is inserted directly into this file and this file must be the entry point of execution. This may get tricky with `import` declarations since those are always executed before the actual file that does the importing, and hence their contents are executed first. `main` must be the first file that executes CHRONOLOGICALLY, not necessarily the topmost level file.

For an `inject` into an HTML-ish index file an `index` filename must be provided and this file will be scanned for a `<head>` section. Once this is found the entire RevDeBug runtime script is inserted as the first script to run in this section.

For `local`, the RevDeBug runtime is copied into the topmost level directory of the project or subproject as `__revdebug.js` and the individual project files `import` or `require()` this file as needed. In this mode, as with `global`, there is no main entry point and any of the project files may be executed first. For `web` projects using this mode the individual Javascript scripts must be loaded as modules.

For `global` the behavior is different between `node` and `web` projects. For a `node` project the runtime is loaded via `import` or `require()` but unlike a `local` path like `import "../__revdebug"` the runtime is assumed to be available either globally or as an installed NPM module dependency and is imported with an absolute path like `import "revdebug"`.

For a `global` `web` project the runtime is assumed to have been loaded as an individual script previously in an HTML file somewhere via something like `<script src="__revdebug.js"></script>` where PATH is the top-level path of your web project where the runtime will be copied. This must be loaded and executed before any Javascript files which were instrumented. If you provide an `index` filename then the script tag described will be automatically inserted into that file, otherwise, you are responsible for loading the RevDeBug runtime somewhere yourself.

### Subprojects, RevDeBug and the global scope

RevDeBug works by injecting itself into the global scope where it is running and recording a project in that scope. There can only be one project or subproject per scope because otherwise, their instrumentation IDs would overlap. This means that for a given `node` or `web` project you should have only one main project. But if your overall solution comprises a node server and a web component for example then each should be its own subproject. The exception to this is when using WebWorkers or worker threads as those each gets their own global scope when they are created and can thus host a completely different project from the code which created them.

What this means basically is that all code that will run in the same global scope of your solution should be part of the same project. However, if you have multiple types of workers or threads which run in their own global scopes then each one can have its own project with different options. You could include them all in a single project if you wish but they would have to share the same options such as `target`, `runtime` and `type` which may be inconvenient or impossible across subprojects.

### Post-processing options and source maps

Post-processing options of RevDeBug allow multilevel mapping of source maps back to original pre-RevDeBug uninstrumented source code in case more processing is done after RevDeBug instrumentation of original source files (like for example with a Typescript compiler or webpack).&#x20;

This is only really useful for web projects in order to be able to see the original source code in a dev console or correct line numbers in stack traces - RevDeBug will present the recordings on the original source code either way.

In order to preserve the information needed for post-processing you must turn on source maps when instrumenting with RevDeBug, as well as in whatever compilation steps you take after ReDeBug instrumentation. After you have instrumented your source files like this and after completing whatever compilation steps follow RevDeBug, when you have your final output files, you will run `revd --post` a second time so that it can merge the two levels of source maps (one from the RevDeBug instrumentation pass and the second from the following compilation passes) into a single level of source maps pointing back to the original code.

In order to do this you will need to specify `postPath` where the final output files live along with their source map files. if `postPath` is not provided it will default to the root directory of the project. Likewise, you will need to specify `postFiles` in the same way that `files` are specified. The `postFiles` may be a single output webpacked file or multiple files selected via wildcards. An example would be source `files` of `*.ts` and `postFiles` as `*.js` to process all the Javascript files compiled from original Typescript files.

`revd --post` will only process output files once, running it again after this will have no effect on files that have already been processed, but will reprocess any individual files which may have been recompiled.

{% hint style="info" %}
*Note: As of the time of writing this RevDeBug only works with individual standalone source map files, it does not work with source maps embedded in Javascript files.*
{% endhint %}

### Custom object stringification

If any object has a `__revdrec` method on itself or in its prototype chain then this method will be called on the object during recording when the value of the object needs to be stringified. The object is assumed to be mutable so this call happens whenever the object is accessed in code that is being recorded. The call is of the form `obj.__revdrec(obj)` so the actual object can be accessed as `this` or in case of arrow function as the first argument.

The method should return a string which will be shown as the value of the object at this point. Any exceptions in this method are suppressed but shown as the value of the object. Recording is turned off when this function is called and in fact by default the body of the function is not instrumented by RevDeBug for performance (or actually any function which starts with "\_\_revd").

The size of the string returned by this function is not truncated in any way by RevDeBug so keep this in mind if your function can potentially generate huge stringified values. RevDeBug takes care of detecting and truncating recursive object cycles. RevDeBug's own stringification functions are made available to use in your own stringification function via `revdebug.str(obj)` or more specifically `revdebug.str.type(obj)` where `type` is one of the primitive names `function`, `boolean`, `number`, `bigint`, `array` or `object`. Do not call a type function on an object which is not of that type, if you are not sure of the type then use `revdebug.str(obj)`.

Stringification using this method is not affected by the global mutable mode which is set. Objects with these functions will always be stringified at record time even if this is turned off for all other objects with `mutable: 'none'`.

### Recording code block isolation

This feature allows the isolation of individual async task trees from their siblings in order to get a recording of an individual service handler or request. When you declare an async task block via `revdebug.block()` you are marking this async context as well as any child async tasks it creates as isolated, meaning that if a `revdebug.snapshot()` or an `revdebug.exception()` in this async context or its children it will only include the task and its children in the recording, not siblings or parent. When used in the APM portion of RevDeBug, this allows the isolation of a single given HTTP handler for example which may have an error from any number of other handlers which may be running concurrently.

The particular details of how async context propagates in Node are a little wonky and possibly subject to change in future versions of the V8 Javascript engine used in Node. This means that in order to use the `block()` functionality correctly you need to understand when the async task context changes in async code (it does not change for example upon initial entry into an `async` function). That information is beyond the scope of this documentation but is available in the documentation for the Node `async_hooks` package.

The idea is that at the start of the code you want to isolate you call `block = revdebug.block()`, and when you are done with the part you want to isolate simply call `revdebug.async()`. If you need to return synchronous control to some other async task without ending your isolation block yet (it will get control later), do the `async()` before returning control to non-isolated code. Upon re-entry to your code which you want to isolate execute a `lastBlock = block.resync()`, execute your code, and return to the previously executing context via `block.async(lastBlock)`. The `lastBlock` here is important because it allows recursive isolation of code blocks, otherwise the wrong previous context may be set if simply calling `async()` (though this is ok after the initial `revdebug.block()` because in this case we are sure we did not recurse into this block.

One last detail about this functionality is that the isolation can be total, only code in the block is shown as part of the recording. Or it can be partial where all code is included in the recording up until the initial `revdebug.block()`, after which only code that is part of the block is shown. This is specified as either no parameter or a falsey parameter to `revdebug.block(falsey)` for complete isolation, or a truthy parameter for partial isolation.

### Environment Variables

The following environment variables can override various configuration settings at runtime (for NodeJS projects):

```
    REVDEBUG_APPLICATIONS_HOST
    REVDEBUG_APPLICATIONS_PORT
    REVDEBUG_SECURE
    REVDEBUG_CONNECTION_TIMEOUT
    REVDEBUG_RECONNECT_WAIT
    REVDEBUG_SOLUTION
    REVDEBUG_APPLICATION
    REVDEBUG_VERSION
    REVDEBUG_RELEASE
    REVDEBUG_AUTH

    REVDEBUG_APM
    REVDEBUG_APM_HOST
    REVDEBUG_APM_PORT
    SW_AGENT_NAME
    SW_AGENT_DISABLE_PLUGINS
    SW_AGENT_MAX_BUFFER_SIZE
    SW_COLD_ENDPOINT
    SW_TRACE_IGNORE_PATH
    SW_IGNORE_SUFFIX

    REVDEBUG_MODE
    REVDEBUG_LOGGING
    REVDEBUG_LOGTIME
    REVDEBUG_MUTABLE
    REVDEBUG_RECORDINGS
    REVDEBUG_BACKLOG
    REVDEBUG_BLOCKS
    REVDEBUG_SYMBOLS
    REVDEBUG_CLASSPROPS
    REVDEBUG_FUNCTIONPROPS
    REVDEBUG_STDOBJECTS
    REVDEBUG_TYPEDARRAYS
    REVDEBUG_OBJECTIDS
    REVDEBUG_DEPTH
    REVDEBUG_STRLEN
```

{% hint style="info" %}
*Note:* REVDEBUG\_APM, REVDEBUG\_BLOCKS, REVDEBUG\_CLASSPROPS, REVDEBUG\_STDOBJECTS and REVDEBUG\_TYPEDARRAYS should be "true" or "false".
{% endhint %}

### Possible minification issues when working on the runtime

* The pseudoMinify() function which is applied to the runtime when it is injected into javascript or HTML files can potentially break the code if it finds a "// " (slash, slash, space) sequence inside a string constant, so be aware of it.
* Also, pseudoMinify() will not remove /\* \*/ style comments.
* If you are getting a minified production runtime that works, but a non-minified one that does not then most likely you did not terminate a "name = function(){}" or "name = class {}" with a semicolon ";". All such assignments must be terminated like this since newlines are removed in pseudo-minification and won't act as delimiters.
