@forgecart/sdk 1.0.0 → 1.2.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.
@@ -4,7 +4,7 @@
4
4
  * This file was automatically generated and should not be manually edited.
5
5
  * To regenerate, run: npm run codegen:ts
6
6
  *
7
- * Generated at: 2025-12-12T11:13:16.730Z
7
+ * Generated at: 2025-12-15T07:01:16.361Z
8
8
  * Generator version: 1.0.0
9
9
  *
10
10
  * 🤖 Generated with ForgeCart SDK Generator
@@ -28,6 +28,8 @@ export interface SDKConfig {
28
28
  headers?: Record<string, string>;
29
29
  /** Custom WebSocket implementation (optional, auto-detected if not provided) */
30
30
  webSocketImpl?: unknown;
31
+ /** Use HTTP only, skip WebSocket initialization (default: false) */
32
+ httpOnly?: boolean;
31
33
  }
32
34
 
33
35
  export type ActiveAdministratorQueryVariables = Types.ActiveAdministratorQueryVariables;
@@ -462,12 +464,51 @@ export type UpdateCustomerNoteMutationResult = Types.UpdateCustomerNoteMutation;
462
464
  export type DeleteCustomerNoteMutationVariables = Types.DeleteCustomerNoteMutationVariables;
463
465
  export type DeleteCustomerNoteMutation = Types.DeleteCustomerNoteMutation;
464
466
  export type DeleteCustomerNoteMutationResult = Types.DeleteCustomerNoteMutation;
467
+ export type DeploymentsQueryVariables = Types.DeploymentsQueryVariables;
468
+ export type DeploymentsQuery = Types.DeploymentsQuery;
469
+ export type DeploymentsQueryResult = Types.DeploymentsQuery;
470
+ export type DeploymentQueryVariables = Types.DeploymentQueryVariables;
471
+ export type DeploymentQuery = Types.DeploymentQuery;
472
+ export type DeploymentQueryResult = Types.DeploymentQuery;
473
+ export type DeploymentEnvQueryVariables = Types.DeploymentEnvQueryVariables;
474
+ export type DeploymentEnvQuery = Types.DeploymentEnvQuery;
475
+ export type DeploymentEnvQueryResult = Types.DeploymentEnvQuery;
476
+ export type ChannelInfoQueryVariables = Types.ChannelInfoQueryVariables;
477
+ export type ChannelInfoQuery = Types.ChannelInfoQuery;
478
+ export type ChannelInfoQueryResult = Types.ChannelInfoQuery;
479
+ export type ValidateChannelTokenQueryVariables = Types.ValidateChannelTokenQueryVariables;
480
+ export type ValidateChannelTokenQuery = Types.ValidateChannelTokenQuery;
481
+ export type ValidateChannelTokenQueryResult = Types.ValidateChannelTokenQuery;
482
+ export type CreateDeploymentMutationVariables = Types.CreateDeploymentMutationVariables;
483
+ export type CreateDeploymentMutation = Types.CreateDeploymentMutation;
484
+ export type CreateDeploymentMutationResult = Types.CreateDeploymentMutation;
485
+ export type DeleteDeploymentMutationVariables = Types.DeleteDeploymentMutationVariables;
486
+ export type DeleteDeploymentMutation = Types.DeleteDeploymentMutation;
487
+ export type DeleteDeploymentMutationResult = Types.DeleteDeploymentMutation;
488
+ export type ScaleDeploymentMutationVariables = Types.ScaleDeploymentMutationVariables;
489
+ export type ScaleDeploymentMutation = Types.ScaleDeploymentMutation;
490
+ export type ScaleDeploymentMutationResult = Types.ScaleDeploymentMutation;
491
+ export type SetDeploymentEnvMutationVariables = Types.SetDeploymentEnvMutationVariables;
492
+ export type SetDeploymentEnvMutation = Types.SetDeploymentEnvMutation;
493
+ export type SetDeploymentEnvMutationResult = Types.SetDeploymentEnvMutation;
494
+ export type UnsetDeploymentEnvMutationVariables = Types.UnsetDeploymentEnvMutationVariables;
495
+ export type UnsetDeploymentEnvMutation = Types.UnsetDeploymentEnvMutation;
496
+ export type UnsetDeploymentEnvMutationResult = Types.UnsetDeploymentEnvMutation;
497
+ export type RefreshDeploymentStatusMutationVariables = Types.RefreshDeploymentStatusMutationVariables;
498
+ export type RefreshDeploymentStatusMutation = Types.RefreshDeploymentStatusMutation;
499
+ export type RefreshDeploymentStatusMutationResult = Types.RefreshDeploymentStatusMutation;
500
+ export type DeploymentLogsSubscriptionVariables = Types.DeploymentLogsSubscriptionVariables;
501
+ export type DeploymentLogsSubscription = Types.DeploymentLogsSubscription;
502
+ export type DeploymentLogsSubscriptionResult = Types.DeploymentLogsSubscription;
465
503
  export type EntityDuplicatorsQueryVariables = Types.EntityDuplicatorsQueryVariables;
