@kithinji/orca 1.0.13 → 1.0.15
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 +535 -0
- package/dist/browser/index.iife.js +1 -1
- package/dist/browser/index.iife.js.map +2 -2
- package/dist/browser/index.mjs +1 -1
- package/dist/browser/index.mjs.map +2 -2
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.cjs.map +2 -2
- package/dist/node/index.mjs +1 -1
- package/dist/node/index.mjs.map +2 -2
- package/package.json +32 -12
package/README.md
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
<h1 align="center">Orca</h1>
|
|
2
|
+
<p align="center">
|
|
3
|
+
<img src="https://i.postimg.cc/Wpq8CWvV/orca.png" alt="orca-logo" width="150px"/>
|
|
4
|
+
<br>
|
|
5
|
+
<em>One codebase. One deployment.
|
|
6
|
+
<br> Build full-stack applications without the frontend/backend divide.</em>
|
|
7
|
+
<br>
|
|
8
|
+
</p>
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://orca.dafifi.net/"><strong>orca.dafifi.net</strong></a>
|
|
11
|
+
<br>
|
|
12
|
+
</p>
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://www.npmjs.com/package/@kithinji/orca">
|
|
15
|
+
<img src="https://img.shields.io/badge/NPM_package-v1.0.14-blue" alt="Orca on npm" />
|
|
16
|
+
</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<hr>
|
|
20
|
+
|
|
21
|
+
## The Problem
|
|
22
|
+
|
|
23
|
+
Building modern web apps means maintaining two separate projects: a frontend repo and a backend repo. Two package.jsons. Two deployment pipelines. Two sets of bugs for what should be _one feature_.
|
|
24
|
+
|
|
25
|
+
The cognitive overhead is exhausting. You're not just switching files, you're switching mental models. Frontend brain, backend brain. Component lifecycle, request lifecycle. By the time you've wired everything together, you've spent more time _connecting_ things than building them.
|
|
26
|
+
|
|
27
|
+
**Orca solves this.**
|
|
28
|
+
|
|
29
|
+
## What is Orca?
|
|
30
|
+
|
|
31
|
+
Orca is a full-stack TypeScript framework that lets you build your entire application - API, business logic, and UI - in a single codebase with shared types, unified architecture, and zero artificial boundaries.
|
|
32
|
+
|
|
33
|
+
Inspired by NestJS and Angular, Orca brings structure and convention to full-stack development using dependency injection, event systems, and a novel approach to client-server separation.
|
|
34
|
+
|
|
35
|
+
### The Core Innovation
|
|
36
|
+
|
|
37
|
+
Instead of forcing you to choose between server rendering or client interactivity, Orca gives you **both** with two simple directives:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// Server-rendered by default - fast, works without JavaScript
|
|
41
|
+
@Component()
|
|
42
|
+
export class ProductList {
|
|
43
|
+
constructor(private products: ProductService) {}
|
|
44
|
+
|
|
45
|
+
async build() {
|
|
46
|
+
const items = await this.products.getAll();
|
|
47
|
+
return (
|
|
48
|
+
<div>
|
|
49
|
+
{items.map((item) => (
|
|
50
|
+
<ProductCard key={item.id} product={item} />
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
// "use interactive" creates islands of interactivity
|
|
60
|
+
"use interactive";
|
|
61
|
+
import { Component, signal } from "@kithinji/orca";
|
|
62
|
+
|
|
63
|
+
@Component()
|
|
64
|
+
export class AddToCartButton {
|
|
65
|
+
constructor(private cart: CartService) {}
|
|
66
|
+
|
|
67
|
+
props!: { productId: number };
|
|
68
|
+
private adding = signal(false);
|
|
69
|
+
|
|
70
|
+
build() {
|
|
71
|
+
return (
|
|
72
|
+
<button
|
|
73
|
+
disabled={this.adding.value}
|
|
74
|
+
onClick={async () => {
|
|
75
|
+
this.adding.value = true;
|
|
76
|
+
await this.cart.addItem(this.props.productId);
|
|
77
|
+
this.adding.value = false;
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{this.adding.value ? "Adding..." : "Add to Cart"}
|
|
81
|
+
</button>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
// "use public" creates type-safe API endpoints automatically
|
|
89
|
+
"use public";
|
|
90
|
+
import { Injectable } from "@kithinji/orca";
|
|
91
|
+
|
|
92
|
+
@Injectable()
|
|
93
|
+
export class CartService {
|
|
94
|
+
public async addItem(productId: number) {
|
|
95
|
+
// This code runs on the server
|
|
96
|
+
// But can be called from the client like a local function
|
|
97
|
+
const item = await this.db.products.findUnique({ where: { productId } });
|
|
98
|
+
return this.db.cart.create({ data: { productId, quantity: 1 } });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public async getTotal() {
|
|
102
|
+
return this.db.cart.aggregate({ _sum: { price: true } });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
When you call `this.cart.addItem()` from a client component, Orca automatically:
|
|
108
|
+
|
|
109
|
+
1. Generates a `/CartService/addItem` API endpoint
|
|
110
|
+
2. Validates the input on the server
|
|
111
|
+
3. Executes your server-side logic
|
|
112
|
+
4. Returns the typed response
|
|
113
|
+
|
|
114
|
+
**You never write `fetch()` calls. The types never drift.**
|
|
115
|
+
|
|
116
|
+
## Key Features
|
|
117
|
+
|
|
118
|
+
- **Islands Architecture**: Server-render by default, add interactivity only where needed with `"use interactive"`
|
|
119
|
+
- **Type-Safe APIs**: Mark services with `"use public"` to auto-generate typed API endpoints. No manual fetch calls
|
|
120
|
+
- **Dependency Injection**: Services, controllers, and components work together with clean separation of concerns
|
|
121
|
+
- **Stack-Based Navigation**: Push components onto a navigation stack instead of wrestling with file-based routing
|
|
122
|
+
- **Shared TypeScript Types**: Your types never drift because they're literally the same types across client and server
|
|
123
|
+
- **Decorator-Based APIs**: Express your intent clearly with TypeScript decorators
|
|
124
|
+
- **Built-in Validation**: Request validation using schemas like Zod
|
|
125
|
+
- **Modular Architecture**: Organize code by feature, not by technical layer
|
|
126
|
+
|
|
127
|
+
## Why Not...?
|
|
128
|
+
|
|
129
|
+
### "Why not separate frontend/backend repos?"
|
|
130
|
+
|
|
131
|
+
Because maintaining two repos for one app doubles your work. Two sets of types that drift. Two deployment pipelines. Constant context switching between mental models. If you're a solo dev or small team, you're spending more time wiring things together than building features.
|
|
132
|
+
|
|
133
|
+
### "Why not Next.js?"
|
|
134
|
+
|
|
135
|
+
Next.js is excellent at rendering UI fast. But the moment you try to build a real backend with Server Actions, the lines blur in uncomfortable ways. Validation logic bleeds into components. Database queries live next to UI code. It's optimized for frontend-first development, not full-stack architecture.
|
|
136
|
+
|
|
137
|
+
Orca gives you a proper backend with controllers, services, and dependency injection, plus UI rendering that doesn't feel like an afterthought.
|
|
138
|
+
|
|
139
|
+
### "Why not HTMX?"
|
|
140
|
+
|
|
141
|
+
HTMX is elegant for server-rendered apps. But endpoints that return HTML lock you in. What happens when you need a mobile app? A CLI? A webhook consumer? You either build a second JSON API or parse HTML on the client.
|
|
142
|
+
|
|
143
|
+
Orca's API returns JSON by default. The UI rendering is a layer on top, not a replacement. You're never painted into a corner.
|
|
144
|
+
|
|
145
|
+
## Getting Started
|
|
146
|
+
|
|
147
|
+
### Prerequisites
|
|
148
|
+
|
|
149
|
+
- Node.js v20.9 or above
|
|
150
|
+
- A text editor (VS Code recommended)
|
|
151
|
+
|
|
152
|
+
### Installation
|
|
153
|
+
|
|
154
|
+
Install the Orca CLI globally:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm install -g @kithinji/pod
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Create Your First Project
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
pod new my-app
|
|
164
|
+
cd my-app
|
|
165
|
+
npm run dev
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Visit `http://localhost:8080` to see your application running. 🎉
|
|
169
|
+
|
|
170
|
+
## Project Structure
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
src/
|
|
174
|
+
├── features/
|
|
175
|
+
│ ├── user/
|
|
176
|
+
│ │ ├── user.controller.ts # HTTP endpoints (optional)
|
|
177
|
+
│ │ ├── user.service.ts # Business logic
|
|
178
|
+
│ │ ├── pages/ # UI page components
|
|
179
|
+
│ │ │ ├── user-profile.page.tsx
|
|
180
|
+
│ │ │ └── user-login.page.tsx
|
|
181
|
+
│ │ ├── components/ # UI components
|
|
182
|
+
│ │ │ └── avatar.component.tsx
|
|
183
|
+
│ │ └── user.module.ts # Module definition
|
|
184
|
+
│ └── product/
|
|
185
|
+
│ ├── product.service.ts
|
|
186
|
+
│ ├── components/
|
|
187
|
+
│ └── product.module.ts
|
|
188
|
+
└── app.module.ts # Root module
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Core Concepts
|
|
192
|
+
|
|
193
|
+
### 1. Services (Business Logic)
|
|
194
|
+
|
|
195
|
+
Services contain your application's business logic. They're injectable classes that can be used anywhere in your app.
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// product.service.ts
|
|
199
|
+
"use public"; // Makes this service callable from the client
|
|
200
|
+
import { Injectable, Signature } from "@kithinji/orca";
|
|
201
|
+
import { z } from "zod";
|
|
202
|
+
|
|
203
|
+
const GetProductSchema = z.object({ id: z.number() });
|
|
204
|
+
const ProductSchema = z.object({
|
|
205
|
+
id: z.number(),
|
|
206
|
+
name: z.string(),
|
|
207
|
+
price: z.number(),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
@Injectable()
|
|
211
|
+
export class ProductService {
|
|
212
|
+
constructor(private db: DatabaseService) {}
|
|
213
|
+
|
|
214
|
+
@Signature(GetProductSchema, ProductSchema) // used in generating validation logic automatically
|
|
215
|
+
public async getProduct(id: number) {
|
|
216
|
+
return this.db.products.findUnique({ where: { id } });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public async listProducts() {
|
|
220
|
+
return this.db.products.findMany();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 2. Components (UI Layer)
|
|
226
|
+
|
|
227
|
+
Components are class-based and return JSX from a `build()` method. They're server-rendered by default.
|
|
228
|
+
|
|
229
|
+
**Server Component (async data fetching):**
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
// product-list.component.tsx
|
|
233
|
+
import { Component } from "@kithinji/orca";
|
|
234
|
+
|
|
235
|
+
@Component()
|
|
236
|
+
export class ProductList {
|
|
237
|
+
constructor(private products: ProductService) {}
|
|
238
|
+
|
|
239
|
+
async build() {
|
|
240
|
+
const items = await this.products.listProducts();
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<div>
|
|
244
|
+
<h1>Products</h1>
|
|
245
|
+
{items.map((item) => (
|
|
246
|
+
<div key={item.id}>
|
|
247
|
+
<h3>{item.name}</h3>
|
|
248
|
+
<p>${item.price}</p>
|
|
249
|
+
<AddToCartButton productId={item.id} />
|
|
250
|
+
</div>
|
|
251
|
+
))}
|
|
252
|
+
</div>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Interactive Component (client-side reactivity):**
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
// add-to-cart-button.component.tsx
|
|
262
|
+
"use interactive";
|
|
263
|
+
import { Component, signal } from "@kithinji/orca";
|
|
264
|
+
|
|
265
|
+
@Component()
|
|
266
|
+
export class AddToCartButton {
|
|
267
|
+
constructor(private cart: CartService) {}
|
|
268
|
+
|
|
269
|
+
props!: { productId: number };
|
|
270
|
+
private adding = signal(false);
|
|
271
|
+
|
|
272
|
+
build() {
|
|
273
|
+
return (
|
|
274
|
+
<button
|
|
275
|
+
onClick={async () => {
|
|
276
|
+
this.adding.value = true;
|
|
277
|
+
await this.cart.addItem(this.props.productId);
|
|
278
|
+
this.adding.value = false;
|
|
279
|
+
}}
|
|
280
|
+
>
|
|
281
|
+
{this.adding.value ? "Adding..." : "Add to Cart"}
|
|
282
|
+
</button>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 3. Controllers (HTTP Layer)
|
|
289
|
+
|
|
290
|
+
Controllers handle HTTP requests and define REST endpoints. You can write them manually or let Orca generate them automatically for `"use public"` services.
|
|
291
|
+
|
|
292
|
+
**Manual Controller:**
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { Controller, Get, Post, Body, Param } from "@kithinji/orca";
|
|
296
|
+
|
|
297
|
+
@Controller("/products")
|
|
298
|
+
export class ProductController {
|
|
299
|
+
constructor(private products: ProductService) {}
|
|
300
|
+
|
|
301
|
+
@Get()
|
|
302
|
+
async findAll() {
|
|
303
|
+
return this.products.listProducts();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@Get("/:id")
|
|
307
|
+
async findOne(@Param("id") id: number) {
|
|
308
|
+
return this.products.getProduct(id);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@Post()
|
|
312
|
+
async create(@Body() data: CreateProductDto) {
|
|
313
|
+
return this.products.create(data);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Auto-Generated Controller:**
|
|
319
|
+
|
|
320
|
+
When you mark a service with `"use public"`, Orca automatically creates endpoints:
|
|
321
|
+
|
|
322
|
+
- `POST /ProductService/getProduct`
|
|
323
|
+
- `GET /ProductService/listProducts`
|
|
324
|
+
|
|
325
|
+
No controller code needed - just mark the service and call methods from your client components.
|
|
326
|
+
|
|
327
|
+
### 4. Modules (Organization)
|
|
328
|
+
|
|
329
|
+
Modules group related functionality together and manage dependencies.
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
// product.module.ts
|
|
333
|
+
import { Module } from "@kithinji/orca";
|
|
334
|
+
import { ProductController } from "./product.controller";
|
|
335
|
+
import { ProductService } from "./product.service";
|
|
336
|
+
import { ProductList, AddToCartButton } from "./components";
|
|
337
|
+
|
|
338
|
+
@Module({
|
|
339
|
+
imports: [DatabaseModule], // Modules we depend on
|
|
340
|
+
controllers: [ProductController], // HTTP endpoints
|
|
341
|
+
providers: [ProductService], // Services
|
|
342
|
+
declarations: [ProductList, AddToCartButton], // UI components
|
|
343
|
+
exports: [ProductService, ProductList], // What others can use
|
|
344
|
+
})
|
|
345
|
+
export class ProductModule {}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 5. Navigation (Stack-Based Routing)
|
|
349
|
+
|
|
350
|
+
Instead of file-based routing, Orca uses a navigation stack. Push components onto the stack to navigate.
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
import { Navigate } from "@kithinji/orca";
|
|
354
|
+
|
|
355
|
+
@Component()
|
|
356
|
+
export class HomePage {
|
|
357
|
+
constructor(private navigate: Navigate) {}
|
|
358
|
+
|
|
359
|
+
build() {
|
|
360
|
+
return (
|
|
361
|
+
<div>
|
|
362
|
+
<h1>Welcome</h1>
|
|
363
|
+
<button onClick={() => this.navigate.push(<UserProfile userId={1} />)}>
|
|
364
|
+
View Profile
|
|
365
|
+
</button>
|
|
366
|
+
</div>
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Navigation methods:
|
|
373
|
+
|
|
374
|
+
- `push()` - Add a new page on top
|
|
375
|
+
- `pop()` - Go back to previous page
|
|
376
|
+
- `replace()` - Replace current page
|
|
377
|
+
- `popToRoot()` - Clear stack and return to root
|
|
378
|
+
- `canPop()` - Check if back navigation is possible
|
|
379
|
+
|
|
380
|
+
## The Magic: How It All Works Together
|
|
381
|
+
|
|
382
|
+
Here's a complete feature showing the full stack:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
// cart.service.ts
|
|
386
|
+
"use public";
|
|
387
|
+
@Injectable()
|
|
388
|
+
export class CartService {
|
|
389
|
+
constructor(private db: DatabaseService) {}
|
|
390
|
+
|
|
391
|
+
public async addItem(productId: number, quantity: number = 1) {
|
|
392
|
+
const product = await this.db.products.findUnique({ where: { productId } });
|
|
393
|
+
return this.db.cart.create({
|
|
394
|
+
data: { productId, quantity, price: product.price },
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
public async getCart() {
|
|
399
|
+
return this.db.cart.findMany();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// cart-page.component.tsx
|
|
404
|
+
@Component()
|
|
405
|
+
export class CartPage {
|
|
406
|
+
constructor(private cart: CartService) {}
|
|
407
|
+
|
|
408
|
+
async build() {
|
|
409
|
+
const items = await this.cart.getCart();
|
|
410
|
+
return (
|
|
411
|
+
<div>
|
|
412
|
+
<h1>Your Cart</h1>
|
|
413
|
+
{items.map((item) => (
|
|
414
|
+
<CartItem key={item.id} item={item} />
|
|
415
|
+
))}
|
|
416
|
+
</div>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// add-to-cart-button.component.tsx
|
|
422
|
+
("use interactive");
|
|
423
|
+
|
|
424
|
+
@Component()
|
|
425
|
+
export class AddToCartButton {
|
|
426
|
+
constructor(private cart: CartService, private navigate: Navigate) {}
|
|
427
|
+
|
|
428
|
+
props!: { productId: number };
|
|
429
|
+
|
|
430
|
+
build() {
|
|
431
|
+
return (
|
|
432
|
+
<button
|
|
433
|
+
onClick={async () => {
|
|
434
|
+
await this.cart.addItem(this.props.productId);
|
|
435
|
+
this.navigate.push(<CartPage />);
|
|
436
|
+
}}
|
|
437
|
+
>
|
|
438
|
+
Add to Cart
|
|
439
|
+
</button>
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**What happens here:**
|
|
446
|
+
|
|
447
|
+
1. `CartService` is marked `"use public"`, so Orca generates API endpoints
|
|
448
|
+
2. `CartPage` (server component) calls `cart.getCart()` on the server during initial render
|
|
449
|
+
3. `AddToCartButton` (interactive component) calls `cart.addItem()` from the browser
|
|
450
|
+
4. Orca automatically converts that call into `fetch('/CartService/addItem', ...)`
|
|
451
|
+
5. Types are preserved end-to-end; TypeScript catches errors everywhere
|
|
452
|
+
6. Navigation happens by pushing a component, not a URL string
|
|
453
|
+
|
|
454
|
+
## Is Orca for You?
|
|
455
|
+
|
|
456
|
+
**Orca is great if you:**
|
|
457
|
+
|
|
458
|
+
- Are a solo developer or small team
|
|
459
|
+
- Want to ship features without maintaining two separate projects
|
|
460
|
+
- Value clear architecture and separation of concerns
|
|
461
|
+
- Need a real API that can grow (mobile apps, CLIs, integrations)
|
|
462
|
+
- Are tired of context switching between frontend and backend mental models
|
|
463
|
+
- Build internal tools, dashboards, or admin panels
|
|
464
|
+
- You're building highly interactive web apps
|
|
465
|
+
|
|
466
|
+
**Orca might not be for you if:**
|
|
467
|
+
|
|
468
|
+
- You have a large team with dedicated frontend/backend developers
|
|
469
|
+
- You prefer the frontend/backend split and it works for your workflow
|
|
470
|
+
- You need a purely client-side SPA framework
|
|
471
|
+
- You're building a marketing site or content-heavy blog (use Astro or Next.js)
|
|
472
|
+
- Your team is already deeply invested in another stack
|
|
473
|
+
|
|
474
|
+
This isn't a crusade. If the traditional split works for you, keep doing what works. But if you've ever thought "there has to be a simpler way", Orca is that way.
|
|
475
|
+
|
|
476
|
+
## Philosophy
|
|
477
|
+
|
|
478
|
+
With the rise of React, Vue, and Angular, web development split into two worlds: frontend and backend. For large teams, that makes sense. But for solo devs and small teams, it doubles the work.
|
|
479
|
+
|
|
480
|
+
Orca rejects the artificial divide. Instead:
|
|
481
|
+
|
|
482
|
+
- **One codebase**: Write features end-to-end in one place
|
|
483
|
+
- **Islands of interactivity**: Server-render by default, add JavaScript only where needed
|
|
484
|
+
- **Type-safe APIs**: No manual fetch calls, no drifting types
|
|
485
|
+
- **Clear architecture**: DI, decorators, and modules keep large apps maintainable
|
|
486
|
+
- **Stack-based navigation**: Route by pushing components, not by folder structure
|
|
487
|
+
|
|
488
|
+
This is opinionated software. It has rules, structure, and conventions. That's the point. The rules exist to free you from decision fatigue so you can focus on building.
|
|
489
|
+
|
|
490
|
+
## Documentation
|
|
491
|
+
|
|
492
|
+
Full guides, API references, and examples at **[orca.dafifi.net](https://orca.dafifi.net/)**
|
|
493
|
+
|
|
494
|
+
Topics covered:
|
|
495
|
+
|
|
496
|
+
- Components and JSX
|
|
497
|
+
- Dependency Injection
|
|
498
|
+
- Modules and Providers
|
|
499
|
+
- Controllers and Routing
|
|
500
|
+
- The `"use interactive"` directive
|
|
501
|
+
- The `"use public"` directive
|
|
502
|
+
- Signals and Reactivity
|
|
503
|
+
- Observables
|
|
504
|
+
- Navigation Stack
|
|
505
|
+
- Validation with Zod
|
|
506
|
+
|
|
507
|
+
## Roadmap
|
|
508
|
+
|
|
509
|
+
- [ ] Database integrations (TypeORM, Prisma)
|
|
510
|
+
- [ ] Authentication & authorization modules
|
|
511
|
+
- [ ] WebSocket support
|
|
512
|
+
- [ ] GraphQL adapter
|
|
513
|
+
- [ ] CLI scaffolding improvements
|
|
514
|
+
- [ ] File upload handling
|
|
515
|
+
- [ ] Background jobs / task queues
|
|
516
|
+
|
|
517
|
+
## Contributing
|
|
518
|
+
|
|
519
|
+
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
|
|
520
|
+
|
|
521
|
+
## Stay in Touch
|
|
522
|
+
|
|
523
|
+
- **Author**: [Kithinji Brian](https://www.linkedin.com/in/kithinjibrian/)
|
|
524
|
+
- **Website**: [orca.dafifi.net](https://orca.dafifi.net/)
|
|
525
|
+
- **NPM**: [@kithinji/orca](https://www.npmjs.com/package/@kithinji/orca)
|
|
526
|
+
|
|
527
|
+
## License
|
|
528
|
+
|
|
529
|
+
MIT
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
<p align="center">
|
|
534
|
+
Made in Nairobi with ❤️ for developers who just want to ship
|
|
535
|
+
</p>
|
|
@@ -1373,7 +1373,7 @@ var kithinjiorca = (() => {
|
|
|
1373
1373
|
const subst = obs.subscribe((val) => {
|
|
1374
1374
|
sig.value = val;
|
|
1375
1375
|
});
|
|
1376
|
-
instance.
|
|
1376
|
+
instance.__cleanup = [...instance.__cleanup ?? [], () => subst.unsubscribe()];
|
|
1377
1377
|
return sig;
|
|
1378
1378
|
}
|
|
1379
1379
|
function isObservable(value) {
|