5htp-core 0.6.0 → 0.6.1-1

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 (48) hide show
  1. package/client/app/component.tsx +1 -0
  2. package/client/assets/css/colors.less +46 -25
  3. package/client/assets/css/components/button.less +14 -5
  4. package/client/assets/css/components/card.less +5 -10
  5. package/client/assets/css/components/mantine.less +6 -5
  6. package/client/assets/css/components/table.less +1 -1
  7. package/client/assets/css/text/icons.less +1 -1
  8. package/client/assets/css/text/text.less +4 -0
  9. package/client/assets/css/utils/borders.less +1 -1
  10. package/client/assets/css/utils/layouts.less +8 -5
  11. package/client/components/Button.tsx +20 -17
  12. package/client/components/Checkbox.tsx +6 -1
  13. package/client/components/ConnectedInput.tsx +34 -0
  14. package/client/components/DropDown.tsx +21 -4
  15. package/client/components/Input.tsx +2 -2
  16. package/client/components/Rte/Editor.tsx +23 -9
  17. package/client/components/Rte/ToolbarPlugin/ElementFormat.tsx +1 -1
  18. package/client/components/Rte/ToolbarPlugin/index.tsx +272 -183
  19. package/client/components/Rte/currentEditor.ts +31 -2
  20. package/client/components/Rte/index.tsx +3 -0
  21. package/client/components/Rte/plugins/FloatingTextFormatToolbarPlugin/index.tsx +4 -1
  22. package/client/components/Select.tsx +29 -16
  23. package/client/components/Table/index.tsx +27 -11
  24. package/client/components/containers/Popover/index.tsx +21 -4
  25. package/client/components/index.ts +4 -2
  26. package/client/services/router/index.tsx +7 -5
  27. package/common/errors/index.tsx +27 -3
  28. package/common/router/index.ts +4 -1
  29. package/common/utils/rte.ts +183 -0
  30. package/package.json +3 -2
  31. package/server/app/container/console/index.ts +62 -42
  32. package/server/app/container/index.ts +4 -0
  33. package/server/app/service/index.ts +4 -2
  34. package/server/services/auth/index.ts +28 -14
  35. package/server/services/auth/router/index.ts +1 -1
  36. package/server/services/auth/router/request.ts +4 -4
  37. package/server/services/email/index.ts +8 -51
  38. package/server/services/prisma/Facet.ts +118 -0
  39. package/server/services/prisma/index.ts +24 -0
  40. package/server/services/router/http/index.ts +0 -2
  41. package/server/services/router/index.ts +220 -86
  42. package/server/services/router/response/index.ts +0 -15
  43. package/server/utils/rte.ts +21 -132
  44. package/types/global/utils.d.ts +4 -22
  45. package/types/icons.d.ts +1 -1
  46. package/server/services/email/service.json +0 -6
  47. package/server/services/email/templates.ts +0 -49
  48. package/server/services/email/transporter.ts +0 -31
@@ -11,20 +11,21 @@
11
11
 
12
12
  // Node
13
13
  // Npm
14
+ import got from 'got';
15
+ import hInterval from 'human-interval';
14
16
  import type express from 'express';
15
17
  import type { Request, Response, NextFunction } from 'express';
16
18
  import { v4 as uuid } from 'uuid';
17
- import zod from 'zod';
19
+ import zod, { ZodError } from 'zod';
18
20
  export { default as schema } from 'zod';
19
21
  import type { GlobImportedWithMetas } from 'babel-plugin-glob-import';
20
22
 
21
23
  // Core
22
24
  import type { Application } from '@server/app';
23
25
  import Service, { AnyService, TServiceArgs } from '@server/app/service';
24
- import type { TRegisteredServicesIndex } from '@server/app/service/container';
25
26
  import context from '@server/context';
26
27
  import type DisksManager from '@server/services/disks';