466
504
  export type EntityDuplicatorsQuery = Types.EntityDuplicatorsQuery;
467
505
  export type EntityDuplicatorsQueryResult = Types.EntityDuplicatorsQuery;
468
506
  export type DuplicateEntityMutationVariables = Types.DuplicateEntityMutationVariables;
469
507
  export type DuplicateEntityMutation = Types.DuplicateEntityMutation;
470
508
  export type DuplicateEntityMutationResult = Types.DuplicateEntityMutation;
509
+ export type EntityEventSubscriptionVariables = Types.EntityEventSubscriptionVariables;
510
+ export type EntityEventSubscription = Types.EntityEventSubscription;
511
+ export type EntityEventSubscriptionResult = Types.EntityEventSubscription;
471
512
  export type FacetQueryVariables = Types.FacetQueryVariables;
472
513
  export type FacetQuery = Types.FacetQuery;
473
514
  export type FacetQueryResult = Types.FacetQuery;
@@ -4448,6 +4489,108 @@ const deleteCustomerNoteDocument = `mutation deleteCustomerNote($id: ID!) {
4448
4489
  }
4449
4490
  }`;
4450
4491
 
4492
+ const deploymentsDocument = `query Deployments {
4493
+ deployments {
4494
+ id
4495
+ type
4496
+ status
4497
+ url
4498
+ instances
4499
+ lastDeployedAt
4500
+ errorMessage
4501
+ }
4502
+ }`;
4503
+
4504
+ const deploymentDocument = `query Deployment($type: DeploymentType!) {
4505
+ deployment(type: $type) {
4506
+ id
4507
+ type
4508
+ status
4509
+ url
4510
+ instances
4511
+ lastDeployedAt
4512
+ errorMessage
4513
+ }
4514
+ }`;
4515
+
4516
+ const deploymentEnvDocument = `query DeploymentEnv($type: DeploymentType!) {
4517
+ deploymentEnv(type: $type) {
4518
+ key
4519
+ value
4520
+ }
4521
+ }`;
4522
+
4523
+ const channelInfoDocument = `query ChannelInfo {
4524
+ channelInfo {
4525
+ id
4526
+ code
4527
+ name
4528
+ domain
4529
+ hasApplication
4530
+ applicationName
4531
+ }
4532
+ }`;
4533
+
4534
+ const validateChannelTokenDocument = `query ValidateChannelToken {
4535
+ validateChannelToken
4536
+ }`;
4537
+
4538
+ const createDeploymentDocument = `mutation CreateDeployment($input: CreateDeploymentInput!) {
4539
+ createDeployment(input: $input) {
4540
+ id
4541
+ type
4542
+ status
4543
+ url
4544
+ instances
4545
+ lastDeployedAt
4546
+ errorMessage
4547
+ }
4548
+ }`;
4549
+
4550
+ const deleteDeploymentDocument = `mutation DeleteDeployment($type: DeploymentType!) {
4551
+ deleteDeployment(type: $type)
4552
+ }`;
4553
+
4554
+ const scaleDeploymentDocument = `mutation ScaleDeployment($input: ScaleDeploymentInput!) {
4555
+ scaleDeployment(input: $input) {
4556
+ id
4557
+ type
4558
+ status
4559
+ url
4560
+ instances
4561
+ lastDeployedAt
4562
+ errorMessage
4563
+ }
4564
+ }`;
4565
+
4566
+ const setDeploymentEnvDocument = `mutation SetDeploymentEnv($input: SetEnvInput!) {
4567
+ setDeploymentEnv(input: $input)
4568
+ }`;
4569
+
4570
+ const unsetDeploymentEnvDocument = `mutation UnsetDeploymentEnv($input: UnsetEnvInput!) {
4571
+ unsetDeploymentEnv(input: $input)
4572
+ }`;
4573
+
4574
+ const refreshDeploymentStatusDocument = `mutation RefreshDeploymentStatus($type: DeploymentType!) {
4575
+ refreshDeploymentStatus(type: $type) {
4576
+ id
4577
+ type
4578
+ status
4579
+ url
4580
+ instances
4581
+ lastDeployedAt
4582
+ errorMessage
4583
+ }
4584
+ }`;
4585
+
4586
+ const deploymentLogsDocument = `subscription DeploymentLogs($type: DeploymentType!) {
4587
+ deploymentLogs(type: $type) {
4588
+ timestamp
4589
+ message
4590
+ type
4591
+ }
4592
+ }`;
4593
+
4451
4594
  const entityDuplicatorsDocument = `query entityDuplicators {
4452
4595
  entityDuplicators {
4453
4596
  code
@@ -4479,6 +4622,19 @@ const duplicateEntityDocument = `mutation duplicateEntity($input: DuplicateEntit
4479
4622
  }
