divhunt 2.0.10 → 2.0.12

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.
@@ -25,8 +25,8 @@ commands.Fn('http.server', async function(port = 3000, callbacks = {})
25
25
 
26
26
  if(!command || !command.Get('exposed'))
27
27
  {
28
- http.response.code = 404;
29
- http.response.message = 'Command not found.';
28
+ http.respond.code = 404;
29
+ http.respond.message = 'Command not found.';
30
30
 
31
31
  callbacks['onResponse'] && callbacks['onResponse'](http);
32
32
  return;
@@ -47,7 +47,7 @@ commands.Fn('http.server', async function(port = 3000, callbacks = {})
47
47
  {
48
48
  http.data.streaming = 1;
49
49
  http.prevent = true;
50
- http.raw.writeHead(200, {
50
+ http.response.writeHead(200, {
51
51
  'Content-Type': type.contentType,
52
52
  'Transfer-Encoding': 'chunked'
53
53
  });
@@ -58,7 +58,7 @@ commands.Fn('http.server', async function(port = 3000, callbacks = {})
58
58
  if(http.data.streaming)
59
59
  {
60
60
  http.data.streaming++;
61
- http.raw.write(type.formatter(chunk.data) + '\n');
61
+ http.response.write(type.formatter(chunk.data) + '\n');
62
62
  }
63
63
 
64
64
  callbacks['onChunk'] && callbacks['onChunk'](http, chunk);
@@ -68,16 +68,16 @@ commands.Fn('http.server', async function(port = 3000, callbacks = {})
68
68
  {
69
69
  if(http.data.streaming === 1)
70
70
  {
71
- http.raw.write(type.formatter(response.data) + '\n');
71
+ http.response.write(type.formatter(response.data) + '\n');
72
72
  }
73
73
 
74
- http.raw.end();
74
+ http.response.end();
75
75
  }
76
76
 
77
- http.response.type = command.Get('type');
78
- http.response.data = response.data;
79
- http.response.message = response.message;
80
- http.response.code = response.code;
77
+ http.respond.type = command.Get('type');
78
+ http.respond.data = response.data;
79
+ http.respond.message = response.message;
80
+ http.respond.code = response.code;
81
81
 
82
82
  callbacks['onResponse'] && callbacks['onResponse'](http);
83
83
  },
@@ -1,90 +1,92 @@
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
- if(node.tagName.toLowerCase() !== 'dh-command')
1
+ divhunt.AddonReady('directives', function()
2
+ {
3
+ directives.ItemAdd({
4
+ id: 'dh-command',
5
+ icon: 'terminal',
6
+ name: 'Command',
7
+ description: 'Execute a command instantly on render',
8
+ category: 'data',
9
+ trigger: 'node',
10
+ order: 664,
11
+ strict: false,
12
+ tag: 'dh-command',
13
+ attributes: {
14
+ 'command': ['string', null, true],
15
+ 'bind': ['string', 'command'],
16
+ '_success': ['function'],
17
+ '_error': ['function'],
18
+ 'data': ['object', {}],
19
+ 'api': ['boolean', false]
20
+ },
21
+ code: function(data, item, compile, node, identifier)
22
22
  {
23
- return;
24
- }
25
-
26
- const config = {};
27
- const methods = {};
28
-
29
- methods.init = () =>
30
- {
31
- methods.config();
32
-
33
- if(compile.data[config.bind] !== undefined)
23
+ if(node.tagName.toLowerCase() !== 'dh-command')
34
24
  {
35
25
  return;
36
26
  }
37
27
 
38
- compile.data[config.bind] = null;
39
- methods.run();
40
- };
28
+ const config = {};
29
+ const methods = {};
41
30
 
42
- methods.config = () =>
43
- {
44
- config.command = data['command'].value;
45
- config.bind = data['bind'].value;
46
- config.onSuccess = data['_success'].value;
47
- config.onError = data['_error'].value;
48
- config.data = data['data'].value;
49
- config.api = data['api'].value;
50
- };
31
+ methods.init = () =>
32
+ {
33
+ methods.config();
51
34
 
52
- methods.run = async () =>
53
- {
54
- const state = {
55
- response: null,
56
- error: null,
57
- loading: true
35
+ if(compile.data[config.bind] !== undefined)
36
+ {
37
+ return;
38
+ }
39
+
40
+ compile.data[config.bind] = null;
41
+ methods.run();
58
42
  };
59
43
 
60
- try
44
+ methods.config = () =>
61
45
  {
62
- const result = config.api
63
- ? await commands.Fn('api', config.command, config.data)
64
- : await commands.Fn('run', config.command, config.data);
65
-
66
- state.response = result;
67
- state.error = null;
68
- state.loading = false;
46
+ config.command = data['command'].value;
47
+ config.bind = data['bind'].value;
48
+ config.onSuccess = data['_success'].value;
49
+ config.onError = data['_error'].value;
50
+ config.data = data['data'].value;
51
+ config.api = data['api'].value;
52
+ };
69
53
 
70
- config.onSuccess && config.onSuccess(state);
71
- }
72
- catch(error)
54
+ methods.run = async () =>
73
55
  {
74
- state.response = null;
75
- state.error = error.message;
76
- state.loading = false;
56
+ const state = {
57
+ response: null,
58
+ error: null,
59
+ loading: true
60
+ };
77
61
 
78
- config.onError && config.onError(state);
79
- }
80
- finally
81
- {
82
-
83
- compile.data[config.bind] = state;
84
- compile.data.Update();
85
- }
86
- };
62
+ try
63
+ {
64
+ const result = config.api
65
+ ? await commands.Fn('api', config.command, config.data)
66
+ : await commands.Fn('run', config.command, config.data);
87
67
 
88
- methods.init();
89
- }
68
+ state.response = result;
69
+ state.error = null;
70
+ state.loading = false;
71
+
72
+ config.onSuccess && config.onSuccess(state);
73
+ }
74
+ catch(error)
75
+ {
76
+ state.response = null;
77
+ state.error = error.message;
78
+ state.loading = false;
79
+
80
+ config.onError && config.onError(state);
81
+ }
82
+ finally
83
+ {
84
+ compile.data[config.bind] = state;
85
+ compile.data.Update();
86
+ }
87
+ };
88
+
89
+ methods.init();
90
+ }
91
+ });
90
92
  });
@@ -1,139 +1,139 @@
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 = () =>
1
+ divhunt.AddonReady('directives', function()
2
+ {
3
+ directives.ItemAdd({
4
+ id: 'dh-command-submit',
5
+ icon: 'terminal',
6
+ name: 'Command Submit',
7
+ description: 'Submit form data to a command via commands.Fn',
8
+ category: 'data',
9
+ trigger: 'node',
10
+ order: 665,
11
+ strict: false,
12
+ tag: 'dh-command-submit',
13
+ attributes: {
14
+ 'command': ['string', null, true],
15
+ 'bind': ['string', 'command'],
16
+ '_success': ['function'],
17
+ '_error': ['function'],
18
+ 'reset': ['boolean', false],
19
+ 'stop': ['boolean', false],
20
+ 'data': ['object', {}],
21
+ 'api': ['boolean', false]
22
+ },
23
+ code: function(data, item, compile, node, identifier)
27
24
  {
28
- methods.config();
29
- methods.state();
30
- methods.element();
31
- methods.handler();
32
- };
25
+ const config = {};
26
+ const methods = {};
33
27
 
34
- methods.state = () =>
35
- {
36
- if(!compile.data[config.bind])
28
+ methods.init = () =>
37
29
  {
38
- compile.data[config.bind] = {
39
- response: null,
40
- error: null,
41
- loading: false
42
- };
43
- }
44
- };
45
-
46
- methods.config = () =>
47
- {
48
- config.command = data['command'].value;
49
- config.bind = data['bind'].value;
50
- config.onSuccess = data['_success'].value;
51
- config.onError = data['_error'].value;
52
- config.reset = data['reset'].value;
53
- config.stop = data['stop'].value;
54
- config.data = data['data'].value;
55
- config.api = data['api'].value;
56
- };
57
-
58
- methods.element = () =>
59
- {
60
- config.form = document.createElement('form');
61
- config.form.setAttribute('autocomplete', 'off');
30
+ methods.config();
31
+ methods.state();
32
+ methods.element();
33
+ methods.handler();
34
+ };
62
35
 
63
- while(node.firstChild)
36
+ methods.state = () =>
64
37
  {
65
- config.form.appendChild(node.firstChild);
66
- }
38
+ if(!compile.data[config.bind])
39
+ {
40
+ compile.data[config.bind] = {
41
+ response: null,
42
+ error: null,
43
+ loading: false
44
+ };
45
+ }
46
+ };
67
47
 
68
- node.appendChild(config.form);
69
- divhunt.FormSet(config.form, config.data);
70
- };
48
+ methods.config = () =>
49
+ {
50
+ config.command = data['command'].value;
51
+ config.bind = data['bind'].value;
52
+ config.onSuccess = data['_success'].value;
53
+ config.onError = data['_error'].value;
54
+ config.reset = data['reset'].value;
55
+ config.stop = data['stop'].value;
56
+ config.data = data['data'].value;
57
+ config.api = data['api'].value;
58
+ };
71
59
 
72
- methods.handler = () =>
73
- {
74
- config.form.dhCommandSubmit = async (event) =>
60
+ methods.element = () =>
75
61
  {
76
- event.preventDefault();
62
+ config.form = document.createElement('form');
63
+ config.form.setAttribute('autocomplete', 'off');
77
64
 
78
- if(config.stop)
65
+ while(node.firstChild)
79
66
  {
80
- event.stopPropagation();
67
+ config.form.appendChild(node.firstChild);
81
68
  }
82
69
 
83
- await methods.submit();
70
+ node.appendChild(config.form);
71
+ divhunt.FormSet(config.form, config.data);
84
72
  };
85
- };
86
-
87
- methods.submit = async () =>
88
- {
89
- compile.data[config.bind];
90
73
 
91
- if(compile.data[config.bind].loading)
74
+ methods.handler = () =>
92
75
  {
93
- return;
94
- }
95
-
96
- compile.data[config.bind].loading = true;
97
- compile.data[config.bind].error = null;
76
+ config.form.dhCommandSubmit = async (event) =>
77
+ {
78
+ event.preventDefault();
98
79
 
99
- console.log(compile.data[config.bind]);
80
+ if(config.stop)
81
+ {
82
+ event.stopPropagation();
83
+ }
100
84
 
101
- compile.data.Update();
85
+ await methods.submit();
86
+ };
87
+ };
102
88
 
103
- try
89
+ methods.submit = async () =>
104
90
  {
105
- const formData = divhunt.FormGet(config.form);
106
- const result = config.api
107
- ? await commands.Fn('api', config.command, formData)
108
- : await commands.Fn('run', config.command, formData);
91
+ compile.data[config.bind];
109
92
 
110
- compile.data[config.bind].response = result;
111
- compile.data[config.bind].error = null;
112
- compile.data[config.bind].loading = false;
93
+ if(compile.data[config.bind].loading)
94
+ {
95
+ return;
96
+ }
113
97
 
114
- config.reset && config.form.reset();
115
- config.onSuccess && config.onSuccess(compile.data[config.bind]);
116
- }
117
- catch(error)
118
- {
119
- compile.data[config.bind].response = null;
120
- compile.data[config.bind].error = error.message;
121
- compile.data[config.bind].loading = false;
98
+ compile.data[config.bind].loading = true;
99
+ compile.data[config.bind].error = null;
100
+
101
+ console.log(compile.data[config.bind]);
122
102
 
123
- config.onError && config.onError(compile.data[config.bind]);
124
- }
125
- finally
126
- {
127
103
  compile.data.Update();
128
- }
129
- };
130
104
 
131
- methods.init();
132
- }
133
- });
105
+ try
106
+ {
107
+ const formData = divhunt.FormGet(config.form);
108
+ const result = config.api
109
+ ? await commands.Fn('api', config.command, formData)
110
+ : await commands.Fn('run', config.command, formData);
111
+
112
+ compile.data[config.bind].response = result;
113
+ compile.data[config.bind].error = null;
114
+ compile.data[config.bind].loading = false;
115
+
116
+ config.reset && config.form.reset();
117
+ config.onSuccess && config.onSuccess(compile.data[config.bind]);
118
+ }
119
+ catch(error)
120
+ {
121
+ compile.data[config.bind].response = null;
122
+ compile.data[config.bind].error = error.message;
123
+ compile.data[config.bind].loading = false;
124
+
125
+ config.onError && config.onError(compile.data[config.bind]);
126
+ }
127
+ finally
128
+ {
129
+ compile.data.Update();
130
+ }
131
+ };
132
+
133
+ methods.init();
134
+ }
135
+ });
134
136
 
