@explorins/pers-sdk 2.1.42 → 2.2.0-alpha.1

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.
@@ -1587,7 +1587,7 @@ class DefaultAuthProvider {
1587
1587
  /** SDK package name */
1588
1588
  const SDK_NAME = "@explorins/pers-sdk";
1589
1589
  /** SDK version - injected from package.json at build time */
1590
- const SDK_VERSION = "2.1.42";
1590
+ const SDK_VERSION = "2.2.0-alpha.1";
1591
1591
  /** Full SDK identifier for headers */
1592
1592
  const SDK_USER_AGENT = `${SDK_NAME}/${SDK_VERSION}`;
1593
1593
 
@@ -10108,6 +10108,429 @@ class WalletEventsManager {
10108
10108
  }
10109
10109
  }
10110
10110
 
10111
+ /**
10112
+ * Custom Field Definitions API
10113
+ *
10114
+ * Low-level API for custom field definition CRUD operations.
10115
+ * Used internally by CustomFieldDefinitionManager.
10116
+ *
10117
+ * @internal
10118
+ */
10119
+ class CustomFieldApi {
10120
+ constructor(apiClient) {
10121
+ this.apiClient = apiClient;
10122
+ this.basePath = '/custom-field-definitions';
10123
+ }
10124
+ /**
10125
+ * List all custom field definitions
10126
+ * Backend returns non-paginated array sorted by sortOrder
10127
+ */
10128
+ async getDefinitions(entityType) {
10129
+ const params = new URLSearchParams();
10130
+ if (entityType) {
10131
+ params.append('entityType', entityType);
10132
+ }
10133
+ const query = params.toString();
10134
+ const url = query ? `${this.basePath}?${query}` : this.basePath;
10135
+ return this.apiClient.get(url);
10136
+ }
10137
+ /**
10138
+ * Get a single custom field definition by ID
10139
+ */
10140
+ async getDefinition(id) {
10141
+ return this.apiClient.get(`${this.basePath}/${id}`);
10142
+ }
10143
+ /**
10144
+ * Create a new custom field definition
10145
+ */
10146
+ async createDefinition(data) {
10147
+ return this.apiClient.post(this.basePath, data);
10148
+ }
10149
+ /**
10150
+ * Update an existing custom field definition
10151
+ */
10152
+ async updateDefinition(id, data) {
10153
+ return this.apiClient.put(`${this.basePath}/${id}`, data);
10154
+ }
10155
+ /**
10156
+ * Delete a custom field definition
10157
+ */
10158
+ async deleteDefinition(id) {
10159
+ return this.apiClient.delete(`${this.basePath}/${id}`);
10160
+ }
10161
+ /**
10162
+ * Get usage count for a field definition
10163
+ */
10164
+ async getUsages(id) {
10165
+ return this.apiClient.get(`${this.basePath}/${id}/usages`);
10166
+ }
10167
+ /**
10168
+ * Resolve dynamic select options for a field
10169
+ */
10170
+ async resolveSelectOptions(id) {
10171
+ return this.apiClient.get(`${this.basePath}/${id}/options`);
10172
+ }
10173
+ }
10174
+
10175
+ /**
10176
+ * Custom Field Definition Manager - Manage tenant-specific custom fields
10177
+ *
10178
+ * Provides CRUD operations for custom field definitions that extend the built-in
10179
+ * user profile fields. Custom fields are defined per-tenant and can be used for
10180
+ * additional user data collection, redemption requirements, and form validation.
10181
+ *
10182
+ * @group Managers
10183
+ * @category Custom Fields
10184
+ *
10185
+ * @example Basic Operations
10186
+ * ```typescript
10187
+ * // List all user custom fields
10188
+ * const fields = await sdk.customFields.getDefinitions();
10189
+ *
10190
+ * // Create a new custom field
10191
+ * const field = await sdk.customFields.createDefinition({
10192
+ * key: 'employee_id',
10193
+ * label: 'Employee ID',
10194
+ * fieldType: 'text',
10195
+ * validation: { required: true, pattern: '^E[0-9]{5}$' }
10196
+ * });
10197
+ *
10198
+ * // Update a field
10199
+ * await sdk.customFields.updateDefinition(field.id, {
10200
+ * label: 'Company Employee ID'
10201
+ * });
10202
+ *
10203
+ * // Delete a field
10204
+ * await sdk.customFields.deleteDefinition(field.id);
10205
+ * ```
10206
+ *
10207
+ * @example Validation
10208
+ * ```typescript
10209
+ * // Validate user custom data against definitions
10210
+ * const definitions = await sdk.customFields.getDefinitions();
10211
+ * const errors = sdk.customFields.validateUserData(
10212
+ * { employee_id: 'INVALID' },
10213
+ * definitions
10214
+ * );
10215
+ * if (errors.length > 0) {
10216
+ * console.log('Validation errors:', errors);
10217
+ * }
10218
+ * ```
10219
+ */
10220
+ class CustomFieldDefinitionManager {
10221
+ constructor(apiClient, events) {
10222
+ this.events = events;
10223
+ this.api = new CustomFieldApi(apiClient);
10224
+ }
10225
+ /**
10226
+ * List all custom field definitions for the tenant
10227
+ *
10228
+ * Retrieves all custom field definitions, optionally filtered by entity type.
10229
+ * Results are sorted by sortOrder (ascending).
10230
+ *
10231
+ * @param options - Query options including entity type filter
10232
+ * @returns Array of custom field definitions
10233
+ *
10234
+ * @example List All User Fields
10235
+ * ```typescript
10236
+ * const fields = await sdk.customFields.getDefinitions();
10237
+ * console.log(`Found ${fields.length} custom fields`);
10238
+ *
10239
+ * fields.forEach(field => {
10240
+ * console.log(`${field.key}: ${field.label} (${field.fieldType})`);
10241
+ * });
10242
+ * ```
10243
+ *
10244
+ * @example Filter by Entity Type
10245
+ * ```typescript
10246
+ * // Get only business custom fields
10247
+ * const businessFields = await sdk.customFields.getDefinitions({
10248
+ * entityType: 'business'
10249
+ * });
10250
+ * ```
10251
+ */
10252
+ async getDefinitions(options) {
10253
+ return this.api.getDefinitions(options?.entityType);
10254
+ }
10255
+ /**
10256
+ * Get a single custom field definition by ID
10257
+ *
10258
+ * @param id - The UUID of the custom field definition
10259
+ * @returns The custom field definition
10260
+ * @throws {PersApiError} When definition not found (404)
10261
+ *
10262
+ * @example
10263
+ * ```typescript
10264
+ * try {
10265
+ * const field = await sdk.customFields.getDefinition('uuid-here');
10266
+ * console.log('Field:', field.label);
10267
+ * } catch (error) {
10268
+ * if (error.statusCode === 404) {
10269
+ * console.log('Field not found');
10270
+ * }
10271
+ * }
10272
+ * ```
10273
+ */
10274
+ async getDefinition(id) {
10275
+ return this.api.getDefinition(id);
10276
+ }
10277
+ /**
10278
+ * Create a new custom field definition
10279
+ *
10280
+ * Creates a new custom field for the tenant. The field key must be unique
10281
+ * within the tenant and entity type combination.
10282
+ *
10283
+ * @param data - The field definition data
10284
+ * @returns The created custom field definition
10285
+ * @throws {PersApiError} When key already exists (409) or validation fails (400)
10286
+ *
10287
+ * @example Text Field with Pattern
10288
+ * ```typescript
10289
+ * const employeeIdField = await sdk.customFields.createDefinition({
10290
+ * key: 'employee_id',
10291
+ * label: 'Employee ID',
10292
+ * description: 'Your company employee ID (E + 5 digits)',
10293
+ * fieldType: 'text',
10294
+ * validation: {
10295
+ * required: true,
10296
+ * pattern: '^E[0-9]{5}$',
10297
+ * patternMessage: 'Must be E followed by 5 digits'
10298
+ * },
10299
+ * sortOrder: 1
10300
+ * });
10301
+ * ```
10302
+ *
10303
+ * @example Date Field with Comparison
10304
+ * ```typescript
10305
+ * const checkOutField = await sdk.customFields.createDefinition({
10306
+ * key: 'check_out',
10307
+ * label: 'Check-out Date',
10308
+ * fieldType: 'date',
10309
+ * validation: {
10310
+ * required: true,
10311
+ * comparisons: [
10312
+ * { field: 'check_in', operator: '>', message: 'Must be after check-in' }
10313
+ * ]
10314
+ * },
10315
+ * sortOrder: 2
10316
+ * });
10317
+ * ```
10318
+ *
10319
+ * @example Select Field with Static Options
10320
+ * ```typescript
10321
+ * const departmentField = await sdk.customFields.createDefinition({
10322
+ * key: 'department',
10323
+ * label: 'Department',
10324
+ * fieldType: 'select',
10325
+ * selectOptions: [
10326
+ * { value: 'engineering', label: 'Engineering' },
10327
+ * { value: 'sales', label: 'Sales' },
10328
+ * { value: 'hr', label: 'Human Resources' }
10329
+ * ],
10330
+ * validation: { required: true }
10331
+ * });
10332
+ * ```
10333
+ *
10334
+ * @example Select Field with Dynamic Options
10335
+ * ```typescript
10336
+ * const hotelField = await sdk.customFields.createDefinition({
10337
+ * key: 'preferred_hotel',
10338
+ * label: 'Preferred Hotel',
10339
+ * fieldType: 'select',
10340
+ * selectOptionsSource: {
10341
+ * entity: 'business',
10342
+ * valueField: 'id',
10343
+ * labelField: 'name',
10344
+ * filter: { tags: ['hotel'], isActive: true }
10345
+ * },
10346
+ * validation: { required: true }
10347
+ * });
10348
+ * ```
10349
+ */
10350
+ async createDefinition(data) {
10351
+ const result = await this.api.createDefinition(data);
10352
+ // Using 'user' domain until pers-shared adds 'customField' domain
10353
+ this.events?.emitSuccess({
10354
+ domain: 'user',
10355
+ type: 'definition_created',
10356
+ userMessage: `Custom field "${result.label}" created`,
10357
+ details: { id: result.id, key: result.key }
10358
+ });
10359
+ return result;
10360
+ }
10361
+ /**
10362
+ * Update an existing custom field definition
10363
+ *
10364
+ * Updates a custom field definition. Note that key and entityType cannot
10365
+ * be changed after creation.
10366
+ *
10367
+ * @param id - The UUID of the custom field definition to update
10368
+ * @param data - The fields to update (partial update supported)
10369
+ * @returns The updated custom field definition
10370
+ * @throws {PersApiError} When definition not found (404) or validation fails (400)
10371
+ *
10372
+ * @example Update Label and Validation
10373
+ * ```typescript
10374
+ * const updated = await sdk.customFields.updateDefinition('uuid-here', {
10375
+ * label: 'Employee ID (Required)',
10376
+ * validation: {
10377
+ * required: true,
10378
+ * minLength: 6,
10379
+ * maxLength: 6
10380
+ * }
10381
+ * });
10382
+ * ```
10383
+ *
10384
+ * @example Update Sort Order
10385
+ * ```typescript
10386
+ * await sdk.customFields.updateDefinition('uuid-here', {
10387
+ * sortOrder: 5
10388
+ * });
10389
+ * ```
10390
+ */
10391
+ async updateDefinition(id, data) {
10392
+ const result = await this.api.updateDefinition(id, data);
10393
+ // Using 'user' domain until pers-shared adds 'customField' domain
10394
+ this.events?.emitSuccess({
10395
+ domain: 'user',
10396
+ type: 'definition_updated',
10397
+ userMessage: `Custom field "${result.label}" updated`,
10398
+ details: { id: result.id, key: result.key }
10399
+ });
10400
+ return result;
10401
+ }
10402
+ /**
10403
+ * Delete a custom field definition (soft delete)
10404
+ *
10405
+ * Soft deletes a custom field definition. Existing user data in customData
10406
+ * is preserved, but the field will no longer appear in forms or validation.
10407
+ *
10408
+ * ⚠️ Consider the impact on existing user data before deleting.
10409
+ *
10410
+ * @param id - The UUID of the custom field definition to delete
10411
+ * @throws {PersApiError} When definition not found (404)
10412
+ *
10413
+ * @example
10414
+ * ```typescript
10415
+ * try {
10416
+ * await sdk.customFields.deleteDefinition('uuid-here');
10417
+ * console.log('Field deleted');
10418
+ * } catch (error) {
10419
+ * console.log('Failed to delete:', error.message);
10420
+ * }
10421
+ * ```
10422
+ */
10423
+ async deleteDefinition(id) {
10424
+ await this.api.deleteDefinition(id);
10425
+ // Using 'user' domain until pers-shared adds 'customField' domain
10426
+ this.events?.emitSuccess({
10427
+ domain: 'user',
10428
+ type: 'definition_deleted',
10429
+ userMessage: 'Custom field deleted',
10430
+ details: { id }
10431
+ });
10432
+ }
10433
+ /**
10434
+ * Resolve dynamic select options for a field
10435
+ *
10436
+ * For fields with selectOptionsSource (dynamic options from entities),
10437
+ * this resolves the actual options by querying the source entity.
10438
+ *
10439
+ * @param id - The UUID of the custom field definition
10440
+ * @returns Array of select options
10441
+ *
10442
+ * @example
10443
+ * ```typescript
10444
+ * const field = await sdk.customFields.getDefinition('hotel-field-id');
10445
+ *
10446
+ * if (field.selectOptionsSource) {
10447
+ * // Options come from entity - need to resolve
10448
+ * const options = await sdk.customFields.resolveSelectOptions(field.id);
10449
+ * console.log('Available hotels:', options);
10450
+ * } else {
10451
+ * // Static options
10452
+ * console.log('Options:', field.selectOptions);
10453
+ * }
10454
+ * ```
10455
+ */
10456
+ async resolveSelectOptions(id) {
10457
+ const response = await this.api.resolveSelectOptions(id);
10458
+ return response.options;
10459
+ }
10460
+ /**
10461
+ * Validate user custom data against field definitions
10462
+ *
10463
+ * Client-side validation using the same rules as the backend. Use this
10464
+ * to validate form data before submission.
10465
+ *
10466
+ * @param data - User's custom data (key-value pairs)
10467
+ * @param definitions - Custom field definitions to validate against
10468
+ * @returns Array of validation errors (empty if valid)
10469
+ *
10470
+ * @example Form Validation
10471
+ * ```typescript
10472
+ * const definitions = await sdk.customFields.getDefinitions();
10473
+ * const formData = {
10474
+ * employee_id: 'E123', // Missing a digit
10475
+ * department: 'engineering'
10476
+ * };
10477
+ *
10478
+ * const errors = sdk.customFields.validateUserData(formData, definitions);
10479
+ * if (errors.length > 0) {
10480
+ * errors.forEach(err => {
10481
+ * console.log(`${err.field}: ${err.message}`);
10482
+ * });
10483
+ * return; // Don't submit
10484
+ * }
10485
+ *
10486
+ * // No errors, safe to submit
10487
+ * await sdk.users.updateCurrentUser({ customData: formData });
10488
+ * ```
10489
+ */
10490
+ validateUserData(data, definitions) {
10491
+ // Convert CustomFieldDefinitionDTO to FieldDefinition for validation
10492
+ const fieldDefinitions = definitions.map(def => ({
10493
+ key: def.key,
10494
+ fieldType: def.fieldType,
10495
+ label: def.label,
10496
+ validation: def.validation ?? undefined,
10497
+ }));
10498
+ return persShared.validateAllFields(data, fieldDefinitions);
10499
+ }
10500
+ /**
10501
+ * Validate a single field value
10502
+ *
10503
+ * Validates a single value against a field's rules. Useful for
10504
+ * real-time validation as the user types.
10505
+ *
10506
+ * @param value - The value to validate
10507
+ * @param definition - The field definition
10508
+ * @returns Validation error or null if valid
10509
+ *
10510
+ * @example Real-time Validation
10511
+ * ```typescript
10512
+ * const employeeIdField = definitions.find(d => d.key === 'employee_id');
10513
+ *
10514
+ * const handleBlur = (value: string) => {
10515
+ * const error = sdk.customFields.validateFieldValue(value, employeeIdField);
10516
+ * if (error) {
10517
+ * setFieldError('employee_id', error.message);
10518
+ * } else {
10519
+ * clearFieldError('employee_id');
10520
+ * }
10521
+ * };
10522
+ * ```
10523
+ */
10524
+ validateFieldValue(value, definition) {
10525
+ const error = persShared.validateFieldValue(value, definition.validation ?? null, definition.fieldType);
10526
+ if (error) {
10527
+ // Add field key to error
10528
+ return { ...error, field: definition.key };
10529
+ }
10530
+ return null;
10531
+ }
10532
+ }
10533
+
10111
10534
  /**
10112
10535
  * @fileoverview PERS SDK - Platform-agnostic TypeScript SDK with High-Level Managers
10113
10536
  *
@@ -10796,6 +11219,37 @@ class PersSDK {
10796
11219
  }
10797
11220
  return this._webhooks;
10798
11221
  }
11222
+ /**
11223
+ * Custom Field Definition Manager - Manage tenant-specific custom fields
11224
+ *
11225
+ * Provides CRUD operations for custom field definitions that extend the built-in
11226
+ * user profile fields. Custom fields are tenant-specific and support validation.
11227
+ *
11228
+ * @returns CustomFieldDefinitionManager instance
11229
+ *
11230
+ * @example Basic Operations
11231
+ * ```typescript
11232
+ * // List all custom fields
11233
+ * const fields = await sdk.customFields.getDefinitions();
11234
+ *
11235
+ * // Create a new field
11236
+ * const field = await sdk.customFields.createDefinition({
11237
+ * key: 'employee_id',
11238
+ * label: 'Employee ID',
11239
+ * fieldType: 'text',
11240
+ * validation: { required: true }
11241
+ * });
11242
+ *
11243
+ * // Validate user data
11244
+ * const errors = sdk.customFields.validateUserData(formData, fields.data);
11245
+ * ```
11246
+ */
11247
+ get customFields() {
11248
+ if (!this._customFields) {
11249
+ this._customFields = new CustomFieldDefinitionManager(this.apiClient, this._events);
11250
+ }
11251
+ return this._customFields;
11252
+ }
10799
11253
  /**
10800
11254
  * Wallet Events Manager - Real-time blockchain events for user's wallets
10801
11255
  *
@@ -10912,6 +11366,7 @@ exports.AuthService = AuthService;
10912
11366
  exports.AuthTokenManager = AuthTokenManager;
10913
11367
  exports.BusinessManager = BusinessManager;
10914
11368
  exports.CampaignManager = CampaignManager;
11369
+ exports.CustomFieldDefinitionManager = CustomFieldDefinitionManager;
10915
11370
  exports.DEFAULT_PERS_CONFIG = DEFAULT_PERS_CONFIG;
10916
11371
  exports.DPOP_STORAGE_KEYS = DPOP_STORAGE_KEYS;
10917
11372
  exports.DPoPManager = DPoPManager;
@@ -10950,4 +11405,4 @@ exports.createPersEventsClient = createPersEventsClient;
10950
11405
  exports.createPersSDK = createPersSDK;
10951
11406
  exports.isFatalAuthErrorInMessage = isFatalAuthErrorInMessage;
10952
11407
  exports.mergeWithDefaults = mergeWithDefaults;
10953
- //# sourceMappingURL=pers-sdk-DeFxjuRB.cjs.map
11408
+ //# sourceMappingURL=pers-sdk-DcNDMx1Y.cjs.map