@cap-kit/people 8.0.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.
Files changed (42) hide show
  1. package/CapKitPeople.podspec +20 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +1177 -0
  5. package/android/build.gradle +101 -0
  6. package/android/src/main/AndroidManifest.xml +4 -0
  7. package/android/src/main/java/io/capkit/people/PeopleImpl.kt +1003 -0
  8. package/android/src/main/java/io/capkit/people/PeopleObserver.kt +80 -0
  9. package/android/src/main/java/io/capkit/people/PeoplePlugin.kt +766 -0
  10. package/android/src/main/java/io/capkit/people/config/PeopleConfig.kt +44 -0
  11. package/android/src/main/java/io/capkit/people/error/PeopleError.kt +90 -0
  12. package/android/src/main/java/io/capkit/people/error/PeopleErrorMessages.kt +39 -0
  13. package/android/src/main/java/io/capkit/people/logger/PeopleLogger.kt +85 -0
  14. package/android/src/main/java/io/capkit/people/models/ContactModels.kt +64 -0
  15. package/android/src/main/java/io/capkit/people/utils/PeopleUtils.kt +133 -0
  16. package/android/src/main/res/.gitkeep +0 -0
  17. package/dist/docs.json +1449 -0
  18. package/dist/esm/definitions.d.ts +775 -0
  19. package/dist/esm/definitions.js +31 -0
  20. package/dist/esm/definitions.js.map +1 -0
  21. package/dist/esm/index.d.ts +15 -0
  22. package/dist/esm/index.js +18 -0
  23. package/dist/esm/index.js.map +1 -0
  24. package/dist/esm/web.d.ts +120 -0
  25. package/dist/esm/web.js +252 -0
  26. package/dist/esm/web.js.map +1 -0
  27. package/dist/plugin.cjs +300 -0
  28. package/dist/plugin.cjs.map +1 -0
  29. package/dist/plugin.js +303 -0
  30. package/dist/plugin.js.map +1 -0
  31. package/ios/Sources/PeoplePlugin/PeopleImpl.swift +463 -0
  32. package/ios/Sources/PeoplePlugin/PeoplePlugin.swift +627 -0
  33. package/ios/Sources/PeoplePlugin/PrivacyInfo.xcprivacy +13 -0
  34. package/ios/Sources/PeoplePlugin/Utils/PeopleUtils.swift +120 -0
  35. package/ios/Sources/PeoplePlugin/Version.swift +16 -0
  36. package/ios/Sources/PeoplePlugin/config/PeopleConfig.swift +56 -0
  37. package/ios/Sources/PeoplePlugin/error/PeopleError.swift +89 -0
  38. package/ios/Sources/PeoplePlugin/error/PeopleErrorMessages.swift +25 -0
  39. package/ios/Sources/PeoplePlugin/logger/PeopleLogging.swift +69 -0
  40. package/ios/Sources/PeoplePlugin/models/ContactModels.swift +68 -0
  41. package/ios/Tests/PeoplePluginTests/PeoplePluginTests.swift +10 -0
  42. package/package.json +119 -0
