remult 0.25.5-exp.8 → 0.25.5

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 (43) hide show
  1. package/esm/graphql.js +24 -17
  2. package/esm/index.js +1 -0
  3. package/esm/package.json +1 -1
  4. package/esm/remult-fastify.js +3 -0
  5. package/esm/remult-hapi.js +3 -0
  6. package/esm/remult-knex/index.js +12 -2
  7. package/esm/remult-next.js +8 -0
  8. package/esm/remult-nuxt.js +3 -0
  9. package/esm/remult-sveltekit.js +63 -42
  10. package/esm/server/expressBridge.js +28 -0
  11. package/esm/server/get-remult-admin-html.js +3 -0
  12. package/esm/server/remult-admin.js +92 -0
  13. package/esm/src/data-providers/array-entity-data-provider.js +0 -1
  14. package/esm/src/remult3/Fields.js +7 -1
  15. package/esm/src/remult3/RepositoryImplementation.js +1 -2
  16. package/esm/src/remult3/remult3.js +25 -3
  17. package/esm/src/server-action.js +3 -1
  18. package/graphql.js +40 -33
  19. package/index.d.ts +1 -0
  20. package/index.js +3 -1
  21. package/package.json +1 -1
  22. package/remult-fastify.js +3 -0
  23. package/remult-hapi.js +3 -0
  24. package/remult-knex/index.js +63 -46
  25. package/remult-next.js +8 -0
  26. package/remult-nuxt.js +3 -0
  27. package/remult-sveltekit.d.ts +5 -1
  28. package/remult-sveltekit.js +85 -56
  29. package/server/expressBridge.d.ts +13 -1
  30. package/server/expressBridge.js +42 -0
  31. package/server/get-remult-admin-html.d.ts +1 -0
  32. package/server/get-remult-admin-html.js +7 -0
  33. package/server/remult-admin.d.ts +36 -0
  34. package/server/remult-admin.js +121 -0
  35. package/src/data-providers/array-entity-data-provider.d.ts +13 -0
  36. package/src/data-providers/array-entity-data-provider.js +0 -1
  37. package/src/remult3/Fields.d.ts +1 -0
  38. package/src/remult3/Fields.js +7 -1
  39. package/src/remult3/RepositoryImplementation.d.ts +2 -0
  40. package/src/remult3/RepositoryImplementation.js +1 -2
  41. package/src/remult3/remult3.d.ts +1 -1
  42. package/src/remult3/remult3.js +25 -3
  43. package/src/server-action.js +3 -1
package/esm/graphql.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getRelationFieldInfo } from './internals.js';
2
- import { Remult, remult } from './index.js';
2
+ import { CompoundIdField, Remult, remult } from './index.js';
3
3
  import { DataApi } from './src/data-api.js';
4
4
  import { getRepositoryInternals } from './src/remult3/repository-internals.js';
5
5
  const v2ConnectionAndPagination = false;
@@ -369,9 +369,12 @@ export function remultGraphql(options) {
369
369
  });
370
370
  currentType.mutation.delete.payload = upsertTypes(deletePayload);
371
371
  const deletedResultKey = `id`;
372
+ const type = meta.idMetadata.field instanceof CompoundIdField
373
+ ? 'String'
374
+ : getGraphqlBaseType(meta.idMetadata.field);
372
375
  currentType.mutation.delete.payload.fields.push({
373
376
  key: deletedResultKey,
374
- value: 'ID',
377
+ value: `${type}`,
375
378
  }, argErrorDetail, argClientMutationId);
