@squidcloud/cli 1.0.415 → 1.0.417

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 CHANGED
@@ -30556,7 +30556,7 @@ function exitWithError(...messages) {
30556
30556
  /***/ ((module) => {
30557
30557
 
30558
30558
  "use strict";
30559
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.415","description":"The Squid CLI","main":"dist/index.js","scripts":{"start":"node dist/index.js","start-ts":"ts-node -r tsconfig-paths/register src/index.ts","prebuild":"rimraf dist","build":"webpack --mode=production","build:dev":"webpack --mode=development","lint":"eslint","link":"npm run build && chmod 755 dist/index.js && npm link","watch":"webpack --watch","deploy":"npm run build && npm pack --silent | xargs -I {} mv {} package.tgz && npm install -g package.tgz && rm -rf package.tgz","publish:public":"npm run build && npm publish --access public"},"files":["dist/**/*"],"bin":{"squid":"dist/index.js"},"keywords":[],"author":"","license":"ISC","engines":{"node":">=18.0.0"},"dependencies":{"@squidcloud/local-backend":"^1.0.415","adm-zip":"^0.5.16","copy-webpack-plugin":"^12.0.2","decompress":"^4.2.1","nodemon":"^3.1.9","terser-webpack-plugin":"^5.3.10","ts-loader":"^9.5.1","ts-node":"^10.9.2","tsconfig-paths":"^4.2.0","tsconfig-paths-webpack-plugin":"^4.1.0","webpack":"^5.101.3","zip-webpack-plugin":"^4.0.1"},"devDependencies":{"@types/adm-zip":"^0.5.7","@types/decompress":"^4.2.7","@types/node":"^20.19.9","terminal-link":"^3.0.0"}}');
30559
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.417","description":"The Squid CLI","main":"dist/index.js","scripts":{"start":"node dist/index.js","start-ts":"ts-node -r tsconfig-paths/register src/index.ts","prebuild":"rimraf dist","build":"webpack --mode=production","build:dev":"webpack --mode=development","lint":"eslint","link":"npm run build && chmod 755 dist/index.js && npm link","watch":"webpack --watch","deploy":"npm run build && npm pack --silent | xargs -I {} mv {} package.tgz && npm install -g package.tgz && rm -rf package.tgz","publish:public":"npm run build && npm publish --access public"},"files":["dist/**/*"],"bin":{"squid":"dist/index.js"},"keywords":[],"author":"","license":"ISC","engines":{"node":">=18.0.0"},"dependencies":{"@squidcloud/local-backend":"^1.0.417","adm-zip":"^0.5.16","copy-webpack-plugin":"^12.0.2","decompress":"^4.2.1","nodemon":"^3.1.9","terser-webpack-plugin":"^5.3.10","ts-loader":"^9.5.1","ts-node":"^10.9.2","tsconfig-paths":"^4.2.0","tsconfig-paths-webpack-plugin":"^4.1.0","webpack":"^5.101.3","zip-webpack-plugin":"^4.0.1"},"devDependencies":{"@types/adm-zip":"^0.5.7","@types/decompress":"^4.2.7","@types/node":"^20.19.9","terminal-link":"^3.0.0"}}');
30560
30560
 
30561
30561
  /***/ }),
30562
30562
 
@@ -15,6 +15,235 @@ Squid is a backend-as-a-service platform that provides:
15
15
  - **CLI** (`@squidcloud/cli`) - Local development and deployment tools
16
16
  - **Built-in integrations** - Databases, queues, storage, AI, APIs
17
17
 
18
+ ## Squid Architecture: The Three Parts
19
+
20
+ When developing with Squid, you work with three distinct but interconnected parts:
21
+
22
+ ### 1. Client (Frontend/External Services)
23
+
24
+ **What it is:** Any application that needs to interact with your Squid backend - web apps, mobile apps, desktop apps, or even other servers.
25
+
26
+ **How it works:**
27
+ - Initializes the Squid Client SDK (`@squidcloud/client`)
28
+ - Communicates with Squid functionality over HTTP/WebSocket
29
+ - Can interact with AI agents, modify agent settings, query databases, call backend functions, etc.
30
+ - Optionally uses authentication (OAuth2.0) for user-specific access
31
+ - Respects security rules defined in the backend
32
+
33
+ **Common use cases:**
34
+ ```typescript
35
+ // Web/mobile application
36
+ const squid = new Squid({
37
+ appId: 'your-app-id',
38
+ region: 'us-east-1.aws',
39
+ authProvider: { /* user auth */ }
40
+ });
41
+
42
+ // Interact with agents
43
+ const agent = squid.ai().agent('support-agent');
44
+ const response = await agent.ask('How do I reset my password?');
45
+
46
+ // Query databases
47
+ const users = await squid.collection('users').query().eq('active', true).snapshot();
48
+
49
+ // Call backend functions
50
+ const result = await squid.executeFunction('processPayment', paymentData);
51
+ ```
52
+
53
+ **Key point:** Clients have limited, controlled access based on security rules you define in the backend.
54
+
55
+ ### 2. Squid Backend (Your Server-Side Code)
56
+
57
+ **What it is:** TypeScript code that runs on Squid's infrastructure, containing your business logic, security rules, and integrations.
58
+
59
+ **How it works:**
60
+ - Contains services that extend `SquidService`
61
+ - Uses **decorators** to define functionality:
62
+ - `@executable()` - Backend functions callable from clients
63
+ - `@webhook()` - HTTP endpoints for external services
64
+ - `@trigger()` - React to database changes
65
+ - `@scheduler()` - Run code on a schedule (cron jobs)
66
+ - `@secureDatabase()`, `@secureCollection()` - Define who can access data
67
+ - `@secureAiAgent()` - Control agent access
68
+ - `@aiFunction()` - Functions that AI agents can call
69
+ - And many more decorators for security, rate limiting, etc.
70
+ - Has **full access** to all Squid functionality via pre-initialized `this.squid` client (with API key permissions)
71
+ - Deployed to Squid infrastructure using `squid deploy`
72
+
73
+ **Example backend service:**
74
+ ```typescript
75
+ import { SquidService, executable, scheduler, trigger, secureCollection } from '@squidcloud/backend';
76
+
77
+ export class MyService extends SquidService {
78
+ // Backend function callable from client
79
+ @executable()
80
+ async processPayment(amount: number, userId: string): Promise<PaymentResult> {
81
+ // Full access to Squid - this.squid has API key permissions
82
+ const user = await this.squid.collection('users').doc({ id: userId }).snapshot();
83
+
84
+ // Your business logic here
85
+ return { success: true, transactionId: '...' };
86
+ }
87
+
88
+ // React to database changes
89
+ @trigger({ id: 'new-user', collection: 'users', mutationTypes: ['insert'] })
90
+ async onNewUser(request: TriggerRequest<User>): Promise<void> {
91
+ await sendWelcomeEmail(request.docAfter);
92
+ }
93
+
94
+ // Scheduled task (cron job)
95
+ @scheduler({ id: 'daily-report', cron: '0 0 * * *' })
96
+ async generateDailyReport(): Promise<void> {
97
+ // Runs every day at midnight
98
+ const stats = await this.calculateStats();
99
+ await this.sendReport(stats);
100
+ }
101
+
102
+ // Security rule - who can read users collection
103
+ @secureCollection('users', 'read')
104
+ allowUserRead(context: QueryContext): boolean {
105
+ const userId = this.getUserAuth()?.userId;
106
+ // Only allow users to read their own data
107
+ return context.isSubqueryOf('id', '==', userId);
108
+ }
109
+
110
+ // Function that AI agents can call
111
+ @aiFunction('Gets order status', [
112
+ { name: 'orderId', type: 'string', required: true }
113
+ ])
114
+ async getOrderStatus({ orderId }: { orderId: string }): Promise<string> {
115
+ const order = await this.squid.collection('orders').doc({ id: orderId }).snapshot();
116
+ return order?.status || 'not found';
117
+ }
118
+ }
119
+ ```
120
+
121
+ **Key points:**
122
+ - Backend code has **full permissions** (API key access)
123
+ - Defines **what clients can and cannot do** through security decorators
124
+ - Contains **business logic** that shouldn't be exposed to clients
125
+ - Automatically deployed and scaled by Squid
126
+
127
+ ### 3. Squid Console (Web UI)
128
+
129
+ **What it is:** A web-based management interface at https://console.getsquid.ai/ for setting up and managing your Squid applications.
130
+
131
+ **What you can do in the Console:**
132
+ - **Organizations & Applications:**
133
+ - Create organizations (teams/workspaces)
134
+ - Create applications (projects)
135
+ - Manage API keys and secrets
136
+ - View application logs and metrics
137
+
138
+ - **AI Studio:**
139
+ - Create and configure AI agents visually
140
+ - Set up agent instructions, models, and guardrails
141
+ - Test agents in real-time
142
+ - Connect agents to functions and knowledge bases
143
+
144
+ - **Knowledge Bases:**
145
+ - Create knowledge bases for RAG (Retrieval Augmented Generation)
146
+ - Upload documents and manage contexts
147
+ - Configure embedding models
148
+
149
+ - **Integrations:**
150
+ - Connect databases (PostgreSQL, MySQL, MongoDB, etc.)
151
+ - Connect SaaS services (Stripe, Slack, etc.)
152
+ - Configure OAuth integrations
153
+ - Set up storage providers (AWS S3, etc.)
154
+ - Configure message queues (Kafka, etc.)
155
+
156
+ - **Monitoring & Debugging:**
157
+ - View real-time logs
158
+ - Monitor API usage
159
+ - Debug agent conversations
160
+ - Track performance metrics
161
+
162
+ **Console vs SDK:**
163
+ - **Console is great for:** Initial setup, visual agent configuration, quick testing, monitoring
164
+ - **SDK is more powerful for:** Programmatic control, CI/CD pipelines, dynamic configuration, complex automation
165
+
166
+ **Example: Everything in Console can be done via SDK (except creating orgs/apps):**
167
+
168
+ ```typescript
169
+ // Console: Click to create an agent with AI Studio
170
+ // SDK equivalent:
171
+ const agent = squid.ai().agent('my-agent');
172
+ await agent.upsert({
173
+ description: 'Customer support agent',
174
+ options: {
175
+ model: 'gpt-4o',
176
+ instructions: 'You are a helpful support agent...'
177
+ }
178
+ });
179
+
180
+ // Console: Upload document to knowledge base
181
+ // SDK equivalent:
182
+ const kb = squid.ai().knowledgeBase('docs');
183
+ await kb.upsertContext({
184
+ contextId: 'doc-1',
185
+ text: 'Product documentation...'
186
+ }, pdfFile);
187
+
188
+ // Console: Configure database integration
189
+ // SDK equivalent:
190
+ const integrations = squid.admin().integrations();
191
+ await integrations.upsertIntegration({
192
+ integrationId: 'my-db',
193
+ type: 'postgres',
194
+ connectionString: 'postgresql://...'
195
+ });
196
+ ```
197
+
198
+ **Key point:** The Console provides a visual interface for management, but everything (except org/app creation) can be automated through the SDK for more flexibility and control.
199
+
200
+ ### How They Work Together
201
+
202
+ ```
203
+ ┌─────────────────────┐
204
+ │ CLIENT (Web/ │
205
+ │ Mobile/Server) │
206
+ │ │
207
+ │ - Squid SDK init │
208
+ │ - User auth │
209
+ │ - Limited access │
210
+ └──────────┬──────────┘
211
+
212
+ │ HTTP/WebSocket
213
+
214
+
215
+ ┌─────────────────────┐
216
+ │ SQUID BACKEND │
217
+ │ (Your Code) │
218
+ │ │
219
+ │ - SquidService │
220
+ │ - Decorators │
221
+ │ - Full permissions │
222
+ │ - Business logic │
223
+ │ - Security rules │
224
+ └──────────┬──────────┘
225
+
226
+ │ Deployed via CLI
227
+ │ or managed via
228
+
229
+ ┌─────────────────────┐
230
+ │ SQUID CONSOLE │
231
+ │ (Web UI) │
232
+ │ │
233
+ │ - Manage apps │
234
+ │ - AI Studio │
235
+ │ - Integrations │
236
+ │ - Monitoring │
237
+ └─────────────────────┘
238
+ ```
239
+
240
+ **Development workflow:**
241
+ 1. Create application in **Squid Console**
242
+ 2. Develop backend services in **Squid Backend** (local development with `squid start`)
243
+ 3. Deploy backend to Squid infrastructure (`squid deploy`)
244
+ 4. Build **Client** applications that use the Squid Client SDK
245
+ 5. Use **Console** for monitoring and management, or use **SDK** for programmatic control
246
+
18
247
  ## CLI Commands
19
248
 
20
249
  ### Installation
@@ -24,6 +253,7 @@ npm install -g @squidcloud/cli
24
253
 
25
254
  ### `squid init <project-name>`
26
255
  Creates new backend project with `.env` and example service.
256
+ The backend project has access to an already initialized client SDK with API key (full permissions)
27
257
 
28
258
  ```bash
29
259
  squid init backend --appId YOUR_APP_ID --apiKey YOUR_API_KEY --environmentId dev --squidDeveloperId YOUR_DEV_ID --region us-east-1.aws
@@ -66,7 +296,7 @@ The Squid Client SDK can be instantiated in various environments:
66
296
  - **Mobile applications** (React Native, etc.)
67
297
  - **Desktop applications** (Electron, etc.)
68
298
 
69
- **Important:** When writing backend code that runs on Squid's infrastructure, the Squid client is **already initialized and available** for you (see Backend SDK section). You don't need to manually create a new instance.
299
+ **Important:** When writing backend code that runs on Squid's infrastructure, the Squid client is **already initialized and available with API key and full permissions** for you (see Backend SDK section). You don't need to manually create a new instance.
70
300
 
71
301
  ### Initialization
72
302
 
@@ -286,6 +516,13 @@ userDoc.snapshots().subscribe(data => {
286
516
  // Get cached data (no server fetch)
287
517
  const cached = userDoc.peek();
288
518
 
519
+ // Check if document has data populated
520
+ if (userDoc.hasData) {
521
+ console.log('Document is loaded');
522
+ // Access data directly (with defensive copy)
523
+ console.log(userDoc.data);
524
+ }
525
+
289
526
  // Bulk operations
290
527
  await users.insertMany([
291
528
  { id: 'user-1', data: { name: 'Alice' } },
@@ -368,11 +605,16 @@ users.query()
368
605
  snapshot.data.forEach(doc => console.log(doc.data));
369
606
  });
370
607
 
371
- // Pattern matching
608
+ // Pattern matching (CASE-INSENSITIVE by default)
372
609
  const results = await users.query()
373
610
  .like('email', '%.com') // case-insensitive by default
374
611
  .snapshot();
375
612
 
613
+ // Case-sensitive pattern matching
614
+ const caseSensitive = await users.query()
615
+ .like('name', 'John%', true) // third parameter: caseSensitive = true
616
+ .snapshot();
617
+
376
618
  // Array operators
377
619
  const tagged = await posts.query()
378
620
  .in('category', ['tech', 'news'])
@@ -799,6 +1041,26 @@ await myAgent.delete();
799
1041
  // List all agents
800
1042
  const agents = await squid.ai().listAgents();
801
1043
  agents.forEach(agent => console.log(`${agent.id}: ${agent.description}`));
1044
+
1045
+ // Manage agent API keys
1046
+ const apiKey = await myAgent.regenerateApiKey();
1047
+ console.log('New API key:', apiKey);
1048
+
1049
+ const existingKey = await myAgent.getApiKey();
1050
+ console.log('Current API key:', existingKey);
1051
+
1052
+ // Update agent options at specific path
1053
+ await myAgent.setAgentOptionInPath('temperature', 0.9);
1054
+ await myAgent.setAgentOptionInPath('options.maxTokens', 2000);
1055
+
1056
+ // Update connected agents
1057
+ await myAgent.updateConnectedAgents([
1058
+ { agentId: 'helper-agent', description: 'Helps with tasks' }
1059
+ ]);
1060
+
1061
+ // Update or delete custom guardrails
1062
+ await myAgent.updateCustomGuardrails('Never reveal sensitive information');
1063
+ await myAgent.deleteCustomGuardrail();
802
1064
  ```
803
1065
 
804
1066
  **Agent Lifecycle:**
@@ -1002,9 +1264,13 @@ chatObs.subscribe(text => {
1002
1264
  const response = await agent.ask('Question?', { /* same options */ });
1003
1265
 
1004
1266
  // Ask with annotations (includes file references, citations)
1005
- const result = await agent.askWithAnnotations('Question?');
1267
+ const result = await agent.askWithAnnotations('Question?', { /* same options as ask */ });
1006
1268
  console.log(result.responseString);
1007
- console.log(result.annotations);
1269
+ console.log(result.annotations); // File references, sources, etc.
1270
+
1271
+ // Ask asynchronously (doesn't wait for response, uses job system)
1272
+ await agent.askAsync('Long running task', 'job-id-123', { /* same options */ });
1273
+ // Check job status later with squid.job().getJob('job-id-123')
1008
1274
 
1009
1275
  // Voice responses
1010
1276
  const voiceResult = await agent.askWithVoiceResponse('Hello', {
@@ -1018,6 +1284,19 @@ const transcribeResult = await agent.transcribeAndChat(audioFile);
1018
1284
  console.log(transcribeResult.transcribedPrompt);
1019
1285
  transcribeResult.responseStream.subscribe(text => console.log(text));
1020
1286
 
1287
+ // Transcribe audio and ask (non-streaming)
1288
+ const askResult = await agent.transcribeAndAsk(audioFile, { /* ask options */ });
1289
+ console.log(askResult.transcribedPrompt);
1290
+ console.log(askResult.response);
1291
+
1292
+ // Transcribe audio and get voice response
1293
+ const voiceResponse = await agent.transcribeAndAskWithVoiceResponse(audioFile, {
1294
+ voiceOptions: { modelName: 'tts-1', voice: 'alloy' }
1295
+ });
1296
+ console.log(voiceResponse.transcribedPrompt);
1297
+ console.log(voiceResponse.responseString);
1298
+ console.log(voiceResponse.voiceResponseFile);
1299
+
1021
1300
  // Get chat history
1022
1301
  const history = await agent.getChatHistory('memory-id-123');
1023
1302
 
@@ -1068,6 +1347,22 @@ export class MyService extends SquidService {
1068
1347
  ```typescript
1069
1348
  const kb = squid.ai().knowledgeBase('product-docs');
1070
1349
 
1350
+ // Get knowledge base details
1351
+ const kbDetails = await kb.getKnowledgeBase();
1352
+ console.log(kbDetails);
1353
+
1354
+ // Create or update knowledge base
1355
+ await kb.upsertKnowledgeBase({
1356
+ description: 'Product documentation knowledge base',
1357
+ // ...other options
1358
+ });
1359
+
1360
+ // Delete knowledge base
1361
+ await kb.delete();
1362
+
1363
+ // List all knowledge bases
1364
+ const allKBs = await squid.ai().listKnowledgeBases();
1365
+
1071
1366
  // Upsert context (with or without file)
1072
1367
  await kb.upsertContext({
1073
1368
  contextId: 'doc-123',
@@ -1118,6 +1413,25 @@ await kb.deleteContexts(['doc-1', 'doc-2']);
1118
1413
  const allKBs = await squid.ai().listKnowledgeBases();
1119
1414
  ```
1120
1415
 
1416
+ ### AI - Files
1417
+
1418
+ Manage files stored with AI providers (OpenAI, etc.) for use with agents.
1419
+
1420
+ ```typescript
1421
+ const aiFiles = squid.ai().files('openai'); // provider: 'openai' | 'anthropic' | etc.
1422
+
1423
+ // Upload file to AI provider
1424
+ const fileId = await aiFiles.uploadFile({
1425
+ file: myFile, // Browser File object
1426
+ purpose: 'assistants' // Purpose for the file
1427
+ });
1428
+ console.log('Uploaded file ID:', fileId);
1429
+
1430
+ // Delete file from AI provider
1431
+ const deleted = await aiFiles.deleteFile(fileId);
1432
+ console.log('File deleted:', deleted);
1433
+ ```
1434
+
1121
1435
  ### AI - Image & Audio
1122
1436
 
1123
1437
  ```typescript
@@ -1182,6 +1496,84 @@ const apiResult = await squid.ai().executeAiApiCall(
1182
1496
  );
1183
1497
  ```
1184
1498
 
1499
+ ### AI - Document Extraction & PDF Creation
1500
+
1501
+ Extract structured data from documents and create PDFs programmatically.
1502
+
1503
+ ```typescript
1504
+ const extraction = squid.extraction();
1505
+
1506
+ // Extract data from document file
1507
+ const extractedData = await extraction.extractDataFromDocumentFile(
1508
+ myPdfFile, // File object
1509
+ {
1510
+ schema: {
1511
+ fields: [
1512
+ { name: 'invoiceNumber', type: 'string', description: 'Invoice number' },
1513
+ { name: 'total', type: 'number', description: 'Total amount' },
1514
+ { name: 'date', type: 'date', description: 'Invoice date' }
1515
+ ]
1516
+ }
1517
+ }
1518
+ );
1519
+ console.log(extractedData);
1520
+
1521
+ // Extract data from document URL
1522
+ const urlData = await extraction.extractDataFromDocumentUrl(
1523
+ 'https://example.com/document.pdf',
1524
+ {
1525
+ schema: {
1526
+ fields: [
1527
+ { name: 'title', type: 'string' },
1528
+ { name: 'author', type: 'string' }
1529
+ ]
1530
+ }
1531
+ }
1532
+ );
1533
+
1534
+ // Create PDF from HTML or markdown
1535
+ const pdfResponse = await extraction.createPdf({
1536
+ content: '<h1>Hello</h1><p>This is a PDF</p>',
1537
+ contentType: 'html', // or 'markdown'
1538
+ options: {
1539
+ pageSize: 'A4',
1540
+ margin: { top: '1cm', bottom: '1cm', left: '1cm', right: '1cm' }
1541
+ }
1542
+ });
1543
+ console.log('PDF created:', pdfResponse.url);
1544
+ ```
1545
+
1546
+ **Use cases:**
1547
+ - Invoice/receipt processing
1548
+ - Form data extraction
1549
+ - PDF report generation
1550
+ - Document digitization
1551
+ - Automated data entry
1552
+
1553
+ ### AI - Application Settings
1554
+
1555
+ Manage AI provider settings and API keys for your application.
1556
+
1557
+ ```typescript
1558
+ const aiClient = squid.ai();
1559
+
1560
+ // Get application AI settings
1561
+ const settings = await aiClient.getApplicationAiSettings();
1562
+ console.log(settings);
1563
+
1564
+ // Set application AI settings
1565
+ await aiClient.setApplicationAiSettings({
1566
+ defaultModel: 'gpt-4o',
1567
+ // ... other settings
1568
+ });
1569
+
1570
+ // Set AI provider API key secret
1571
+ await aiClient.setAiProviderApiKeySecret(
1572
+ 'openai', // providerType: 'openai' | 'anthropic' | 'google' | etc.
1573
+ 'OPENAI_API_KEY' // secret key name from secrets manager
1574
+ );
1575
+ ```
1576
+
1185
1577
  ### Storage
1186
1578
 
1187
1579
  ```typescript
@@ -1208,6 +1600,34 @@ await storage.deleteFile('/documents/report.pdf');
1208
1600
  await storage.deleteFiles(['/docs/file1.pdf', '/docs/file2.pdf']);
1209
1601
  ```
1210
1602
 
1603
+ ### External OAuth Integration
1604
+
1605
+ Manage OAuth tokens for external integrations. Squid automatically handles token refresh when tokens expire.
1606
+
1607
+ ```typescript
1608
+ const externalAuth = squid.externalAuth('google-oauth-integration');
1609
+
1610
+ // Save authorization code (exchange for access token)
1611
+ const tokenResponse = await externalAuth.saveAuthCode(
1612
+ 'authorization-code-from-oauth-flow',
1613
+ 'user-identifier' // Unique identifier for this user
1614
+ );
1615
+ console.log('Access token:', tokenResponse.accessToken);
1616
+ console.log('Refresh token:', tokenResponse.refreshToken);
1617
+ console.log('Expires at:', tokenResponse.expiresAt);
1618
+
1619
+ // Get access token (auto-refreshes if expired)
1620
+ const token = await externalAuth.getAccessToken('user-identifier');
1621
+ console.log('Current access token:', token.accessToken);
1622
+ ```
1623
+
1624
+ **Use cases:**
1625
+ - Google Drive/Calendar integration
1626
+ - GitHub OAuth
1627
+ - Slack OAuth
1628
+ - Any external service requiring OAuth 2.0
1629
+ - Squid handles token refresh automatically
1630
+
1211
1631
  ### Queues
1212
1632
 
1213
1633
  ```typescript
@@ -1240,13 +1660,22 @@ try {
1240
1660
  lock.release(); // Note: release() is synchronous
1241
1661
  }
1242
1662
 
1243
- // Check if released
1244
- console.log(lock.isReleased()); // true after release
1663
+ // Acquire with auto-release timeout (maxHoldTimeMillis)
1664
+ const lockWithTimeout = await squid.acquireLock('my-mutex', {
1665
+ maxHoldTimeMillis: 30000 // Auto-release after 30 seconds
1666
+ });
1667
+
1668
+ // Access lock properties
1669
+ console.log(lock.resourceId); // The mutex name: 'payment-processing'
1670
+ console.log(lock.lockId); // Unique ID for this lock instance
1671
+ console.log(lock.isReleased()); // Check if released: true/false
1245
1672
 
1246
1673
  // Observe release (RxJS Observable)
1247
1674
  const sub = lock.observeRelease().subscribe(() => {
1248
1675
  console.log('Lock was released');
1249
1676
  });
1677
+ // Don't forget to unsubscribe when done
1678
+ sub.unsubscribe();
1250
1679
 
1251
1680
  // Automatic release with withLock (recommended)
1252
1681
  const result = await squid.withLock('payment-processing', async (lock) => {
@@ -1261,6 +1690,7 @@ const result = await squid.withLock('payment-processing', async (lock) => {
1261
1690
  **Important notes:**
1262
1691
  - Lock is automatically released if WebSocket connection is lost
1263
1692
  - If lock is already held by another client, `acquireLock()` will reject
1693
+ - `maxHoldTimeMillis` option automatically releases lock after specified duration
1264
1694
  - Use `@secureDistributedLock(mutexName?)` decorator to secure lock access
1265
1695
  - Without API key, you must define security rules for locks
1266
1696
 
@@ -1269,19 +1699,32 @@ const result = await squid.withLock('payment-processing', async (lock) => {
1269
1699
  ```typescript
1270
1700
  const api = squid.api();
1271
1701
 
1272
- // HTTP methods
1273
- const customer = await api.get<Customer>('stripe-api', 'get-customer', {
1702
+ // HTTP methods - All return HttpResponse<T> with status, headers, and body
1703
+ const customerResponse = await api.get<Customer>('stripe-api', 'get-customer', {
1274
1704
  pathParams: { customerId: 'cus_123' },
1275
1705
  queryParams: { expand: 'subscriptions' }
1276
1706
  });
1707
+ // Access response details
1708
+ console.log(customerResponse.status); // HTTP status code
1709
+ console.log(customerResponse.headers); // Response headers
1710
+ console.log(customerResponse.body); // Parsed response body
1277
1711
 
1278
- const charge = await api.post<Charge, ChargeRequest>(
1712
+ const chargeResponse = await api.post<Charge, ChargeRequest>(
1279
1713
  'stripe-api',
1280
1714
  'create-charge',
1281
1715
  { amount: 1000, currency: 'usd' },
1282
1716
  { headers: { 'Idempotency-Key': 'unique' } }
1283
1717
  );
1284
1718
 
1719
+ // Generic request method (for custom HTTP methods or complex requests)
1720
+ const response = await api.request<ResponseType, RequestType>(
1721
+ 'integration-id',
1722
+ 'endpoint-id',
1723
+ requestBody,
1724
+ { headers: {}, queryParams: {} },
1725
+ 'POST' // or 'GET', 'PUT', 'PATCH', 'DELETE'
1726
+ );
1727
+
1285
1728
  // Other methods: put, patch, delete
1286
1729
  await api.put(integrationId, endpointId, body, options);
1287
1730
  await api.patch(integrationId, endpointId, body, options);
@@ -1354,6 +1797,35 @@ const metrics = await obs.queryMetrics({
1354
1797
  await obs.flush();
1355
1798
  ```
1356
1799
 
1800
+ ### Custom Notifications
1801
+
1802
+ Send custom messages between clients for real-time coordination.
1803
+
1804
+ ```typescript
1805
+ const notifications = squid.getNotificationClient();
1806
+
1807
+ // Observe incoming notifications
1808
+ const subscription = notifications.observeNotifications().subscribe(payload => {
1809
+ console.log('Received notification:', payload);
1810
+ // payload can be any serializable data
1811
+ });
1812
+
1813
+ // Publish notification to specific clients - can be done only if Squid was initialized with API key.
1814
+ await notifications.publishNotification(
1815
+ { type: 'update', message: 'Data changed' }, // payload
1816
+ ['client-id-1', 'client-id-2'] // target client IDs
1817
+ );
1818
+
1819
+ // Unsubscribe when done
1820
+ subscription.unsubscribe();
1821
+ ```
1822
+
1823
+ **Use cases:**
1824
+ - Real-time coordination between users
1825
+ - Custom event notifications
1826
+ - Client-to-client messaging
1827
+ - Broadcast updates to specific users
1828
+
1357
1829
  ### Jobs
1358
1830
 
1359
1831
  Jobs allow you to track the status of long-running asynchronous operations. Each job has a unique ID that can be used to query its status or wait for completion.
@@ -1406,6 +1878,24 @@ await integrations.upsertIntegration({
1406
1878
  // Delete
1407
1879
  await integrations.delete('old-integration');
1408
1880
  await integrations.deleteMany(['int-1', 'int-2']);
1881
+
1882
+ // Get integration schema
1883
+ const schema = await integrations.getIntegrationSchema<MySchemaType>('postgres-db');
1884
+ console.log(schema);
1885
+
1886
+ // Set integration schema
1887
+ await integrations.setIntegrationSchema('postgres-db', {
1888
+ collections: [
1889
+ {
1890
+ name: 'users',
1891
+ fields: [
1892
+ { name: 'id', type: 'string', primaryKey: true },
1893
+ { name: 'email', type: 'string' },
1894
+ { name: 'name', type: 'string' }
1895
+ ]
1896
+ }
1897
+ ]
1898
+ });
1409
1899
  ```
1410
1900
 
1411
1901
  ### Admin - Secrets
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squidcloud/cli",
3
- "version": "1.0.415",
3
+ "version": "1.0.417",
4
4
  "description": "The Squid CLI",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -28,7 +28,7 @@
28
28
  "node": ">=18.0.0"
29
29
  },
30
30
  "dependencies": {
31
- "@squidcloud/local-backend": "^1.0.415",
31
+ "@squidcloud/local-backend": "^1.0.417",
32
32
  "adm-zip": "^0.5.16",
33
33
  "copy-webpack-plugin": "^12.0.2",
34
34
  "decompress": "^4.2.1",