@helloleo/plugins 0.2.13 → 0.2.14
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/dist/index.js +2 -1
- package/dist/templates/tanstack-start-2026-07-30/src/lib/kv.ts +37 -0
- package/dist/templates/tanstack-start-2026-07-30/src/lib/storage.ts +44 -0
- package/package.json +1 -1
- package/src/templates/tanstack-start-2026-07-30/src/lib/kv.ts +37 -0
- package/src/templates/tanstack-start-2026-07-30/src/lib/storage.ts +44 -0
- package/src/tools/scaffold.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -24955,7 +24955,8 @@ var scaffold = tool({
|
|
|
24955
24955
|
const typeNotes = isStart ? [
|
|
24956
24956
|
"- This is a TanStack Start project. The server entry is src/server.ts. There is no index.html or client entrypoint.",
|
|
24957
24957
|
"- For JSON/CRUD APIs, add server routes under src/routes/api/. Read src/routes/api/health.ts first, add routes as needed.",
|
|
24958
|
-
"- The database schema lives in src/db/schema.ts and is the single source of truth. Migration files under drizzle/ are generated and applied automatically. Never create, edit or delete them. Prefer adding new columns/tables over renaming existing ones."
|
|
24958
|
+
"- The database schema lives in src/db/schema.ts and is the single source of truth. Migration files under drizzle/ are generated and applied automatically. Never create, edit or delete them. Prefer adding new columns/tables over renaming existing ones.",
|
|
24959
|
+
"- Persistence goes through @helloleo/runtime exclusively: database via #/db (see src/db/index.ts), key-value store via #/lib/kv (see src/lib/kv.ts), file storage + presigned browser uploads via #/lib/storage (see src/lib/storage.ts), env/secrets via env from @helloleo/runtime. Read those files before server-side data work. Never install another DB/storage client, never import from cloudflare:workers, all of it is server-side only."
|
|
24959
24960
|
] : [
|
|
24960
24961
|
"- This is a TanStack Router SPA. The client entry is index.html -> src/main.tsx. There is no server: no API routes, no server functions, no database.",
|
|
24961
24962
|
"- Fetch data from external APIs only. If the app needs its own persistence or server-side code, it should have been scaffolded as tanstack-start."
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { kv } from '@helloleo/runtime'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Key-value store — @helloleo/runtime `kv`. Use this file as the base for
|
|
5
|
+
* caches, sessions, counters and flags. Same import in dev and production;
|
|
6
|
+
* never install redis/ioredis or branch on environment.
|
|
7
|
+
*
|
|
8
|
+
* The raw contract (values are ALWAYS strings):
|
|
9
|
+
*
|
|
10
|
+
* await kv.put('session:abc', value, { expirationTtl: 3600 }) // ttl in seconds, optional
|
|
11
|
+
* await kv.get('session:abc') // string | null
|
|
12
|
+
* await kv.delete('session:abc')
|
|
13
|
+
* await kv.list({ prefix: 'session:', limit: 100 }) // { keys, cursor, listComplete }
|
|
14
|
+
*
|
|
15
|
+
* Rules:
|
|
16
|
+
* - Server-side only (route handlers, loaders, server functions) — the
|
|
17
|
+
* binding does not exist in the browser or at app module scope.
|
|
18
|
+
* - KV is for small, hot values. Relational data belongs in the database
|
|
19
|
+
* (`#/db`); files belong in storage (`#/lib/storage`).
|
|
20
|
+
* - Keys are flat strings — namespace with prefixes ('cache:', 'session:').
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** JSON convenience wrappers — kv stores strings, most values are objects. */
|
|
24
|
+
export async function kvGetJson<T>(key: string): Promise<T | null> {
|
|
25
|
+
const raw = await kv.get(key)
|
|
26
|
+
return raw === null ? null : (JSON.parse(raw) as T)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function kvPutJson(
|
|
30
|
+
key: string,
|
|
31
|
+
value: unknown,
|
|
32
|
+
opts?: { expirationTtl?: number },
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
await kv.put(key, JSON.stringify(value), opts)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { kv }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { storage } from '@helloleo/runtime'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* File/object storage — @helloleo/runtime `storage`. Use this file as the
|
|
5
|
+
* base for uploads, images, exports and any binary data. Same import in dev
|
|
6
|
+
* and production; never install @aws-sdk/*, multer, or use node:fs.
|
|
7
|
+
*
|
|
8
|
+
* The raw contract:
|
|
9
|
+
*
|
|
10
|
+
* await storage.put('avatars/u1.png', bytes, { contentType: 'image/png' })
|
|
11
|
+
* await storage.get('avatars/u1.png') // { body: ReadableStream, size, contentType } | null
|
|
12
|
+
* await storage.head('avatars/u1.png') // { size, contentType } | null
|
|
13
|
+
* await storage.delete('avatars/u1.png')
|
|
14
|
+
* await storage.list({ prefix: 'avatars/', limit: 100 }) // { keys: [{ key, size }], cursor }
|
|
15
|
+
*
|
|
16
|
+
* Rules:
|
|
17
|
+
* - Server-side only (route handlers, loaders, server functions).
|
|
18
|
+
* - Browser uploads/downloads go through PRESIGNED URLS (below) — never
|
|
19
|
+
* stream file bytes through your own API route when a presigned URL works:
|
|
20
|
+
* the browser talks to storage directly.
|
|
21
|
+
* - Key layout is up to the app — namespace with prefixes ('avatars/',
|
|
22
|
+
* 'exports/').
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Presign an upload: the server hands the browser a short-lived URL it can
|
|
27
|
+
* `fetch(url, { method: 'PUT', body: file })` to directly. Pair with a DB row
|
|
28
|
+
* that records the key.
|
|
29
|
+
*/
|
|
30
|
+
export function getUploadUrl(
|
|
31
|
+
key: string,
|
|
32
|
+
opts?: { ttlSeconds?: number; contentType?: string },
|
|
33
|
+
): Promise<string> {
|
|
34
|
+
return storage.presignPut(key, opts?.ttlSeconds ?? 600, {
|
|
35
|
+
contentType: opts?.contentType,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Presign a download — short-lived direct GET URL for the browser. */
|
|
40
|
+
export function getDownloadUrl(key: string, ttlSeconds = 600): Promise<string> {
|
|
41
|
+
return storage.presignGet(key, ttlSeconds)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { storage }
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { kv } from '@helloleo/runtime'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Key-value store — @helloleo/runtime `kv`. Use this file as the base for
|
|
5
|
+
* caches, sessions, counters and flags. Same import in dev and production;
|
|
6
|
+
* never install redis/ioredis or branch on environment.
|
|
7
|
+
*
|
|
8
|
+
* The raw contract (values are ALWAYS strings):
|
|
9
|
+
*
|
|
10
|
+
* await kv.put('session:abc', value, { expirationTtl: 3600 }) // ttl in seconds, optional
|
|
11
|
+
* await kv.get('session:abc') // string | null
|
|
12
|
+
* await kv.delete('session:abc')
|
|
13
|
+
* await kv.list({ prefix: 'session:', limit: 100 }) // { keys, cursor, listComplete }
|
|
14
|
+
*
|
|
15
|
+
* Rules:
|
|
16
|
+
* - Server-side only (route handlers, loaders, server functions) — the
|
|
17
|
+
* binding does not exist in the browser or at app module scope.
|
|
18
|
+
* - KV is for small, hot values. Relational data belongs in the database
|
|
19
|
+
* (`#/db`); files belong in storage (`#/lib/storage`).
|
|
20
|
+
* - Keys are flat strings — namespace with prefixes ('cache:', 'session:').
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** JSON convenience wrappers — kv stores strings, most values are objects. */
|
|
24
|
+
export async function kvGetJson<T>(key: string): Promise<T | null> {
|
|
25
|
+
const raw = await kv.get(key)
|
|
26
|
+
return raw === null ? null : (JSON.parse(raw) as T)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function kvPutJson(
|
|
30
|
+
key: string,
|
|
31
|
+
value: unknown,
|
|
32
|
+
opts?: { expirationTtl?: number },
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
await kv.put(key, JSON.stringify(value), opts)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { kv }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { storage } from '@helloleo/runtime'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* File/object storage — @helloleo/runtime `storage`. Use this file as the
|
|
5
|
+
* base for uploads, images, exports and any binary data. Same import in dev
|
|
6
|
+
* and production; never install @aws-sdk/*, multer, or use node:fs.
|
|
7
|
+
*
|
|
8
|
+
* The raw contract:
|
|
9
|
+
*
|
|
10
|
+
* await storage.put('avatars/u1.png', bytes, { contentType: 'image/png' })
|
|
11
|
+
* await storage.get('avatars/u1.png') // { body: ReadableStream, size, contentType } | null
|
|
12
|
+
* await storage.head('avatars/u1.png') // { size, contentType } | null
|
|
13
|
+
* await storage.delete('avatars/u1.png')
|
|
14
|
+
* await storage.list({ prefix: 'avatars/', limit: 100 }) // { keys: [{ key, size }], cursor }
|
|
15
|
+
*
|
|
16
|
+
* Rules:
|
|
17
|
+
* - Server-side only (route handlers, loaders, server functions).
|
|
18
|
+
* - Browser uploads/downloads go through PRESIGNED URLS (below) — never
|
|
19
|
+
* stream file bytes through your own API route when a presigned URL works:
|
|
20
|
+
* the browser talks to storage directly.
|
|
21
|
+
* - Key layout is up to the app — namespace with prefixes ('avatars/',
|
|
22
|
+
* 'exports/').
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Presign an upload: the server hands the browser a short-lived URL it can
|
|
27
|
+
* `fetch(url, { method: 'PUT', body: file })` to directly. Pair with a DB row
|
|
28
|
+
* that records the key.
|
|
29
|
+
*/
|
|
30
|
+
export function getUploadUrl(
|
|
31
|
+
key: string,
|
|
32
|
+
opts?: { ttlSeconds?: number; contentType?: string },
|
|
33
|
+
): Promise<string> {
|
|
34
|
+
return storage.presignPut(key, opts?.ttlSeconds ?? 600, {
|
|
35
|
+
contentType: opts?.contentType,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Presign a download — short-lived direct GET URL for the browser. */
|
|
40
|
+
export function getDownloadUrl(key: string, ttlSeconds = 600): Promise<string> {
|
|
41
|
+
return storage.presignGet(key, ttlSeconds)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { storage }
|
package/src/tools/scaffold.ts
CHANGED
|
@@ -153,6 +153,7 @@ export const scaffold = tool({
|
|
|
153
153
|
"- This is a TanStack Start project. The server entry is src/server.ts. There is no index.html or client entrypoint.",
|
|
154
154
|
"- For JSON/CRUD APIs, add server routes under src/routes/api/. Read src/routes/api/health.ts first, add routes as needed.",
|
|
155
155
|
"- The database schema lives in src/db/schema.ts and is the single source of truth. Migration files under drizzle/ are generated and applied automatically. Never create, edit or delete them. Prefer adding new columns/tables over renaming existing ones.",
|
|
156
|
+
"- Persistence goes through @helloleo/runtime exclusively: database via #/db (see src/db/index.ts), key-value store via #/lib/kv (see src/lib/kv.ts), file storage + presigned browser uploads via #/lib/storage (see src/lib/storage.ts), env/secrets via env from @helloleo/runtime. Read those files before server-side data work. Never install another DB/storage client, never import from cloudflare:workers, all of it is server-side only.",
|
|
156
157
|
]
|
|
157
158
|
: [
|
|
158
159
|
"- This is a TanStack Router SPA. The client entry is index.html -> src/main.tsx. There is no server: no API routes, no server functions, no database.",
|