@@ -0,0 +1,775 @@
1
+ /**
2
+ * Extend the PluginsConfig interface to include configuration options for the People plugin.
3
+ */
4
+ import { PermissionState, PluginListenerHandle } from '@capacitor/core';
5
+ /**
6
+ * Extension of the Capacitor CLI configuration to include specific settings for People.
7
+ * This allows users to configure the plugin via capacitor.config.ts or capacitor.config.json.
8
+ */
9
+ declare module '@capacitor/cli' {
10
+ interface PluginsConfig {
11
+ /**
12
+ * Configuration options for the People plugin.
13
+ */
14
+ People?: PeopleConfig;
15
+ }
16
+ }
17
+ /**
18
+ * Static configuration options for the People plugin.
19
+ *
20
+ * These values are defined in `capacitor.config.ts` and consumed
21
+ * exclusively by native code during plugin initialization.
22
+ *
23
+ * Configuration values:
24
+ * - do NOT change the JavaScript API shape
25
+ * - do NOT enable/disable methods
26
+ * - are applied once during plugin load
27
+ */
28
+ export interface PeopleConfig {
29
+ /**
30
+ * Enables verbose native logging.
31
+ *
32
+ * When enabled, additional debug information is printed
33
+ * to the native console (Logcat on Android, Xcode on iOS).
34
+ *
35
+ * This option affects native logging behavior only and
36
+ * has no impact on the JavaScript API.
37
+ *
38
+ * @default false
39
+ * @example true
40
+ * @since 8.0.0
41
+ */
42
+ verboseLogging?: boolean;
43
+ }
44
+ /**
45
+ * Options for picking a contact.
46
+ */
47
+ export interface PickOptions {
48
+ projection?: PeopleProjection[];
49
+ }
50
+ /**
51
+ * Standardized error codes used by the People plugin.
52
+ *
53
+ * These codes are returned when a Promise is rejected and can be caught
54
+ * via try/catch blocks.
55
+ *
56
+ * @since 8.0.0
57
+ */
58
+ export declare enum PeopleErrorCode {
59
+ /** The device does not have the requested hardware or the feature is not available on this platform. */
60
+ UNAVAILABLE = "UNAVAILABLE",
61
+ /** The user cancelled an interactive flow. */
62
+ CANCELLED = "CANCELLED",
63
+ /** The user denied the permission or the feature is disabled by the OS. */
64
+ PERMISSION_DENIED = "PERMISSION_DENIED",
65
+ /** The plugin failed to initialize or perform an operation. */
66
+ INIT_FAILED = "INIT_FAILED",
67
+ /** The input provided to the plugin method is invalid, missing, or malformed. */
68
+ INVALID_INPUT = "INVALID_INPUT",
69
+ /** The requested type is not valid or supported. */
70
+ UNKNOWN_TYPE = "UNKNOWN_TYPE",
71
+ /** The requested resource does not exist. */
72
+ NOT_FOUND = "NOT_FOUND",
73
+ /** The operation conflicts with the current state. */
74
+ CONFLICT = "CONFLICT",
75
+ /** The operation did not complete within the expected time. */
76
+ TIMEOUT = "TIMEOUT"
77
+ }
78
+ /**
79
+ * Result object returned by the `getPluginVersion()` method.
80
+ */
81
+ export interface PluginVersionResult {
82
+ /**
83
+ * The native plugin version string.
84
+ */
85
+ version: string;
86
+ }
87
+ /**
88
+ * Supported fields for the Projection Engine.
89
+ * Requesting only what you need reduces memory usage by O(N).
90
+ * `image` projection support is iOS-only. On Android and Web, requesting `image` is rejected with `UNKNOWN_TYPE` and message `Unsupported projection field: image`.
91
+ */
92
+ export type PeopleProjection = 'name' | 'organization' | 'birthday' | 'phones' | 'emails' | 'addresses' | 'urls' | 'image' | 'note';
93
+ /**
94
+ * Capabilities of the People plugin on this device/implementation.
95
+ */
96
+ export interface PeopleCapabilities {
97
+ canRead: boolean;
98
+ canWrite: boolean;
99
+ canObserve: boolean;
100
+ canManageGroups: boolean;
101
+ canPickContact: boolean;
102
+ }
103
+ /**
104
+ * Phone number representation.
105
+ */
106
+ export interface PhoneNumber {
107
+ /** Normalized label (e.g., 'mobile', 'home', 'work') */
108
+ label?: string;
109
+ /** The raw input string */
110
+ number: string;
111
+ /** E.164 formatted number (if parsing succeeded) */
112
+ normalized?: string;
113
+ }
114
+ /**
115
+ * Email address representation.
116
+ */
117
+ export interface EmailAddress {
118
+ label?: string;
119
+ address: string;
120
+ }
121
+ /**
122
+ * Postal address representation.
123
+ */
124
+ export interface PostalAddress {
125
+ label?: string;
126
+ formatted?: string;
127
+ street?: string;
128
+ city?: string;
129
+ region?: string;
130
+ postcode?: string;
131
+ country?: string;
132
+ }
133
+ /**
134
+ * Represents a Unified Person in the directory.
135
+ * Maps to CNContact (iOS) and Aggregated Contact (Android).
136
+ */
137
+ export interface UnifiedContact {
138
+ /** The platform-specific unique identifier (UUID or Long) */
139
+ id: string;
140
+ /** The unified display name */
141
+ name?: {
142
+ display: string;
143
+ given?: string;
144
+ middle?: string;
145
+ family?: string;
146
+ prefix?: string;
147
+ suffix?: string;
148
+ };
149
+ organization?: {
150
+ company?: string;
151
+ title?: string;
152
+ department?: string;
153
+ };
154
+ birthday?: {
155
+ year?: number;
156
+ month: number;
157
+ day: number;
158
+ };
159
+ phones?: PhoneNumber[];
160
+ emails?: EmailAddress[];
161
+ addresses?: PostalAddress[];
162
+ urls?: string[];
163
+ note?: string;
164
+ /** Base64 thumbnail string (iOS only, only if projected). */
165
+ image?: string;
166
+ }
167
+ /**
168
+ * Payload delivered to listeners registered for "peopleChange".
169
+ * - `ids`: always present, contains changed contact IDs (may be empty).
170
+ * - `type`: one of 'insert' | 'update' | 'delete' (default 'update').
171
+ * Current native implementations emit `update`.
172
+ */
173
+ export type PeopleChangeType = 'insert' | 'update' | 'delete';
174
+ /**
175
+ * Event emitted when changes are detected in the device's address book.
176
+ */
177
+ export interface PeopleChangeEvent {
178
+ /** Array of affected contact IDs (always present, may be empty) */
179
+ ids: string[];
180
+ /** The type of change detected */
181
+ type: PeopleChangeType;
182
+ }
183
+ /**
184
+ * Result returned by pickContact().
185
+ * Now strictly returns the contact object on success.
186
+ */
187
+ export interface PickContactResult {
188
+ contact: UnifiedContact;
189
+ }
190
+ /**
191
+ * Options for querying contacts.
192
+ */
193
+ export interface GetContactsOptions {
194
+ /**
195
+ * Array of fields to fetch.
196
+ * MISSING fields will not be read from DB (Performance).
197
+ * @default ['name']
198
+ */
199
+ projection?: PeopleProjection[];
200
+ /** Max number of records to return */
201
+ limit?: number;
202
+ /** Skip count (implement pagination via cursor usually better, but offset for now) */
203
+ offset?: number;
204
+ /**
205
+ * Whether to compute totalCount across the full contacts set.
206
+ * This may require scanning/counting the full address book and can be expensive on large datasets.
207
+ * @default false
208
+ */
209
+ includeTotal?: boolean;
210
+ }
211
+ /**
212
+ * Result returned by getContacts().
213
+ */
214
+ export interface GetContactsResult {
215
+ contacts: UnifiedContact[];
216
+ /** Total count in the DB (permissions permitting) */
217
+ totalCount: number;
218
+ }
219
+ /**
220
+ * Permissions status interface.
221
+ */
222
+ export interface PeoplePluginPermissions {
223
+ contacts: PermissionState;
224
+ }
225
+ /**
226
+ * Represents a group in the address book.
227
+ * A group can be system-generated (e.g., "All Contacts") or user-created.
228
+ *
229
+ * @since 8.0.0
230
+ */
231
+ export interface Group {
232
+ /**
233
+ * A unique identifier for the group.
234
+ * This ID is stable and can be used for subsequent operations.
235
+ */
236
+ id: string;
237
+ /**
238
+ * The display name of the group.
239
+ * e.g., "Family", "Work", "Book Club"
240
+ */
241
+ name: string;
242
+ /**
243
+ * The source or account where the group originates.
244
+ * On iOS, this could be "iCloud" or "Local". On Android, this corresponds to the account name (e.g., "user@gmail.com").
245
+ * For logical groups, this will be 'local'.
246
+ */
247
+ source?: string;
248
+ /**
249
+ * Indicates if the group is read-only.
250
+ * System groups are typically read-only and cannot be deleted or renamed.
251
+ */
252
+ readOnly: boolean;
253
+ }
254
+ /**
255
+ * Result returned by `listGroups`.
256
+ *
257
+ * @since 8.0.0
258
+ */
259
+ export interface ListGroupsResult {
260
+ /**
261
+ * An array of groups found in the address book.
262
+ */
263
+ groups: Group[];
264
+ }
265
+ /**
266
+ * Options for creating a new group.
267
+ *
268
+ * @since 8.0.0
269
+ */
270
+ export interface CreateGroupOptions {
271
+ /**
272
+ * The name for the new group.
273
+ */
274
+ name: string;
275
+ }
276
+ /**
277
+ * Result returned by `createGroup`.
278
+ *
279
+ * @since 8.0.0
280
+ */
281
+ export interface CreateGroupResult {
282
+ /**
283
+ * The newly created group.
284
+ */
285
+ group: Group;
286
+ }
287
+ /**
288
+ * Options for deleting a group.
289
+ *
290
+ * @since 8.0.0
291
+ */
292
+ export interface DeleteGroupOptions {
293
+ /**
294
+ * The unique identifier of the group to delete.
295
+ */
296
+ groupId: string;
297
+ }
298
+ /**
299
+ * Options for adding people to a group.
300
+ *
301
+ * @since 8.0.0
302
+ */
303
+ export interface AddPeopleToGroupOptions {
304
+ /**
305
+ * The unique identifier of the group.
306
+ */
307
+ groupId: string;
308
+ /**
309
+ * An array of contact identifiers to add to the group.
310
+ */
311
+ contactIds: string[];
312
+ }
313
+ /**
314
+ * Options for removing people from a group.
315
+ *
316
+ * @since 8.0.0
317
+ */
318
+ export interface RemovePeopleFromGroupOptions {
319
+ /**
320
+ * The unique identifier of the group.
321
+ */
322
+ groupId: string;
323
+ /**
324
+ * An array of contact identifiers to remove from the group.
325
+ */
326
+ contactIds: string[];
327
+ }
328
+ /**
329
+ * Options for creating a new contact.
330
+ * The contact data is provided as a partial UnifiedContact.
331
+ *
332
+ * @since 8.0.0
333
+ */
334
+ export interface CreateContactOptions {
335
+ /**
336
+ * The contact data to be saved.
337
+ * At least one writable field (e.g., name, email) must be provided.
338
+ */
339
+ contact: Partial<Omit<UnifiedContact, 'id'>>;
340
+ }
341
+ /**
342
+ * Result returned by `createContact`.
343
+ *
344
+ * @since 8.0.0
345
+ */
346
+ export interface CreateContactResult {
347
+ /**
348
+ * The full contact object as it was saved, including its new unique ID.
349
+ */
350
+ contact: UnifiedContact;
351
+ }
352
+ /**
353
+ * Options for updating an existing contact.
354
+ * This operation performs a patch, not a full replacement.
355
+ *
356
+ * @since 8.0.0
357
+ */
358
+ export interface UpdateContactOptions {
359
+ /**
360
+ * The unique identifier of the contact to update.
361
+ */
362
+ contactId: string;
363
+ /**
364
+ * An object containing the fields to be updated.
365
+ * Only the provided fields will be modified.
366
+ */
367
+ contact: Partial<Omit<UnifiedContact, 'id'>>;
368
+ }
369
+ /**
370
+ * Result returned by `updateContact`.
371
+ *
372
+ * @since 8.0.0
373
+ */
374
+ export interface UpdateContactResult {
375
+ /**
376
+ * The full contact object after the update has been applied.
377
+ */
378
+ contact: UnifiedContact;
379
+ }
380
+ /**
381
+ * Options for deleting a contact.
382
+ *
383
+ * @since 8.0.0
384
+ */
385
+ export interface DeleteContactOptions {
386
+ /**
387
+ * The unique identifier of the contact to delete.
388
+ */
389
+ contactId: string;
390
+ }
391
+ /**
392
+ * Options for merging two contacts.
393
+ *
394
+ * @since 8.0.0
395
+ */
396
+ export interface MergeContactsOptions {
397
+ /**
398
+ * The identifier of the contact that will be subsumed and deleted.
399
+ */
400
+ sourceContactId: string;
401
+ /**
402
+ * The identifier of the contact that will be kept and updated.
403
+ */
404
+ destinationContactId: string;
405
+ }
406
+ /**
407
+ * Result returned by `mergeContacts`.
408
+ *
409
+ * @since 8.0.0
410
+ */
411
+ export interface MergeContactsResult {
412
+ /**
413
+ * The state of the destination contact after the merge.
414
+ */
415
+ contact: UnifiedContact;
416
+ }
417
+ /**
418
+ * Capacitor People plugin interface.
419
+ * * This interface defines the contract between the JavaScript layer and the
420
+ * native implementations (Android and iOS).
421
+ */
422
+ export interface PeoplePlugin {
423
+ /**
424
+ * [CRUD]
425
+ * Creates a new contact in the device's address book.
426
+ * * @throws {PeopleError} PERMISSION_DENIED if contacts permission is missing.
427
+ * @throws {PeopleError} UNAVAILABLE if the operation fails on the native side.
428
+ *
429
+ * @example
430
+ * ```typescript
431
+ * import { People } from '@cap-kit/people';
432
+ *
433
+ * try {
434
+ * const { contact } = await People.createContact({
435
+ * contact: {
436
+ * name: { given: 'John', family: 'Appleseed' },
437
+ * emails: [{ address: 'john.appleseed@example.com', label: 'work' }],
438
+ * },
439
+ * });
440
+ * console.log('Created contact ID:', contact.id);
441
+ * } catch (error) {
442
+ * console.error('Failed to create contact:', error.code);
443
+ * }
444
+ * ```
445
+ *
446
+ * @since 8.0.0
447
+ */
448
+ createContact(options: CreateContactOptions): Promise<CreateContactResult>;
449
+ /**
450
+ * [CRUD]
451
+ * Updates an existing contact using a patch-based approach.
452
+ * * @throws {PeopleError} PERMISSION_DENIED if permission is missing.
453
+ * @throws {PeopleError} UNAVAILABLE if the contact is not owned by the app or not found.
454
+ *
455
+ * @example
456
+ * ```typescript
457
+ * import { People } from '@cap-kit/people';
458
+ *
459
+ * try {
460
+ * const { contact } = await People.updateContact({
461
+ * contactId: 'some-contact-id',
462
+ * contact: {
463
+ * organization: { company: 'New Company Inc.' },
464
+ * },
465
+ * });
466
+ * console.log('Updated contact company:', contact.organization?.company);
467
+ * } catch (error) {
468
+ * console.error('Update failed:', error.message);
469
+ * }
470
+ * ```
471
+ *
472
+ * @since 8.0.0
473
+ */
474
+ updateContact(options: UpdateContactOptions): Promise<UpdateContactResult>;
475
+ /**
476
+ * [CRUD]
477
+ * Deletes a contact from the device's address book.
478
+ * Only contacts owned by the app can be deleted.
479
+ * * @throws {PeopleError} UNAVAILABLE if deletion fails or contact is not app-owned.
480
+ *
481
+ * @example
482
+ * ```typescript
483
+ * import { People } from '@cap-kit/people';
484
+ *
485
+ * await People.deleteContact({ contactId: 'contact-id-to-delete' });
486
+ * ```
487
+ *
488
+ * @since 8.0.0
489
+ */
490
+ deleteContact(options: DeleteContactOptions): Promise<void>;
491
+ /**
492
+ * [CRUD]
493
+ * Merges a source contact into a destination contact.
494
+ * The source contact is deleted after the merge.
495
+ * * @throws {PeopleError} PERMISSION_DENIED if permission is missing.
496
+ *
497
+ * @example
498
+ * ```typescript
499
+ * import { People } from '@cap-kit/people';
500
+ *
501
+ * const { contact } = await People.mergeContacts({
502
+ * sourceContactId: 'duplicate-contact-id',
503
+ * destinationContactId: 'main-contact-id',
504
+ * });
505
+ * console.log('Final contact state:', contact);
506
+ * ```
507
+ *
508
+ * @since 8.0.0
509
+ */
510
+ mergeContacts(options: MergeContactsOptions): Promise<MergeContactsResult>;
511
+ /**
512
+ * [GROUPS]
513
+ * Lists all available contact groups.
514
+ *
515
+ * @example
516
+ * ```typescript
517
+ * const { groups } = await People.listGroups();
518
+ * ```
519
+ *
520
+ * @since 8.0.0
521
+ */
522
+ listGroups(): Promise<ListGroupsResult>;
523
+ /**
524
+ * [GROUPS]
525
+ * Creates a new contact group.
526
+ * * @example
527
+ * ```typescript
528
+ * const { group } = await People.createGroup({ name: 'Family' });
529
+ * ```
530
+ *
531
+ * @since 8.0.0
532
+ */
533
+ createGroup(options: CreateGroupOptions): Promise<CreateGroupResult>;
534
+ /**
535
+ * [GROUPS]
536
+ * Deletes a contact group.
537
+ *
538
+ * @example
539
+ * ```typescript
540
+ * import { People } from '@cap-kit/people';
541
+ *
542
+ * await People.deleteGroup({ groupId: 'group-id-to-delete' });
543
+ * ```
544
+ *
545
+ * @since 8.0.0
546
+ */
547
+ deleteGroup(options: DeleteGroupOptions): Promise<void>;
548
+ /**
549
+ * [GROUPS]
550
+ * Adds contacts to a group.
551
+ *
552
+ * @example
553
+ * ```typescript
554
+ * import { People } from '@cap-kit/people';
555
+ *
556
+ * await People.addPeopleToGroup({
557
+ * groupId: 'group-id',
558
+ * contactIds: ['contact-id-1', 'contact-id-2'],
559
+ * });
560
+ * ```
561
+ *
562
+ * @since 8.0.0
563
+ */
564
+ addPeopleToGroup(options: AddPeopleToGroupOptions): Promise<void>;
565
+ /**
566
+ * [GROUPS]
567
+ * Removes contacts from a group.
568
+ *
569
+ * @example
570
+ * ```typescript
571
+ * import { People } from '@cap-kit/people';
572
+ *
573
+ * await People.removePeopleFromGroup({
574
+ * groupId: 'group-id',
575
+ * contactIds: ['contact-id-1'],
576
+ * });
577
+ * ```
578
+ *
579
+ * @since 8.0.0
580
+ */
581
+ removePeopleFromGroup(options: RemovePeopleFromGroupOptions): Promise<void>;
582
+ /**
583
+ * Check the status of permissions.
584
+ * @returns A promise resolving to the current permission states.
585
+ *
586
+ * @example
587
+ * ```typescript
588
+ * import { People } from '@cap-kit/people';
589
+ * const permissions = await People.checkPermissions();
590
+ * console.log(permissions.contacts); // Output: 'granted' | 'denied' | 'prompt'
591
+ * ```
592
+ *
593
+ * @since 8.0.0
594
+ */
595
+ checkPermissions(): Promise<PeoplePluginPermissions>;
596
+ /**
597
+ * Request permissions.
598
+ * @param permissions - An optional object specifying which permissions to request.
599
+ * If not provided, all permissions defined in the plugin will be requested.
600
+ * @returns A promise resolving to the updated permission states.
601
+ *
602
+ * @example
603
+ * ```typescript
604
+ * import { People } from '@cap-kit/people';
605
+ * const permissions = await People.requestPermissions();
606
+ * // OR
607
+ * // const permissions = await People.requestPermissions({ permissions: ['contacts'] });
608
+ * console.log(permissions.contacts); // Output: 'granted' | 'denied'
609
+ * ```
610
+ *
611
+ * @since 8.0.0
612
+ */
613
+ requestPermissions(permissions?: {
614
+ permissions: 'contacts'[];
615
+ }): Promise<PeoplePluginPermissions>;
616
+ /**
617
+ * [ZERO-PERMISSION]
618
+ * Launches the native OS contact picker UI.
619
+ * This method does NOT require any entries in AndroidManifest.xml or Info.plist
620
+ * as the user explicitly selects the data via the system UI.
621
+ *
622
+ * @throws {PeopleError} CANCELLED if the user cancels or the picker fails.
623
+ *
624
+ * @example
625
+ * ```typescript
626
+ * try {
627
+ * const { contact } = await People.pickContact({
628
+ * projection: ['name', 'phones', 'emails']
629
+ * });
630
+ * console.log('User selected:', contact);
631
+ * } catch (error) {
632
+ * if (error.code === 'CANCELLED') {
633
+ * console.log('User cancelled the picker.');
634
+ * }
635
+ * }
636
+ * ```
637
+ *
638
+ * @since 8.0.0
639
+ */
640
+ pickContact(options?: {
641
+ projection?: PeopleProjection[];
642
+ }): Promise<PickContactResult>;
643
+ /**
644
+ * [SYSTEMIC-ACCESS]
645
+ * Queries the entire contact database with specific projection and pagination.
646
+ * REQUIRES 'contacts' permission.
647
+ * Use `includeTotal` only when needed: computing `totalCount` may require scanning/counting across the full contacts set and can be expensive on large address books. Default is `false`.
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * const result = await People.getContacts({
652
+ * projection: ['name', 'phones'],
653
+ * limit: 20,
654
+ * offset: 0
655
+ * });
656
+ * ```
657
+ *
658
+ * @since 8.0.0
659
+ */
660
+ getContacts(options?: GetContactsOptions): Promise<GetContactsResult>;
661
+ /**
662
+ * Retrieves a single contact by ID.
663
+ * * @throws {PeopleError} UNAVAILABLE if contact is not found.
664
+ *
665
+ * @example
666
+ * ```typescript
667
+ * import { People } from '@cap-kit/people';
668
+ *
669
+ * const { contact } = await People.getContact({ id: 'contact-id', projection: ['name', 'emails'] });
670
+ * console.log('Contact details:', contact);
671
+ * ```
672
+ *
673
+ * @since 8.0.0
674
+ */
675
+ getContact(options: {
676
+ id: string;
677
+ projection?: PeopleProjection[];
678
+ }): Promise<{
679
+ contact: UnifiedContact;
680
+ }>;
681
+ /**
682
+ * Returns what this device/implementation is capable of.
683
+ * Useful for UI adaptation (e.g. hiding "Edit" buttons).
684
+ *
685
+ * @example
686
+ * ```typescript
687
+ * import { People } from '@cap-kit/people';
688
+ *
689
+ * const capabilities = await People.getCapabilities();
690
+ * console.log('Can Read Contacts:', capabilities.canRead);
691
+ * console.log('Can Write Contacts:', capabilities.canWrite);
692
+ * ```
693
+ *
694
+ * @since 8.0.0
695
+ */
696
+ getCapabilities(): Promise<PeopleCapabilities>;
697
+ /**
698
+ * Returns the native plugin version.
699
+ *
700
+ * The returned version corresponds to the native implementation
701
+ * bundled with the application.
702
+ *
703
+ * @returns A promise resolving to the plugin version.
704
+ *
705
+ * @example
706
+ * ```ts
707
+ * const { version } = await People.getPluginVersion();
708
+ * ```
709
+ *
710
+ * @since 8.0.0
711
+ */
712
+ getPluginVersion(): Promise<PluginVersionResult>;
713
+ /**
714
+ * [SYSTEMIC-ACCESS]
715
+ * Searches the database with projection.
716
+ * REQUIRES 'contacts' permission.
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * import { People } from '@cap-kit/people';
721
+ *
722
+ * const result = await People.searchPeople({ query: 'John', projection: ['name', 'phones'], limit: 10 });
723
+ * console.log('Fetched contacts:', result.contacts);
724
+ * ```
725
+ *
726
+ * @since 8.0.0
727
+ */
728
+ searchPeople(options: {
729
+ query: string;
730
+ projection?: PeopleProjection[];
731
+ limit?: number;
732
+ }): Promise<GetContactsResult>;
733
+ /**
734
+ * Listen for changes in the system address book.
735
+ * REQUIRES 'contacts' permission.
736
+ * * @returns A promise that resolves to a handle to remove the listener.
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * import { People } from '@cap-kit/people';
741
+ *
742
+ * const handle = await People.addListener('peopleChange', (event) => {
743
+ * console.log('People change detected:', event.type);
744
+ * });
745
+ *
746
+ * // To remove the listener later:
747
+ * // await handle.remove();
748
+ * ```
749
+ *
750
+ * @since 8.0.0
751
+ */
752
+ addListener(eventName: 'peopleChange', listenerFunc: (payload: PeopleChangeEvent) => void): Promise<PluginListenerHandle>;
753
+ /**
754
+ * Registers a listener for plugin events using a generic event name.
755
+ *
756
+ * Prefer the typed `peopleChange` overload for full payload type safety.
757
+ *
758
+ * @since 8.0.0
759
+ */
760
+ addListener(eventName: string, listenerFunc: (...args: unknown[]) => void): Promise<PluginListenerHandle>;
761
+ /**
762
+ * Removes all registered listeners for this plugin.
763
+ * @returns Promise that resolves when all listeners have been removed.
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * import { People } from '@cap-kit/people';
768
+ *
769
+ * await People.removeAllListeners();
770
+ * ```
771
+ *
772
+ * @since 8.0.0
773
+ */
774
+ removeAllListeners(): Promise<void>;
775
+ }