remult 0.26.1 → 0.26.3-exp.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.
package/README.md CHANGED
@@ -39,7 +39,7 @@ Remult uses **TypeScript entities** as a single source of truth for: ✅ CRUD +
39
39
 
40
40
  **Remult supports all major databases**, including: PostgreSQL, MySQL, SQLite, MongoDB, MSSQL and Oracle.
41
41
 
42
- **Remult is frontend and backend framework agnostic** and comes with adapters for Express, Fastify, Next.js, Nuxt, SvelteKit, Nest, Koa, Hapi and Hono.
42
+ **Remult is frontend and backend framework agnostic** and comes with adapters for Express, Fastify, Next.js, Nuxt, SvelteKit, SolidStart, Nest, Koa, Hapi and Hono.
43
43
 
44
44
  Remult promotes a **consistent query syntax for both frontend and Backend code**:
45
45
 
@@ -93,7 +93,7 @@ _Example:_
93
93
  // backend/index.ts
94
94
 
95
95
  import express from 'express'
96
- import { remultExpress } from 'remult/remult-express' // adapters for: Fastify, Next.js, Nuxt, SvelteKit, Nest, more...
96
+ import { remultExpress } from 'remult/remult-express' // adapters for: Fastify,Next.js, Nuxt, SvelteKit, SolidStart, Nest, more...
97
97
  import { createPostgresDataProvider } from 'remult/postgres' // supported: PostgreSQL, MySQL, SQLite, MongoDB, MSSQL and Oracle
98
98
  import { Product } from '../shared/product'
99
99
 
