@bardioc/app-sdk 0.5.0 → 1.0.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.
Files changed (47) hide show
  1. package/README.md +86 -253
  2. package/dist/api/graph.d.ts +30 -0
  3. package/dist/api/graph.js +139 -0
  4. package/dist/api/os.d.ts +30 -0
  5. package/dist/api/os.js +48 -0
  6. package/dist/api/relay.d.ts +7 -0
  7. package/dist/api/relay.js +16 -0
  8. package/dist/api/request.d.ts +18 -0
  9. package/dist/api/request.js +12 -0
  10. package/dist/client.d.ts +104 -0
  11. package/dist/client.js +106 -0
  12. package/dist/contract.d.ts +294 -0
  13. package/dist/contract.js +150 -0
  14. package/dist/dev-idb.d.ts +10 -0
  15. package/dist/dev-idb.js +42 -0
  16. package/dist/dev-proxy.js +17 -3
  17. package/dist/dev.d.ts +16 -12
  18. package/dist/dev.js +101 -119
  19. package/dist/errors.d.ts +24 -25
  20. package/dist/errors.js +33 -48
  21. package/dist/index.d.ts +10 -7
  22. package/dist/index.js +2 -4
  23. package/dist/manifest.d.ts +10 -2
  24. package/dist/manifest.js +28 -24
  25. package/dist/protocol.d.ts +6 -29
  26. package/dist/protocol.js +3 -31
  27. package/dist/react.d.ts +21 -27
  28. package/dist/react.js +88 -212
  29. package/dist/serve.d.ts +26 -0
  30. package/dist/serve.js +64 -0
  31. package/dist/testing.d.ts +17 -0
  32. package/dist/testing.js +128 -0
  33. package/dist/types.d.ts +0 -250
  34. package/dist/vite.js +3 -0
  35. package/dist/wire.d.ts +46 -0
  36. package/dist/wire.js +138 -0
  37. package/package.json +12 -4
  38. package/dist/contract-matrix.d.ts +0 -148
  39. package/dist/contract-matrix.js +0 -150
  40. package/dist/host-bridge.d.ts +0 -3
  41. package/dist/host-bridge.js +0 -318
  42. package/dist/transports/backend-transport.d.ts +0 -24
  43. package/dist/transports/backend-transport.js +0 -54
  44. package/dist/transports/graph-transport.d.ts +0 -241
  45. package/dist/transports/graph-transport.js +0 -616
  46. package/dist/transports/os-transport.d.ts +0 -190
  47. package/dist/transports/os-transport.js +0 -444
package/README.md CHANGED
@@ -1,25 +1,17 @@
1
1
  # @bardioc/app-sdk
2
2
 
3
- SDK and Vite integration for building apps for the Bardioc OS.
3
+ SDK for building apps that run inside Bardioc as isolated iframes.
4
4
 
5
- This package focuses on the runtime SDK and Vite plugin only:
6
-
7
- 1. Bridge communication between an app and the OS, IndexedDB, and host APIs.
8
- 2. Validate app manifests and wire Vite apps for iframe-based development.
5
+ An app talks to its host only through a typed contract over a `MessagePort`: it calls host
6
+ methods (`ui.*`, `bff.request`, `idb.*`, `apps.*`), receives host calls (`ui.command`) and
7
+ events (`context.changed`), and reads streams (`events.graph`). Every failure is a
8
+ `BardiocError` with a `code`.
9
9
 
10
10
  ## Requirements
11
11
 
12
12
  - Node.js `>=20.19.0`
13
13
  - TypeScript `>=6.0.0`
14
- - For React apps, install `react` and `react-dom` in the consuming project
15
-
16
- ## Install into an existing project
17
-
18
- ```bash
19
- pnpm add @bardioc/app-sdk
20
- ```
21
-
22
- Apps can be developed independently outside the Bardioc OS and then tested through a live AppStore development session. That keeps the local development loop fast while still exercising the real host communication path.
14
+ - For React apps, `react` and `react-dom` in the consuming project
23
15
 
24
16
  ## Quick start
25
17
 
@@ -29,284 +21,135 @@ import { createRoot } from 'react-dom/client';
29
21
 
