nurev 0.0.9 → 0.1.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
@@ -12,6 +12,8 @@ Template generator for [Nuxt](https://nuxt.com/) configured with “on-demand re
12
12
 
13
13
  ## How to use it?
14
14
 
15
+ 1. Run the script
16
+
15
17
  ```bash
16
18
  bunx nurev
17
19
  ```
@@ -23,3 +25,53 @@ npx nurev
23
25
  ```bash
24
26
  pnpm dlx nurev
25
27
  ```
28
+
29
+ 2. After the script completes, start the backend in dev mode
30
+
31
+ ```bash
32
+ make backend-dev
33
+ ```
34
+
35
+ 3. Then start frontend in dev mode
36
+
37
+ ```bash
38
+ make frontend-dev
39
+ ```
40
+
41
+ ## How it works?
42
+
43
+ 1. **Interactive prompts**: Asks you to choose a package manager (`bun`, `npm`, or `pnpm`) and a backend (`PocketBase`)
44
+ 2. **Template copying**: Copies the base Nuxt template, backend-specific files, and package-manager-specific configuration to your current directory
45
+ 3. **Installation & setup**: Runs `make install` to install dependencies and `make setup` to initialize the project
46
+ 4. **Backend configuration**: Applies backend-specific setup (e.g., PocketBase configuration)
47
+ 5. **Ready to use**: Your Nuxt project with on-demand revalidation is ready
48
+
49
+ ## On-Demand Revalidation
50
+
51
+ The caching system uses a webhook pattern between PocketBase and Nuxt:
52
+
53
+ 1. **Cache storage**: Nuxt routes use `defineCachedEventHandler` with `swr: true` (stale-while-revalidate) and `maxAge: 604800` (1 week). Route rules set `prerender: true` for `/` and `swr: true` for `/posts/**`
54
+
55
+ 2. **Backend hooks**: Backend (PocketBase) registers hooks on `OnRecordAfterCreateSuccess`, `OnRecordAfterUpdateSuccess`, `OnRecordAfterDeleteSuccess`, `OnBackupCreate` and `OnBackupRestore` for collections defined in `TABLES_TRIGGER`
56
+
57
+ 3. **Webhook notification**: When a record changes, PocketBase sends an authenticated POST (JWT Bearer token) to `/api/private/reloadcache` with the table name and record ID
58
+
59
+ 4. **Selective invalidation**: The Nuxt endpoint validates the JWT and uses `useStorage("cache")` to remove only cache entries matching the changed table and record ID. Backup events trigger a full cache clear
60
+
61
+ 5. **Next request**: Subsequent requests fetch fresh data and repopulate the cache
62
+
63
+ ## Pros and Cons
64
+
65
+ ### Pros
66
+
67
+ - ⚡ **Performance**: Cached responses are served instantly without hitting the database on each request
68
+ - 📉 **Reduced backend load**: Fewer API calls to PocketBase, lowering server resource usage
69
+ - 🔄 **Fresh data on demand**: Cache is invalidated only when data actually changes, avoiding stale content
70
+ - 🚀 **Scalability**: SWR (stale-while-revalidate) serves cached content while refreshing in the background, keeping response times low under high traffic
71
+
72
+ ### Cons
73
+
74
+ - 🔗 **Tight coupling**: The backend must know the frontend URL and send webhooks, creating a dependency between services
75
+ - 🌐 **Network reliability**: If the webhook fails to reach Nuxt (network issues, downtime), the cache won't be invalidated and stale data persists
76
+ - 🖥️ **Single-server limitation**: Cache is stored in-memory/local storage, so this approach doesn't work well with multi-instance deployments without a shared cache layer (e.g., Redis)
77
+ - ⚙️ **Complexity**: Requires configuring JWT secrets, environment variables, and ensuring both services are running and communicating correctly
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nurev",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "module": "index.js",
5
5
  "dependencies": {
6
6
  "bcrypt": "^6.0.0",
@@ -7,7 +7,10 @@ export default defineNitroPlugin(async (nitroApp) => {
7
7
  try {
8
8
  await pb
9
9
  .collection("users")
10
- .authWithPassword(config.pocketbaseUser, config.pocketbasePassword);
10
+ .authWithPassword(
11
+ config.pocketbaseUser,
12
+ config.pocketbasePassword.toString(),
13
+ );
11
14
 
12
15
  nitroApp.hooks.hook("request", (event) => {
13
16
  event.context.pocketbase = pb;
@@ -1,7 +1,7 @@
1
1
  TABLES_TRIGGER=posts
2
2
  JWT_EXPIRES_MINUTES=1
3
3
  FRONTEND_URL=http://localhost:3000/api/private/reloadcache
4
- NUXT_POCKETBASE_URL=https://localhost:8090
4
+ NUXT_POCKETBASE_URL=http://localhost:8090
5
5
  NUXT_POCKETBASE_USER=
6
6
  NUXT_POCKETBASE_PASSWORD=
7
7
  NUXT_JWT_SECRET=
@@ -53,20 +53,20 @@ Tech stack:
53
53
  make backend-dev
54
54
  ```
55
55
 
56
- 3. Create a collection named `posts` and change API Rules for give permissions with `@request.auth.id != ""`
57
-
58
- 4. Create a new post
59
-
60
- 5. Start frontend dev mode
56
+ 3. Start frontend dev mode
61
57
 
62
58
  ```bash
63
59
  make frontend-dev
64
60
  ```
65
61
 
66
- 6. Open `http://localhost:3000/posts/[id]` and replace `[id]` with the post id created in the 6. step
62
+ 4. Copy a post ID from the `posts` collection
63
+
64
+ 5. Open `http://localhost:3000/posts/[id]` and replace `[id]` with the copied post ID
65
+
66
+ 6. Verify caching by checking the `ETag` header in the response (Network tab in browser dev tools). The `ETag` will change when you modify post records or create a backup
67
67
 
68
- ## Build
68
+ ## More commands
69
69
 
70
70
  ```bash
71
- make build
71
+ make help
72
72
  ```
@@ -38,19 +38,19 @@ frontend-setup:
38
38
 
39
39
  frontend-install:
40
40
  @echo "Installing frontend dependencies..."
41
- cd frontend && bun --bun install
41
+ cd frontend && bun install
42
42
 
43
43
  frontend-dev: frontend-install
44
44
  @echo "Starting frontend development server..."
45
- cd frontend && bun --bun run dev
45
+ cd frontend && bun run dev
46
46
 
47
47
  frontend-build: frontend-install
48
48
  @echo "Building frontend for production..."
49
- cd frontend && bun --bun run build
49
+ cd frontend && bun run build
50
50
 
51
51
  frontend-preview: frontend-build
52
52
  @echo "Previewing frontend production build..."
53
- cd frontend && bun --bun run preview
53
+ cd frontend && bun run preview
54
54
 
55
55
  install: backend-update frontend-install
56
56
  @echo "Dependencies installed"
package/utils/sqlite.js CHANGED
@@ -9,7 +9,7 @@ export class SQLiteManager {
9
9
  return new Promise(async (resolve, reject) => {
10
10
  try {
11
11
  this.db.exec(
12
- `CREATE TABLE IF NOT EXIST ${name} (${params.toString()})`,
12
+ `CREATE TABLE IF NOT EXISTS ${name} (${params.toString()})`,
13
13
  );
14
14
  resolve();
15
15
  } catch (error) {
@@ -77,7 +77,32 @@ export function setup(paths) {
77
77
 
78
78
  console.log(`\nUser API created\n`);
79
79
 
80
- //TODO: POSTS TABLE
80
+ await db.insert("_collections", {
81
+ created: `'${date}'`,
82
+ fields: `'[{"autogeneratePattern":"[a-z0-9]{15}","hidden":false,"id":"text3208210256","max":15,"min":15,"name":"id","pattern":"^[a-z0-9]+$","presentable":false,"primaryKey":true,"required":true,"system":true,"type":"text"},{"hidden":false,"id":"autodate2990389176","name":"created","onCreate":true,"onUpdate":false,"presentable":false,"system":false,"type":"autodate"},{"hidden":false,"id":"autodate3332085495","name":"updated","onCreate":true,"onUpdate":true,"presentable":false,"system":false,"type":"autodate"}]'`,
83
+ indexes: `'[]'`,
84
+ name: `'posts'`,
85
+ options: `'{}'`,
86
+ system: false,
87
+ updated: `'${date}'`,
88
+ type: `'base'`,
89
+ listRule: `'@request.auth.id != ""'`,
90
+ viewRule: `'@request.auth.id != ""'`,
91
+ });
92
+
93
+ await db.create("posts", [
94
+ `created TEXT DEFAULT '' NOT NULL`,
95
+ `id TEXT PRIMARY KEY DEFAULT ('r'||lower(hex(randomblob(7)))) NOT NULL`,
96
+ `updated TEXT DEFAULT '' NOT NULL`,
97
+ ]);
98
+
99
+ await db.insert("posts", {
100
+ created: `'${date}'`,
101
+ updated: `'${date}'`,
102
+ });
103
+
104
+ console.log(`\nPosts example created\n`);
105
+
81
106
  resolve();
82
107
  } catch (error) {
83
108
  reject(error);