proteum 1.0.0 → 1.0.3

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 (70) hide show
  1. package/AGENTS.md +9 -0
  2. package/cli/app/config.ts +61 -0
  3. package/cli/app/index.ts +227 -0
  4. package/cli/bin.js +35 -0
  5. package/cli/commands/build.ts +60 -0
  6. package/cli/commands/deploy/app.ts +29 -0
  7. package/cli/commands/deploy/web.ts +60 -0
  8. package/cli/commands/dev.ts +124 -0
  9. package/cli/commands/init.ts +85 -0
  10. package/cli/commands/refresh.ts +18 -0
  11. package/cli/compiler/client/identite.ts +69 -0
  12. package/cli/compiler/client/index.ts +343 -0
  13. package/cli/compiler/common/babel/index.ts +173 -0
  14. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  15. package/cli/compiler/common/babel/plugins/services.ts +586 -0
  16. package/cli/compiler/common/babel/routes/imports.ts +127 -0
  17. package/cli/compiler/common/babel/routes/routes.ts +1170 -0
  18. package/cli/compiler/common/files/autres.ts +39 -0
  19. package/cli/compiler/common/files/images.ts +42 -0
  20. package/cli/compiler/common/files/style.ts +82 -0
  21. package/cli/compiler/common/index.ts +165 -0
  22. package/cli/compiler/index.ts +585 -0
  23. package/cli/compiler/server/index.ts +220 -0
  24. package/cli/index.ts +213 -0
  25. package/cli/paths.ts +165 -0
  26. package/cli/print.ts +12 -0
  27. package/cli/tsconfig.json +42 -0
  28. package/cli/utils/index.ts +22 -0
  29. package/cli/utils/keyboard.ts +78 -0
  30. package/client/app/index.ts +2 -0
  31. package/client/components/Dialog/Manager.tsx +3 -49
  32. package/client/components/Dialog/index.less +3 -1
  33. package/client/components/index.ts +1 -2
  34. package/client/services/router/index.tsx +6 -16
  35. package/common/errors/index.tsx +12 -31
  36. package/package.json +58 -22
  37. package/server/app/container/config.ts +20 -1
  38. package/server/app/container/console/index.ts +1 -1
  39. package/server/services/auth/index.ts +62 -27
  40. package/server/services/auth/router/request.ts +17 -6
  41. package/server/services/router/http/index.ts +3 -3
  42. package/server/services/router/response/index.ts +1 -1
  43. package/server/services/schema/request.ts +28 -10
  44. package/server/utils/slug.ts +0 -3
  45. package/tsconfig.common.json +2 -1
  46. package/types/global/constants.d.ts +12 -0
  47. package/changelog.md +0 -5
  48. package/client/components/Button.tsx +0 -298
  49. package/client/components/Dialog/card.tsx +0 -208
  50. package/client/data/input.ts +0 -32
  51. package/client/pages/bug.tsx.old +0 -60
  52. package/templates/composant.tsx +0 -40
  53. package/templates/form.ts +0 -30
  54. package/templates/modal.tsx +0 -47
  55. package/templates/modele.ts +0 -56
  56. package/templates/page.tsx +0 -74
  57. package/templates/route.ts +0 -43
  58. package/templates/service.ts +0 -75
  59. package/vscode/copyimportationpath/.eslintrc.json +0 -24
  60. package/vscode/copyimportationpath/.vscodeignore +0 -12
  61. package/vscode/copyimportationpath/CHANGELOG.md +0 -9
  62. package/vscode/copyimportationpath/README.md +0 -3
  63. package/vscode/copyimportationpath/copyimportationpath-0.0.1.vsix +0 -0
  64. package/vscode/copyimportationpath/out/extension.js +0 -206
  65. package/vscode/copyimportationpath/out/extension.js.map +0 -1
  66. package/vscode/copyimportationpath/package-lock.json +0 -4536
  67. package/vscode/copyimportationpath/package.json +0 -86
  68. package/vscode/copyimportationpath/src/extension.ts +0 -300
  69. package/vscode/copyimportationpath/tsconfig.json +0 -22
  70. package/vscode/copyimportationpath/vsc-extension-quickstart.md +0 -42
