@squidcloud/cli 1.0.449 → 1.0.451

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.
@@ -18,7 +18,7 @@ Squid is a backend-as-a-service platform that provides:
18
18
  - **[client.md](reference/client.md)** → client SDK, initialization, setup, auth, login, tokens, OAuth, appId, region, environmentId, apiKey, authProvider, getToken, setAuthProvider, Squid client, frontend, collection, executeFunction, executeFunctionWithHeaders, getWebhookUrl, externalAuth, saveAuthCode, getAccessToken, storage, uploadFile, downloadUrl, queues, produce, consume, distributed locks, acquireLock, withLock, web, aiSearch, getUrlContent, createShortUrl, jobs, getJob, awaitJob, observability, metrics, reportMetric, queryMetrics, notifications, publishNotification, observeNotifications
19
19
  - **[console.md](reference/console.md)** → Squid Console, web UI, organizations, applications, AI Studio, knowledge bases, integrations, monitoring, logs, API keys, secrets, testing, debugging, profile settings, management API keys
20
20
  - **[ai.md](reference/ai.md)** → AI agents, chat, ask, askWithAnnotations, askAsync, askWithVoiceResponse, transcribeAndChat, transcribeAndAsk, knowledge bases, RAG, embeddings, image generation, audio, transcription, text-to-speech, TTS, connectedAgents, connectedIntegrations, connectedKnowledgeBases, @aiFunction, @secureAiAgent, @secureAiQuery, memory, memoryOptions, voiceOptions, OpenAI, Anthropic, Gemini, Grok, DALL-E, Whisper, MCP, @mcpServer, @mcpTool, executeAiQuery, executeAiApiCall, extraction, createPdf, upsert agent, listAgents
21
- - **[databases.md](reference/databases.md)** → collections, documents, queries, subscriptions, snapshots, insert, update, delete, CRUD, real-time, dereference, pagination, transactions, query operators, eq, neq, gt, gte, lt, lte, like, in, nin, arrayIncludesSome, arrayIncludesAll, sortBy, limit, join queries, OR queries, @trigger, native queries, SQL, MongoDB, Elasticsearch, incrementInPath, decrementInPath, watch changes, doc()
21
+ - **[databases.md](reference/databases.md)** → collections, documents, queries, subscriptions, snapshots, insert, update, delete, CRUD, real-time, dereference, pagination, transactions, query operators, eq, neq, gt, gte, lt, lte, like, in, nin, arrayIncludesSome, arrayIncludesAll, sortBy, limit, join queries, OR queries, @trigger, native queries, SQL, MongoDB, Elasticsearch, incrementInPath, decrementInPath, watch changes, doc(), projectFields, field projection, __docId__, __id
22
22
  - **[backend.md](reference/backend.md)** → SquidService, @executable, @webhook, @trigger, TriggerRequest, @scheduler, @limits, rate limiting, quotas, decorators, backend functions, WebhookRequest, CronExpression, cron, file handling, SquidFile, getUserAuth, isAuthenticated, assertIsAuthenticated, createWebhookResponse, this.squid, this.secrets, @clientConnectionStateHandler, CLI, squid init, squid start, squid deploy, squid build, project structure
23
23
  - **[security.md](reference/security.md)** → security rules, @secureDatabase, @secureCollection, @secureTopic, @secureStorage, @secureApi, @secureNativeQuery, @secureAiQuery, @secureAiAgent, @secureDistributedLock, @secureGraphQL, QueryContext, MutationContext, isSubqueryOf, affectsPath, permissions, authorization, row-level security, role-based access
24
24
  - **[admin.md](reference/admin.md)** → ManagementClient, management API keys, organizations, applications, programmatic management, CI/CD, automation, integrations admin, secrets admin, upsertIntegration, discoverDataConnectionSchema, testDataConnection, createOrganization, createApplication