4480
4623
  }`;
4481
4624
 
4625
+ const entityEventDocument = `subscription entityEvent($categories: [EventCategory!]) {
4626
+ entityEvent(categories: $categories) {
4627
+ channelId
4628
+ eventName
4629
+ eventClass
4630
+ type
4631
+ entityId
4632
+ entity
4633
+ input
4634
+ timestamp
4635
+ }
4636
+ }`;
4637
+
4482
4638
  const facetDocument = `query facet($id: ID!) {
4483
4639
  facet(id: $id) {
4484
4640
  id
@@ -8020,9 +8176,32 @@ class BaseGraphQLClient {
8020
8176
  this.wsEndpoint = config.wsEndpoint || 'wss://api.forgecart.com/admin-api';
8021
8177
  this.config = config;
8022
8178
 
8023
- // Initialize HTTP client (as fallback)
8179
+ // Custom fetch that captures session token from response headers
8180
+ const customFetch = async (url: RequestInfo | URL, options?: RequestInit): Promise<Response> => {
8181
+ const response = await fetch(url, options);
8182
+
8183
+ // Capture session token from response header
8184
+ const authToken = response.headers.get('forge-auth-token');
8185
+ if (authToken && authToken !== this.authToken) {
8186
+ this.authToken = authToken;
8187
+ // Reconnect WebSocket with new token
8188
+ if (this.wsClient) {
8189
+ this.wsConnected = false;
8190
+ this.wsClient.dispose();
8191
+ this.wsClient = null;
8192
+ this.wsInitializing = null;
8193
+ this.initializeWebSocket();
8194
+ }
8195
+ }
8196
+
8197
+ return response;
8198
+ };
8199
+
8200
+ // Initialize HTTP client with custom fetch
8024
8201
  this.httpClient = new GraphQLClient(this.endpoint, {
8025
8202
  headers: config.headers || {},
8203
+ credentials: 'include',
8204
+ fetch: customFetch,
8026
8205
  });
8027
8206
 
8028
8207
  // Initialize WebSocket connection immediately
@@ -8137,6 +8316,11 @@ class BaseGraphQLClient {
8137
8316
  * Connects immediately and tracks connection state
8138
8317
  */
8139
8318
  private initializeWebSocket(): void {
8319
+ // Skip WebSocket if httpOnly mode is enabled
8320
+ if (this.config.httpOnly) {
8321
+ return;
8322
+ }
8323
+
8140
8324
  // Prevent multiple simultaneous initializations
8141
8325
  if (this.wsClient || this.wsInitializing) {
8142
8326
  return;
@@ -8159,7 +8343,23 @@ class BaseGraphQLClient {
8159
8343
  keepAlive: 10_000, // Send keep-alive pings every 10 seconds
8160
8344
  connectionParams: async () => {
8161
8345
  try {
8162
- return this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {};
8346
+ const params: Record<string, string> = {};
8347
+
8348
+ // Add session token if available
8349
+ if (this.authToken) {
8350
+ params.Authorization = `bearer ${this.authToken}`;
8351
+ }
8352
+
8353
+ // Pass all configured headers (including forge-token for channel)
8354
+ if (this.config.headers) {
8355
+ Object.entries(this.config.headers).forEach(([key, value]) => {
8356
+ if (value) {
8357
+ params[key] = value;
8358
+ }
8359
+ });
8360
+ }
8361
+
8362
+ return params;
8163
8363
  } catch (error) {
8164
8364
  console.error('Error in connectionParams:', error);
8165
8365
  return {};
@@ -8308,6 +8508,72 @@ class BaseGraphQLClient {
8308
8508
  }
8309
8509
  }
8310
8510
 
8511
+ // Event handler types for SDK subscriptions
8512
+ export type EventCallback<T = EntityEventPayload> = (event: T) => void;
8513
+ export type BlockingEventCallback<T = EntityEventPayload> = (event: T) => Promise<void>;
8514
+
8515
+ export interface EventSubscription {
8516
+ unsubscribe: () => void;
8517
+ }
8518
+
8519
+ interface EventHandlerRegistry {
8520
+ handlers: Map<string, Set<EventCallback>>;
8521
+ blockingHandlers: Map<string, Set<BlockingEventCallback>>;
8522
+ }
8523
+
8524
+ // Entity event payload from server
8525
+ export interface EntityEventPayload {
8526
+ channelId: string;
8527
+ eventName: string;
8528
+ eventClass: string;
8529
+ type: string;
8530
+ entityId: string | null;
8531
+ entity: unknown;
8532
+ input: unknown;
8533
+ timestamp: string;
8534
+ }
8535
+
8536
+ // Event categories for filtering
8537
+ export const ProductEvents = [
8538
+ 'product.created', 'product.updated', 'product.deleted',
8539
+ 'product.variant.created', 'product.variant.updated', 'product.variant.deleted',
8540
+ 'product.option.created', 'product.option.updated', 'product.option.deleted',
8541
+ 'product.optionGroup.created', 'product.optionGroup.updated', 'product.optionGroup.deleted',
8542
+ 'product.variant.price.updated',
8543
+ ] as const;
8544
+
8545
+ export const OrderEvents = [
8546
+ 'order.stateTransition', 'order.placementStateTransition', 'order.line.event',
8547
+ 'order.paymentStateTransition', 'order.refundStateTransition',
8548
+ 'order.coupon.applied', 'order.coupon.removed',
8549
+ ] as const;
8550
+
8551
+ export const CustomerEvents = [
8552
+ 'customer.created', 'customer.updated', 'customer.deleted',
8553
+ 'customer.address.created', 'customer.address.updated', 'customer.address.deleted',
8554
+ 'customer.groupChange', 'customer.login', 'customer.loginfail',
8555
+ ] as const;
8556
+
8557
+ export const FulfillmentEvents = [
8558
+ 'fulfillment.created', 'fulfillment.stateTransition',
8559
+ ] as const;
8560
+
8561
+ export const PaymentEvents = [
8562
+ 'payment.stateTransition', 'payment.method.created', 'payment.method.updated', 'payment.method.deleted',
8563
+ ] as const;
8564
+
8565
+ export const CatalogEvents = [
8566
+ 'collection.created', 'collection.updated', 'collection.deleted', 'collection.modification',
8567
+ 'facet.created', 'facet.updated', 'facet.deleted',
8568
+ 'facetValue.created', 'facetValue.updated', 'facetValue.deleted',
8569
+ 'asset.created', 'asset.updated', 'asset.deleted',
8570
+ ] as const;
8571
+
8572
+ export const AllEvents = [
8573
+ ...ProductEvents, ...OrderEvents, ...CustomerEvents,
8574
+ ...FulfillmentEvents, ...PaymentEvents, ...CatalogEvents,
8575
+ ] as const;
8576
+
8311
8577
  /**
8312
8578
  * Administrator operations
8313
8579
  */
@@ -8351,9 +8617,18 @@ class AdministratorOperations {
8351
8617
 
8352
8618
  /**
8353
8619
  * login mutation
8620
+ * Automatically sets the auth token on successful login
8354
8621
  */
8355
8622
  async login(variables: Types.LoginMutationVariables): Promise<Types.LoginMutation> {
8356
- return await this.client.request<Types.LoginMutation>(loginDocument, variables);
8623
+ const response = await this.client.request<Types.LoginMutation>(loginDocument, variables);
8624
+
8625
+ // Auto-set auth token if login was successful
8626
+ const loginResult = (response as any)?.login;
8627
+ if (loginResult && loginResult.__typename === 'CurrentUser' && loginResult.sessionToken) {
8628
+ this.client.setAuthToken(loginResult.sessionToken);
8629
+ }
8630
+
8631
+ return response;
8357
8632
  }
8358
8633
 
8359
8634
  /**
@@ -9386,6 +9661,100 @@ class CustomerOperations {
9386
9661
  }
9387
9662
  }
9388
9663
 
9664
+ /**
9665
+ * Deployment operations
9666
+ */
9667
+ class DeploymentOperations {
9668
+ constructor(private client: BaseGraphQLClient) {}
9669
+
9670
+ /**
9671
+ * Deployments query
9672
+ */
9673
+ async deployments(): Promise<Types.DeploymentsQuery> {
9674
+ return await this.client.request<Types.DeploymentsQuery>(deploymentsDocument);
9675
+ }
9676
+
9677
+ /**
9678
+ * Deployment query
9679
+ */
9680
+ async deployment(variables: Types.DeploymentQueryVariables): Promise<Types.DeploymentQuery> {
9681
+ return await this.client.request<Types.DeploymentQuery>(deploymentDocument, variables);
9682
+ }
9683
+
9684
+ /**
9685
+ * DeploymentEnv query
9686
+ */
9687
+ async deploymentEnv(variables: Types.DeploymentEnvQueryVariables): Promise<Types.DeploymentEnvQuery> {
9688
+ return await this.client.request<Types.DeploymentEnvQuery>(deploymentEnvDocument, variables);
9689
+ }
9690
+
9691
+ /**
9692
+ * ChannelInfo query
9693
+ */
9694
+ async channelInfo(): Promise<Types.ChannelInfoQuery> {
9695
+ return await this.client.request<Types.ChannelInfoQuery>(channelInfoDocument);
9696
+ }
9697
+
9698
+ /**
9699
+ * ValidateChannelToken query
9700
+ */
9701
+ async validateChannelToken(): Promise<Types.ValidateChannelTokenQuery> {
9702
+ return await this.client.request<Types.ValidateChannelTokenQuery>(validateChannelTokenDocument);
9703
+ }
9704
+
9705
+ /**
9706
+ * CreateDeployment mutation
9707
+ */
9708
+ async createDeployment(variables: Types.CreateDeploymentMutationVariables): Promise<Types.CreateDeploymentMutation> {
9709
+ return await this.client.request<Types.CreateDeploymentMutation>(createDeploymentDocument, variables);
9710
+ }
9711
+
9712
+ /**
9713
+ * DeleteDeployment mutation
9714
+ */
9715
+ async deleteDeployment(variables: Types.DeleteDeploymentMutationVariables): Promise<Types.DeleteDeploymentMutation> {
9716
+ return await this.client.request<Types.DeleteDeploymentMutation>(deleteDeploymentDocument, variables);
9717
+ }
9718
+
9719
+ /**
9720
+ * ScaleDeployment mutation
9721
+ */
9722
+ async scaleDeployment(variables: Types.ScaleDeploymentMutationVariables): Promise<Types.ScaleDeploymentMutation> {
9723
+ return await this.client.request<Types.ScaleDeploymentMutation>(scaleDeploymentDocument, variables);
9724
+ }
9725
+
9726
+ /**
9727
+ * SetDeploymentEnv mutation
9728
+ */
9729
+ async setDeploymentEnv(variables: Types.SetDeploymentEnvMutationVariables): Promise<Types.SetDeploymentEnvMutation> {
9730
+ return await this.client.request<Types.SetDeploymentEnvMutation>(setDeploymentEnvDocument, variables);
9731
+ }
9732
+
9733
+ /**
9734
+ * UnsetDeploymentEnv mutation
9735
+ */
9736
+ async unsetDeploymentEnv(variables: Types.UnsetDeploymentEnvMutationVariables): Promise<Types.UnsetDeploymentEnvMutation> {
9737
+ return await this.client.request<Types.UnsetDeploymentEnvMutation>(unsetDeploymentEnvDocument, variables);
9738
+ }
9739
+
9740
+ /**
9741
+ * RefreshDeploymentStatus mutation
9742
+ */
9743
+ async refreshDeploymentStatus(variables: Types.RefreshDeploymentStatusMutationVariables): Promise<Types.RefreshDeploymentStatusMutation> {
9744
+ return await this.client.request<Types.RefreshDeploymentStatusMutation>(refreshDeploymentStatusDocument, variables);
9745
+ }
9746
+
9747
+ /**
9748
+ * DeploymentLogs subscription
9749
+ */
9750
+ async *deploymentLogs(variables: Types.DeploymentLogsSubscriptionVariables): AsyncIterableIterator<Types.DeploymentLogsSubscription> {
9751
+ const iterator = this.client.subscribe<Types.DeploymentLogsSubscription>(deploymentLogsDocument, variables);
9752
+ for await (const data of iterator) {
9753
+ yield data;
9754
+ }
9755
+ }
9756
+ }
9757
+
9389
9758
  /**
9390
9759
  * EntityDuplication operations
9391
9760
  */
@@ -9407,6 +9776,23 @@ class EntityDuplicationOperations {
9407
9776
  }
9408
9777
  }
9409
9778
 
9779
+ /**
9780
+ * EntityEvents operations
9781
+ */
9782
+ class EntityEventsOperations {
9783
+ constructor(private client: BaseGraphQLClient) {}
9784
+
9785
+ /**
9786
+ * entityEvent subscription
9787
+ */
9788
+ async *entityEvent(variables: Types.EntityEventSubscriptionVariables): AsyncIterableIterator<Types.EntityEventSubscription> {
9789
+ const iterator = this.client.subscribe<Types.EntityEventSubscription>(entityEventDocument, variables);
9790
+ for await (const data of iterator) {
9791
+ yield data;
9792
+ }
9793
+ }
9794
+ }
9795
+
9410
9796
  /**
9411
9797
  * Facet operations
9412
9798
  */
@@ -10680,7 +11066,9 @@ export class AdminNamespace {
10680
11066
  readonly customFields: CustomFieldsOperations;
10681
11067
  readonly customerGroup: CustomerGroupOperations;
10682
11068
  readonly customer: CustomerOperations;
11069
+ readonly deployment: DeploymentOperations;
10683
11070
  readonly entityDuplication: EntityDuplicationOperations;
11071
+ readonly entityEvents: EntityEventsOperations;
10684
11072
  readonly facet: FacetOperations;
10685
11073
  readonly fulfillment: FulfillmentOperations;
10686
11074
  readonly globalSettings: GlobalSettingsOperations;
@@ -10704,6 +11092,25 @@ export class AdminNamespace {
10704
11092
  readonly tax: TaxOperations;
10705
11093
  readonly zone: ZoneOperations;
10706
11094
 
11095
+ // Event handler registry and state
11096
+ private eventRegistry: EventHandlerRegistry = {
11097
+ handlers: new Map(),
11098
+ blockingHandlers: new Map(),
11099
+ };
11100
+ private eventSubscription: AsyncIterableIterator<{ entityEvent: EntityEventPayload }> | null = null;
11101
+ private isListening = false;
11102
+ private retryCount = 0;
11103
+ private abortController: AbortController | null = null;
11104
+
11105
+ // Reconnection configuration
11106
+ private static readonly RECONNECT_CONFIG = {
11107
+ maxRetries: 5,
11108
+ baseDelayMs: 1000,
11109
+ maxDelayMs: 30000,
11110
+ backoffMultiplier: 2,
11111
+ };
11112
+ private static readonly BLOCKING_TIMEOUT_MS = 1000;
11113
+
10707
11114
  constructor(config: SDKConfig) {
10708
11115
  this.client = new BaseGraphQLClient(config);
10709
11116
 
@@ -10717,7 +11124,9 @@ export class AdminNamespace {
10717
11124
  this.customFields = new CustomFieldsOperations(this.client);
10718
11125
  this.customerGroup = new CustomerGroupOperations(this.client);
10719
11126
  this.customer = new CustomerOperations(this.client);
11127
+ this.deployment = new DeploymentOperations(this.client);
10720
11128
  this.entityDuplication = new EntityDuplicationOperations(this.client);
11129
+ this.entityEvents = new EntityEventsOperations(this.client);
10721
11130
  this.facet = new FacetOperations(this.client);
10722
11131
  this.fulfillment = new FulfillmentOperations(this.client);
10723
11132
  this.globalSettings = new GlobalSettingsOperations(this.client);
@@ -10763,4 +11172,173 @@ export class AdminNamespace {
10763
11172
  dispose(): void {
10764
11173
  this.client.dispose();
10765
11174
  }
11175
+
11176
+ /**
11177
+ * Register a non-blocking event handler
11178
+ * The callback will be called for each matching event without waiting
11179
+ */
11180
+ registerEventHandler(
11181
+ eventName: string,
11182
+ callback: EventCallback
11183
+ ): EventSubscription {
11184
+ if (!this.eventRegistry.handlers.has(eventName)) {
11185
+ this.eventRegistry.handlers.set(eventName, new Set());
11186
+ }
11187
+ this.eventRegistry.handlers.get(eventName)!.add(callback);
11188
+
11189
+ void this.ensureEventListening();
11190
+
11191
+ return {
11192
+ unsubscribe: () => {
11193
+ this.eventRegistry.handlers.get(eventName)?.delete(callback);
11194
+ },
11195
+ };
11196
+ }
11197
+
11198
+ /**
11199
+ * Register a blocking event handler
11200
+ * The callback must complete within 1000ms or it will timeout
11201
+ */
11202
+ registerBlockingEventHandler(
11203
+ eventName: string,
11204
+ callback: BlockingEventCallback
11205
+ ): EventSubscription {
11206
+ if (!this.eventRegistry.blockingHandlers.has(eventName)) {
11207
+ this.eventRegistry.blockingHandlers.set(eventName, new Set());
11208
+ }
11209
+ this.eventRegistry.blockingHandlers.get(eventName)!.add(callback);
11210
+
11211
+ void this.ensureEventListening();
11212
+
11213
+ return {
11214
+ unsubscribe: () => {
11215
+ this.eventRegistry.blockingHandlers.get(eventName)?.delete(callback);
11216
+ },
11217
+ };
11218
+ }
11219
+
11220
+ /**
11221
+ * Start listening to events with retry logic
11222
+ */
11223
+ private async ensureEventListening(): Promise<void> {
11224
+ if (this.isListening) return;
11225
+ this.isListening = true;
11226
+ this.retryCount = 0;
11227
+ this.abortController = new AbortController();
11228
+
11229
+ await this.startSubscription();
11230
+ }
11231
+
11232
+ private async startSubscription(): Promise<void> {
11233
+ try {
11234
+ this.eventSubscription = this.client.subscribe<{ entityEvent: EntityEventPayload }>(
11235
+ entityEventDocument,
11236
+ {}
11237
+ );
11238
+
11239
+ // Reset retry count on successful connection
11240
+ this.retryCount = 0;
11241
+
11242
+ // Process events
11243
+ for await (const result of this.eventSubscription!) {
11244
+ if (!this.isListening) break;
11245
+ const event = result.entityEvent;
11246
+ await this.dispatchEvent(event);
11247
+ }
11248
+ } catch (error) {
11249
+ if (this.isListening) {
11250
+ console.error('Event subscription error:', error);
11251
+ await this.handleReconnect();
11252
+ }
11253
+ }
11254
+ }
11255
+
11256
+ private async handleReconnect(): Promise<void> {
11257
+ const { maxRetries, baseDelayMs, maxDelayMs, backoffMultiplier } = AdminNamespace.RECONNECT_CONFIG;
11258
+
11259
+ if (this.retryCount >= maxRetries) {
11260
+ this.isListening = false;
11261
+ throw new Error(`Max reconnection attempts (${maxRetries}) exceeded`);
11262
+ }
11263
+
11264
+ // Calculate delay with exponential backoff
11265
+ const delay = Math.min(
11266
+ baseDelayMs * Math.pow(backoffMultiplier, this.retryCount),
11267
+ maxDelayMs
11268
+ );
11269
+
11270
+ this.retryCount++;
11271
+ console.log(`Reconnecting in ${delay}ms (attempt ${this.retryCount}/${maxRetries})`);
11272
+
11273
+ await new Promise(resolve => setTimeout(resolve, delay));
11274
+ await this.startSubscription();
11275
+ }
11276
+
11277
+ /**
11278
+ * Dispatch event to registered handlers
11279
+ */
11280
+ private async dispatchEvent(event: EntityEventPayload): Promise<void> {
11281
+ const eventName = event.eventName;
11282
+
11283
+ // Non-blocking handlers (fire-and-forget)
11284
+ const handlers = this.eventRegistry.handlers.get(eventName);
11285
+ if (handlers) {
11286
+ for (const handler of handlers) {
11287
+ try {
11288
+ handler(event);
11289
+ } catch (error) {
11290
+ console.error(`Error in event handler for ${eventName}:`, error);
11291
+ }
11292
+ }
11293
+ }
11294
+
11295
+ // Blocking handlers (with timeout)
11296
+ const blockingHandlers = this.eventRegistry.blockingHandlers.get(eventName);
11297
+ if (blockingHandlers) {
11298
+ for (const handler of blockingHandlers) {
11299
+ try {
11300
+ await this.executeWithTimeout(
11301
+ handler(event),
11302
+ AdminNamespace.BLOCKING_TIMEOUT_MS,
11303
+ `Blocking handler for ${eventName} exceeded ${AdminNamespace.BLOCKING_TIMEOUT_MS}ms`
11304
+ );
11305
+ } catch (error) {
11306
+ console.error(`Error in blocking event handler for ${eventName}:`, error);
11307
+ throw error; // Re-throw for blocking handlers
11308
+ }
11309
+ }
11310
+ }
11311
+ }
11312
+
11313
+ /**
11314
+ * Execute promise with timeout
11315
+ */
11316
+ private async executeWithTimeout<T>(
11317
+ promise: Promise<T>,
11318
+ timeoutMs: number,
11319
+ errorMessage: string
11320
+ ): Promise<T> {
11321
+ return Promise.race([
11322
+ promise,
11323
+ new Promise<never>((_, reject) =>
11324
+ setTimeout(() => reject(new Error(errorMessage)), timeoutMs)
11325
+ ),
11326
+ ]);
11327
+ }
11328
+
11329
+ /**
11330
+ * Stop all event listening
11331
+ */
11332
+ stopEventListening(): void {
11333
+ this.isListening = false;
11334
+ this.retryCount = 0;
11335
+ if (this.abortController) {
11336
+ this.abortController.abort();
11337
+ this.abortController = null;
11338
+ }
11339
+ this.eventSubscription = null;
11340
+ this.eventRegistry.handlers.clear();
11341
+ this.eventRegistry.blockingHandlers.clear();
11342
+ }
11343
+
10766
11344
  }