27
- import { CoreError, NotFound, toJson as errorToJson } from '@common/errors';
28
+ import { CoreError, InputError, NotFound, toJson as errorToJson } from '@common/errors';
28
29
  import BaseRouter, {
29
30
  TRoute, TErrorRoute, TRouteModule,
30
31
  TRouteOptions, defaultOptions,
@@ -138,7 +139,13 @@ export default class ServerRouter
138
139
  public ssrRoutes: TSsrUnresolvedRoute[] = [];
139
140
 
140
141
  // Cache (ex: for static pages)
141
- public cache: {[pageId: string]: string} = {}
142
+ public cache: {
143
+ [pageId: string]: {
144
+ rendered: any,
145
+ expire: number | undefined,
146
+ options: TRouteOptions["static"]
147
+ }
148
+ } = {}
142
149
 
143
150
  /*----------------------------------
144
151
  - SERVICE
@@ -158,6 +165,11 @@ export default class ServerRouter
158
165
 
159
166
  public async ready() {
160
167
 
168
+ // Every hours
169
+ setInterval(() => {
170
+ this.refreshStaticPages();
171
+ }, 1000 * 60 * 60);
172
+
161
173
  // Detect router services
162
174
  for (const serviceName in this.config.plugins) {
163
175
  this.app.register( this.config.plugins[serviceName] )
@@ -173,6 +185,32 @@ export default class ServerRouter
173
185
  // Start HTTP server
174
186
  await this.http.start();
175
187
 
188
+ // override
189
+ const originalLog = console.log;
190
+ console.log = (...args: any[]) => {
191
+
192
+ // parse stack trace: skip this function and the console.log call
193
+ /*const stackLine = (new Error()).stack?.split('\n')[2] || '';
194
+ const match = stackLine.match(/at (\w+)\.(\w+) /);
195
+ const className = match ? match[1] : '<global>';
196
+ const methodName = match ? match[2] : '<anonymous>';*/
197
+
198
+ const contextData = context.getStore() || {
199
+ channelType: 'master',
200
+ }
201
+
202
+ const requestPrefix = contextData.channelType === 'request'
203
+ ? `[${contextData.user ? contextData.user : 'guest'}] ${contextData.method} ${contextData.path} |`
204
+ : 'master';
205
+
206
+ // prefix and forward
207
+ originalLog.call(
208
+ console,
209
+ `${requestPrefix}`, // ${className}.${methodName}
210
+ ...args
211
+ );
212
+ };
213
+
176
214
  }
177
215
 
178
216
  public async shutdown() {
@@ -183,6 +221,65 @@ export default class ServerRouter
183
221
  - ACTIONS
184
222
  ----------------------------------*/
185
223
 
224
+ public async renderStatic(
225
+ path: string,
226
+ options: TRouteOptions["static"],
227
+ rendered?: any
228
+ ) {
229
+
230
+ // Wildcard: tell that the newly rendered pages should be cached
231
+ if (path === '*' || !path)
232
+ return;
233
+
234
+ if (!rendered) {
235
+
236
+ const fullUrl = this.url(path, {}, true);
237
+ console.log('[router] renderStatic', fullUrl);
238
+
239
+ const response = await got( fullUrl, {
240
+ method: 'GET',
241
+ headers: {
242
+ 'Accept': 'text/html'
243
+ },
244
+ throwHttpErrors: false,
245
+ });
246
+
247
+ if (response.statusCode !== 200) {
248
+ console.error('renderStatic', response.statusCode, response.body);
249
+ return;
250
+ }
251
+
252
+ rendered = response.body;
253
+ }
254
+
255
+ this.cache[path] = {
256
+ rendered: rendered,
257
+ options: options,
258
+ expire: typeof options === 'object'
259
+ ? Date.now() + (hInterval(options.refresh) || 3600)
260
+ : undefined
261
+ };
262
+
263
+ }
264
+
265
+ private refreshStaticPages() {
266
+
267
+ console.log('[router] refreshStaticPages');
268
+
269
+ for (const pageId in this.cache) {
270
+ const page = this.cache[pageId];
271
+ if (page.path && page.expire && page.expire < Date.now()) {
272
+
273
+ this.renderStatic(page.path, page.options);
274
+
275
+ }
276
+ }
277
+ }
278
+
279
+
280
+
281
+
282
+
186
283
  private registerRoutes(defModules: GlobImportedWithMetas<TRouteModule>) {
187
284
  for (const routeModule of defModules) {
188
285
 
@@ -231,6 +328,14 @@ export default class ServerRouter
231
328
 
232
329
  this.routes.push(route);
233
330
 
331
+ // Add to static pages
332
+ // Should be a GET oage that don't take any parameter
333
+ if (options.static) {
334
+ for (const url of options.static.urls) {
335
+ this.renderStatic(url, options.static);
336
+ }
337
+ }
338
+
234
339
  return this;
235
340
 
236
341
  }
@@ -393,7 +498,13 @@ export default class ServerRouter
393
498
  "Cache-Control",
394
499
  "no-store, no-cache, must-revalidate, proxy-revalidate"
395
500
  );
396
- res.setHeader("Pragma", "no-cache");
501
+
502
+ // Static pages
503
+ if (this.cache[req.path]) {
504
+ console.log('[router] Get static page from cache', req.path);
505
+ res.send( this.cache[req.path].rendered );
506
+ return;
507
+ }
397
508
 
398
509
  // Create request
399
510
  let requestId = uuid();
@@ -410,39 +521,34 @@ export default class ServerRouter
410
521
  this
411
522
  );
