@final-commerce/command-frame 0.0.6 → 0.1.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/README.md CHANGED
@@ -146,6 +146,342 @@ console.log('Current build:', context.buildName);
146
146
 
147
147
  For complete usage examples and detailed parameter descriptions, see the documentation for each action in the [Actions Documentation](#actions-documentation) section.
148
148
 
149
+ ## Pub/Sub System
150
+
151
+ The library includes a pub/sub system that allows iframe apps to subscribe to topics and receive events published by the host application (Render).
152
+
153
+ ### Quick Start - Pub/Sub
154
+
155
+ ```typescript
156
+ import { topics } from '@final-commerce/command-frame';
157
+
158
+ // Get available topics
159
+ const availableTopics = await topics.getTopics();
160
+ console.log('Available topics:', availableTopics);
161
+
162
+ // Subscribe to a topic with a callback
163
+ const subscriptionId = topics.subscribe('customers', (event) => {
164
+ if (event.type === 'customer-created') {
165
+ console.log('New customer created:', event.data);
166
+ // Handle the event
167
+ }
168
+ });
169
+
170
+ // Later, unsubscribe when done
171
+ topics.unsubscribe('customers', subscriptionId);
172
+ ```
173
+
174
+ ### Pub/Sub API
175
+
176
+ #### `topics.getTopics()`
177
+
178
+ Retrieves the list of available topics from the host application.
179
+
180
+ **Returns:** `Promise<TopicDefinition[]>`
181
+
182
+ **Example:**
183
+ ```typescript
184
+ const topics = await topics.getTopics();
185
+ topics.forEach(topic => {
186
+ console.log(`Topic: ${topic.name} (${topic.id})`);
187
+ console.log(`Event types: ${topic.eventTypes.map(et => et.id).join(', ')}`);
188
+ });
189
+ ```
190
+
191
+ #### `topics.subscribe(topic, callback)`
192
+
193
+ Subscribes to a topic and receives events via the callback function.
194
+
195
+ **Parameters:**
196
+ - `topic: string` - The topic ID to subscribe to
197
+ - `callback: (event: TopicEvent) => void` - Function called when an event is received
198
+
199
+ **Returns:** `string` - Subscription ID (use this to unsubscribe)
200
+
201
+ **Example:**
202
+ ```typescript
203
+ const subscriptionId = topics.subscribe('customers', (event) => {
204
+ console.log('Received event:', event.type);
205
+ console.log('Event data:', event.data);
206
+ console.log('Timestamp:', event.timestamp);
207
+ });
208
+ ```
209
+
210
+ #### `topics.unsubscribe(topic, subscriptionId)`
211
+
212
+ Unsubscribes from a topic using the subscription ID returned from `subscribe()`.
213
+
214
+ **Parameters:**
215
+ - `topic: string` - The topic ID
216
+ - `subscriptionId: string` - The subscription ID returned from `subscribe()`
217
+
218
+ **Returns:** `boolean` - `true` if successfully unsubscribed
219
+
220
+ **Example:**
221
+ ```typescript
222
+ const success = topics.unsubscribe('customers', subscriptionId);
223
+ ```
224
+
225
+ #### `topics.unsubscribeAll(topic)`
226
+
227
+ Unsubscribes all callbacks for a specific topic.
228
+
229
+ **Parameters:**
230
+ - `topic: string` - The topic ID
231
+
232
+ **Returns:** `number` - Number of subscriptions removed
233
+
234
+ **Example:**
235
+ ```typescript
236
+ const removed = topics.unsubscribeAll('customers');
237
+ console.log(`Removed ${removed} subscriptions`);
238
+ ```
239
+
240
+ ### Topic and Event Types
241
+
242
+ ```typescript
243
+ interface TopicDefinition {
244
+ id: string;
245
+ name: string;
246
+ description?: string;
247
+ eventTypes: TopicEventType[];
248
+ }
249
+
250
+ interface TopicEvent<T = any> {
251
+ topic: string;
252
+ type: string;
253
+ data: T;
254
+ timestamp: string;
255
+ }
256
+ ```
257
+
258
+ ### Example: React Component with Pub/Sub
259
+
260
+ ```typescript
261
+ import { useEffect, useState } from 'react';
262
+ import { topics, type TopicEvent } from '@final-commerce/command-frame';
263
+
264
+ function CustomerEvents() {
265
+ const [events, setEvents] = useState<TopicEvent[]>([]);
266
+
267
+ useEffect(() => {
268
+ // Subscribe on mount
269
+ const subscriptionId = topics.subscribe('customers', (event) => {
270
+ if (event.type === 'customer-created') {
271
+ setEvents(prev => [event, ...prev]);
272
+ }
273
+ });
274
+
275
+ // Unsubscribe on unmount
276
+ return () => {
277
+ topics.unsubscribe('customers', subscriptionId);
278
+ };
279
+ }, []);
280
+
281
+ return (
282
+ <div>
283
+ <h2>Customer Events ({events.length})</h2>
284
+ {events.map((event, index) => (
285
+ <div key={index}>
286
+ <p>Type: {event.type}</p>
287
+ <pre>{JSON.stringify(event.data, null, 2)}</pre>
288
+ </div>
289
+ ))}
290
+ </div>
291
+ );
292
+ }
293
+ ```
294
+
295
+ ### Available Topics
296
+
297
+ #### Customers Topic (`customers`)
298
+
299
+ The customers topic provides events related to customer lifecycle and cart assignment.
300
+
301
+ **Event Types:**
302
+
303
+ 1. **`customer-created`** - Fired when a new customer is created
304
+ - **Event Data:**
305
+ ```typescript
306
+ {
307
+ customer: {
308
+ _id: string;
309
+ companyId: string;
310
+ email: string;
311
+ firstName: string;
312
+ lastName: string;
313
+ phone?: string;
314
+ tags?: string[];
315
+ metadata?: Record<string, string>[];
316
+ notes?: CustomerNote[];
317
+ billing: Address | null;
318
+ shipping: Address | null;
319
+ createdAt: string;
320
+ updatedAt: string;
321
+ // ... other customer fields
322
+ }
323
+ }
324
+ ```
325
+
326
+ 2. **`customer-updated`** - Fired when a customer's information is updated
327
+ - **Event Data:**
328
+ ```typescript
329
+ {
330
+ customer: {
331
+ // Updated customer object with all fields
332
+ }
333
+ }
334
+ ```
335
+
336
+ 3. **`customer-note-added`** - Fired when a note is added to a customer
337
+ - **Event Data:**
338
+ ```typescript
339
+ {
340
+ customer: {
341
+ // Customer object with updated notes array
342
+ },
343
+ note: {
344
+ createdAt: string;
345
+ message: string;
346
+ }
347
+ }
348
+ ```
349
+
350
+ 4. **`customer-note-deleted`** - Fired when a note is deleted from a customer
351
+ - **Event Data:**
352
+ ```typescript
353
+ {
354
+ customer: {
355
+ // Customer object with updated notes array
356
+ },
357
+ note: {
358
+ createdAt: string;
359
+ message: string;
360
+ }
361
+ }
362
+ ```
363
+
364
+ 5. **`customer-assigned`** - Fired when a customer is assigned to the cart
365
+ - **Event Data:**
366
+ ```typescript
367
+ {
368
+ customer: {
369
+ // Full customer object
370
+ }
371
+ }
372
+ ```
373
+
374
+ 6. **`customer-unassigned`** - Fired when a customer is unassigned from the cart
375
+ - **Event Data:**
376
+ ```typescript
377
+ {
378
+ customer: {
379
+ // Full customer object (before removal)
380
+ }
381
+ }
382
+ ```
383
+
384
+ **Example: Subscribing to Customer Events**
385
+
386
+ ```typescript
387
+ import { topics, type TopicEvent } from '@final-commerce/command-frame';
388
+
389
+ // Subscribe to all customer events
390
+ const subscriptionId = topics.subscribe('customers', (event: TopicEvent) => {
391
+ switch (event.type) {
392
+ case 'customer-created':
393
+ console.log('New customer created:', event.data.customer);
394
+ // Update your customer list, show notification, etc.
395
+ break;
396
+
397
+ case 'customer-updated':
398
+ console.log('Customer updated:', event.data.customer);
399
+ // Refresh customer details in your UI
400
+ break;
401
+
402
+ case 'customer-note-added':
403
+ console.log('Note added to customer:', event.data.customer._id);
404
+ console.log('Note:', event.data.note);
405
+ // Update customer notes display
406
+ break;
407
+
408
+ case 'customer-note-deleted':
409
+ console.log('Note deleted from customer:', event.data.customer._id);
410
+ // Update customer notes display
411
+ break;
412
+
413
+ case 'customer-assigned':
414
+ console.log('Customer assigned to cart:', event.data.customer);
415
+ // Update cart UI to show customer info
416
+ break;
417
+
418
+ case 'customer-unassigned':
419
+ console.log('Customer unassigned from cart:', event.data.customer);
420
+ // Clear customer info from cart UI
421
+ break;
422
+ }
423
+ });
424
+
425
+ // Later, unsubscribe
426
+ topics.unsubscribe('customers', subscriptionId);
427
+ ```
428
+
429
+ **Example: Filtering Specific Event Types**
430
+
431
+ ```typescript
432
+ import { topics, type TopicEvent } from '@final-commerce/command-frame';
433
+
434
+ // Only listen for customer assignment/unassignment
435
+ const subscriptionId = topics.subscribe('customers', (event: TopicEvent) => {
436
+ if (event.type === 'customer-assigned' || event.type === 'customer-unassigned') {
437
+ console.log(`Customer ${event.type}:`, event.data.customer);
438
+ // Update your cart UI accordingly
439
+ }
440
+ });
441
+ ```
442
+
443
+ ### Host Application (Render) - Publishing Events
444
+
445
+ In the Render application, use the `topicPublisher` to publish events:
446
+
447
+ ```typescript
448
+ import { topicPublisher } from '@render/command-frame';
449
+
450
+ // When a customer is created
451
+ topicPublisher.publish('customers', 'customer-created', {
452
+ customer: newCustomer
453
+ });
454
+
455
+ // When a customer is updated
456
+ topicPublisher.publish('customers', 'customer-updated', {
457
+ customer: updatedCustomer
458
+ });
459
+
460
+ // When a note is added to a customer
461
+ topicPublisher.publish('customers', 'customer-note-added', {
462
+ customer: updatedCustomer,
463
+ note: newNote
464
+ });
465
+
466
+ // When a note is deleted from a customer
467
+ topicPublisher.publish('customers', 'customer-note-deleted', {
468
+ customer: updatedCustomer,
469
+ note: deletedNote
470
+ });
471
+
472
+ // When a customer is assigned to the cart
473
+ topicPublisher.publish('customers', 'customer-assigned', {
474
+ customer: customer
475
+ });
476
+
477
+ // When a customer is unassigned from the cart
478
+ topicPublisher.publish('customers', 'customer-unassigned', {
479
+ customer: customer
480
+ });
481
+ ```
482
+
483
+ The host application must register topics before they can be used. Topics are registered automatically when the `TopicPublisher` is initialized. See the Render application's pub/sub implementation for details on topic registration.
484
+
149
485
  ## Actions Documentation
150
486
 
151
487
  Each action has detailed documentation with complete parameter descriptions, response structures, and multiple usage examples:
@@ -23,6 +23,8 @@ export interface GetCustomersParams {
23
23
  outletId?: string;
24
24
  [key: string]: any;
25
25
  };
26
+ offset?: number;
27
+ limit?: number;
26
28
  }
