5htp-core 0.5.9 → 0.6.0

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 (63) hide show
  1. package/client/app/component.tsx +1 -0
  2. package/client/assets/css/colors.less +244 -0
  3. package/client/assets/css/components/button.less +27 -9
  4. package/client/assets/css/components/card.less +24 -0
  5. package/client/assets/css/components/input.less +0 -4
  6. package/client/assets/css/components/mantine.less +11 -0
  7. package/client/assets/css/components/other.less +1 -0
  8. package/client/assets/css/components/progressbar.less +45 -0
  9. package/client/assets/css/components/table.less +8 -12
  10. package/client/assets/css/components.less +1 -0
  11. package/client/assets/css/core.less +6 -4
  12. package/client/assets/css/text/text.less +0 -9
  13. package/client/assets/css/theme.less +10 -0
  14. package/client/assets/css/utils/layouts.less +8 -4
  15. package/client/assets/css/utils/sizing.less +2 -0
  16. package/client/components/Card/index.tsx +1 -2
  17. package/client/components/Checkbox.tsx +2 -1
  18. package/client/components/DropDown.tsx +11 -5
  19. package/client/components/Input.tsx +1 -0
  20. package/client/components/Rte/ToolbarPlugin/BlockFormat.tsx +1 -1
  21. package/client/components/Rte/ToolbarPlugin/ElementFormat.tsx +5 -3
  22. package/client/components/Rte/ToolbarPlugin/index.tsx +4 -4
  23. package/client/components/Select.tsx +95 -69
  24. package/client/components/Table/index.tsx +34 -23
  25. package/client/components/containers/Popover/index.tsx +1 -1
  26. package/client/components/containers/Popover/popover.less +1 -1
  27. package/client/components/index.ts +3 -2
  28. package/client/components/utils.tsx +5 -5
  29. package/client/index.ts +1 -0
  30. package/client/services/router/components/router.tsx +0 -1
  31. package/client/services/router/index.tsx +1 -2
  32. package/client/services/router/request/api.ts +4 -4
  33. package/common/errors/index.tsx +6 -0
  34. package/common/router/index.ts +8 -2
  35. package/package.json +1 -2
  36. package/server/app/commands.ts +2 -21
  37. package/server/app/container/console/index.ts +1 -6
  38. package/server/app/container/index.ts +0 -2
  39. package/server/app/index.ts +88 -22
  40. package/server/app/service/index.ts +30 -35
  41. package/server/services/auth/index.ts +15 -17
  42. package/server/services/auth/old.ts +1 -1
  43. package/server/services/auth/router/index.ts +24 -12
  44. package/server/services/cache/index.ts +5 -16
  45. package/server/services/cron/index.ts +2 -9
  46. package/server/services/database/index.ts +5 -10
  47. package/server/services/database/stats.ts +0 -2
  48. package/server/services/disks/driver.ts +1 -1
  49. package/server/services/disks/drivers/s3/index.ts +4 -8
  50. package/server/services/disks/index.ts +10 -9
  51. package/server/services/email/index.ts +5 -2
  52. package/server/services/email/transporter.ts +1 -21
  53. package/server/services/fetch/index.ts +9 -11
  54. package/server/services/fetch/service.json +2 -1
  55. package/server/services/prisma/index.ts +1 -14
  56. package/server/services/router/index.ts +28 -53
  57. package/server/services/router/request/api.ts +2 -7
  58. package/server/services/router/service.ts +5 -17
  59. package/server/services/security/encrypt/aes/index.ts +1 -1
  60. package/server/services/socket/index.ts +11 -19
  61. package/types/global/utils.d.ts +44 -1
  62. package/types/icons.d.ts +1 -1
  63. package/server/app/container/patch.ts +0 -15