412
523
 
413
- // Create request context so we can access request context across all the request-triggered libs
414
- context.run({ channelType: 'request', channelId: requestId }, async () => {
415
-
416
- let response: ServerResponse<this>;
417
- try {
418
-
419
- // Hook
420
- await this.runHook('request', request);
524
+ let response: ServerResponse<this>;
525
+ try {
421
526
 
422
- // Bulk API Requests
423
- if (request.path === '/api' && typeof request.data.fetchers === "object") {
527
+ // Hook
528
+ await this.runHook('request', request);
424
529
 
425
- return await this.resolveApiBatch(request.data.fetchers, request);
530
+ // Bulk API Requests
531
+ if (request.path === '/api' && typeof request.data.fetchers === "object") {
426
532
 
427
- } else {
428
- response = await this.resolve(request);
429
- }
430
- } catch (e) {
431
- response = await this.handleError(e, request);
432
- }
533
+ return await this.resolveApiBatch(request.data.fetchers, request);
433
534
 
434
- if (!res.headersSent) {
435
- // Status
436
- res.status(response.statusCode);
437
- // Headers
438
- res.header(response.headers);
439
- // Data
440
- res.send(response.data);
441
- } else if (response.data !== 'true') {
442
- throw new Error("Can't return data from the controller since response has already been sent via express.");
535
+ } else {
536
+ response = await this.resolve(request);
443
537
  }
538
+ } catch (e) {
539
+ response = await this.handleError(e, request);
540
+ }
444
541
 
445
- });
542
+ if (!res.headersSent) {
543
+ // Status
544
+ res.status(response.statusCode);
545
+ // Headers
546
+ res.header(response.headers);
547
+ // Data
548
+ res.send(response.data);
549
+ } else if (response.data !== 'true') {
550
+ throw new Error("Can't return data from the controller since response has already been sent via express.");
551
+ }
446
552
  }
447
553
 
448
554
  public createContextServices( request: ServerRequest<this> ) {
@@ -466,75 +572,86 @@ export default class ServerRouter
466
572
  return contextServices;
467
573
  }
468
574
 
