@proofchain/sdk 2.14.0 → 2.16.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.
package/dist/index.d.mts CHANGED
@@ -1858,6 +1858,7 @@ interface UserReward {
1858
1858
  id: string;
1859
1859
  reward_name: string;
1860
1860
  reward_type: string;
1861
+ category?: string;
1861
1862
  slug?: string;
1862
1863
  description?: string;
1863
1864
  status: string;
@@ -1914,6 +1915,23 @@ interface ManualRewardRequest {
1914
1915
  trigger_data?: Record<string, any>;
1915
1916
  distribute_immediately?: boolean;
1916
1917
  }
1918
+ interface ClaimNFTResult {
1919
+ success: boolean;
1920
+ reward_id: string;
1921
+ token_id?: number;
1922
+ tx_hash: string;
1923
+ wallet_address: string;
1924
+ }
1925
+ interface DistributeResult {
1926
+ success: boolean;
1927
+ reward_id: string;
1928
+ message: string;
1929
+ }
1930
+ interface RevokeResult {
1931
+ success: boolean;
1932
+ reward_id: string;
1933
+ status: string;
1934
+ }
1917
1935
  interface ListRewardsOptions {
1918
1936
  is_active?: boolean;
1919
1937
  reward_type?: string;
@@ -1962,37 +1980,108 @@ declare class RewardsClient {
1962
1980
  offset?: number;
1963
1981
  }): Promise<EarnedReward[]>;
1964
1982
  /**
1965
- * Get earned rewards for a user (with full badge/reward details)
1983
+ * Get earned rewards for a user (with full badge/reward details).
1984
+ * Use this to display a user's reward collection on a dedicated screen.
1985
+ *
1986
+ * @example
1987
+ * ```ts
1988
+ * // All user rewards
1989
+ * const all = await client.rewards.getUserRewards('user-123');
1990
+ *
1991
+ * // Only badges in the "Fan Pass" category
1992
+ * const badges = await client.rewards.getUserRewards('user-123', {
1993
+ * reward_type: 'badge',
1994
+ * category: 'Fan Pass',
1995
+ * });
1996
+ *
1997
+ * // Only distributed rewards
1998
+ * const distributed = await client.rewards.getUserRewards('user-123', {
1999
+ * status: 'distributed',
2000
+ * });
2001
+ * ```
1966
2002
  */
1967
2003
  getUserRewards(userId: string, options?: {
1968
2004
  status?: string;
1969
2005
  reward_type?: string;
2006
+ category?: string;
1970
2007
  }): Promise<UserReward[]>;
1971
2008
  /**
1972
- * Get the public reward catalog (active, public reward definitions)
2009
+ * Get the public reward catalog (active, public reward definitions).
1973
2010
  * Available to both API key and end-user JWT clients.
2011
+ *
2012
+ * @param category - Optional category filter (e.g. "Fan Pass", "Partner: Acme")
2013
+ *
2014
+ * @example
2015
+ * ```ts
2016
+ * // All available rewards
2017
+ * const all = await client.rewards.getCatalog();
2018
+ *
2019
+ * // Only "Fan Pass" rewards
2020
+ * const fanPass = await client.rewards.getCatalog('Fan Pass');
2021
+ * ```
1974
2022
  */
1975
- getCatalog(): Promise<RewardDefinition[]>;
2023
+ getCatalog(category?: string): Promise<RewardDefinition[]>;
1976
2024
  /**
1977
2025
  * Claim a lazy-minted NFT reward.
1978
2026
  * The wallet_address receives the minted NFT. The tenant's treasury pays gas.
1979
2027
  * Available to both API key and end-user JWT clients (scoped to own rewards).
2028
+ *
2029
+ * For non-NFT rewards, use {@link distribute} instead.
1980
2030
  */
1981
- claimReward(earnedRewardId: string, walletAddress: string): Promise<{
1982
- success: boolean;
1983
- reward_id: string;
1984
- token_id?: number;
1985
- tx_hash: string;
1986
- wallet_address: string;
1987
- }>;
2031
+ claimNFT(earnedRewardId: string, walletAddress: string): Promise<ClaimNFTResult>;
2032
+ /**
2033
+ * @deprecated Use {@link claimNFT} instead — this method only works for lazy-mint NFTs.
2034
+ */
2035
+ claimReward(earnedRewardId: string, walletAddress: string): Promise<ClaimNFTResult>;
1988
2036
  /**
1989
- * Manually award rewards to users
2037
+ * Manually award rewards to one or more users.
2038
+ * Works for all reward types: points, tokens, NFTs, badges, custom.
2039
+ *
2040
+ * @example
2041
+ * ```ts
2042
+ * // Award a badge to two users
2043
+ * const rewards = await client.rewards.award({
2044
+ * definition_id: 'badge-def-id',
2045
+ * user_ids: ['user-1', 'user-2'],
2046
+ * distribute_immediately: true,
2047
+ * });
2048
+ * ```
2049
+ */
2050
+ award(request: ManualRewardRequest): Promise<EarnedReward[]>;
2051
+ /**
2052
+ * @deprecated Use {@link award} instead.
1990
2053
  */
1991
2054
  awardManual(request: ManualRewardRequest): Promise<EarnedReward[]>;
1992
2055
  /**
1993
- * Distribute pending rewards (mint NFTs, transfer tokens)
2056
+ * Distribute a pending or failed reward.
2057
+ * Works for all reward types — triggers the appropriate distribution
2058
+ * (mint NFT, transfer tokens, issue badge, credit points, etc.).
2059
+ *
2060
+ * @example
2061
+ * ```ts
2062
+ * // Distribute a pending reward
2063
+ * const result = await client.rewards.distribute('earned-reward-id');
2064
+ * ```
2065
+ */
2066
+ distribute(earnedRewardId: string): Promise<DistributeResult>;
2067
+ /**
2068
+ * @deprecated Use {@link distribute} instead.
2069
+ */
2070
+ distributePending(earnedRewardId: string): Promise<DistributeResult>;
2071
+ /**
2072
+ * Distribute all pending rewards for the tenant.
2073
+ * Queues every pending reward for background distribution.
2074
+ */
2075
+ distributeAll(): Promise<{
2076
+ queued: number;
2077
+ }>;
2078
+ /**
2079
+ * Revoke an earned reward.
2080
+ *
2081
+ * @param earnedRewardId - The earned reward ID to revoke
2082
+ * @param reason - Reason for revocation
1994
2083
  */
1995
- distributePending(earnedRewardId: string): Promise<EarnedReward>;
2084
+ revoke(earnedRewardId: string, reason: string): Promise<RevokeResult>;
1996
2085
  /**
1997
2086
  * Upload an asset for a reward (image, metadata JSON)
1998
2087
  */
@@ -3128,6 +3217,16 @@ interface IngestionClientOptions {
3128
3217
  ingestUrl?: string;
3129
3218
  timeout?: number;
3130
3219
  }
3220
+ interface EndUserIngestionClientOptions {
3221
+ /** End-user JWT from your auth provider (Auth0, Firebase, Clerk, etc.) */
3222
+ userToken: string;
3223
+ /** Proofchain tenant slug or client_id */
3224
+ tenantId: string;
3225
+ /** Base URL for the tenant API (default: https://api.proofchain.co.za) */
3226
+ apiUrl?: string;
3227
+ /** Request timeout in ms (default: 30000) */
3228
+ timeout?: number;
3229
+ }
3131
3230
  /**
3132
3231
  * High-performance ingestion client for the Rust ingestion API.
3133
3232
  *
@@ -3176,6 +3275,47 @@ declare class IngestionClient {
3176
3275
  ipfsHash?: string;
3177
3276
  }>;
3178
3277
  }
3278
+ /**
3279
+ * End-user ingestion client that routes events through the tenant-api JWKS proxy.
3280
+ * Events are validated (JWT + user_id enforcement) then forwarded to the Rust
3281
+ * ingestion pipeline for consistent processing.
3282
+ *
3283
+ * @example
3284
+ * ```typescript
3285
+ * const ingestion = new EndUserIngestionClient({
3286
+ * userToken: auth.getIdToken(),
3287
+ * tenantId: 'my-tenant-slug',
3288
+ * });
3289
+ *
3290
+ * // Submit event (user_id MUST match the JWT's user identity)
3291
+ * const result = await ingestion.ingest({
3292
+ * userId: 'user-123',
3293
+ * eventType: 'page_view',
3294
+ * data: { page: '/home' },
3295
+ * });
3296
+ * ```
3297
+ */
3298
+ declare class EndUserIngestionClient {
3299
+ private userToken;
3300
+ private tenantId;
3301
+ private apiUrl;
3302
+ private timeout;
3303
+ constructor(options: EndUserIngestionClientOptions);
3304
+ /** Update the end-user JWT token (e.g., after token refresh). */
3305
+ setToken(userToken: string): void;
3306
+ private getHeaders;
3307
+ private handleResponse;
3308
+ /**
3309
+ * Submit a single event as an authenticated end-user.
3310
+ * The userId MUST match the JWT's user identity or the request will be rejected with 403.
3311
+ */
3312
+ ingest(request: IngestEventRequest): Promise<IngestEventResponse>;
3313
+ /**
3314
+ * Submit a batch of events as an authenticated end-user (up to 100 events).
3315
+ * ALL events must have userId matching the JWT's user identity.
3316
+ */
3317
+ ingestBatch(request: BatchIngestRequest): Promise<BatchIngestResponse>;
3318
+ }
3179
3319
 
3180
3320
  /**
3181
3321
  * ProofChain SDK Error Classes
@@ -3217,4 +3357,4 @@ declare class TimeoutError extends ProofChainError {
3217
3357
  constructor(message?: string);
3218
3358
  }
3219
3359
 
3220
- export { type Achievement, type ActivitySummaryView, type AddNFTRequest, type ApiKey, type AttestRequest, type AttestationMode, type AttestationResult, AuthenticationError, AuthorizationError, type AvailableView, type Badge, type BatchIngestRequest, type BatchIngestResponse, type BatchVerifyResult, type BlockchainProof, type BlockchainStats, type Certificate, type CertificateVerifyResult, CertificatesResource, type Channel, type ChannelState, type ChannelStatus, ChannelsResource, type ClaimRewardResult, type CohortDefinition, type CohortGroupStats, CohortLeaderboardClient, type CohortLeaderboardEntry, type CohortLeaderboardOptions, type CohortLeaderboardResponse, type ComprehensiveWalletInfo, type CreateAchievementRequest, type CreateApiKeyRequest, type CreateBadgeRequest, type CreateChannelRequest, type CreateDataViewRequest, type CreateDualWalletsRequest, type CreateEndUserRequest, type CreateEventRequest, type CreatePassportDefinitionRequest, type CreatePassportRequest, type CreateQuestRequest, type CreateQuestStepRequest, type CreateRewardDefinitionRequest, type CreateSchemaRequest, type CreateTemplateFieldRequest, type CreateTemplateRequest, type CreateWalletRequest as CreateUserWalletRequest, type CreateWalletRequest$1 as CreateWalletRequest, type CreateWebhookRequest, type DataViewColumn, type DataViewComputation, type DataViewDetail, type DataViewExecuteResult, type DataViewInfo, type DataViewListResponse, type DataViewPreviewRequest, type DataViewPreviewResult, type DataViewSummary, DataViewsClient, DocumentsResource, type DualWallets, type EarnedReward, type EndUser, type EndUserListResponse, EndUsersClient, type Event, type EventBatchProof, type EventMetadata, type EventStatus, EventsResource, type ExecuteSwapRequest, type Facet, type FacetsResponse, type FanProfileView, type FanpassGroupStats, FanpassLeaderboardClient, type FanpassLeaderboardEntry, type FanpassLeaderboardOptions, type FanpassLeaderboardResponse, type FanpassUserComparisonResponse, type FieldValue, type GDPRDeletionRequest, type GDPRDeletionResponse, type GDPRPreviewResponse, type IngestEventRequest, type IngestEventResponse, IngestionClient, type IngestionClientOptions, type IssueCertificateRequest, type LeaderboardUserProfile$1 as LeaderboardUserProfile, type LinkWalletRequest, type ListCertificatesRequest, type ListCohortsOptions, type ListEndUsersOptions, type ListEventsRequest, type ListQuestsOptions, type ListRewardsOptions, type ListSchemasOptions, type ManualRewardRequest, type MergeUsersRequest, type Milestone, type NFT, NetworkError, NotFoundError, type Passport, PassportClient, type PassportDefinition, type PassportFieldValue, type PassportHistory, type PassportTemplate, type PassportV2Data, type PassportWithFields, ProofChain, ProofChainError, type ProofChainOptions, type ProofVerifyResult, type Quest, type QuestStep, type QuestWithProgress, QuestsClient, RateLimitError, type RegisterWalletRequest, type RewardAsset, type RewardDefinition, type RewardEarned, RewardsClient, type Schema, type SchemaDetail, type SchemaField, type SchemaListResponse, type ValidationError$1 as SchemaValidationError, SchemasClient, type SearchFilters, type SearchQueryRequest, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type SearchStats, ServerError, type SetProfileRequest, type Settlement, type StepCompletionResult, type StepProgress, type StreamAck, type StreamEventRequest, type SwapQuote, type SwapQuoteRequest, type SwapResult, type TemplateField, type TenantInfo, TenantResource, type TierDefinition, TimeoutError, type TokenBalance, type TransferRequest, type TransferResult, type UpdateDataViewRequest, type UpdateEndUserRequest, type UpdatePassportRequest, type UpdateWebhookRequest, type UsageStats, type UserAchievement, type UserActivity, type UserActivityResponse, type UserBadge, type UserBreakdownResponse, type UserCohortBreakdownEntry, type UserQuestProgress, type UserReward$1 as UserReward, type UserRewardsResponse, type UserWalletSummary, type UserWithWallets, type UsersWithWalletsResponse, type ValidateDataRequest, ValidationError, type ValidationErrorDetail, type ValidationResult, type VaultFile, type VaultFolder, type VaultListResponse, VaultResource, type VaultStats, type VaultUploadRequest, type VerificationResult, VerifyResource, type ViewColumn, type ViewTemplate, type Wallet, type WalletBalance, WalletClient, type WalletCreationResult, type WalletStats, type Webhook, WebhooksResource };
3360
+ export { type Achievement, type ActivitySummaryView, type AddNFTRequest, type ApiKey, type AttestRequest, type AttestationMode, type AttestationResult, AuthenticationError, AuthorizationError, type AvailableView, type Badge, type BatchIngestRequest, type BatchIngestResponse, type BatchVerifyResult, type BlockchainProof, type BlockchainStats, type Certificate, type CertificateVerifyResult, CertificatesResource, type Channel, type ChannelState, type ChannelStatus, ChannelsResource, type ClaimNFTResult, type ClaimRewardResult, type CohortDefinition, type CohortGroupStats, CohortLeaderboardClient, type CohortLeaderboardEntry, type CohortLeaderboardOptions, type CohortLeaderboardResponse, type ComprehensiveWalletInfo, type CreateAchievementRequest, type CreateApiKeyRequest, type CreateBadgeRequest, type CreateChannelRequest, type CreateDataViewRequest, type CreateDualWalletsRequest, type CreateEndUserRequest, type CreateEventRequest, type CreatePassportDefinitionRequest, type CreatePassportRequest, type CreateQuestRequest, type CreateQuestStepRequest, type CreateRewardDefinitionRequest, type CreateSchemaRequest, type CreateTemplateFieldRequest, type CreateTemplateRequest, type CreateWalletRequest as CreateUserWalletRequest, type CreateWalletRequest$1 as CreateWalletRequest, type CreateWebhookRequest, type DataViewColumn, type DataViewComputation, type DataViewDetail, type DataViewExecuteResult, type DataViewInfo, type DataViewListResponse, type DataViewPreviewRequest, type DataViewPreviewResult, type DataViewSummary, DataViewsClient, type DistributeResult, DocumentsResource, type DualWallets, type EarnedReward, type EndUser, EndUserIngestionClient, type EndUserIngestionClientOptions, type EndUserListResponse, EndUsersClient, type Event, type EventBatchProof, type EventMetadata, type EventStatus, EventsResource, type ExecuteSwapRequest, type Facet, type FacetsResponse, type FanProfileView, type FanpassGroupStats, FanpassLeaderboardClient, type FanpassLeaderboardEntry, type FanpassLeaderboardOptions, type FanpassLeaderboardResponse, type FanpassUserComparisonResponse, type FieldValue, type GDPRDeletionRequest, type GDPRDeletionResponse, type GDPRPreviewResponse, type IngestEventRequest, type IngestEventResponse, IngestionClient, type IngestionClientOptions, type IssueCertificateRequest, type LeaderboardUserProfile$1 as LeaderboardUserProfile, type LinkWalletRequest, type ListCertificatesRequest, type ListCohortsOptions, type ListEndUsersOptions, type ListEventsRequest, type ListQuestsOptions, type ListRewardsOptions, type ListSchemasOptions, type ManualRewardRequest, type MergeUsersRequest, type Milestone, type NFT, NetworkError, NotFoundError, type Passport, PassportClient, type PassportDefinition, type PassportFieldValue, type PassportHistory, type PassportTemplate, type PassportV2Data, type PassportWithFields, ProofChain, ProofChainError, type ProofChainOptions, type ProofVerifyResult, type Quest, type QuestStep, type QuestWithProgress, QuestsClient, RateLimitError, type RegisterWalletRequest, type RevokeResult, type RewardAsset, type RewardDefinition, type RewardEarned, RewardsClient, type Schema, type SchemaDetail, type SchemaField, type SchemaListResponse, type ValidationError$1 as SchemaValidationError, SchemasClient, type SearchFilters, type SearchQueryRequest, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type SearchStats, ServerError, type SetProfileRequest, type Settlement, type StepCompletionResult, type StepProgress, type StreamAck, type StreamEventRequest, type SwapQuote, type SwapQuoteRequest, type SwapResult, type TemplateField, type TenantInfo, TenantResource, type TierDefinition, TimeoutError, type TokenBalance, type TransferRequest, type TransferResult, type UpdateDataViewRequest, type UpdateEndUserRequest, type UpdatePassportRequest, type UpdateWebhookRequest, type UsageStats, type UserAchievement, type UserActivity, type UserActivityResponse, type UserBadge, type UserBreakdownResponse, type UserCohortBreakdownEntry, type UserQuestProgress, type UserReward$1 as UserReward, type UserRewardsResponse, type UserWalletSummary, type UserWithWallets, type UsersWithWalletsResponse, type ValidateDataRequest, ValidationError, type ValidationErrorDetail, type ValidationResult, type VaultFile, type VaultFolder, type VaultListResponse, VaultResource, type VaultStats, type VaultUploadRequest, type VerificationResult, VerifyResource, type ViewColumn, type ViewTemplate, type Wallet, type WalletBalance, WalletClient, type WalletCreationResult, type WalletStats, type Webhook, WebhooksResource };
package/dist/index.d.ts CHANGED
@@ -1858,6 +1858,7 @@ interface UserReward {
1858
1858
  id: string;
1859
1859
  reward_name: string;
1860
1860
  reward_type: string;
1861
+ category?: string;
1861
1862
  slug?: string;
1862
1863
  description?: string;
1863
1864
  status: string;
@@ -1914,6 +1915,23 @@ interface ManualRewardRequest {
1914
1915
  trigger_data?: Record<string, any>;
1915
1916
  distribute_immediately?: boolean;
1916
1917
  }
1918
+ interface ClaimNFTResult {
1919
+ success: boolean;
1920
+ reward_id: string;
1921
+ token_id?: number;
1922
+ tx_hash: string;
1923
+ wallet_address: string;
1924
+ }
1925
+ interface DistributeResult {
1926
+ success: boolean;
1927
+ reward_id: string;
1928
+ message: string;
1929
+ }
1930
+ interface RevokeResult {
1931
+ success: boolean;
1932
+ reward_id: string;
1933
+ status: string;
1934
+ }
1917
1935
  interface ListRewardsOptions {
1918
1936
  is_active?: boolean;
1919
1937
  reward_type?: string;
@@ -1962,37 +1980,108 @@ declare class RewardsClient {
1962
1980
  offset?: number;
1963
1981
  }): Promise<EarnedReward[]>;
1964
1982
  /**
1965
- * Get earned rewards for a user (with full badge/reward details)
1983
+ * Get earned rewards for a user (with full badge/reward details).
1984
+ * Use this to display a user's reward collection on a dedicated screen.
1985
+ *
1986
+ * @example
1987
+ * ```ts
1988
+ * // All user rewards
1989
+ * const all = await client.rewards.getUserRewards('user-123');
1990
+ *
1991
+ * // Only badges in the "Fan Pass" category
1992
+ * const badges = await client.rewards.getUserRewards('user-123', {
1993
+ * reward_type: 'badge',
1994
+ * category: 'Fan Pass',
1995
+ * });
1996
+ *
1997
+ * // Only distributed rewards
1998
+ * const distributed = await client.rewards.getUserRewards('user-123', {
1999
+ * status: 'distributed',
2000
+ * });
2001
+ * ```
1966
2002
  */
1967
2003
  getUserRewards(userId: string, options?: {
1968
2004
  status?: string;
1969
2005
  reward_type?: string;
2006
+ category?: string;
1970
2007
  }): Promise<UserReward[]>;
1971
2008
  /**
1972
- * Get the public reward catalog (active, public reward definitions)
2009
+ * Get the public reward catalog (active, public reward definitions).
1973
2010
  * Available to both API key and end-user JWT clients.
2011
+ *
2012
+ * @param category - Optional category filter (e.g. "Fan Pass", "Partner: Acme")
2013
+ *
2014
+ * @example
2015
+ * ```ts
2016
+ * // All available rewards
2017
+ * const all = await client.rewards.getCatalog();
2018
+ *
2019
+ * // Only "Fan Pass" rewards
2020
+ * const fanPass = await client.rewards.getCatalog('Fan Pass');
2021
+ * ```
1974
2022
  */
1975
- getCatalog(): Promise<RewardDefinition[]>;
2023
+ getCatalog(category?: string): Promise<RewardDefinition[]>;
1976
2024
  /**
1977
2025
  * Claim a lazy-minted NFT reward.
1978
2026
  * The wallet_address receives the minted NFT. The tenant's treasury pays gas.
1979
2027
  * Available to both API key and end-user JWT clients (scoped to own rewards).
2028
+ *
2029
+ * For non-NFT rewards, use {@link distribute} instead.
1980
2030
  */
1981
- claimReward(earnedRewardId: string, walletAddress: string): Promise<{
1982
- success: boolean;
1983
- reward_id: string;
1984
- token_id?: number;
1985
- tx_hash: string;
1986
- wallet_address: string;
1987
- }>;
2031
+ claimNFT(earnedRewardId: string, walletAddress: string): Promise<ClaimNFTResult>;
2032
+ /**
2033
+ * @deprecated Use {@link claimNFT} instead — this method only works for lazy-mint NFTs.
2034
+ */
2035
+ claimReward(earnedRewardId: string, walletAddress: string): Promise<ClaimNFTResult>;
1988
2036
  /**
1989
- * Manually award rewards to users
2037
+ * Manually award rewards to one or more users.
2038
+ * Works for all reward types: points, tokens, NFTs, badges, custom.
2039
+ *
2040
+ * @example
2041
+ * ```ts
2042
+ * // Award a badge to two users
2043
+ * const rewards = await client.rewards.award({
2044
+ * definition_id: 'badge-def-id',
2045
+ * user_ids: ['user-1', 'user-2'],
2046
+ * distribute_immediately: true,
2047
+ * });
2048
+ * ```
2049
+ */
2050
+ award(request: ManualRewardRequest): Promise<EarnedReward[]>;
2051
+ /**
2052
+ * @deprecated Use {@link award} instead.
1990
2053
  */
1991
2054
  awardManual(request: ManualRewardRequest): Promise<EarnedReward[]>;
1992
2055
  /**
1993
- * Distribute pending rewards (mint NFTs, transfer tokens)
2056
+ * Distribute a pending or failed reward.
2057
+ * Works for all reward types — triggers the appropriate distribution
2058
+ * (mint NFT, transfer tokens, issue badge, credit points, etc.).
2059
+ *
2060
+ * @example
2061
+ * ```ts
2062
+ * // Distribute a pending reward
2063
+ * const result = await client.rewards.distribute('earned-reward-id');
2064
+ * ```
2065
+ */
2066
+ distribute(earnedRewardId: string): Promise<DistributeResult>;
2067
+ /**
2068
+ * @deprecated Use {@link distribute} instead.
2069
+ */
2070
+ distributePending(earnedRewardId: string): Promise<DistributeResult>;
2071
+ /**
2072
+ * Distribute all pending rewards for the tenant.
2073
+ * Queues every pending reward for background distribution.
2074
+ */
2075
+ distributeAll(): Promise<{
2076
+ queued: number;
2077
+ }>;
2078
+ /**
2079
+ * Revoke an earned reward.
2080
+ *
2081
+ * @param earnedRewardId - The earned reward ID to revoke
2082
+ * @param reason - Reason for revocation
1994
2083
  */
1995
- distributePending(earnedRewardId: string): Promise<EarnedReward>;
2084
+ revoke(earnedRewardId: string, reason: string): Promise<RevokeResult>;
1996
2085
  /**
1997
2086
  * Upload an asset for a reward (image, metadata JSON)
1998
2087
  */
@@ -3128,6 +3217,16 @@ interface IngestionClientOptions {
3128
3217
  ingestUrl?: string;
3129
3218
  timeout?: number;
3130
3219
  }
3220
+ interface EndUserIngestionClientOptions {
3221
+ /** End-user JWT from your auth provider (Auth0, Firebase, Clerk, etc.) */
3222
+ userToken: string;
3223
+ /** Proofchain tenant slug or client_id */
3224
+ tenantId: string;
3225
+ /** Base URL for the tenant API (default: https://api.proofchain.co.za) */
3226
+ apiUrl?: string;
3227
+ /** Request timeout in ms (default: 30000) */
3228
+ timeout?: number;
3229
+ }
3131
3230
  /**
3132
3231
  * High-performance ingestion client for the Rust ingestion API.
3133
3232
  *
@@ -3176,6 +3275,47 @@ declare class IngestionClient {
3176
3275
  ipfsHash?: string;
3177
3276
  }>;
3178
3277
  }
3278
+ /**
3279
+ * End-user ingestion client that routes events through the tenant-api JWKS proxy.
3280
+ * Events are validated (JWT + user_id enforcement) then forwarded to the Rust
3281
+ * ingestion pipeline for consistent processing.
3282
+ *
3283
+ * @example
3284
+ * ```typescript
3285
+ * const ingestion = new EndUserIngestionClient({
3286
+ * userToken: auth.getIdToken(),
3287
+ * tenantId: 'my-tenant-slug',
3288
+ * });
3289
+ *
3290
+ * // Submit event (user_id MUST match the JWT's user identity)
3291
+ * const result = await ingestion.ingest({
3292
+ * userId: 'user-123',
3293
+ * eventType: 'page_view',
3294
+ * data: { page: '/home' },
3295
+ * });
3296
+ * ```
3297
+ */
3298
+ declare class EndUserIngestionClient {
3299
+ private userToken;
3300
+ private tenantId;
3301
+ private apiUrl;
3302
+ private timeout;
3303
+ constructor(options: EndUserIngestionClientOptions);
3304
+ /** Update the end-user JWT token (e.g., after token refresh). */
3305
+ setToken(userToken: string): void;
3306
+ private getHeaders;
3307
+ private handleResponse;
3308
+ /**
3309
+ * Submit a single event as an authenticated end-user.
3310
+ * The userId MUST match the JWT's user identity or the request will be rejected with 403.
3311
+ */
3312
+ ingest(request: IngestEventRequest): Promise<IngestEventResponse>;
3313
+ /**
3314
+ * Submit a batch of events as an authenticated end-user (up to 100 events).
3315
+ * ALL events must have userId matching the JWT's user identity.
3316
+ */
3317
+ ingestBatch(request: BatchIngestRequest): Promise<BatchIngestResponse>;
3318
+ }
3179
3319
 
3180
3320
  /**
3181
3321
  * ProofChain SDK Error Classes
@@ -3217,4 +3357,4 @@ declare class TimeoutError extends ProofChainError {
3217
3357
  constructor(message?: string);
3218
3358
  }
3219
3359
 
3220
- export { type Achievement, type ActivitySummaryView, type AddNFTRequest, type ApiKey, type AttestRequest, type AttestationMode, type AttestationResult, AuthenticationError, AuthorizationError, type AvailableView, type Badge, type BatchIngestRequest, type BatchIngestResponse, type BatchVerifyResult, type BlockchainProof, type BlockchainStats, type Certificate, type CertificateVerifyResult, CertificatesResource, type Channel, type ChannelState, type ChannelStatus, ChannelsResource, type ClaimRewardResult, type CohortDefinition, type CohortGroupStats, CohortLeaderboardClient, type CohortLeaderboardEntry, type CohortLeaderboardOptions, type CohortLeaderboardResponse, type ComprehensiveWalletInfo, type CreateAchievementRequest, type CreateApiKeyRequest, type CreateBadgeRequest, type CreateChannelRequest, type CreateDataViewRequest, type CreateDualWalletsRequest, type CreateEndUserRequest, type CreateEventRequest, type CreatePassportDefinitionRequest, type CreatePassportRequest, type CreateQuestRequest, type CreateQuestStepRequest, type CreateRewardDefinitionRequest, type CreateSchemaRequest, type CreateTemplateFieldRequest, type CreateTemplateRequest, type CreateWalletRequest as CreateUserWalletRequest, type CreateWalletRequest$1 as CreateWalletRequest, type CreateWebhookRequest, type DataViewColumn, type DataViewComputation, type DataViewDetail, type DataViewExecuteResult, type DataViewInfo, type DataViewListResponse, type DataViewPreviewRequest, type DataViewPreviewResult, type DataViewSummary, DataViewsClient, DocumentsResource, type DualWallets, type EarnedReward, type EndUser, type EndUserListResponse, EndUsersClient, type Event, type EventBatchProof, type EventMetadata, type EventStatus, EventsResource, type ExecuteSwapRequest, type Facet, type FacetsResponse, type FanProfileView, type FanpassGroupStats, FanpassLeaderboardClient, type FanpassLeaderboardEntry, type FanpassLeaderboardOptions, type FanpassLeaderboardResponse, type FanpassUserComparisonResponse, type FieldValue, type GDPRDeletionRequest, type GDPRDeletionResponse, type GDPRPreviewResponse, type IngestEventRequest, type IngestEventResponse, IngestionClient, type IngestionClientOptions, type IssueCertificateRequest, type LeaderboardUserProfile$1 as LeaderboardUserProfile, type LinkWalletRequest, type ListCertificatesRequest, type ListCohortsOptions, type ListEndUsersOptions, type ListEventsRequest, type ListQuestsOptions, type ListRewardsOptions, type ListSchemasOptions, type ManualRewardRequest, type MergeUsersRequest, type Milestone, type NFT, NetworkError, NotFoundError, type Passport, PassportClient, type PassportDefinition, type PassportFieldValue, type PassportHistory, type PassportTemplate, type PassportV2Data, type PassportWithFields, ProofChain, ProofChainError, type ProofChainOptions, type ProofVerifyResult, type Quest, type QuestStep, type QuestWithProgress, QuestsClient, RateLimitError, type RegisterWalletRequest, type RewardAsset, type RewardDefinition, type RewardEarned, RewardsClient, type Schema, type SchemaDetail, type SchemaField, type SchemaListResponse, type ValidationError$1 as SchemaValidationError, SchemasClient, type SearchFilters, type SearchQueryRequest, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type SearchStats, ServerError, type SetProfileRequest, type Settlement, type StepCompletionResult, type StepProgress, type StreamAck, type StreamEventRequest, type SwapQuote, type SwapQuoteRequest, type SwapResult, type TemplateField, type TenantInfo, TenantResource, type TierDefinition, TimeoutError, type TokenBalance, type TransferRequest, type TransferResult, type UpdateDataViewRequest, type UpdateEndUserRequest, type UpdatePassportRequest, type UpdateWebhookRequest, type UsageStats, type UserAchievement, type UserActivity, type UserActivityResponse, type UserBadge, type UserBreakdownResponse, type UserCohortBreakdownEntry, type UserQuestProgress, type UserReward$1 as UserReward, type UserRewardsResponse, type UserWalletSummary, type UserWithWallets, type UsersWithWalletsResponse, type ValidateDataRequest, ValidationError, type ValidationErrorDetail, type ValidationResult, type VaultFile, type VaultFolder, type VaultListResponse, VaultResource, type VaultStats, type VaultUploadRequest, type VerificationResult, VerifyResource, type ViewColumn, type ViewTemplate, type Wallet, type WalletBalance, WalletClient, type WalletCreationResult, type WalletStats, type Webhook, WebhooksResource };
3360
+ export { type Achievement, type ActivitySummaryView, type AddNFTRequest, type ApiKey, type AttestRequest, type AttestationMode, type AttestationResult, AuthenticationError, AuthorizationError, type AvailableView, type Badge, type BatchIngestRequest, type BatchIngestResponse, type BatchVerifyResult, type BlockchainProof, type BlockchainStats, type Certificate, type CertificateVerifyResult, CertificatesResource, type Channel, type ChannelState, type ChannelStatus, ChannelsResource, type ClaimNFTResult, type ClaimRewardResult, type CohortDefinition, type CohortGroupStats, CohortLeaderboardClient, type CohortLeaderboardEntry, type CohortLeaderboardOptions, type CohortLeaderboardResponse, type ComprehensiveWalletInfo, type CreateAchievementRequest, type CreateApiKeyRequest, type CreateBadgeRequest, type CreateChannelRequest, type CreateDataViewRequest, type CreateDualWalletsRequest, type CreateEndUserRequest, type CreateEventRequest, type CreatePassportDefinitionRequest, type CreatePassportRequest, type CreateQuestRequest, type CreateQuestStepRequest, type CreateRewardDefinitionRequest, type CreateSchemaRequest, type CreateTemplateFieldRequest, type CreateTemplateRequest, type CreateWalletRequest as CreateUserWalletRequest, type CreateWalletRequest$1 as CreateWalletRequest, type CreateWebhookRequest, type DataViewColumn, type DataViewComputation, type DataViewDetail, type DataViewExecuteResult, type DataViewInfo, type DataViewListResponse, type DataViewPreviewRequest, type DataViewPreviewResult, type DataViewSummary, DataViewsClient, type DistributeResult, DocumentsResource, type DualWallets, type EarnedReward, type EndUser, EndUserIngestionClient, type EndUserIngestionClientOptions, type EndUserListResponse, EndUsersClient, type Event, type EventBatchProof, type EventMetadata, type EventStatus, EventsResource, type ExecuteSwapRequest, type Facet, type FacetsResponse, type FanProfileView, type FanpassGroupStats, FanpassLeaderboardClient, type FanpassLeaderboardEntry, type FanpassLeaderboardOptions, type FanpassLeaderboardResponse, type FanpassUserComparisonResponse, type FieldValue, type GDPRDeletionRequest, type GDPRDeletionResponse, type GDPRPreviewResponse, type IngestEventRequest, type IngestEventResponse, IngestionClient, type IngestionClientOptions, type IssueCertificateRequest, type LeaderboardUserProfile$1 as LeaderboardUserProfile, type LinkWalletRequest, type ListCertificatesRequest, type ListCohortsOptions, type ListEndUsersOptions, type ListEventsRequest, type ListQuestsOptions, type ListRewardsOptions, type ListSchemasOptions, type ManualRewardRequest, type MergeUsersRequest, type Milestone, type NFT, NetworkError, NotFoundError, type Passport, PassportClient, type PassportDefinition, type PassportFieldValue, type PassportHistory, type PassportTemplate, type PassportV2Data, type PassportWithFields, ProofChain, ProofChainError, type ProofChainOptions, type ProofVerifyResult, type Quest, type QuestStep, type QuestWithProgress, QuestsClient, RateLimitError, type RegisterWalletRequest, type RevokeResult, type RewardAsset, type RewardDefinition, type RewardEarned, RewardsClient, type Schema, type SchemaDetail, type SchemaField, type SchemaListResponse, type ValidationError$1 as SchemaValidationError, SchemasClient, type SearchFilters, type SearchQueryRequest, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type SearchStats, ServerError, type SetProfileRequest, type Settlement, type StepCompletionResult, type StepProgress, type StreamAck, type StreamEventRequest, type SwapQuote, type SwapQuoteRequest, type SwapResult, type TemplateField, type TenantInfo, TenantResource, type TierDefinition, TimeoutError, type TokenBalance, type TransferRequest, type TransferResult, type UpdateDataViewRequest, type UpdateEndUserRequest, type UpdatePassportRequest, type UpdateWebhookRequest, type UsageStats, type UserAchievement, type UserActivity, type UserActivityResponse, type UserBadge, type UserBreakdownResponse, type UserCohortBreakdownEntry, type UserQuestProgress, type UserReward$1 as UserReward, type UserRewardsResponse, type UserWalletSummary, type UserWithWallets, type UsersWithWalletsResponse, type ValidateDataRequest, ValidationError, type ValidationErrorDetail, type ValidationResult, type VaultFile, type VaultFolder, type VaultListResponse, VaultResource, type VaultStats, type VaultUploadRequest, type VerificationResult, VerifyResource, type ViewColumn, type ViewTemplate, type Wallet, type WalletBalance, WalletClient, type WalletCreationResult, type WalletStats, type Webhook, WebhooksResource };
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  CohortLeaderboardClient: () => CohortLeaderboardClient,
28
28
  DataViewsClient: () => DataViewsClient,
29
29
  DocumentsResource: () => DocumentsResource,
30
+ EndUserIngestionClient: () => EndUserIngestionClient,
30
31
  EndUsersClient: () => EndUsersClient,
31
32
  EventsResource: () => EventsResource,
32
33
  FanpassLeaderboardClient: () => FanpassLeaderboardClient,
@@ -1465,42 +1466,133 @@ var RewardsClient = class {
1465
1466
  return this.http.get(`/rewards/earned?${params.toString()}`);
1466
1467
  }
1467
1468
  /**
1468
- * Get earned rewards for a user (with full badge/reward details)
1469
+ * Get earned rewards for a user (with full badge/reward details).
1470
+ * Use this to display a user's reward collection on a dedicated screen.
1471
+ *
1472
+ * @example
1473
+ * ```ts
1474
+ * // All user rewards
1475
+ * const all = await client.rewards.getUserRewards('user-123');
1476
+ *
1477
+ * // Only badges in the "Fan Pass" category
1478
+ * const badges = await client.rewards.getUserRewards('user-123', {
1479
+ * reward_type: 'badge',
1480
+ * category: 'Fan Pass',
1481
+ * });
1482
+ *
1483
+ * // Only distributed rewards
1484
+ * const distributed = await client.rewards.getUserRewards('user-123', {
1485
+ * status: 'distributed',
1486
+ * });
1487
+ * ```
1469
1488
  */
1470
1489
  async getUserRewards(userId, options = {}) {
1471
1490
  const params = new URLSearchParams();
1472
1491
  if (options.status) params.append("status", options.status);
1473
1492
  if (options.reward_type) params.append("reward_type", options.reward_type);
1493
+ if (options.category) params.append("category", options.category);
1474
1494
  const query = params.toString();
1475
1495
  return this.http.get(`/rewards/users/${userId}/rewards${query ? "?" + query : ""}`);
1476
1496
  }
1477
1497
  /**
1478
- * Get the public reward catalog (active, public reward definitions)
1498
+ * Get the public reward catalog (active, public reward definitions).
1479
1499
  * Available to both API key and end-user JWT clients.
1500
+ *
1501
+ * @param category - Optional category filter (e.g. "Fan Pass", "Partner: Acme")
1502
+ *
1503
+ * @example
1504
+ * ```ts
1505
+ * // All available rewards
1506
+ * const all = await client.rewards.getCatalog();
1507
+ *
1508
+ * // Only "Fan Pass" rewards
1509
+ * const fanPass = await client.rewards.getCatalog('Fan Pass');
1510
+ * ```
1480
1511
  */
1481
- async getCatalog() {
1482
- return this.http.get("/rewards/catalog");
1512
+ async getCatalog(category) {
1513
+ const params = new URLSearchParams();
1514
+ if (category) params.append("category", category);
1515
+ const query = params.toString();
1516
+ return this.http.get(`/rewards/catalog${query ? "?" + query : ""}`);
1483
1517
  }
1484
1518
  /**
1485
1519
  * Claim a lazy-minted NFT reward.
1486
1520
  * The wallet_address receives the minted NFT. The tenant's treasury pays gas.
1487
1521
  * Available to both API key and end-user JWT clients (scoped to own rewards).
1522
+ *
1523
+ * For non-NFT rewards, use {@link distribute} instead.
1488
1524
  */
1489
- async claimReward(earnedRewardId, walletAddress) {
1525
+ async claimNFT(earnedRewardId, walletAddress) {
1490
1526
  return this.http.post(`/rewards/earned/${earnedRewardId}/claim?wallet_address=${encodeURIComponent(walletAddress)}`, {});
1491
1527
  }
1492
1528
  /**
1493
- * Manually award rewards to users
1529
+ * @deprecated Use {@link claimNFT} instead — this method only works for lazy-mint NFTs.
1494
1530
  */
1495
- async awardManual(request) {
1531
+ async claimReward(earnedRewardId, walletAddress) {
1532
+ return this.claimNFT(earnedRewardId, walletAddress);
1533
+ }
1534
+ /**
1535
+ * Manually award rewards to one or more users.
1536
+ * Works for all reward types: points, tokens, NFTs, badges, custom.
1537
+ *
1538
+ * @example
1539
+ * ```ts
1540
+ * // Award a badge to two users
1541
+ * const rewards = await client.rewards.award({
1542
+ * definition_id: 'badge-def-id',
1543
+ * user_ids: ['user-1', 'user-2'],
1544
+ * distribute_immediately: true,
1545
+ * });
1546
+ * ```
1547
+ */
1548
+ async award(request) {
1496
1549
  return this.http.post("/rewards/award", request);
1497
1550
  }
1498
1551
  /**
1499
- * Distribute pending rewards (mint NFTs, transfer tokens)
1552
+ * @deprecated Use {@link award} instead.
1500
1553
  */
1501
- async distributePending(earnedRewardId) {
1554
+ async awardManual(request) {
1555
+ return this.award(request);
1556
+ }
1557
+ /**
1558
+ * Distribute a pending or failed reward.
1559
+ * Works for all reward types — triggers the appropriate distribution
1560
+ * (mint NFT, transfer tokens, issue badge, credit points, etc.).
1561
+ *
1562
+ * @example
1563
+ * ```ts
1564
+ * // Distribute a pending reward
1565
+ * const result = await client.rewards.distribute('earned-reward-id');
1566
+ * ```
1567
+ */
1568
+ async distribute(earnedRewardId) {
1502
1569
  return this.http.post(`/rewards/earned/${earnedRewardId}/distribute`, {});
1503
1570
  }
1571
+ /**
1572
+ * @deprecated Use {@link distribute} instead.
1573
+ */
1574
+ async distributePending(earnedRewardId) {
1575
+ return this.distribute(earnedRewardId);
1576
+ }
1577
+ /**
1578
+ * Distribute all pending rewards for the tenant.
1579
+ * Queues every pending reward for background distribution.
1580
+ */
1581
+ async distributeAll() {
1582
+ return this.http.post("/rewards/distribute-all-pending", {});
1583
+ }
1584
+ /**
1585
+ * Revoke an earned reward.
1586
+ *
1587
+ * @param earnedRewardId - The earned reward ID to revoke
1588
+ * @param reason - Reason for revocation
1589
+ */
1590
+ async revoke(earnedRewardId, reason) {
1591
+ return this.http.post(
1592
+ `/rewards/earned/${earnedRewardId}/revoke?reason=${encodeURIComponent(reason)}`,
1593
+ {}
1594
+ );
1595
+ }
1504
1596
  // ---------------------------------------------------------------------------
1505
1597
  // Reward Assets
1506
1598
  // ---------------------------------------------------------------------------
@@ -2552,6 +2644,135 @@ var IngestionClient = class {
2552
2644
  }
2553
2645
  }
2554
2646
  };
2647
+ var EndUserIngestionClient = class {
2648
+ constructor(options) {
2649
+ this.userToken = options.userToken;
2650
+ this.tenantId = options.tenantId;
2651
+ this.apiUrl = (options.apiUrl || "https://api.proofchain.co.za").replace(/\/$/, "");
2652
+ this.timeout = options.timeout || 3e4;
2653
+ }
2654
+ /** Update the end-user JWT token (e.g., after token refresh). */
2655
+ setToken(userToken) {
2656
+ this.userToken = userToken;
2657
+ }
2658
+ getHeaders() {
2659
+ return {
2660
+ "Authorization": `Bearer ${this.userToken}`,
2661
+ "X-Tenant-ID": this.tenantId,
2662
+ "Content-Type": "application/json",
2663
+ "User-Agent": USER_AGENT2
2664
+ };
2665
+ }
2666
+ async handleResponse(response) {
2667
+ const contentType = response.headers.get("content-type");
2668
+ const isJson = contentType?.includes("application/json");
2669
+ if (response.ok) {
2670
+ if (response.status === 204 || !isJson) {
2671
+ return {};
2672
+ }
2673
+ return response.json();
2674
+ }
2675
+ const body = isJson ? await response.json().catch(() => ({})) : {};
2676
+ const message = body.detail || body.message || `HTTP ${response.status}`;
2677
+ switch (response.status) {
2678
+ case 401:
2679
+ throw new AuthenticationError(message);
2680
+ case 403:
2681
+ throw new ProofChainError(message, 403, body);
2682
+ case 422:
2683
+ case 400:
2684
+ throw new ValidationError(message, body.errors);
2685
+ case 429:
2686
+ const retryAfter = response.headers.get("Retry-After");
2687
+ throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
2688
+ default:
2689
+ if (response.status >= 500) {
2690
+ throw new ServerError(message, response.status);
2691
+ }
2692
+ throw new ProofChainError(message, response.status, body);
2693
+ }
2694
+ }
2695
+ /**
2696
+ * Submit a single event as an authenticated end-user.
2697
+ * The userId MUST match the JWT's user identity or the request will be rejected with 403.
2698
+ */
2699
+ async ingest(request) {
2700
+ const controller = new AbortController();
2701
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2702
+ try {
2703
+ const response = await fetch(`${this.apiUrl}/end-user/events/ingest`, {
2704
+ method: "POST",
2705
+ headers: this.getHeaders(),
2706
+ body: JSON.stringify({
2707
+ user_id: request.userId,
2708
+ event_type: request.eventType,
2709
+ data: request.data || {},
2710
+ event_source: request.eventSource || "end_user_sdk"
2711
+ }),
2712
+ signal: controller.signal
2713
+ });
2714
+ const result = await this.handleResponse(response);
2715
+ return {
2716
+ eventId: result.event_id,
2717
+ certificateId: result.certificate_id,
2718
+ status: result.status,
2719
+ queuePosition: result.queue_position,
2720
+ estimatedConfirmation: result.estimated_confirmation
2721
+ };
2722
+ } catch (error) {
2723
+ if (error instanceof Error && error.name === "AbortError") {
2724
+ throw new NetworkError("Request timed out");
2725
+ }
2726
+ throw error;
2727
+ } finally {
2728
+ clearTimeout(timeoutId);
2729
+ }
2730
+ }
2731
+ /**
2732
+ * Submit a batch of events as an authenticated end-user (up to 100 events).
2733
+ * ALL events must have userId matching the JWT's user identity.
2734
+ */
2735
+ async ingestBatch(request) {
2736
+ if (request.events.length > 100) {
2737
+ throw new ValidationError("End-user batch size cannot exceed 100 events");
2738
+ }
2739
+ const controller = new AbortController();
2740
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout * 2);
2741
+ try {
2742
+ const response = await fetch(`${this.apiUrl}/end-user/events/ingest/batch`, {
2743
+ method: "POST",
2744
+ headers: this.getHeaders(),
2745
+ body: JSON.stringify({
2746
+ events: request.events.map((e) => ({
2747
+ user_id: e.userId,
2748
+ event_type: e.eventType,
2749
+ data: e.data || {},
2750
+ event_source: e.eventSource || "end_user_sdk"
2751
+ }))
2752
+ }),
2753
+ signal: controller.signal
2754
+ });
2755
+ const result = await this.handleResponse(response);
2756
+ return {
2757
+ totalEvents: result.total_events || result.total,
2758
+ queued: result.queued,
2759
+ failed: result.failed,
2760
+ results: (result.results || result.responses || []).map((r) => ({
2761
+ eventId: r.event_id,
2762
+ certificateId: r.certificate_id,
2763
+ status: r.status
2764
+ }))
2765
+ };
2766
+ } catch (error) {
2767
+ if (error instanceof Error && error.name === "AbortError") {
2768
+ throw new NetworkError("Request timed out");
2769
+ }
2770
+ throw error;
2771
+ } finally {
2772
+ clearTimeout(timeoutId);
2773
+ }
2774
+ }
2775
+ };
2555
2776
  // Annotate the CommonJS export names for ESM import in node:
2556
2777
  0 && (module.exports = {
2557
2778
  AuthenticationError,
@@ -2561,6 +2782,7 @@ var IngestionClient = class {
2561
2782
  CohortLeaderboardClient,
2562
2783
  DataViewsClient,
2563
2784
  DocumentsResource,
2785
+ EndUserIngestionClient,
2564
2786
  EndUsersClient,
2565
2787
  EventsResource,
2566
2788
  FanpassLeaderboardClient,
package/dist/index.mjs CHANGED
@@ -1411,42 +1411,133 @@ var RewardsClient = class {
1411
1411
  return this.http.get(`/rewards/earned?${params.toString()}`);
1412
1412
  }
1413
1413
  /**
1414
- * Get earned rewards for a user (with full badge/reward details)
1414
+ * Get earned rewards for a user (with full badge/reward details).
1415
+ * Use this to display a user's reward collection on a dedicated screen.
1416
+ *
1417
+ * @example
1418
+ * ```ts
1419
+ * // All user rewards
1420
+ * const all = await client.rewards.getUserRewards('user-123');
1421
+ *
1422
+ * // Only badges in the "Fan Pass" category
1423
+ * const badges = await client.rewards.getUserRewards('user-123', {
1424
+ * reward_type: 'badge',
1425
+ * category: 'Fan Pass',
1426
+ * });
1427
+ *
1428
+ * // Only distributed rewards
1429
+ * const distributed = await client.rewards.getUserRewards('user-123', {
1430
+ * status: 'distributed',
1431
+ * });
1432
+ * ```
1415
1433
  */
1416
1434
  async getUserRewards(userId, options = {}) {
1417
1435
  const params = new URLSearchParams();
1418
1436
  if (options.status) params.append("status", options.status);
1419
1437
  if (options.reward_type) params.append("reward_type", options.reward_type);
1438
+ if (options.category) params.append("category", options.category);
1420
1439
  const query = params.toString();
1421
1440
  return this.http.get(`/rewards/users/${userId}/rewards${query ? "?" + query : ""}`);
1422
1441
  }
1423
1442
  /**
1424
- * Get the public reward catalog (active, public reward definitions)
1443
+ * Get the public reward catalog (active, public reward definitions).
1425
1444
  * Available to both API key and end-user JWT clients.
1445
+ *
1446
+ * @param category - Optional category filter (e.g. "Fan Pass", "Partner: Acme")
1447
+ *
1448
+ * @example
1449
+ * ```ts
1450
+ * // All available rewards
1451
+ * const all = await client.rewards.getCatalog();
1452
+ *
1453
+ * // Only "Fan Pass" rewards
1454
+ * const fanPass = await client.rewards.getCatalog('Fan Pass');
1455
+ * ```
1426
1456
  */
1427
- async getCatalog() {
1428
- return this.http.get("/rewards/catalog");
1457
+ async getCatalog(category) {
1458
+ const params = new URLSearchParams();
1459
+ if (category) params.append("category", category);
1460
+ const query = params.toString();
1461
+ return this.http.get(`/rewards/catalog${query ? "?" + query : ""}`);
1429
1462
  }
1430
1463
  /**
1431
1464
  * Claim a lazy-minted NFT reward.
1432
1465
  * The wallet_address receives the minted NFT. The tenant's treasury pays gas.
1433
1466
  * Available to both API key and end-user JWT clients (scoped to own rewards).
1467
+ *
1468
+ * For non-NFT rewards, use {@link distribute} instead.
1434
1469
  */
1435
- async claimReward(earnedRewardId, walletAddress) {
1470
+ async claimNFT(earnedRewardId, walletAddress) {
1436
1471
  return this.http.post(`/rewards/earned/${earnedRewardId}/claim?wallet_address=${encodeURIComponent(walletAddress)}`, {});
1437
1472
  }
1438
1473
  /**
1439
- * Manually award rewards to users
1474
+ * @deprecated Use {@link claimNFT} instead — this method only works for lazy-mint NFTs.
1440
1475
  */
1441
- async awardManual(request) {
1476
+ async claimReward(earnedRewardId, walletAddress) {
1477
+ return this.claimNFT(earnedRewardId, walletAddress);
1478
+ }
1479
+ /**
1480
+ * Manually award rewards to one or more users.
1481
+ * Works for all reward types: points, tokens, NFTs, badges, custom.
1482
+ *
1483
+ * @example
1484
+ * ```ts
1485
+ * // Award a badge to two users
1486
+ * const rewards = await client.rewards.award({
1487
+ * definition_id: 'badge-def-id',
1488
+ * user_ids: ['user-1', 'user-2'],
1489
+ * distribute_immediately: true,
1490
+ * });
1491
+ * ```
1492
+ */
1493
+ async award(request) {
1442
1494
  return this.http.post("/rewards/award", request);
1443
1495
  }
1444
1496
  /**
1445
- * Distribute pending rewards (mint NFTs, transfer tokens)
1497
+ * @deprecated Use {@link award} instead.
1446
1498
  */
1447
- async distributePending(earnedRewardId) {
1499
+ async awardManual(request) {
1500
+ return this.award(request);
1501
+ }
1502
+ /**
1503
+ * Distribute a pending or failed reward.
1504
+ * Works for all reward types — triggers the appropriate distribution
1505
+ * (mint NFT, transfer tokens, issue badge, credit points, etc.).
1506
+ *
1507
+ * @example
1508
+ * ```ts
1509
+ * // Distribute a pending reward
1510
+ * const result = await client.rewards.distribute('earned-reward-id');
1511
+ * ```
1512
+ */
1513
+ async distribute(earnedRewardId) {
1448
1514
  return this.http.post(`/rewards/earned/${earnedRewardId}/distribute`, {});
1449
1515
  }
1516
+ /**
1517
+ * @deprecated Use {@link distribute} instead.
1518
+ */
1519
+ async distributePending(earnedRewardId) {
1520
+ return this.distribute(earnedRewardId);
1521
+ }
1522
+ /**
1523
+ * Distribute all pending rewards for the tenant.
1524
+ * Queues every pending reward for background distribution.
1525
+ */
1526
+ async distributeAll() {
1527
+ return this.http.post("/rewards/distribute-all-pending", {});
1528
+ }
1529
+ /**
1530
+ * Revoke an earned reward.
1531
+ *
1532
+ * @param earnedRewardId - The earned reward ID to revoke
1533
+ * @param reason - Reason for revocation
1534
+ */
1535
+ async revoke(earnedRewardId, reason) {
1536
+ return this.http.post(
1537
+ `/rewards/earned/${earnedRewardId}/revoke?reason=${encodeURIComponent(reason)}`,
1538
+ {}
1539
+ );
1540
+ }
1450
1541
  // ---------------------------------------------------------------------------
1451
1542
  // Reward Assets
1452
1543
  // ---------------------------------------------------------------------------
@@ -2498,6 +2589,135 @@ var IngestionClient = class {
2498
2589
  }
2499
2590
  }
2500
2591
  };
2592
+ var EndUserIngestionClient = class {
2593
+ constructor(options) {
2594
+ this.userToken = options.userToken;
2595
+ this.tenantId = options.tenantId;
2596
+ this.apiUrl = (options.apiUrl || "https://api.proofchain.co.za").replace(/\/$/, "");
2597
+ this.timeout = options.timeout || 3e4;
2598
+ }
2599
+ /** Update the end-user JWT token (e.g., after token refresh). */
2600
+ setToken(userToken) {
2601
+ this.userToken = userToken;
2602
+ }
2603
+ getHeaders() {
2604
+ return {
2605
+ "Authorization": `Bearer ${this.userToken}`,
2606
+ "X-Tenant-ID": this.tenantId,
2607
+ "Content-Type": "application/json",
2608
+ "User-Agent": USER_AGENT2
2609
+ };
2610
+ }
2611
+ async handleResponse(response) {
2612
+ const contentType = response.headers.get("content-type");
2613
+ const isJson = contentType?.includes("application/json");
2614
+ if (response.ok) {
2615
+ if (response.status === 204 || !isJson) {
2616
+ return {};
2617
+ }
2618
+ return response.json();
2619
+ }
2620
+ const body = isJson ? await response.json().catch(() => ({})) : {};
2621
+ const message = body.detail || body.message || `HTTP ${response.status}`;
2622
+ switch (response.status) {
2623
+ case 401:
2624
+ throw new AuthenticationError(message);
2625
+ case 403:
2626
+ throw new ProofChainError(message, 403, body);
2627
+ case 422:
2628
+ case 400:
2629
+ throw new ValidationError(message, body.errors);
2630
+ case 429:
2631
+ const retryAfter = response.headers.get("Retry-After");
2632
+ throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
2633
+ default:
2634
+ if (response.status >= 500) {
2635
+ throw new ServerError(message, response.status);
2636
+ }
2637
+ throw new ProofChainError(message, response.status, body);
2638
+ }
2639
+ }
2640
+ /**
2641
+ * Submit a single event as an authenticated end-user.
2642
+ * The userId MUST match the JWT's user identity or the request will be rejected with 403.
2643
+ */
2644
+ async ingest(request) {
2645
+ const controller = new AbortController();
2646
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2647
+ try {
2648
+ const response = await fetch(`${this.apiUrl}/end-user/events/ingest`, {
2649
+ method: "POST",
2650
+ headers: this.getHeaders(),
2651
+ body: JSON.stringify({
2652
+ user_id: request.userId,
2653
+ event_type: request.eventType,
2654
+ data: request.data || {},
2655
+ event_source: request.eventSource || "end_user_sdk"
2656
+ }),
2657
+ signal: controller.signal
2658
+ });
2659
+ const result = await this.handleResponse(response);
2660
+ return {
2661
+ eventId: result.event_id,
2662
+ certificateId: result.certificate_id,
2663
+ status: result.status,
2664
+ queuePosition: result.queue_position,
2665
+ estimatedConfirmation: result.estimated_confirmation
2666
+ };
2667
+ } catch (error) {
2668
+ if (error instanceof Error && error.name === "AbortError") {
2669
+ throw new NetworkError("Request timed out");
2670
+ }
2671
+ throw error;
2672
+ } finally {
2673
+ clearTimeout(timeoutId);
2674
+ }
2675
+ }
2676
+ /**
2677
+ * Submit a batch of events as an authenticated end-user (up to 100 events).
2678
+ * ALL events must have userId matching the JWT's user identity.
2679
+ */
2680
+ async ingestBatch(request) {
2681
+ if (request.events.length > 100) {
2682
+ throw new ValidationError("End-user batch size cannot exceed 100 events");
2683
+ }
2684
+ const controller = new AbortController();
2685
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout * 2);
2686
+ try {
2687
+ const response = await fetch(`${this.apiUrl}/end-user/events/ingest/batch`, {
2688
+ method: "POST",
2689
+ headers: this.getHeaders(),
2690
+ body: JSON.stringify({
2691
+ events: request.events.map((e) => ({
2692
+ user_id: e.userId,
2693
+ event_type: e.eventType,
2694
+ data: e.data || {},
2695
+ event_source: e.eventSource || "end_user_sdk"
2696
+ }))
2697
+ }),
2698
+ signal: controller.signal
2699
+ });
2700
+ const result = await this.handleResponse(response);
2701
+ return {
2702
+ totalEvents: result.total_events || result.total,
2703
+ queued: result.queued,
2704
+ failed: result.failed,
2705
+ results: (result.results || result.responses || []).map((r) => ({
2706
+ eventId: r.event_id,
2707
+ certificateId: r.certificate_id,
2708
+ status: r.status
2709
+ }))
2710
+ };
2711
+ } catch (error) {
2712
+ if (error instanceof Error && error.name === "AbortError") {
2713
+ throw new NetworkError("Request timed out");
2714
+ }
2715
+ throw error;
2716
+ } finally {
2717
+ clearTimeout(timeoutId);
2718
+ }
2719
+ }
2720
+ };
2501
2721
  export {
2502
2722
  AuthenticationError,
2503
2723
  AuthorizationError,
@@ -2506,6 +2726,7 @@ export {
2506
2726
  CohortLeaderboardClient,
2507
2727
  DataViewsClient,
2508
2728
  DocumentsResource,
2729
+ EndUserIngestionClient,
2509
2730
  EndUsersClient,
2510
2731
  EventsResource,
2511
2732
  FanpassLeaderboardClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proofchain/sdk",
3
- "version": "2.14.0",
3
+ "version": "2.16.0",
4
4
  "description": "Official JavaScript/TypeScript SDK for ProofChain - blockchain-anchored document attestation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",