@arkeytyp/valu-api 1.1.0 → 1.1.2

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
@@ -1,62 +1,107 @@
1
- The `valu-api` package enables developers to create custom iframe applications for Valu Social. It provides tools to invoke functions of registered Valu applications and subscribe to their events. With features like API versioning, event handling, and console command testing, developers can seamlessly integrate and extend functionality within the Valu Social ecosystem.
1
+ The `valu-api` package enables developers to build custom iframe applications for Valu Social.
2
+ It provides tools to invoke functions on registered Valu applications, subscribe to their events, and communicate via intents.
3
+ With features like API versioning, event handling, and console command execution, you can seamlessly integrate and extend functionality within the Valu Social ecosystem.
2
4
 
3
- # Installation
5
+ ## Installation
4
6
 
5
7
  ```bash
6
8
  npm install @arkeytyp/valu-api
7
9
  ```
8
10
 
9
- # Usage
11
+ ## Usage
10
12
 
11
- ## Initialize ValuApi
13
+ ### Initialize ValuApi
12
14
 
13
- On your application startup, create an instance of `ValuApi` and subscribe to the `API_READY` event. This event will be triggered only when your application is launched as an iframe within the Valu Verse application.
15
+ On application startup, create an instance of `ValuApi` and subscribe to the `API_READY` event.
16
+ This event is triggered only when your application is launched as an iframe within the Valu Verse application.
14
17
 
15
18
  ```javascript
16
- import { ValuApi } from 'valu-api';
19
+ import { ValuApi } from "@arkeytyp/valu-api";
17
20
 
18
21
  const valuApi = new ValuApi();
19
- valuApi.current.addEventListener(ValuApi.API_READY, async (e) => {
20
- console.log("API IS READY!!!");
22
+ valuApi.addEventListener(ValuApi.API_READY, async (e) => {
23
+ console.log("API IS READY!");
21
24
  });
22
25
  ```
23
26
 
24
- # Running Application Intents
25
27
 
26
- Intents are a powerful way to communicate with other applications inside the Valu Social ecosystem. They allow your application to request actions from other registered Valu apps in a standardized way — for example, opening a chat, joining a meeting, or performing any predefined operation supported by another app.
28
+ ## Running Application Intents
29
+
30
+ Intents are a powerful way to communicate with other applications inside Valu Social.
31
+ They allow your application to request actions from other registered apps in a standardized way — for example, opening a chat, joining a meeting, or performing any supported operation.
27
32
 
28
33
  Each Intent contains:
29
34
 
30
- * **applicationId:** The target application’s ID.
31
- * **action:** The action you want to perform (e.g., `open`, `connect-to-meeting`).
32
- * **params:** Optional parameters for the action (e.g., room IDs, configuration data).
35
+ - **applicationId:** The target application’s ID.
36
+ - **action:** The action to perform (e.g., `open`, `connect-to-meeting`).
37
+ - **params:** Optional parameters for the action (e.g., room IDs, configuration data).
33
38
 
34
- Here’s an example of creating and running an intent to connect to a video meeting:
39
+ ### Example: Open a Video Chat
35
40
 
36
41
  ```javascript
37
- import { Intent } from 'valu-api';
38
-
39
- const intent = new Intent(
40
- 'videochat', // Target application ID
41
- 'connect-to-meeting', // Action to perform
42
- {
43
- roomId: '<room-id>', // Additional parameters
44
- withLocalTracks: true
45
- }
46
- );
42
+ import { Intent } from "@arkeytyp/valu-api";
47
43
 
44
+ const intent = new Intent('videochat');
48
45
  await valuApi.sendIntent(intent);
49
46
  ```
50
47
 