@@ -33,7 +33,7 @@ import {
33
33
 
34
34
  // Core
35
35
  import Button from '@client/components/Button';
36
- import DropDown from '@client/components/dropdown';
36
+ import DropDown from '@client/components/DropDown';
37
37
 
38
38
  /*----------------------------------
39
39
  - TYPES
@@ -14,7 +14,7 @@ import {
14
14
 
15
15
  // Core
16
16
  import Button from '@client/components/Button';
17
- import DropDown from '@client/components/dropdown';
17
+ import DropDown from '@client/components/DropDown';
18
18
 
19
19
  /*----------------------------------
20
20
  - TYPES
@@ -85,8 +85,10 @@ export default function ElementFormatDropdown({
85
85
  const formatOption = FormatOptions.find((option) => option.value === currentValue) || FormatOptions[0];
86
86
 
87
87
  return (
88
- <DropDown disabled={disabled} icon={isRTL ? formatOption.iconRTL : formatOption.icon} size="s"
89
- label={formatOption.label}
88
+ <DropDown disabled={disabled}
89
+ icon={isRTL ? formatOption.iconRTL : formatOption.icon}
90
+ size="s"
91
+ hint={formatOption.label}
90
92
  popover={{ tag: 'li' }}
91
93
  >
92
94
  {FormatOptions.map((option) => (
@@ -510,7 +510,7 @@ export default function ToolbarPlugin({
510
510
  )}
511
511
 
512
512
  {blockType === 'code' ? (
513
- <DropDown label={getLanguageFriendlyName(codeLanguage)}
513
+ <DropDown size="s" label={getLanguageFriendlyName(codeLanguage)}
514
514
  disabled={!isEditable}
515
515
  icon="code"
516
516
  >
@@ -591,7 +591,7 @@ export default function ToolbarPlugin({
591
591
 
592
592
  <DropDown popover={{ tag: 'li' }} icon="font" size="s"
593
593
  disabled={!isEditable}
594
- label="Formatting options for additional text styles"
594
+ hint="Formatting options for additional text styles"
595
595
  >
596
596
 
597
597
  <Button icon="strikethrough" size="s"
@@ -640,8 +640,8 @@ export default function ToolbarPlugin({
640
640
  <DropDown popover={{ tag: 'li' }}
641
641
  disabled={!isEditable}
642
642
  size="s"
643
- label="Insert"
644
- title="Insert specialized editor node"
643
+ icon="plus-circle"
644
+ hint="Insert specialized editor node"
645
645
  >
646
646
 
647
647
  <Button icon="horizontal-rule" size="s" onClick={() => {
@@ -5,41 +5,44 @@
5
5
  // Npm
6
6
  import React from 'react';
7
7
  import {
8
- Select as MantineSelect,
9
8
  SelectProps,
10
9
  MultiSelect as MantineMultiSelect,
11
10
  ComboboxItem,
12
-
13
- Menu,
14
- Button
11
+ Menu
15
12
  } from '@mantine/core';
16
13
  import Input from '@client/components/Input';
17
14
 
18
15
  // Core
19
- import { Props as DropdownProps } from '@client/components/dropdown';
20
16
  import { useMantineInput, InputBaseProps } from '@client/components/utils';
17
+ import Button, { Props as ButtonProps } from '@client/components/Button';
18
+ import Popover, { Props as PopoverProps } from '@client/components/containers/Popover';
21
19
 
22
20
  /*----------------------------------
23
21
  - TYPES
24
22
  ----------------------------------*/
25
23
 
26
24
  export type Props = SelectProps & InputBaseProps<ComboboxItem> & {
27
-
25
+ popoverProps?: PopoverProps
28
26
  }
29
27
 
30
28
  export type Choice = ComboboxItem;
31
29
 
32
- const ensureChoice = (choice: ComboboxItem | string, choices: ComboboxItem[]): ComboboxItem => {
30
+ const ensureChoice = (
31
+ choice: ComboboxItem | string,
32
+ choices: ComboboxItem[],
33
+ current: ComboboxItem[]
34
+ ): ComboboxItem => {
33
35
 
34
36
  // Allready a choice
35
- if (typeof choice === 'object' && choice.label) {
37
+ if (typeof choice === 'object')
36
38
  return choice;
37
- }
39
+
40
+ // Ensure current is an array of choices
41
+ const allChoices = [...choices, ...current];
38
42
 
39
43
  // Find the choice
40
- const found = choices.find( c => c.value === choice);
41
- if (found)
42
- return found;
44
+ const found = allChoices.find( c => c.value === choice );
45
+ if (found) return found;
43
46
 
44
47
  // Create a new choice
45
48
  return {
@@ -60,28 +63,23 @@ export default (initProps: Props) => {
60
63
  onChange, value: current,
61
64
  required
62
65
  }, {
63
- multiple, choices: initChoices, enableSearch,
66
+ multiple, choices: initChoices, enableSearch, popoverProps,
64
67
  ...props
65
68
  }] = useMantineInput<Props, string|number>(initProps);
66
69
 
67
- const initRef = React.useRef<boolean>();
70
+ const currentArray = (Array.isArray(current)
71
+ ? current
72
+ : current ? [current] : []
73
+ ).map(c => ensureChoice(c, [], []));
68
74
 
69
75
  const choicesViaFunc = typeof initChoices === 'function';
70
76
  if (choicesViaFunc)
71
77
  enableSearch = true;
72
78
  else
73
- initChoices = initChoices?.map( c => ensureChoice(c, []) ) || [];
74
-
75
- if (enableSearch)
76
- props.searchable = true;
79
+ initChoices = initChoices?.map( c => ensureChoice(c, [], currentArray) ) || [];
77
80
 
78
81
  let [choices, setChoices] = React.useState<ComboboxItem[]>( choicesViaFunc
79
- ? (Array.isArray(current)
80
- ? current.map( c => ensureChoice(c, []) )
81
- : current
82
- ? [ensureChoice(current, [])]
83
- : []
84
- ) || []
82
+ ? currentArray.map( c => ensureChoice(c, [], currentArray) )
85
83
  : initChoices
86
84
  );
87
85
 
@@ -98,71 +96,70 @@ export default (initProps: Props) => {
98
96
  - ACTIONS
99
97
  ----------------------------------*/
100
98
 
101
- const valueToChoice = (value: string) => choices.find(c => c.value === value);
102
-
103
99
  React.useEffect(() => {
104
100
 
105
101
  if (choicesViaFunc && opened) {
102
+
103
+ const keywords = search.keywords === current?.label
104
+ ? undefined
105
+ : search.keywords;
106
+
106
107
  //setSearch(s => ({ ...s, loading: true }));
107
- initChoices(search.keywords).then((searchResults) => {
108
+ initChoices(keywords).then((searchResults) => {
108
109
  //setSearch(s => ({ ...s, loading: false }))
109
110
  setChoices(searchResults);
110
111
  })
111
112
  }
112
113
 
113
- initRef.current = true;
114
-
115
114
  }, [
116
115
  opened,
117
- //search.keywords,
116
+ search.keywords,
118
117
  // When initChoices is a function, React considers it's always different
119
118
  // It avoids the choices are fetched everytimle the parent component is re-rendered
120
119
  typeof initChoices === 'function' ? true : initChoices
121
120
  ]);
122
121
 
123
- let Component: typeof MantineSelect | typeof MantineMultiSelect;
122
+ /*----------------------------------
123
+ - RENDER
124
+ ----------------------------------*/
125
+
124
126
  if (multiple) {
125
- Component = MantineMultiSelect;
126
- props.value = current ? current.map( c => ensureChoice(c, choices).value ) : [];
127
- props.onChange = (value: string[]) => onChange( value.map(valueToChoice) );
127
+
128
+ props.value = current
129
+ ? current.map( c => ensureChoice(c, choices, currentArray).value )
130
+ : [];
131
+
132
+ props.onChange = (value: string[]) => {
133
+ onChange( value.map(value => ensureChoice(value, choices, currentArray)) )
134
+ };
135
+
128
136
  } else {
129
- Component = MantineSelect;
130
- props.value = current ? ensureChoice(current, choices).value : '';
131
- props.onChange = (value: string) => onChange( valueToChoice(value) );
137
+
138
+ props.value = current
139
+ ? [ensureChoice(current, choices, currentArray).value]
140
+ : [];
141
+
142
+ props.onChange = (value: string[]) => {
143
+
144
+ setOpened(false);
145
+
146
+ onChange( value.length > 0
147
+ ? ensureChoice(value[value.length - 1], choices, currentArray)
148
+ : undefined
149
+ )
150
+ };
132
151
  }
133
152
 
134
- /*----------------------------------
135
- - RENDER
136
- ----------------------------------*/
137
153
  if (minimal) {
138
154
  return (
139
- <Menu width={300} opened={opened} onChange={setOpened}
140
- trapFocus withArrow shadow='lg'
141
- closeOnItemClick={!multiple}>
142
- <Menu.Target>
143
- <Button variant="subtle"
144
- leftSection={(
145
- (current && multiple) ? (
146
- <span class="badge bg info s">
147
- {current.length}
148
- </span>
149
- ) : null
150
- )}
151
- rightSection={<i src="angle-down" />}
152
- onClick={() => setOpened((o) => !o)} >
153
-
154
- {props.label || props.placeholder}
155
-
156
- </Button>
157
- </Menu.Target>
158
- <Menu.Dropdown>
159
-
155
+ <Popover {...(popoverProps || {})} state={[opened, setOpened]} content={(
156
+ <div class="card col menu floating">
160
157
  {enableSearch && <>
158
+
161
159
  <Input title="Search" value={search.keywords}
162
160
  wrapper={false} minimal icon="search"
163
161
  onChange={v => setSearch(s => ({ ...s, keywords: v }))} />
164
162
 
165
- <Menu.Divider />
166
163
  </>}
167
164
 
168
165
  {choices.map(choice => {
@@ -172,8 +169,9 @@ export default (initProps: Props) => {
172
169
  : props.value === choice.value;
173
170
 
174
171
  return (
175
- <Menu.Item key={choice.value}
176
- rightSection={isSelected ? <i src="check" /> : null}
172
+ <Button key={choice.value}
173
+ size="s"
174
+ suffix={isSelected ? <i src="check" /> : null}
177
175
  onClick={() => onChange( multiple
178
176
  ? (isSelected
179
177
  ? current.filter(c => c.value !== choice.value)
@@ -185,28 +183,56 @@ export default (initProps: Props) => {
185
183
  )
186
184
  )}>
187
185
  {choice.label}
188
- </Menu.Item>
186
+ </Button>
189
187
  )
190
188
  })}
191
- </Menu.Dropdown>
192
- </Menu>
189
+ </div>
190
+ )}>
191
+ <Button
192
+ prefix={(
193
+ (multiple && current?.length) ? (
194
+ <span class="badge bg info s">
195
+ {current.length}
196
+ </span>
197
+ ) : icon ? <i src={icon} /> : null
198
+ )}
199
+ suffix={iconR ? <i src={iconR} /> : <i src="angle-down" />}
200
+ onClick={() => setOpened((o) => !o)}>
201
+
202
+ {props.label || props.placeholder}
203
+
204
+ </Button>
205
+ </Popover>
193
206
  )
194
207
 
195
208
  } else {
196
209
  return (
197
- <Component
210
+ <MantineMultiSelect
198
211
  {...props}
199
212
 
200
- data={choices}
213
+ data={[
214
+ {
215
+ group: 'Search results',
216
+ // Exclude the choices that are already selected
217
+ items: choices.filter(c => !props.value.includes(c.value))
218
+ },
219
+ {
220
+ group: 'Selected',
221
+ items: currentArray
222
+ }
223
+ ]}
201
224
  nothingFound={search.loading ? 'Loading...' : props || 'No options found'}
202
225
  comboboxProps={{
203
226
  withArrow: false
204
227
  }}
205
228
 
229
+ searchable={enableSearch}
206
230
  clearable={!required}
207
231
  required={required}
208
232
  allowDeselect={!required}
233
+ checkIconPosition="right"
209
234
 
235
+ dropdownOpened={opened}
210
236
  onDropdownOpen={() => setOpened(true)}
211
237
  onDropdownClose={() => setOpened(false)}
212
238
  onSearchChange={(keywords) => setSearch(s => ({ ...s, keywords }))}
@@ -34,6 +34,7 @@ export type Props<TRow> = {
34
34
  // Interactions
35
35
  sort?: TSortOptions,
36
36
  onSort?: (columnId: string | null, order: TSortOptions["order"]) => void,
37
+ onCellClick?: (row: TRow) => void,
37
38
 
38
39
  selection?: [TRow[], React.SetStateAction<TRow[]>],
39
40
  maxSelection?: number,
@@ -58,6 +59,7 @@ type TSortOptions = {
58
59
  export default function Liste<TRow extends TDonneeInconnue>({
59
60
  stickyHeader, onSort, sort: sorted,
60
61
  data: rows, setData, empty,
62
+ onCellClick,
61
63
  selection: selectionState, maxSelection,
62
64
  columns, ...props
63
65
  }: Props<TRow>) {
@@ -136,32 +138,41 @@ export default function Liste<TRow extends TDonneeInconnue>({
136
138
  }
137
139
  }
138
140
 
139
- const isCurrentlySorted = sort && sorted && sorted.id === sort.id;
140
- const isSortable = sort && onSort;
141
- if (isSortable) {
142
- classe += ' clickable';
143
- cellProps.onClick = () => {
144
- if (isCurrentlySorted)
145
- onSort(null, sort.order);
146
- else
147
- onSort(sort.id, sort.order);
141
+ if (iDonnee === 0) {
142
+
143
+ const headerProps = { className: '', ...cellProps };
144
+ const isCurrentlySorted = sort && sorted && sorted.id === sort.id;
145
+ const isSortable = sort && onSort;
146
+ if (isSortable) {
147
+ headerProps.className += ' clickable';
148
+ headerProps.onClick = () => {
149
+ if (isCurrentlySorted)
150
+ onSort(null, sort.order);
151
+ else
152
+ onSort(sort.id, sort.order);
153
+ }
148
154
  }
155
+
156
+ renduColonnes.push(
157
+ <th {...headerProps}>
158
+ <div class="row sp-btw">
159
+
160
+ {isSortable ? (
161
+ <a>{label}</a>
162
+ ) : label}
163
+
164
+ {isCurrentlySorted && (
165
+ <i src={sort.order === "asc" ? "caret-up" : "caret-down"} />
166
+ )}
167
+ </div>
168
+ </th>
169
+ );
149
170
  }
150
171
 
151
- if (iDonnee === 0) renduColonnes.push(
152
- <th class={classe} {...cellProps}>
153
- <div class="row sp-btw">
154
-
155
- {isSortable ? (
156
- <a>{label}</a>
157
- ) : label}
158
-
159
- {isCurrentlySorted && (
160
- <i src={sort.order === "asc" ? "caret-up" : "caret-down"} />
161
- )}
162
- </div>
163
- </th>
164
- );
172
+ if (onCellClick) {
173
+ cellProps.onClick = () => onCellClick(row);
174
+ classe += ' clickable';
175
+ }
165
176
 
166
177
  let render: ComponentChild;
167
178
  if (Array.isArray(cell)) {
@@ -113,7 +113,7 @@ export default (props: Props) => {
113
113
  renderedContent = React.cloneElement(
114
114
  content,
115
115
  {
116
- className: 'card popover pd-1'
116
+ className: 'card popover'
117
117
  + (position ? ' pos_' + position.cote : '')
118
118
  + ' ' + (content.props.className || ''),
119
119
 
@@ -29,7 +29,7 @@
29
29
 
30
30
  list-style: none;
31
31
  text-align: left;
32
- line-height: 2rem;
32
+ //line-height: 2rem; Why ?
33
33
 
34
34
  overflow: auto;
35
35
 
@@ -31,7 +31,7 @@ export {
31
31
  UnstyledButton,
32
32
  VisuallyHidden,
33
33
  Paper,
34
- //Popover,
34
+ Popover as PopoverMantine,
35
35
  ActionIcon,
36
36
  CloseButton,
37
37
  Group,
@@ -103,9 +103,10 @@ export {
103
103
  Progress,
104
104
  Radio,
105
105
  Rating,
106
+ RangeSlider,
106
107
  RingProgress,
107
108
  SegmentedControl,
108
- //Select,
109
+ Select as SelectMantine,
109
110
  SemiCircleProgress,
110
111
  SimpleGrid,
111
112
  Skeleton,
@@ -57,7 +57,7 @@ const sizeAdapter = {
57
57
  }
58
58
 
59
59
  export function useMantineInput<TProps extends __BaseInputProps & InputBaseProps<any>, TValue>({
60
- title, wrapper, hint, errors, icon, iconR, minimal, onChange, value, ...props
60
+ title, wrapper, hint, errors, icon, iconR, prefix, suffix, minimal, onChange, value, ...props
61
61
  }: InputBaseProps<TValue> & TProps): [
62
62
  InputBaseProps<any>,
63
63
  TProps
@@ -74,11 +74,11 @@ export function useMantineInput<TProps extends __BaseInputProps & InputBaseProps
74
74
  props.description = hint;
75
75
  }
76
76
  // Prefix
77
- if (props.leftSection === undefined && icon !== undefined)
78
- props.leftSection = <i src={icon} />;
77
+ if (props.leftSection === undefined)
78
+ props.leftSection = icon !== undefined ? <i src={icon} /> : prefix;
79
79
  // Suffix
80
- if (props.rightSection === undefined && iconR !== undefined)
81
- props.rightSection = <i src={iconR} />;
80
+ if (props.rightSection === undefined)
81
+ props.rightSection = iconR !== undefined ? <i src={iconR} /> : suffix;
82
82
 
83
83
  // Errors
84
84
  if (errors?.length)
package/client/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import Application from '@/client';
2
2
 
3
3
  const app = new Application();
4
+ app.app = app;
4
5
 
5
6
  app.start();
@@ -191,7 +191,6 @@ export default ({ service: clientRouter, loaderComponent }: TProps) => {
191
191
  // Reset scroll
192
192
  window.scrollTo(0, 0);
193
193
  // Should be called AFTER rendering the page (so after the state change)
194
- console.log("CHANGE PAGE", currentPage);
195
194
  currentPage?.updateClient();
196
195
  // Scroll to the selected content via url hash
197
196
  restoreScroll(currentPage);
@@ -55,7 +55,6 @@ const LogPrefix = '[router]'
55
55
 
56
56
  // Client router can handle Client requests AND Server requests (for pages only)
57
57
  export type { default as ClientResponse, TRouterContext } from "./response";
58
- export { Link } from './components/Link';
59
58
 
60
59
  export type Router = ClientRouter | ServerRouter;
61
60
 
@@ -128,7 +127,7 @@ type THookName = 'page.change' | 'page.changed' | 'page.rendered'
128
127
 
129
128
  type Config<TAdditionnalContext extends {} = {}> = {
130
129
  preload: string[], // List of globs
131
- context: (context: ClientContext, router: ClientRouter) => TAdditionnalContext,
130
+ context: (context: {}, router: ClientRouter) => TAdditionnalContext,
132
131
  }
133
132
 
134
133
  /*----------------------------------
@@ -21,7 +21,7 @@ import FileToUpload from '@client/components/File/FileToUpload';
21
21
  - TYPES
22
22
  ----------------------------------*/
23
23
 
24
- const debug = true;
24
+ const debug = false;
25
25
 
26
26
  export type Config = {
27
27
 
@@ -86,7 +86,7 @@ export default class ApiClient implements ApiClientService {
86
86
  else if (typeof ids === 'string')
87
87
  ids = [ids];
88
88
 
89
- console.log("[api] Reload data", ids, params, page.fetchers);
89
+ debug && console.log("[api] Reload data", ids, params, page.fetchers);
90
90
 
91
91
  for (const id of ids) {
92
92
 
@@ -97,7 +97,7 @@ export default class ApiClient implements ApiClientService {
97
97
  if (params !== undefined)
98
98
  fetcher.data = { ...(fetcher.data || {}), ...params };
99
99
 
100
- console.log("[api][reload]", id, fetcher.method, fetcher.path, fetcher.data);
100
+ debug && console.log("[api][reload]", id, fetcher.method, fetcher.path, fetcher.data);
101
101
 
102
102
  this.fetchAsync(fetcher.method, fetcher.path, fetcher.data).then((data) => {
103
103
 
@@ -227,7 +227,7 @@ export default class ApiClient implements ApiClientService {
227
227
 
228
228
  } else if (options.encoding === 'multipart') {
229
229
 
230
- console.log("[api] Multipart request", data);
230
+ debug && console.log("[api] Multipart request", data);
231
231
  // Browser will automatically choose the right headers
232
232
  config.body = toMultipart(data);
233
233
 
@@ -187,6 +187,12 @@ export class NotFound extends CoreError {
187
187
  public static msgDefaut = "The resource you asked for was not found.";
188
188
  }
189
189
 
190
+ export class Gone extends CoreError {
191
+ public http = 410;
192
+ public title = "Gone";
193
+ public static msgDefaut = "The resource you asked for has been removed.";
194
+ }
195
+
190
196
  export class RateLimit extends CoreError {
191
197
  public http = 429;
192
198
  public title = "You're going too fast";
@@ -2,6 +2,9 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
+ // Npm
6
+ import zod from 'zod';
7
+
5
8
  // types
6
9
  import type {
7
10
  default as ClientRouter,
@@ -42,6 +45,7 @@ export type TRoute<RouterContext extends TClientOrServerContextForPage = TClient
42
45
  path: string,
43
46
 
44
47
  // Execute
48
+ schema?: zod.ZodSchema,
45
49
  controller: TRouteController<RouterContext>,
46
50
  options: TRouteOptions
47
51
  } & (
@@ -67,7 +71,8 @@ export type TErrorRoute<RouterContext extends TClientOrServerContextForPage = TC
67
71
  export type TAnyRoute<RouterContext extends TClientOrServerContextForPage = TClientOrServerContextForPage> =
68
72
  TRoute<RouterContext> | TErrorRoute<RouterContext>
69
73
 
70
- export type TClientOrServerContext = ClientRouterContext | ServerRouterContext;
74
+ // ClientRouterContext already includes server context
75
+ export type TClientOrServerContext = ClientRouterContext;// | ServerRouterContext;
71
76
 
72
77
  export type TClientOrServerContextForPage = With<TClientOrServerContext, 'page'>
73
78
 
@@ -90,10 +95,11 @@ export type TRouteOptions = {
90
95
  accept?: string,
91
96
  raw?: boolean, // true to return raw data
92
97
  auth?: TUserRole | boolean,
93
- canonicalParams?: string[],
98
+ redirectLogged?: string, // Redirect to this route if auth: false and user is logged
94
99
 
95
100
  // Rendering
96
101
  static?: boolean,
102
+ canonicalParams?: string[], // For SEO + unique ID for static cache
97
103
  layout?: false | string, // The nale of the layout
98
104
 
99
105
  // To cleanup
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.5.9",
4
+ "version": "0.6.0",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -73,7 +73,6 @@
73
73
  "prettier": "^3.3.3",
74
74
  "react-scrollbars-custom": "^4.0.27",
75
75
  "react-slider": "^2.0.1",
76
- "react-textarea-autosize": "^8.3.3",
77
76
  "regenerator-runtime": "^0.13.9",
78
77
  "request": "^2.88.2",
79
78
  "slugify": "^1.6.6",
@@ -48,31 +48,12 @@ export type Services = {
48
48
  /*----------------------------------
49
49
  - SERVICE
50
50
  ----------------------------------*/
51
- export default class CommandsManager extends Service<Config, Hooks, Application, Services> {
51
+ export default class CommandsManager extends Service<Config, Hooks, Application> {
52
52
 
53
53
  public priority = 2 as 2;
54
54
 
55
55
  public commandsIndex: CommandsList = {}
56
-
57
- /*----------------------------------
58
- - LIFECYCLE
59
- ----------------------------------*/
60
-
61
- protected async start() {
62
-
63
- }
64
-
65
- protected async ready() {
66
-
67
- }
68
-
69
- protected async shutdown() {
70
-
71
- }
72
-
73
- /*----------------------------------
74
- - DEFINITIONS
75
- ----------------------------------*/
56
+
76
57
  public command<TArgs extends any[]>(
77
58
  ...args: (
78
59
  [name: string, description: string, childrens: Command[]]