tosijs-platform 1.0.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.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +552 -0
  3. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Tonio Loewald
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.
package/README.md ADDED
@@ -0,0 +1,552 @@
1
+ # tosijs-platform
2
+
3
+ ## The Problem
4
+
5
+ Developer experience has been in freefall since the late 1990s.
6
+
7
+ In the REALbasic era, you could build an app, package it, and distribute it in a day. With PHP/LAMP, you could download a project, copy it to a server, edit a config file, and have a working app in an hour.
8
+
9
+ Then Node.js became the "standard stack" and standing up "hello world" became a nightmare of tooling, configuration, and dependencies. Platforms like Heroku helped, but we're still miles behind where we were with WordPress - let alone RAD tools from the 90s.
10
+
11
+ **tosijs-platform brings back that simplicity** - but with a modern stack.
12
+
13
+ ## The Solution
14
+
15
+ 1. Set up a Google developer account
16
+ 2. Run `npx create-tosijs-platform-app my-site`
17
+ 3. Follow the prompts
18
+ 4. You have a working, production-ready website
19
+
20
+ The database is configured. Permissions are set up. Authentication works. You can use it as-is, or customize it *without ever deploying code* - using the `/esm` endpoint and `<tosi-esm>` component to load and run modules dynamically.
21
+
22
+ **tosijs-platform** is built on [tosijs](https://tosijs.net), which distills 30 years of UI development lessons into one small library. It eliminates the need for most state management and binding code (typically 75%+ of a React app) through automatic binding conventions - the same patterns that made 90s RAD tools so productive - while keeping your business logic free of framework dependencies.
23
+
24
+ ## What You Get
25
+
26
+ - **Firebase backend** - Firestore, Auth, Storage, Cloud Functions
27
+ - **Built-in CMS** - blog, pages, custom content types
28
+ - **Fine-grained access control** - RBAC with field-level permissions
29
+ - **SEO-friendly SSR** - server-side rendering with prefetch
30
+ - **Type-safe** - TypeScript throughout
31
+ - **Extend without deploying** - dynamic ES modules via `/esm` endpoint
32
+
33
+ ## Quick Start
34
+
35
+ ```bash
36
+ npx create-tosijs-platform-app my-awesome-site
37
+ ```
38
+
39
+ The CLI will:
40
+ 1. ✓ Check Firebase CLI is installed and you're logged in
41
+ 2. ✓ Ask for your Firebase project ID and admin email
42
+ 3. ✓ Clone and configure the template
43
+ 4. ✓ Install dependencies
44
+ 5. ✓ Generate setup scripts
45
+
46
+ Then follow the printed instructions to deploy!
47
+
48
+ ## Architecture: TypeScript Access Control
49
+
50
+ **tosijs-platform** uses a fundamentally different security model than typical Firebase apps:
51
+
52
+ | Traditional Firebase | tosijs-platform |
53
+ |---------------------|-----------------|
54
+ | Security rules in Google's DSL | Access control in TypeScript |
55
+ | Limited to document/collection level | **Field-level granularity** |
56
+ | Basic auth checks | **Full RBAC with 6 roles** |
57
+ | Rules separate from app logic | Access logic alongside validation |
58
+ | Hard to test | **Fully unit-testable** |
59
+
60
+ **How it works:**
61
+ - All data access goes through Cloud Functions (`/doc`, `/docs` endpoints)
62
+ - Access control is defined in TypeScript per-collection (see `functions/src/collections/`)
63
+ - Roles: `public` → `author` → `editor` → `admin` → `developer` → `owner`
64
+ - Each role can have different read/write/list permissions, down to individual fields
65
+ - Server-side validation with `tosijs-schema`
66
+
67
+ **Example access configuration:**
68
+ ```typescript
69
+ access: {
70
+ [ROLES.public]: {
71
+ read: ALL, // Anyone can read
72
+ list: ALL, // Anyone can list
73
+ },
74
+ [ROLES.author]: {
75
+ write: ['title', 'body', 'tags'], // Authors can edit these fields
76
+ },
77
+ [ROLES.admin]: {
78
+ write: ALL, // Admins can edit everything
79
+ delete: true, // Admins can delete
80
+ },
81
+ }
82
+ ```
83
+
84
+ > **Important**: Cloud Functions deployment is **required** for the platform to work. The Firestore rules file (`firestore.rules`) uses deny-all defaults because all access is mediated through the Functions layer.
85
+
86
+ See [Firestore REST API & Security](docs/FIRESTORE_API.md) for complete documentation.
87
+
88
+ ## Documentation
89
+
90
+ 📚 **Core Concepts:**
91
+ - [Firestore REST API & Security](docs/FIRESTORE_API.md) - `/doc`, `/docs` endpoints and role-based access
92
+ - [ES Modules](docs/ESM_MODULES.md) - `/esm` endpoint and `<tosi-esm>` component for dynamic code loading
93
+ - [Prefetch & SEO](docs/PREFETCH.md) - Server-side rendering for fast loads and search engines
94
+
95
+ 🧩 **Components:**
96
+ - [Blog Component](docs/BLOG_COMPONENT.md) - Full-featured blog with Markdown editing
97
+ - [Page Component](docs/PAGE_COMPONENT.md) - Generic HTML/component renderer
98
+
99
+ ## Features
100
+
101
+ ### Content Management
102
+ - **Built-in blog** with Markdown/HTML editing
103
+ - **Static pages** for about, contact, etc.
104
+ - **Media library** with image uploads to Cloud Storage
105
+ - **Easy to extend** - add custom content types by defining collections
106
+
107
+ ### Developer Experience
108
+ - **Hot reload** dev server with HTTPS (uses self-signed TLS certs)
109
+ - **Type-safe** APIs and components
110
+ - **REST-based** data access (no SDK lock-in)
111
+ - **Flexible development** - work against production Firebase or use emulators
112
+
113
+ ### Security & Access Control
114
+ - **Role-based access** (public, author, editor, admin, developer, owner)
115
+ - **Per-collection rules** with validation
116
+ - **Field-level permissions**
117
+ - **Server-side validation**
118
+
119
+ ### Performance
120
+ - **Client-side rendering** with prefetch for SEO
121
+ - **Caching** (configurable per content type)
122
+ - **Optimized builds** with Bun
123
+ - **CDN-ready** static hosting
124
+
125
+ ## Tech Stack
126
+
127
+ - **Frontend**: [tosijs](https://tosijs.net) + [tosijs-ui](https://ui.tosijs.net)
128
+ - **Build**: [Bun](https://bun.sh/) for lightning-fast builds
129
+ - **Backend**: [Firebase](https://firebase.google.com/) (Functions, Firestore, Auth, Storage)
130
+ - **Language**: TypeScript throughout
131
+
132
+ ## Why Blaze Plan is Required
133
+
134
+ tosijs-platform uses **Cloud Functions** to provide a secure REST API for Firestore access. This approach:
135
+ - ✅ **Minimizes client bundle size** (no Firestore SDK in browser)
136
+ - ✅ **Centralized security** (validation and access control on server)
137
+ - ✅ **Fine-grained permissions** (role-based access, field-level filtering)
138
+
139
+ However, Cloud Functions are **only available on Firebase Blaze plan** (pay-as-you-go).
140
+
141
+ **Good news:** Blaze plan includes a generous free tier:
142
+ - 2M function invocations/month
143
+ - 5GB storage
144
+ - 10GB hosting transfer
145
+
146
+ Most small-to-medium sites stay **completely free** within these limits. You only pay for what you use beyond the free tier.
147
+
148
+ ## Prerequisites
149
+
150
+ 1. **Bun** - Install from [bun.sh](https://bun.sh)
151
+ ```bash
152
+ curl -fsSL https://bun.sh/install | bash
153
+ ```
154
+
155
+ 2. **Firebase CLI** - For deployment
156
+ ```bash
157
+ npm install -g firebase-tools
158
+ firebase login
159
+ ```
160
+
161
+ 3. **Firebase Project with Blaze Plan** - Create at [console.firebase.google.com](https://console.firebase.google.com)
162
+ - **REQUIRED: Blaze plan** (pay-as-you-go)
163
+ - tosijs-platform uses Cloud Functions for secure REST API access
164
+ - Free tier does NOT support Cloud Functions - the platform will not work without Blaze
165
+ - Blaze includes generous free tier: 2M function invocations/month, 5GB storage
166
+ - Most small sites stay within free limits
167
+ - Note your **Project ID**
168
+
169
+ ## Installation & Setup
170
+
171
+ ### Step 1: Create Project
172
+
173
+ ```bash
174
+ npx create-tosijs-platform-app my-site
175
+ ```
176
+
177
+ You'll be prompted for:
178
+ - **Firebase Project ID**: Your Firebase project ID (from console)
179
+ - **Admin Email**: Your Google account email (for owner access)
180
+ - **Site Name**: Display name for your site
181
+ - **Site Description**: Meta description
182
+
183
+ ### Step 2: Get Firebase Config
184
+
185
+ 1. Go to [Firebase Console](https://console.firebase.google.com)
186
+ 2. Select your project
187
+ 3. Go to **Project Settings** → **General**
188
+ 4. Scroll to **Your apps** → Add a web app (or use existing)
189
+ 5. Copy the config object
190
+
191
+ ### Step 3: Update Configuration
192
+
193
+ Edit `src/firebase-config.ts` with your Firebase config:
194
+
195
+ ```typescript
196
+ const PROJECT_ID = 'your-project-id'
197
+
198
+ export const config = {
199
+ authDomain: `${PROJECT_ID}.firebaseapp.com`,
200
+ projectId: PROJECT_ID,
201
+ storageBucket: `${PROJECT_ID}.appspot.com`,
202
+ apiKey: 'YOUR_API_KEY',
203
+ messagingSenderId: 'YOUR_SENDER_ID',
204
+ appId: 'YOUR_APP_ID',
205
+ measurementId: 'YOUR_MEASUREMENT_ID',
206
+ }
207
+ ```
208
+
209
+ ### Step 4: Enable Firebase Services
210
+
211
+ In Firebase Console, enable:
212
+
213
+ 1. **Authentication** → Sign-in method → Google (enable)
214
+ 2. **Firestore Database** → Create database (production mode)
215
+ 3. **Storage** → Get started
216
+ 4. **Functions** → (automatically enabled with Blaze plan)
217
+
218
+ ### Step 5: Deploy Functions
219
+
220
+ ```bash
221
+ cd my-site
222
+ bun deploy-functions
223
+ ```
224
+
225
+ Wait for deployment to complete (~2-5 minutes).
226
+
227
+ ### Step 6: Initialize Admin User
228
+
229
+ After functions are deployed, run the setup script:
230
+
231
+ ```bash
232
+ bun setup.js
233
+ ```
234
+
235
+ This creates:
236
+ - Owner role for your admin email
237
+ - Welcome post to get started
238
+
239
+ ### Step 7: Start Development
240
+
241
+ ```bash
242
+ bun start
243
+ ```
244
+
245
+ Visit **https://localhost:8020** and sign in with your admin email.
246
+
247
+ > **Note:** Your browser will warn about the self-signed certificate - this is expected. Click through to proceed.
248
+
249
+ #### Why HTTPS for Local Development?
250
+
251
+ Unlike typical Firebase setups that use HTTP emulators, tosijs-platform uses a custom HTTPS dev server that connects directly to your production Firebase backend. This approach:
252
+
253
+ - **Simplifies development** - no emulator setup or management
254
+ - **Matches production** - test against real data and auth
255
+ - **Enables secure cookies** - Firebase Auth requires HTTPS
256
+ - **Faster startup** - just `bun start`, no emulator spin-up
257
+
258
+ The TLS certificates in `tls/` are generated automatically by `create-tosijs-platform-app`, or you can regenerate them with `./tls/create-dev-certs.sh`.
259
+
260
+ ### Step 8: Deploy Hosting
261
+
262
+ When ready to go live:
263
+
264
+ ```bash
265
+ bun deploy-hosting
266
+ ```
267
+
268
+ Your site will be live at `https://your-project-id.web.app`
269
+
270
+ ## Project Structure
271
+
272
+ ```
273
+ my-site/
274
+ ├── src/ # Client-side code
275
+ │ ├── index.ts # App entry point
276
+ │ ├── app.ts # Global state
277
+ │ ├── blog.ts # Blog component
278
+ │ ├── firebase.ts # Firebase client wrapper
279
+ │ ├── tosi-esm.ts # Dynamic ES module loader component
280
+ │ └── style.ts # Theme & styling
281
+ ├── functions/ # Cloud Functions
282
+ │ ├── src/
283
+ │ │ ├── index.ts # Function exports
284
+ │ │ ├── doc.ts # Document CRUD API
285
+ │ │ ├── docs.ts # Collection query API
286
+ │ │ ├── esm.ts # ES module serving endpoint
287
+ │ │ ├── gen.ts # LLM generation endpoint
288
+ │ │ ├── prefetch.ts # SSR prefetch endpoint
289
+ │ │ ├── blog.ts # Blog collection config
290
+ │ │ ├── module.ts # Module collection config
291
+ │ │ ├── access.ts # Access control system
292
+ │ │ ├── elements.ts # Server-side HTML rendering
293
+ │ │ └── roles.ts # Role definitions
294
+ │ └── shared/ # Shared TypeScript types
295
+ │ ├── module.ts # Module interface
296
+ │ └── page.ts # Page interface
297
+ ├── initial_state/ # Seed data for Firestore
298
+ │ └── firestore/
299
+ │ ├── page.json # Initial pages
300
+ │ └── module.json # Initial modules
301
+ ├── public/ # Static assets
302
+ │ ├── index.html
303
+ │ └── logo.svg
304
+ ├── firebase.json # Firebase config
305
+ ├── firestore.rules # Security rules
306
+ ├── storage.rules # Storage security
307
+ └── dev.ts # Dev server
308
+ ```
309
+
310
+ ## Adding Custom Content Types
311
+
312
+ Define new content types by adding to `COLLECTIONS` in `functions/src/`:
313
+
314
+ ```typescript
315
+ // functions/src/products.ts
316
+ import { COLLECTIONS } from './collections'
317
+ import { ROLES } from './roles'
318
+ import { ALL } from './access'
319
+
320
+ COLLECTIONS.product = {
321
+ unique: ['sku'],
322
+ validate: async (data) => {
323
+ if (!data.name || !data.price) {
324
+ return new Error('Name and price required')
325
+ }
326
+ return data
327
+ },
328
+ access: {
329
+ [ROLES.public]: {
330
+ read: ALL,
331
+ list: ALL,
332
+ },
333
+ [ROLES.admin]: {
334
+ write: ALL,
335
+ }
336
+ }
337
+ }
338
+ ```
339
+
340
+ Then import in `functions/src/index.ts`:
341
+
342
+ ```typescript
343
+ import './products'
344
+ ```
345
+
346
+ ## Customization
347
+
348
+ ### Theme
349
+
350
+ Edit `src/style.ts` to customize colors, fonts, spacing:
351
+
352
+ ```typescript
353
+ export const theme = tosi({
354
+ mode: 'light', // 'light' | 'dark' | 'system'
355
+ colors: {
356
+ primary: '#007acc',
357
+ // ... more colors
358
+ }
359
+ })
360
+ ```
361
+
362
+ ### Content Collections
363
+
364
+ Each content type (blog posts, pages, etc.) is defined in `functions/src/` as a collection config with:
365
+ - **Validation** rules
366
+ - **Unique** field constraints
367
+ - **Access control** per role
368
+ - **Field-level** permissions
369
+
370
+ See `functions/src/blog.ts` for a complete example.
371
+
372
+ ### UI Components
373
+
374
+ Create custom components using tosijs:
375
+
376
+ ```typescript
377
+ import { elements, Component } from 'tosijs'
378
+
379
+ export class MyComponent extends Component {
380
+ content = () => {
381
+ const { div, h1 } = elements
382
+ return div(
383
+ h1('Hello World')
384
+ )
385
+ }
386
+ }
387
+ ```
388
+
389
+ ### Custom Endpoints
390
+
391
+ Create custom Cloud Function endpoints. See `functions/src/hello.ts` for a minimal example:
392
+
393
+ ```typescript
394
+ import { onRequest } from 'firebase-functions/v2/https'
395
+ import compression from 'compression'
396
+ import { optionsResponse, getUserRoles } from './utilities'
397
+
398
+ const compressResponse = compression()
399
+
400
+ export const myEndpoint = onRequest({}, async (req, res) => {
401
+ // Handle CORS preflight
402
+ if (optionsResponse(req, res)) {
403
+ return
404
+ }
405
+
406
+ // Get authenticated user's roles
407
+ const userRoles = await getUserRoles(req)
408
+
409
+ // Your logic here
410
+ compressResponse(req, res, () => {
411
+ res.json({ message: 'Hello!', roles: userRoles.roles })
412
+ })
413
+ })
414
+ ```
415
+
416
+ Then export in `functions/src/index.ts`:
417
+
418
+ ```typescript
419
+ export { myEndpoint } from './my-endpoint'
420
+ ```
421
+
422
+ For endpoints using secrets (API keys), see `functions/src/gen.ts` which demonstrates the `defineSecret` pattern.
423
+
424
+ ## Development Commands
425
+
426
+ ```bash
427
+ bun start # Start dev server (https://localhost:8020)
428
+ bun start-emulated # Start with Firebase emulators
429
+ bun seed # Seed emulators with initial_state data
430
+ bun seed-clear # Clear emulators and reseed
431
+ bun deploy-functions # Deploy Cloud Functions
432
+ bun deploy-hosting # Deploy static hosting
433
+ bun format # Format code with Prettier
434
+ bun latest # Update all dependencies
435
+ ```
436
+
437
+ ### Using Emulators
438
+
439
+ For isolated development without affecting production data:
440
+
441
+ ```bash
442
+ # Start emulators and dev server
443
+ bun start-emulated
444
+
445
+ # In another terminal, seed with initial data
446
+ bun seed
447
+ ```
448
+
449
+ The emulators provide local Firestore, Auth, Storage, and Functions. Data is seeded from `initial_state/firestore/`.
450
+
451
+ ## Secrets Management
452
+
453
+ For API keys (e.g., Gemini, OpenAI, Stripe), use Firebase Secret Manager (required for v2 functions):
454
+
455
+ ```bash
456
+ firebase functions:secrets:set OPENAI_API_KEY
457
+ ```
458
+
459
+ Access in functions:
460
+
461
+ ```typescript
462
+ import { defineSecret } from 'firebase-functions/params'
463
+
464
+ const openaiKey = defineSecret('OPENAI_API_KEY')
465
+
466
+ export const myFunction = onRequest(
467
+ { secrets: [openaiKey] },
468
+ async (req, res) => {
469
+ const key = openaiKey.value()
470
+ // use key...
471
+ }
472
+ )
473
+ ```
474
+
475
+ ## User Management
476
+
477
+ Users are managed via the `user` collection in Firestore. Roles are assigned per user:
478
+
479
+ ```typescript
480
+ // In Firestore console or via code:
481
+ collection('user').doc(userId).set({
482
+ email: 'user@example.com',
483
+ roles: ['author'], // 'public', 'author', 'editor', 'admin', 'developer', 'owner'
484
+ })
485
+ ```
486
+
487
+ ## Deployment Checklist
488
+
489
+ - [ ] Firebase config updated in `src/firebase-config.ts`
490
+ - [ ] Google Auth enabled in Firebase Console
491
+ - [ ] Firestore Database created
492
+ - [ ] Cloud Storage enabled
493
+ - [ ] Functions deployed (`bun deploy-functions`)
494
+ - [ ] Admin user created (`bun setup.js`)
495
+ - [ ] Local dev working (`bun start`)
496
+ - [ ] Hosting deployed (`bun deploy-hosting`)
497
+ - [ ] Custom domain configured (optional)
498
+
499
+ ## Troubleshooting
500
+
501
+ ### "Firebase CLI not found"
502
+ ```bash
503
+ npm install -g firebase-tools
504
+ ```
505
+
506
+ ### "Not logged in to Firebase"
507
+ ```bash
508
+ firebase login
509
+ ```
510
+
511
+ ### "Functions deployment failed"
512
+ - Check Firebase project has Blaze plan enabled
513
+ - Verify `.firebaserc` has correct project ID
514
+
515
+ ### "Permission denied" errors
516
+ - Make sure admin user exists in `user` collection
517
+ - Check `roles` array includes 'owner' or 'admin'
518
+
519
+ ### "CORS errors" in development
520
+ - The dev server uses HTTPS (required for Firebase)
521
+ - Accept the self-signed certificate in your browser
522
+
523
+ ## Performance Tips
524
+
525
+ 1. **Limit Firestore reads**: Use caching and prefetch
526
+ 2. **Optimize images**: Compress before uploading
527
+ 3. **Use Cloud CDN**: Firebase Hosting includes CDN
528
+ 4. **Monitor costs**: Check Firebase usage dashboard
529
+
530
+ ## Contributing
531
+
532
+ Issues and PRs welcome at [github.com/tonioloewald/tosijs-platform](https://github.com/tonioloewald/tosijs-platform)
533
+
534
+ ## License
535
+
536
+ MIT © Tonio Loewald
537
+
538
+ ## Learn More
539
+
540
+ - [tosijs Documentation](https://tosijs.net) - State management and components (includes AI context)
541
+ - [tosijs-ui Components](https://ui.tosijs.net) - UI component library with live examples
542
+ - [Firebase Documentation](https://firebase.google.com/docs)
543
+ - [Bun Documentation](https://bun.sh/docs)
544
+
545
+ ## Platform Documentation
546
+
547
+ - **[Firestore REST API & Security](docs/FIRESTORE_API.md)** - How the REST endpoints work, access control, validation
548
+ - **[ES Modules](docs/ESM_MODULES.md)** - Dynamic code loading via `/esm` endpoint
549
+ - **[LLM Generation](docs/GEN_ENDPOINT.md)** - `/gen` endpoint for Gemini/ChatGPT text generation
550
+ - **[Blog Component](docs/BLOG_COMPONENT.md)** - Built-in blog system, editing, publishing
551
+ - **[Page Component](docs/PAGE_COMPONENT.md)** - Generic content renderer, static pages
552
+ - **[Prefetch & SEO](docs/PREFETCH.md)** - Server-side rendering, meta tags, social media previews
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "tosijs-platform",
3
+ "version": "1.0.0",
4
+ "description": "Full-stack web application platform - Firebase + tosijs, simpler than PHP/LAMP",
5
+ "keywords": [
6
+ "tosijs",
7
+ "firebase",
8
+ "cms",
9
+ "blog",
10
+ "platform",
11
+ "full-stack"
12
+ ],
13
+ "homepage": "https://github.com/tonioloewald/tosijs-platform",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/tonioloewald/tosijs-platform.git"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Tonio Loewald",
20
+ "type": "module",
21
+ "files": [
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "scripts": {
26
+ "start": "bun --watch dev.ts",
27
+ "kill-ports": "lsof -ti:4000,5001,5002,8080,9099,9199 | xargs kill -9 2>/dev/null || true",
28
+ "start-emulated": "bun run kill-ports && bun run build && (cd functions && bun run build) && bun bin/start-emulated.js",
29
+ "seed": "bun bin/seed-emulators.js",
30
+ "seed-clear": "bun bin/seed-emulators.js --clear",
31
+ "build": "bun build ./src/index.ts --outdir ./dist --sourcemap=linked --minify && cp -a public/. dist/ && rm dist/index.html",
32
+ "format": "bun prettier --write src functions/src",
33
+ "latest": "bun upgrade && bun install && cd functions && npm install && cd ..",
34
+ "deploy-hosting": "firebase deploy --only hosting && echo 'deployed hosting'",
35
+ "deploy-functions": "firebase deploy --only functions && echo 'deployed functions'"
36
+ },
37
+ "devDependencies": {
38
+ "@types/bun": "^1.3.5",
39
+ "@types/marked": "^5.0.2",
40
+ "@types/turndown": "^5.0.6",
41
+ "@types/web": "^0.0.99",
42
+ "bun-types": "canary",
43
+ "chokidar": "^3.6.0",
44
+ "http-server": "^14.1.1",
45
+ "marked": "^16.4.2",
46
+ "prettier": "^2.8.8",
47
+ "tosijs": "^1.0.10",
48
+ "tosijs-schema": "^1.0.3",
49
+ "tosijs-ui": "^1.0.10",
50
+ "typescript": "^5.9.3"
51
+ },
52
+ "dependencies": {
53
+ "firebase": "^12.7.0",
54
+ "turndown": "^7.2.2"
55
+ }
56
+ }