51
- # Handling Application Lifecycle
48
+ ### Example: Open a Text Channel for the Current User
49
+
50
+ First, get the current user ID using the `users` API:
51
+
52
+ ```javascript
53
+ import { Intent } from "@arkeytyp/valu-api";
54
+
55
+ const usersApi = await valuApi.getApi('users');
56
+ const currentUser = await usersApi.run('current');
57
+ if (!currentUser) {
58
+ console.error('Something went wrong');
59
+ return;
60
+ }
61
+
62
+ const intent = new Intent('textchat', 'open-channel', { userId: currentUser.id });
63
+ await valuApi.sendIntent(intent);
64
+ ```
65
+ ## Invoking Services
66
+
67
+ Invoking a Service works almost the same way as running an Application Intent.
68
+ You still use the same `Intent` object with `applicationId`, `action`, and optional `params` — the key difference is **what the `applicationId` points to and how the call affects the UI**.
69
+
70
+ When calling a **Service Intent**:
71
+
72
+ - **`applicationId`** refers to the **service name** (e.g., `ApplicationStorage`), not a visible UI application.
73
+ - Services run entirely **in the background**.
74
+ - Invoking a service **does not change** the currently opened applications.
75
+ - Service Intents are ideal for performing background logic such as:
76
+ - Running searches
77
+ - Fetching or processing data
78
+ - Triggering non-visual workflows
79
+ - Performing system-level operations
80
+
81
+ This makes Services a parallel mechanism to Application Intents, with the difference that they target **non-UI services** instead of interactive apps.
82
+
83
+ ---
84
+
85
+ ### Example: Querying the `ApplicationStorage` Service
86
+
87
+ Below is an example of using an `Intent` to query the `ApplicationStorage` service to search for resources:
88
+
89
+ ```ts
90
+ const intent = new Intent('ApplicationStorage', 'resource-search', {
91
+ size: 10,
92
+ });
93
+
94
+ const result = await valuApi.callService(intent);
95
+ ```
52
96
 
53
- The `valu-api` package provides a way to handle **application lifecycle events** inside your iframe application. By implementing a `ValuApplication` class and registering it with `ValuApi`, you can easily respond to events such as when your app is created, receives a new intent, or is destroyed.
97
+ ## Handling Application Lifecycle
54
98
 
55
- This allows you to **separate application logic from API wiring** and makes it simple to handle incoming intents and return values back to the caller.
99
+ The `valu-api` package lets your iframe app handle **application lifecycle events**.
100
+ By extending `ValuApplication` and registering it with `ValuApi`, you can respond when your app is created, receives a new intent, or is destroyed.
56
101
 
57
- ## 1. Create Your Application Class
102
+ This helps you **separate application logic from API wiring** and makes handling incoming intents straightforward.
58
103
 
59
- Extend the `ValuApplication` class and override its lifecycle methods:
104
+ ### 1. Create Your Application Class
60
105
 
61
106
  ```javascript
62
107
  import { ValuApplication } from '@arkeytyp/valu-api';
@@ -72,15 +117,13 @@ class MyApp extends ValuApplication {
72
117
  return { handled: true, data: { message: 'Processed successfully' } };
73
118
  }
74
119
 
75
- async onDestroy() {
120
+ onDestroy() {
76
121
  console.log('App is shutting down');
77
122
  }
78
123
  }
79
124
  ```
80
125
 
81
- ## 2. Register Your Application with ValuApi
82
-
83
- Set your application instance within `ValuApi`:
126
+ ### 2. Register Your Application with ValuApi
84
127
 
85
128
  ```javascript
86
129
  import { ValuApi } from '@arkeytyp/valu-api';
@@ -89,101 +132,199 @@ const valuApi = new ValuApi();
89
132
  valuApi.setApplication(new MyApp());
90
133
  ```
91
134
 
92
- Once registered, the `ValuApi` will call the appropriate lifecycle methods when events are received from the host (e.g., app launch, new intent, app close).
93
-
94
- ## Lifecycle Methods
135
+ **Lifecycle Methods:**
136
+ - `onCreate(intent)` — Triggered when the application is first launched with an intent.
137
+ - `onNewIntent(intent)` — Triggered when a new intent is sent while the application is already running.
138
+ - `onDestroy()` — Triggered when the application is about to be destroyed.
95
139
 