@@ -393,8 +393,8 @@ export class MyService extends SquidService {
393
393
  Handle client connection and disconnection events.
394
394
 
395
395
  ```typescript
396
- import { SquidService, clientConnectionStateHandler, ClientConnectionState } from '@squidcloud/backend';
397
- import { ClientId } from '@squidcloud/client';
396
+ import { SquidService, clientConnectionStateHandler } from '@squidcloud/backend';
397
+ import { ClientConnectionState, ClientId } from '@squidcloud/client';
398
398
 
399
399
  export class MyService extends SquidService {
400
400
  @clientConnectionStateHandler()
@@ -11,6 +11,7 @@ Squid provides database functionality similar to Firestore but more powerful, wi
11
11
  - OR Queries
12
12
  - Join Queries
13
13
  - Dereference
14
+ - Field Projection
14
15
  - Pagination
15
16
  - Watch Changes
16
17
  - Transactions
@@ -314,6 +315,144 @@ const userData = await users.query()
314
315
  // - You need DocumentReference methods like .update() or .delete()
315
316
  ```
316
317
 
318
+ ## Field Projection
319
+
320
+ Return only specific fields from queries to reduce bandwidth and improve performance.
321
+
322
+ ```typescript
323
+ // Basic usage
324
+ const results = await users.query()
325
+ .projectFields(['name', 'email'])
326
+ .dereference()
327
+ .snapshot();
328
+
329
+ // Works with all query methods
330
+ const results = await users.query()
331
+ .eq('status', 'active')
332
+ .sortBy('name')
333
+ .limit(50)
334
+ .projectFields(['name', 'email', 'status'])
335
+ .dereference()
336
+ .snapshot();
337
+ ```
338
+
339
+ ### Always-Included Fields
340
+
341
+ These fields are **always** included in results regardless of projection:
342
+
343
+ | Field | Present On | Description |
344
+ |-------|------------|-------------|
345
+ | `__docId__` | All integrations | JSON-stringified document identifier |
346
+ | `__id` | `built_in_db` only | Primary key value |
347
+
348
+ For **composite primary keys**, individual key fields are automatically spread to the top level:
349
+ ```typescript
350
+ // Document with composite PK (pk1, pk2)
351
+ // Result includes: { name: 'Alice', __docId__: '{"pk1":"a","pk2":1}', pk1: 'a', pk2: 1 }
352
+ ```
353
+
354
+ ### Nested Fields
355
+
356
+ Use dot notation for nested paths:
357
+ ```typescript
358
+ const results = await users.query()
359
+ .projectFields(['name', 'address.city', 'address.zip'])
360
+ .dereference()
361
+ .snapshot();
362
+ // Result: { name: 'Alice', address: { city: 'NYC', zip: '10001' } }
363
+ // Other address fields NOT included
364
+ ```
365
+
366
+ ### Validation Rules
367
+
368
+ **Filter fields must be projected:**
369
+ ```typescript
370
+ // ERROR: Cannot filter by 'email' not in projectFields
371
+ users.query().eq('email', 'test@example.com').projectFields(['name']);
372
+
373
+ // CORRECT: Include filter field
374
+ users.query().eq('email', 'test@example.com').projectFields(['name', 'email']);
375
+ ```
376
+
377
+ **Sort fields must be projected:**
378
+ ```typescript
379
+ // ERROR: Cannot sort by 'email' not in projectFields
380
+ users.query().sortBy('email').projectFields(['name']);
381
+
382
+ // CORRECT: Include sort field
383
+ users.query().sortBy('email').projectFields(['name', 'email']);
384
+ ```
385
+
386
+ **Exception:** `__docId__` can always be used for filtering/sorting without being in projection:
387
+ ```typescript
388
+ // ALLOWED: __docId__ is always available
389
+ users.query().where('__docId__', '>=', 'user_100').projectFields(['name']);
390
+ users.query().sortBy('__docId__').projectFields(['name']);
391
+ ```
392
+
393
+ **Composite conditions must use projected fields:**
394
+ ```typescript
395
+ // ERROR: Cannot filter by 'email' not in projectFields
396
+ users.query().projectFields(['name']).addCompositeCondition([{ fieldName: 'email', operator: '>=', value: 'a' }]);
397
+
398
+ // ALLOWED: __docId__ works without projection
399
+ users.query().projectFields(['name']).addCompositeCondition([{ fieldName: '__docId__', operator: '>=', value: 'a' }]);
400
+ ```
401
+
402
+ **Calling projectFields twice:** Second call must be a subset of the first:
403
+ ```typescript
404
+ // ALLOWED: ['name'] is subset of ['name', 'age', 'email']
405
+ users.query().projectFields(['name', 'age', 'email']).projectFields(['name']);
406
+
407
+ // ERROR: 'email' was not in first projection
408
+ users.query().projectFields(['name', 'age']).projectFields(['name', 'email']);
409
+ ```
410
+
411
+ **Cloning:** `projectFields` returns a cloned QueryBuilder - original is unmodified:
412
+ ```typescript
413
+ const base = collection.query().where('age', '>=', 18);
414
+ const projected = base.projectFields(['name']); // Returns clone
415
+ // base still returns all fields, projected returns only 'name'
416
+ ```
417
+
418
+ ### Empty Array Behavior
419
+
420
+ | Integration | Behavior |
421
+ |-------------|----------|
422
+ | `built_in_db` | Returns documents with only `__docId__` and `__id`, no user fields |
423
+ | External DBs | **Throws error** - must specify at least one field |
424
+
425
+ ```typescript
426
+ // built_in_db: returns { __docId__: '...', __id: '...' }
427
+ await builtInCollection.query().projectFields([]).snapshot();
428
+
429
+ // External DB: throws error
430
+ await postgresCollection.query().projectFields([]); // Error!
431
+ ```
432
+
433
+ ### Edge Cases
434
+
435
+ - **Non-existent fields:** Silently ignored, no error thrown
436
+ - **Duplicate fields:** Handled gracefully, no duplication in results
437
+ - **Including `__id` explicitly:** Not duplicated if already auto-included
438
+ - **Optimistic updates:** Local updates respect the projection - document store only contains projected fields. Multiple subscriptions with different projections maintain isolated views of the same document.
439
+
440
+ ### Without dereference()
441
+
442
+ When not using `dereference()`, you get `DocumentReference` objects. Access projected data via `.data`:
443
+ ```typescript
444
+ const refs = await users.query().projectFields(['name']).snapshot();
445
+ console.log(refs[0].data.name); // Projected data on .data property
446
+ ```
447
+
448
+ ### Works With
449
+
450
+ - One-time queries (`.snapshot()`)
451
+ - Real-time subscriptions (`.snapshots()`)
452
+ - Pagination (`.paginate()`)
453
+ - Join queries
454
+ - All database integrations (MongoDB, PostgreSQL, MySQL, ClickHouse, MS SQL, built_in_db)
455
+
317
456
  ## Pagination
318
457
 
319
458
  ```typescript
@@ -21,6 +21,15 @@ module.exports = function (env, argv) {
21
21
  'bufferutil': 'commonjs bufferutil',
22
22
  'utf-8-validate': 'commonjs utf-8-validate',
23
23
  },
24
+ // Suppress warnings from dependencies that use dynamic requires.
25
+ // These are typically dev dependencies used during build and don't affect runtime.
26
+ ignoreWarnings: [
27
+ { module: /tsoa/ },
28
+ { module: /@tsoa\/cli/ },
29
+ { module: /handlebars/ },
30
+ { module: /typescript/ },
31
+ { module: /yargs/ },
32
+ ],
24
33
  output: {
25
34
  path: path.resolve(process.cwd(), 'dist'),
26
35
  filename: 'index.js',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squidcloud/cli",
3
- "version": "1.0.449",
3
+ "version": "1.0.451",
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.449",
31
+ "@squidcloud/local-backend": "^1.0.451",
32
32
  "adm-zip": "^0.5.16",
33
33
  "copy-webpack-plugin": "^12.0.2",
34
34
  "decompress": "^4.2.1",