@@ -306,6 +306,7 @@ with a Node.js Express backend.
306
306
  - [Tutorial with Vue](https://remult.dev/tutorials/vue/)
307
307
  - [Tutorial with Next.js](https://remult.dev/tutorials/react-next/)
308
308
  - [Tutorial with Sveltekit](https://remult.dev/tutorials/sveltekit/)
309
+ - [Tutorial with SolidStart](https://remult.dev/tutorials/react-next/)
309
310
 
310
311
  ## Demo
311
312
 
@@ -29,8 +29,6 @@ export function remultHono(options) {
29
29
  });
30
30
  let honoRouter = {
31
31
  route(path) {
32
- if (path.endsWith('*'))
33
- path = path.substring(0, path.length - 1) + '.*';
34
32
  let r = {
35
33
  get(handler) {
36
34
  app.get(path, honoHandler(handler));
@@ -68,7 +66,7 @@ export function remultHono(options) {
68
66
  if (sse)
69
67
  sse.close();
70
68
  else
71
- res(c.text(''));
69
+ res(c.body(null));
72
70
  },
73
71
  send: (data) => {
74
72
  res(c.html(data));
@@ -0,0 +1,97 @@
1
+ import { getRequestEvent } from 'solid-js/web';
2
+ import { createRemultServer } from './server/index.js';
3
+ export function remultSolidStart(options) {
4
+ let result = createRemultServer(options, {
5
+ buildGenericRequestInfo: (event) => ({
6
+ url: event.request.url,
7
+ method: event.request.method,
8
+ on: (e, do1) => {
9
+ if (e === 'close') {
10
+ event.locals['_tempOnClose'] = do1;
11
+ }
12
+ },
13
+ }),
14
+ getRequestBody: (event) => event.request.json(),
15
+ });
16
+ const serverHandler = async () => {
17
+ const event = await getRequestEvent();
18
+ let sseResponse = undefined;
19
+ if (event)
20
+ event.locals['_tempOnClose'] = () => { };
21
+ const response = {
22
+ end: () => { },
23
+ json: () => { },
24
+ send: () => { },
25
+ status: () => {
26
+ return response;
27
+ },
28
+ write: () => { },
29
+ writeHead: (status, headers) => {
30
+ if (status === 200 && headers) {
31
+ const contentType = headers['Content-Type'];
32
+ if (contentType === 'text/event-stream') {
33
+ const messages = [];
34
+ response.write = (x) => messages.push(x);
35
+ const stream = new ReadableStream({
36
+ start: (controller) => {
37
+ for (const message of messages) {
38
+ controller.enqueue(message);
39
+ }
40
+ response.write = (data) => {
41
+ controller.enqueue(data);
42
+ };
43
+ },
44
+ cancel: () => {
45
+ response.write = () => { };
46
+ event?.locals?.['_tempOnClose']?.();
47
+ },
48
+ });
49
+ sseResponse = new Response(stream, { headers });
50
+ }
51
+ }
52
+ },
53
+ };
54
+ const responseFromRemultHandler = await result.handle(event, response);
55
+ if (sseResponse !== undefined) {
56
+ return sseResponse;
57
+ }
58
+ if (responseFromRemultHandler) {
59
+ if (responseFromRemultHandler.html)
60
+ return new Response(responseFromRemultHandler.html, {
61
+ status: responseFromRemultHandler.statusCode,
62
+ headers: {
63
+ 'Content-Type': 'text/html',
64
+ },
65
+ });
66
+ const res = new Response(JSON.stringify(responseFromRemultHandler.data), {
67
+ status: responseFromRemultHandler.statusCode,
68
+ });
69
+ return res;
70
+ }
71
+ return new Response('Not Found', {
72
+ status: 404,
73
+ });
74
+ };
75
+ const handler = {}; //async ({ event, resolve }) => {
76
+ // if (event.url.pathname.startsWith(options!.rootPath!)) {
77
+ // const result = await serverHandler(event)
78
+ // if (result != null && result?.status != 404) return result
79
+ // }
80
+ // return new Promise<Response>((res) => {
81
+ // result.withRemult(event, undefined!, async () => {
82
+ // res(await resolve(event))
83
+ // })
84
+ // })
85
+ // }
86
+ return Object.assign(handler, {
87
+ getRemult: (req) => result.getRemult(req),
88
+ openApiDoc: (options) => result.openApiDoc(options),
89
+ async withRemult(what) {
90
+ return result.withRemultAsync(await getRequestEvent(), what);
91
+ },
92
+ GET: serverHandler,
93
+ PUT: serverHandler,
94
+ POST: serverHandler,
95
+ DELETE: serverHandler,
96
+ });
97
+ }
@@ -197,7 +197,7 @@ export class RemultServerImplementation {
197
197
  doWork: undefined,
198
198
  }, r);
199
199
  if (this.options.admin !== undefined && this.options.admin !== false) {
200
- r.route(this.options.rootPath + '/admin*').get(this.process(async (remult, req, res, orig, origResponse) => {
200
+ const admin = this.process(async (remult, req, res, orig, origResponse) => {
201
201
  if (remult.isAllowed(this.options.admin))
202
202
  origResponse.send(remultAdminHtml({
203
203
  remult: remult,
@@ -206,7 +206,10 @@ export class RemultServerImplementation {
206
206
  }));
207
207
  else
208
208
  res.notFound();
209
- }));
209
+ });
210
+ r.route(this.options.rootPath + '/admin/:id').get(admin);
211
+ r.route(this.options.rootPath + '/admin/').get(admin);
212
+ r.route(this.options.rootPath + '/admin').get(admin);
210
213
  }
211
214
  if (this.options.subscriptionServer instanceof SseSubscriptionServer) {
212
215
  const streamPath = this.options.rootPath + '/' + streamUrl;
@@ -1,23 +1,22 @@
1
1
  export {};
2
2
  //y1 - https://discord.com/channels/975754286384418847/1230386433093533698/1230386433093533698
3
3
  //y1 - fix async hooks - was it fixed?
4
- //p1 - release solid start with example project
4
+ //p1 - consider upsert (where,set)
5
+ //p1 - consider id to also support keyof (id:['company','index'])
6
+ //p1 - wait a second to close stream
7
+ //p1 - reconsider update many, maybe the second parameter should be in a set option - break existing
5
8
  //p1 - add documentation for bun sqlite
6
- //p1 - fix dark background to also work on groups
7
9
  //p1 - describe entity
8
10
  //p1 - prepare the createEntity discussion
9
- //p1 - fix async hooks
10
11
  //p1 - write active record article
11
12
  //p1 - maybe add decorator comment in the readme as well (I heard you've lost me in decorators) - and improve the describeClass function
12
13
  //p1 - return error on connection error
13
- //p1 - reconsider update many, maybe the second parameter should be in a set option - break existing
14
- //p1 - consider upsert (where,set)
15
- //p1 - consider id to also support keyof (id:['company','index'])
16
14
  //p1 - consider including the admin in the tutorial - and maybe even in the demo when we setup the api
15
+ //p2 -fix remult admin not to load the html into memory until used
17
16
  //y2 - JY suggestion of having generate as part of the ensure schema - not sure
18
17
  //y2 - currently for string fields we default for 255 in knex (which is their default) why not just use text (varchar max) - and only use exact length when one is provided?
19
18
  //p2 - create foreign key constraints in user code - https://codesandbox.io/p/devbox/fk-validator-tdshcs
20
- //p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string}
19
+ //p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string} also checkout the admin* as it should probably be something else and didn't work in hono
21
20
  //p1 - article auth.js with express - played with it, requires type="module" and a few more configurations - https://github.com/noam-honig/express-auth
22
21
  //y2 - fix validators cache
23
22
  //y2 - should we validate relations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.26.1",
3
+ "version": "0.26.3-exp.0",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -140,6 +140,11 @@
140
140
  "require": "./remult-nuxt.js",
141
141
  "import": "./esm/remult-nuxt.js",
142
142
  "types": "./remult-nuxt.d.ts"
143
+ },
144
+ "./remult-solid-start": {
145
+ "require": "./remult-solid-start.js",
146
+ "import": "./esm/remult-solid-start.js",
147
+ "types": "./remult-solid-start.d.ts"
143
148
  }
144
149
  },
145
150
  "main": "./index.js",
package/remult-hono.js CHANGED
@@ -36,8 +36,6 @@ function remultHono(options) {
36
36
  });
37
37
  var honoRouter = {
38
38
  route: function (path) {
39
- if (path.endsWith('*'))
40
- path = path.substring(0, path.length - 1) + '.*';
41
39
  var r = {
42
40
  get: function (handler) {
43
41
  app.get(path, honoHandler(handler));
@@ -75,7 +73,7 @@ function remultHono(options) {
75
73
  if (sse_1)
76
74
  sse_1.close();
77
75
  else
78
- res(c.text(''));
76
+ res(c.body(null));
79
77
  },
80
78
  send: function (data) {
81
79
  res(c.html(data));
@@ -0,0 +1,12 @@
1
+ import { type RequestEvent } from 'solid-js/web';
2
+ import type { RemultServerCore, RemultServerOptions } from './server/index.js';
3
+ export declare function remultSolidStart(options: RemultServerOptions<RequestEvent>): RemultSolidStartServer;
4
+ type RequestHandler = (event: RequestEvent) => Promise<Response>;
5
+ export type RemultSolidStartServer = RemultServerCore<RequestEvent> & {
6
+ withRemult<T>(what: () => Promise<T>): Promise<T>;
7
+ GET: RequestHandler;
8
+ PUT: RequestHandler;
9
+ POST: RequestHandler;
10
+ DELETE: RequestHandler;
11
+ };
12
+ export {};
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.remultSolidStart = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var web_1 = require("solid-js/web");
6
+ var index_js_1 = require("./server/index.js");
7
+ function remultSolidStart(options) {
8
+ var _this = this;
9
+ var result = (0, index_js_1.createRemultServer)(options, {
10
+ buildGenericRequestInfo: function (event) { return ({
11
+ url: event.request.url,
12
+ method: event.request.method,
13
+ on: function (e, do1) {
14
+ if (e === 'close') {
15
+ event.locals['_tempOnClose'] = do1;
16
+ }
17
+ },
18
+ }); },
19
+ getRequestBody: function (event) { return event.request.json(); },
20
+ });
21
+ var serverHandler = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
22
+ var event, sseResponse, response, responseFromRemultHandler, res;
23
+ return tslib_1.__generator(this, function (_a) {
24
+ switch (_a.label) {
25
+ case 0: return [4 /*yield*/, (0, web_1.getRequestEvent)()];
26
+ case 1:
27
+ event = _a.sent();
28
+ sseResponse = undefined;
29
+ if (event)
30
+ event.locals['_tempOnClose'] = function () { };
31
+ response = {
32
+ end: function () { },
33
+ json: function () { },
34
+ send: function () { },
35
+ status: function () {
36
+ return response;
37
+ },
38
+ write: function () { },
39
+ writeHead: function (status, headers) {
40
+ if (status === 200 && headers) {
41
+ var contentType = headers['Content-Type'];
42
+ if (contentType === 'text/event-stream') {
43
+ var messages_1 = [];
44
+ response.write = function (x) { return messages_1.push(x); };
45
+ var stream = new ReadableStream({
46
+ start: function (controller) {
47
+ var e_1, _a;
48
+ try {
49
+ for (var messages_2 = tslib_1.__values(messages_1), messages_2_1 = messages_2.next(); !messages_2_1.done; messages_2_1 = messages_2.next()) {
50
+ var message = messages_2_1.value;
51
+ controller.enqueue(message);
52
+ }
53
+ }
54
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
55
+ finally {
56
+ try {
57
+ if (messages_2_1 && !messages_2_1.done && (_a = messages_2.return)) _a.call(messages_2);
58
+ }
59
+ finally { if (e_1) throw e_1.error; }
60
+ }
61
+ response.write = function (data) {
62
+ controller.enqueue(data);
63
+ };
64
+ },
65
+ cancel: function () {
66
+ var _a, _b;
67
+ response.write = function () { };
68
+ (_b = (_a = event === null || event === void 0 ? void 0 : event.locals) === null || _a === void 0 ? void 0 : _a['_tempOnClose']) === null || _b === void 0 ? void 0 : _b.call(_a);
69
+ },
70
+ });
71
+ sseResponse = new Response(stream, { headers: headers });
72
+ }
73
+ }
74
+ },
75
+ };
76
+ return [4 /*yield*/, result.handle(event, response)];
77
+ case 2:
78
+ responseFromRemultHandler = _a.sent();
79
+ if (sseResponse !== undefined) {
80
+ return [2 /*return*/, sseResponse];
81
+ }
82
+ if (responseFromRemultHandler) {
83
+ if (responseFromRemultHandler.html)
84
+ return [2 /*return*/, new Response(responseFromRemultHandler.html, {
85
+ status: responseFromRemultHandler.statusCode,
86
+ headers: {
87
+ 'Content-Type': 'text/html',
88
+ },
89
+ })];
90
+ res = new Response(JSON.stringify(responseFromRemultHandler.data), {
91
+ status: responseFromRemultHandler.statusCode,
92
+ });
93
+ return [2 /*return*/, res];
94
+ }
95
+ return [2 /*return*/, new Response('Not Found', {
96
+ status: 404,
97
+ })];
98
+ }
99
+ });
100
+ }); };
101
+ var handler = {}; //async ({ event, resolve }) => {
102
+ // if (event.url.pathname.startsWith(options!.rootPath!)) {
103
+ // const result = await serverHandler(event)
104
+ // if (result != null && result?.status != 404) return result
105
+ // }
106
+ // return new Promise<Response>((res) => {
107
+ // result.withRemult(event, undefined!, async () => {
108
+ // res(await resolve(event))
109
+ // })
110
+ // })
111
+ // }
112
+ return Object.assign(handler, {
113
+ getRemult: function (req) { return result.getRemult(req); },
114
+ openApiDoc: function (options) { return result.openApiDoc(options); },
115
+ withRemult: function (what) {
116
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
117
+ var _a, _b;
118
+ return tslib_1.__generator(this, function (_c) {
119
+ switch (_c.label) {
120
+ case 0:
121
+ _b = (_a = result).withRemultAsync;
122
+ return [4 /*yield*/, (0, web_1.getRequestEvent)()];
123
+ case 1: return [2 /*return*/, _b.apply(_a, [_c.sent(), what])];
124
+ }
125
+ });
126
+ });
127
+ },
128
+ GET: serverHandler,
129
+ PUT: serverHandler,
130
+ POST: serverHandler,
131
+ DELETE: serverHandler,
132
+ });
133
+ }
134
+ exports.remultSolidStart = remultSolidStart;
@@ -331,7 +331,7 @@ var RemultServerImplementation = /** @class */ (function () {
331
331
  doWork: undefined,
332
332
  }, r);
333
333
  if (this.options.admin !== undefined && this.options.admin !== false) {
334
- r.route(this.options.rootPath + '/admin*').get(this.process(function (remult, req, res, orig, origResponse) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
334
+ var admin = this.process(function (remult, req, res, orig, origResponse) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
335
335
  return tslib_1.__generator(this, function (_a) {
336
336
  if (remult.isAllowed(this.options.admin))
337
337
  origResponse.send((0, remult_admin_js_1.default)({
@@ -343,7 +343,10 @@ var RemultServerImplementation = /** @class */ (function () {
343
343
  res.notFound();
344
344
  return [2 /*return*/];
345
345
  });
346
- }); }));
346
+ }); });
347
+ r.route(this.options.rootPath + '/admin/:id').get(admin);
348
+ r.route(this.options.rootPath + '/admin/').get(admin);
349
+ r.route(this.options.rootPath + '/admin').get(admin);
347
350
  }
348
351
  if (this.options.subscriptionServer instanceof SseSubscriptionServer_js_1.SseSubscriptionServer) {
349
352
  var streamPath = this.options.rootPath + '/' + SubscriptionChannel_js_1.streamUrl;
@@ -2,23 +2,22 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  //y1 - https://discord.com/channels/975754286384418847/1230386433093533698/1230386433093533698
4
4
  //y1 - fix async hooks - was it fixed?
5
- //p1 - release solid start with example project
5
+ //p1 - consider upsert (where,set)
6
+ //p1 - consider id to also support keyof (id:['company','index'])
7
+ //p1 - wait a second to close stream
8
+ //p1 - reconsider update many, maybe the second parameter should be in a set option - break existing
6
9
  //p1 - add documentation for bun sqlite
7
- //p1 - fix dark background to also work on groups
8
10
  //p1 - describe entity
9
11
  //p1 - prepare the createEntity discussion
10
- //p1 - fix async hooks
11
12
  //p1 - write active record article
12
13
  //p1 - maybe add decorator comment in the readme as well (I heard you've lost me in decorators) - and improve the describeClass function
13
14
  //p1 - return error on connection error
14
- //p1 - reconsider update many, maybe the second parameter should be in a set option - break existing
15
- //p1 - consider upsert (where,set)
16
- //p1 - consider id to also support keyof (id:['company','index'])
17
15
  //p1 - consider including the admin in the tutorial - and maybe even in the demo when we setup the api
16
+ //p2 -fix remult admin not to load the html into memory until used
18
17
  //y2 - JY suggestion of having generate as part of the ensure schema - not sure
19
18
  //y2 - currently for string fields we default for 255 in knex (which is their default) why not just use text (varchar max) - and only use exact length when one is provided?
20
19
  //p2 - create foreign key constraints in user code - https://codesandbox.io/p/devbox/fk-validator-tdshcs
21
- //p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string}
20
+ //p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string} also checkout the admin* as it should probably be something else and didn't work in hono
22
21
  //p1 - article auth.js with express - played with it, requires type="module" and a few more configurations - https://github.com/noam-honig/express-auth
23
22
  //y2 - fix validators cache
24
23
  //y2 - should we validate relations