96
- * **`onCreate(intent)`** – Triggered when the application is first launched with an Intent. You can return an optional value to send back to the caller.
97
- * **`onNewIntent(intent)`** – Triggered when a new Intent is sent to the application while it is already running. The return value will be sent back to whoever triggered the Intent.
98
- * **`onDestroy()`** – Triggered when the application is about to be destroyed. Use this to clean up resources.
99
-
100
- ### Lifecycle Flow
140
+ #### Lifecycle Flow
101
141
 
102
142
  ```
103
- [onCreate] → [onNewIntent] (many times) → [onDestroy]
143
+ [onCreate] → [onNewIntent] (0..N times) → [onDestroy]
104
144
  ```
105
145
 
106
- # Using System API
107
-
108
- The **System API** allows your iframe application to interact directly with the Valu Social platform and its internal applications.
109
146
 
110
- This API provides a unified way to:
147
+ ## Using the System API
111
148
 
112
- * Access core platform features (apps, chat, etc.)
113
- * Call specific commands on these features
114
- * Subscribe to real-time events emitted by the platform
115
- * Run and test commands from the console for debugging
149
+ The **System API** allows your iframe app to interact directly with the Valu Social platform and its internal applications.
150
+ It provides a unified way to:
116
151
 
117
- This makes it easy to extend the functionality of Valu Social and integrate your iframe application with other parts of the ecosystem.
152
+ - Access core platform features (apps, chat, etc.)
153
+ - Call commands on these features
154
+ - Subscribe to real-time events from the platform
155
+ - Run and test commands from the console for debugging
118
156
 
119
- ## 1. Get an API Pointer
157
+ ### 1. Get an API Pointer
120
158
 
121
- Once the API is ready, you can create an `APIPointer` instance by specifying the name and version of the API you want to use. The version parameter is optional, and if omitted, the latest version will be used.
159
+ Once the API is ready, you can get an `APIPointer` by specifying the API name and (optionally) the version.
122
160
 
123
161
  ```javascript
124
- const appApi = valuApi.getApi('app', 1); // Specific version
125
- const appApiLatest = valuApi.current.getApi('app'); // Latest version
162
+ const appApi = await valuApi.getApi('app', 1); // Specific version
163
+ const appApiLatest = await valuApi.getApi('app'); // Latest version
126
164
  ```
127
165
 
128
- ## 2. Invoke API Commands
166
+ ### 2. Invoke API Commands
129
167
 
130
- After obtaining the API pointer, you can invoke commands on the API. Here's an example of opening the `text_chat` on the app API:
168
+ After obtaining the API pointer, you can invoke commands.
169
+ For example, to get the current network id:
131
170
 
132
171
  ```javascript
133
- await appApi.run('open', 'text_chat');
172
+ const networkApi = await valuApi.getApi('network');
173
+ const networkId = await networkApi.run('id');
174
+ console.log(networkId);
134
175
  ```
135
176
 
136
- For interacting with other APIs, like the chat API:
137
-
138
- ```javascript
139
- const chatApi = valuApi.current.getApi('chat');
140
- await chatApi.run('open-channel', { roomId: 'room123', propId: 'prop456' });
141
- ```
177
+ ### 3. Subscribe to Events
142
178
 
143
- ## 3. Subscribe to Events
144
-
145
- You can subscribe to events emitted by the API. For example, if you want to listen for the `app-open` event:
179
+ You can subscribe to events emitted by the API.
180
+ For example, listen for the `app-open` event:
146
181
 
147
182
  ```javascript
183
+ const appApi = await valuApi.getApi('app');
148
184
  appApi.addEventListener('app-open', (event) => {
149
185
  console.log(event);
150
186
  });
151
187
  ```
152
188
 
153
- ## 4. Run Console Commands (For Testing)
189
+ ### 4. Run Console Commands (For Testing)
154
190
 
155
- You can use the `runConsoleCommand` method to execute commands directly in the console environment. This method processes the output and returns a resolved promise on success or an error message if the command fails.
191
+ Use `runConsoleCommand` to execute commands directly in the console environment.
156
192
 
