@scout9/app 1.0.0-alpha.0.1.9 → 1.0.0-alpha.0.1.91
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 +33 -0
- package/dist/{index-92deaa5f.cjs → exports-212ef6be.cjs} +46636 -4591
- package/dist/index.cjs +58 -15
- package/dist/{multipart-parser-090f08a9.cjs → multipart-parser-54a3ab5f.cjs} +13 -7
- package/dist/spirits-3b603262.cjs +1218 -0
- package/dist/spirits.cjs +9 -0
- package/dist/testing-tools.cjs +48 -0
- package/package.json +37 -8
- package/src/cli.js +162 -69
- package/src/core/config/agents.js +300 -7
- package/src/core/config/entities.js +58 -28
- package/src/core/config/index.js +37 -15
- package/src/core/config/project.js +160 -6
- package/src/core/config/workflow.js +13 -12
- package/src/core/data.js +27 -0
- package/src/core/index.js +386 -137
- package/src/core/sync.js +71 -0
- package/src/core/templates/Dockerfile +22 -0
- package/src/core/templates/app.js +453 -0
- package/src/core/templates/project-files.js +36 -0
- package/src/core/templates/template-package.json +13 -0
- package/src/exports.js +21 -17
- package/src/platform.js +189 -33
- package/src/public.d.ts.text +330 -0
- package/src/report.js +117 -0
- package/src/runtime/client/api.js +56 -159
- package/src/runtime/client/config.js +60 -11
- package/src/runtime/client/entity.js +19 -6
- package/src/runtime/client/index.js +5 -3
- package/src/runtime/client/message.js +13 -3
- package/src/runtime/client/platform.js +86 -0
- package/src/runtime/client/{agent.js → users.js} +35 -3
- package/src/runtime/client/utils.js +10 -9
- package/src/runtime/client/workflow.js +132 -9
- package/src/runtime/entry.js +2 -2
- package/src/testing-tools/dev.js +373 -0
- package/src/testing-tools/index.js +1 -0
- package/src/testing-tools/mocks.js +37 -5
- package/src/testing-tools/spirits.js +530 -0
- package/src/utils/audio-buffer.js +16 -0
- package/src/utils/audio-type.js +27 -0
- package/src/utils/configs/agents.js +68 -0
- package/src/utils/configs/entities.js +145 -0
- package/src/utils/configs/project.js +23 -0
- package/src/utils/configs/workflow.js +47 -0
- package/src/utils/file-type.js +569 -0
- package/src/utils/file.js +164 -0
- package/src/utils/glob.js +30 -0
- package/src/utils/image-buffer.js +23 -0
- package/src/utils/image-type.js +39 -0
- package/src/utils/index.js +1 -0
- package/src/utils/is-svg.js +37 -0
- package/src/utils/logger.js +111 -0
- package/src/utils/module.js +14 -25
- package/src/utils/project-templates.js +191 -0
- package/src/utils/project.js +387 -0
- package/src/utils/video-type.js +29 -0
- package/types/index.d.ts +7588 -206
- package/types/index.d.ts.map +97 -22
- package/dist/index-1b8d7dd2.cjs +0 -49555
- package/dist/index-2ccb115e.cjs +0 -49514
- package/dist/index-66b06a30.cjs +0 -49549
- package/dist/index-bc029a1d.cjs +0 -49528
- package/dist/index-d9a93523.cjs +0 -49527
- package/dist/multipart-parser-1508046a.cjs +0 -413
- package/dist/multipart-parser-7007403a.cjs +0 -413
- package/dist/multipart-parser-70c32c1d.cjs +0 -413
- package/dist/multipart-parser-71dec101.cjs +0 -413
- package/dist/multipart-parser-f15bf2e0.cjs +0 -414
- package/src/public.d.ts +0 -209
|
@@ -1,17 +1,171 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { requireProjectFile } from '../../utils/index.js';
|
|
3
3
|
import { globSync } from 'glob';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import fss from 'node:fs';
|
|
6
|
+
import fs from 'node:fs/promises';
|
|
7
|
+
import { writeFileToLocal } from '../../utils/file.js';
|
|
8
|
+
import { Configuration, Scout9Api } from '@scout9/admin';
|
|
9
|
+
import { projectTemplates } from '../../utils/project-templates.js';
|
|
10
|
+
import imageBuffer from '../../utils/image-buffer.js';
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object} input
|
|
15
|
+
* @param {string | Buffer} input.img
|
|
16
|
+
* @param {'icon' | 'logo'} [input.type]
|
|
17
|
+
* @returns {Promise<string>}
|
|
18
|
+
*/
|
|
19
|
+
async function writeImageToServer({img, type = 'icon', source}) {
|
|
20
|
+
const buffer = await imageBuffer(img, type === 'icon', source).then((res => res.buffer));
|
|
21
|
+
const scout9 = new Scout9Api(new Configuration({apiKey: process.env.SCOUT9_API_KEY}));
|
|
22
|
+
let url;
|
|
23
|
+
if (type === 'icon') {
|
|
24
|
+
const result = await scout9.organizationIcon(buffer).then(res => res.data);
|
|
25
|
+
url = result.url;
|
|
26
|
+
} else {
|
|
27
|
+
const result = await scout9.organizationLogo(buffer).then(res => res.data);
|
|
28
|
+
url = result.url;
|
|
29
|
+
}
|
|
30
|
+
if (!url) {
|
|
31
|
+
throw new Error(`Failed to upload agent image or no data returned: ${url}`);
|
|
32
|
+
}
|
|
33
|
+
return url;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Loads the users local package.json, if they provide a package-s9-test.json,
|
|
39
|
+
* it will load that instead (used for scout9 internal testing)
|
|
40
|
+
* @param {cwd?: string}
|
|
41
|
+
* @returns {Promise<{isTest: boolean, pkg: {name: string; version: string; dependencies: Record<string, string>}}>}
|
|
42
|
+
*/
|
|
43
|
+
export async function loadUserPackageJson({cwd = process.cwd()}) {
|
|
44
|
+
const packageJsonPath = path.resolve(cwd, './package.json');
|
|
45
|
+
const packageTestJsonPath = path.resolve(cwd, './package-s9-test.json');
|
|
46
|
+
const packageJsonUrl = pathToFileURL(packageJsonPath);
|
|
47
|
+
const packageTestJsonUrl = pathToFileURL(packageTestJsonPath);
|
|
48
|
+
const isTest = fss.existsSync(packageTestJsonUrl);
|
|
49
|
+
const targetPkgUrl = isTest ? packageTestJsonUrl : packageJsonUrl;
|
|
50
|
+
const pkg = JSON.parse(await fs.readFile(new URL(targetPkgUrl, import.meta.url), 'utf-8'));
|
|
51
|
+
return {
|
|
52
|
+
pkg,
|
|
53
|
+
isTest
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @returns {Promise<import('../../runtime/client/config.js').IScout9ProjectConfig>}
|
|
59
|
+
*/
|
|
60
|
+
export default async function loadProjectConfig({cwd = process.cwd(), deploying = false, src = 'src', cb = (message) => {}} = {}) {
|
|
61
|
+
// Grab the project tag name (from their package.json)
|
|
62
|
+
const {pkg} = await loadUserPackageJson({cwd});
|
|
63
|
+
const tag = `${pkg.name || 'scout9-app'}-v${pkg.version || '0.0.1'}`;
|
|
64
|
+
|
|
65
|
+
// Grab the project config file (from src/index.{ts,js})
|
|
66
|
+
const paths = globSync(`${src}/index.{ts,cjs,mjs,js}`, {cwd, absolute: true});
|
|
8
67
|
if (paths.length === 0) {
|
|
9
|
-
throw new Error(`Missing main project entry file ${
|
|
68
|
+
throw new Error(`Missing main project entry file ${src}/index.{js|ts|cjs|mjs}`);
|
|
10
69
|
} else if (paths.length > 1) {
|
|
11
|
-
throw new Error(`Multiple main project entry files found ${
|
|
70
|
+
throw new Error(`Multiple main project entry files found ${src}/index.{js|ts|cjs|mjs}`);
|
|
12
71
|
}
|
|
13
72
|
const [filePath] = paths;
|
|
14
73
|
const project = await requireProjectFile(filePath).then(mod => mod.default);
|
|
74
|
+
|
|
75
|
+
let serverDeployed = false;
|
|
76
|
+
|
|
77
|
+
if (project.organization.logo) {
|
|
78
|
+
if (typeof project.organization.logo === 'string') {
|
|
79
|
+
if (!project.organization.logo.startsWith('https://storage.googleapis.com')) {
|
|
80
|
+
if (deploying) {
|
|
81
|
+
project.organization.logo = await writeImageToServer({img: project.organization.logo, type: 'logo', source: filePath});
|
|
82
|
+
cb(`✅ Uploaded logo to server: ${project.organization.logo}`);
|
|
83
|
+
serverDeployed = true;
|
|
84
|
+
} else {
|
|
85
|
+
project.organization.logo = await writeFileToLocal({file: project.organization.logo, fileName: 'logo', source: filePath})
|
|
86
|
+
.then(({uri, isImage}) => {
|
|
87
|
+
if (!isImage) {
|
|
88
|
+
throw new Error(`Invalid image type: ${uri}`);
|
|
89
|
+
}
|
|
90
|
+
return uri;
|
|
91
|
+
});
|
|
92
|
+
cb(`✅ Wrote logo to local: ${project.organization.logo}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} else if (Buffer.isBuffer(project.organization.logo)) {
|
|
96
|
+
if (deploying) {
|
|
97
|
+
project.organization.logo = await writeImageToServer({img: project.organization.logo, type: 'logo', source: filePath});
|
|
98
|
+
cb(`✅ Uploaded logo to server: ${project.organization.logo}`);
|
|
99
|
+
serverDeployed = true;
|
|
100
|
+
} else {
|
|
101
|
+
project.organization.logo = await writeFileToLocal({file: project.organization.logo, fileName: 'logo', source: filePath})
|
|
102
|
+
.then(({uri, isImage}) => {
|
|
103
|
+
if (!isImage) {
|
|
104
|
+
throw new Error(`Invalid image type: ${uri}`);
|
|
105
|
+
}
|
|
106
|
+
return uri;
|
|
107
|
+
});
|
|
108
|
+
cb(`✅ Wrote logo to local: ${project.organization.logo}`);
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
throw new Error(`Invalid logo type: ${typeof project.organization.logo}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (project.organization.icon) {
|
|
116
|
+
if (typeof project.organization.icon === 'string') {
|
|
117
|
+
if (!project.organization.icon.startsWith('https://storage.googleapis.com')) {
|
|
118
|
+
if (deploying) {
|
|
119
|
+
project.organization.icon = await writeImageToServer({img: project.organization.icon, type: 'icon', source: filePath});
|
|
120
|
+
cb(`✅ Uploaded icon to server: ${project.organization.icon}`);
|
|
121
|
+
serverDeployed = true;
|
|
122
|
+
} else {
|
|
123
|
+
project.organization.icon = await writeFileToLocal({file: project.organization.icon, fileName: 'icon', source: filePath})
|
|
124
|
+
.then(({uri, isImage}) => {
|
|
125
|
+
if (!isImage) {
|
|
126
|
+
throw new Error(`Invalid image type: ${uri}`);
|
|
127
|
+
}
|
|
128
|
+
return uri;
|
|
129
|
+
});
|
|
130
|
+
cb(`✅ Wrote icon to local: ${project.organization.icon}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} else if (Buffer.isBuffer(project.organization.icon)) {
|
|
134
|
+
if (deploying) {
|
|
135
|
+
project.organization.icon = await writeImageToServer({img: project.organization.icon, type: 'icon', source: filePath});
|
|
136
|
+
cb(`✅ Uploaded icon to server: ${project.organization.icon}`);
|
|
137
|
+
serverDeployed = true;
|
|
138
|
+
} else {
|
|
139
|
+
project.organization.icon = await writeFileToLocal({file: project.organization.icon, fileName: 'icon', source: filePath})
|
|
140
|
+
.then(({uri, isImage}) => {
|
|
141
|
+
if (!isImage) {
|
|
142
|
+
throw new Error(`Invalid image type: ${uri}`);
|
|
143
|
+
}
|
|
144
|
+
return uri;
|
|
145
|
+
});
|
|
146
|
+
cb(`✅ Wrote icon to local: ${project.organization.icon}`);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
throw new Error(`Invalid icon type: ${typeof project.organization.icon}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
15
153
|
// @TODO validation type check with zod
|
|
16
|
-
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if (serverDeployed) {
|
|
157
|
+
cb(`Syncing ${filePath} with latest server changes`);
|
|
158
|
+
await fs.writeFile(filePath, projectTemplates.root({tag, ...project}, path.extname(filePath)));
|
|
159
|
+
// const update = await p.confirm({
|
|
160
|
+
// message: `Changes uploaded, sync local entities/agents file?`,
|
|
161
|
+
// initialValue: true
|
|
162
|
+
// });
|
|
163
|
+
// if (update) {
|
|
164
|
+
// }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
tag,
|
|
169
|
+
...project,
|
|
170
|
+
};
|
|
17
171
|
}
|
|
@@ -1,38 +1,39 @@
|
|
|
1
1
|
import { globSync } from 'glob';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
WorkflowConfigurationSchema,
|
|
5
|
-
WorkflowsConfigurationSchema
|
|
6
|
-
} from '../../runtime/index.js';
|
|
2
|
+
import { WorkflowConfigurationSchema, WorkflowsConfigurationSchema } from '../../runtime/index.js';
|
|
7
3
|
|
|
8
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @returns {Promise<import('../../runtime/client/workflow.js').IWorkflowsConfiguration>}
|
|
7
|
+
*/
|
|
9
8
|
export default async function loadWorkflowsConfig(
|
|
10
9
|
{
|
|
11
10
|
cwd = process.cwd(),
|
|
12
|
-
|
|
11
|
+
src = 'src',
|
|
12
|
+
cb = (message) => {}
|
|
13
13
|
} = {}
|
|
14
14
|
) {
|
|
15
|
-
|
|
16
|
-
const config = globSync(
|
|
15
|
+
// const config = globSync(path.resolve(cwd, `${src}/workflows/**/workflow.{ts,js}`), {cwd, absolute: true})
|
|
16
|
+
const config = globSync(`${src}/workflows/**/workflow.{ts,js}`, {cwd, absolute: true})
|
|
17
17
|
.map((path) => {
|
|
18
18
|
const segments = path.split('/');
|
|
19
|
-
const srcIndex = segments.findIndex((segment, index) => segment ===
|
|
20
|
-
const parents = segments.slice(srcIndex + 2, -1).reverse(); // +2 to skip "${
|
|
19
|
+
const srcIndex = segments.findIndex((segment, index) => segment === src && segments[index + 1] === 'workflows');
|
|
20
|
+
const parents = segments.slice(srcIndex + 2, -1).reverse(); // +2 to skip "${src}" and "workflows"
|
|
21
21
|
return {path, parents};
|
|
22
22
|
})
|
|
23
23
|
.filter(path => {
|
|
24
24
|
if (path.parents.length > 0) {
|
|
25
25
|
return true;
|
|
26
26
|
} else {
|
|
27
|
-
console.log(`WARNING: "${path}" Is not a valid entity path, must be contained in a named
|
|
27
|
+
console.log(`WARNING: "${path}" Is not a valid entity path, must be contained in a named src under workflows/`);
|
|
28
28
|
}
|
|
29
29
|
})
|
|
30
30
|
.map(({path, parents}) => {
|
|
31
31
|
|
|
32
32
|
// Validate project configuration
|
|
33
|
+
/** @type {import('../../runtime/client/workflow.js').IWorkflowConfiguration} */
|
|
33
34
|
const workflowConfig = {
|
|
34
35
|
entity: parents[0],
|
|
35
|
-
entities: parents,
|
|
36
|
+
entities: parents.reverse(),
|
|
36
37
|
}
|
|
37
38
|
WorkflowConfigurationSchema.parse(workflowConfig);
|
|
38
39
|
|
package/src/core/data.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
|
|
3
|
+
export async function platformApi(url, options = {}, retries = 0) {
|
|
4
|
+
if (retries > 3) {
|
|
5
|
+
throw new Error(`Request timed out, try again later`);
|
|
6
|
+
}
|
|
7
|
+
if (!process.env.SCOUT9_API_KEY) {
|
|
8
|
+
throw new Error('Missing required environment variable "SCOUT9_API_KEY"');
|
|
9
|
+
}
|
|
10
|
+
return fetch(url, {
|
|
11
|
+
method: 'GET',
|
|
12
|
+
...options,
|
|
13
|
+
headers: {
|
|
14
|
+
'Authorization': process.env.SCOUT9_API_KEY || '',
|
|
15
|
+
...(options.headers || {})
|
|
16
|
+
}
|
|
17
|
+
}).then((res) => {
|
|
18
|
+
if (res.status === 504) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
resolve(platformApi(url, options, retries + 1));
|
|
22
|
+
}, 3000);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return Promise.resolve(res);
|
|
26
|
+
});
|
|
27
|
+
}
|