0.2.10 • Published 1 year ago

webn v0.2.10

Weekly downloads
-
License
WTFPL
Repository
-
Last release
1 year ago

webn

A simple application server. RPC via AJAX.

How to use

Just import webn in your server and send it an object containing some functions:

import webn from 'webn'

webn({
	test(input) {
		console.log(input)
		return 'hello'
	}
})

Then create a page for the frontend (call it "web/index.html"):

<html>
	<head>
		<script src="script.js" type="module"></script>
	</head>
	<body>
	</body>
</html>

Then import webn (in "web/script.js") and call the function, like so:

import webn from '/webn'

document.body.onload = async function() {
	const text = await webn.test('testing')
	alert(text)
}

Config object

webn will pick some default options like port, folder for the frontend files, and so on for you, but if you want more flexibility you can add a configuration object.

import webn from 'webn'

webn({path: 'webapp', port: 8080}, {
	fn() {}
})

The available config items are:

  • develop - Set this to true to remove caching and add some extra logging and timing.
  • path - Path to frontend files. Default is "web". Setting this to null means no files will be served. The webn import for the frontend and he RPC part will still work as normal.
  • port - Port used by application. Default is 80 for http, 443 for https.
  • timeout - Time, in seconds, for sessions to time out and disappear after last activity.

Logging:

  • log - a function to call for logging, or an object with two values:
    • info - Function to call for regular logging. Set to true to log to console.info.
    • error - Function to call for error logging. Defaults to console.error. Set to false to turn off error logging.
  • NOTE: setting log to true or false instead of an object is the same as setting both of these to true or false.

If you do not supply an index.html file, there are also these options:

  • title - Name of application. Default is empty string.
  • script - Inject this script file into a dummy index file. Default is "script.js".

For https there are also these options:

  • key - Name of key file or its content.
  • cert - Name of certificate file or its content.
  • pfx - Name of pfx file or its content.
  • passphrase - Passphrase for pfx.
  • NOTE: Defining either key/cert or pfx/passphrase will cause webn to use https. Otherwise, http will be used. Note that https is limited to TLS 1.2 and 1.3

Using webn only for RPC

By setting config.path to null, webn becomes RPC only. This means two things. First, CORS will be allowed. It's up to you to secure your service as you see fit. Second, after importing webn you have to set the RPC URL manually, like so:

import webn from `http://webn-host.com:4000/webn`

document.body.onload = async function() {
	webn.url = 'http://webn-host.com:4000'
	const text = await webn.test('testing')
	alert(text)
}

The this object

In the webn serverside functions, a couple of utilities are available in the this object, which represents the current request:

Cookies

this.cookies can be read from to obtain the request cookies, or written to to set response cookies. Like so:

webn({
	test() {
		// read the "fromclient" cookie
		console.log(this.cookie.fromclient)
		// set the "toclient" cookie
		this.cookie.toclient = 'some value'
	}
})

Note that you can't see the values of cookies that you set!

Logging

You can use the logging functions to log informative text as well as error messages via this.info and this.error.

webn({
	fn(input) {
		this.info('input is: ', input)
		if(info == 0) this.error('input = 0 detected!')
	}
})

Scoped functions

You can put a function inside an object to protect it from unauthorized access. The this.grant and this.revoke functions allows you to control access to the objects. Note that this.grant takes the object path as a string, while this.revoke takes a regexp to allow you to revoke multiple authorizations at once. Use this.revoke(/.*/) to revoke all authorizations. A list of authorizations can be obtained from this.grants.

webn({
	login(password) {
		if(password == 'super_secret') this.grant('protected')
	},

	logout() {
		this.revoke()
	},

	protected: {
		internal() {
			return 'stuff that you need to log in to see'
		}
	}
})

Session object

Once you used this.grant for a certain user, even if you called it with no parameters, there will be a session object available in this.session, where you can save anything you want to attach it to the user's session. Using this.revoke with no parameters will remove the session object.

webn({
	fn1() {
		this.grant()
	},

	fn2() {
		this.session.hello = 'hello'
	}
})

Throwing errors

Throwing an error in a webn function will result in the error being thrown on the client side.

webn({
	login(password) {
		if(password != 'correct password') throw 'Wrong password!'
		return 'Welcome'
	}
})

There is a difference between throwing a string and throwing an actual error object. Throwing a string will simply throw it on the client side. Throwing an error object will do that, but also print the stack trace to the error log.

FAQ

Q: This is literally just a dumb web server that translates POST requests into function calls, right?\ A: Pretty much, yeah.

Q: I want to use promises or async execution in the backend part.\ A: Just do it, all the functions are ran with await. Also, to receive the return value in the frontend, it's important to use await there as well.

Q: I want to use it together with webpack/gulp/react/express(?)/sass/whatever, how do I do that?\ A: The only thing webn does is serve the things in the ui folder via http (or https see below) and let you call functions over AJAX. If you use something that puts whatever in that folder, it'll work.

Q: Where do I insert my middleware for headers/cookies/corporate proxy handling/whatever?\ A: This isn't express. It's meant for small, simple applications. If you do anything more serious, use something else. Cookies and sessions are supported via the this object, see above.

Q: Why do you use that license?\ A: The code was written for something else and repurposed into this project. It's just about 200 lines of not complex code. Anyone can use it for anything without limits, I decided. Most common use case is probably to study as a cautionary tale.

0.2.10

1 year ago

0.2.7

2 years ago

0.2.6

2 years ago

0.2.9

2 years ago

0.2.8

2 years ago

0.2.5

2 years ago

0.2.4

2 years ago

0.2.3

2 years ago

0.2.2

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.1.11

3 years ago

0.1.10

3 years ago

0.1.9

3 years ago

0.1.8

3 years ago

0.1.7

3 years ago

0.1.6

3 years ago

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.0

3 years ago

0.1.1

3 years ago