@arkeytyp/valu-api 1.0.3 → 1.1.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.
package/README.md CHANGED
@@ -1,104 +1,234 @@
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
- # install
4
- ```
5
+ ## Installation
6
+
7
+ ```bash
5
8
  npm install @arkeytyp/valu-api
6
9
  ```
7
10
 
8
- # Usage
11
+ ## Usage
9
12
 
10
- ## 1. Initialize ValuApi
11
- 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.
13
+ ### Initialize ValuApi
14
+
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.
12
17
 
13
18
  ```javascript
14
- import { ValuApi } from 'valu-api';
19
+ import { ValuApi } from "@arkeytyp/valu-api";
15
20
 
16
21
  const valuApi = new ValuApi();
17
- valuApi.current.addEventListener(ValuApi.API_READY, async (e) => {
18
- console.log("API IS READY!!!");
22
+ valuApi.addEventListener(ValuApi.API_READY, async (e) => {
23
+ console.log("API IS READY!");
24
+ });
25
+ ```
26
+
27
+
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.
32
+
33
+ Each Intent contains:
34
+
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).
38
+
39
+ ### Example: Open a Video Chat
40
+
41
+ ```javascript
42
+ import { Intent } from "@arkeytyp/valu-api";
43
+
44
+ const intent = new Intent('videochat');
45
+ await valuApi.sendIntent(intent);
46
+ ```
47
+
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,
19
92
  });
93
+
94
+ const result = await valuApi.callService(intent);
20
95
  ```
21
96
 
22
- ## 2. Get an API Pointer
23
- 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.
97
+ ## Handling Application Lifecycle
98
+
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.
101
+
102
+ This helps you **separate application logic from API wiring** and makes handling incoming intents straightforward.
24
103
 
25
- To get a pointer to the app API version 1:
104
+ ### 1. Create Your Application Class
26
105
 
27
106
  ```javascript
28
- const appApi = valuApi.getApi('app', 1);
107
+ import { ValuApplication } from '@arkeytyp/valu-api';
108
+
109
+ class MyApp extends ValuApplication {
110
+ async onCreate(intent) {
111
+ console.log('App created with:', intent);
112
+ return { status: 'initialized' };
113
+ }
114
+
115
+ async onNewIntent(intent) {
116
+ console.log('New intent received:', intent);
117
+ return { handled: true, data: { message: 'Processed successfully' } };
118
+ }
119
+
120
+ onDestroy() {
121
+ console.log('App is shutting down');
122
+ }
123
+ }
29
124
  ```
30
125
 
31
- To use the latest version of the API:
126
+ ### 2. Register Your Application with ValuApi
32
127
 
33
128
  ```javascript
34
- const appApi = valuApi.current.getApi('app');
129
+ import { ValuApi } from '@arkeytyp/valu-api';
130
+
131
+ const valuApi = new ValuApi();
132
+ valuApi.setApplication(new MyApp());
35
133
  ```
36
134
 
37
- ## 3. Invoke API Commands
38
- 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:
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.
139
+
140
+ #### Lifecycle Flow
141
+
142
+ ```
143
+ [onCreate] → [onNewIntent] (0..N times) → [onDestroy]
144
+ ```
145
+
146
+
147
+ ## Using the System API
148
+
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:
151
+
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
156
+
157
+ ### 1. Get an API Pointer
158
+
159
+ Once the API is ready, you can get an `APIPointer` by specifying the API name and (optionally) the version.
39
160
 
40
161
  ```javascript
41
- await appApi.run('open', 'text_chat');
162
+ const appApi = await valuApi.getApi('app', 1); // Specific version
163
+ const appApiLatest = await valuApi.getApi('app'); // Latest version
42
164
  ```
43
165
 
44
- For interacting with other APIs, like the chat API:
166
+ ### 2. Invoke API Commands
167
+
168
+ After obtaining the API pointer, you can invoke commands.
169
+ For example, to get the current network id:
45
170
 
46
171
  ```javascript
47
- const chatApi = valuApi.current.getApi('chat');
48
- await chatApi.run('open-channel', { roomId: 'room123', propId: 'prop456' });
172
+ const networkApi = await valuApi.getApi('network');
173
+ const networkId = await networkApi.run('id');
174
+ console.log(networkId);
49
175
  ```
50
176
 
51
- ## 4. Subscribe to Events
52
- You can subscribe to events emitted by the API. For example, if you want to listen for the app-open event:
177
+ ### 3. Subscribe to Events
178
+
179
+ You can subscribe to events emitted by the API.
180
+ For example, listen for the `app-open` event:
53
181
 
54
182
  ```javascript
183
+ const appApi = await valuApi.getApi('app');
55
184
  appApi.addEventListener('app-open', (event) => {
56
185
  console.log(event);
57
186
  });
58
187
  ```
59
188
 
60
- ## 5. Run Console Commands (For Testing)
61
- 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.
189
+ ### 4. Run Console Commands (For Testing)
62
190
 
63
- To run a console command, use:
191
+ Use `runConsoleCommand` to execute commands directly in the console environment.
64
192
 
65
193
  ```javascript
66
- let command = 'app open text_chat';
67
- let reply = await valuApi.current.runConsoleCommand(command);
68
- console.log(reply);
69
-
70
- command = 'chat open-channel roomId xz21wd31tx83kk propId 812t26xbq5424b';
71
- reply = await valuApi.current.runConsoleCommand(command);
194
+ const reply = await valuApi.runConsoleCommand('network id');
72
195
  console.log(reply);
73
196
  ```
74
197
 
75
- ## Example Workflow
76
- Here's an example of a simple workflow using valu-api:
198
+ #### Run Intents via Console Commands
77
199
 
78
- ```javascript
79
- import { ValuApi } from 'valu-api';
200
+ You can also use the console to run intents — the following two examples achieve the same result:
80
201
 
81
- const valuApi = new ValuApi();
202
+ **Via API:**
82
203
 
83
- // Wait for the API to be ready
84
- valuApi.current.addEventListener(ValuApi.API_READY, async () => {
85
- console.log("API IS READY!!!");
204
+ ```javascript
205
+ import { Intent } from "@arkeytyp/valu-api";
86
206
 
87
- // Get API pointer
88
- const appApi = valuApi.current.getApi('app');
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
+ }
89
213
 
90
- // Run a command on the app API
91
- await appApi.run('open', 'text_chat');
214
+ const intent = new Intent('textchat', 'open-channel', { userId: currentUser.id });
215
+ await valuApi.sendIntent(intent);
216
+ ```
92
217
 
93
- // Subscribe to events
94
- appApi.addEventListener('app-open', (event) => {
95
- console.log('App opened:', event);
96
- });
218
+ **Via Console:**
97
219
 
98
- // Run console command for testing
99
- let command = 'app open text_chat';
100
- let reply = await valuApi.current.runConsoleCommand(command);
101
- console.log(reply);
102
- });
220
+ ```javascript
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);
103
226
  ```
104
227
 
228
+ ## Sample Project
229
+
230
+ We've created a sample application integrated with Valu API.
231
+ Check out the repository here and feel free to leave comments or feedback:
232
+
233
+ [https://github.com/Roomful/ValuSampleApp](https://github.com/Roomful/ValuSampleApp)
234
+ 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.0.3",
3
+ "version": "1.1.1",
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/Intent.js ADDED
@@ -0,0 +1,57 @@
1
+
2
+ export class Intent {
3
+
4
+ // Predefined actions
5
+ static ACTION_VIEW = 'view';
6
+ static ACTION_OPEN = 'open';
7
+
8
+
9
+ // Private fields
10
+ #applicationId;
11
+ #action;
12
+ #params;
13
+
14
+ /** @returns {string} */
15
+ get applicationId() {
16
+ return this.#applicationId;
17
+ }
18
+
19
+ /** @returns {string} */
20
+ get action() {
21
+ return this.#action;
22
+ }
23
+
24
+ /** @returns {Object} */
25
+ get params() {
26
+ return this.#params;
27
+ }
28
+
29
+
30
+
31
+ constructor(applicationId, action = Intent.ACTION_OPEN, params = {}) {
32
+ this.#applicationId = applicationId;
33
+ this.#action = action;
34
+ this.#params = params;
35
+ }
36
+
37
+ /**
38
+ * Validates if a given object is a valid Intent instance.
39
+ * @param {any} obj
40
+ * @returns {boolean}
41
+ */
42
+ static isValid(obj) {
43
+ return (
44
+ obj instanceof Intent &&
45
+ typeof obj.applicationId === 'string' &&
46
+ typeof obj.action === 'string'
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Returns a stringified representation of the intent.
52
+ * @returns {string}
53
+ */
54
+ toString() {
55
+ return `[Intent] applicationId="${this.applicationId}", action="${this.action}", params=${JSON.stringify(this.params)}`;
56
+ }
57
+ }
package/src/ValuApi.js CHANGED
@@ -1,6 +1,11 @@
1
1
  import {EventEmitter} from "./EventEmitter.js";
2
2
  import {APIPointer} from "./APIPointer.js";
3
3
  import {guid4, nextId} from "./Utils.js";
4
+ import {Intent} from "./Intent";
5
+
6
+ export { ValuApplication } from "./ValuApplication.js";
7
+ export { Intent } from "./Intent.js";
8
+ export { APIPointer } from "./APIPointer.js";
4
9
 
5
10
 
6
11
  /**
@@ -16,6 +21,11 @@ export class ValuApi {
16
21
  #eventEmitter;
17
22
  #valuApplication = {};
18
23
  #requests = new Map();
24
+ #lastIntent;
25
+
26
+ /** @type ValuApplication */
27
+ #applicationInstance = null;
28
+
19
29
 
20
30
  get connected() {
21
31
  return this.#valuApplication.origin !== undefined;
@@ -58,6 +68,21 @@ export class ValuApi {
58
68
  return apiPointer;
59
69
  }
60
70
 
71
+ /**
72
+ * Registers an application instance to handle lifecycle events.
73
+ *
74
+ * Developers should create a class that extends {@link ValuApplication} and implement
75
+ * its lifecycle methods.
76
+ * This instance will receive all lifecycle callbacks sent from the Valu Social host application.
77
+ */
78
+ setApplication(appInstance) {
79
+ this.#applicationInstance = appInstance;
80
+
81
+ if(this.#lastIntent) {
82
+ this.#applicationInstance.onCreate(this.#lastIntent).catch(console.error);
83
+ }
84
+ }
85
+
61
86
  async #registerApiPointer(apiName, version, guid) {
62
87
  let deferredPromise = this.#createDeferred();
63
88
 
@@ -74,8 +99,6 @@ export class ValuApi {
74
99
 
75
100
  #postToValuApp(name, message) {
76
101
  const data = { name: name, message: message};
77
-
78
- // console.log('Posting to Valu: ', name, ' ', message, ' source: ', this.#valuApplication.source);
79
102
  this.#valuApplication.source.postMessage(data, this.#valuApplication.origin);
80
103
  }
81
104
 
@@ -91,6 +114,51 @@ export class ValuApi {
91
114
  });
92
115
  }
93
116
 
117
+ /**
118
+ * Sends an intent to the Valu application.
119
+ *
120
+ * This method posts the intent data to the Valu application and returns a promise
121
+ * that resolves or rejects when the corresponding response is received.
122
+ *
123
+ * Internally, it creates a deferred promise and assigns a unique `requestId` to track
124
+ * the response for this specific intent execution.
125
+ *
126
+ * @param {Intent} intent - The intent object containing the target application ID, action, and parameters.
127
+ * @returns {Promise<unknown>} A promise that resolves with the response from the Valu application.
128
+ *
129
+ * @example
130
+ * const intent = new Intent('chatApp', Intent.ACTION_OPEN, { roomId: '1234' });
131
+ * const result = await api.sendIntent(intent);
132
+ * console.log(result);
133
+ */
134
+ async sendIntent(intent) {
135
+ let deferredPromise = this.#createDeferred();
136
+
137
+ this.#postToValuApp('api:run-intent', {
138
+ applicationId: intent.applicationId,
139
+ action: intent.action,
140
+ params: intent.params,
141
+ requestId: deferredPromise.id,
142
+ });
143
+
144
+ this.#requests[deferredPromise.id] = deferredPromise;
145
+ return deferredPromise.promise;
146
+ }
147
+
148
+ async callService(intent) {
149
+ let deferredPromise = this.#createDeferred();
150
+
151
+ this.#postToValuApp('api:service-intent', {
152
+ applicationId: intent.applicationId,
153
+ action: intent.action,
154
+ params: intent.params,
155
+ requestId: deferredPromise.id,
156
+ });
157
+
158
+ this.#requests[deferredPromise.id] = deferredPromise;
159
+ return deferredPromise.promise;
160
+ }
161
+
94
162
  /**
95
163
  * Executes a given console command and returns the result of an API function.
96
164
  *
@@ -133,23 +201,33 @@ export class ValuApi {
133
201
  }
134
202
 
135
203
  const message = event.data.message;
136
- // console.log('Message From Valu: ', event.data.name, ' ', message);
204
+ //console.log('Message From Valu: ', event.data.name, ' ', message);
137
205
 
138
206
  switch (event.data.name) {
139
207
  case 'api:ready': {
140
208
  this.#valuApplication = {
141
- id : message,
209
+ id : message.applicationId,
142
210
  source: event.source,
143
211
  origin: event.origin,
144
212
  }
145
213
 
146
214
  this.#eventEmitter.emit(ValuApi.API_READY);
215
+
216
+ const intent = new Intent(message.applicationId, message.action, message.params);
217
+ this.#applicationInstance?.onCreate(intent);
218
+ this.#lastIntent = intent;
147
219
  break;
148
220
  }
149
221
 
222
+ case 'api:new-intent': {
223
+ const intent = new Intent(message.applicationId, message.action, message.params);
224
+ this.#applicationInstance?.onNewIntent(intent);
225
+ }
226
+
150
227
  case 'api:run-console-completed': {
151
228
  const requestId = event.data.requestId;
152
229
  const deferred = this.#requests[requestId];
230
+
153
231
  if(deferred) {
154
232
  deferred.resolve(message);
155
233
  } else {
@@ -0,0 +1,31 @@
1
+
2
+ /**
3
+ * Abstract base class for Valu iframe applications.
4
+ *
5
+ * Developers should extend this class to implement application-specific logic
6
+ * for handling lifecycle events within the Valu Social ecosystem.
7
+ *
8
+ * The Valu API will automatically call these lifecycle methods when the host
9
+ * application sends corresponding events (e.g., app launch, new intent, destroy).
10
+ */
11
+
12
+ export class ValuApplication {
13
+ /**
14
+ * Called when the app is first launched with an Intent.
15
+ * @param {Intent} intent
16
+ * @returns {Promise<any>}
17
+ */
18
+ async onCreate(intent) {}
19
+
20
+ /**
21
+ * Called when the app receives an Intent while already running (docked).
22
+ * @param {Intent} intent
23
+ * @returns {Promise<any>} - The result will be sent back to the caller
24
+ */
25
+ async onNewIntent(intent) {}
26
+
27
+ /**
28
+ * Called when the app is about to be destroyed.
29
+ */
30
+ async onDestroy() {}
31
+ }
@@ -4,6 +4,20 @@ declare module '@arkeytyp/valu-api' {
4
4
 
5
5
  get connected(): boolean;
6
6
 
7
+ /**
8
+ * Registers an application instance to handle lifecycle events.
9
+ * @param appInstance An instance of a class extending ValuApplication.
10
+ */
11
+ setApplication(appInstance: ValuApplication): void;
12
+
13
+ /**
14
+ * Sends an intent to another Valu application and returns the response.
15
+ * @param intent The Intent object containing the target application ID, action, and parameters.
16
+ * @returns A promise resolving to the response from the target application.
17
+ */
18
+ sendIntent(intent: Intent): Promise<any>;
19
+ callService(intent: Intent): Promise<any>;
20
+
7
21
  addEventListener(event: string, callback: (data: any) => void): void;
8
22
  removeEventListener(event: string, callback: (data: any) => void): void;
9
23
  getApi(apiName: string, version?: number): Promise<APIPointer>;
@@ -19,4 +33,79 @@ declare module '@arkeytyp/valu-api' {
19
33
  removeEventListener(event: string, callback: (data: any) => void): void;
20
34
  run(functionName: string, params?: any): Promise<any>;
21
35
  }
36
+
37
+ export type IntentParams = Record<string, any>;
38
+
39
+ export class Intent {
40
+ // Predefined actions
41
+ static ACTION_VIEW: string;
42
+ static ACTION_OPEN: string;
43
+
44
+ // Fields
45
+ private readonly _applicationId: string;
46
+ private readonly _action: string;
47
+ private readonly _params: IntentParams;
48
+
49
+ /**
50
+ * @param applicationId The ID of the application this intent targets.
51
+ * @param action The action to perform (defaults to 'open').
52
+ * @param params Optional parameters for the action.
53
+ */
54
+ constructor(applicationId: string, action?: string, params?: IntentParams);
55
+
56
+ /** Application ID this intent targets */
57
+ get applicationId(): string;
58
+
59
+ /** Action this intent performs */
60
+ get action(): string;
61
+
62
+ /** Additional parameters for this intent */
63
+ get params(): IntentParams;
64
+
65
+ /**
66
+ * Validates if a given object is a valid Intent instance.
67
+ * @param obj Any object to validate.
68
+ * @returns True if the object is a valid Intent instance.
69
+ */
70
+ static isValid(obj: any): boolean;
71
+
72
+ /**
73
+ * Returns a stringified representation of the intent.
74
+ */
75
+ toString(): string;
76
+ }
77
+
78
+ /**
79
+ * Abstract base class for Valu iframe applications.
80
+ *
81
+ * Developers should extend this class to implement application-specific logic
82
+ * for handling lifecycle events within the Valu Social ecosystem.
83
+ *
84
+ * The Valu API will automatically call these lifecycle methods when the host
85
+ * application sends corresponding events (e.g., app launch, new intent, destroy).
86
+ */
87
+ export class ValuApplication {
88
+ /**
89
+ * Called when the app is first launched with an Intent.
90
+ *
91
+ * @param intent - The Intent that triggered the app launch.
92
+ * @returns A value or a Promise resolving to a value that will be sent back to the caller.
93
+ */
94
+ onCreate(intent: Intent): Promise<any> | any;
95
+
96
+ /**
97
+ * Called when the app receives an Intent while already running (docked).
98
+ *
99
+ * @param intent - The incoming Intent.
100
+ * @returns A value or a Promise resolving to a value that will be sent back to whoever triggered the Intent.
101
+ */
102
+ onNewIntent(intent: Intent): Promise<any> | any;
103
+
104
+ /**
105
+ * Called when the app is about to be destroyed.
106
+ *
107
+ * Use this to clean up resources (e.g., closing connections, clearing timers).
108
+ */
109
+ onDestroy(): void;
110
+ }
22
111
  }