@@ -20,10 +20,47 @@ import { InputError, AuthRequired, Forbidden } from '@common/errors';
20
20
  - TYPES
21
21
  ----------------------------------*/
22
22
 
23
- export type TUserRole = typeof UserRoles[number]
23
+ declare global {
24
+ /**
25
+ * Optional app-level role registry.
26
+ *
27
+ * Apps can add their own roles (keys are role ids):
28
+ * `interface ProteumAuthRoleCatalog { GOD: true }`
29
+ */
30
+ interface ProteumAuthRoleCatalog {}
31
+
32
+ /**
33
+ * App-level feature catalog consumed by auth permission checks.
34
+ *
35
+ * Apps can augment this interface with their own feature map:
36
+ * `interface ProteumAuthFeatureCatalog extends MyFeatures {}`
37
+ */
38
+ interface ProteumAuthFeatureCatalog {}
39
+
40
+ /**
41
+ * Canonical feature keys union used across app + framework.
42
+ *
43
+ * Notes:
44
+ * - If the app does not define a feature catalog, this defaults to `string`.
45
+ * - Otherwise it becomes the string keys of `ProteumAuthFeatureCatalog`.
46
+ */
47
+ type FeatureKeys = (
48
+ keyof ProteumAuthFeatureCatalog extends never
49
+ ? string
50
+ : Extract<keyof ProteumAuthFeatureCatalog, string>
51
+ );
52
+ }
53
+
54
+ export type TUserRole = (
55
+ typeof UserRoles[number]
56
+ |
57
+ Extract<keyof ProteumAuthRoleCatalog, string>
58
+ );
24
59
 
25
60
  export type THttpRequest = express.Request | http.IncomingMessage;
26
61
 
62
+ export type TFeatureKey = FeatureKeys;
63
+
27
64
  /*----------------------------------
28
65
  - CONFIG
29
66
  ----------------------------------*/
@@ -167,7 +204,7 @@ export default abstract class AuthService<
167
204
  return session;
168
205
  }
169
206
 
