Skip to content

Commit 9c7862f

Browse files
first commit
0 parents  commit 9c7862f

File tree

129 files changed

+20141
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+20141
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
analyze:
13+
name: Analyze
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- uses: dart-lang/setup-dart@v1
19+
with:
20+
sdk: "3.10.7"
21+
22+
- name: Install dependencies
23+
run: dart pub get
24+
25+
- name: Check formatting
26+
run: dart format --output=none --set-exit-if-changed .
27+
28+
- name: Analyze
29+
run: dart analyze --fatal-infos
30+
31+
test:
32+
name: Test
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- uses: dart-lang/setup-dart@v1
38+
with:
39+
sdk: "3.10.7"
40+
41+
- name: Install dependencies
42+
run: dart pub get
43+
44+
- name: Run tests
45+
run: |
46+
cd packages/spark && dart test
47+
cd ../spark_cli && dart test
48+
cd ../spark_generator && dart test

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# https://dart.dev/guides/libraries/private-files
2+
# Created by `dart pub`
3+
.dart_tool/
4+
5+
# Avoid committing pubspec.lock for library packages; see
6+
# https://dart.dev/guides/libraries/private-files#pubspeclock.
7+
pubspec.lock
8+
9+
# Build outputs
10+
build/
11+
12+
# IDE
13+
.idea/
14+
*.iml
15+
.vscode/
16+
17+
*.g.dart

packages/spark/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Dart generated files
2+
.dart_tool/
3+
pubspec.lock
4+
5+
# Build outputs
6+
build/
7+
8+
# IDE
9+
.idea/
10+
*.iml
11+
.vscode/

packages/spark/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 1.0.0-alpha.1
2+
3+
- Initial version

