@squidcloud/cli 1.0.446 → 1.0.447
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 +1 -5
- package/dist/resources/claude/skills/squid-development/SKILL.md +66 -2473
- package/dist/resources/claude/skills/squid-development/reference/admin.md +242 -0
- package/dist/resources/claude/skills/squid-development/reference/ai.md +773 -0
- package/dist/resources/claude/skills/squid-development/reference/api.md +87 -0
- package/dist/resources/claude/skills/squid-development/reference/backend.md +462 -0
- package/dist/resources/claude/skills/squid-development/reference/client.md +442 -0
- package/dist/resources/claude/skills/squid-development/reference/connectors.md +33 -0
- package/dist/resources/claude/skills/squid-development/reference/console.md +189 -0
- package/dist/resources/claude/skills/squid-development/reference/databases.md +472 -0
- package/dist/resources/claude/skills/squid-development/reference/openai.md +98 -0
- package/dist/resources/claude/skills/squid-development/reference/security.md +356 -0
- package/package.json +2 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# REST API Reference
|
|
2
|
+
|
|
3
|
+
Most Squid SDK functionality is also available via REST APIs.
|
|
4
|
+
|
|
5
|
+
## API Documentation
|
|
6
|
+
|
|
7
|
+
Full API reference: https://docs.getsquid.ai/reference-docs/api/
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
All API endpoints require an API key. Include it in the request headers:
|
|
12
|
+
```
|
|
13
|
+
Authorization: Bearer YOUR_API_KEY
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## API Categories
|
|
17
|
+
|
|
18
|
+
### [Agent API](https://docs.getsquid.ai/reference-docs/api/#tag/Agent)
|
|
19
|
+
Manage AI agents. SDK: [ai.md](ai.md)
|
|
20
|
+
- `GET /agent/get/{agentId}` - Get agent details
|
|
21
|
+
- `POST /agent/upsert` - Create or update agent
|
|
22
|
+
- `POST /agent/delete` - Delete agent
|
|
23
|
+
- `POST /agent/updateInstructions` - Update agent instructions
|
|
24
|
+
- `POST /agent/updateModel` - Change LLM model
|
|
25
|
+
- `POST /agent/updateConnectedAgents` - Manage connected agents
|
|
26
|
+
- `POST /agent/updateGuardrails` - Configure guardrails
|
|
27
|
+
- `POST /agent/updateCustomGuardrails` - Set custom guardrails
|
|
28
|
+
- `POST /agent/deleteCustomGuardrails` - Remove custom guardrails
|
|
29
|
+
- `POST /agent/ask` - Send prompt, get response
|
|
30
|
+
- `POST /agent/askWithAnnotations` - Get response with annotations
|
|
31
|
+
- `GET /agent/revisions/{agentId}` - List revisions
|
|
32
|
+
- `POST /agent/restoreRevision` - Restore revision
|
|
33
|
+
- `POST /agent/deleteRevision` - Delete revision
|
|
34
|
+
|
|
35
|
+
### [AI Audio API](https://docs.getsquid.ai/reference-docs/api/#tag/AI-Audio)
|
|
36
|
+
Transcribe audio, text-to-speech. SDK: [ai.md](ai.md)
|
|
37
|
+
- `POST /audio/transcribe` - Transcribe audio to text
|
|
38
|
+
- `POST /audio/createSpeech` - Text to speech
|
|
39
|
+
|
|
40
|
+
### [AI Image API](https://docs.getsquid.ai/reference-docs/api/#tag/AI-Image)
|
|
41
|
+
Generate images, remove backgrounds. SDK: [ai.md](ai.md)
|
|
42
|
+
- `POST /image/generate` - Generate image from prompt
|
|
43
|
+
- `POST /image/removeBackground` - Remove image background
|
|
44
|
+
|
|
45
|
+
### [KnowledgeBase API](https://docs.getsquid.ai/reference-docs/api/#tag/KnowledgeBase)
|
|
46
|
+
Manage knowledge bases for RAG. SDK: [ai.md](ai.md)
|
|
47
|
+
- `GET /knowledge-base/get/{knowledgeBaseId}` - Get knowledge base
|
|
48
|
+
- `POST /knowledge-base/upsert` - Create or update knowledge base
|
|
49
|
+
- `POST /knowledge-base/delete` - Delete knowledge base
|
|
50
|
+
- `POST /knowledge-base/upsertContexts` - Add or update contexts
|
|
51
|
+
- `POST /knowledge-base/deleteContexts` - Delete contexts
|
|
52
|
+
- `GET /knowledge-base/getContext/{knowledgeBaseId}/{contextId}` - Get context
|
|
53
|
+
- `GET /knowledge-base/listContexts/{knowledgeBaseId}` - List contexts
|
|
54
|
+
- `POST /knowledge-base/search` - Semantic search
|
|
55
|
+
|
|
56
|
+
### [Matchmaking API](https://docs.getsquid.ai/reference-docs/api/#tag/Matchmaking) *(deprecated)*
|
|
57
|
+
Use `knowledgeBase().searchContextsWith*()` instead.
|
|
58
|
+
|
|
59
|
+
### [Web Utilities API](https://docs.getsquid.ai/reference-docs/api/#tag/Web-Utilities)
|
|
60
|
+
Web search, URL content, short URLs. SDK: [client.md](client.md)
|
|
61
|
+
- `POST /web/aiSearch` - AI-powered web search
|
|
62
|
+
- `POST /web/getUrlContent` - Fetch URL as markdown
|
|
63
|
+
- `POST /web/createShortUrl` - Create short URL
|
|
64
|
+
- `POST /web/createShortUrls` - Create multiple short URLs
|
|
65
|
+
- `POST /web/deleteShortUrl` - Delete short URL
|
|
66
|
+
- `POST /web/deleteShortUrls` - Delete multiple short URLs
|
|
67
|
+
|
|
68
|
+
### [Database API](https://docs.getsquid.ai/reference-docs/api/#tag/Database)
|
|
69
|
+
AI queries against databases. SDK: [ai.md](ai.md)
|
|
70
|
+
- `POST /db/executeAiQuery` - Execute AI query
|
|
71
|
+
|
|
72
|
+
### [Extraction Utilities API](https://docs.getsquid.ai/reference-docs/api/#tag/Extraction-Utilities)
|
|
73
|
+
Create PDFs, extract data from documents. SDK: [client.md](client.md)
|
|
74
|
+
- `POST /extraction/createPdf` - Create PDF from HTML/markdown
|
|
75
|
+
- `POST /extraction/extractDataFromUrl` - Extract data from URL
|
|
76
|
+
- `POST /extraction/extractDataFromFile` - Extract data from file
|
|
77
|
+
|
|
78
|
+
## SDK vs REST API
|
|
79
|
+
|
|
80
|
+
| Feature | SDK | REST API |
|
|
81
|
+
|---------|-----|----------|
|
|
82
|
+
| AI Agents | `squid.ai().agent()` | Agent API |
|
|
83
|
+
| Audio | `squid.ai().audio()` | AI Audio API |
|
|
84
|
+
| Image | `squid.ai().image()` | AI Image API |
|
|
85
|
+
| Knowledge Bases | `squid.ai().knowledgeBase()` | KnowledgeBase API |
|
|
86
|
+
| Web Utilities | `squid.web()` | Web Utilities API |
|
|
87
|
+
| Extraction | `squid.extraction()` | Extraction Utilities API |
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
# Backend SDK
|
|
2
|
+
|
|
3
|
+
The Squid Backend SDK (`@squidcloud/backend`) provides TypeScript decorators and base classes for building server-side logic that runs on Squid's infrastructure.
|
|
4
|
+
|
|
5
|
+
Docs: https://docs.getsquid.ai/reference-docs/backend/
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
- CLI Commands
|
|
9
|
+
- Project Structure
|
|
10
|
+
- How Backend Runs
|
|
11
|
+
- SquidService Base Class
|
|
12
|
+
- Backend Functions (@executable)
|
|
13
|
+
- Webhooks (@webhook)
|
|
14
|
+
- Triggers (@trigger)
|
|
15
|
+
- Schedulers (@scheduler)
|
|
16
|
+
- Rate Limiting (@limits)
|
|
17
|
+
- Client Connection State (@clientConnectionStateHandler)
|
|
18
|
+
- Using Squid Client in Backend
|
|
19
|
+
- File Handling
|
|
20
|
+
|
|
21
|
+
## CLI Commands
|
|
22
|
+
|
|
23
|
+
Install the CLI globally:
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g @squidcloud/cli
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**`squid init <project-name>`** - Creates a new backend project with `.env` and example service. Also populates `.claude/skills/` with Squid development skills for Claude.
|
|
29
|
+
```bash
|
|
30
|
+
squid init backend --appId YOUR_APP_ID --apiKey YOUR_API_KEY --environmentId dev --squidDeveloperId YOUR_DEV_ID --region us-east-1.aws
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**`squid start`** - Runs backend locally with hot-reload. Connects to Squid Cloud via reverse proxy.
|
|
34
|
+
```bash
|
|
35
|
+
cd backend && squid start
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**`squid deploy`** - Builds and deploys to Squid Cloud.
|
|
39
|
+
```bash
|
|
40
|
+
squid deploy [--apiKey KEY] [--environmentId prod] [--skipBuild]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**`squid build`** - Builds backend project without deploying.
|
|
44
|
+
```bash
|
|
45
|
+
squid build [--dev] [--skip-version-check]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Extended logging** - Add to `.env`:
|
|
49
|
+
```env
|
|
50
|
+
SQUID_LOG_TYPES=QUERY,MUTATION,AI,API,ERROR
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Project Structure
|
|
54
|
+
|
|
55
|
+
After running `squid init`, your backend project has this structure:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
backend/
|
|
59
|
+
├── .env # Environment config: SQUID_APP_ID, SQUID_API_KEY, SQUID_ENVIRONMENT_ID, SQUID_REGION
|
|
60
|
+
├── package.json # Dependencies: @squidcloud/backend, devDeps: @squidcloud/cli
|
|
61
|
+
├── tsconfig.json # TypeScript configuration
|
|
62
|
+
├── src/
|
|
63
|
+
│ ├── index.ts # Entry point - exports SquidProject and all services
|
|
64
|
+
│ ├── service/ # All SquidService classes go here
|
|
65
|
+
│ │ ├── index.ts # Re-exports all services (e.g., export * from './example-service')
|
|
66
|
+
│ │ └── *.ts # Your SquidService classes with decorators
|
|
67
|
+
│ └── public/ # Static assets (accessible via this.assetsDirectory)
|
|
68
|
+
└── dist/ # Build output
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Key files:**
|
|
72
|
+
- `src/index.ts` - Must export a `SquidProject` instance and all services
|
|
73
|
+
- `src/service/index.ts` - Re-exports all service files so they're included in the bundle
|
|
74
|
+
- `.env` - Contains credentials from Squid Console (never commit to git)
|
|
75
|
+
|
|
76
|
+
## How Backend Runs
|
|
77
|
+
|
|
78
|
+
**Local development (`squid start`):**
|
|
79
|
+
- Runs your backend code on your machine
|
|
80
|
+
- Hot-reload on file changes
|
|
81
|
+
- Connects to Squid Cloud via reverse proxy
|
|
82
|
+
- Your code can access integrations configured in Console
|
|
83
|
+
|
|
84
|
+
**Production (`squid deploy`):**
|
|
85
|
+
- Builds and uploads your code to Squid Cloud
|
|
86
|
+
- Squid Cloud runs your backend in a managed environment
|
|
87
|
+
- Multiple backend instances can be configured for scaling
|
|
88
|
+
|
|
89
|
+
## SquidService Base Class
|
|
90
|
+
|
|
91
|
+
All backend services extend `SquidService`:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { SquidService } from '@squidcloud/backend';
|
|
95
|
+
|
|
96
|
+
export class MyService extends SquidService {
|
|
97
|
+
// Decorated methods
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Important:** In backend code running on Squid's infrastructure, the Squid client is **already initialized and available** via `this.squid`. You don't need to manually create a new instance or provide configuration parameters.
|
|
102
|
+
|
|
103
|
+
### Available Properties
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
this.region // 'local' during dev, region in production
|
|
107
|
+
this.backendBaseUrl
|
|
108
|
+
this.secrets // From Squid Console
|
|
109
|
+
this.apiKeys
|
|
110
|
+
this.context // RunContext (appId, clientId, sourceIp, headers, openApiContext)
|
|
111
|
+
this.squid // Pre-initialized Squid client (initialized with admin API key, full permissions)
|
|
112
|
+
this.assetsDirectory // Path to public/ folder
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Auth Methods
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Get user authentication (JWT token)
|
|
119
|
+
this.getUserAuth() // AuthWithBearer | undefined
|
|
120
|
+
// Returns: { type: 'Bearer', userId: string, expiration: number, attributes: Record<string, any>, jwt?: string }
|
|
121
|
+
|
|
122
|
+
// Get API key authentication
|
|
123
|
+
this.getApiKeyAuth() // AuthWithApiKey | undefined
|
|
124
|
+
// Returns: { type: 'ApiKey', apiKey: string }
|
|
125
|
+
|
|
126
|
+
this.isAuthenticated() // boolean - true if user token OR API key
|
|
127
|
+
this.assertIsAuthenticated() // throws if not authenticated
|
|
128
|
+
this.assertApiKeyCall() // throws if not API key auth
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Example: Getting User Info**
|
|
132
|
+
```typescript
|
|
133
|
+
@executable()
|
|
134
|
+
async getUserData(): Promise<UserData> {
|
|
135
|
+
this.assertIsAuthenticated();
|
|
136
|
+
const userId = this.getUserAuth()?.userId;
|
|
137
|
+
if (!userId) throw new Error('User not authenticated');
|
|
138
|
+
return await fetchUserData(userId);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Helper Methods
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Create webhook response (for @webhook decorated functions)
|
|
146
|
+
this.createWebhookResponse(body?, statusCode?, headers?)
|
|
147
|
+
// Throws webhook response immediately (interrupts execution)
|
|
148
|
+
this.throwWebhookResponse({ body?, statusCode?, headers? })
|
|
149
|
+
|
|
150
|
+
// Create OpenAPI response (for OpenAPI/tsoa decorated functions)
|
|
151
|
+
this.createOpenApiResponse(body?, statusCode?, headers?)
|
|
152
|
+
// Throws OpenAPI response immediately (interrupts execution)
|
|
153
|
+
this.throwOpenApiResponse({ body?, statusCode?, headers? })
|
|
154
|
+
|
|
155
|
+
// Convert browser File to SquidFile for OpenAPI file returns
|
|
156
|
+
await this.convertToSquidFile(file: File): Promise<SquidFile>
|
|
157
|
+
|
|
158
|
+
// Publish AI status update to specific client (used in @aiFunction)
|
|
159
|
+
await this.publishAiStatusUpdate(update: AiStatusMessage, clientId: ClientId)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Backend Functions (@executable)
|
|
163
|
+
|
|
164
|
+
Backend functions allow you to write custom server-side logic that can be called from the client.
|
|
165
|
+
|
|
166
|
+
### Backend Definition
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { SquidService, executable, SquidFile } from '@squidcloud/backend';
|
|
170
|
+
|
|
171
|
+
export class MyService extends SquidService {
|
|
172
|
+
@executable()
|
|
173
|
+
async greetUser(name: string): Promise<string> {
|
|
174
|
+
return `Hello, ${name}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@executable()
|
|
178
|
+
async uploadFile(file: SquidFile): Promise<Result> {
|
|
179
|
+
console.log(file.originalName, file.size, file.data);
|
|
180
|
+
return { success: true };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Client Invocation
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// Execute @executable() decorated function
|
|
189
|
+
const result = await squid.executeFunction('greetUser', 'John');
|
|
190
|
+
const typedResult = await squid.executeFunction<string>('greetUser', 'John');
|
|
191
|
+
|
|
192
|
+
// With headers
|
|
193
|
+
const result = await squid.executeFunctionWithHeaders(
|
|
194
|
+
'processPayment',
|
|
195
|
+
{ 'X-Custom-Header': 'value' },
|
|
196
|
+
paymentData
|
|
197
|
+
);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Webhooks (@webhook)
|
|
201
|
+
|
|
202
|
+
Webhooks allow you to create publicly accessible HTTP endpoints that can receive data from external services.
|
|
203
|
+
|
|
204
|
+
### Backend Definition
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { SquidService, webhook, WebhookRequest } from '@squidcloud/backend';
|
|
208
|
+
|
|
209
|
+
export class MyService extends SquidService {
|
|
210
|
+
@webhook('github-events')
|
|
211
|
+
async handleGithub(request: WebhookRequest): Promise<any> {
|
|
212
|
+
console.log(request.body);
|
|
213
|
+
console.log(request.headers);
|
|
214
|
+
console.log(request.queryParams);
|
|
215
|
+
console.log(request.httpMethod); // 'post' | 'get' | 'put' | 'delete'
|
|
216
|
+
console.log(request.files);
|
|
217
|
+
|
|
218
|
+
return this.createWebhookResponse({ received: true }, 200);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Webhook URL:** `https://<appId>.<region>.squid.cloud/webhooks/<webhook-id>`
|
|
224
|
+
|
|
225
|
+
### Client Usage
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// Get URL for a specific webhook
|
|
229
|
+
const webhookUrl = squid.getWebhookUrl('github-events');
|
|
230
|
+
// Returns: https://<appId>.<region>.squid.cloud/webhooks/github-events
|
|
231
|
+
|
|
232
|
+
// Get base webhooks URL (no webhook ID)
|
|
233
|
+
const baseUrl = squid.getWebhookUrl();
|
|
234
|
+
// Returns: https://<appId>.<region>.squid.cloud/webhooks
|
|
235
|
+
|
|
236
|
+
// Call webhook programmatically (optional)
|
|
237
|
+
// Usually webhooks are called by external services
|
|
238
|
+
const result = await squid.executeWebhook<Response>('github-events', {
|
|
239
|
+
headers: { 'X-GitHub-Event': 'push' },
|
|
240
|
+
queryParams: { ref: 'main' },
|
|
241
|
+
body: { commits: [...] },
|
|
242
|
+
files: [file1, file2]
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Triggers (@trigger)
|
|
247
|
+
|
|
248
|
+
Triggers respond to database document changes (insert, update, delete).
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { SquidService, trigger, TriggerRequest } from '@squidcloud/backend';
|
|
252
|
+
|
|
253
|
+
export class MyService extends SquidService {
|
|
254
|
+
// Using options object (recommended)
|
|
255
|
+
@trigger({ collection: 'users', mutationTypes: ['insert'] })
|
|
256
|
+
async onUserCreated(request: TriggerRequest<User>): Promise<void> {
|
|
257
|
+
console.log(request.mutationType); // 'insert' | 'update' | 'delete'
|
|
258
|
+
console.log(request.docId); // Document ID
|
|
259
|
+
console.log(request.collectionName);
|
|
260
|
+
console.log(request.integrationId);
|
|
261
|
+
console.log(request.docBefore); // undefined for insert
|
|
262
|
+
console.log(request.docAfter); // undefined for delete
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Custom ID and specific integration
|
|
266
|
+
@trigger({ id: 'order-update', collection: 'orders', integrationId: 'my-postgres' })
|
|
267
|
+
async onOrderChange(request: TriggerRequest<Order>): Promise<void> {
|
|
268
|
+
if (request.mutationType === 'update') {
|
|
269
|
+
const before = request.docBefore;
|
|
270
|
+
const after = request.docAfter;
|
|
271
|
+
// Handle order update
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Positional arguments (legacy)
|
|
276
|
+
@trigger('user-deleted', 'users')
|
|
277
|
+
async onUserDeleted(request: TriggerRequest<User>): Promise<void> {
|
|
278
|
+
// Called for all mutation types on 'users' collection
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**TriggerOptions:**
|
|
284
|
+
- `id?: string` - Trigger ID (defaults to `ClassName.FunctionName`)
|
|
285
|
+
- `collection: string` - Collection name to watch
|
|
286
|
+
- `integrationId?: string` - Database integration (defaults to `built_in_db`)
|
|
287
|
+
- `mutationTypes?: ('insert' | 'update' | 'delete')[]` - Filter by mutation types
|
|
288
|
+
|
|
289
|
+
**TriggerRequest<T>:**
|
|
290
|
+
- `mutationType` - The type of mutation ('insert' | 'update' | 'delete')
|
|
291
|
+
- `docId` - Document ID
|
|
292
|
+
- `collectionName` - Collection name
|
|
293
|
+
- `integrationId` - Integration ID
|
|
294
|
+
- `docBefore?: T` - Document state before mutation (undefined for insert)
|
|
295
|
+
- `docAfter?: T` - Document state after mutation (undefined for delete)
|
|
296
|
+
|
|
297
|
+
## Schedulers (@scheduler)
|
|
298
|
+
|
|
299
|
+
Schedules periodic execution using cron expressions.
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { SquidService, scheduler, CronExpression } from '@squidcloud/backend';
|
|
303
|
+
|
|
304
|
+
export class MyService extends SquidService {
|
|
305
|
+
// Using cron string directly
|
|
306
|
+
@scheduler({ id: 'daily-cleanup', cron: '0 0 * * *' }) // Daily at midnight UTC
|
|
307
|
+
async cleanup(): Promise<void> {
|
|
308
|
+
console.log('Running cleanup');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Using predefined CronExpression enum
|
|
312
|
+
@scheduler({ id: 'hourly-sync', cron: CronExpression.EVERY_HOUR })
|
|
313
|
+
async hourlySync(): Promise<void> {
|
|
314
|
+
console.log('Running hourly sync');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
@scheduler({ id: 'weekday-morning', cron: CronExpression.MONDAY_TO_FRIDAY_AT_9AM })
|
|
318
|
+
async weekdayTask(): Promise<void> {
|
|
319
|
+
console.log('Running weekday morning task');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@scheduler({ id: 'frequent', cron: CronExpression.EVERY_5_MINUTES, exclusive: false })
|
|
323
|
+
async frequentTask(): Promise<void> {
|
|
324
|
+
// exclusive: false allows concurrent runs
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Common CronExpression values:**
|
|
330
|
+
- `EVERY_SECOND`, `EVERY_5_SECONDS`, `EVERY_10_SECONDS`, `EVERY_30_SECONDS`
|
|
331
|
+
- `EVERY_MINUTE`, `EVERY_5_MINUTES`, `EVERY_10_MINUTES`, `EVERY_30_MINUTES`
|
|
332
|
+
- `EVERY_HOUR`, `EVERY_2_HOURS`, `EVERY_3_HOURS`, etc.
|
|
333
|
+
- `EVERY_DAY_AT_MIDNIGHT`, `EVERY_DAY_AT_NOON`, `EVERY_DAY_AT_1AM`, etc.
|
|
334
|
+
- `EVERY_WEEKDAY`, `EVERY_WEEKEND`, `EVERY_WEEK`
|
|
335
|
+
- `MONDAY_TO_FRIDAY_AT_9AM`, `MONDAY_TO_FRIDAY_AT_5PM`, etc.
|
|
336
|
+
- `EVERY_1ST_DAY_OF_MONTH_AT_MIDNIGHT`, `EVERY_QUARTER`, `EVERY_YEAR`
|
|
337
|
+
|
|
338
|
+
### Client Management
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const schedulers = squid.schedulers;
|
|
342
|
+
|
|
343
|
+
// List all
|
|
344
|
+
const all = await schedulers.list();
|
|
345
|
+
|
|
346
|
+
// Enable/disable
|
|
347
|
+
await schedulers.enable('daily-cleanup');
|
|
348
|
+
await schedulers.enable(['scheduler-1', 'scheduler-2']);
|
|
349
|
+
|
|
350
|
+
await schedulers.disable('hourly-sync');
|
|
351
|
+
await schedulers.disable(['scheduler-1', 'scheduler-2']);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Rate Limiting (@limits)
|
|
355
|
+
|
|
356
|
+
Apply rate limits and quotas to functions.
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import { SquidService, executable, limits } from '@squidcloud/backend';
|
|
360
|
+
|
|
361
|
+
export class MyService extends SquidService {
|
|
362
|
+
// Simple rate limit (5 QPS globally)
|
|
363
|
+
@limits({ rateLimit: 5 })
|
|
364
|
+
@executable()
|
|
365
|
+
async limited(): Promise<void> {}
|
|
366
|
+
|
|
367
|
+
// Quota (100 calls/month per user)
|
|
368
|
+
@limits({ quotaLimit: { value: 100, scope: 'user', renewPeriod: 'monthly' } })
|
|
369
|
+
@executable()
|
|
370
|
+
async quotaLimited(): Promise<void> {}
|
|
371
|
+
|
|
372
|
+
// Multiple limits
|
|
373
|
+
@limits({
|
|
374
|
+
rateLimit: [
|
|
375
|
+
{ value: 100, scope: 'global' },
|
|
376
|
+
{ value: 10, scope: 'user' }
|
|
377
|
+
],
|
|
378
|
+
quotaLimit: [
|
|
379
|
+
{ value: 10000, scope: 'global', renewPeriod: 'monthly' },
|
|
380
|
+
{ value: 500, scope: 'user', renewPeriod: 'weekly' }
|
|
381
|
+
]
|
|
382
|
+
})
|
|
383
|
+
@executable()
|
|
384
|
+
async multiLimited(): Promise<void> {}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Scopes:** `'global'`, `'user'`, `'ip'`
|
|
389
|
+
**Periods:** `'hourly'`, `'daily'`, `'weekly'`, `'monthly'`, `'quarterly'`, `'annually'`
|
|
390
|
+
|
|
391
|
+
## Client Connection State (@clientConnectionStateHandler)
|
|
392
|
+
|
|
393
|
+
Handle client connection and disconnection events.
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
import { SquidService, clientConnectionStateHandler, ClientConnectionState } from '@squidcloud/backend';
|
|
397
|
+
import { ClientId } from '@squidcloud/client';
|
|
398
|
+
|
|
399
|
+
export class MyService extends SquidService {
|
|
400
|
+
@clientConnectionStateHandler()
|
|
401
|
+
async handleConnectionState(
|
|
402
|
+
clientId: ClientId,
|
|
403
|
+
state: ClientConnectionState
|
|
404
|
+
): Promise<void> {
|
|
405
|
+
if (state === 'CONNECTED') {
|
|
406
|
+
console.log('Client connected:', clientId);
|
|
407
|
+
} else if (state === 'DISCONNECTED') {
|
|
408
|
+
console.log('Client disconnected:', clientId);
|
|
409
|
+
} else if (state === 'REMOVED') {
|
|
410
|
+
console.log('Client removed:', clientId);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**ClientConnectionState values:**
|
|
417
|
+
- `'CONNECTED'` - Client just connected
|
|
418
|
+
- `'DISCONNECTED'` - Client disconnected but ID still retained
|
|
419
|
+
- `'REMOVED'` - Client disconnected and ID removed
|
|
420
|
+
|
|
421
|
+
## Using Squid Client in Backend
|
|
422
|
+
|
|
423
|
+
The pre-initialized `this.squid` client has full permissions:
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
export class MyService extends SquidService {
|
|
427
|
+
@executable()
|
|
428
|
+
async aggregateStats(userId: string): Promise<Stats> {
|
|
429
|
+
// this.squid has API key permissions - full access
|
|
430
|
+
const orders = await this.squid.collection('orders')
|
|
431
|
+
.query()
|
|
432
|
+
.eq('userId', userId)
|
|
433
|
+
.snapshot();
|
|
434
|
+
|
|
435
|
+
return { totalOrders: orders.data.length };
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## File Handling
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
// Receiving files in backend functions
|
|
444
|
+
@executable()
|
|
445
|
+
async processFile(file: SquidFile): Promise<Result> {
|
|
446
|
+
console.log(file.originalName); // Original filename
|
|
447
|
+
console.log(file.size); // File size in bytes
|
|
448
|
+
console.log(file.mimetype); // MIME type
|
|
449
|
+
const content = new TextDecoder().decode(file.data); // Read as text
|
|
450
|
+
return { processed: true };
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
For AI-related decorators (`@aiFunction`, `@secureAiAgent`, etc.), see [ai.md](ai.md).
|
|
455
|
+
For security decorators (`@secureDatabase`, `@secureCollection`, etc.), see [security.md](security.md).
|
|
456
|
+
|
|
457
|
+
## Best Practices
|
|
458
|
+
|
|
459
|
+
1. **Don't store state in class properties** - Use collections instead (instances may restart or scale)
|
|
460
|
+
2. **Validate input in executables** - Always check auth and validate parameters before processing
|
|
461
|
+
3. **Never commit `.env` to git** - Contains credentials from Squid Console
|
|
462
|
+
4. **Use options object for decorators** - Prefer `@trigger({ collection: 'users' })` over positional args (legacy)
|