27
29
  export interface GetCustomersResponse {
28
30
  customers: CFCustomer[];
package/dist/index.d.ts CHANGED
@@ -108,3 +108,5 @@ export type { TriggerZapierWebhook, TriggerZapierWebhookParams, TriggerZapierWeb
108
108
  export * from "./CommonTypes";
109
109
  export { commandFrameClient, CommandFrameClient } from "./client";
110
110
  export type { PostMessageRequest, PostMessageResponse } from "./client";
111
+ export { topics } from "./pubsub";
112
+ export type { TopicDefinition, TopicEvent, TopicEventType, TopicSubscriptionCallback, TopicSubscription } from "./pubsub/types";
package/dist/index.js CHANGED
@@ -121,3 +121,5 @@ export const command = {
121
121
  export * from "./CommonTypes";
122
122
  // Export client
123
123
  export { commandFrameClient, CommandFrameClient } from "./client";
124
+ // Export Pub/Sub
125
+ export { topics } from "./pubsub";
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Pub/Sub module for Command Frame
3
+ * Provides topic subscription functionality for iframe apps
4
+ */
5
+ export * from "./types";
6
+ export { TopicSubscriber } from "./subscriber";
7
+ import { TopicSubscriber } from "./subscriber";
8
+ /**
9
+ * Get or create the singleton TopicSubscriber instance
10
+ */
11
+ export declare function getTopicSubscriber(options?: {
12
+ origin?: string;
13
+ debug?: boolean;
14
+ }): TopicSubscriber;
15
+ /**
16
+ * Topics API for iframe apps
17
+ */
18
+ declare const topicsApi: {
19
+ /**
20
+ * Subscribe to a topic
21
+ */
22
+ subscribe: <T = any>(topic: string, callback: (event: import("./types").TopicEvent<T>) => void) => string;
23
+ /**
24
+ * Unsubscribe from a topic
25
+ */
26
+ unsubscribe: (topic: string, subscriptionId: string) => boolean;
27
+ /**
28
+ * Unsubscribe all callbacks for a topic
29
+ */
30
+ unsubscribeAll: (topic: string) => number;
31
+ /**
32
+ * Get available topics
33
+ */
34
+ getTopics: () => Promise<import("./types").TopicDefinition[]>;
35
+ };
36
+ export { topicsApi as topics };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Pub/Sub module for Command Frame
3
+ * Provides topic subscription functionality for iframe apps
4
+ */
5
+ export * from "./types";
6
+ export { TopicSubscriber } from "./subscriber";
7
+ // Singleton instance
8
+ import { TopicSubscriber } from "./subscriber";
9
+ let subscriberInstance = null;
10
+ /**
11
+ * Get or create the singleton TopicSubscriber instance
12
+ */
13
+ export function getTopicSubscriber(options) {
14
+ if (!subscriberInstance) {
15
+ subscriberInstance = new TopicSubscriber(options);
16
+ }
17
+ return subscriberInstance;
18
+ }
19
+ /**
20
+ * Topics API for iframe apps
21
+ */
22
+ const topicsApi = {
23
+ /**
24
+ * Subscribe to a topic
25
+ */
26
+ subscribe: (topic, callback) => {
27
+ const subscriber = getTopicSubscriber();
28
+ return subscriber.subscribe(topic, callback);
29
+ },
30
+ /**
31
+ * Unsubscribe from a topic
32
+ */
33
+ unsubscribe: (topic, subscriptionId) => {
34
+ const subscriber = getTopicSubscriber();
35
+ return subscriber.unsubscribe(topic, subscriptionId);
36
+ },
37
+ /**
38
+ * Unsubscribe all callbacks for a topic
39
+ */
40
+ unsubscribeAll: (topic) => {
41
+ const subscriber = getTopicSubscriber();
42
+ return subscriber.unsubscribeAll(topic);
43
+ },
44
+ /**
45
+ * Get available topics
46
+ */
47
+ getTopics: async () => {
48
+ const subscriber = getTopicSubscriber();
49
+ return await subscriber.getTopics();
50
+ }
51
+ };
52
+ export { topicsApi as topics };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Topic Subscriber for iframe communication
3
+ * Manages subscriptions to topics and receives events from the host window
4
+ */
5
+ import type { TopicDefinition, TopicSubscriptionCallback } from "./types";
6
+ export declare class TopicSubscriber {
7
+ private subscriptions;
8
+ private topics;
9
+ private origin;
10
+ private debug;
11
+ private useGlobalDebug;
12
+ private boundHandleMessage;
13
+ private subscriptionIdCounter;
14
+ constructor(options?: {
15
+ origin?: string;
16
+ debug?: boolean;
17
+ });
18
+ private isDebugEnabled;
19
+ /**
20
+ * Request the list of available topics from the host
21
+ */
22
+ private requestTopics;
23
+ /**
24
+ * Subscribe to a topic with a callback
25
+ * Returns a subscription ID that can be used to unsubscribe
26
+ */
27
+ subscribe<T = any>(topic: string, callback: TopicSubscriptionCallback<T>): string;
28
+ /**
29
+ * Unsubscribe from a topic using subscription ID
30
+ */
31
+ unsubscribe(topic: string, subscriptionId: string): boolean;
32
+ /**
33
+ * Unsubscribe all callbacks for a topic
34
+ */
35
+ unsubscribeAll(topic: string): number;
36
+ /**
37
+ * Get list of available topics
38
+ */
39
+ getTopics(): Promise<TopicDefinition[]>;
40
+ /**
41
+ * Notify host about subscription changes
42
+ */
43
+ private notifySubscription;
44
+ /**
45
+ * Handle incoming messages from host
46
+ */
47
+ private handleMessage;
48
+ /**
49
+ * Handle incoming topic event and dispatch to callbacks
50
+ */
51
+ private handleTopicEvent;
52
+ /**
53
+ * Cleanup and destroy the subscriber
54
+ */
55
+ destroy(): void;
56
+ }
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Topic Subscriber for iframe communication
3
+ * Manages subscriptions to topics and receives events from the host window
4
+ */
5
+ export class TopicSubscriber {
6
+ constructor(options = {}) {
7
+ this.subscriptions = new Map();
8
+ this.topics = [];
9
+ this.subscriptionIdCounter = 0;
10
+ this.origin = options.origin || "*";
11
+ this.debug = options.debug ?? false;
12
+ this.useGlobalDebug = options.debug === undefined;
13
+ // Store bound handler for cleanup
14
+ this.boundHandleMessage = this.handleMessage.bind(this);
15
+ if (typeof window !== "undefined") {
16
+ window.addEventListener("message", this.boundHandleMessage);
17
+ }
18
+ // Request topics list on initialization
19
+ this.requestTopics();
20
+ if (this.isDebugEnabled()) {
21
+ console.log("[TopicSubscriber] Initialized", {
22
+ origin: this.origin,
23
+ debug: this.isDebugEnabled()
24
+ });
25
+ }
26
+ }
27
+ isDebugEnabled() {
28
+ if (!this.useGlobalDebug) {
29
+ return this.debug;
30
+ }
31
+ return typeof window !== "undefined" && window.__POSTMESSAGE_DEBUG__ === true;
32
+ }
33
+ /**
34
+ * Request the list of available topics from the host
35
+ */
36
+ requestTopics() {
37
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
38
+ const message = {
39
+ type: "pubsub-request-topics",
40
+ requestId: `topics_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
41
+ };
42
+ if (this.isDebugEnabled()) {
43
+ console.log("[TopicSubscriber] Requesting topics list", message);
44
+ }
45
+ window.parent.postMessage(message, this.origin);
46
+ }
47
+ }
48
+ /**
49
+ * Subscribe to a topic with a callback
50
+ * Returns a subscription ID that can be used to unsubscribe
51
+ */
52
+ subscribe(topic, callback) {
53
+ const subscriptionId = `sub_${++this.subscriptionIdCounter}_${Date.now()}`;
54
+ if (!this.subscriptions.has(topic)) {
55
+ this.subscriptions.set(topic, []);
56
+ }
57
+ const subscription = {
58
+ id: subscriptionId,
59
+ topic,
60
+ callback: callback
61
+ };
62
+ this.subscriptions.get(topic).push(subscription);
63
+ // Notify host about the subscription
64
+ this.notifySubscription(topic, true);
65
+ if (this.isDebugEnabled()) {
66
+ console.log("[TopicSubscriber] Subscribed to topic", {
67
+ topic,
68
+ subscriptionId,
69
+ totalSubscriptions: this.subscriptions.get(topic).length
70
+ });
71
+ }
72
+ return subscriptionId;
73
+ }
74
+ /**
75
+ * Unsubscribe from a topic using subscription ID
76
+ */
77
+ unsubscribe(topic, subscriptionId) {
78
+ const topicSubscriptions = this.subscriptions.get(topic);
79
+ if (!topicSubscriptions) {
80
+ if (this.isDebugEnabled()) {
81
+ console.warn("[TopicSubscriber] Topic not found for unsubscribe", { topic });
82
+ }
83
+ return false;
84
+ }
85
+ const index = topicSubscriptions.findIndex(sub => sub.id === subscriptionId);
86
+ if (index === -1) {
87
+ if (this.isDebugEnabled()) {
88
+ console.warn("[TopicSubscriber] Subscription ID not found", { topic, subscriptionId });
89
+ }
90
+ return false;
91
+ }
92
+ topicSubscriptions.splice(index, 1);
93
+ // If no more subscriptions for this topic, remove it
94
+ if (topicSubscriptions.length === 0) {
95
+ this.subscriptions.delete(topic);
96
+ // Notify host about unsubscription
97
+ this.notifySubscription(topic, false);
98
+ }
99
+ if (this.isDebugEnabled()) {
100
+ console.log("[TopicSubscriber] Unsubscribed from topic", {
101
+ topic,
102
+ subscriptionId,
103
+ remainingSubscriptions: topicSubscriptions.length
104
+ });
105
+ }
106
+ return true;
107
+ }
108
+ /**
109
+ * Unsubscribe all callbacks for a topic
110
+ */
111
+ unsubscribeAll(topic) {
112
+ const topicSubscriptions = this.subscriptions.get(topic);
113
+ if (!topicSubscriptions) {
114
+ return 0;
115
+ }
116
+ const count = topicSubscriptions.length;
117
+ this.subscriptions.delete(topic);
118
+ this.notifySubscription(topic, false);
119
+ if (this.isDebugEnabled()) {
120
+ console.log("[TopicSubscriber] Unsubscribed all from topic", { topic, count });
121
+ }
122
+ return count;
123
+ }
124
+ /**
125
+ * Get list of available topics
126
+ */
127
+ async getTopics() {
128
+ // Request fresh topics list
129
+ this.requestTopics();
130
+ // Return cached topics (host will send updated list via message)
131
+ return [...this.topics];
132
+ }
133
+ /**
134
+ * Notify host about subscription changes
135
+ */
136
+ notifySubscription(topic, isSubscribed) {
137
+ if (typeof window !== "undefined" && window.parent && window.parent !== window) {
138
+ const message = {
139
+ type: isSubscribed ? "pubsub-subscribe" : "pubsub-unsubscribe",
140
+ topic,
141
+ requestId: `sub_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
142
+ };
143
+ if (this.isDebugEnabled()) {
144
+ console.log("[TopicSubscriber] Notifying subscription change", message);
145
+ }
146
+ window.parent.postMessage(message, this.origin);
147
+ }
148
+ }
149
+ /**
150
+ * Handle incoming messages from host
151
+ */
152
+ handleMessage(event) {
153
+ if (this.origin !== "*" && event.origin !== this.origin) {
154
+ if (this.isDebugEnabled()) {
155
+ console.warn("[TopicSubscriber] Origin mismatch", {
156
+ expected: this.origin,
157
+ received: event.origin
158
+ });
159
+ }
160
+ return;
161
+ }
162
+ const data = event.data;
163
+ // Handle topic event
164
+ if (data && data.type === "pubsub-event") {
165
+ const eventMessage = data;
166
+ this.handleTopicEvent(eventMessage.payload);
167
+ return;
168
+ }
169
+ // Handle topics list
170
+ if (data && data.type === "pubsub-topics-list") {
171
+ const topicsMessage = data;
172
+ this.topics = topicsMessage.payload || [];
173
+ if (this.isDebugEnabled()) {
174
+ console.log("[TopicSubscriber] Received topics list", this.topics);
175
+ }
176
+ return;
177
+ }
178
+ }
179
+ /**
180
+ * Handle incoming topic event and dispatch to callbacks
181
+ */
182
+ handleTopicEvent(event) {
183
+ const topicSubscriptions = this.subscriptions.get(event.topic);
184
+ if (!topicSubscriptions || topicSubscriptions.length === 0) {
185
+ if (this.isDebugEnabled()) {
186
+ console.warn("[TopicSubscriber] Received event for topic with no subscriptions", {
187
+ topic: event.topic
188
+ });
189
+ }
190
+ return;
191
+ }
192
+ if (this.isDebugEnabled()) {
193
+ console.log("[TopicSubscriber] Dispatching event to callbacks", {
194
+ topic: event.topic,
195
+ type: event.type,
196
+ subscriptionCount: topicSubscriptions.length
197
+ });
198
+ }
199
+ // Call all callbacks for this topic
200
+ topicSubscriptions.forEach(subscription => {
201
+ try {
202
+ subscription.callback(event);
203
+ }
204
+ catch (error) {
205
+ console.error("[TopicSubscriber] Error in subscription callback", {
206
+ topic: event.topic,
207
+ subscriptionId: subscription.id,
208
+ error
209
+ });
210
+ }
211
+ });
212
+ }
213
+ /**
214
+ * Cleanup and destroy the subscriber
215
+ */
216
+ destroy() {
217
+ this.subscriptions.clear();
218
+ this.topics = [];
219
+ if (typeof window !== "undefined") {
220
+ window.removeEventListener("message", this.boundHandleMessage);
221
+ }
222
+ if (this.isDebugEnabled()) {
223
+ console.log("[TopicSubscriber] Destroyed");
224
+ }
225
+ }
226
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Pub/Sub Types for Command Frame
3
+ * Defines topic and event structures for pub/sub communication
4
+ */
5
+ /**
6
+ * Event type definition for a topic
7
+ */
8
+ export interface TopicEventType {
9
+ id: string;
10
+ name: string;
11
+ description?: string;
12
+ }
13
+ /**
14
+ * Topic definition with metadata
15
+ */
16
+ export interface TopicDefinition {
17
+ id: string;
18
+ name: string;
19
+ description?: string;
20
+ eventTypes: TopicEventType[];
21
+ }
22
+ /**
23
+ * Event payload structure
24
+ */
25
+ export interface TopicEvent<T = any> {
26
+ topic: string;
27
+ type: string;
28
+ data: T;
29
+ timestamp: string;
30
+ }
31
+ /**
32
+ * Subscription callback function type
33
+ */
34
+ export type TopicSubscriptionCallback<T = any> = (event: TopicEvent<T>) => void;
35
+ /**
36
+ * Subscription information
37
+ */
38
+ export interface TopicSubscription {
39
+ id: string;
40
+ topic: string;
41
+ callback: TopicSubscriptionCallback;
42
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Pub/Sub Types for Command Frame
3
+ * Defines topic and event structures for pub/sub communication
4
+ */
5
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@final-commerce/command-frame",
3
- "version": "0.0.6",
3
+ "version": "0.1.0",
4
4
  "description": "Commands Frame library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",