solidstep 0.1.0 → 0.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.
- package/README.md +536 -18
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -1,18 +1,536 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
# SolidStep
|
|
2
|
+
|
|
3
|
+
Next Solid Step towards a more performant web - A full-stack SolidJS framework for building modern web applications with file-based routing, SSR, and built-in security.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **File-based Routing** - Automatic routing based on your file structure
|
|
8
|
+
- ⚡ **Server-Side Rendering (SSR)** - Fast initial page loads with full SSR support
|
|
9
|
+
- 🔄 **Data Loading** - Built-in loaders for efficient data fetching
|
|
10
|
+
- 🎨 **Layouts & Groups** - Nested layouts and parallel route groups
|
|
11
|
+
- 🛡️ **Security First** - Built-in CSP, CORS, CSRF, and cookie utilities
|
|
12
|
+
- 🎯 **Server Actions** - Type-safe server functions with automatic serialization
|
|
13
|
+
- ⚙️ **Middleware Support** - Request/response interceptors
|
|
14
|
+
- 📦 **Caching** - Built-in page-level caching
|
|
15
|
+
- 🔥 **Hot Module Replacement** - Fast development experience
|
|
16
|
+
- 📝 **TypeScript** - Full TypeScript support out of the box
|
|
17
|
+
|
|
18
|
+
## Getting Started
|
|
19
|
+
|
|
20
|
+
### Create a New Project
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
[npx | yarn dlx | pnpm dlx | bunx] @varlabs/create-solidstep@latest my-app
|
|
24
|
+
cd my-app
|
|
25
|
+
[npm | yarn | pnpm | bun] install
|
|
26
|
+
[npm | yarn | pnpm | bun] run dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Special Files
|
|
30
|
+
|
|
31
|
+
- `page.tsx` - Page component
|
|
32
|
+
- `layout.tsx` - Layout wrapper
|
|
33
|
+
- `loading.tsx` - Loading state (Streaming - optional)
|
|
34
|
+
- `error.tsx` - Error boundary (optional)
|
|
35
|
+
- `not-found.tsx` - 404 page (root only - optional)
|
|
36
|
+
- `route.ts` - API route handler
|
|
37
|
+
- `middleware.ts` - Request middleware
|
|
38
|
+
|
|
39
|
+
**A route is defined by either the presence of a `page.tsx` or `route.ts` file in a directory.**
|
|
40
|
+
|
|
41
|
+
### Configuration
|
|
42
|
+
|
|
43
|
+
Configure your app in `app.config.ts`:
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { defineConfig } from 'solidstep';
|
|
47
|
+
|
|
48
|
+
export default defineConfig({
|
|
49
|
+
server: {
|
|
50
|
+
port: 3000,
|
|
51
|
+
preset: 'node',
|
|
52
|
+
},
|
|
53
|
+
plugins: [
|
|
54
|
+
{
|
|
55
|
+
type: 'both',
|
|
56
|
+
plugin: myVitePlugin(),
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Project Structure
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
my-app/
|
|
66
|
+
├── app/
|
|
67
|
+
│ ├── page.tsx # Home page (/)
|
|
68
|
+
│ ├── layout.tsx # Root layout
|
|
69
|
+
│ ├── middleware.ts # Request middleware
|
|
70
|
+
│ ├── about/
|
|
71
|
+
│ │ └── page.tsx # About page (/about)
|
|
72
|
+
│ ├── (admin)/
|
|
73
|
+
│ | └── dashboard/
|
|
74
|
+
│ | └── page.tsx # Group route (/dashboard)
|
|
75
|
+
│ └── blog/
|
|
76
|
+
│ ├── layout.tsx # Blog layout
|
|
77
|
+
│ ├── page.tsx # Blog index (/blog)
|
|
78
|
+
│ └── [slug]/
|
|
79
|
+
│ └── page.tsx # Dynamic route (/blog/:slug)
|
|
80
|
+
├── public/
|
|
81
|
+
│ └── favicon.ico
|
|
82
|
+
├── app.config.ts
|
|
83
|
+
└── package.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Core Concepts
|
|
87
|
+
|
|
88
|
+
### Layouts
|
|
89
|
+
|
|
90
|
+
Wrap multiple pages with shared UI:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
export default function BlogLayout(props: { children: any }) {
|
|
94
|
+
return (
|
|
95
|
+
<div>
|
|
96
|
+
<nav>Blog Navigation</nav>
|
|
97
|
+
{props.children()}
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Pages
|
|
104
|
+
|
|
105
|
+
Create a `page.tsx` file in any directory under `app/` to define a route:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
export default function HomePage() {
|
|
109
|
+
return <h1>Welcome to SolidStep!</h1>;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Similar to NextJS, only content returned by a `page` or `route` is sent to the client**
|
|
114
|
+
|
|
115
|
+
### Group Routes
|
|
116
|
+
Use parentheses to group routes without affecting the URL:
|
|
117
|
+
|
|
118
|
+
```app/
|
|
119
|
+
├── (admin)/
|
|
120
|
+
│ └── dashboard/
|
|
121
|
+
│ └── page.tsx // matches /dashboard
|
|
122
|
+
└── (user)/
|
|
123
|
+
└── profile/
|
|
124
|
+
└── page.tsx // matches /profile
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Dynamic Routes
|
|
128
|
+
|
|
129
|
+
Use square brackets for dynamic segments:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// app/blog/[slug]/page.tsx - matches /blog/my-post, /blog/another-post, etc.
|
|
133
|
+
|
|
134
|
+
export default function BlogPost(props: { routeParams: { slug: string } }) {
|
|
135
|
+
return <h1>Post: {props.routeParams.slug}</h1>;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Catch-all routes:**
|
|
140
|
+
```tsx
|
|
141
|
+
// app/docs/[...path]/page.tsx - matches /docs/a, /docs/a/b, etc.
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Catch-all routes (Optional):**
|
|
145
|
+
```tsx
|
|
146
|
+
// app/docs/[[...path]]/page.tsx - matches /docs, /docs/a, /docs/a/b, etc.
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Parallel Routes (Groups)
|
|
150
|
+
|
|
151
|
+
Render multiple sections simultaneously:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
app/
|
|
155
|
+
├── layout.tsx
|
|
156
|
+
├── page.tsx
|
|
157
|
+
└── @graph1/
|
|
158
|
+
└── page.tsx
|
|
159
|
+
└── @graph2/
|
|
160
|
+
└── page.tsx
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
export default function RootLayout(props: {
|
|
165
|
+
children: any;
|
|
166
|
+
slots: { graph1: any; graph2: any; };
|
|
167
|
+
}) {
|
|
168
|
+
return (
|
|
169
|
+
<div>
|
|
170
|
+
<main>
|
|
171
|
+
{props.children()}
|
|
172
|
+
<aside>
|
|
173
|
+
<div>{props.slots.graph1()}</div>
|
|
174
|
+
<div>{props.slots.graph2()}</div>
|
|
175
|
+
</aside>
|
|
176
|
+
</main>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Data Loading
|
|
183
|
+
|
|
184
|
+
Use `defineLoader` to fetch data on the server:
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
import { defineLoader, type LoaderDataFromFunction } from 'solidstep/utils/loader';
|
|
188
|
+
|
|
189
|
+
export const loader = defineLoader(async (request) => {
|
|
190
|
+
const posts = await fetchPosts();
|
|
191
|
+
return { posts };
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
type LoaderData = LoaderDataFromFunction<typeof loader>;
|
|
195
|
+
|
|
196
|
+
export default function BlogPage(props: { loaderData: LoaderData }) {
|
|
197
|
+
return (
|
|
198
|
+
<ul>
|
|
199
|
+
<For each={props.loaderData.posts}>
|
|
200
|
+
{(post) => <li>{post.title}</li>}
|
|
201
|
+
</For>
|
|
202
|
+
</ul>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Server Actions
|
|
208
|
+
|
|
209
|
+
Create type-safe server functions:
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
'use server';
|
|
213
|
+
|
|
214
|
+
export const createPost = async (data: { title: string }) => {
|
|
215
|
+
await db.posts.create(data);
|
|
216
|
+
return { success: true };
|
|
217
|
+
};
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Call from client:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { createPost } from './actions';
|
|
224
|
+
|
|
225
|
+
function CreatePostForm() {
|
|
226
|
+
const handleSubmit = async (e: Event) => {
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
await createPost({ title: 'My Post' });
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
return <form onSubmit={handleSubmit}>...</form>;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Metadata
|
|
236
|
+
|
|
237
|
+
Define metadata for SEO:
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import type { Meta } from 'solidstep/utils/types';
|
|
241
|
+
|
|
242
|
+
export const generateMeta = async () => {
|
|
243
|
+
return {
|
|
244
|
+
title: {
|
|
245
|
+
type: 'title',
|
|
246
|
+
content: 'My Site',
|
|
247
|
+
attributes: {},
|
|
248
|
+
},
|
|
249
|
+
description: {
|
|
250
|
+
type: 'meta',
|
|
251
|
+
attributes: {
|
|
252
|
+
name: 'description',
|
|
253
|
+
content: 'My awesome site',
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
// manifest
|
|
257
|
+
manifest: {
|
|
258
|
+
type: 'link',
|
|
259
|
+
attributes: {
|
|
260
|
+
rel: 'manifest',
|
|
261
|
+
href: '/site.webmanifest',
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
// google fonts
|
|
265
|
+
'google-font-link': {
|
|
266
|
+
type: 'link',
|
|
267
|
+
attributes: {
|
|
268
|
+
rel: 'preconnect',
|
|
269
|
+
href: 'https://fonts.googleapis.com'
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
'gstatic-font-link': {
|
|
273
|
+
type: 'link',
|
|
274
|
+
attributes: {
|
|
275
|
+
rel: 'preconnect',
|
|
276
|
+
href: 'https://fonts.gstatic.com',
|
|
277
|
+
crossorigin: ''
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
'inter-font': {
|
|
281
|
+
type: 'link',
|
|
282
|
+
attributes: {
|
|
283
|
+
rel: 'stylesheet',
|
|
284
|
+
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
// external js
|
|
288
|
+
'analytics-script': {
|
|
289
|
+
type: 'script',
|
|
290
|
+
attributes: {
|
|
291
|
+
src: 'analytics.js',
|
|
292
|
+
defer: true,
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
} satisfies Meta;
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Middleware
|
|
300
|
+
|
|
301
|
+
Intercept and modify requests:
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
import { eventHandler } from 'vinxi/http';
|
|
305
|
+
|
|
306
|
+
export default eventHandler((event) => {
|
|
307
|
+
event.locals = { user: getCurrentUser() };
|
|
308
|
+
|
|
309
|
+
// you can also modify request/response here
|
|
310
|
+
// also include cors, csrf, csp logic if needed
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Page Options
|
|
315
|
+
|
|
316
|
+
Configure page-level caching:
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
export const options = {
|
|
320
|
+
cache: {
|
|
321
|
+
ttl: 60000,
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## API Routes
|
|
327
|
+
|
|
328
|
+
Create REST endpoints:
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
export async function GET(request: Request, { params }: any) {
|
|
332
|
+
const posts = await fetchPosts();
|
|
333
|
+
return new Response(JSON.stringify(posts), {
|
|
334
|
+
headers: { 'Content-Type': 'application/json' },
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export async function POST(request: Request) {
|
|
339
|
+
const data = await request.json();
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Utilities
|
|
344
|
+
|
|
345
|
+
### Cookies
|
|
346
|
+
```tsx
|
|
347
|
+
import { getCookie, setCookie } from 'solidstep/utils/cookies';
|
|
348
|
+
|
|
349
|
+
export const loader = defineLoader(async () => {
|
|
350
|
+
const userData = await getCookie();
|
|
351
|
+
|
|
352
|
+
if (!userData) {
|
|
353
|
+
return [];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const userId = userData.id;
|
|
357
|
+
|
|
358
|
+
const { data, error } = await getDocumentsByUserId(userId);
|
|
359
|
+
|
|
360
|
+
if (error || !data) {
|
|
361
|
+
return [];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return data as Document[];
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const action = async () => {
|
|
368
|
+
'use server';
|
|
369
|
+
|
|
370
|
+
await setCookie('session', JSON.stringify({ id: 'user-id' }), { httpOnly: true, secure: true, maxAge: 3600 });
|
|
371
|
+
|
|
372
|
+
return { success: true };
|
|
373
|
+
};
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### CORS
|
|
377
|
+
```tsx
|
|
378
|
+
import { cors } from 'solidstep/utils/cors';
|
|
379
|
+
|
|
380
|
+
const trustedOrigins = ['https://example.com', 'https://another-example.com'];
|
|
381
|
+
|
|
382
|
+
const corsMiddleware = cors(trustedOrigins);
|
|
383
|
+
|
|
384
|
+
...
|
|
385
|
+
|
|
386
|
+
const corsHeaders = corsMiddleware(origin, event.node.req.method === 'OPTIONS');
|
|
387
|
+
|
|
388
|
+
...
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### CSP
|
|
392
|
+
```tsx
|
|
393
|
+
import { createBasePolicy, serializePolicy, withNonce } from '@varlabs/solidstep/utils/csp';
|
|
394
|
+
|
|
395
|
+
let cspPolicy = createBasePolicy();
|
|
396
|
+
|
|
397
|
+
...
|
|
398
|
+
|
|
399
|
+
cspPolicy = withNonce(cspPolicy, nonce);
|
|
400
|
+
|
|
401
|
+
...
|
|
402
|
+
|
|
403
|
+
event.response.headers.set('Content-Security-Policy', serializePolicy(cspPolicy));
|
|
404
|
+
|
|
405
|
+
...
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### CSRF Protection
|
|
409
|
+
```tsx
|
|
410
|
+
import { csrf } from '@varlabs/solidstep/utils/csrf';
|
|
411
|
+
|
|
412
|
+
const trustedOrigins = ['https://example.com', 'https://another-example.com'];
|
|
413
|
+
|
|
414
|
+
const csrfMiddleware = csrf(trustedOrigins);
|
|
415
|
+
|
|
416
|
+
...
|
|
417
|
+
|
|
418
|
+
const csrfResult = csrfMiddleware(
|
|
419
|
+
event.node.req.method,
|
|
420
|
+
requestUrl,
|
|
421
|
+
origin,
|
|
422
|
+
event.node.req.headers.referer
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
if (!csrfResult.success) {
|
|
426
|
+
event.node.res.statusCode = 403; // Forbidden
|
|
427
|
+
event.node.res.end(csrfResult.message);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Redirects
|
|
433
|
+
```tsx
|
|
434
|
+
import { redirect } from 'solidstep/utils/redirect';
|
|
435
|
+
|
|
436
|
+
export const loader = defineLoader(async () => {
|
|
437
|
+
redirect('/login');
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// or in client
|
|
441
|
+
export function MyComponent() {
|
|
442
|
+
const handleClick = () => {
|
|
443
|
+
redirect('/dashboard');
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
return <button onClick={handleClick}>Go to Dashboard</button>;
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Error Handling
|
|
451
|
+
```tsx
|
|
452
|
+
// first define an error collection
|
|
453
|
+
import { createErrorFactory } from 'solidstep/utils/error-handler';
|
|
454
|
+
|
|
455
|
+
export const createError = createErrorFactory({
|
|
456
|
+
'db-query-error': {
|
|
457
|
+
message: 'Something went wrong with the database query, not idea what',
|
|
458
|
+
severity: 'high',
|
|
459
|
+
action: (error) => {
|
|
460
|
+
console.error('Generic DB query error', error);
|
|
461
|
+
throw error;
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
'auth-error': {
|
|
465
|
+
message: 'User authentication failed',
|
|
466
|
+
severity: 'high',
|
|
467
|
+
action: (error) => {
|
|
468
|
+
console.error('User authentication error', error);
|
|
469
|
+
throw error;
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
'service-error': {
|
|
473
|
+
message:
|
|
474
|
+
'Some service (external or internal that is interfacing with the app) failed',
|
|
475
|
+
severity: 'high',
|
|
476
|
+
action: (error) => {
|
|
477
|
+
console.error('Service error', error);
|
|
478
|
+
throw error;
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// then use it in your loaders, actions or routes
|
|
484
|
+
export const loader = defineLoader(async () => {
|
|
485
|
+
const data = await tryCatch(fetchDataFromDB());
|
|
486
|
+
if (data.error) {
|
|
487
|
+
// handle the error using the defined error collection
|
|
488
|
+
createError('db-query-error').action();
|
|
489
|
+
|
|
490
|
+
// or overwrite the defaults
|
|
491
|
+
createError('db-query-error', {
|
|
492
|
+
// customize the error
|
|
493
|
+
message: data.error.message,
|
|
494
|
+
action: (error) => {
|
|
495
|
+
// just log it for example
|
|
496
|
+
console.error('Custom action for DB error', error);
|
|
497
|
+
},
|
|
498
|
+
severity: 'critical',
|
|
499
|
+
cause: data.error,
|
|
500
|
+
metadata: { query: 'SELECT * FROM users' },
|
|
501
|
+
}).action();
|
|
502
|
+
|
|
503
|
+
// defer the definition and the handling
|
|
504
|
+
const error = createError('db-query-error');
|
|
505
|
+
// some logic
|
|
506
|
+
error.action();
|
|
507
|
+
|
|
508
|
+
// or throw the error
|
|
509
|
+
const error = createError('db-query-error', {
|
|
510
|
+
cause: data.error,
|
|
511
|
+
});
|
|
512
|
+
throw error;
|
|
513
|
+
}
|
|
514
|
+
return data.result;
|
|
515
|
+
});
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
## Future Plans
|
|
519
|
+
- Support for dynamic site.webmanifest, robots.txt, sitemap.xml, manifest.json, and llms.txt
|
|
520
|
+
- Support loading and error pages for parallel routes
|
|
521
|
+
- Support deferring loaders
|
|
522
|
+
- Image/font optimizations
|
|
523
|
+
- Possible CSR/SPA, SSG, ISR, and PPR
|
|
524
|
+
|
|
525
|
+
## License
|
|
526
|
+
|
|
527
|
+
MIT
|
|
528
|
+
|
|
529
|
+
## Links
|
|
530
|
+
|
|
531
|
+
- [GitHub](https://github.com/HamzaKV/solidstep)
|
|
532
|
+
- [SolidJS Documentation](https://www.solidjs.com/)
|
|
533
|
+
|
|
534
|
+
## Special Mentions
|
|
535
|
+
- Inspired by [Remix](https://remix.run/), [Next.js](https://nextjs.org/), and [TanStack](https://tanstack.com/)
|
|
536
|
+
- Built with [Vite](https://vitejs.dev/), [SolidJS](https://www.solidjs.com/), [Vinxi](https://github.com/nksaraf/vinxi) and [Seroval](https://github.com/lxsmnsyc/seroval)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solidstep",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Next Step SolidJS Framework for building web applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "HamzaKV <hamzakv333@gmail.com>",
|
|
@@ -54,5 +54,11 @@
|
|
|
54
54
|
"rimraf": "^6.0.1",
|
|
55
55
|
"typescript": "^5.8.3",
|
|
56
56
|
"vite-plugin-solid": "^2.11.7"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=20"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
57
63
|
}
|
|
58
64
|
}
|