157
193
  ```javascript
158
- let command = 'app open text_chat';
159
- let reply = await valuApi.current.runConsoleCommand(command);
194
+ const reply = await valuApi.runConsoleCommand('network id');
160
195
  console.log(reply);
196
+ ```
161
197
 
162
- command = 'chat open-channel roomId xz21wd31tx83kk propId 812t26xbq5424b';
163
- reply = await valuApi.current.runConsoleCommand(command);
164
- console.log(reply);
198
+ #### Run Intents via Console Commands
199
+
200
+ You can also use the console to run intents — the following two examples achieve the same result:
201
+
202
+ **Via API:**
203
+
204
+ ```javascript
205
+ import { Intent } from "@arkeytyp/valu-api";
206
+
207
+ const usersApi = await valuApi.getApi('users');
208
+ const currentUser = await usersApi.run('current');
209
+ if (!currentUser) {
210
+ console.error('Something went wrong');
211
+ return;
212
+ }
213
+
214
+ const intent = new Intent('textchat', 'open-channel', { userId: currentUser.id });
215
+ await valuApi.sendIntent(intent);
165
216
  ```
166
217
 
167
- ## Example Workflow
218
+ **Via Console:**
168
219
 
169
220
  ```javascript
170
- import { ValuApi } from 'valu-api';
221
+ const currentUser = await valuApi.runConsoleCommand('users current');
222
+ const reply = await valuApi.runConsoleCommand(
223
+ `app run -applicationId textchat -action open-channel -userId ${currentUser.id}`
224
+ );
225
+ console.log(reply);
226
+ ```
171
227
 
172
- const valuApi = new ValuApi();
228
+ # Routing in Valu iFrame Applications
229
+
230
+ The application is embedded inside Valuverse and controlled by the host.
231
+
232
+ - Valuverse owns the global routing context
233
+ - Your app receives route updates from Valu
234
+ - Your app should push navigation changes back to Valu
235
+
236
+ ---
237
+
238
+ ## Important Concept: Route Visibility
239
+
240
+ There are **two different routing scopes**:
241
+
242
+ ### Local (App-only) Routing
243
+ Routing handled only inside your application (e.g. React Router).
244
+
245
+ - ✅ App works normally
246
+ - ❌ Routes are **not visible** to Valuverse
247
+ - ❌ No deep linking from the main application
248
+
249
+ ### Valu Routing (Host-aware)
250
+ Routing handled through Valu API.
251
+
252
+ - ✅ Routes appear in the main application
253
+ - ✅ Deep linking works
254
+ - ✅ Navigation state is shared with Valuverse
255
+
256
+ ---
257
+
258
+ ## Using React Router in an iFrame App
259
+
260
+ Using **React Router inside an iFrame Valu app is totally fine**.
261
+
262
+ Your application will:
263
+ - render pages correctly
264
+ - navigate normally
265
+ - function as a self-contained UI
173
266
 