170
- public createSession( session: TJwtSession, request: TRequest ): string {
207
+ public createSession( session: TJwtSession, request2: TRequest ): string {
171
208
 
172
209
  this.config.debug && console.info(LogPrefix, `Creating new session:`, session);
173
210
 
@@ -175,7 +212,7 @@ export default abstract class AuthService<
175
212
 
176
213
  this.config.debug && console.info(LogPrefix, `Generated JWT token for session:` + token);
177
214
 
178
- request.res.cookie('authorization', token, {
215
+ request2.res.cookie('authorization', token, {
179
216
  maxAge: this.config.jwt.expiration,
180
217
  });
181
218
 
@@ -191,30 +228,28 @@ export default abstract class AuthService<
191
228
  request.res.clearCookie('authorization');
192
229
  }
193
230
 
194
- public check(
195
- request: TRequest,
196
- role: TUserRole,
197
- motivation?: string,
198
- dataForDebug?: { [key: string]: any }
199
- ): TUser;
200
-
201
- public check(
202
- request: TRequest,
203
- role: false,
204
- motivation?: string,
205
- dataForDebug?: { [key: string]: any }
206
- ): null;
207
-
208
- public check(
209
- request: TRequest,
210
- role: TUserRole | false = 'USER',
211
- motivation?: string,
212
- dataForDebug?: { [key: string]: any }
231
+ public check(
232
+ request: TRequest,
233
+ role?: TUserRole | false,
234
+ ): TUser | null;
235
+
236
+ public check(
237
+ request: TRequest,
238
+ role: TUserRole | false,
239
+ feature: FeatureKeys,
240
+ action?: string,
241
+ ): TUser | null;
242
+
243
+ public check(
244
+ request: TRequest,
245
+ role: TUserRole | false = 'USER',
246
+ feature?: FeatureKeys,
247
+ action?: string,
213
248
  ): TUser | null {
214
249
 
215
250
  const user = request.user;
216
251
 
217
- this.config.debug && console.warn(LogPrefix, `Check auth, role = ${role}. Current user =`, user?.name, motivation);
252
+ this.config.debug && console.warn(LogPrefix, `Check auth, role = ${role}. Current user =`, user?.name, feature);
218
253
 
219
254
  if (user === undefined) {
220
255
 
@@ -223,13 +258,13 @@ export default abstract class AuthService<
223
258
  // Shoudln't be logged
224
259
  } else if (role === false) {
225
260
 
226
- return user;
261
+ return user as TUser;
227
262
 
228
263
  // Not connected
229
264
  } else if (user === null) {
230
265
 
231
266
  console.warn(LogPrefix, "Refusé pour anonyme (" + request.ip + ")");
232
- throw new AuthRequired('Please login to continue', motivation, dataForDebug);
267
+ throw new AuthRequired('Please login to continue', feature as any, action as any);
233
268
 
234
269
  // Insufficient permissions
235
270
  } else if (!user.roles.includes(role)) {
@@ -244,7 +279,7 @@ export default abstract class AuthService<
244
279
 
245
280
  }
246
281
 
247
- return user;
282
+ return user as TUser;
248
283
  }
249
284
 
250
- }
285
+ }
@@ -8,7 +8,6 @@ import jwt from 'jsonwebtoken';
8
8
  // Core
9
9
  import type { default as Router, Request as ServerRequest, TAnyRouter } from '@server/services/router';
10
10
  import RequestService from '@server/services/router/request/service';
11
- import { InputError, AuthRequired, Forbidden } from '@common/errors';
12
11
 
13
12
  // Specific
14
13
  import type AuthenticationRouterService from '.';
@@ -45,10 +44,22 @@ export default class UsersRequestService<
45
44
  return this.users.logout( this.request );
46
45
  }
47
46
 
47
+ public check(): TUser;
48
+
48
49
  // TODO: return user type according to entity
49
- public check(role: TUserRole, motivation?: string, dataForDebug?: {}): TUser;
50
- public check(role: false, motivation?: string, dataForDebug?: {}): null;
51
- public check(role: TUserRole | boolean = 'USER', motivation?: string, dataForDebug?: {}): TUser | null {
52
- return this.users.check( this.request, role, motivation, dataForDebug );
50
+ public check(role: TUserRole, feature: null): TUser;
51
+
52
+ public check(role: false): null;
53
+
54
+ public check(role: TUserRole, feature: FeatureKeys, action?: string): TUser;
55
+
56
+ public check(role: false, feature: FeatureKeys, action?: string): null;
57
+
58
+ public check(
59
+ role: TUserRole | false = 'USER',
60
+ feature?: FeatureKeys | null,
61
+ action?: string
62
+ ) {
63
+ return this.users.check( this.request, role, feature, action ) as any;
53
64
  }
54
- }
65
+ }
@@ -115,7 +115,7 @@ export default class HttpServer {
115
115
  routes.use('/public', cors());
116
116
  routes.use(
117
117
  '/public',
118
- express.static( Container.path.root + '/bin/public', {
118
+ express.static( path.join(Container.path.root, APP_OUTPUT_DIR, 'public'), {
119
119
  dotfiles: 'deny',
120
120
  setHeaders: function setCustomCacheControl(res, path) {
121
121
 
@@ -193,7 +193,7 @@ export default class HttpServer {
193
193
 
194
194
  routes.use( csp.expressCspHeader({
195
195
  directives: {
196
- 'script-src': [csp.INLINE, csp.SELF,
196
+ 'script-src': [csp.INLINE, csp.SELF, csp.UNSAFE_EVAL,
197
197
  ...this.config.csp.scripts
198
198
  ]
199
199
  }
@@ -214,4 +214,4 @@ export default class HttpServer {
214
214
  public async cleanup() {
215
215
  this.http.close();
216
216
  }
217
- }
217
+ }
@@ -52,7 +52,7 @@ export type TRouterContext<TRouter extends TServerRouter> = (
52
52
  Router: TRouter,
53
53
  }
54
54
  & TRouterContextServices<TRouter>
55
- //& TRouterRequestContext<TRouter>
55
+ & TRouterRequestContext<TRouter>
56
56
  )
57
57
 
58
58
  export type TRouterContextServices<
@@ -4,7 +4,6 @@
4
4
 
5
5
  // Npm
6
6
  import zod from 'zod';
7
- import { SomeType } from 'zod/v4/core';
8
7
 
9
8
  // Core
10
9
  import {
@@ -24,6 +23,18 @@ export type TConfig = {
24
23
  debug?: boolean
25
24
  }
26
25
 
26
+ type TValidationSchema = zod.ZodTypeAny;
27
+ type TValidationShape = zod.ZodRawShape;
28
+
29
+ const isZodSchema = (fields: unknown): fields is TValidationSchema => {
30
+ return (
31
+ typeof fields === 'object'
32
+ && fields !== null
33
+ && 'safeParse' in fields
34
+ && typeof (fields as TValidationSchema).safeParse === 'function'
35
+ );
36
+ }
37
+
27
38
  /*----------------------------------
28
39
  - SERVICE
29
40
  ----------------------------------*/
@@ -32,18 +43,25 @@ export default(
32
43
  config: TConfig,
33
44
  router = request.router,
34
45
  app = router.app
35
- ) => ({
36
-
37
- ...schema,
46
+ ) => {
38
47
 
39
- validate( fields: zod.ZodSchema | { [key: string]: zod.ZodSchema } ) {
48
+ function validate<TSchema extends TValidationSchema>( fields: TSchema ): zod.output<TSchema>;
49
+ function validate<TShape extends TValidationShape>( fields: TShape ): zod.output<zod.ZodObject<TShape>>;
50
+ function validate( fields: TValidationSchema | TValidationShape ) {
40
51
 
41
52
  config.debug && console.log(LogPrefix, "Validate request data:", request.data);
42
53
 
43
- const schema = typeof fields === 'object' ? zod.object(fields) : fields;
54
+ const validationSchema = isZodSchema(fields) ? fields : zod.object(fields);
44
55
 
45
- const preprocessedSchema = preprocessSchema(schema);
56
+ //const preprocessedSchema = preprocessSchema(validationSchema);
46
57
 
47
- return preprocessedSchema.parse(request.data);
48
- },
49
- })
58
+ return validationSchema.parse(request.data);
59
+ }
60
+
61
+ return {
62
+
63
+ ...schema,
64
+
65
+ validate,
66
+ }
67
+ }
@@ -7,9 +7,6 @@ import escapeStringRegexp from 'escape-regexp';
7
7
  import slugify from 'slugify';
8
8
  import { removeStopwords, eng } from 'stopword';
9
9
 
10
- // Core
11
- import type SQL from "@server/services/database";
12
-
13
10
  /*----------------------------------
14
11
  - TYPES
15
12
  ----------------------------------*/
@@ -40,5 +40,6 @@
40
40
  "react/jsx-runtime": ["preact/jsx-runtime"]
41
41
  },
42
42
  },
43
- "include": ["."]
43
+ "include": ["."],
44
+ "exclude": ["cli"]
44
45
  }
@@ -0,0 +1,12 @@
1
+ declare const __DEV__: boolean;
2
+ declare const SERVER: boolean;
3
+
4
+ declare const CORE_VERSION: string;
5
+ declare const CORE_PATH: string;
6
+
7
+ declare const BUILD_DATE: string;
8
+ declare const BUILD_ID: number;
9
+
10
+ declare const APP_PATH: string;
11
+ declare const APP_NAME: string;
12
+ declare const APP_OUTPUT_DIR: string;
package/changelog.md DELETED
@@ -1,5 +0,0 @@
1
- # 01/01/2023:
2
-
3
- * Redesigned systems service. Pass app instance servces list through constructor attribute instead of importing instance
4
- * Update babel-plugn-glob-import
5
- *
@@ -1,298 +0,0 @@
1
- /*----------------------------------
2
- - DEPENDANCES
3
- ----------------------------------*/
4
-
5
- // Npm
6
- import React from 'react';
7
- import { VNode, RefObject,ComponentChild } from 'preact';
8
-
9
- // Core
10
- import { shouldOpenNewTab } from '@client/services/router/components/Link';
11
- import { history } from '@client/services/router/request/history';
12
- import useContext from '@/client/context';
13
-
14
- /*----------------------------------
15
- - TYPES
16
- ----------------------------------*/
17
-
18
- export type Props = {
19
-
20
- id?: string,
21
- refElem?: RefObject<HTMLElement>,
22
-
23
- icon?: ComponentChild,
24
- iconR?: ComponentChild,
25
-
26
- prefix?: ComponentChild,
27
- suffix?: ComponentChild,
28
-
29
- tag?: "a" | "button",
30
- type?: 'guide' | 'primary' | 'secondary' | 'link',
31
- shape?: 'default' | 'icon' | 'tile' | 'pill' | 'custom',
32
- size?: TComponentSize,
33
- class?: string,
34
-
35
- state?: [string, React.StateUpdater<string>],
36
- active?: boolean,
37
- selected?: boolean,
38
- disabled?: boolean,
39
- loading?: boolean,
40
- autoFocus?: boolean,
41
- onClick?: (e: MouseEvent) => any,
42
- async?: boolean,
43
-
44
- submenu?: ComponentChild,
45
- nav?: boolean | 'exact'
46
-
47
- // SEO: if icon only, should provinde a hint (aria-label)
48
- } & ({
49
- hint: string,
50
- children?: ComponentChild | ComponentChild[],
51
- } | {
52
- children: ComponentChild | ComponentChild[],
53
- hint?: string,
54
- }) & (TButtonProps | TLinkProps)
55
-
56
- export type TButtonProps = React.JSX.HTMLAttributes<HTMLButtonElement>
57
-
58
- export type TLinkProps = React.JSX.HTMLAttributes<HTMLAnchorElement>
59
-
60
- /*----------------------------------
61
- - HELPERS
62
- ----------------------------------*/
63
- const trimSlash = (str: string): string => {
64
- return str.endsWith('/') ? str.slice(0, -1) : str;
65
- }
66
-
67
- const isCurrentUrl = (currentUrl: string, url: string, exact?: boolean) => {
68
- return (
69
- (exact && (url === currentUrl || trimSlash(url) === currentUrl))
70
- ||
71
- (!exact && currentUrl.startsWith(url))
72
- )
73
- }
74
-
75
- /*----------------------------------
76
- - CONTROLEUR
77
- ----------------------------------*/
78
- export default ({
79
-
80
- id,
81
-
82
- // Content
83
- icon, prefix,
84
- children,
85
- iconR, suffix,
86
- submenu,
87
- nav,
88
- hint,
89
-
90
- // Style
91
- class: className,
92
- shape,
93
- size,
94
- type,
95
-
96
- // Interactions
97
- active,
98
- selected,
99
- state: stateUpdater,
100
- disabled,
101
- loading,
102
- //autoFocus,
103
- async,
104
-
105
- // HTML attributes
106
- tag: Tag,
107
- refElem,
108
- ...props
109
-
110
- }: Props) => {
111
-
112
- const ctx = useContext();
113
- let [isSelected, setIsSelected] = React.useState(false);
114
- let [isActive, setIsActive] = React.useState(false);
115
- const [isLoading, setLoading] = React.useState(false);
116
-
117
- if (isLoading || loading) {
118
- icon = <i src="spin" />
119
- iconR = undefined;
120
- disabled = true;
121
- }
122
-
123
- if (stateUpdater && id !== undefined) {
124
- const [active, setActive] = stateUpdater;
125
- if (id === active)
126
- isSelected = true;
127
- props.onClick = () => setActive(id);
128
- }
129
-
130
- // Hint
131
- if (hint !== undefined) {
132
- props['aria-label'] = hint;
133
- props.title = hint;
134
- }
135
-
136
- // Shape classes
137
- const classNames: string[] = ['btn'];
138
- if (className)
139
- classNames.push(className);
140
-
141
- if (shape !== undefined) {
142
- if (shape === 'tile')
143
- classNames.push('col');
144
- else
145
- classNames.push(shape);
146
- }
147
-
148
- if (size !== undefined)
149
- classNames.push(size);
150
-
151
- if (icon) {
152
- if (children === undefined)
153
- classNames.push('icon');
154
- }
155
-
156
- // state classes
157
- const [isMouseDown, setMouseDown] = React.useState(false);
158
- props.onMouseDown = () => setMouseDown(true);
159
- props.onMouseUp = () => setMouseDown(false);
160
- props.onMouseLeave = () => setMouseDown(false);
161
-
162
- // Theming & state
163
- if (isMouseDown)
164
- classNames.push('pressed');
165
- else if (selected || isSelected === true)
166
- classNames.push('bg accent');
167
- else if (type !== undefined)
168
- classNames.push(type === 'link' ? type : (' bg ' + type));
169
-
170
- if (active || isActive === true)
171
- classNames.push('active');
172
-
173
- // Icon
174
- if (prefix === undefined && icon !== undefined)
175
- prefix = typeof icon === "string" ? <i class={"svg-" + icon} /> : icon;
176
- if (suffix === undefined && iconR !== undefined)
177
- suffix = typeof iconR === "string" ? <i class={"svg-" + iconR} /> : iconR;
178
-
179
- // Render
180
- if ('link' in props || Tag === "a") {
181
-
182
- // Link (only if enabled)
183
- if (!disabled) {
184
-
185
- props.href = props.link;
186
-
187
- // External = open in new tab by default
188
- if (shouldOpenNewTab( props.href, props.target ))
189
- props.target = '_blank';
190
- }
191
-
192
- // Nav
193
- if (nav && props.target === undefined) {
194
-
195
- const checkIfCurrentUrl = (url: string) =>
196
- isCurrentUrl(url, props.link, nav === 'exact');
197
-
198
- React.useEffect(() => {
199
-
200
- // Init
201
- if (checkIfCurrentUrl(ctx.request.path))
202
- setIsActive(true);
203
-
204
- // On location change
205
- return history?.listen(({ location }) => {
206
-
207
- setIsActive( checkIfCurrentUrl(location.pathname) );
208
-
209
- })
210
-
211
- }, []);
212
- }
213
-
214
- Tag = 'a';
215
-
216
- } else {
217
- Tag = 'button';
218
-
219
- // Avoid to trigget onclick when presing enter
220
- if (type !== 'primary')
221
- props.type = 'button';
222
- else
223
- props.type = 'submit';
224
- }
225
-
226
- let render: VNode = (
227
- <Tag {...props} id={id} class={classNames.join(' ')} disabled={disabled} ref={refElem} onClick={(e: MouseEvent) => {
228
-
229
- // annulation si:
230
- // - Pas clic gauche
231
- // - Event annulé
232
- if (e.button !== 0)
233
- return;
234
-
235
- // Disabled
236
- if (disabled)
237
- return false;
238
-
239
- // Custom event
240
- if (props.onClick !== undefined) {
241
-
242
- const returned = props.onClick(e);
243
- if (async && returned?.then) {
244
- setLoading(true);
245
- returned.finally(() => setLoading(false));
246
- }
247
- }
248
-
249
- // Link
250
- let nativeEvent: boolean = false;
251
- if (('link' in props) && !e.defaultPrevented) {
252
-
253
- // Nouvelle fenetre = event par defaut
254
- if (props.target === '_blank') {
255
-
256
- nativeEvent = true;
257
-
258
- // Page change = loading indicator
259
- } else if (props.target === "_self") {
260
-
261
- setLoading(true);
262
- window.location.href = props.link;
263
-
264
- } else {
265
-
266
- history?.push(props.link);
267
- }
268
- }
269
-
270
- if (!nativeEvent) {
271
- e.preventDefault();
272
- return false;
273
- }
274
- }}>
275
- {prefix}
276
- {children === undefined
277
- ? null
278
- : shape === 'custom'
279
- ? children : (
280
- <span class={"label"}>
281
- {children}
282
- </span>
283
- )}
284
- {suffix}
285
- </Tag>
286
- )
287
-
288
- if (Tag === "li" || submenu) {
289
- render = (
290
- <li>
291
- {render}
292
- {submenu}
293
- </li>
294
- )
295
- }
296
-
297
- return render;
298
- }