{"id":13565676,"url":"https://github.com/organix/tartjs","last_synced_at":"2026-01-10T13:05:40.613Z","repository":{"id":12165948,"uuid":"14763043","full_name":"organix/tartjs","owner":"organix","description":"Tiny Actor Run-Time in JavaScript","archived":false,"fork":false,"pushed_at":"2016-12-12T19:32:36.000Z","size":88,"stargazers_count":72,"open_issues_count":0,"forks_count":5,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-14T10:48:31.932Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/organix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-11-28T00:25:00.000Z","updated_at":"2024-02-29T05:59:07.000Z","dependencies_parsed_at":"2022-09-05T20:21:39.803Z","dependency_job_id":null,"html_url":"https://github.com/organix/tartjs","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/organix%2Ftartjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/organix%2Ftartjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/organix%2Ftartjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/organix%2Ftartjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/organix","download_url":"https://codeload.github.com/organix/tartjs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247061886,"owners_count":20877176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T13:01:52.782Z","updated_at":"2025-04-03T23:30:27.446Z","avatar_url":"https://github.com/organix.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# tart\n\n_Stability: 1 - [Experimental](https://github.com/tristanls/stability-index#stability-1---experimental)_\n\n[![NPM version](https://badge.fury.io/js/tart.png)](http://npmjs.org/package/tart)\n\nJavaScript implementation of [Tiny Actor Run-Time](https://github.com/organix/tart).\n\n## Contributors\n\n[@dalnefre](https://github.com/dalnefre), [@tristanls](https://github.com/tristanls)\n\n## Overview\n\nThe goal of `tart` is to provide the smallest possible actor library in JavaScript that has the full power of a \"pure\" actor model of computation.\n\n  * [Modules](#modules)\n  * [Usage](#usage)\n  * [Tests](#tests)\n  * [Benchmarks](#benchmarks) \n  * [Documentation](#documentation)\n    * [Tweet](#tweet)\n    * [Minimal](#minimal)\n    * [Pluggable](#pluggable)\n  * [Sources](#sources)\n\n`tart` happens to fit into a tweet :D\n\n    function(){var c=function(b){var a=function(m){setImmediate(function(){x.behavior(m)})},x={self:a,behavior:b,sponsor:c};return a};return c}\n\n## Modules\n\nHere is a selection of modules from the authors of Tart:\n\n  * [tart-adapter](https://github.com/tristanls/tart-adapter) Adapter turning synchronous functions into asynchronous Tart actors.\n  * [tart-ansible](https://github.com/tristanls/tart-ansible) Enables remote message delivery for Tart actors.\n  * [tart-lambda](https://github.com/dalnefre/tart-lambda) A simple lambda-calculus evaluator.\n  * [tart-marshal](https://github.com/dalnefre/tart-marshal) Send messages between memory domains (JSON serialization).\n  * [tart-membrane](https://github.com/tristanls/tart-membrane) Tart membrane implementation (distributed confinement).\n  * [tart-revocable](https://github.com/tristanls/tart-revocable) Tart implementation of a revocable proxy.\n  * [tart-stepping](https://github.com/dalnefre/tart-stepping). --DEPRECATED-- superceded by [tart-tracing](https://github.com/tristanls/tart-tracing).\n  * [tart-stepping-sandbox](https://github.com/tristanls/tart-stepping-sandbox) Remotely controlled sandbox for controlling [tart-stepping](https://github.com/dalnefre/tart-stepping).\n  * [tart-tracing](https://github.com/tristanls/tart-tracing) Tart tracing control (maintains a full event history for debugging).\n  * [tart-transport-http](https://github.com/tristanls/tart-transport-http) HTTP transport implementation for Tart.\n  * [tart-transport-https](https://github.com/tristanls/tart-transport-https) HTTPS transport implementation for Tart.\n  * [tart-transport-tcp](https://github.com/tristanls/tart-transport-tcp) TCP transport implementation for Tart.\n  * [tart-transport-tls](https://github.com/tristanls/tart-transport-tls) TLS transport implementation for Tart.\n  * [tart-transport-udp](https://github.com/tristanls/tart-transport-udp) UDP transport implementation for Tart.\n  * [tart-vm](https://github.com/tristanls/tart-vm) Tart behavior sandbox.\n\n## Usage\n\nTo run the below example run:\n\n    npm run readme\n\n```javascript\n\"use strict\";\n\nvar tart = require('../index.js');\n\nvar sponsor = tart.minimal();\n\n// create an actor that has no state\nvar statelessActor = sponsor(function (message) {\n    console.log('got message', message); \n});\n\n// create an actor with state\nvar statefulActorBeh = function (state) {\n    return function (message) {\n        console.log('got message', message);\n        console.log('actor state', state);\n    };\n};\n\nvar statefulActor = sponsor(statefulActorBeh({some: 'state'}));\n\n// create an actor with state that changes behavior\nvar flipFlop = function (state) {\n    var firstBeh = function (message) {\n        console.log('firstBeh got message', message);\n        console.log('actor state', state);\n        this.behavior = secondBeh;\n    };\n    var secondBeh = function (message) {\n        console.log('secondBeh got message', message);\n        console.log('actor state', state);\n        this.behavior = firstBeh;\n    };\n    return firstBeh;\n};\n\nvar serialActor = sponsor(flipFlop({some: 'state'}));\n\n// create an actor that creates a chain of actors\nvar chainActorBeh = function (count) {\n    return function (message) {\n        console.log('chain actor', count);\n        if (--count \u003e= 0) {\n            var next = this.sponsor(chainActorBeh(count));\n            next(message);\n        }\n    }; \n};\n\nvar chainActor = sponsor(chainActorBeh(10));\n\n// send messages to the actors\nstatelessActor('some message');\nstatefulActor({some: 'other message'});\nserialActor('first message');\nserialActor('second message');\nserialActor('third message');\nserialActor('fourth message');\nchainActor('go');\n```\n\n## Tests\n\n    npm test\n\n## Benchmarks\n\nBenchmarks were run on the [Minimal](#minimal) implementation.\n\n### Erlang Challenge\n\nErlang Challenge consists of creating a ring of M actors, sending N simple messages around the ring and increasing M until running out of resources. \n\nThe benchmark implements a modified version of the challenge by creating 100,000 actors and running 10 simple messages around the ring.\n\n    npm run erlangChallenge\n\n### 100,000 actor ring\n\n    starting 100000 actor ring\n    sending 10 messages\n    ..........\n    done\n    all times in NANOSECONDS\n    construction time:\n    336492833\n    loop times:\n    221762650\n    212925428\n    213672756\n    215595649\n    215465809\n    216958143\n    217696839\n    221343351\n    222385758\n    226308376\n    loop average:\n    218411475.9\n\nFor rings of sizes larger than 4 Million you may need to expand memory available to V8. To do that, the following command will start the Erlang challenge with ~10GB of memory available:\n\n    node --max_old_space_size=10000 scripts/erlangChallenge.js\n\n### 30,000,000 actor ring\n\n30 Million actor ring benchmark took up about ~8.5 GB of memory.\n\n    starting 30000000 actor ring\n    sending 1 messages\n    .\n    done\n    all times in NANOSECONDS\n    construction time:\n    233098891645\n    loop times:\n    244265390009\n    loop average:\n    244265390009\n\n## Documentation\n\nThe [Minimal](#minimal) implementation is the implementation optimized for fastest execution time. In contrast, [Pluggable](#pluggable) implementation allows for total control of the runtime and execution semantics. Although the default behavior of [Pluggable](#pluggable) is the same as [Minimal](#minimal), it is somewhat slower due to extra overhead incurred by pluggability of control and observability mechanisms.\n\n  * [Tweet](#tweet)\n  * [Minimal](#minimal)\n  * [Pluggable](#pluggable)\n\n### Tweet\n\n**Public API**\n\n  * [tart.tweet()](#tarttweet)\n  * [sponsor(behavior)](#sponsorbehavior)\n  * [actor(message)](#actormessage)\n\n### tart.tweet()\n\nCreates a sponsor capability to create new actors with using the Tweetable implementation :D.\n\nWARNING: If an exception is thrown during message processing the Tweetable run-time will crash. For fastest stable implementation use [Minimal](#minimal).\n\n### sponsor(behavior)\n\nSame as the core [Minimal](#minimal) implementation. _See: [sponsor(behavior)](#sponsorbehavior-1)_\n\n### actor(message)\n\nSame as the core [Minimal](#minimal) implementation. _See: [actor(message)](#actormessage-1)_\n\n### Minimal\n\n**Public API**\n\n  * [tart.minimal(\\[options\\])](#tartminimaloptions)\n  * [sponsor(behavior)](#sponsorbehavior-1)\n  * [actor(message)](#actormessage-1)\n\n### tart.minimal([options])\n\n  * `options`: _Object_ _(Default: `undefined`)_\n    * `fail`: _Function_ _(Default: `function (exception) {}`)_ `function (exception) {}` An optional handler to call if a sponsored actor behavior throws an exception.\n  * Return: _Function_ `function (behavior) {}` A capability to create new actors.\n\nCreates a sponsor capability to create new actors with.\n\n```javascript\nvar tart = require('tart');\nvar sponsor = tart.minimal();\n\nvar reportingSponsor = tart.minimal({\n    fail: function (exception) {\n        console.dir(exception);\n    }\n});\n```\n\n### sponsor(behavior)\n\n  * `behavior`: _Function_ `function (message) {}` Actor behavior to invoke every time an actor receives a message.\n  * Return: _Function_ `function (message) {}` Actor reference in form of a capability that can be invoked to send the actor a message.\n\nCreates a new actor and returns the actor reference in form of a capability to send that actor a message.\n\n```javascript\nvar tart = require('tart');\nvar sponsor = tart.minimal();\nvar actor = sponsor(function (message) {\n    console.log('got message', message); \n    console.log(this.self);\n    console.log(this.behavior);\n    console.log(this.sponsor);\n});\n```\n\nWhen the `behavior` is invoked upon the receipt of a message, it's `this` will be bound with the following:\n\n  * `this.self`: _Function_ `function (message) {}` Reference to the actor that is executing the `behavior` (in form of a capability that can be invoked to send the actor a message).\n  * `this.behavior`: _Function_ `function (message) {}` The behavior of the actor. To change actor behavior (a \"become\" operation) assign a new function to this parameter.\n  * `this.sponsor`: _Function_ `function (behavior) {}` A capability to create new actors. To create a new actor call `this.sponsor(behavior)`.\n\n### actor(message)\n\n  * `message`: _Any_ Any message.\n\nAsynchronously sends the `message` to the `actor`.\n\n```javascript\nvar tart = require('tart');\nvar sponsor = tart.minimal();\nvar actor = sponsor(function behavior(message) {\n    console.log('got message', message);\n});\nactor('hello actor world');\n```\n\n### Pluggable\n\n**Public API**\n\n  * [tart.pluggable(\\[options\\])](#tartpluggableoptions)\n  * [sponsor(behavior)](#sponsorbehavior-2)\n  * [actor(message)](#actormessage-2)\n\n### tart.pluggable([options])\n\n  * `options`: _Object_ _(Default: undefined)_ Optional overrides.\n    * `constructConfig`: _Function_ _(Default: `function (options) {}`)_ `function (options) {}` Configuration creation function that is given `options`. It should return a capability `function (behavior) {}` to create new actors.\n    * `deliver`: _Function_ _(Default: `function (context, message, options) {}`)_ `function (context, message, options) {}` Deliver function that returns a function for `dispatch` to dispatch.\n    * `dispatch`: _Function_ _(Default: `setImmediate`)_ `function (deliver) {}` Dispatch function for dispatching `deliver` closures. \n    * `fail`: _Function_ _(Default: `function (exception) {}`)_ `function (exception) {}` An optional handler to call if a sponsored actor behavior throws an exception.  \n    * `annotate`: _Function_ _(Default: `function (actor) { return actor; }`)_ `function (actor) {}` An optional method to wrap/modify newly-created actors.  \n  * Return: _Function_ `function (behavior) {}` A capability to create new actors.\n\nCreates a sponsor capability to create new actors with and allows replacing parts of the implementation.\n\nTo run the below example run:\n\n    npm run pluggable\n\n```javascript\nvar tart = require('tart');\n\nvar dispatch = function (deliver) {\n    console.log('delivering a message'); \n    deliver(); \n};\n\nvar deliver = function deliver(context, message, options) {\n    console.log('delivering message', message, 'to context', context);\n    return function deliver() {\n        try {\n            context.behavior(message);\n        } catch (exception) {\n            console.log('got exception', exception);\n        }\n    };\n};\n\nvar constructConfig = function constructConfig(options) {\n    var config = function create(behavior) {\n        var actor = function send(message) {\n            options.dispatch(options.deliver(context, message, options));\n        };\n        actor = options.annotate(actor);\n        var context = {\n            self: actor,\n            behavior: behavior,\n            sponsor: config\n        };\n        console.log('created actor in context', context);\n        return actor;\n    };\n    return config;\n};\n\nvar annotate = (function (n) {\n    return function annotate(actor) {\n        var id = '@' + n++;\n        actor.toString = actor.inspect = function () {\n            return id;\n        };\n        return actor;\n    };\n})(0);\n\nvar sponsor = tart.pluggable({\n    constructConfig: constructConfig,\n    deliver: deliver,\n    dispatch: dispatch,\n    annotate: annotate\n});\n\nvar actor = sponsor(function (message) {\n    console.log('got message', message);\n});\n\nactor('foo');\n```\n\n### sponsor(behavior)\n\nSame as the core [Minimal](#minimal) implementation. _See: [sponsor(behavior)](#sponsorbehavior-1)_\n\n### actor(message)\n\nSame as the core [Minimal](#minimal) implementation. _See: [actor(message)](#actormessage-1)_\n\n## Releases\n\nWe follow semantic versioning policy ([semver.org](http://semver.org/)):\n\n\u003eGiven a version number MAJOR.MINOR.PATCH, increment the:\n\u003e\n\u003eMAJOR version when you make incompatible API changes,\u003cbr/\u003e\n\u003eMINOR version when you add functionality in a backwards-compatible manner, and\u003cbr/\u003e\n\u003ePATCH version when you make backwards-compatible bug fixes.\n\n## Sources\n\n  * [Tiny Actor Run-Time](https://github.com/organix/tart)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forganix%2Ftartjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forganix%2Ftartjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forganix%2Ftartjs/lists"}