174
- valuApi.current.addEventListener(ValuApi.API_READY, async () => {
175
- console.log("API IS READY!!!");
267
+ However:
176
268
 
177
- const appApi = valuApi.current.getApi('app');
269
+ - those routes are **internal only**
270
+ - they **do not propagate** to Valuverse
271
+ - the main application will not see or control them
178
272
 
179
- await appApi.run('open', 'text_chat');
273
+ This approach is acceptable for:
274
+ - demo applications
275
+ - prototypes
276
+ - isolated tools
277
+ - apps that do not need host-level routing
180
278
 
181
- appApi.addEventListener('app-open', (event) => {
182
- console.log('App opened:', event);
183
- });
279
+ ---
184
280
 
185
- let command = 'app open text_chat';
186
- let reply = await valuApi.current.runConsoleCommand(command);
187
- console.log(reply);
281
+ ## Best Practice for Valuverse Applications
282
+
283
+ If your application is built to behave like a **native Valuverse app**, the recommended approach is:
284
+
285
+ > **Use Valu routing instead of (or in addition to) local routing.**
286
+
287
+ This ensures:
288
+ - consistent navigation behavior
289
+ - correct deep linking
290
+ - visibility in the main application router
291
+ - proper docking and context switching
292
+
293
+ ---
294
+
295
+ ## Valu Routing API
296
+
297
+ ### Subscribing to Route Changes
298
+
299
+ Valu notifies your application when the route changes:
300
+
301
+ ```ts
302
+ valuApi.addEventListener(ValuApi.ON_ROUTE, (route) => {
303
+ // route example:
304
+ // "/console"
305
+ // "/api/users/id/123"
188
306
  });
189
- ```
307
+ ```
308
+
309
+ ### Pushing a New Route
310
+
311
+ Navigate forward:
312
+
313
+ ```ts
314
+ valuApi.pushRoute("/documentation");
315
+ ```
316
+
317
+ Replacing the Current Route
318
+ Redirect without adding a history entry:
319
+
320
+ ```ts
321
+ valuApi.replaceRoute("/console");
322
+ ```
323
+
324
+ ## Sample Project
325
+
326
+ We've created a sample application integrated with Valu API.
327
+ Check out the repository here and feel free to leave comments or feedback:
328
+
329
+ [https://github.com/Roomful/ValuSampleApp](https://github.com/Roomful/ValuSampleApp)
330
+ know if you want a **quick start** section, more real-world samples, or even a troubleshooting/FAQ block!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkeytyp/valu-api",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "A package for developing iframe applications for Valu Social. Allows invoking functions of registered Valu applications and subscribing to events, as well as other features that enable developers creating own ifram apps for the value social",
5
5
  "main": "src/ValuApi.js",
6
6
  "scripts": {
package/src/ValuApi.js CHANGED
@@ -17,6 +17,7 @@ export { APIPointer } from "./APIPointer.js";
17
17
  export class ValuApi {
18
18
 
19
19
  static API_READY = 'api:ready'
20
+ static ON_ROUTE = `on_route`;
20
21
 
21
22
  #eventEmitter;
22
23
  #valuApplication = {};
@@ -145,6 +146,20 @@ export class ValuApi {
145
146
  return deferredPromise.promise;
146
147
  }
147
148
 
149
+ async callService(intent) {
150
+ let deferredPromise = this.#createDeferred();
151
+
152
+ this.#postToValuApp('api:service-intent', {
153
+ applicationId: intent.applicationId,
154
+ action: intent.action,
155
+ params: intent.params,
156
+ requestId: deferredPromise.id,
157
+ });
158
+
159
+ this.#requests[deferredPromise.id] = deferredPromise;
160
+ return deferredPromise.promise;
161
+ }
162
+
148
163
  /**
149
164
  * Executes a given console command and returns the result of an API function.
150
165
  *
@@ -170,6 +185,40 @@ export class ValuApi {
170
185
  return deferredPromise.promise;
171
186
  }
172
187
 
188
+
189
+ #runCommand(name, data) {
190
+ this.#postToValuApp('api:run-command', {
191
+ command: name,
192
+ data: data,
193
+ });
194
+ }
195
+
196
+ /**
197
+ * Pushes a new route onto the navigation stack.
198
+ *
199
+ * Use this when:
200
+ * navigating forward
201
+ * opening a new view
202
+ * preserving back-navigation history
203
+ * @param path
204
+ */
205
+ pushRoute = (path) => {
206
+ this.#runCommand('pushRoute', path);
207
+ }
208
+
209
+ /**
210
+ * Replaces the current route without adding a new history entry.
211
+ * Use this when:
212
+ * redirecting
213
+ * normalizing URLs
214
+ * preventing back-navigation to the previous route
215
+ * @param {string }path
216
+ */
217
+ replaceRoute = (path) => {
218
+ this.#runCommand('replaceRoute', path);
219
+ }
220
+
221
+
173
222
  #createDeferred() {
174
223
  let resolve, reject;
175
224
  const promise = new Promise((res, rej) => {
@@ -187,7 +236,7 @@ export class ValuApi {
187
236
  }
188
237
 
189
238
  const message = event.data.message;
190
- // console.log('Message From Valu: ', event.data.name, ' ', message);
239
+ //console.log('Message From Valu: ', event.data.name, ' ', message);
191
240
 
192
241
  switch (event.data.name) {
193
242
  case 'api:ready': {
@@ -205,14 +254,26 @@ export class ValuApi {
205
254
  break;
206
255
  }
207
256
 
257
+ case 'api:trigger': {
258
+ switch (message.action) {
259
+ case ValuApi.ON_ROUTE: {
260
+ this.#eventEmitter.emit(ValuApi.ON_ROUTE, message.data);
261
+ this.#applicationInstance?.onUpdateRouterContext(message.data);
262
+ }
263
+ }
264
+ break;
265
+ }
266
+
208
267
  case 'api:new-intent': {
209
268
  const intent = new Intent(message.applicationId, message.action, message.params);
210
269
  this.#applicationInstance?.onNewIntent(intent);
270
+ break;
211
271
  }
212
272
 
213
273
  case 'api:run-console-completed': {
214
274
  const requestId = event.data.requestId;
215
275
  const deferred = this.#requests[requestId];
276
+
216
277
  if(deferred) {
217
278
  deferred.resolve(message);
218
279
  } else {
@@ -28,4 +28,15 @@ export class ValuApplication {
28
28
  * Called when the app is about to be destroyed.
29
29
  */
30
30
  async onDestroy() {}
31
+
32
+
33
+ /**
34
+ * Called when the application’s router context changes.
35
+ *
36
+ * This typically happens when:
37
+ * the app moves between main / side / modal containers
38
+ * the host updates routing or layout state
39
+ * @param {string} context
40
+ */
41
+ onUpdateRouterContext(context) {};
31
42
  }
@@ -1,6 +1,7 @@
1
1
  declare module '@arkeytyp/valu-api' {
2
2
  export class ValuApi {
3
3
  static API_READY: string;
4
+ static ON_ROUTE : string;
4
5
 
5
6
  get connected(): boolean;
6
7
 
@@ -16,11 +17,33 @@ declare module '@arkeytyp/valu-api' {
16
17
  * @returns A promise resolving to the response from the target application.
17
18
  */
18
19
  sendIntent(intent: Intent): Promise<any>;
20
+ callService(intent: Intent): Promise<any>;
19
21
 
20
22
  addEventListener(event: string, callback: (data: any) => void): void;
21
23
  removeEventListener(event: string, callback: (data: any) => void): void;
22
24
  getApi(apiName: string, version?: number): Promise<APIPointer>;
23
25
  runConsoleCommand(command: string): Promise<any | string>;
26
+
27
+ /**
28
+ * Pushes a new route onto the navigation stack.
29
+ *
30
+ * Use this when:
31
+ * navigating forward
32
+ * opening a new view
33
+ * preserving back-navigation history
34
+ * @param path
35
+ */
36
+ pushRoute(path: string): void;
37
+
38
+ /**
39
+ * Replaces the current route without adding a new history entry.
40
+ * Use this when:
41
+ * redirecting
42
+ * normalizing URLs
43
+ * preventing back-navigation to the previous route
44
+ * @param {string }path
45
+ */
46
+ replaceRoute(path: string): void;
24
47
  }
25
48
 
26
49
  export class APIPointer {
@@ -106,5 +129,15 @@ declare module '@arkeytyp/valu-api' {
106
129
  * Use this to clean up resources (e.g., closing connections, clearing timers).
107
130
  */
108
131
  onDestroy(): void;
132
+
133
+ /**
134
+ * Called when the application’s router context changes.
135
+ *
136
+ * This typically happens when:
137
+ * the app moves between main / side / modal containers
138
+ * the host updates routing or layout state
139
+ * @param context - updated application route
140
+ */
141
+ onUpdateRouterContext(context: string): void;
109
142
  }
110
143
  }