30
22
  function App() {
31
23
  const notify = useNotify();
32
-
33
- function sayHello() {
34
- notify('Hello from my app', 'success');
35
- }
36
-
37
- return <button onClick={sayHello}>Say hello</button>;
24
+ return <button onClick={() => notify('Hello.', 'success')}>Say hello</button>;
38
25
  }
39
26
 
40
- const isInsideIframe = globalThis.window.parent !== globalThis.window;
41
-
42
27
  createRoot(document.getElementById('root')!).render(
43
- isInsideIframe ? (
44
- <AppSdkProvider appId="my-app">
45
- <App />
46
- </AppSdkProvider>
47
- ) : (
48
- <div>Open this app from the Bardioc OS dock to use SDK features.</div>
49
- )
28
+ <AppSdkProvider>
29
+ <App />
30
+ </AppSdkProvider>
50
31
  );
51
32
  ```
52
33
 
53
- ## Exports
54
-
55
- | Path | Contents |
56
- | --------------------------- | ------------------------------------------- |
57
- | `@bardioc/app-sdk` | `createHostBridge`, errors, types, manifest |
58
- | `@bardioc/app-sdk/react` | `AppSdkProvider`, hooks (`useSdk`, etc.) |
59
- | `@bardioc/app-sdk/dev` | standalone dev bridge helpers |
60
- | `@bardioc/app-sdk/types` | Type-only TypeScript exports |
61
- | `@bardioc/app-sdk/protocol` | `SDK_MSG` constants, wire format types |
62
- | `@bardioc/app-sdk/vite` | `bardiocApp()` Vite plugin |
63
-
64
- ### Key exports
65
-
66
- ```ts
67
- // Bridge and types
68
- import {
69
- createHostBridge,
70
- type HostBridge,
71
- type HostBridgeConfig,
72
- type GraphNodeRaw,
73
- type GraphEdgeRaw,
74
- type UserProfile,
75
- type OrgStructure,
76
- } from '@bardioc/app-sdk';
77
-
78
- // Errors
79
- import {
80
- EntityNotFoundError,
81
- ValidationError,
82
- PermissionError,
83
- TimeoutError,
84
- NetworkError,
85
- SdkError,
86
- } from '@bardioc/app-sdk';
87
-
88
- // React hooks
89
- import { AppSdkProvider, useSdk, useNotify, useSendToKernel } from '@bardioc/app-sdk/react';
90
-
91
- // Standalone dev helpers
92
- import { installDevBridge, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';
93
- ```
94
-
95
- ## Vite plugin
34
+ Without React:
96
35
 
97
36
  ```ts
98
- // vite.config.ts
99
- import { bardiocApp } from '@bardioc/app-sdk/vite';
100
- import react from '@vitejs/plugin-react';
101
- import { defineConfig } from 'vite';
37
+ import { connect } from '@bardioc/app-sdk';
102
38
 
103
- export default defineConfig({
104
- plugins: [react(), bardiocApp({ appName: 'my-app', port: 3005 })],
105
- });
39
+ const bardioc = await connect();
40
+ const profile = await bardioc.os.profile.get();
106
41
  ```
107
42
 
108
- Handles dev base path, port config, host session proxy routes, platform fonts, and manifest validation on build.
109
-
110
- ### Platform fonts
111
-
112
- The Bardioc platform guarantees a stable font endpoint wherever an app runs — like `/api/transport`, it is a public contract that will never be renamed or removed. Load it with one line in `index.html` and do **not** bundle font packages into your app:
43
+ ## Exports
113
44
 
114
- ```html
115
- <link rel="stylesheet" href="/fonts/bardioc-fonts.css" />
116
- ```
45
+ | Path | Contents |
46
+ | ---------------------------- | ------------------------------------------------------------- |
47
+ | `@bardioc/app-sdk` | `connect`, `Bardioc`, `BardiocError`, manifest, domain types |
48
+ | `@bardioc/app-sdk/react` | `AppSdkProvider` and hooks |
49
+ | `@bardioc/app-sdk/protocol` | the contract: `APP_METHODS`, `serve`, `acceptApp` — for hosts |
50
+ | `@bardioc/app-sdk/dev` | `installDevHost`, `isDevStandalone`, `isInsideIframe` |
51
+ | `@bardioc/app-sdk/dev-proxy` | `startDevAuthProxy` for dev servers without the Vite plugin |
52
+ | `@bardioc/app-sdk/vite` | `bardiocApp()`, `bardiocDevAuth()` |
53
+ | `@bardioc/app-sdk/testing` | `hostConformance`: the behaviour every host must share |
117
54
 
118
- It provides `Nunito Sans Variable` (normal + italic) and `Geist Mono Variable` as variable fonts (latin subset), matching the `--font-nunito-sans` / `--font-geist-mono` theme variables that `@bardioc/ui` resolves by default.
55
+ ## API
119
56
 
120
- - **Embedded in the OS** the URL resolves same-origin against the host, which serves it with immutable caching — one download shared by the host and every app.
121
- - **Standalone dev** the `bardiocApp()` plugin serves the same files from assets shipped inside this package (dev server only — they are never added to your bundle). This applies to Vite-based apps; the angular and nextjs templates run their own dev servers, where the link is a harmless 404 standalone and resolves normally embedded in the OS.
122
-
123
- New apps scaffolded with `create-bardioc-app` include the `<link>` already.
124
-
125
- ## Standalone Dev Session
57
+ ```ts
58
+ const bardioc = await connect();
126
59
 
127
- Standalone local development is host-backed only.
60
+ bardioc.context; // { appId, host: 'os' | 'dev', osConfig }
61
+ bardioc.onContextChange(context => {});
128
62
 
129
- 1. Set `DEV_SECRET` and `API_BASE_URL` in your local `.env`.
130
- 2. Run `pnpm dev`.
63
+ await bardioc.ui.notify('Saved.', 'success');
64
+ await bardioc.ui.setCommands([{ id: 'save', title: 'Save' }]);
65
+ await bardioc.ui.setMenu([{ label: 'File', items: [{ type: 'command', commandId: 'save' }] }]);
66
+ const off = bardioc.ui.onCommand('save', () => save());
131
67
 
132
- The Vite plugin proxies `/rest/*` requests to `API_BASE_URL` with the `X-Dev-Secret` header, and `installDevBridge()` handles SDK messages when running in standalone dev.
68
+ await bardioc.bff.request({ path: '/os/me/profile' }); // any BFF path outside /auth
69
+ await bardioc.graph.query('ogit/_type:ogit/Note', { limit: 10 });
70
+ await bardioc.os.organization.getStructure();
71
+ await bardioc.relay('notes').request({ path: '/items' });
133
72
 
134
- Dev servers that cannot host the Vite plugin (angular, nextjs) run the same proxy as a standalone server:
73
+ const notes = bardioc.idb('notes');
74
+ await notes.put('n1', { title: 'Hi' });
75
+ await notes.get('n1'); // { key, value, updatedAt } | null
135
76
 
136
- ```javascript
137
- import { startDevAuthProxy } from '@bardioc/app-sdk/dev-proxy';
77
+ const end = await bardioc.events.graph({ types: ['ogit/Note'] }, event => {});
78
+ end();
138
79
 
139
- // Reads DEV_SECRET / API_BASE_URL from the project's .env files; resolves to null when unset.
140
- await startDevAuthProxy({ projectDir: process.cwd(), port: 3105 });
80
+ await bardioc.apps.list();
141
81
  ```
142
82
 
143
- Point the app at it with `installDevBridge({ apiBaseUrl: 'http://127.0.0.1:3105/rest' })`.
144
-
145
- ## React hooks
83
+ Scope: a call without `scopeId` uses the window's instance; `scopeId` makes the scope required;
84
+ `scopePolicy: 'none'` sends none.
146
85
 
147
- - `useSdk()` — raw bridge instance
148
- - `useNotify()` — fire-and-forget toast
149
- - `useSendToKernel()` — proxy a whitelisted message to the OS service worker
86
+ ### React hooks
150
87
 
151
- ### IndexedDB persistence
88
+ `useSdk()`, `useNotify()`, `useCommandMenu(commands, menu)`, `useActiveTab(tab)`,
89
+ `useOsConfig()`, `useGraphEvents({ types }, handler)`.
152
90
 
153
- `useSdk()` exposes `bridge.idb(storeName)` for app-scoped persistence:
91
+ ### Errors
154
92
 
155
93
  ```ts
156
- const drafts = bridge.idb('drafts');
94
+ import { BardiocError } from '@bardioc/app-sdk';
157
95
 
158
- await drafts.put('welcome', {
159
- title: 'Q2 rollout',
160
- summary: 'Publish SDK changes before updating the host workspace.',
161
- });
162
- const draft = await drafts.get<{ title: string; summary: string }>('welcome');
163
- const items = await drafts.query({ prefix: 'wel', limit: 20 });
164
- await drafts.delete('welcome');
96
+ try {
97
+ await bardioc.graph.get(id);
98
+ } catch (error) {
99
+ if (error instanceof BardiocError && error.code === 'not_found') return null;
100
+ throw error;
101
+ }
165
102
  ```
166
103
 
167
- Each handle is scoped by the host to the app's manifest `id`, so two apps can use the same `storeName` without colliding.
168
-
169
- ### Transport API
170
-
171
- The bridge provides namespaced transport APIs for graph database and OS operations.
104
+ Codes: `invalid`, `unauthenticated`, `forbidden`, `not_found`, `conflict`, `rate_limited`,
105
+ `unavailable`, `timeout`, `cancelled`, `protocol`, `internal`. HTTP failures carry `status` and the
106
+ response body as `details`.
172
107
 
173
- **Note:** For multiple graph/OS instances or contexts, the Host OS is responsible for routing requests. The SDK proxies all transport requests to the host via postMessage - one bridge = one iframe = one host connection.
108
+ ## Standalone development
174
109
 
175
- #### Graph API
176
-
177
- Access the graph database via `bridge.transport.graph.*`:
110
+ 1. Set `DEV_SECRET` and `API_BASE_URL` in `.env`.
111
+ 2. Install the dev host before rendering, then run `pnpm dev`:
178
112
 
179
113
  ```ts
180
- const sdk = useSdk();
181
-
182
- // Get single node
183
- const node = await sdk.transport.graph.get<GraphNodeRaw>('node-id');
184
-
185
- // Query with Lucene
186
- const people = await sdk.transport.graph.query<GraphNodeRaw>(
187
- 'ogit/_type:ogit/Person AND ogit/name:John*',
188
- { limit: 50, offset: 0, scopeId: 'instance-scope-id' }
189
- );
190
-
191
- // Gremlin traversal
192
- const edges = await sdk.transport.graph.gremlin(rootId, "outE('ogit/relates')");
193
-
194
- // Create node
195
- const newNode = await sdk.transport.graph.create('ogit/Person', {
196
- 'ogit/name': 'Jane Doe',
197
- 'ogit/email': 'jane@example.com',
198
- });
199
-
200
- // Update node
201
- await sdk.transport.graph.update('node-id', {
202
- 'ogit/name': 'Updated Name',
203
- });
114
+ import { installDevHost, isDevStandalone } from '@bardioc/app-sdk/dev';
204
115
 
205
- // Create edge
206
- await sdk.transport.graph.connect(fromId, toId, 'ogit/relates');
207
-
208
- // Delete node
209
- await sdk.transport.graph.delete('node-id');
210
-
211
- // Combined query: Elasticsearch picks the start vertices, Gremlin traverses from them
212
- const speeches = await sdk.transport.graph.combined(
213
- '+(ogit\\/_type: "ogit/Politics/AgendaItem")',
214
- "inE().outV().has('ogit/_type', 'ogit/Politics/Discussion')",
215
- { limit: 1000 }
216
- );
217
-
218
- // Time series
219
- const values = await sdk.transport.graph.timeseries.get('ts-id', {
220
- from: '2026-01-01',
221
- to: '2026-01-31',
222
- });
223
-
224
- // Several series in one request, averaged per timestamp
225
- const merged = await sdk.transport.graph.timeseries.get('ts-id', {
226
- from: '2026-01-01',
227
- to: '2026-01-31',
228
- withIds: ['ts-id-2', 'ts-id-3'],
229
- aggregate: 'avg',
230
- });
116
+ if (isDevStandalone()) installDevHost({ appId: 'my-app' });
231
117
  ```
232
118
 
233
- Available methods: `get`, `getMany`, `getByXid`, `query`, `gremlin`, `combined`, `create`, `update`, `delete`, `connect`, `history`, `batch.delete`, `timeseries.get`, `timeseries.add`, `timeseries.query`, `timeseries.history`, `content.set`, `content.get`.
234
-
235
- `combined` and multi-ID time series reads both return one flat result set: a combined query carries
236
- no marker for which start vertex a row came from (label and `select()` in the traversal when you need
237
- it), and time series entries carry only `timestamp` and `value` (read one ID per request when values
238
- must stay attributable).
239
-
240
- All graph request option types accept optional `scopeId` when a request must target a specific scope.
119
+ The dev host answers the same contract as the Bardioc host: BFF calls go through the dev-auth
120
+ proxy (the `bardiocDevAuth` Vite plugin, or `startDevAuthProxy` beside angular and nextjs dev
121
+ servers — pass its origin as `apiBaseUrl`), `idb` lives in this browser's IndexedDB, `ui` calls
122
+ are acknowledged, and `apps` answer `unavailable`.
241
123
 
242
- #### OS API
243
-
244
- Access OS features via `bridge.transport.os.*`:
124
+ ## Vite plugin
245
125
 
246
126
  ```ts
247
- const sdk = useSdk();
248
-
249
- // User profile
250
- const profile = await sdk.transport.os.profile.get();
251
- const avatar = await sdk.transport.os.profile.getAvatar();
252
- await sdk.transport.os.profile.setAvatar(imageBlob);
253
-
254
- // Organization
255
- const org = await sdk.transport.os.organization.getStructure();
256
- const unit = await sdk.transport.os.organization.createUnit({
257
- name: 'Engineering',
258
- parentId: 'parent-unit-id',
259
- });
127
+ // vite.config.ts
128
+ import { bardiocApp } from '@bardioc/app-sdk/vite';
129
+ import react from '@vitejs/plugin-react';
130
+ import { defineConfig } from 'vite';
260
131
 
261
- // Applications
262
- const apps = await sdk.transport.os.applications.list();
263
- const app = await sdk.transport.os.applications.get('app-id');
264
- await sdk.transport.os.applications.upload('app-id', zipBlob);
265
- await sdk.transport.os.request({
266
- path: '/custom/endpoint',
267
- method: 'GET',
268
- scopeId: 'instance-scope-id',
132
+ export default defineConfig({
133
+ plugins: [react(), bardiocApp({ appName: 'my-app', port: 3005 })],
269
134
  });
270
135
  ```
271
136
 
272
- Available namespaces:
137
+ Handles dev base path, port config, host session proxy routes, platform fonts, and manifest validation on build.
273
138
 
274
- - `os.profile.*` — `get`, `getAvatar`, `setAvatar`, `getInstances`
275
- - `os.organization.*` — `getStructure`, `createUnit`, `updateUnit`, `createMember`, `updateMember`, `deleteMember`, `inviteMember`
276
- - `os.applications.*` — `list`, `get`, `upload`, `download`, `getFiles`, `getFile`, `getConfigurations`
139
+ ### Platform fonts
277
140
 
278
- ### Error handling
141
+ The Bardioc platform guarantees a stable font endpoint wherever an app runs — like `/api/transport`, it is a public contract that will never be renamed or removed. Load it with one line in `index.html` and do **not** bundle font packages into your app:
279
142
 
280
- All transport methods throw structured errors:
143
+ ```html
144
+ <link rel="stylesheet" href="/fonts/bardioc-fonts.css" />
145
+ ```
281
146
 
282
- ```ts
283
- import {
284
- EntityNotFoundError,
285
- ValidationError,
286
- PermissionError,
287
- TimeoutError,
288
- NetworkError,
289
- SdkError,
290
- } from '@bardioc/app-sdk';
147
+ It provides `Nunito Sans Variable` (normal + italic) and `Geist Mono Variable` as variable fonts (latin subset), matching the `--font-nunito-sans` / `--font-geist-mono` theme variables that `@bardioc/ui` resolves by default.
291
148
 
292
- try {
293
- const node = await sdk.transport.graph.get('node-id');
294
- } catch (error) {
295
- if (error instanceof EntityNotFoundError) {
296
- console.log('Node not found:', error.context.id);
297
- } else if (error instanceof ValidationError) {
298
- console.log('Invalid data:', error.context?.field);
299
- } else if (error instanceof PermissionError) {
300
- console.log('Missing permission:', error.context.permission);
301
- } else if (error instanceof TimeoutError) {
302
- console.log('Request timed out:', error.context.operation);
303
- } else if (error instanceof NetworkError) {
304
- console.log('Network error:', error.statusCode, error.message);
305
- }
306
- }
307
- ```
149
+ - **Embedded in the OS** the URL resolves same-origin against the host, which serves it with immutable caching — one download shared by the host and every app.
150
+ - **Standalone dev** the `bardiocApp()` plugin serves the same files from assets shipped inside this package (dev server only — they are never added to your bundle). This applies to Vite-based apps; the angular and nextjs templates run their own dev servers, where the link is a harmless 404 standalone and resolves normally embedded in the OS.
308
151
 
309
- All errors extend `SdkError` with properties: `code`, `statusCode`, `context`, `message`.
152
+ New apps scaffolded with `create-bardioc-app` include the `<link>` already.
310
153
 
311
154
  ## App manifest
312
155
 
@@ -317,19 +160,10 @@ Every app must include `public/app-manifest.json`:
317
160
  "manifestVersion": 2,
318
161
  "id": "my-app",
319
162
  "name": "My App",
320
- "version": "1.0.0",
321
- "permissions": ["notify", "transport"]
163
+ "version": "1.0.0"
322
164
  }