packages/spark/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 KLEAK Development
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/spark/README.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Spark Framework
2+
3+
A lightweight, isomorphic SSR web framework for Dart that enables Server-Side Rendering with interactive "islands" of client-side logic using Custom Elements and Declarative Shadow DOM.
4+
5+
## Features
6+
7+
- **HTML-first**: Server sends fully formed HTML for instant display.
8+
- **Isomorphic Components**: Single Dart file defines both server and client logic.
9+
- **Zero-JS Initial Paint**: Uses Declarative Shadow DOM for immediate rendering.
10+
- **Typed CSS**: Type-safe, autocompleted styling API (`Style.typed`).
11+
- **Automatic OpenAPI**: Generate OpenAPI specifications directly from your code.
12+
- **DTO Validation**: Automatic request body validation using annotations.
13+
- **Multi-Page Architecture**: Each route has its own lightweight JavaScript bundle.
14+
15+
## Installation
16+
17+
Add dependencies to your `pubspec.yaml`:
18+
19+
```yaml
20+
dependencies:
21+
spark_framework: ^1.0.0-alpha.1
22+
```
23+
24+
Install the CLI tool globally:
25+
26+
```bash
27+
dart pub global activate spark_cli
28+
```
29+
30+
## CLI Usage
31+
32+
The `spark` CLI helps you manage your project lifecycle.
33+
34+
- **Initialize a new project**:
35+
36+
```bash
37+
spark init my_app
38+
```
39+
40+
- **Run development server** (with hot reload):
41+
42+
```bash
43+
spark dev
44+
```
45+
46+
- **Build for production**:
47+
48+
```bash
49+
spark build
50+
```
51+
52+
- **Generate OpenAPI specification**:
53+
```bash
54+
spark openapi
55+
```
56+
57+
## Quick Start
58+
59+
### 1. Create a Component
60+
61+
Create a reusable component with typed styling and isomorphic logic.
62+
63+
```dart
64+
import 'package:spark_framework/spark.dart';
65+
66+
part 'counter.g.dart';
67+
68+
@Component(tag: Counter.tag)
69+
class Counter extends SparkComponent with _\$CounterSync {
70+
Counter({this.count = 0, this.label = 'Count'});
71+
72+
static const tag = 'my-counter';
73+
74+
@override
75+
String get tagName => tag;
76+
77+
@Attribute(observable: true)
78+
int count;
79+
80+
String label;
81+
82+
@override
83+
Element build() {
84+
return div([
85+
style([
86+
css({
87+
':host': .typed(
88+
display: .inlineBlock,
89+
padding: .all(.px(16)),
90+
border: CssBorder(
91+
width: .px(1),
92+
style: .solid,
93+
color: .hex('#ccc'),
94+
),
95+
borderRadius: .px(8),
96+
fontFamily: .raw('sans-serif'),
97+
),
98+
'button': .typed(
99+
cursor: .pointer,
100+
padding: .symmetric(vertical: .px(4), horizontal: .px(8)),
101+
margin: .symmetric(horizontal: .px(4)),
102+
),
103+
}).toCss(),
104+
]),
105+
span([label, ': ']),
106+
span(id: 'val', [count]),
107+
button(
108+
id: 'inc',
109+
onClick: (_) {
110+
count++;
111+
},
112+
['+'],
113+
),
114+
button(
115+
id: 'dec',
116+
onClick: (_) {
117+
count--;
118+
},
119+
['-'],
120+
),
121+
]);
122+
}
123+
}
124+
```
125+
126+
### 3. Server Route
127+
128+
Serve your component using a Shelf handler.
129+
130+
```dart
131+
import 'package:spark_framework/spark.dart';
132+
import 'package:spark_framework/server.dart';
133+
import 'package:your_package_name/spark_router.g.dart';
134+
135+
void main() async {
136+
final server = await createSparkServer(
137+
SparkServerConfig(
138+
port: 8080,
139+
),
140+
);
141+
print('Server running at http://localhost:\${server.port}');
142+
}
143+
```
144+
145+
## Core Concepts
146+
147+
### Styling with Typed CSS
148+
149+
Spark provides a type-safe API for writing CSS, reducing errors and providing autocomplete.
150+
151+
```dart
152+
final myStyle = Style.typed(
153+
width: CssLength.percent(100),
154+
height: CssLength.vh(100),
155+
display: CssDisplay.grid,
156+
gridTemplateColumns: 'repeat(3, 1fr)', // Complex values can still use strings
157+
gap: CssLength.rem(2),
158+
margin: CssSpacing.symmetric(
159+
vertical: CssLength.px(20),
160+
horizontal: CssLength.px(0),
161+
),
162+
color: CssColor.rgb(50, 50, 50),
163+
);
164+
```
165+
166+
### Endpoints & Validation
167+
168+
Define robust API endpoints with automatic validation and documentation.
169+
170+
```dart
171+
@Endpoint(path: '/api/users', method: 'POST')
172+
class CreateUser extends SparkEndpoint<CreateUserDto> {
173+
@override
174+
Future<Response> handler(SparkRequest req, CreateUserDto body) async {
175+
// body is automatically validated and typed
176+
return Response.ok({'id': 123, 'name': body.name});
177+
}
178+
}
179+
180+
class CreateUserDto {
181+
@NotEmpty(message: 'Name is required')
182+
@Length(min: 2, max: 50)
183+
final String name;
184+
185+
@Email()
186+
final String email;
187+
188+
CreateUserDto({required this.name, required this.email});
189+
}
190+
```
191+
192+
### Validation Annotations
193+
194+
Supported annotations include:
195+
196+
- `@NotEmpty`, `@Length`, `@Min`, `@Max`
197+
- `@Email`, `@Pattern`, `@IsNumeric`, `@IsBooleanString`
198+
199+
## Project Structure
200+
201+
A typical Spark project looks like this:
202+
203+
```
204+
my_app/
205+
├── bin/
206+
│ └── server.dart # Server entry point
207+
├── lib/
208+
│ ├── components/ # Isomorphic components
209+
│ ├── endpoints/ # API endpoints
210+
│ └── pages/ # Page layouts
211+
├── web/
212+
│ └── main.dart # Browser entry points
213+
├── pubspec.yaml
214+
└── README.md
215+
```
216+
217+
## License
218+
219+
MIT
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
include: package:lints/recommended.yaml
2+
3+
analyzer:
4+
exclude:
5+
- "**/*.g.dart"

packages/spark/example/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Dart generated files
2+
.dart_tool/
3+
pubspec.lock
4+
5+
# Build outputs
6+
build
7+
8+
# IDE
9+
.idea/
10+
*.iml
11+
.vscode/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
include: package:lints/recommended.yaml
2+
3+
analyzer:
4+
exclude:
5+
- "**/*.g.dart"
6+
- "build/**/*"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:shelf/shelf.dart';
2+
import 'package:spark_framework/spark.dart';
3+
import 'package:spark_example/spark_router.g.dart';
4+
5+
@OpenApi(
6+
title: 'Spark Example API',
7+
version: '1.0.0',
8+
description: 'An example API built with Spark.',
9+
servers: ['http://localhost:8080'],
10+
securitySchemes: {
11+
'ApiKeyAuth': SecurityScheme.apiKey(
12+
name: 'X-API-KEY',
13+
inLocation: 'header',
14+
),
15+
'BearerAuth': SecurityScheme.http(scheme: 'bearer', bearerFormat: 'JWT'),
16+
},
17+
security: [
18+
{'ApiKeyAuth': []},
19+
],
20+
)
21+
void main() async {
22+
final server = await createSparkServer(
23+
SparkServerConfig(port: 9003, middleware: [logRequests()]),
24+
);
25+
print('Server running at http://localhost:${server.port}');
26+
}

0 commit comments

Comments
 (0)