@brantrusnak/openclaw-omadeus 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.
- package/README.md +107 -0
- package/api.ts +2 -0
- package/index.ts +14 -0
- package/openclaw.plugin.json +91 -0
- package/package.json +68 -0
- package/runtime-api.ts +37 -0
- package/setup-entry.ts +4 -0
- package/src/allowed-reaction-emojis.ts +22 -0
- package/src/api/auth.api.ts +189 -0
- package/src/api/message.api.ts +241 -0
- package/src/api/nugget.api.ts +148 -0
- package/src/auth.ts +33 -0
- package/src/channel.ts +817 -0
- package/src/config.ts +80 -0
- package/src/defaults.ts +2 -0
- package/src/inbound.ts +112 -0
- package/src/message-handler.ts +357 -0
- package/src/nugget-lookup.ts +196 -0
- package/src/onboarding.ts +434 -0
- package/src/outbound.ts +26 -0
- package/src/reply-dispatcher.ts +63 -0
- package/src/runtime.ts +7 -0
- package/src/setup-core.ts +54 -0
- package/src/setup-surface.ts +1 -0
- package/src/socket/dolphin.socket.ts +31 -0
- package/src/socket/jaguar.socket.ts +49 -0
- package/src/socket/socket.ts +207 -0
- package/src/store.ts +18 -0
- package/src/token.ts +120 -0
- package/src/types.ts +186 -0
- package/src/utils/http.util.ts +62 -0
- package/src/utils/jwt.util.ts +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# OpenClaw Omadeus Plugin
|
|
2
|
+
|
|
3
|
+
Omadeus channel plugin for [OpenClaw](https://www.npmjs.com/package/openclaw).
|
|
4
|
+
|
|
5
|
+
This plugin connects OpenClaw to Omadeus over WebSocket so OpenClaw can listen
|
|
6
|
+
for Omadeus messages and reply through the selected Omadeus channel.
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Node.js 22 or newer
|
|
11
|
+
- OpenClaw 2026.4.10 or newer
|
|
12
|
+
- An Omadeus account with access to the organization and channel you want
|
|
13
|
+
OpenClaw to use
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
Install OpenClaw first:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g openclaw
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Set up OpenClaw if you have not already:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
openclaw onboard
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then install this plugin with the OpenClaw plugin command:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
openclaw plugins install @brantrusnak/openclaw-omadeus
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You can confirm OpenClaw discovered the plugin with:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
openclaw plugins list
|
|
39
|
+
openclaw plugins inspect omadeus
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configure
|
|
43
|
+
|
|
44
|
+
After installing the plugin, run OpenClaw configuration and choose Omadeus when
|
|
45
|
+
prompted:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
openclaw configure
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The Omadeus setup flow asks for:
|
|
52
|
+
|
|
53
|
+
- Omadeus email and password
|
|
54
|
+
- Organization ID
|
|
55
|
+
- The Omadeus member/account to listen as
|
|
56
|
+
- The Omadeus channel to use for messages
|
|
57
|
+
|
|
58
|
+
The plugin also supports these environment variables:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
export OMADEUS_EMAIL="you@example.com"
|
|
62
|
+
export OMADEUS_PASSWORD="your-password"
|
|
63
|
+
export OMADEUS_ORGANIZATION_ID="123"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The default Omadeus endpoints are:
|
|
67
|
+
|
|
68
|
+
- CAS: `https://dev1-cas.rouztech.com`
|
|
69
|
+
- Maestro: `https://dev3-maestro.rouztech.com`
|
|
70
|
+
|
|
71
|
+
If your Omadeus deployment uses different endpoints, configure them through the
|
|
72
|
+
OpenClaw setup flow or in your OpenClaw config under `channels.omadeus`.
|
|
73
|
+
|
|
74
|
+
## Start OpenClaw
|
|
75
|
+
|
|
76
|
+
Once OpenClaw and the plugin are configured, start or restart the gateway:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
openclaw gateway
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Check channel health with:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
openclaw channels status --deep
|
|
86
|
+
openclaw plugins doctor
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Local Development
|
|
90
|
+
|
|
91
|
+
From this repository, you can link the local plugin into OpenClaw:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
openclaw plugins install . --link
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Before publishing, inspect the npm package contents:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm pack --dry-run
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Publish to npm:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm publish
|
|
107
|
+
```
|
package/api.ts
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import { omadeusPlugin } from "./src/channel.js";
|
|
3
|
+
import { setOmadeusRuntime } from "./src/runtime.js";
|
|
4
|
+
|
|
5
|
+
export { omadeusPlugin } from "./src/channel.js";
|
|
6
|
+
export { setOmadeusRuntime } from "./src/runtime.js";
|
|
7
|
+
|
|
8
|
+
export default defineChannelPluginEntry({
|
|
9
|
+
id: "omadeus",
|
|
10
|
+
name: "Omadeus",
|
|
11
|
+
description: "Omadeus project management channel plugin",
|
|
12
|
+
plugin: omadeusPlugin,
|
|
13
|
+
setRuntime: setOmadeusRuntime,
|
|
14
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "omadeus",
|
|
3
|
+
"channels": ["omadeus"],
|
|
4
|
+
"configSchema": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {
|
|
8
|
+
"enabled": { "type": "boolean" },
|
|
9
|
+
"casUrl": { "type": "string" },
|
|
10
|
+
"maestroUrl": { "type": "string" },
|
|
11
|
+
"email": { "type": "string" },
|
|
12
|
+
"password": { "type": "string" },
|
|
13
|
+
"organizationId": { "type": "number" },
|
|
14
|
+
"sessionToken": { "type": "string" },
|
|
15
|
+
"selectedMemberReferenceId": { "type": "number" },
|
|
16
|
+
"selectedChannelViewId": { "type": "number" },
|
|
17
|
+
"selectedChannelTitle": { "type": "string" },
|
|
18
|
+
"selectedChannelPrivateRoomId": { "type": "number" },
|
|
19
|
+
"selectedChannelPublicRoomId": { "type": "number" }
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"channelConfigs": {
|
|
23
|
+
"omadeus": {
|
|
24
|
+
"schema": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"properties": {
|
|
28
|
+
"enabled": { "type": "boolean" },
|
|
29
|
+
"casUrl": { "type": "string" },
|
|
30
|
+
"maestroUrl": { "type": "string" },
|
|
31
|
+
"email": { "type": "string" },
|
|
32
|
+
"password": { "type": "string" },
|
|
33
|
+
"organizationId": { "type": "number" },
|
|
34
|
+
"sessionToken": { "type": "string" },
|
|
35
|
+
"selectedMemberReferenceId": { "type": "number" },
|
|
36
|
+
"selectedChannelViewId": { "type": "number" },
|
|
37
|
+
"selectedChannelTitle": { "type": "string" },
|
|
38
|
+
"selectedChannelPrivateRoomId": { "type": "number" },
|
|
39
|
+
"selectedChannelPublicRoomId": { "type": "number" }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"uiHints": {
|
|
43
|
+
"casUrl": {
|
|
44
|
+
"label": "CAS URL",
|
|
45
|
+
"placeholder": "https://dev1-cas.rouztech.com"
|
|
46
|
+
},
|
|
47
|
+
"maestroUrl": {
|
|
48
|
+
"label": "Maestro URL",
|
|
49
|
+
"placeholder": "https://dev3-maestro.rouztech.com"
|
|
50
|
+
},
|
|
51
|
+
"email": {
|
|
52
|
+
"label": "Email"
|
|
53
|
+
},
|
|
54
|
+
"password": {
|
|
55
|
+
"label": "Password",
|
|
56
|
+
"sensitive": true
|
|
57
|
+
},
|
|
58
|
+
"organizationId": {
|
|
59
|
+
"label": "Organization ID"
|
|
60
|
+
},
|
|
61
|
+
"sessionToken": {
|
|
62
|
+
"label": "Session token",
|
|
63
|
+
"sensitive": true,
|
|
64
|
+
"advanced": true
|
|
65
|
+
},
|
|
66
|
+
"selectedMemberReferenceId": {
|
|
67
|
+
"label": "Selected member reference ID",
|
|
68
|
+
"advanced": true
|
|
69
|
+
},
|
|
70
|
+
"selectedChannelViewId": {
|
|
71
|
+
"label": "Selected channel view ID",
|
|
72
|
+
"advanced": true
|
|
73
|
+
},
|
|
74
|
+
"selectedChannelTitle": {
|
|
75
|
+
"label": "Selected channel title",
|
|
76
|
+
"advanced": true
|
|
77
|
+
},
|
|
78
|
+
"selectedChannelPrivateRoomId": {
|
|
79
|
+
"label": "Selected private room ID",
|
|
80
|
+
"advanced": true
|
|
81
|
+
},
|
|
82
|
+
"selectedChannelPublicRoomId": {
|
|
83
|
+
"label": "Selected public room ID",
|
|
84
|
+
"advanced": true
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"label": "Omadeus",
|
|
88
|
+
"description": "Omadeus project management channel configuration"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brantrusnak/openclaw-omadeus",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "OpenClaw Omadeus project management channel plugin",
|
|
6
|
+
"homepage": "https://github.com/brantrusnak/openclaw-omadeus-plugin#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/brantrusnak/openclaw-omadeus-plugin/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/brantrusnak/openclaw-omadeus-plugin.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"author": "Brant Rusnak",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./index.ts",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"prepack": "node ./scripts/verify-npm-files.mjs"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"ws": "^8.20.0"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"index.ts",
|
|
27
|
+
"setup-entry.ts",
|
|
28
|
+
"api.ts",
|
|
29
|
+
"runtime-api.ts",
|
|
30
|
+
"openclaw.plugin.json",
|
|
31
|
+
"src",
|
|
32
|
+
"!**/*.test.ts"
|
|
33
|
+
],
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"openclaw": ">=2026.4.10",
|
|
36
|
+
"vitest": "^4.1.5"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"openclaw": ">=2026.4.10"
|
|
40
|
+
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"openclaw": {
|
|
43
|
+
"optional": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"openclaw": {
|
|
50
|
+
"extensions": [
|
|
51
|
+
"./index.ts"
|
|
52
|
+
],
|
|
53
|
+
"setupEntry": "./setup-entry.ts",
|
|
54
|
+
"channel": {
|
|
55
|
+
"id": "omadeus",
|
|
56
|
+
"label": "Omadeus",
|
|
57
|
+
"selectionLabel": "Omadeus (WebSocket)",
|
|
58
|
+
"docsPath": "/channels/omadeus",
|
|
59
|
+
"docsLabel": "omadeus",
|
|
60
|
+
"blurb": "Omadeus project management — tasks, chat rooms, and sprints.",
|
|
61
|
+
"order": 70
|
|
62
|
+
},
|
|
63
|
+
"install": {
|
|
64
|
+
"localPath": ".",
|
|
65
|
+
"defaultChoice": "local"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
package/runtime-api.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/core";
|
|
2
|
+
export type {
|
|
3
|
+
ChannelPlugin,
|
|
4
|
+
OpenClawConfig,
|
|
5
|
+
PluginRuntime,
|
|
6
|
+
} from "openclaw/plugin-sdk/core";
|
|
7
|
+
export {
|
|
8
|
+
type ChannelStatusIssue,
|
|
9
|
+
createReplyPrefixContext,
|
|
10
|
+
} from "openclaw/plugin-sdk/channel-runtime";
|
|
11
|
+
export { logInboundDrop } from "openclaw/plugin-sdk/channel-inbound";
|
|
12
|
+
export { resolveControlCommandGate } from "openclaw/plugin-sdk/command-auth";
|
|
13
|
+
export { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
14
|
+
export {
|
|
15
|
+
readStoreAllowFromForDmPolicy,
|
|
16
|
+
resolveDmGroupAccessWithLists,
|
|
17
|
+
} from "openclaw/plugin-sdk/channel-policy";
|
|
18
|
+
export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
|
|
19
|
+
export type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
|
|
20
|
+
export {
|
|
21
|
+
addWildcardAllowFrom,
|
|
22
|
+
formatDocsLink,
|
|
23
|
+
mergeAllowFromEntries,
|
|
24
|
+
} from "openclaw/plugin-sdk/setup";
|
|
25
|
+
export type {
|
|
26
|
+
ChannelSetupDmPolicy,
|
|
27
|
+
ChannelSetupWizard,
|
|
28
|
+
DmPolicy,
|
|
29
|
+
WizardPrompter,
|
|
30
|
+
} from "openclaw/plugin-sdk/setup";
|
|
31
|
+
|
|
32
|
+
export function missingTargetError(provider: string, hint?: string): Error {
|
|
33
|
+
const normalizedHint = hint?.trim();
|
|
34
|
+
return new Error(
|
|
35
|
+
`Delivering to ${provider} requires target${normalizedHint ? ` ${normalizedHint}` : ""}`,
|
|
36
|
+
);
|
|
37
|
+
}
|
package/setup-entry.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omadeus only accepts these exact reaction strings; any other value is ignored (no API call).
|
|
3
|
+
*/
|
|
4
|
+
export const ALLOWED_OMADEUS_REACTION_EMOJI_LIST = [
|
|
5
|
+
"👍",
|
|
6
|
+
"👎",
|
|
7
|
+
"❤️",
|
|
8
|
+
"😂",
|
|
9
|
+
"😮",
|
|
10
|
+
"😢",
|
|
11
|
+
"🙏",
|
|
12
|
+
] as const;
|
|
13
|
+
|
|
14
|
+
const ALLOWED = new Set<string>(ALLOWED_OMADEUS_REACTION_EMOJI_LIST);
|
|
15
|
+
|
|
16
|
+
export function isAllowedOmadeusReactionEmoji(raw: string): boolean {
|
|
17
|
+
const trimmed = raw.trim();
|
|
18
|
+
if (!trimmed) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return ALLOWED.has(trimmed);
|
|
22
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { getCasSession, setCasSession } from "../store.js";
|
|
2
|
+
import type {
|
|
3
|
+
CasAuthorizationCodeResponse,
|
|
4
|
+
OmadeusChannelView,
|
|
5
|
+
OmadeusOrganizationMember,
|
|
6
|
+
OmadeusOrganization,
|
|
7
|
+
OmadeusSessionTokenResponse,
|
|
8
|
+
} from "../types.js";
|
|
9
|
+
|
|
10
|
+
const CAS_APPLICATION_ID = 1;
|
|
11
|
+
const CAS_SCOPES = "title,email,avatar,firstName,lastName,birth,phone,countryCode";
|
|
12
|
+
|
|
13
|
+
export async function createCasToken(params: {
|
|
14
|
+
casUrl: string;
|
|
15
|
+
email: string;
|
|
16
|
+
password: string;
|
|
17
|
+
}): Promise<{ token: string; refreshCookie: string }> {
|
|
18
|
+
const { casUrl, email, password } = params;
|
|
19
|
+
const url = `${casUrl}/apiv1/tokens`;
|
|
20
|
+
const jsonBody = JSON.stringify({ email, password });
|
|
21
|
+
const res = await fetch(url, {
|
|
22
|
+
method: "CREATE",
|
|
23
|
+
headers: {
|
|
24
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
25
|
+
"Content-Length": String(jsonBody.length),
|
|
26
|
+
},
|
|
27
|
+
body: jsonBody,
|
|
28
|
+
});
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
const text = await res.text().catch(() => "");
|
|
31
|
+
throw new Error(`CAS token request failed (${res.status}): ${text}`);
|
|
32
|
+
}
|
|
33
|
+
const body = (await res.json()) as { token: string };
|
|
34
|
+
const refreshCookie = res.headers.get("set-cookie") ?? "";
|
|
35
|
+
|
|
36
|
+
setCasSession({ token: body.token, refreshCookie });
|
|
37
|
+
|
|
38
|
+
return { token: body.token, refreshCookie };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function getMe(params: {
|
|
42
|
+
casUrl: string;
|
|
43
|
+
casToken: string;
|
|
44
|
+
refreshCookie?: string;
|
|
45
|
+
}): Promise<{ email: string }> {
|
|
46
|
+
const { casUrl, casToken, refreshCookie } = params;
|
|
47
|
+
const url = `${casUrl}/apiv1/members/me`;
|
|
48
|
+
const res = await fetch(url, {
|
|
49
|
+
method: "GET",
|
|
50
|
+
headers: {
|
|
51
|
+
Authorization: `Bearer ${casToken}`,
|
|
52
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
53
|
+
...(refreshCookie ? { Cookie: refreshCookie } : {}),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
const text = await res.text().catch(() => "");
|
|
58
|
+
throw new Error(`CAS get member failed (${res.status}): ${text}`);
|
|
59
|
+
}
|
|
60
|
+
return (await res.json()) as { email: string };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function createAuthorizationCode(params: {
|
|
64
|
+
casUrl: string;
|
|
65
|
+
token: string;
|
|
66
|
+
email: string;
|
|
67
|
+
redirectUri?: string;
|
|
68
|
+
}): Promise<string> {
|
|
69
|
+
const { casUrl, token, email, redirectUri } = params;
|
|
70
|
+
const casSession = getCasSession();
|
|
71
|
+
const qs = new URLSearchParams({
|
|
72
|
+
applicationId: String(CAS_APPLICATION_ID),
|
|
73
|
+
scopes: CAS_SCOPES,
|
|
74
|
+
state: email,
|
|
75
|
+
redirectUri: redirectUri ?? "",
|
|
76
|
+
});
|
|
77
|
+
if (redirectUri) qs.set("redirectUri", redirectUri);
|
|
78
|
+
const url = `${casUrl}/apiv1/authorizationcodes?${qs}`;
|
|
79
|
+
const body = "";
|
|
80
|
+
const headers: Record<string, string> = {
|
|
81
|
+
Authorization: `Bearer ${token}`,
|
|
82
|
+
...(casSession?.refreshCookie ? { Cookie: casSession.refreshCookie } : {}),
|
|
83
|
+
};
|
|
84
|
+
const res = await fetch(url, {
|
|
85
|
+
method: "CREATE",
|
|
86
|
+
body,
|
|
87
|
+
headers,
|
|
88
|
+
});
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
const text = await res.text().catch(() => "");
|
|
91
|
+
throw new Error(`CAS authorization code request failed (${res.status}): ${text}`);
|
|
92
|
+
}
|
|
93
|
+
const jsonResponse = (await res.json()) as CasAuthorizationCodeResponse;
|
|
94
|
+
const code = jsonResponse.authorizationCode ?? jsonResponse.code;
|
|
95
|
+
if (!code) {
|
|
96
|
+
throw new Error("CAS authorization code response missing code");
|
|
97
|
+
}
|
|
98
|
+
return code;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function obtainSessionToken(params: {
|
|
102
|
+
maestroUrl: string;
|
|
103
|
+
authorizationCode: string;
|
|
104
|
+
organizationId: number;
|
|
105
|
+
}): Promise<string> {
|
|
106
|
+
const { maestroUrl, authorizationCode, organizationId } = params;
|
|
107
|
+
const url = `${maestroUrl}/dolphin/apiv1/oauth2/tokens`;
|
|
108
|
+
const res = await fetch(url, {
|
|
109
|
+
method: "OBTAIN",
|
|
110
|
+
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
111
|
+
body: JSON.stringify({ authorizationCode, organizationId }),
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
const text = await res.text().catch(() => "");
|
|
115
|
+
throw new Error(`Omadeus session token request failed (${res.status}): ${text}`);
|
|
116
|
+
}
|
|
117
|
+
const body = (await res.json()) as OmadeusSessionTokenResponse;
|
|
118
|
+
if (!body.token) {
|
|
119
|
+
throw new Error("Omadeus session token response missing token");
|
|
120
|
+
}
|
|
121
|
+
return body.token;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function listOrganizations(params: {
|
|
125
|
+
maestroUrl: string;
|
|
126
|
+
email: string;
|
|
127
|
+
}): Promise<OmadeusOrganization[]> {
|
|
128
|
+
const { maestroUrl, email } = params;
|
|
129
|
+
const url = `${maestroUrl}/dolphin/apiv1/organizations`;
|
|
130
|
+
const res = await fetch(url, {
|
|
131
|
+
method: "LIST",
|
|
132
|
+
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
133
|
+
body: JSON.stringify({ email }),
|
|
134
|
+
});
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
const text = await res.text().catch(() => "");
|
|
137
|
+
throw new Error(`Omadeus list organizations failed (${res.status}): ${text}`);
|
|
138
|
+
}
|
|
139
|
+
return (await res.json()) as OmadeusOrganization[];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function listMemberChannelViews(params: {
|
|
143
|
+
maestroUrl: string;
|
|
144
|
+
sessionToken: string;
|
|
145
|
+
memberReferenceId: number;
|
|
146
|
+
skip?: number;
|
|
147
|
+
take?: number;
|
|
148
|
+
}): Promise<OmadeusChannelView[]> {
|
|
149
|
+
const { maestroUrl, sessionToken, memberReferenceId, skip = 0, take = 100 } = params;
|
|
150
|
+
const qs = new URLSearchParams({
|
|
151
|
+
skip: String(skip),
|
|
152
|
+
take: String(take),
|
|
153
|
+
sort: "-recentMessageAt",
|
|
154
|
+
});
|
|
155
|
+
const url = `${maestroUrl}/jaguar/apiv1/members/${memberReferenceId}/channelviews?${qs.toString()}`;
|
|
156
|
+
const res = await fetch(url, {
|
|
157
|
+
method: "LIST",
|
|
158
|
+
headers: {
|
|
159
|
+
Authorization: `Bearer ${sessionToken}`,
|
|
160
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
if (!res.ok) {
|
|
164
|
+
const text = await res.text().catch(() => "");
|
|
165
|
+
throw new Error(`Omadeus list channel views failed (${res.status}): ${text}`);
|
|
166
|
+
}
|
|
167
|
+
return (await res.json()) as OmadeusChannelView[];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function listOrganizationMembers(params: {
|
|
171
|
+
maestroUrl: string;
|
|
172
|
+
sessionToken: string;
|
|
173
|
+
organizationId: number;
|
|
174
|
+
}): Promise<OmadeusOrganizationMember[]> {
|
|
175
|
+
const { maestroUrl, sessionToken, organizationId } = params;
|
|
176
|
+
const url = `${maestroUrl}/dolphin/apiv1/organizations/${organizationId}/members`;
|
|
177
|
+
const res = await fetch(url, {
|
|
178
|
+
method: "LIST",
|
|
179
|
+
headers: {
|
|
180
|
+
Authorization: `Bearer ${sessionToken}`,
|
|
181
|
+
"Content-Type": "application/json;charset=UTF-8",
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
if (!res.ok) {
|
|
185
|
+
const text = await res.text().catch(() => "");
|
|
186
|
+
throw new Error(`Omadeus list organization members failed (${res.status}): ${text}`);
|
|
187
|
+
}
|
|
188
|
+
return (await res.json()) as OmadeusOrganizationMember[];
|
|
189
|
+
}
|