135
- divhunt.AddonReady('directives', function()
136
- {
137
137
  document.addEventListener('submit', function(event)
138
138
  {
139
139
  let node = event.target;
@@ -27,11 +27,11 @@ serversHTTP.Fn('item.start', function(item)
27
27
  user: this.methods.user(request),
28
28
  time: performance.now(),
29
29
  error: null,
30
- raw: response,
30
+ response,
31
31
  streaming: false,
32
32
  types: this.methods.types,
33
33
  prevent: false,
34
- response: {
34
+ respond: {
35
35
  type: 'JSON',
36
36
  data: null,
37
37
  message: 'Request processed',
@@ -64,7 +64,7 @@ serversHTTP.Fn('item.start', function(item)
64
64
  return;
65
65
  }
66
66
 
67
- const type = http.types[http.response.type] || http.types.JSON;
67
+ const type = http.types[http.respond.type] || http.types.JSON;
68
68
 
69
69
  http.time = (performance.now() - http.time).toFixed(2);
70
70
 
@@ -83,14 +83,14 @@ serversHTTP.Fn('item.start', function(item)
83
83
  return;
84
84
  }
85
85
 
86
- const content = http.response.type === 'JSON' ? {
87
- data: http.response.data || {},
88
- message: http.response.message || 'No response message provided.',
89
- code: http.response.code,
86
+ const content = http.respond.type === 'JSON' ? {
87
+ data: http.respond.data || {},
88
+ message: http.respond.message || 'No response message provided.',
89
+ code: http.respond.code,
90
90
  time: http.time
91
- } : http.response.data || '';
91
+ } : http.respond.data || '';
92
92
 
93
- response.writeHead(http.response.code, { 'Content-Type': type.contentType });
93
+ response.writeHead(http.respond.code, { 'Content-Type': type.contentType });
94
94
  response.end(type.formatter(content));
95
95
 
96
96
  item.Get('onComplete') && item.Get('onComplete')(http);
@@ -1,38 +1,41 @@
1
- directives.ItemAdd({
2
- id: 'dh-page',
3
- icon: 'file',
4
- name: 'Page',
5
- description: 'Navigate to a page on render',
6
- category: 'navigation',
7
- trigger: 'node',
8
- order: 666,
9
- strict: false,
10
- tag: 'dh-page',
11
- attributes: {
12
- 'route': ['string', null, true],
13
- 'parameters': ['object', {}],
14
- 'history': ['boolean', true],
15
- 'timeout': ['number', 0]
16
- },
17
- code: function(data, item, compile, node, identifier)
18
- {
19
- const route = data['route'].value;
20
- const parameters = data['parameters'].value;
21
- const push = data['history'].value;
22
- const timeout = data['timeout'].value;
23
-
24
- const change = () =>
1
+ divhunt.AddonReady('directives', function()
2
+ {
3
+ directives.ItemAdd({
4
+ id: 'dh-page',
5
+ icon: 'file',
6
+ name: 'Page',
7
+ description: 'Navigate to a page on render',
8
+ category: 'navigation',
9
+ trigger: 'node',
10
+ order: 666,
11
+ strict: false,
12
+ tag: 'dh-page',
13
+ attributes: {
14
+ 'route': ['string', null, true],
15
+ 'parameters': ['object', {}],
16
+ 'history': ['boolean', true],
17
+ 'timeout': ['number', 0]
18
+ },
19
+ code: function(data, item, compile, node, identifier)
25
20
  {
26
- pages.Fn('change', route, parameters, { path: true, push });
27
- };
21
+ const route = data['route'].value;
22
+ const parameters = data['parameters'].value;
23
+ const push = data['history'].value;
24
+ const timeout = data['timeout'].value;
28
25
 
29
- if(timeout > 0)
30
- {
31
- setTimeout(change, timeout);
32
- }
33
- else
34
- {
35
- change();
26
+ const change = () =>
27
+ {
28
+ pages.Fn('change', route, parameters, { path: true, push });
29
+ };
30
+
31
+ if(timeout > 0)
32
+ {
33
+ setTimeout(change, timeout);
34
+ }
35
+ else
36
+ {
37
+ change();
38
+ }
36
39
  }
37
- }
40
+ });
38
41
  });
@@ -1,40 +1,43 @@
1
- directives.ItemAdd({
2
- id: 'dh-transform',
3
- icon: 'auto_fix_high',
4
- name: 'Transform',
5
- description: 'Apply transform functions to elements for advanced functionality. Enables custom element behaviors and third-party integrations.',
6
- trigger: 'node',
7
- order: 1100,
8
- type: '1',
9
- code: async function(data, item, compile, node, identifier)
10
- {
11
- const transformer = transforms.ItemGet(node.tagName.toLowerCase());
12
-
13
- if(!transformer)
1
+ divhunt.AddonReady('directives', function()
2
+ {
3
+ directives.ItemAdd({
4
+ id: 'dh-transform',
5
+ icon: 'auto_fix_high',
6
+ name: 'Transform',
7
+ description: 'Apply transform functions to elements for advanced functionality. Enables custom element behaviors and third-party integrations.',
8
+ trigger: 'node',
9
+ order: 1100,
10
+ type: '1',
11
+ code: async function(data, item, compile, node, identifier)
14
12
  {
15
- return;
16
- }
13
+ const transformer = transforms.ItemGet(node.tagName.toLowerCase());
17
14
 
18
- // Don't stop children processing - let each transform handle itself
19
- // compile.children = false;
15
+ if(!transformer)
16
+ {
17
+ return;
18
+ }
20
19
 
21
- const html = node.outerHTML.replace(new RegExp(`^<${node.tagName.toLowerCase()}\\b`), `<div`) .replace(new RegExp(`</${node.tagName.toLowerCase()}>$`), `</div>`);
22
- const compiled = item.Compile(html, compile.data);
20
+ // Don't stop children processing - let each transform handle itself
21
+ // compile.children = false;
23
22
 
24
- data = directives.Fn('process.data', transformer.Get('config'), compiled.element.firstElementChild, compiled);
23
+ const html = node.outerHTML.replace(new RegExp(`^<${node.tagName.toLowerCase()}\\b`), `<div`) .replace(new RegExp(`</${node.tagName.toLowerCase()}>$`), `</div>`);
24
+ const compiled = item.Compile(html, compile.data);
25
25
 
26
- node.style.display = 'none';
26
+ data = directives.Fn('process.data', transformer.Get('config'), compiled.element.firstElementChild, compiled);
27
27
 
28
- await transforms.Fn('load.assets', transformer);
28
+ node.style.display = 'none';
29
29
 
30
- // Use Promise to handle async properly
31
- return new Promise((resolve) => {
32
- setTimeout(() => {
33
- const targetNode = compiled.element.firstElementChild;
34
- transformer.Get('code').call({}, data, transformer, compile, targetNode, identifier);
35
- node.replaceWith(targetNode);
36
- resolve();
37
- }, 0);
38
- });
39
- }
40
- });
30
+ await transforms.Fn('load.assets', transformer);
31
+
32
+ // Use Promise to handle async properly
33
+ return new Promise((resolve) => {
34
+ setTimeout(() => {
35
+ const targetNode = compiled.element.firstElementChild;
36
+ transformer.Get('code').call({}, data, transformer, compile, targetNode, identifier);
37
+ node.replaceWith(targetNode);
38
+ resolve();
39
+ }, 0);
40
+ });
41
+ }
42
+ });
43
+ });
@@ -3,12 +3,12 @@
3
3
  ## File structure
4
4
 
5
5
  ```
6
- lib/ Core Divhunt class + 16 mixins
6
+ lib/ Core Divhunt class + 17 mixins
7
7
  load.js Entry point — creates Divhunt instance, handles signals
8
8
  src/
9
9
  divhunt.js Main class (mixin-composed)
10
10
  mixins/ Addons, Emitter, Middleware, Data, DOM, Route,
11
- Function, Generate, Binaries, Helper, and more
11
+ Function, Generate, Binaries, Helper, Cookie, and more
12
12
  classes/
13
13
  addon/ DivhuntAddon + mixins (fields, items, functions, find, render, store)
14
14
  classes/
package/docs/servers.md CHANGED
@@ -20,6 +20,60 @@ commands.Fn('http.server', 3000, {
20
20
  });
21
21
  ```
22
22
 
23
+ ## HTTP object
24
+
25
+ Every request creates an `http` object passed to `onRequest` and command callbacks (via `this.http`):
26
+
27
+ | Property | Type | Description |
28
+ |---|---|---|
29
+ | `request` | IncomingMessage | Node.js request (headers, method, url) |
30
+ | `response` | ServerResponse | Node.js response (writeHead, setHeader, end) |
31
+ | `data` | object | Parsed request data (query params + body) |
32
+ | `url` | URL | Parsed request URL |
33
+ | `user` | object | `{ ip, agent, forwarded, referrer }` |
34
+ | `respond` | object | `{ type, data, message, code }` — response payload |
35
+ | `prevent` | boolean | Set `true` to skip automatic response |
36
+
37
+ ## Cookies
38
+
39
+ Built-in cookie support via `divhunt.Cookie*` methods. Works on both front (browser) and back (server) — detected via `divhunt.environment`.
40
+
41
+ ### Back (server)
42
+
43
+ ```js
44
+ // Read from request
45
+ const token = divhunt.CookieGet('token', this.http.request);
46
+
47
+ // Set on response (HttpOnly + Secure by default)
48
+ divhunt.CookieSet('token', value, {
49
+ path: '/',
50
+ maxAge: 86400,
51
+ sameSite: 'Strict'
52
+ }, this.http.response);
53
+
54
+ // Clear
55
+ divhunt.CookieClear('token', { path: '/' }, this.http.response);
56
+ ```
57
+
58
+ ### Front (browser)
59
+
60
+ ```js
61
+ divhunt.CookieSet('theme', 'dark', { path: '/', maxAge: 86400 });
62
+ const theme = divhunt.CookieGet('theme');
63
+ divhunt.CookieClear('theme');
64
+ ```
65
+
66
+ ### Options
67
+
68
+ | Option | Back default | Front default | Description |
69
+ |---|---|---|---|
70
+ | `path` | — | — | Cookie path |
71
+ | `maxAge` | — | — | Lifetime in seconds |
72
+ | `domain` | — | — | Cookie domain |
73
+ | `httpOnly` | `true` | N/A | JS can't read the cookie |
74
+ | `secure` | `true` | `false` | HTTPS only |
75
+ | `sameSite` | — | — | `Strict`, `Lax`, or `None` |
76
+
23
77
  ## gRPC server
24
78
 
25
79
  Bidirectional streaming with automatic reconnection and binary data transport.
@@ -17,11 +17,13 @@ import DivhuntRoute from './mixins/route.js';
17
17
  import DivhuntError from './mixins/error.js';
18
18
  import DivhuntCrypto from './mixins/crypto.js';
19
19
  import DivhuntForm from './mixins/form.js';
20
+ import DivhuntCookie from './mixins/cookie.js';
20
21
 
21
22
  class Divhunt
22
23
  {
23
24
  constructor()
24
25
  {
26
+ this.environment = typeof window !== 'undefined' ? 'front' : 'back';
25
27
  this.emitters = {};
26
28
  this.middleware = {};
27
29
 
@@ -84,5 +86,6 @@ Object.assign(Divhunt.prototype, DivhuntRoute);
84
86
  Object.assign(Divhunt.prototype, DivhuntError);
85
87
  Object.assign(Divhunt.prototype, DivhuntCrypto);
86
88
  Object.assign(Divhunt.prototype, DivhuntForm);
89
+ Object.assign(Divhunt.prototype, DivhuntCookie);
87
90
 
88
91
  export default Divhunt;
@@ -0,0 +1,73 @@
1
+ const DivhuntCookie =
2
+ {
3
+ CookieGet(name, request)
4
+ {
5
+ const header = this.environment === 'front' ? document.cookie : (request?.headers?.cookie || '');
6
+ const match = header.match(new RegExp('(?:^|;\\s*)' + name + '=([^;]*)'));
7
+
8
+ if(!match)
9
+ {
10
+ return null;
11
+ }
12
+
13
+ return decodeURIComponent(match[1]);
14
+ },
15
+
16
+ CookieSet(name, value, options, response)
17
+ {
18
+ const parts = [encodeURIComponent(name) + '=' + encodeURIComponent(value)];
19
+
20
+ if(options?.path)
21
+ {
22
+ parts.push('Path=' + options.path);
23
+ }
24
+
25
+ if(options?.maxAge)
26
+ {
27
+ parts.push('Max-Age=' + options.maxAge);
28
+ }
29
+
30
+ if(options?.domain)
31
+ {
32
+ parts.push('Domain=' + options.domain);
33
+ }
34
+
35
+ if(options?.sameSite)
36
+ {
37
+ parts.push('SameSite=' + options.sameSite);
38
+ }
39
+
40
+ if(this.environment === 'front')
41
+ {
42
+ if(options?.secure)
43
+ {
44
+ parts.push('Secure');
45
+ }
46
+
47
+ document.cookie = parts.join('; ');
48
+ return;
49
+ }
50
+
51
+ if(options?.httpOnly !== false)
52
+ {
53
+ parts.push('HttpOnly');
54
+ }
55
+
56
+ if(options?.secure !== false)
57
+ {
58
+ parts.push('Secure');
59
+ }
60
+
61
+ const existing = response.getHeader('Set-Cookie') || [];
62
+ const cookies = Array.isArray(existing) ? existing : [existing];
63
+ cookies.push(parts.join('; '));
64
+ response.setHeader('Set-Cookie', cookies);
65
+ },
66
+
67
+ CookieClear(name, options, response)
68
+ {
69
+ this.CookieSet(name, '', { path: options?.path || '/', maxAge: 0 }, response);
70
+ }
71
+ };
72
+
73
+ export default DivhuntCookie;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "divhunt",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "description": "Full-stack isomorphic JavaScript framework built from scratch. One addon abstraction powers databases, servers, commands, pages, directives, queues, and more.",
5
5
  "type": "module",
6
6
  "main": "lib/load.js",
package/test.js CHANGED
@@ -42,7 +42,6 @@ commands.Item({
42
42
  }
43
43
  });
44
44
 
45
-
46
45
  commands.Fn('expose', 'commands:run', '/api/commands/run');
47
46
 
48
47
  await commands.Fn('http.server', 3000, {