469
- public async resolve(request: ServerRequest<this>): Promise<ServerResponse<this>> {
575
+ public resolve = (request: ServerRequest<this>) => new Promise<ServerResponse<this>>((resolve, reject) => {
576
+
577
+ // Create request context so we can access request context across all the request-triggered libs
578
+ context.run({
579
+ // This is for debugging
580
+ channelType: 'request',
581
+ channelId: request.id,
582
+ method: request.method,
583
+ path: request.path,
584
+ }, async () => {
585
+
586
+ const timeStart = Date.now();
587
+
588
+ if (this.status === 'starting') {
589
+ console.log(LogPrefix, `Waiting for servert to be resdy before resolving request`);
590
+ await this.started;
591
+ }
470
592
 
471
- const logId = LogPrefix + ' ' + (request.isVirtual ? ' ---- ' : '') + request.ip + ' ' + request.method + ' ' + request.domain + ' ' + request.path;
472
- console.info(logId);
473
- const timeStart = Date.now();
593
+ try {
474
594
 
475
- if (this.status === 'starting') {
476
- console.log(LogPrefix, `Waiting for servert to be resdy before resolving request`);
477
- await this.started;
478
- }
595
+ const response = new ServerResponse<this>(request);
479
596
 
480
- try {
597
+ await this.runHook('resolve', request);
481
598
 
482
- const response = new ServerResponse<this>(request);
599
+ // Controller route
600
+ let route = this.controllers[request.path];
601
+ if (route !== undefined) {
483
602
 
484
- await this.runHook('resolve', request);
603
+ // Create response
604
+ await this.resolvedRoute(route, response, timeStart);
605
+ if (response.wasProvided)
606
+ return resolve(response);
607
+ }
485
608
 
486
- // Controller route
487
- let route = this.controllers[request.path];
488
- if (route !== undefined) {
609
+ const contextStore = context.getStore();
610
+ if (contextStore)
611
+ contextStore.user = request.user?.email;
489
612
 
490
- // Create response
491
- await this.resolvedRoute(route, response, logId, timeStart);
492
- if (response.wasProvided)
493
- return response;
494
- }
613
+ // Classic routes
614
+ for (route of this.routes) {
495
615
 
496
- // Classic routes
497
- for (route of this.routes) {
616
+ // Match Method
617
+ if (request.method !== route.method && route.method !== '*')
618
+ continue;
498
619
 
499
- // Match Method
500
- if (request.method !== route.method && route.method !== '*')
501
- continue;
620
+ // Match Response format
621
+ if (!request.accepts(route.options.accept))
622
+ continue;
502
623
 
503
- // Match Response format
504
- if (!request.accepts(route.options.accept))
505
- continue;
624
+ const isMatching = matchRoute(route, request);
625
+ if (!isMatching)
626
+ continue;
506
627
 
507
- const isMatching = matchRoute(route, request);
508
- if (!isMatching)
509
- continue;
628
+ await this.resolvedRoute(route, response, timeStart);
629
+ if (response.wasProvided)
630
+ return resolve(response);
631
+ }
510
632
 
511
- await this.resolvedRoute(route, response, logId, timeStart);
512
- if (response.wasProvided)
513
- return response;
514
- }
633
+ reject( new NotFound() );
515
634
 
516
- throw new NotFound();
635
+ } catch (error) {
517
636
 
518
- } catch (error) {
637
+ if (this.app.env.profile === 'dev') {
638
+ console.log('API batch error:', request.method, request.path, error);
639
+ const errOrigin = request.method + ' ' + request.path;
640
+ if (error.details === undefined)
641
+ error.details = { origin: errOrigin }
642
+ else
643
+ error.details.origin = errOrigin;
644
+ }
519
645
 
520
- if (this.app.env.profile === 'dev') {
521
- console.log('API batch error:', request.method, request.path, error);
522
- const errOrigin = request.method + ' ' + request.path;
523
- if (error.details === undefined)
524
- error.details = { origin: errOrigin }
525
- else
526
- error.details.origin = errOrigin;
646
+ this.printTakenTime(timeStart);
647
+ reject( error );
527
648
  }
528
-
529
- this.printTakenTime(logId, timeStart);
530
- throw error;
531
- }
532
- }
649
+ });
650
+ });
533
651
 
534
652
  private async resolvedRoute(
535
653
  route: TRoute,
536
654
  response: ServerResponse<this>,
537
- logId: string,
538
655
  timeStart: number
539
656
  ) {
540
657
 
@@ -546,15 +663,25 @@ export default class ServerRouter
546
663
  if (!response.wasProvided)
547
664
  return;
548
665
 
666
+ // Set in cache
667
+ if (
668
+ response.request.path
669
+ && route.options.static
670
+ && route.options.static.urls.includes('*')
671
+ ) {
672
+ console.log('[router] Set in cache', response.request.path);
673
+ this.renderStatic(response.request.path, route.options.static, response.data);
674
+ }
675
+
549
676
  const timeEndResolving = Date.now();
550
- this.printTakenTime(logId, timeStart, timeEndResolving);
677
+ this.printTakenTime(timeStart, timeEndResolving);
551
678
  }
552
679
 
553
- private printTakenTime = (logId: string, timeStart: number, timeEndResolving?: number) => {
680
+ private printTakenTime = (timeStart: number, timeEndResolving?: number) => {
554
681
 
555
682
  if (this.app.env.name === 'server') return;
556
683
 
557
- console.log(logId + ' ' + Math.round(Date.now() - timeStart) + 'ms' +
684
+ console.log( Math.round(Date.now() - timeStart) + 'ms' +
558
685
  (timeEndResolving === undefined ? '' : ' | Routing: ' + Math.round(timeEndResolving - timeStart))
559
686
  );
560
687
  }
@@ -583,7 +710,12 @@ export default class ServerRouter
583
710
  request.res.json(responseData);
584
711
  }
585
712
 
586
- private async handleError( e: CoreError, request: ServerRequest<ServerRouter> ) {
713
+ private async handleError( e: Error |CoreError | ZodError, request: ServerRequest<ServerRouter> ) {
714
+
715
+ if (e instanceof ZodError)
716
+ e = new InputError(
717
+ e.errors.map(e => e.path.join('.') + ': ' + e.message).join(', ')
718
+ );
587
719
 
588
720
  const code = 'http' in e ? e.http : 500;
589
721
 
@@ -600,7 +732,9 @@ export default class ServerRouter
600
732
 
601
733
  // Don't exose technical errors to users
602
734
  if (this.app.env.profile === 'prod')
603
- e.message = "We encountered an internal error, and our team has just been notified. Sorry for the inconvenience.";
735
+ e = new Error(
736
+ "We encountered an internal error, and our team has just been notified. Sorry for the inconvenience."
737
+ );
604
738
 
605
739
  } else {
606
740
 
@@ -111,17 +111,6 @@ export default class ServerResponse<
111
111
  // Create response context for controllers
112
112
  const context = await this.createContext(route);
113
113
 
114
- // Static rendering
115
- const chunkId = route.options["id"];
116
- if (route.options.static &&
117
- chunkId !== undefined
118
- &&
119
- this.router.cache[ chunkId ] !== undefined
120
- ) {
121
- await this.html( this.router.cache[ chunkId ] );
122
- return;
123
- }
124
-
125
114
  // Run controller
126
115
  const content = await this.route.controller( context );
127
116
  if (content === undefined)
@@ -139,10 +128,6 @@ export default class ServerResponse<
139
128
  // Return JSON
140
129
  else
141
130
  await this.json(content);
142
-
143
- // Cache
144
- if (route.options.static)
145
- this.router.cache[ chunkId ] = this.data;
146
131
  }
147
132
 
148
133
  private updateCanonicalUrl( route: TAnyRoute ) {
@@ -9,131 +9,39 @@ import path from 'path';
9
9
  import md5 from 'md5';
10
10
  import { fromBuffer } from 'file-type';
11
11
  import { JSDOM } from 'jsdom';
12
- // Lexical
13
- import { $getRoot } from 'lexical';
14
- import { createHeadlessEditor } from '@lexical/headless';
15
- import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
16
12
 
17
13
  // Core
18
- import { Anomaly } from '@common/errors';
19
14
  import editorNodes from '@common/data/rte/nodes';
20
15
  import ExampleTheme from '@client/components/Rte/themes/PlaygroundEditorTheme';
21
- import type Driver from '@server/services/disks/driver';
22
16
  import Slug from '@server/utils/slug';
23
17
 
18
+ // Lexical
19
+ import { $getRoot, SerializedEditorState, SerializedLexicalNode } from 'lexical';
20
+ import { createHeadlessEditor } from '@lexical/headless';
21
+ import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
22
+
23
+ // Specifc
24
+ import {
25
+ default as BaseRteUtils,
26
+ LexicalNode,
27
+ LexicalState,
28
+ TRenderOptions,
29
+ TContentAssets,
30
+ TSkeleton
31
+ } from '@common/utils/rte';
32
+
24
33
  /*----------------------------------
25
34
  - TYPES
26
35
  ----------------------------------*/
27
36
 
28
- type LexicalState = {
29
- root: LexicalNode
30
- }
31
-
32
- export type LexicalNode = {
33
- version: number,
34
- type: string,
35
- children?: LexicalNode[],
36
- // Attachement
37
- src?: string;
38
- // Headhing
39
- text?: string;
40
- anchor?: string;
41
- tag?: string;
42
- }
43
-
44
- type TRenderOptions = {
45
-
46
- transform?: RteUtils["transformNode"],
47
-
48
- render?: (
49
- node: LexicalNode,
50
- parent: LexicalNode | null,
51
- options: TRenderOptions
52
- ) => Promise<LexicalNode>,
53
-
54
- attachements?: {
55
- disk: Driver,
56
- directory: string,
57
- prevVersion?: string | LexicalState | null,
58
- }
59
- }
60
-
61
- type TSkeleton = {
62
- id: string,
63
- title: string,
64
- level: number,
65
- childrens: TSkeleton
66
- }[];
67
-
68
- type TContentAssets = {
69
- attachements: string[],
70
- skeleton: TSkeleton
71
- }
72
37
 
73
38
  /*----------------------------------
74
39
  - FUNCTIONS
75
40
  ----------------------------------*/
76
41
 
77
- export class RteUtils {
78
-
79
- public async render(
80
- content: string | LexicalState,
81
- options: TRenderOptions = {}
82
- ): Promise<TContentAssets & {
83
- html: string,
84
- json: string | LexicalState,
85
- }> {
42
+ export class RteUtils extends BaseRteUtils {
86
43
 
87
- // Transform content
88
- const assets: TContentAssets = {
89
- attachements: [],
90
- skeleton: []
91
- }
92
-
93
- // Parse content if string
94
- let json: LexicalState;
95
- if (typeof content === 'string' && content.trim().startsWith('{')) {
96
- try {
97
- json = JSON.parse(content) as LexicalState;
98
- } catch (error) {
99
- throw new Anomaly("Invalid JSON format for the given JSON RTE content.");
100
- }
101
- } else if (content && typeof content === 'object' && content.root)
102
- json = content;
103
- else
104
- return { html: '', json: content, ...assets };
105
-
106
- // Parse prev version if string
107
- if (typeof options?.attachements?.prevVersion === 'string') {
108
- try {
109
- options.attachements.prevVersion = JSON.parse(options.attachements.prevVersion) as LexicalState;
110
- } catch (error) {
111
- throw new Anomaly("Invalid JSON format for the given JSON RTE prev version.");
112
- }
113
- }
114
-
115
- const root = await this.processContent(json.root, null, async (node, parent) => {
116
- return await this.transformNode(node, parent, assets, options);
117
- });
118
-
119
- json = { ...json, root };
120
-
121
- // Delete unused attachements
122
- const attachementOptions = options?.attachements;
123
- if (attachementOptions && attachementOptions.prevVersion !== undefined) {
124
-
125
- await this.processContent(root, null, async (node) => {
126
- return await this.deleteUnusedFile(node, assets, attachementOptions);
127
- });
128
- }
129
-
130
- // Convert json to HTML
131
- const html = await this.jsonToHtml( json, options );
132
-
133
- return { html, json: content, ...assets };
134
- }
135
-
136
- private async processContent(
44
+ protected async processContent(
137
45
  node: LexicalNode,
138
46
  parent: LexicalNode | null,
139
47
  callback: (node: LexicalNode, parent: LexicalNode | null) => Promise<LexicalNode>
@@ -153,7 +61,7 @@ export class RteUtils {
153
61
  return node;
154
62
  }
155
63
 
156
- private async transformNode(
64
+ protected async transformNode(
157
65
  node: LexicalNode,
158
66
  parent: LexicalNode | null,
159
67
  assets: TContentAssets,
@@ -254,7 +162,7 @@ export class RteUtils {
254
162
  });
255
163
  }
256
164
 
257
- private async deleteUnusedFile(
165
+ protected async deleteUnusedFile(
258
166
  node: LexicalNode,
259
167
  assets: TContentAssets,
260
168
  options: NonNullable<TRenderOptions["attachements"]>
@@ -282,7 +190,7 @@ export class RteUtils {
282
190
  return node;
283
191
  }
284
192
 
285
- public async jsonToHtml( json: LexicalState, options: TRenderOptions = {} ) {
193
+ public async jsonToHtml( json: LexicalState, options: TRenderOptions = {} ): Promise<string | null> {
286
194
 
287
195
  // Transform before rendering
288
196
  const renderTransform = options.render;
@@ -310,7 +218,7 @@ export class RteUtils {
310
218
  });
311
219
 
312
220
  // Set the editor state from JSON
313
- const state = editor.parseEditorState(json);
221
+ const state = editor.parseEditorState(json as SerializedEditorState<SerializedLexicalNode>);
314
222
  if (state.isEmpty())
315
223
  return '';
316
224
 
@@ -334,25 +242,6 @@ export class RteUtils {
334
242
  return html;
335
243
  }
336
244
 
337
- private jsonToText( node: LexicalNode ) {
338
-
339
- let text = '';
340
-
341
- // Check if the node has text content
342
- if (node.type === 'text' && node.text) {
343
- text += node.text;
344
- }
345
-
346
- // Recursively process children nodes
347
- if (node.children && Array.isArray(node.children)) {
348
- node.children.forEach(childNode => {
349
- text += this.jsonToText(childNode);
350
- });
351
- }
352
-
353
- return text;
354
- }
355
-
356
245
  public async htmlToJson(htmlString: string): Promise<LexicalState> {
357
246
 
358
247
  const editor = createHeadlessEditor({