divhunt 2.0.6 → 2.0.9

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.
Files changed (39) hide show
  1. package/addons/core/commands/back/functions/expose.js +14 -0
  2. package/addons/core/commands/back/functions/find.js +1 -1
  3. package/addons/core/commands/back/functions/grpc/client.js +1 -1
  4. package/addons/core/commands/back/functions/grpc/server.js +1 -1
  5. package/addons/core/commands/back/functions/hide.js +14 -0
  6. package/addons/core/commands/back/functions/http/server.js +1 -1
  7. package/addons/core/commands/back/items/{many.js → self/many.js} +2 -4
  8. package/addons/core/commands/back/items/{one.js → self/one.js} +2 -4
  9. package/addons/core/commands/back/items/{run.js → self/run.js} +3 -7
  10. package/addons/core/commands/core/functions/run.js +13 -0
  11. package/addons/core/commands/{back → core}/item/functions/run.js +1 -1
  12. package/addons/core/commands/core/load.js +25 -0
  13. package/addons/core/commands/front/directives/run.js +84 -0
  14. package/addons/core/commands/front/directives/submit.js +150 -0
  15. package/addons/core/commands/front/functions/api.js +30 -0
  16. package/addons/render/assets/back/functions/import.js +1 -1
  17. package/examples/basic-front/back/assets.js +11 -0
  18. package/examples/basic-front/back/index.js +13 -0
  19. package/examples/basic-front/back/items/commands/html.js +14 -0
  20. package/examples/basic-front/back/items/commands/test.js +19 -0
  21. package/examples/basic-front/back/items/html/fonts.js +12 -0
  22. package/examples/basic-front/front/pages/home.js +16 -0
  23. package/examples/basic-front/front/styles/main.css +31 -0
  24. package/examples/basic-front/front/test.js +7 -0
  25. package/examples/basic-front/package.json +7 -0
  26. package/lib/src/divhunt.js +2 -0
  27. package/lib/src/mixins/form.js +67 -0
  28. package/package.json +3 -3
  29. package/test/front/test.js +31 -0
  30. package/test.js +52 -0
  31. package/addons/core/commands/LICENSE.txt +0 -40
  32. package/addons/core/commands/README.md +0 -294
  33. package/addons/core/commands/back/load.js +0 -18
  34. package/addons/core/commands/front/#register/addon.js +0 -9
  35. package/addons/core/commands/front/functions/find.js +0 -22
  36. package/addons/core/commands/front/item/functions/run.js +0 -96
  37. package/addons/core/commands/front/items/elements/table/table.css +0 -18
  38. package/addons/core/commands/front/items/elements/table/table.js +0 -254
  39. /package/addons/core/commands/{back → core}/addon.js +0 -0
@@ -0,0 +1,14 @@
1
+ import commands from '#commands/core/addon.js';
2
+
3
+ commands.Fn('expose', function(id, endpoint = null)
4
+ {
5
+ const command = commands.ItemGet(id);
6
+
7
+ if(!command)
8
+ {
9
+ return;
10
+ }
11
+
12
+ command.Set('exposed', true);
13
+ command.Set('endpoint', endpoint || '/api/' + id.replace(/:/g, '/'));
14
+ });
@@ -1,4 +1,4 @@
1
- import commands from '../addon.js';
1
+ import commands from '#commands/core/addon.js';
2
2
 
