@liquidmetal-ai/raindrop 0.13.0 → 0.15.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 +327 -89
- package/bundle/build-CBEGQPJT.js +62 -0
- package/bundle/{chunk-IEF2XC25.js → chunk-2PH3PHH3.js} +5 -3
- package/bundle/{chunk-4HZ22KOV.js → chunk-3CMR7ES5.js} +4 -4
- package/bundle/{chunk-JSBM2JYW.js → chunk-3EYKCHIK.js} +1 -1
- package/bundle/chunk-5XHDP4VK.js +1697 -0
- package/bundle/{chunk-TSQK4HH6.js → chunk-674GMSXY.js} +1 -1
- package/bundle/{chunk-PS3WZBDF.js → chunk-6L4V66WZ.js} +1105 -2728
- package/bundle/{chunk-5245CEUM.js → chunk-AGG7JZVH.js} +2 -2
- package/bundle/{chunk-3GFKUF5D.js → chunk-B3IY2XS6.js} +4 -2
- package/bundle/{chunk-WIDI65NO.js → chunk-CBAXTRCS.js} +1 -1
- package/bundle/{chunk-JLVDTXO2.js → chunk-DPV5HIG7.js} +4 -4
- package/bundle/{chunk-36GNZK4A.js → chunk-EVXLXWP7.js} +1 -1
- package/bundle/{chunk-4YVU5KEQ.js → chunk-HN3AAKRY.js} +4 -2
- package/bundle/{chunk-NVNEQXHN.js → chunk-IGLE4Y3B.js} +7 -5
- package/bundle/{chunk-FGSYWVBA.js → chunk-IQ6HFRA6.js} +1 -1
- package/bundle/{chunk-O3QZDJ75.js → chunk-JQONDSHY.js} +2 -2
- package/bundle/{chunk-W4IPOFZC.js → chunk-KADMFJLN.js} +8 -6
- package/bundle/chunk-KG5BLUGU.js +246 -0
- package/bundle/{chunk-V5LHJTYS.js → chunk-KLOYSTZY.js} +13 -2
- package/bundle/{chunk-ETC5VU7H.js → chunk-KXHVSLAI.js} +1 -1
- package/bundle/{chunk-Y4WFGNPM.js → chunk-L6FRQULN.js} +1 -1
- package/bundle/{chunk-3QCVYSRU.js → chunk-LT3BFQ4O.js} +1 -1
- package/bundle/{chunk-KQZJHBNG.js → chunk-MBLKVNI5.js} +1 -1
- package/bundle/{chunk-6AIUQUUM.js → chunk-MFMVJZW6.js} +71 -15
- package/bundle/{chunk-25T7MEKO.js → chunk-MJBLNWG3.js} +1 -1
- package/bundle/{chunk-MSJ33O5Y.js → chunk-NRCQIE3Z.js} +95 -115
- package/bundle/{chunk-XKKPPSPC.js → chunk-OCYTN4IH.js} +2 -2
- package/bundle/{chunk-2GAMWFJE.js → chunk-QEF5D4VE.js} +1 -1
- package/bundle/{chunk-4B3QYXBA.js → chunk-T7MQCLXF.js} +5 -3
- package/bundle/{chunk-LDFYPOXJ.js → chunk-TFQY5TSY.js} +1 -1
- package/bundle/{chunk-BWK4MC7Y.js → chunk-USZXZZAR.js} +8 -6
- package/bundle/{chunk-ER2RCPCY.js → chunk-V54KHS5B.js} +2 -2
- package/bundle/{chunk-YSKASURB.js → chunk-V6J23FL2.js} +1 -1
- package/bundle/{chunk-UHSTDJ7X.js → chunk-VN2QYX4C.js} +1 -1
- package/bundle/{chunk-Z4OWKG7J.js → chunk-VOT5MMEY.js} +1 -1
- package/bundle/{chunk-W6GU26WO.js → chunk-WG6BDFPZ.js} +1 -1
- package/bundle/{chunk-AK77X5GL.js → chunk-XX74I5RK.js} +4 -2
- package/bundle/{chunk-6BT265R3.js → chunk-YQCRWPNI.js} +1 -1
- package/bundle/commands/annotation/get.js +3 -3
- package/bundle/commands/annotation/list.js +3 -3
- package/bundle/commands/annotation/put.js +3 -3
- package/bundle/commands/auth/apikey.js +2 -2
- package/bundle/commands/auth/list.js +2 -2
- package/bundle/commands/auth/login.js +2 -2
- package/bundle/commands/auth/logout.js +2 -2
- package/bundle/commands/auth/select.js +3 -3
- package/bundle/commands/bucket/create-credential.js +2 -2
- package/bundle/commands/bucket/delete-credential.js +2 -2
- package/bundle/commands/bucket/get-credential.js +2 -2
- package/bundle/commands/bucket/list-credentials.js +2 -2
- package/bundle/commands/build/actor/setup.js +124 -0
- package/bundle/commands/build/branch.js +10 -10
- package/bundle/commands/build/bucket-events/setup.js +146 -0
- package/bundle/commands/build/checkout.js +8 -8
- package/bundle/commands/build/clone.js +6 -6
- package/bundle/commands/build/delete.js +8 -8
- package/bundle/commands/build/deploy.js +10 -10
- package/bundle/commands/build/env/get.js +3 -3
- package/bundle/commands/build/env/list.js +2 -2
- package/bundle/commands/build/env/set.js +3 -3
- package/bundle/commands/build/env.js +2 -2
- package/bundle/commands/build/features.js +192 -0
- package/bundle/commands/build/find.js +4 -4
- package/bundle/commands/build/generate.js +52 -3
- package/bundle/commands/build/init-workspace.js +3 -3
- package/bundle/commands/build/init.js +15 -3
- package/bundle/commands/build/list.js +5 -5
- package/bundle/commands/build/queue/setup.js +133 -0
- package/bundle/commands/build/sandbox.js +6 -6
- package/bundle/commands/build/smartbucket/setup.js +165 -0
- package/bundle/commands/build/smartmemory/setup.js +171 -0
- package/bundle/commands/build/smartsql/setup.js +167 -0
- package/bundle/commands/build/start.js +2 -2
- package/bundle/commands/build/status.js +5 -5
- package/bundle/commands/build/stop.js +2 -2
- package/bundle/commands/build/stripe/dashboard.js +3 -3
- package/bundle/commands/build/stripe/onboard.js +3 -3
- package/bundle/commands/build/stripe/setup.js +3 -3
- package/bundle/commands/build/stripe/start.js +14 -14
- package/bundle/commands/build/stripe/status.js +3 -3
- package/bundle/commands/build/stripe/subscription/create.js +4 -4
- package/bundle/commands/build/stripe/subscription/get.js +4 -4
- package/bundle/commands/build/stripe/subscription/update.js +4 -4
- package/bundle/commands/build/tools/check.js +2 -2
- package/bundle/commands/build/tools/fmt.js +2 -2
- package/bundle/commands/build/unsandbox.js +6 -6
- package/bundle/commands/build/upload.js +5 -5
- package/bundle/commands/build/validate.js +85 -14
- package/bundle/commands/build/workos/delete.js +6 -6
- package/bundle/commands/build/workos/env/attach.js +3 -3
- package/bundle/commands/build/workos/env/attached.js +3 -3
- package/bundle/commands/build/workos/env/create.js +3 -3
- package/bundle/commands/build/workos/env/delete.js +3 -3
- package/bundle/commands/build/workos/env/detach.js +3 -3
- package/bundle/commands/build/workos/env/dev-login.js +3 -3
- package/bundle/commands/build/workos/env/get.js +3 -3
- package/bundle/commands/build/workos/env/list.js +3 -3
- package/bundle/commands/build/workos/env/set.js +3 -3
- package/bundle/commands/build/workos/invite.js +3 -3
- package/bundle/commands/build/workos/jwt.js +172 -0
- package/bundle/commands/build/workos/setup.js +3 -3
- package/bundle/commands/build/workos/status.js +3 -3
- package/bundle/commands/dns/create.js +2 -2
- package/bundle/commands/dns/delete.js +6 -6
- package/bundle/commands/dns/get.js +6 -6
- package/bundle/commands/dns/list.js +3 -3
- package/bundle/commands/dns/records/create.js +2 -2
- package/bundle/commands/dns/records/delete.js +3 -3
- package/bundle/commands/dns/records/get.js +2 -2
- package/bundle/commands/dns/records/list.js +2 -2
- package/bundle/commands/dns/records/update.js +2 -2
- package/bundle/commands/doctor.js +309 -0
- package/bundle/commands/logs/query.js +3 -3
- package/bundle/commands/logs/tail.js +3 -3
- package/bundle/commands/mcp/install-claude.js +2 -2
- package/bundle/commands/mcp/install-gemini.js +2 -2
- package/bundle/commands/mcp/install-goose.js +2 -2
- package/bundle/commands/mcp/status.js +2 -2
- package/bundle/commands/object/delete.js +5 -37
- package/bundle/commands/object/get.js +5 -37
- package/bundle/commands/object/list.js +7 -39
- package/bundle/commands/object/put.js +5 -37
- package/bundle/commands/query/chunk-search.js +14 -46
- package/bundle/commands/query/document.js +17 -55
- package/bundle/commands/query/events.js +2 -2
- package/bundle/commands/query/reindex.js +2 -2
- package/bundle/commands/query/search.js +14 -46
- package/bundle/commands/tail.js +2 -2
- package/bundle/index.js +1 -1
- package/dist/commands/build/actor/setup.d.ts +22 -0
- package/dist/commands/build/actor/setup.d.ts.map +1 -0
- package/dist/commands/build/actor/setup.js +116 -0
- package/dist/commands/build/bucket-events/setup.d.ts +22 -0
- package/dist/commands/build/bucket-events/setup.d.ts.map +1 -0
- package/dist/commands/build/bucket-events/setup.js +134 -0
- package/dist/commands/build/features.d.ts +19 -0
- package/dist/commands/build/features.d.ts.map +1 -0
- package/dist/commands/build/features.js +97 -0
- package/dist/commands/build/generate.d.ts +2 -0
- package/dist/commands/build/generate.d.ts.map +1 -1
- package/dist/commands/build/generate.js +52 -0
- package/dist/commands/build/init.d.ts.map +1 -1
- package/dist/commands/build/init.js +10 -0
- package/dist/commands/build/queue/setup.d.ts +21 -0
- package/dist/commands/build/queue/setup.d.ts.map +1 -0
- package/dist/commands/build/queue/setup.js +120 -0
- package/dist/commands/build/smartbucket/setup.d.ts +23 -0
- package/dist/commands/build/smartbucket/setup.d.ts.map +1 -0
- package/dist/commands/build/smartbucket/setup.js +167 -0
- package/dist/commands/build/smartmemory/setup.d.ts +23 -0
- package/dist/commands/build/smartmemory/setup.d.ts.map +1 -0
- package/dist/commands/build/smartmemory/setup.js +172 -0
- package/dist/commands/build/smartsql/setup.d.ts +23 -0
- package/dist/commands/build/smartsql/setup.d.ts.map +1 -0
- package/dist/commands/build/smartsql/setup.js +169 -0
- package/dist/commands/build/validate.d.ts +2 -0
- package/dist/commands/build/validate.d.ts.map +1 -1
- package/dist/commands/build/validate.js +80 -8
- package/dist/commands/build/workos/jwt.d.ts +23 -0
- package/dist/commands/build/workos/jwt.d.ts.map +1 -0
- package/dist/commands/build/workos/jwt.js +172 -0
- package/dist/commands/doctor.d.ts +27 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +328 -0
- package/dist/commands/object/delete.d.ts +0 -2
- package/dist/commands/object/delete.d.ts.map +1 -1
- package/dist/commands/object/delete.js +3 -38
- package/dist/commands/object/get.d.ts +0 -2
- package/dist/commands/object/get.d.ts.map +1 -1
- package/dist/commands/object/get.js +3 -38
- package/dist/commands/object/list.d.ts +0 -2
- package/dist/commands/object/list.d.ts.map +1 -1
- package/dist/commands/object/list.js +5 -40
- package/dist/commands/object/put.d.ts +0 -2
- package/dist/commands/object/put.d.ts.map +1 -1
- package/dist/commands/object/put.js +3 -38
- package/dist/commands/query/chunk-search.d.ts +0 -2
- package/dist/commands/query/chunk-search.d.ts.map +1 -1
- package/dist/commands/query/chunk-search.js +12 -46
- package/dist/commands/query/document.d.ts +1 -3
- package/dist/commands/query/document.d.ts.map +1 -1
- package/dist/commands/query/document.js +16 -60
- package/dist/commands/query/search.d.ts +0 -2
- package/dist/commands/query/search.d.ts.map +1 -1
- package/dist/commands/query/search.js +12 -46
- package/dist/feature-catalog.d.ts +28 -0
- package/dist/feature-catalog.d.ts.map +1 -0
- package/dist/feature-catalog.js +104 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/oclif.manifest.json +4811 -3433
- package/package.json +3 -3
- package/templates/examples/smartbucket-minimal.ts.hbs +87 -0
- package/templates/examples/smartmemory-minimal.ts.hbs +82 -0
- package/templates/examples/smartsql-minimal.ts.hbs +69 -0
- package/templates/handlers/actor/index.test.ts.hbs +48 -85
- package/templates/handlers/actor/index.ts.hbs +16 -316
- package/templates/handlers/bucket-event-notification/index.ts.hbs +32 -235
- package/templates/handlers/bucket-event-observer.ts.hbs +79 -0
- package/templates/handlers/http-service/index.test.ts.hbs +3 -0
- package/templates/handlers/http-service/index.ts.hbs +43 -15
- package/templates/handlers/queue-consumer-setup.ts.hbs +45 -0
- package/templates/handlers/task/index.test.ts.hbs +30 -112
- package/templates/handlers/task/index.ts.hbs +19 -58
- package/templates/init/RAINDROP.md.hbs +97 -1
- package/templates/init/eslint.config.js +43 -0
- package/templates/init/package.json.hbs +4 -1
- package/templates/init/tsconfig.json +3 -3
- package/bundle/chunk-23UBI7BN.js +0 -48
- package/bundle/chunk-2QWMBNE3.js +0 -384
- package/bundle/chunk-45IYWQDC.js +0 -384
- package/bundle/chunk-5YUO23QU.js +0 -4585
- package/bundle/chunk-6MIGCNUO.js +0 -75
- package/bundle/chunk-7ZJWA6HP.js +0 -805
- package/bundle/chunk-AIYVX2M7.js +0 -44
- package/bundle/chunk-BB5TNIEM.js +0 -48
- package/bundle/chunk-BUR3HFKH.js +0 -488
- package/bundle/chunk-BYSBS7KT.js +0 -488
- package/bundle/chunk-CX3RWI62.js +0 -28658
- package/bundle/chunk-DLH7MI57.js +0 -305
- package/bundle/chunk-E3WJIYJZ.js +0 -12148
- package/bundle/chunk-EX7NOPRF.js +0 -12148
- package/bundle/chunk-F76JQS2J.js +0 -231
- package/bundle/chunk-FBOXMVKD.js +0 -28679
- package/bundle/chunk-FTPZ6SQW.js +0 -238909
- package/bundle/chunk-H3CFZ7ZH.js +0 -74
- package/bundle/chunk-HXOILVWA.js +0 -384
- package/bundle/chunk-IMP7O5AC.js +0 -22452
- package/bundle/chunk-IPYOAKRE.js +0 -231
- package/bundle/chunk-J7HN6XF2.js +0 -4461
- package/bundle/chunk-JOLOAALA.js +0 -231
- package/bundle/chunk-JZ2G4Q35.js +0 -4585
- package/bundle/chunk-KVAWPWF7.js +0 -231
- package/bundle/chunk-MEUAAIXV.js +0 -28657
- package/bundle/chunk-QBWFE57Z.js +0 -384
- package/bundle/chunk-SP3LOXPC.js +0 -46
- package/bundle/chunk-T7C564PR.js +0 -28678
- package/bundle/chunk-UFH545WJ.js +0 -22452
- package/bundle/chunk-UHVMPWM5.js +0 -315
- package/bundle/chunk-VB7ZTSZV.js +0 -1089
- package/bundle/chunk-VBIJDFMJ.js +0 -384
- package/bundle/chunk-VR7RLTE3.js +0 -231
- package/bundle/chunk-WFZUJLEC.js +0 -231
- package/bundle/chunk-YDGJTLVZ.js +0 -133
- package/bundle/chunk-YPNQ7UFK.js +0 -502
- package/bundle/chunk-YXFDRMSN.js +0 -384
- package/dist/lib/dns-utils.d.ts +0 -7
- package/dist/lib/dns-utils.d.ts.map +0 -1
- package/dist/lib/dns-utils.js +0 -44
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BucketEventNotification,
|
|
3
|
+
Each,
|
|
4
|
+
Message,
|
|
5
|
+
} from '@liquidmetal-ai/raindrop-framework';
|
|
6
|
+
import { Env } from './raindrop.gen';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Bucket Event Observer
|
|
10
|
+
*
|
|
11
|
+
* This observer reacts to events on the "{{bucketName}}" bucket.
|
|
12
|
+
* It processes upload, deletion, and multipart upload events.
|
|
13
|
+
*
|
|
14
|
+
* Use cases:
|
|
15
|
+
* - File processing pipelines
|
|
16
|
+
* - Automatic indexing
|
|
17
|
+
* - Thumbnail generation
|
|
18
|
+
* - Metadata extraction
|
|
19
|
+
* - Backup and sync operations
|
|
20
|
+
*/
|
|
21
|
+
export default class extends Each<BucketEventNotification, Env> {
|
|
22
|
+
async process(message: Message<BucketEventNotification>): Promise<void> {
|
|
23
|
+
const event = message.body;
|
|
24
|
+
|
|
25
|
+
this.env.logger.info('Bucket event received', {
|
|
26
|
+
action: event.action,
|
|
27
|
+
bucket: event.bucket,
|
|
28
|
+
key: event.object.key,
|
|
29
|
+
size: event.object.size,
|
|
30
|
+
eTag: event.object.eTag,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Handle different event types
|
|
34
|
+
switch (event.action) {
|
|
35
|
+
case 'ObjectCreated:Put':
|
|
36
|
+
await this.handleUpload(event);
|
|
37
|
+
break;
|
|
38
|
+
|
|
39
|
+
case 'ObjectRemoved:Delete':
|
|
40
|
+
await this.handleDeletion(event);
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
case 'ObjectCreated:Post':
|
|
44
|
+
await this.handleMultipartUpload(event);
|
|
45
|
+
break;
|
|
46
|
+
|
|
47
|
+
default:
|
|
48
|
+
this.env.logger.warn('Unhandled event type', { action: event.action });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async handleUpload(event: BucketEventNotification): Promise<void> {
|
|
53
|
+
this.env.logger.info('Processing file upload', {
|
|
54
|
+
key: event.object.key,
|
|
55
|
+
size: event.object.size,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Add your upload processing logic here
|
|
59
|
+
// Example: trigger processing, update index, send notifications
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private async handleDeletion(event: BucketEventNotification): Promise<void> {
|
|
63
|
+
this.env.logger.info('Processing file deletion', {
|
|
64
|
+
key: event.object.key,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Add your deletion logic here
|
|
68
|
+
// Example: clean up related data, update index, notify systems
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private async handleMultipartUpload(event: BucketEventNotification): Promise<void> {
|
|
72
|
+
this.env.logger.info('Processing multipart upload', {
|
|
73
|
+
key: event.object.key,
|
|
74
|
+
size: event.object.size,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Add your multipart upload logic here
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -31,8 +31,11 @@ function createMockEnv() {
|
|
|
31
31
|
import handler from './index.js';
|
|
32
32
|
|
|
33
33
|
describe('{{serviceName}} HTTP Service', () => {
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
35
|
let service: any;
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
37
|
let env: any;
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
39
|
let ctx: any;
|
|
37
40
|
|
|
38
41
|
beforeEach(() => {
|
|
@@ -2,12 +2,12 @@ import { Service } from '@liquidmetal-ai/raindrop-framework';
|
|
|
2
2
|
import { Hono } from 'hono';
|
|
3
3
|
import { Env } from './raindrop.gen';
|
|
4
4
|
|
|
5
|
-
// Web API types
|
|
6
|
-
//
|
|
7
|
-
type Headers = globalThis.Headers;
|
|
8
|
-
type Blob = globalThis.Blob;
|
|
9
|
-
type FormData = globalThis.FormData;
|
|
10
|
-
type ReadableStream = globalThis.ReadableStream;
|
|
5
|
+
// Web API types available in Cloudflare Workers runtime:
|
|
6
|
+
// Uncomment these type aliases if you need to ensure compatibility between test and runtime environments
|
|
7
|
+
// type Headers = globalThis.Headers;
|
|
8
|
+
// type Blob = globalThis.Blob;
|
|
9
|
+
// type FormData = globalThis.FormData;
|
|
10
|
+
// type ReadableStream = globalThis.ReadableStream;
|
|
11
11
|
|
|
12
12
|
// Create Hono app
|
|
13
13
|
const app = new Hono<{ Bindings: Env }>();
|
|
@@ -18,6 +18,10 @@ app.get('/health', (c) => {
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
// === Add Your API Routes Here ===
|
|
21
|
+
//
|
|
22
|
+
// IMPORTANT: The example endpoints below are used by tests.
|
|
23
|
+
// DO NOT remove them - add your new endpoints alongside these examples.
|
|
24
|
+
// Removing these endpoints will break the test suite.
|
|
21
25
|
|
|
22
26
|
// Example: Simple GET endpoint
|
|
23
27
|
app.get('/api/hello', (c) => {
|
|
@@ -46,16 +50,38 @@ app.post('/api/echo', async (c) => {
|
|
|
46
50
|
}
|
|
47
51
|
});
|
|
48
52
|
|
|
49
|
-
//
|
|
50
|
-
//
|
|
53
|
+
// Add your production endpoints here (keep examples above for tests):
|
|
54
|
+
// app.post('/chat', async (c) => { /* your logic */ });
|
|
55
|
+
// app.post('/upload', async (c) => { /* your logic */ });
|
|
56
|
+
|
|
57
|
+
// === Add Production Features ===
|
|
58
|
+
// IMPORTANT: Use setup commands to get working examples with correct APIs!
|
|
59
|
+
//
|
|
60
|
+
// $ raindrop build features # See all 8 available features
|
|
61
|
+
// $ raindrop build smartmemory setup # Conversation memory → src/examples/
|
|
62
|
+
// $ raindrop build smartsql setup # Database queries → src/examples/
|
|
63
|
+
// $ raindrop build smartbucket setup # File storage → src/examples/
|
|
64
|
+
// $ raindrop build workos setup # Authentication
|
|
65
|
+
// $ raindrop build stripe setup # Payments
|
|
66
|
+
//
|
|
67
|
+
// Setup commands create src/examples/ with actual API usage.
|
|
68
|
+
// DO NOT guess at APIs - check examples for correct methods!
|
|
69
|
+
//
|
|
70
|
+
// === AI Model Usage ===
|
|
71
|
+
// The AI binding is automatically available via this.env.AI
|
|
72
|
+
// DO NOT declare "ai" in your manifest - it's auto-provided!
|
|
51
73
|
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
74
|
+
// Correct usage:
|
|
75
|
+
// const result = await this.env.AI.run('openai', {
|
|
76
|
+
// model: 'gpt-4',
|
|
77
|
+
// messages: [{ role: 'user', content: 'Hello' }]
|
|
78
|
+
// });
|
|
57
79
|
//
|
|
58
|
-
//
|
|
80
|
+
// For Llama models:
|
|
81
|
+
// const result = await this.env.AI.run('openai', {
|
|
82
|
+
// model: 'llama-3.3-70b',
|
|
83
|
+
// messages: [...]
|
|
84
|
+
// });
|
|
59
85
|
|
|
60
86
|
export default class extends Service<Env> {
|
|
61
87
|
async fetch(request: Request): Promise<Response> {
|
|
@@ -65,6 +91,8 @@ export default class extends Service<Env> {
|
|
|
65
91
|
// • Rate limiting and security headers
|
|
66
92
|
// • Metrics collection and health monitoring
|
|
67
93
|
|
|
68
|
-
|
|
94
|
+
// IMPORTANT: Pass this.env so Hono routes can access bindings via c.env
|
|
95
|
+
// DO NOT pass this.ctx (ExecutionContext) - Hono only accepts (request, env)
|
|
96
|
+
return app.fetch(request, this.env);
|
|
69
97
|
}
|
|
70
98
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Each, Message } from '@liquidmetal-ai/raindrop-framework';
|
|
2
|
+
import { Env } from './raindrop.gen';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* {{queueName}} Consumer
|
|
6
|
+
*
|
|
7
|
+
* This observer processes messages from the "{{queueName}}" queue.
|
|
8
|
+
* Messages are processed asynchronously in the background.
|
|
9
|
+
*
|
|
10
|
+
* Use cases:
|
|
11
|
+
* - Background job processing
|
|
12
|
+
* - Async task execution
|
|
13
|
+
* - Event-driven workflows
|
|
14
|
+
* - Decoupling services
|
|
15
|
+
*/
|
|
16
|
+
export default class extends Each<MessageBody, Env> {
|
|
17
|
+
async process(message: Message<MessageBody>): Promise<void> {
|
|
18
|
+
this.env.logger.info('Processing queue message', {
|
|
19
|
+
messageId: message.id,
|
|
20
|
+
timestamp: message.timestamp,
|
|
21
|
+
body: message.body,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Add your message processing logic here
|
|
25
|
+
// Example: handle different message types
|
|
26
|
+
const body = message.body;
|
|
27
|
+
|
|
28
|
+
if (body.task === 'example-task') {
|
|
29
|
+
await this.handleExampleTask(body);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Message will be automatically acknowledged on successful return
|
|
33
|
+
// Throw an error to retry the message
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private async handleExampleTask(body: MessageBody): Promise<void> {
|
|
37
|
+
this.env.logger.info('Handling example task', { body });
|
|
38
|
+
// Add your task logic here
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface MessageBody {
|
|
43
|
+
task?: string;
|
|
44
|
+
[key: string]: any;
|
|
45
|
+
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for Task Handler
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - Simple
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
*
|
|
10
|
-
* For 95% of cases, this template provides adequate safety net.
|
|
3
|
+
*
|
|
4
|
+
* FOCUSED TESTING APPROACH:
|
|
5
|
+
* - Simple, essential tests for scheduled tasks
|
|
6
|
+
* - Tests actual task execution
|
|
7
|
+
* - Covers basic error scenarios
|
|
8
|
+
* - Easy to extend with additional tests
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
import { expect, test, describe, beforeEach, vi } from 'vitest';
|
|
14
12
|
|
|
15
|
-
// Simple mock environment
|
|
13
|
+
// Simple mock environment with only what this template uses
|
|
16
14
|
function createMockEnv() {
|
|
17
15
|
return {
|
|
18
16
|
_raindrop: {
|
|
@@ -26,10 +24,7 @@ function createMockEnv() {
|
|
|
26
24
|
error: vi.fn(),
|
|
27
25
|
warn: vi.fn(),
|
|
28
26
|
},
|
|
29
|
-
// Add
|
|
30
|
-
// DATABASE: { executeQuery: vi.fn() },
|
|
31
|
-
// CACHE: { get: vi.fn(), put: vi.fn() },
|
|
32
|
-
// EXTERNAL_API: { post: vi.fn() },
|
|
27
|
+
// Add additional bindings here as you add features to your task
|
|
33
28
|
};
|
|
34
29
|
}
|
|
35
30
|
|
|
@@ -46,7 +41,7 @@ describe('{{taskClassName}} Task', () => {
|
|
|
46
41
|
task = new handler(ctx, env);
|
|
47
42
|
});
|
|
48
43
|
|
|
49
|
-
test('
|
|
44
|
+
test('task instantiates correctly', () => {
|
|
50
45
|
expect(task).toBeDefined();
|
|
51
46
|
expect(typeof task.handle).toBe('function');
|
|
52
47
|
});
|
|
@@ -57,124 +52,47 @@ describe('{{taskClassName}} Task', () => {
|
|
|
57
52
|
expect(env._raindrop.app.organizationId).toBe('test-org');
|
|
58
53
|
});
|
|
59
54
|
|
|
60
|
-
// ===
|
|
55
|
+
// === Essential Task Tests ===
|
|
61
56
|
|
|
62
|
-
test('handles
|
|
57
|
+
test('handles scheduled events', async () => {
|
|
63
58
|
const event: any = {
|
|
64
59
|
type: 'scheduled',
|
|
65
|
-
scheduledTime:
|
|
60
|
+
scheduledTime: Date.now(),
|
|
66
61
|
cron: '0 8 * * *',
|
|
67
62
|
};
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
await expect(task.handle(event)).resolves.not.toThrow();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('handles missing event gracefully', async () => {
|
|
74
|
-
// Should handle null/undefined events without crashing
|
|
75
|
-
await expect(task.handle(null as any)).resolves.not.toThrow();
|
|
76
|
-
await expect(task.handle(undefined as any)).resolves.not.toThrow();
|
|
77
|
-
});
|
|
64
|
+
await task.handle(event);
|
|
78
65
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
await expect(task.handle(event as any)).resolves.not.toThrow();
|
|
66
|
+
expect(env.logger.info).toHaveBeenCalledWith(
|
|
67
|
+
'Scheduled task executed',
|
|
68
|
+
expect.objectContaining({ cron: '0 8 * * *' })
|
|
69
|
+
);
|
|
84
70
|
});
|
|
85
71
|
|
|
86
|
-
test('
|
|
72
|
+
test('handles errors gracefully', async () => {
|
|
87
73
|
const event: any = {
|
|
88
74
|
type: 'scheduled',
|
|
89
|
-
scheduledTime:
|
|
75
|
+
scheduledTime: Date.now(),
|
|
76
|
+
cron: '*/5 * * * *',
|
|
90
77
|
};
|
|
91
78
|
|
|
92
|
-
// Should
|
|
93
|
-
await task.handle(event);
|
|
94
|
-
await task.handle(event);
|
|
95
|
-
await task.handle(event);
|
|
96
|
-
|
|
97
|
-
expect(true).toBe(true); // If we get here, no errors thrown
|
|
79
|
+
// Should not throw even if task logic errors
|
|
80
|
+
await expect(task.handle(event)).resolves.toBeUndefined();
|
|
98
81
|
});
|
|
99
82
|
|
|
100
|
-
test('
|
|
83
|
+
test('processes multiple consecutive runs', async () => {
|
|
101
84
|
const event: any = {
|
|
102
85
|
type: 'scheduled',
|
|
103
|
-
scheduledTime:
|
|
86
|
+
scheduledTime: Date.now(),
|
|
87
|
+
cron: '0 * * * *',
|
|
104
88
|
};
|
|
105
89
|
|
|
90
|
+
await task.handle(event);
|
|
91
|
+
await task.handle(event);
|
|
106
92
|
await task.handle(event);
|
|
107
93
|
|
|
108
|
-
//
|
|
109
|
-
expect(env.logger.info || env.logger.warn || env.logger.error).toHaveBeenCalled();
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
// === EDGE CASE GUARD RAILS ===
|
|
113
|
-
|
|
114
|
-
test('handles malformed events gracefully', async () => {
|
|
115
|
-
// Guard rail: Catches circular reference issues
|
|
116
|
-
const event: any = { type: 'test' };
|
|
117
|
-
event.self = event; // Circular reference
|
|
118
|
-
|
|
119
|
-
// Should not crash during logging or processing
|
|
120
|
-
await expect(task.handle(event)).resolves.not.toThrow();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('handles events with special characters', async () => {
|
|
124
|
-
// Guard rail: Ensures no injection issues
|
|
125
|
-
const event: any = {
|
|
126
|
-
type: 'test',
|
|
127
|
-
data: '<script>alert("xss")</script>',
|
|
128
|
-
sqlQuery: "'; DROP TABLE users--",
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
await expect(task.handle(event)).resolves.not.toThrow();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test('handles events with unicode content', async () => {
|
|
135
|
-
// Guard rail: Validates UTF-8 handling
|
|
136
|
-
const event: any = {
|
|
137
|
-
type: 'test',
|
|
138
|
-
message: 'Hello 世界 🌍',
|
|
139
|
-
unicodeData: '测试数据',
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
await expect(task.handle(event)).resolves.not.toThrow();
|
|
94
|
+
expect(env.logger.info).toHaveBeenCalledTimes(6); // 3 executions * 2 logs each
|
|
143
95
|
});
|
|
144
96
|
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
// test('processes business logic correctly', async () => {
|
|
148
|
-
// const mockDb = {
|
|
149
|
-
// executeQuery: vi.fn().mockResolvedValue({ success: true })
|
|
150
|
-
// };
|
|
151
|
-
// env.DATABASE = mockDb;
|
|
152
|
-
//
|
|
153
|
-
// const event = {
|
|
154
|
-
// type: 'daily_report',
|
|
155
|
-
// reportType: 'sales'
|
|
156
|
-
// };
|
|
157
|
-
//
|
|
158
|
-
// await task.handle(event);
|
|
159
|
-
//
|
|
160
|
-
// expect(mockDb.executeQuery).toHaveBeenCalledWith(
|
|
161
|
-
// expect.stringContaining('sales_report')
|
|
162
|
-
// );
|
|
163
|
-
// });
|
|
164
|
-
//
|
|
165
|
-
// test('handles external API calls', async () => {
|
|
166
|
-
// const mockApi = {
|
|
167
|
-
// post: vi.fn().mockResolvedValue({ status: 'ok' })
|
|
168
|
-
// };
|
|
169
|
-
// env.EXTERNAL_API = mockApi;
|
|
170
|
-
//
|
|
171
|
-
// const event = {
|
|
172
|
-
// type: 'sync_data',
|
|
173
|
-
// endpoint: '/webhook'
|
|
174
|
-
// };
|
|
175
|
-
//
|
|
176
|
-
// await task.handle(event);
|
|
177
|
-
//
|
|
178
|
-
// expect(mockApi.post).toHaveBeenCalled();
|
|
179
|
-
// });
|
|
180
|
-
});
|
|
97
|
+
// === Add Your Custom Tests Here ===
|
|
98
|
+
});
|
|
@@ -4,72 +4,33 @@ import { Env } from './raindrop.gen';
|
|
|
4
4
|
export default class extends Task<Env> {
|
|
5
5
|
async handle(event: Event): Promise<void> {
|
|
6
6
|
try {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Extract event type safely - Event only has 'scheduled' type
|
|
14
|
-
const eventType = event.type || 'scheduled';
|
|
15
|
-
const eventData = event; // Event object contains cron, type, scheduledTime
|
|
16
|
-
|
|
17
|
-
this.env.logger.info('Task executed', {
|
|
18
|
-
eventType,
|
|
19
|
-
scheduledTime: event.scheduledTime
|
|
7
|
+
this.env.logger.info('Scheduled task executed', {
|
|
8
|
+
cron: event.cron,
|
|
9
|
+
scheduledTime: event.scheduledTime,
|
|
20
10
|
});
|
|
21
11
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this.env.logger.warn('Unknown event type', { eventType });
|
|
28
|
-
}
|
|
12
|
+
// === Add Your Task Logic Here ===
|
|
13
|
+
|
|
14
|
+
// Example: Process scheduled data cleanup, reports, etc.
|
|
15
|
+
await this.processScheduledTask(event);
|
|
16
|
+
|
|
29
17
|
} catch (error) {
|
|
30
18
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
31
|
-
this.env.logger.error('Task execution failed', {
|
|
19
|
+
this.env.logger.error('Task execution failed', {
|
|
32
20
|
error: errorMessage,
|
|
33
|
-
|
|
21
|
+
cron: event.cron,
|
|
34
22
|
});
|
|
35
|
-
|
|
36
|
-
// Don't throw - tasks should handle errors gracefully
|
|
37
|
-
return;
|
|
38
23
|
}
|
|
39
24
|
}
|
|
40
25
|
|
|
41
|
-
private async
|
|
42
|
-
this.env.logger.info('Processing scheduled task', { cron:
|
|
43
|
-
|
|
44
|
-
// Note: waitUntil background operations
|
|
45
|
-
// This depends on execution context - commented out for now
|
|
46
|
-
// if ('waitUntil' in this.env) {
|
|
47
|
-
// this.env.waitUntil(Promise.resolve('Background operation'));
|
|
48
|
-
// }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private async handleManualTask(data: any): Promise<void> {
|
|
52
|
-
this.env.logger.info('Processing manual task', { data });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// === Integration Examples ===
|
|
26
|
+
private async processScheduledTask(event: Event): Promise<void> {
|
|
27
|
+
this.env.logger.info('Processing scheduled task', { cron: event.cron });
|
|
56
28
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
private async saveResult(key: string, data: any): Promise<void> {
|
|
64
|
-
try {
|
|
65
|
-
// Example: Use FILES binding (if you have bucket "files" in manifest)
|
|
66
|
-
// const bucket = this.env.FILES;
|
|
67
|
-
// Replace with your actual bucket binding name from raindrop.gen.ts
|
|
68
|
-
throw new Error('Bucket binding not configured - update this method to use your bucket binding');
|
|
69
|
-
} catch (error) {
|
|
70
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
71
|
-
this.env.logger.error('Failed to save result', { error: errorMessage, key });
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
29
|
+
// Add your scheduled task logic here
|
|
30
|
+
// Examples:
|
|
31
|
+
// - Generate daily reports
|
|
32
|
+
// - Clean up old data
|
|
33
|
+
// - Send scheduled notifications
|
|
34
|
+
// - Aggregate metrics
|
|
74
35
|
}
|
|
75
|
-
}
|
|
36
|
+
}
|
|
@@ -23,7 +23,18 @@ A Raindrop application built with Hono.js and modern web technologies.
|
|
|
23
23
|
raindrop build generate
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
3. **
|
|
26
|
+
3. **Discover available features** (recommended for new apps)
|
|
27
|
+
```bash
|
|
28
|
+
raindrop build features
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
4. **Add features you need** (example)
|
|
32
|
+
```bash
|
|
33
|
+
raindrop build smartmemory setup
|
|
34
|
+
raindrop build smartsql setup
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
5. **Deploy to Raindrop**
|
|
27
38
|
```bash
|
|
28
39
|
raindrop build deploy --start
|
|
29
40
|
```
|
|
@@ -33,6 +44,53 @@ A Raindrop application built with Hono.js and modern web technologies.
|
|
|
33
44
|
npm run start
|
|
34
45
|
```
|
|
35
46
|
|
|
47
|
+
## Best Practices for Using Examples
|
|
48
|
+
|
|
49
|
+
When adding features to your app, follow this workflow to avoid issues:
|
|
50
|
+
|
|
51
|
+
### ✅ Recommended Workflow
|
|
52
|
+
|
|
53
|
+
1. **Run setup commands to get examples**
|
|
54
|
+
```bash
|
|
55
|
+
raindrop build smartmemory setup
|
|
56
|
+
raindrop build smartsql setup
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
2. **Test that examples compile**
|
|
60
|
+
```bash
|
|
61
|
+
npm run build
|
|
62
|
+
```
|
|
63
|
+
If examples don't compile, check that you ran `raindrop build generate` first.
|
|
64
|
+
|
|
65
|
+
3. **Study the examples for correct API usage**
|
|
66
|
+
```bash
|
|
67
|
+
cat src/examples/smartmemory-minimal.ts
|
|
68
|
+
```
|
|
69
|
+
Examples show actual available methods - do not guess at APIs!
|
|
70
|
+
|
|
71
|
+
4. **Adapt examples for your use case**
|
|
72
|
+
Copy patterns from examples into your handlers. Don't rewrite from scratch.
|
|
73
|
+
|
|
74
|
+
### ❌ Common Mistakes to Avoid
|
|
75
|
+
|
|
76
|
+
- **Don't remove template example endpoints** - The `/api/hello`, `/api/echo` endpoints are used by tests. Add your endpoints alongside them, don't replace them.
|
|
77
|
+
- **Don't manually edit manifest without running generate** - You'll be missing TypeScript types
|
|
78
|
+
- **Don't guess at API methods** - Check examples for actual available methods
|
|
79
|
+
- SmartBucket has: `put()`, `get()`, `list()`, `delete()`, `head()` (no `search()`!)
|
|
80
|
+
- SmartMemory has: `startWorkingMemorySession()`, `getWorkingMemorySession(sessionId)`
|
|
81
|
+
- SmartSQL has: `executeQuery({ sqlQuery })`, `executeQuery({ textQuery })`
|
|
82
|
+
- **Don't ignore binding names** - Use the exact names from your manifest in examples
|
|
83
|
+
- **Don't skip `npm run build`** - Compile errors catch API mistakes early
|
|
84
|
+
- **Don't declare `ai` in manifest** - AI is auto-available via `this.env.AI`
|
|
85
|
+
|
|
86
|
+
### 🔍 Troubleshooting
|
|
87
|
+
|
|
88
|
+
If you see errors about missing types or methods:
|
|
89
|
+
1. Run `raindrop build generate` to update types
|
|
90
|
+
2. Check `src/examples/` for correct API patterns
|
|
91
|
+
3. Verify binding names match between manifest and code
|
|
92
|
+
4. Run `npm run build` to catch TypeScript errors
|
|
93
|
+
|
|
36
94
|
## Raindrop Commands
|
|
37
95
|
|
|
38
96
|
### Essential Commands
|
|
@@ -41,6 +99,7 @@ A Raindrop application built with Hono.js and modern web technologies.
|
|
|
41
99
|
|---------|-------------|-------------|
|
|
42
100
|
| `raindrop build validate` | Validate your manifest | After changing `raindrop.manifest` |
|
|
43
101
|
| `raindrop build generate` | Generate TypeScript types and handler scaffolding | After changing `raindrop.manifest` |
|
|
102
|
+
| `raindrop build features` | List available features and integrations | When starting or adding functionality |
|
|
44
103
|
| `raindrop build deploy --start` | Build, upload and start your application | When ready to deploy |
|
|
45
104
|
| `raindrop build stop` | Stop your running application | To stop services |
|
|
46
105
|
| `raindrop build status` | Check deployment status | To see current state |
|
|
@@ -141,6 +200,40 @@ import { corsAllowAll } from '@liquidmetal-ai/raindrop-framework/core/cors';
|
|
|
141
200
|
export const cors = corsAllowAll;
|
|
142
201
|
```
|
|
143
202
|
|
|
203
|
+
## Available Features
|
|
204
|
+
|
|
205
|
+
Raindrop provides powerful features you can add to your application. Discover them with:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
raindrop build features
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Popular Features
|
|
212
|
+
|
|
213
|
+
| Feature | Description | Setup Command |
|
|
214
|
+
|---------|-------------|---------------|
|
|
215
|
+
| **SmartMemory** | AI conversation memory management | `raindrop build smartmemory setup` |
|
|
216
|
+
| **SmartSQL** | PostgreSQL with natural language queries | `raindrop build smartsql setup` |
|
|
217
|
+
| **SmartBucket** | File storage with AI-powered search | `raindrop build smartbucket setup` |
|
|
218
|
+
| **Stateful Actor** | Durable objects with state management | `raindrop build actor setup` |
|
|
219
|
+
| **Queue Consumer** | Background message processing | `raindrop build queue setup` |
|
|
220
|
+
| **WorkOS Auth** | Authentication with WorkOS | `raindrop build workos setup` |
|
|
221
|
+
| **Stripe Payments** | Payment processing with Stripe | `raindrop build stripe setup` |
|
|
222
|
+
|
|
223
|
+
### Example: Adding SmartMemory
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# 1. Set up SmartMemory in your app
|
|
227
|
+
raindrop build smartmemory setup
|
|
228
|
+
|
|
229
|
+
# 2. Generate updated types
|
|
230
|
+
raindrop build generate
|
|
231
|
+
|
|
232
|
+
# 3. Use in your handler
|
|
233
|
+
const { workingMemory } = await this.env.MEMORY.startWorkingMemorySession();
|
|
234
|
+
await workingMemory.putMemory({ content: 'Hello', agent: 'user' });
|
|
235
|
+
```
|
|
236
|
+
|
|
144
237
|
## Manifest Configuration
|
|
145
238
|
|
|
146
239
|
Your `raindrop.manifest` defines all resources and modules:
|
|
@@ -194,6 +287,9 @@ Your handlers are generated in `src/handlers/` with comprehensive examples:
|
|
|
194
287
|
# After raindrop init
|
|
195
288
|
npm install
|
|
196
289
|
raindrop build generate
|
|
290
|
+
|
|
291
|
+
# Optional but recommended: explore features
|
|
292
|
+
raindrop build features
|
|
197
293
|
```
|
|
198
294
|
|
|
199
295
|
### 2. Development Cycle
|