376
379
  root[deleteResolverKey] = handleMutationWithErrors(async (dApi, response, setResult, arg1, req) => {
377
380
  await dApi.delete({
@@ -388,21 +391,7 @@ export function remultGraphql(options) {
388
391
  const ri = getRelationFieldInfo(f);
389
392
  if (f.options.includeInApi === false)
390
393
  continue;
391
- let type = 'String';
392
- switch (f.valueType) {
393
- case Boolean:
394
- type = 'Boolean';
395
- break;
396
- case Number:
397
- {
398
- if (f.valueConverter?.fieldTypeInDb === 'integer' ||
399
- f.valueConverter?.fieldTypeInDb === 'autoincrement')
400
- type = 'Int';
401
- else
402
- type = 'Float';
403
- }
404
- break;
405
- }
394
+ const type = getGraphqlBaseType(f);
406
395
  currentType.query.resultProcessors.push((r) => {
407
396
  r[nodeIdKey] = () => getMetaType(meta) + ':' + meta.idMetadata.getId(r);
408
397
  });
@@ -828,6 +817,24 @@ function fieldFormat(field) {
828
817
  }
829
818
  return `${strComment} ${key_value}`;
830
819
  }
820
+ function getGraphqlBaseType(field) {
821
+ let type = 'String';
822
+ switch (field.valueType) {
823
+ case Boolean:
824
+ type = 'Boolean';
825
+ break;
826
+ case Number:
827
+ {
828
+ if (field.valueConverter?.fieldTypeInDb === 'integer' ||
829
+ field.valueConverter?.fieldTypeInDb === 'autoincrement')
830
+ type = 'Int';
831
+ else
832
+ type = 'Float';
833
+ }
834
+ break;
835
+ }
836
+ return type;
837
+ }
831
838
  function getMetaType(entityMeta) {
832
839
  return entityMeta.entityType.name;
833
840
  }
package/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider.js';
1
2
  export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation.js';
2
3
  export { Entity } from './src/remult3/entity.js';
3
4
  export { getEntityRef } from './src/remult3/getEntityRef.js';
package/esm/package.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "type": "module"
2
+ "type": "module"
3
3
  }
@@ -10,6 +10,9 @@ export function remultFastify(options) {
10
10
  end() {
11
11
  res.send();
12
12
  },
13
+ send(html) {
14
+ res.type('text/html').send(html);
15
+ },
13
16
  json(data) {
14
17
  res.send(data);
15
18
  },
@@ -29,6 +29,9 @@ export function remultHapi(options) {
29
29
  end() {
30
30
  res(h.response().code(status));
31
31
  },
32
+ send(html) {
33
+ res(h.response(html).code(status));
34
+ },
32
35
  json(data) {
33
36
  res(h.response(data).code(status));
34
37
  },
@@ -31,6 +31,17 @@ export class KnexDataProvider {
31
31
  };
32
32
  }
33
33
  }
34
+ else if (this.knex.client.config.client === 'mysql2') {
35
+ for (const f of entity.fields.toArray()) {
36
+ if (f.valueConverter.fieldTypeInDb === 'json') {
37
+ //@ts-ignore
38
+ f.valueConverter = {
39
+ ...f.valueConverter,
40
+ toDb: ValueConverters.JsonString.toDb,
41
+ };
42
+ }
43
+ }
44
+ }
34
45
  return new KnexEntityDataProvider(entity, this.knex);
35
46
  }
36
47
  async transaction(action) {
@@ -416,8 +427,7 @@ function supportsJsonLoadingAndSaving(knex) {
416
427
  const client = knex.client.config.client;
417
428
  if (client?.includes('sqlite3') ||
418
429
  client?.includes('mssql') ||
419
- client?.includes('mysql2') ||
420
- client?.includes('mysql'))
430
+ client == 'mysql')
421
431
  return false;
422
432
  return true;
423
433
  }
@@ -57,6 +57,7 @@ export function remultNextApp(options) {
57
57
  const response = {
58
58
  end: () => { },
59
59
  json: () => { },
60
+ send: () => { },
60
61
  status: () => {
61
62
  return response;
62
63
  },
@@ -91,6 +92,13 @@ export function remultNextApp(options) {
91
92
  return sseResponse;
92
93
  }
93
94
  if (responseFromRemultHandler) {
95
+ if (responseFromRemultHandler.html)
96
+ return new Response(responseFromRemultHandler.html, {
97
+ status: responseFromRemultHandler.statusCode,
98
+ headers: {
99
+ 'Content-Type': 'text/html',
100
+ },
101
+ });
94
102
  return new Response(JSON.stringify(responseFromRemultHandler.data), {
95
103
  status: responseFromRemultHandler.statusCode,
96
104
  });
@@ -17,6 +17,7 @@ export function remultNuxt(options) {
17
17
  let sse = false;
18
18
  const response = {
19
19
  end: () => { },
20
+ send: () => { },
20
21
  json: () => { },
21
22
  status: () => {
22
23
  return response;
@@ -38,6 +39,8 @@ export function remultNuxt(options) {
38
39
  if (r) {
39
40
  if (r.statusCode !== 200)
40
41
  setResponseStatus(event, r.statusCode);
42
+ if (r.html)
43
+ return r.html;
41
44
  return r.data;
42
45
  }
43
46
  };
@@ -12,51 +12,68 @@ export function remultSveltekit(options) {
12
12
  }),
13
13
  getRequestBody: (event) => event.request.json(),
14
14
  });
15
- const handler = async ({ event, resolve }) => {
16
- if (event.url.pathname.startsWith(options.rootPath)) {
17
- let sseResponse = undefined;
18
- event.locals['_tempOnClose'] = () => { };
19
- const response = {
20
- end: () => { },
21
- json: () => { },
22
- status: () => {
23
- return response;
24
- },
25
- write: () => { },
26
- writeHead: (status, headers) => {
27
- if (status === 200 && headers) {
28
- const contentType = headers['Content-Type'];
29
- if (contentType === 'text/event-stream') {
30
- const messages = [];
31
- response.write = (x) => messages.push(x);
32
- const stream = new ReadableStream({
33
- start: (controller) => {
34
- for (const message of messages) {
35
- controller.enqueue(message);
36
- }
37
- response.write = (data) => {
38
- controller.enqueue(data);
39
- };
40
- },
41
- cancel: () => {
42
- response.write = () => { };
43
- event.locals['_tempOnClose']();
44
- },
45
- });
46
- sseResponse = new Response(stream, { headers });
47
- }
15
+ const serverHandler = async (event) => {
16
+ let sseResponse = undefined;
17
+ event.locals['_tempOnClose'] = () => { };
18
+ const response = {
19
+ end: () => { },
20
+ json: () => { },
21
+ send: () => { },
22
+ status: () => {
23
+ return response;
24
+ },
25
+ write: () => { },
26
+ writeHead: (status, headers) => {
27
+ if (status === 200 && headers) {
28
+ const contentType = headers['Content-Type'];
29
+ if (contentType === 'text/event-stream') {
30
+ const messages = [];
31
+ response.write = (x) => messages.push(x);
32
+ const stream = new ReadableStream({
33
+ start: (controller) => {
34
+ for (const message of messages) {
35
+ controller.enqueue(message);
36
+ }
37
+ response.write = (data) => {
38
+ controller.enqueue(data);
39
+ };
40
+ },
41
+ cancel: () => {
42
+ response.write = () => { };
43
+ event.locals['_tempOnClose']();
44
+ },
45
+ });
46
+ sseResponse = new Response(stream, { headers });
48
47
  }
49
- },
50
- };
51
- const responseFromRemultHandler = await result.handle(event, response);
52
- if (sseResponse !== undefined) {
53
- return sseResponse;
54
- }
55
- if (responseFromRemultHandler) {
56
- return new Response(JSON.stringify(responseFromRemultHandler.data), {
48
+ }
49
+ },
50
+ };
51
+ const responseFromRemultHandler = await result.handle(event, response);
52
+ if (sseResponse !== undefined) {
53
+ return sseResponse;
54
+ }
55
+ if (responseFromRemultHandler) {
56
+ if (responseFromRemultHandler.html)
57
+ return new Response(responseFromRemultHandler.html, {
57
58
  status: responseFromRemultHandler.statusCode,
59
+ headers: {
60
+ 'Content-Type': 'text/html',
61
+ },
58
62
  });
59
- }
63
+ const res = new Response(JSON.stringify(responseFromRemultHandler.data), {
64
+ status: responseFromRemultHandler.statusCode,
65
+ });
66
+ return res;
67
+ }
68
+ return new Response('Not Found', {
69
+ status: 404,
70
+ });
71
+ };
72
+ const handler = async ({ event, resolve }) => {
73
+ if (event.url.pathname.startsWith(options.rootPath)) {
74
+ const result = await serverHandler(event);
75
+ if (result != null && result?.status != 404)
76
+ return result;
60
77
  }
61
78
  return new Promise((res) => {
62
79
  result.withRemult(event, undefined, async () => {
@@ -70,5 +87,9 @@ export function remultSveltekit(options) {
70
87
  withRemult(request, what) {
71
88
  return result.withRemultAsync(request, what);
72
89
  },
90
+ GET: serverHandler,
91
+ PUT: serverHandler,
92
+ POST: serverHandler,
93
+ DELETE: serverHandler,
73
94
  });
74
95
  }
@@ -12,6 +12,7 @@ import { Action, classBackendMethodsArray } from '../src/server-action.js';
12
12
  import { serverActionField } from '../src/server-action-info.js';
13
13
  import { initDataProvider } from './initDataProvider.js';
14
14
  import { remultStatic } from '../src/remult-static.js';
15
+ import remultAdminHtml from './remult-admin.js';
15
16
  export function createRemultServerCore(options, serverCoreOptions) {
16
17
  if (!options) {
17
18
  options = {};
@@ -194,6 +195,18 @@ export class RemultServerImplementation {
194
195
  },
195
196
  doWork: undefined,
196
197
  }, r);
198
+ if (this.options.admin !== undefined && this.options.admin !== false) {
199
+ r.route(this.options.rootPath + '/admin*').get(this.process(async (remult, req, res, orig, origResponse) => {
200
+ if (remult.isAllowed(this.options.admin))
201
+ origResponse.send(remultAdminHtml({
202
+ remult: remult,
203
+ entities: this.options.entities,
204
+ baseUrl: this.options.rootPath + '/admin',
205
+ }));
206
+ else
207
+ res.notFound();
208
+ }));
209
+ }
197
210
  if (this.options.subscriptionServer instanceof SseSubscriptionServer) {
198
211
  const streamPath = this.options.rootPath + '/' + streamUrl;
199
212
  r.route(streamPath).get(this.process(async (remult, req, res, origReq, origRes) => {
@@ -814,6 +827,7 @@ export class RouteImplementation {
814
827
  this.coreOptions = coreOptions;
815
828
  }
816
829
  map = new Map();
830
+ starRoutes = [];
817
831
  route(path) {
818
832
  //consider using:
819
833
  //* https://raw.githubusercontent.com/cmorten/opine/main/src/utils/pathToRegex.ts
@@ -821,6 +835,8 @@ export class RouteImplementation {
821
835
  let r = path.toLowerCase();
822
836
  let m = new Map();
823
837
  this.map.set(r, m);
838
+ if (path.endsWith('*'))
839
+ this.starRoutes.push({ route: r.substring(0, r.length - 1), handler: m });
824
840
  const route = {
825
841
  get: (h) => {
826
842
  m.set('get', h);
@@ -864,6 +880,11 @@ export class RouteImplementation {
864
880
  gRes.json(data);
865
881
  res({ statusCode: this.statusCode, data });
866
882
  }
883
+ send(html) {
884
+ if (gRes !== undefined)
885
+ gRes.send(html);
886
+ res({ statusCode: this.statusCode, html });
887
+ }
867
888
  status(statusCode) {
868
889
  if (gRes !== undefined)
869
890
  gRes.status(statusCode);
@@ -913,6 +934,13 @@ export class RouteImplementation {
913
934
  }
914
935
  let lowerPath = path.toLowerCase();
915
936
  let m = this.map.get(lowerPath);
937
+ if (!m)
938
+ for (const route of this.starRoutes) {
939
+ if (lowerPath.startsWith(route.route)) {
940
+ m = route.handler;
941
+ break;
942
+ }
943
+ }
916
944
  if (m) {
917
945
  let h = m.get(req.method.toLowerCase());
918
946
  if (h) {