3
3
  commands.Fn('find', function(method, pathname)
4
4
  {
@@ -1,4 +1,4 @@
1
- import commands from '../../addon.js';
1
+ import commands from '#commands/core/addon.js';
2
2
 
3
3
  commands.Fn('grpc.client', async function(host, port, metadata = {}, prefix = 'remote', bidirectional = false, callbacks = {})
4
4
  {
@@ -1,4 +1,4 @@
1
- import commands from '../../addon.js';
1
+ import commands from '#commands/core/addon.js';
2
2
 
3
3
  commands.Fn('grpc.server', async function(port = 50000, callbacks = {})
4
4
  {
@@ -0,0 +1,14 @@
1
+ import commands from '#commands/core/addon.js';
2
+
3
+ commands.Fn('hide', function(id)
4
+ {
5
+ const command = commands.ItemGet(id);
6
+
7
+ if(!command)
8
+ {
9
+ return;
10
+ }
11
+
12
+ command.Set('exposed', false);
13
+ command.Set('endpoint', null);
14
+ });
@@ -1,5 +1,5 @@
1
1
  import divhunt from '#framework/load.js';
2
- import commands from '../../addon.js';
2
+ import commands from '#commands/core/addon.js';
3
3
 
4
4
  commands.Fn('http.server', async function(port = 3000, callbacks = {})
5
5
  {
@@ -1,11 +1,9 @@
1
1
  import divhunt from '#framework/load.js';
2
- import commands from '../addon.js';
2
+ import commands from '#commands/core/addon.js';
3
3
 
4
4
  commands.Item({
5
5
  id: 'commands:get:many',
6
- exposed: true,
7
6
  method: 'GET',
8
- endpoint: '/api/commands',
9
7
  type: 'JSON',
10
8
  out: {
11
9
  commands: {
@@ -44,7 +42,7 @@ commands.Item({
44
42
  {
45
43
  const list = [];
46
44
 
47
- Object.values(commands.Items()).forEach((item) =>
45
+ Object.values(commands.Items()).forEach((item) =>
48
46
  {
49
47
  if(!item.Get('exposed'))
50
48
  {
@@ -1,11 +1,9 @@
1
1
  import divhunt from '#framework/load.js';
2
- import commands from '../addon.js';
2
+ import commands from '#commands/core/addon.js';
3
3
 
4
4
  commands.Item({
5
5
  id: 'commands:get:one',
6
- exposed: true,
7
6
  method: 'GET',
8
- endpoint: '/api/commands/:id',
9
7
  type: 'JSON',
10
8
  in: {
11
9
  id: ['string']
@@ -73,4 +71,4 @@ commands.Item({
73
71
  }
74
72
  });
75
73
  }
76
- });
74
+ });
@@ -1,10 +1,8 @@
1
- import commands from '../addon.js';
1
+ import commands from '#commands/core/addon.js';
2
2
 
3
3
  commands.Item({
4
4
  id: 'commands:run',
5
- exposed: true,
6
5
  method: 'POST',
7
- endpoint: '/api/commands/run',
8
6
  type: 'JSON',
9
7
  in: {
10
8
  id: ['string', null, true],
@@ -17,8 +15,6 @@ commands.Item({
17
15
  },
18
16
  callback: async function(properties, resolve)
19
17
  {
20
- console.log(properties.id);
21
-
22
18
  const command = commands.ItemGet(properties.id);
23
19
 
24
20
  if(!command)
@@ -31,7 +27,7 @@ commands.Item({
31
27
  return resolve(null, 'Command is not exposed.', 403);
32
28
  }
33
29
 
34
- try
30
+ try
35
31
  {
36
32
  const result = await commands.Item(properties.id).Fn('run', (properties.data || {}));
37
33
 
@@ -46,4 +42,4 @@ commands.Item({
46
42
  resolve(null, error.message, typeof error.code === 'number' ? error.code : 500);
47
43
  }
48
44
  }
49
- });
45
+ });
@@ -0,0 +1,13 @@
1
+ import commands from '#commands/core/addon.js';
2
+
3
+ commands.Fn('run', async function(id, data = {})
4
+ {
5
+ const command = commands.ItemGet(id);
6
+
7
+ if(!command)
8
+ {
9
+ throw new Error(`Command '${id}' not found.`);
10
+ }
11
+
12
+ return await command.Fn('run', data);
13
+ });
@@ -1,5 +1,5 @@
1
1
  import divhunt from '#framework/load.js';
2
- import commands from '../../addon.js';
2
+ import commands from '#commands/core/addon.js';
3
3
 
4
4
  commands.Fn('item.run', function(item, properties = {}, onChunk = null, context = {})
5
5
  {
@@ -0,0 +1,25 @@
1
+ import commands from '#commands/core/addon.js';
2
+
3
+ import '#commands/core/item/functions/run.js';
4
+ import '#commands/core/functions/run.js';
5
+
6
+ /* gRPC */
7
+ import '#commands/back/functions/grpc/server.js';
8
+ import '#commands/back/functions/grpc/client.js';
9
+
10
+ /* HTTP */
11
+ import '#commands/back/functions/http/server.js';
12
+
13
+ /* Find */
14
+ import '#commands/back/functions/find.js';
15
+
16
+ /* Expose */
17
+ import '#commands/back/functions/expose.js';
18
+ import '#commands/back/functions/hide.js';
19
+
20
+ /* Items */
21
+ import '#commands/back/items/self/one.js';
22
+ import '#commands/back/items/self/many.js';
23
+ import '#commands/back/items/self/run.js';
24
+
25
+ export default commands;
@@ -0,0 +1,84 @@
1
+ directives.ItemAdd({
2
+ id: 'dh-command',
3
+ icon: 'terminal',
4
+ name: 'Command',
5
+ description: 'Execute a command instantly on render',
6
+ category: 'data',
7
+ trigger: 'node',
8
+ order: 664,
9
+ strict: false,
10
+ tag: 'dh-command',
11
+ attributes: {
12
+ 'command': ['string', null, true],
13
+ 'bind': ['string', 'command'],
14
+ '_success': ['function'],
15
+ '_error': ['function'],
16
+ 'data': ['object', {}],
17
+ 'api': ['boolean', false]
18
+ },
19
+ code: function(data, item, compile, node, identifier)
20
+ {
21
+ const config = {};
22
+ const methods = {};
23
+
24
+ methods.init = () =>
25
+ {
26
+ methods.config();
27
+
28
+ if(compile.data[config.bind] !== undefined)
29
+ {
30
+ return;
31
+ }
32
+
33
+ compile.data[config.bind] = null;
34
+ methods.run();
35
+ };
36
+
37
+ methods.config = () =>
38
+ {
39
+ config.command = data['command'].value;
40
+ config.bind = data['bind'].value;
41
+ config.onSuccess = data['_success'].value;
42
+ config.onError = data['_error'].value;
43
+ config.data = data['data'].value;
44
+ config.api = data['api'].value;
45
+ };
46
+
47
+ methods.run = async () =>
48
+ {
49
+ const state = {
50
+ response: null,
51
+ error: null,
52
+ loading: true
53
+ };
54
+
55
+ try
56
+ {
57
+ const result = config.api
58
+ ? await commands.Fn('api', config.command, config.data)
59
+ : await commands.Fn('run', config.command, config.data);
60
+
61
+ state.response = result;
62
+ state.error = null;
63
+ state.loading = false;
64
+
65
+ config.onSuccess && config.onSuccess(state);
66
+ }
67
+ catch(error)
68
+ {
69
+ state.response = null;
70
+ state.error = error.message;
71
+ state.loading = false;
72
+
73
+ config.onError && config.onError(state);
74
+ }
75
+ finally
76
+ {
77
+ compile.data[config.bind] = state;
78
+ compile.data.Update();
79
+ }
80
+ };
81
+
82
+ methods.init();
83
+ }
84
+ });
@@ -0,0 +1,150 @@
1
+ directives.ItemAdd({
2
+ id: 'dh-command-submit',
3
+ icon: 'terminal',
4
+ name: 'Command Submit',
5
+ description: 'Submit form data to a command via commands.Fn',
6
+ category: 'data',
7
+ trigger: 'node',
8
+ order: 665,
9
+ strict: false,
10
+ tag: 'dh-command-submit',
11
+ attributes: {
12
+ 'command': ['string', null, true],
13
+ 'bind': ['string', 'command'],
14
+ '_success': ['function'],
15
+ '_error': ['function'],
16
+ 'reset': ['boolean', false],
17
+ 'stop': ['boolean', false],
18
+ 'data': ['object', {}],
19
+ 'api': ['boolean', false]
20
+ },
21
+ code: function(data, item, compile, node, identifier)
22
+ {
23
+ const config = {};
24
+ const methods = {};
25
+
26
+ methods.init = () =>
27
+ {
28
+ methods.config();
29
+
30
+ if(compile.data[config.bind] !== undefined)
31
+ {
32
+ return;
33
+ }
34
+
35
+ compile.data[config.bind] = {
36
+ response: null,
37
+ error: null,
38
+ loading: false
39
+ };
40
+
41
+ methods.element();
42
+ methods.handler();
43
+ };
44
+
45
+ methods.config = () =>
46
+ {
47
+ config.command = data['command'].value;
48
+ config.bind = data['bind'].value;
49
+ config.onSuccess = data['_success'].value;
50
+ config.onError = data['_error'].value;
51
+ config.reset = data['reset'].value;
52
+ config.stop = data['stop'].value;
53
+ config.data = data['data'].value;
54
+ config.api = data['api'].value;
55
+ };
56
+
57
+ methods.element = () =>
58
+ {
59
+ config.form = document.createElement('form');
60
+ config.form.setAttribute('autocomplete', 'off');
61
+
62
+ while(node.firstChild)
63
+ {
64
+ config.form.appendChild(node.firstChild);
65
+ }
66
+
67
+ node.appendChild(config.form);
68
+ divhunt.FormSet(config.form, config.data);
69
+ };
70
+
71
+ methods.handler = () =>
72
+ {
73
+ config.form.dhCommandSubmit = async (event) =>
74
+ {
75
+ event.preventDefault();
76
+
77
+ if(config.stop)
78
+ {
79
+ event.stopPropagation();
80
+ }
81
+
82
+ await methods.submit();
83
+ };
84
+ };
85
+
86
+ methods.submit = async () =>
87
+ {
88
+ const state = compile.data[config.bind];
89
+
90
+ if(state.loading)
91
+ {
92
+ return;
93
+ }
94
+
95
+ state.loading = true;
96
+ state.error = null;
97
+
98
+ compile.data.Update();
99
+
100
+ try
101
+ {
102
+ const formData = divhunt.FormGet(config.form);
103
+ const result = config.api
104
+ ? await commands.Fn('api', config.command, formData)
105
+ : await commands.Fn('run', config.command, formData);
106
+
107
+ state.response = result;
108
+ state.error = null;
109
+ state.loading = false;
110
+
111
+ config.reset && config.form.reset();
112
+ config.onSuccess && config.onSuccess(state);
113
+ }
114
+ catch(error)
115
+ {
116
+ state.response = null;
117
+ state.error = error.message;
118
+ state.loading = false;
119
+
120
+ config.onError && config.onError(state);
121
+ }
122
+ finally
123
+ {
124
+ compile.data[config.bind] = state;
125
+ compile.data.Update();
126
+ }
127
+ };
128
+
129
+ methods.init();
130
+ }
131
+ });
132
+
133
+ divhunt.AddonReady('directives', function()
134
+ {
135
+ document.addEventListener('submit', function(event)
136
+ {
137
+ let node = event.target;
138
+
139
+ while(node && node !== document)
140
+ {
141
+ if('dhCommandSubmit' in node)
142
+ {
143
+ node.dhCommandSubmit(event);
144
+ break;
145
+ }
146
+
147
+ node = node.parentNode;
148
+ }
149
+ });
150
+ });
@@ -0,0 +1,30 @@
1
+ commands.Fn('api', async function(id, data = {})
2
+ {
3
+ try
4
+ {
5
+ const response = await fetch('/api/commands/run', {
6
+ method: 'POST',
7
+ headers: {
8
+ 'Content-Type': 'application/json'
9
+ },
10
+ body: JSON.stringify({ id, data })
11
+ });
12
+
13
+ const result = await response.json();
14
+
15
+ if(result.code !== 200)
16
+ {
17
+ throw result.data;
18
+ }
19
+
20
+ return { time: result.time, ...result.data };
21
+ }
22
+ catch(error)
23
+ {
24
+ return {
25
+ data: null,
26
+ message: error.message,
27
+ code: 500
28
+ };
29
+ }
30
+ });
@@ -8,7 +8,7 @@ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..',
8
8
  const map =
9
9
  {
10
10
  framework: { js: 'lib', ignore: ['lib/load.js'] },
11
- commands: { js: 'addons/core/commands/front', css: 'addons/core/commands/front' },
11
+ commands: { js: 'addons/core/commands', css: 'addons/core/commands/front', ignore: ['addons/core/commands/back'] },
12
12
  database: { js: 'addons/core/database/front' },
13
13
  actions: { js: 'addons/modules/actions/front' },
14
14
  bugs: { js: 'addons/modules/bugs/front' },
@@ -0,0 +1,11 @@
1
+ import assets from 'divhunt/assets';
2
+
3
+ import { dirname, resolve } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
7
+
8
+ assets.Fn('import', ['framework', 'commands', 'pages']);
9
+
10
+ assets.Item({ type: 'js', order: 10, path: resolve(root, 'front') });
11
+ assets.Item({ type: 'css', order: 10, path: resolve(root, 'front') });
@@ -0,0 +1,13 @@
1
+ import './assets.js';
2
+ import './items/html/fonts.js';
3
+ import './items/commands/html.js';
4
+ import './items/commands/test.js';
5
+
6
+ import commands from 'divhunt/commands';
7
+
8
+ commands.Fn('http.server', 3000, {
9
+ onStart: () =>
10
+ {
11
+ console.log('basic-front running on http://localhost:3000');
12
+ }
13
+ });
@@ -0,0 +1,14 @@
1
+ import commands from 'divhunt/commands';
2
+ import html from 'divhunt/html';
3
+
4
+ commands.Item({
5
+ id: 'html',
6
+ exposed: true,
7
+ method: 'GET',
8
+ endpoint: '*',
9
+ type: 'HTML',
10
+ callback: async function(properties, resolve)
11
+ {
12
+ resolve(html.Fn('render'));
13
+ }
14
+ });
@@ -0,0 +1,19 @@
1
+ import commands from 'divhunt/commands';
2
+
3
+ commands.Item({
4
+ id: 'test',
5
+ exposed: true,
6
+ method: 'POST',
7
+ endpoint: '/api/test',
8
+ type: 'JSON',
9
+ in: {
10
+ name: ['string', 'World']
11
+ },
12
+ out: {
13
+ message: ['string']
14
+ },
15
+ callback: async function(properties, resolve)
16
+ {
17
+ resolve({ message: 'Hello, ' + properties.name + '!' });
18
+ }
19
+ });
@@ -0,0 +1,12 @@
1
+ import html from 'divhunt/html';
2
+
3
+ html.Item({
4
+ id: 'fonts',
5
+ tag: 'link',
6
+ position: 'head',
7
+ order: 85,
8
+ attributes: {
9
+ rel: 'stylesheet',
10
+ href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap'
11
+ }
12
+ });
@@ -0,0 +1,16 @@
1
+ pages.Item({
2
+ id: 'home',
3
+ route: '/',
4
+ title: 'Divhunt Framework',
5
+ areas: {
6
+ main: function()
7
+ {
8
+ return `
9
+ <div class="hero">
10
+ <h1>Hello from Divhunt Framework</h1>
11
+ <p>A minimal full-stack JavaScript framework.</p>
12
+ </div>
13
+ `;
14
+ }
15
+ }
16
+ });
@@ -0,0 +1,31 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
9
+ background: #0f0f0f;
10
+ color: #e0e0e0;
11
+ min-height: 100vh;
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ }
16
+
17
+ .hero {
18
+ text-align: center;
19
+ }
20
+
21
+ .hero h1 {
22
+ font-size: 48px;
23
+ font-weight: 600;
24
+ letter-spacing: -1px;
25
+ margin-bottom: 16px;
26
+ }
27
+
28
+ .hero p {
29
+ font-size: 16px;
30
+ color: #888;
31
+ }
@@ -0,0 +1,7 @@
1
+ const commands = divhunt.Addon('commands');
2
+
3
+ (async () =>
4
+ {
5
+ const result = await commands.Fn('api', 'test', { name: 'Dejan' });
6
+ console.log('api result:', result);
7
+ })();
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "basic-front-example",
3
+ "type": "module",
4
+ "dependencies": {
5
+ "divhunt": "^2.0.6"
6
+ }
7
+ }
@@ -16,6 +16,7 @@ import DivhuntHelper from './mixins/helper.js';
16
16
  import DivhuntRoute from './mixins/route.js';
17
17
  import DivhuntError from './mixins/error.js';
18
18
  import DivhuntCrypto from './mixins/crypto.js';
19
+ import DivhuntForm from './mixins/form.js';
19
20
 
20
21
  class Divhunt
21
22
  {
@@ -82,5 +83,6 @@ Object.assign(Divhunt.prototype, DivhuntHelper);
82
83
  Object.assign(Divhunt.prototype, DivhuntRoute);
83
84
  Object.assign(Divhunt.prototype, DivhuntError);
84
85
  Object.assign(Divhunt.prototype, DivhuntCrypto);
86
+ Object.assign(Divhunt.prototype, DivhuntForm);
85
87
 
86
88
  export default Divhunt;
@@ -0,0 +1,67 @@
1
+ const DivhuntForm =
2
+ {
3
+ FormGet(element)
4
+ {
5
+ const data = {};
6
+ const inputs = element.querySelectorAll('input[name], textarea[name], select[name]');
7
+
8
+ inputs.forEach(input =>
9
+ {
10
+ const name = input.getAttribute('name');
11
+
12
+ if(!name)
13
+ {
14
+ return;
15
+ }
16
+
17
+ if(input.type === 'checkbox')
18
+ {
19
+ data[name] = input.checked;
20
+ }
21
+ else if(input.type === 'radio')
22
+ {
23
+ if(input.checked)
24
+ {
25
+ data[name] = input.value;
26
+ }
27
+ }
28
+ else
29
+ {
30
+ data[name] = input.value;
31
+ }
32
+ });
33
+
34
+ return data;
35
+ },
36
+
37
+ FormSet(element, data)
38
+ {
39
+ if(!data || typeof data !== 'object')
40
+ {
41
+ return;
42
+ }
43
+
44
+ Object.entries(data).forEach(([name, value]) =>
45
+ {
46
+ const inputs = element.querySelectorAll(`[name="${name}"]`);
47
+
48
+ inputs.forEach(input =>
49
+ {
50
+ if(input.type === 'checkbox')
51
+ {
52
+ input.checked = !!value;
53
+ }
54
+ else if(input.type === 'radio')
55
+ {
56
+ input.checked = input.value === value;
57
+ }
58
+ else
59
+ {
60
+ input.value = value;
61
+ }
62
+ });
63
+ });
64
+ }
65
+ };
66
+
67
+ export default DivhuntForm;