instaserve 0.0.30 → 0.0.41

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.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # instaserve
2
+ Instant web stack
@@ -1,11 +1,11 @@
1
- [
2
- [
3
- "user:admin",
4
- {
5
- "type": "user",
6
- "name": "admin",
7
- "pass": "01b613da484bee91c3f3806b52a6f40fd61ade874b5ffc0f62a2091cce38158b",
8
- "id": "user:admin"
9
- }
10
- ]
1
+ [
2
+ [
3
+ "user:admin",
4
+ {
5
+ "type": "user",
6
+ "name": "admin",
7
+ "pass": "01b613da484bee91c3f3806b52a6f40fd61ade874b5ffc0f62a2091cce38158b",
8
+ "id": "user:admin"
9
+ }
10
+ ]
11
11
  ]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "instaserve",
3
- "version": "0.0.30",
4
- "description": "",
5
- "main": "index.mjs",
6
- "bin": "./index.mjs"
7
- }
3
+ "version": "0.0.41",
4
+ "description": "Instant web stack",
5
+ "main": "server.mjs",
6
+ "bin": "./server.mjs"
7
+ }
@@ -0,0 +1,150 @@
1
+ const w = {}, d = document
2
+
3
+ // helpers
4
+
5
+ w.$ = d.querySelector.bind(d)
6
+ w.$$ = d.querySelectorAll.bind(d)
7
+ w.loadJS = (src) => {
8
+ return new Promise((r, j) => {
9
+ if ($(`script[src="${src}"]`)) return r(true)
10
+ const s = d.createElement('script')
11
+ s.src = src
12
+ s.addEventListener('load', r)
13
+ d.head.appendChild(s)
14
+ })
15
+ }
16
+ w.loadCSS = (src) => {
17
+ return new Promise((r, j) => {
18
+ const s = document.createElement('link')
19
+ s.rel = 'stylesheet'
20
+ s.href = src
21
+ s.addEventListener('load', r)
22
+ d.head.appendChild(s)
23
+ })
24
+ }
25
+ w.wait = (ms) => new Promise((r) => setTimeout(r, ms))
26
+ w.ready = async () => {
27
+ return new Promise((r) => {
28
+ if (document.readyState === 'complete') r(true)
29
+ document.onreadystatechange = () => {
30
+ if (document.readyState === 'complete') r()
31
+ }
32
+ })
33
+ }
34
+ w.child = (type = 'div', html = '') => {
35
+ const e = d.createElement(type)
36
+ e.innerHTML = html
37
+ d.body.appendChild(e)
38
+ return e
39
+ }
40
+
41
+ // Custom element
42
+
43
+ w.element = (name, { onMount = x => x, beforeData = x => x, style, template = '' }) => {
44
+ customElements.define(name, class extends HTMLElement {
45
+ async connectedCallback(props) {
46
+ await onMount()
47
+ if (style) {
48
+ const s = document.createElement('style')
49
+ s.innerHTML = `${name} {${style}}`
50
+ d.body.appendChild(s)
51
+ }
52
+ this.template = template
53
+ if (!this.template.match('{'))
54
+ this.innerHTML = this.template
55
+ }
56
+ set(o) {
57
+ this.innerHTML = ''
58
+ o = beforeData(o)
59
+ if (!Array.isArray(o)) o = [o]
60
+ const m = new Function('o', 'return `' + this.template + '`')
61
+ o.map((i) => (this.innerHTML += m(o)))
62
+ }
63
+ })
64
+ }
65
+
66
+ if (window.components) {
67
+ for (let name in window.components)
68
+ w.element(name, window.components[name])
69
+ }
70
+
71
+ // Data
72
+
73
+ w.state = new Proxy(
74
+ {}, {
75
+ set: (obj, prop, value) => {
76
+ let ret = []
77
+ for (const e of $$(`[data*=${prop}]`)) {
78
+ console.log(['setting e', e.tagName, e.id, value])
79
+ e.set(value)
80
+ }
81
+ obj[prop] = value
82
+ },
83
+ get: (obj, prop, receiver) => {
84
+ if (prop == '_state') return obj
85
+ return obj[prop]
86
+ },
87
+ }
88
+ )
89
+
90
+ w.dataEvent = (x) => console.log(`dataevent: ${x}`)
91
+
92
+ w.fetchJSON = async (url, key) => {
93
+ const j = await (await fetch(url)).json()
94
+ if (key) state[key] = j
95
+ dataEvent(j)
96
+ return j
97
+ }
98
+
99
+ w.streamJSON = async (url, key) => {
100
+ const ev = new EventSource(url)
101
+ ev.onmessage = (ev) => {
102
+ const j = JSON.parse(ev.data)
103
+ if (key) state[key] = j
104
+ dataEvent(j)
105
+ return j
106
+ }
107
+ }
108
+
109
+ // State changes
110
+
111
+ w.trackStateChanges = () =>
112
+ (w.dataEvent = (o) =>
113
+ localStorage.set(new Date().toISOString(), JSON.stringify(o)))
114
+ w.untrackStateChanges = () =>
115
+ (w.dataEvent = (o) => console.log('dataevent:', o))
116
+
117
+ // Startup
118
+
119
+ w.start = async () => {
120
+ await w.ready();
121
+ [...$$('div')].map((e) => {
122
+ if (!e.id)
123
+ e.id = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 3)
124
+ e.pr = {};
125
+ [...e.attributes].map((a) => (e.pr[a.name] = a.value))
126
+ if (e.pr.fetch) e.fetch = fetchJSON.bind(null, e.pr.fetch, e.id)
127
+ if ('immediate' in e.pr) e.fetch()
128
+ if (e.pr.stream) e.stream = streamJSON.bind(null, e.pr.stream, e.id)
129
+ if (e.pr.data) {
130
+ if (e.innerHTML && e.innerHTML.includes('{')) {
131
+ e.template = e.innerHTML.replaceAll('{', '${')
132
+ e.innerHTML = ''
133
+ }
134
+ e.set = (o) => {
135
+ e.innerHTML = ''
136
+ if (!Array.isArray(o)) o = [o]
137
+ const m = new Function('o', 'return `' + e.template + '`')
138
+ o.map((i) => (e.innerHTML += m(i)))
139
+ }
140
+ }
141
+ })
142
+ }
143
+
144
+ w.enigmatic = { version: '2022-03-05 0.10.2' }
145
+ Object.assign(window, w);
146
+
147
+ (async () => {
148
+ await w.start()
149
+ if (window.main) window.main()
150
+ })()
@@ -0,0 +1,7 @@
1
+ <!DOCTYPE html>
2
+ <script>
3
+ // navigator.serviceWorker.register('sw.js')
4
+ </script>
5
+ <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css'>
6
+
7
+ <div class='bg-yellow-200'>hello</div>
package/public/sw.js ADDED
@@ -0,0 +1,18 @@
1
+ self.addEventListener('fetch', event => {
2
+ const cache = await caches.open('e')
3
+ const req = event.request
4
+
5
+ event.respondWith(async () => {
6
+ if(!req.url.match(/\.js$|\.css$/))
7
+ return fetch(req)
8
+
9
+ const response = await cache.match(req)
10
+ if(response) return response
11
+ response = await fetch(req)
12
+
13
+ if(response.status == 200)
14
+ cache.put(req, response)
15
+
16
+ return response
17
+ })
18
+ })
package/routes.mjs ADDED
@@ -0,0 +1,19 @@
1
+ /*
2
+ routes.mjs
3
+ Unders
4
+ */
5
+
6
+ import FS from 'node:fs'
7
+ export default {
8
+ _debug: ({ r, s, db }) => console.log(r.url, r.method),
9
+ _static: ({r, s}) => {
10
+ if(r.url == '/') r.url = '/index.html'
11
+ const fn = `./public${r.url.replace('..', '')}`
12
+ if(FS.existsSync(fn)) {
13
+ if (fn.match(/sw\.js/)) s.writeHead(200, { 'Content-Type': 'application/javascript' })
14
+ return !s.end(FS.readFileSync(fn, 'utf-8'))
15
+ }
16
+ },
17
+
18
+ '/api': ({s})=>s.end('example of an api response'),
19
+ }
package/server.mjs ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ import http from 'node:http';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { resolve } from 'node:path';
6
+
7
+ const routesfile = resolve('routes.mjs');
8
+ const routesurl = pathToFileURL(routesfile).href;
9
+ console.log(routesfile, routesurl);
10
+
11
+ const routes = (await import(routesurl)).default;
12
+ const VastDB = (await import(`./vastdb.mjs`)).default;
13
+ const db = new VastDB(routes);
14
+ console.log(db.filename, routes);
15
+
16
+ http
17
+ .createServer(async (r, s) => {
18
+ try {
19
+ let data = '';
20
+ r.on('data', (s) => (data += s.toString()));
21
+ r.on('end', (x) => {
22
+ try {
23
+ data = JSON.parse(data);
24
+ } catch {}
25
+ });
26
+ s.endJSON = (o) => s.end(JSON.stringify(o));
27
+ const midware = Object.keys(routes)
28
+ .filter((k) => k.startsWith('_'))
29
+ .find((k) => routes[k]({ r, s, data, db }));
30
+ if (routes[r.url]) return routes[r.url]({ r, s, data, db });
31
+ else s.writeHead(404).end();
32
+ } catch (e) {
33
+ console.log(e);
34
+ s.writeHead(404).end();
35
+ }
36
+ })
37
+ .listen(3000, (x) => console.log('listening on 3000'));
package/vastdb.mjs CHANGED
@@ -2,9 +2,8 @@ import fs from 'node:fs'
2
2
  export default class VastDB extends Map {
3
3
  constructor(v) {
4
4
  super();
5
- this.filename = `${process.cwd()}/db.json`;
5
+ this.filename = `${process.cwd()}/data/db.json`;
6
6
  this.views = v
7
- this.triggers = []
8
7
  if (!fs.existsSync(this.filename)) {
9
8
  this.set({
10
9
  type: 'user',
@@ -23,18 +22,18 @@ export default class VastDB extends Map {
23
22
  query(q = () => false) {
24
23
  return [...this].filter(q).map(([k, v]) => v)
25
24
  }
26
- getView(name) {
27
- if(!this.views[name]) throw `view ${name} does not exist`
28
- return this.query(this.views[name])
25
+ getView(name, param) {
26
+ const res = [...this].filter(this.views[name](param));
27
+ return res.map(([k, v]) => v);
29
28
  }
30
29
  set(arr) {
31
30
  if (!arr.push) arr = [arr];
32
31
  for (const o of arr) {
33
32
  if (!o.name || !o.type) return false;
34
33
  if (!o.id) o.id = o.type + ':' + o.name;
35
- this.triggers.map(t => o = t(o))
36
34
  }
37
35
  arr.map((o) => super.set(o.id, o));
36
+ if(this.event) this.event(arr)
38
37
  this.save();
39
38
  }
40
39
  save() {
package/index.mjs DELETED
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env node
2
- import http from 'node:http'
3
- import fs from 'node:fs'
4
- import {pathToFileURL} from 'node:url'
5
- import { resolve } from 'node:path'
6
-
7
- const routesfile = resolve('routes.mjs')
8
- const routesurl = pathToFileURL(routesfile).href
9
- const indexfile = resolve('index.html')
10
-
11
- console.log(routesfile, routesurl)
12
-
13
- if (!fs.existsSync(routesfile)) {
14
- fs.writeFileSync(routesfile, `import fs from 'node:fs'
15
- export default {
16
- _debug: ({ r, s, db }) => console.log(r.url, r.method),
17
- '/': e => e.s.end(fs.readFileSync('index.html', 'utf-8')),
18
- '/post': ({ e, body }) => db.set(body),
19
- '/tables': ({s}) => s.endJSON(db.getView('tables')),
20
- 'tables': name => ([k, v]) => k.match(name + ':')
21
- }`)
22
- }
23
- if (!fs.existsSync(indexfile)) {
24
- fs.writeFileSync(indexfile, `<!DOCTYPE html>
25
- <link rel="icon" href="data:,">
26
- <script>navigator.serviceWorker.register('sw.js')</script>
27
- <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css'>
28
- <script src='https://unpkg.com/enigmatic/enigmatic.js'></script>
29
-
30
- <div class='bg-yellow-200'>hello</div>`)
31
- }
32
-
33
- const routes = (await import(routesurl)).default
34
- routes['/sw.js'] = e => {
35
- e.s.writeHead(201, { 'Content-Type': 'application/javascript' })
36
- e.s.end('self.addEventListener("fetch",e=>{e.respondWith(caches.open("e").then(function(t){return t.match(e.request).then(function(n){return n||fetch(e.request).then(function(n){return e.request.url.match(/\.js$|\.css$/)&&t.put(e.request,n.clone()),n})})}))});')
37
- }
38
- const VastDB = (await import(`./vastdb.mjs`)).default
39
- const db = new VastDB(routes)
40
- console.log(db.filename, routes)
41
-
42
- http
43
- .createServer(async (r, s) => {
44
- try {
45
- let data = '';
46
- r.on('data', (s) => (data += s.toString()));
47
- r.on('end', (x) => {
48
- try {
49
- data = JSON.parse(data);
50
- } catch { }
51
- });
52
- s.endJSON = o => s.end(JSON.stringify(o))
53
- const midware = Object.keys(routes)
54
- .filter((k) => k.startsWith('_'))
55
- .map((k) => routes[k]({ r, s, data, db }));
56
- if (midware.includes(true)) return;
57
- if (routes[r.url]) return routes[r.url]({ r, s, data, db });
58
- else s.writeHead(404).end()
59
- } catch (e) {
60
- console.log(e);
61
- s.writeHead(404).end();
62
- }
63
- })
64
- .listen(3000, (x) => console.log('listening on 3000'));
package/test.mjs DELETED
@@ -1,22 +0,0 @@
1
- import Vast from './vastdb.mjs'
2
- const db = new Vast()
3
-
4
- db.views = {
5
- tables: ([k, v]) => k.match('user')
6
- }
7
-
8
- db.triggers = {
9
- test_trigger: record => record.value = 100
10
- }
11
-
12
- db.workflows = {
13
- 'testwf' : {
14
- start: db => 'wait_two_sec',
15
- wait_two_sec: db => new Promise(r => setTimeout(r('end'), 2000)),
16
- end: db => console.log('done')
17
- }
18
- }
19
-
20
- //console.log(db.getView('tables'))
21
- db.set({name: 'testrec', value: 0})
22
- console.log(db)