323
165
  ```
324
166
 
325
- Available permissions:
326
-
327
- - `notify` — Show toast notifications via `bridge.notify()`
328
- - `storage` — Key-value storage via `bridge.storage.*`
329
- - `indexdb` — App-scoped IndexedDB via `bridge.idb()`
330
- - `kernel-proxy` — Message the OS service worker via `bridge.sendToKernel()`
331
- - `transport` — Access graph and OS APIs via `bridge.transport.*`
332
-
333
167
  The Vite plugin validates this automatically and fails the build when the manifest is missing or invalid.
334
168
 
335
169
  ### Window
@@ -342,7 +176,6 @@ Optionally control how the OS frames the app via a `window` block:
342
176
  "id": "my-app",
343
177
  "name": "My App",
344
178
  "version": "1.0.0",
345
- "permissions": ["notify"],
346
179
  "window": {
347
180
  "size": "md",
348
181
  "resizable": true
@@ -0,0 +1,30 @@
1
+ import type { BatchResult, CombinedQueryOptions, DeleteOptions, GetNodeOptions, GraphEdgeRaw, GraphNodeRaw, GremlinOptions, HistoryEntry, HistoryOptions, MutationOptions, QueryOptions, TimeseriesHistory, TimeseriesHistoryOptions, TimeseriesOptions, TimeseriesQueryOptions, TimeseriesValue, TransportScopeOptions } from '../types.js';
2
+ import { type BffRequester } from './request.js';
3
+ /** The Bardioc graph API, called through the host. */
4
+ export declare function graphApi(request: BffRequester): {
5
+ get: <T = GraphNodeRaw>(id: string, options?: GetNodeOptions) => Promise<T>;
6
+ getMany: <T = GraphNodeRaw>(ids: string[], options?: GetNodeOptions) => Promise<(T | undefined)[]>;
7
+ getByXid: <T = GraphNodeRaw>(xid: string, options?: GetNodeOptions) => Promise<T>;
8
+ query: <T = GraphNodeRaw>(lucene: string, options?: QueryOptions) => Promise<T[]>;
9
+ gremlin: <T = unknown>(rootId: string, query: string, options?: GremlinOptions) => Promise<T[]>;
10
+ combined: <T = unknown>(elasticsearchQuery: string, gremlinQuery: string, options?: CombinedQueryOptions) => Promise<T[]>;
11
+ create: <T = GraphNodeRaw>(type: string, data: Record<string, unknown>, options?: MutationOptions) => Promise<T>;
12
+ update: <T = GraphNodeRaw>(id: string, data: Record<string, unknown>, options?: MutationOptions) => Promise<T>;
13
+ delete: (id: string, options?: DeleteOptions) => Promise<void>;
14
+ connect: <T = GraphEdgeRaw>(from: string, to: string, type: string, options?: MutationOptions) => Promise<T>;
15
+ history: (id: string, options?: HistoryOptions) => Promise<HistoryEntry[]>;
16
+ batch: {
17
+ delete: (ids: string[], options?: DeleteOptions) => Promise<BatchResult>;
18
+ };
19
+ timeseries: {
20
+ get: (id: string, options?: TimeseriesOptions) => Promise<TimeseriesValue[]>;
21
+ add: (id: string, values: TimeseriesValue[], options?: TransportScopeOptions) => Promise<void>;
22
+ query: (options: TimeseriesQueryOptions) => Promise<TimeseriesValue[]>;
23
+ history: (id: string, timestamp: number, options?: TimeseriesHistoryOptions) => Promise<TimeseriesHistory>;
24
+ };
25
+ content: {
26
+ set: (id: string, data: Blob, contentType: string, options?: TransportScopeOptions) => Promise<string>;
27
+ get: (id: string, contentId: string, options?: TransportScopeOptions) => Promise<Blob>;
28
+ };
29
+ };
30
+ export type GraphApi = ReturnType<typeof graphApi>;
@@ -0,0 +1,139 @@
1
+ import { json, scoped, withQuery } from './request.js';
2
+ const GRAPH = '/bardioc/api/graph/7.4';
3
+ const node = (id, suffix = '') => `${GRAPH}/${encodeURIComponent(id)}${suffix}`;
4
+ const readFields = ({ fields, includeDeleted, listMeta }) => ({
5
+ fields,
6
+ includeDeleted,
7
+ listMeta,
8
+ });
9
+ const mutationQuery = ({ fullResponse, listMeta }) => ({ fullResponse, listMeta });
10
+ /** The Bardioc graph API, called through the host. */
11
+ export function graphApi(request) {
12
+ const get = (id, options = {}) => request({
13
+ path: withQuery(node(id), { ...readFields(options), vid: options.vid }),
14
+ ...scoped(options),
15
+ });
16
+ const remove = (id, options = {}) => request({
17
+ path: withQuery(node(id), { hard: options.hard }),
18
+ method: 'DELETE',
19
+ ...scoped(options),
20
+ });
21
+ return {
22
+ get,
23
+ getMany: (ids, options = {}) => request({
24
+ path: withQuery(`${GRAPH}/query/ids`, { query: ids.join(','), ...readFields(options) }),
25
+ ...scoped(options),
26
+ }),
27
+ getByXid: (xid, options = {}) => request({
28
+ path: withQuery(`${GRAPH}/xid/${encodeURIComponent(xid)}`, readFields(options)),
29
+ ...scoped(options),
30
+ }),
31
+ query: (lucene, options = {}) => request({
32
+ path: withQuery(`${GRAPH}/query/vertices`, {
33
+ query: lucene,
34
+ limit: options.limit,
35
+ offset: options.offset,
36
+ order: options.order,
37
+ ...readFields(options),
38
+ }),
39
+ ...scoped(options),
40
+ }),
41
+ gremlin: (rootId, query, options = {}) => request({
42
+ path: `${GRAPH}/query/gremlin`,
43
+ ...json({ root: rootId, query, ...readFields(options) }),
44
+ ...scoped(options),
45
+ }),
46
+ combined: (elasticsearchQuery, gremlinQuery, options = {}) => request({
47
+ path: `${GRAPH}/query/combined`,
48
+ ...json({
49
+ elasticsearch_query: elasticsearchQuery,
50
+ gremlin_query: gremlinQuery,
51
+ limit: options.limit,
52
+ }),
53
+ ...scoped(options),
54
+ }),
55
+ create: (type, data, options = {}) => request({
56
+ path: withQuery(`${GRAPH}/new/${encodeURIComponent(type)}`, mutationQuery(options)),
57
+ ...json(data),
58
+ ...scoped(options),
59
+ }),
60
+ update: (id, data, options = {}) => request({
61
+ path: withQuery(node(id), mutationQuery(options)),
62
+ ...json(data),
63
+ ...scoped(options),
64
+ }),
65
+ delete: remove,
66
+ connect: (from, to, type, options = {}) => request({
67
+ path: withQuery(`${GRAPH}/connect`, mutationQuery(options)),
68
+ ...json({ fromId: from, toId: to, edgeType: type }),
69
+ ...scoped(options),
70
+ }),
71
+ history: (id, options = {}) => request({
72
+ path: withQuery(node(id, '/history'), {
73
+ from: options.from,
74
+ to: options.to,
75
+ limit: options.limit,
76
+ offset: options.offset,
77
+ includeDeleted: options.includeDeleted,
78
+ }),
79
+ ...scoped(options),
80
+ }),
81
+ batch: {
82
+ delete: async (ids, options = {}) => {
83
+ const results = await Promise.allSettled(ids.map(id => remove(id, options)));
84
+ const result = { succeeded: [], failed: [] };
85
+ results.forEach((outcome, index) => {
86
+ const id = ids[index];
87
+ if (outcome.status === 'fulfilled')
88
+ result.succeeded.push(id);
89
+ else
90
+ result.failed.push({ id, error: String(outcome.reason?.message ?? outcome.reason) });
91
+ });
92
+ return result;
93
+ },
94
+ },
95
+ timeseries: {
96
+ get: (id, options = {}) => request({
97
+ path: withQuery(node(id, '/values'), {
98
+ from: options.from,
99
+ to: options.to,
100
+ limit: options.limit,
101
+ order: options.order,
102
+ with: options.withIds?.join(','),
103
+ aggregate: options.aggregate,
104
+ includeDeleted: options.includeDeleted,
105
+ }),
106
+ ...scoped(options),
107
+ }),
108
+ add: (id, values, options = {}) => request({ path: node(id, '/values'), ...json({ values }), ...scoped(options) }),
109
+ query: (options) => request({
110
+ path: withQuery(`${GRAPH}/query/values`, {
111
+ ids: options.ids?.join(','),
112
+ from: options.from,
113
+ to: options.to,
114
+ limit: options.limit,
115
+ order: options.order,
116
+ aggregate: options.aggregate,
117
+ }),
118
+ ...scoped(options),
119
+ }),
120
+ history: (id, timestamp, options = {}) => request({
121
+ path: withQuery(node(id, '/values/history'), {
122
+ timestamp,
123
+ includeDeleted: options.includeDeleted,
124
+ }),
125
+ ...scoped(options),
126
+ }),
127
+ },
128
+ content: {
129
+ set: async (id, data, contentType, options = {}) => (await request({
130
+ path: node(id, '/content'),
131
+ method: 'POST',
132
+ body: data,
133
+ contentType,
134
+ ...scoped(options),
135
+ })).contentId,
136
+ get: (id, contentId, options = {}) => request({ path: withQuery(node(id, '/content'), { contentId }), ...scoped(options) }),
137
+ },
138
+ };
139
+ }
@@ -0,0 +1,30 @@
1
+ import type { Application, Configuration, CreateMemberInput, CreateUnitInput, FileEntry, InstanceList, OrgMember, OrgStructure, OrgUnit, UpdateMemberInput, UpdateUnitInput, UserProfile } from '../types.js';
2
+ import { type BffRequester } from './request.js';
3
+ /** The Bardioc OS API, called through the host. */
4
+ export declare function osApi(request: BffRequester): {
5
+ profile: {
6
+ get: () => Promise<UserProfile>;
7
+ getAvatar: () => Promise<Blob>;
8
+ setAvatar: (image: Blob) => Promise<void>;
9
+ getInstances: () => Promise<InstanceList>;
10
+ };
11
+ organization: {
12
+ getStructure: () => Promise<OrgStructure>;
13
+ createUnit: (data: CreateUnitInput) => Promise<OrgUnit>;
14
+ updateUnit: (id: string, data: UpdateUnitInput) => Promise<OrgUnit>;
15
+ createMember: (data: CreateMemberInput) => Promise<OrgMember>;
16
+ updateMember: (id: string, data: UpdateMemberInput) => Promise<OrgMember>;
17
+ deleteMember: (id: string) => Promise<void>;
18
+ inviteMember: (id: string) => Promise<void>;
19
+ };
20
+ applications: {
21
+ list: () => Promise<Application[]>;
22
+ get: (id: string) => Promise<Application>;
23
+ upload: (id: string, zip: Blob) => Promise<void>;
24
+ download: (id: string) => Promise<Blob>;
25
+ getFiles: (id: string) => Promise<FileEntry[]>;
26
+ getFile: (id: string, path: string) => Promise<string>;
27
+ getConfigurations: (id: string) => Promise<Configuration[]>;
28
+ };
29
+ };
30
+ export type OsApi = ReturnType<typeof osApi>;