@microtronics/studio-cli 0.60.0 → 0.62.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.
@@ -1,291 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MyDatanetClient = exports.RunExitCode = exports.HttpMethod = void 0;
4
- exports.generateDevApmId = generateDevApmId;
5
- exports.buildDevelopmentInstallInfo = buildDevelopmentInstallInfo;
6
- const manifest_1 = require("./manifest");
7
- const apm_1 = require("./package/apm");
8
- const uuid_1 = require("uuid");
9
- // Used to generate reproducible apmids
10
- const UUID_NAMESPACE = 'b4baec47-0ba4-4e37-b237-8f9cde42b8dd';
11
- /**
12
- * HTTP methods supported by the myDatanet API
13
- */
14
- var HttpMethod;
15
- (function (HttpMethod) {
16
- HttpMethod["Get"] = "GET";
17
- HttpMethod["Post"] = "POST";
18
- HttpMethod["Put"] = "PUT";
19
- HttpMethod["Delete"] = "DELETE";
20
- })(HttpMethod || (exports.HttpMethod = HttpMethod = {}));
21
- /**
22
- * Exit codes for the run command
23
- */
24
- var RunExitCode;
25
- (function (RunExitCode) {
26
- RunExitCode[RunExitCode["Success"] = 0] = "Success";
27
- RunExitCode[RunExitCode["BuildFailed"] = 1] = "BuildFailed";
28
- RunExitCode[RunExitCode["DeviceNotFound"] = 2] = "DeviceNotFound";
29
- RunExitCode[RunExitCode["UsbUploadFailed"] = 3] = "UsbUploadFailed";
30
- RunExitCode[RunExitCode["AuthenticationFailed"] = 4] = "AuthenticationFailed";
31
- RunExitCode[RunExitCode["DevTagUploadFailed"] = 5] = "DevTagUploadFailed";
32
- RunExitCode[RunExitCode["SiteCreationFailed"] = 6] = "SiteCreationFailed";
33
- })(RunExitCode || (exports.RunExitCode = RunExitCode = {}));
34
- /**
35
- * MyDatanet API client for CLI and extension operations
36
- */
37
- class MyDatanetClient {
38
- domain;
39
- auth;
40
- logger;
41
- userInfo = null;
42
- constructor(serverUrlOrOptions, apiTokenOrLogger, loggerOrUndefined) {
43
- if (typeof serverUrlOrOptions === 'object') {
44
- // New options-based constructor
45
- const { serverUrl, apiToken, authHeader, logger } = serverUrlOrOptions;
46
- this.domain = this.normalizeServerUrl(serverUrl);
47
- this.auth = authHeader || (apiToken ? `Bearer ${apiToken}` : '');
48
- this.logger = logger;
49
- }
50
- else {
51
- // Legacy constructor for backward compatibility
52
- this.domain = this.normalizeServerUrl(serverUrlOrOptions);
53
- if (typeof apiTokenOrLogger === 'string') {
54
- this.auth = `Bearer ${apiTokenOrLogger}`;
55
- this.logger = loggerOrUndefined;
56
- }
57
- else {
58
- this.auth = '';
59
- this.logger = apiTokenOrLogger;
60
- }
61
- }
62
- }
63
- /**
64
- * Set or update the authentication header
65
- */
66
- setAuth(authHeader) {
67
- this.auth = authHeader;
68
- }
69
- /**
70
- * Get the current domain
71
- */
72
- getDomain() {
73
- return this.domain;
74
- }
75
- /**
76
- * Normalize server URL to ensure https:// prefix
77
- */
78
- normalizeServerUrl(url) {
79
- if (!url.startsWith('http://') && !url.startsWith('https://')) {
80
- return `https://${url}`;
81
- }
82
- return url;
83
- }
84
- /**
85
- * Remove protocol from domain for display purposes
86
- */
87
- trimDomain(domain) {
88
- return domain.replace(/(^\w+:|^)\/\//, '');
89
- }
90
- /**
91
- * Make an authenticated JSON request to the myDatanet API
92
- */
93
- async fetchJSON(method, path, body) {
94
- const url = `${this.domain}${path}`;
95
- const headers = {
96
- Authorization: this.auth
97
- };
98
- const options = {
99
- method,
100
- headers
101
- };
102
- if (body) {
103
- if (body instanceof FormData) {
104
- options.body = body;
105
- }
106
- else {
107
- headers['Content-Type'] = 'application/json';
108
- options.body = JSON.stringify(body);
109
- }
110
- }
111
- const response = await fetch(url, options);
112
- if (!response.ok) {
113
- const errorText = await response.text().catch(() => 'Unknown error');
114
- throw new Error(`HTTP ${response.status}: ${errorText}`);
115
- }
116
- return response.json();
117
- }
118
- /**
119
- * Authenticate and get user information
120
- */
121
- async authenticate() {
122
- this.logger?.info(`Authenticating with ${this.trimDomain(this.domain)}...`);
123
- try {
124
- const { user, customers } = await this.fetchJSON(HttpMethod.Get, '/api/1/me');
125
- this.userInfo = {
126
- name: user.name,
127
- email: user.email,
128
- group: user.group,
129
- customers: customers
130
- };
131
- this.logger?.info(`Authenticated as ${this.userInfo.name}`);
132
- return this.userInfo;
133
- }
134
- catch (error) {
135
- throw new Error(`Authentication failed: ${error instanceof Error ? error.message : String(error)}`);
136
- }
137
- }
138
- /**
139
- * Get the current user info (must call authenticate first)
140
- */
141
- getUserInfo() {
142
- return this.userInfo;
143
- }
144
- /**
145
- * Upload a development APM tag to the app-center
146
- */
147
- async uploadDevTag(apmId, apmBuffer) {
148
- this.logger?.info(`Uploading development tag ${apmId}...`);
149
- const { applid } = await this.fetchJSON(HttpMethod.Post, `/api/1/app-center/__dev/${apmId}`, apmBuffer);
150
- this.logger?.info(`Development tag uploaded, application ID: ${applid}`);
151
- return applid;
152
- }
153
- /**
154
- * Get customer information by UID or name
155
- */
156
- async getCustomer(customerIdOrUid) {
157
- const { _uid, name } = await this.fetchJSON(HttpMethod.Get, `/api/1/customers/${customerIdOrUid}`);
158
- return { _uid, name };
159
- }
160
- /**
161
- * Get all customers accessible by the current user
162
- */
163
- async getCustomers() {
164
- return this.fetchJSON(HttpMethod.Get, '/api/1/customers');
165
- }
166
- /**
167
- * Get device site information
168
- */
169
- async getDeviceSite(serialNumber) {
170
- try {
171
- return await this.fetchJSON(HttpMethod.Get, `/api/1/devices/${serialNumber}/site`);
172
- }
173
- catch {
174
- return null;
175
- }
176
- }
177
- /**
178
- * Get device information
179
- */
180
- async getDevice(serialNumber) {
181
- try {
182
- return await this.fetchJSON(HttpMethod.Get, `/api/1/devices/${serialNumber}`);
183
- }
184
- catch {
185
- return null;
186
- }
187
- }
188
- /**
189
- * Get or create a site by name within a customer
190
- */
191
- async getSite(customerUid, siteName) {
192
- try {
193
- return await this.fetchJSON(HttpMethod.Get, `/api/1/customers/${customerUid}/sites/${siteName}`);
194
- }
195
- catch {
196
- return null;
197
- }
198
- }
199
- /**
200
- * Create a development site
201
- */
202
- async createDevelopmentSite(customerUid, installInfo, registrationCode) {
203
- this.logger?.info(`Creating development site "${installInfo.name}"...`);
204
- // Check if device is already attached to a site
205
- if (installInfo.serialNumber) {
206
- const existingSite = await this.getSite(customerUid, installInfo.name.toLowerCase());
207
- if (existingSite) {
208
- // Try to attach device to existing site
209
- try {
210
- await this.fetchJSON(HttpMethod.Post, `/api/1/customers/${customerUid}/sites/${existingSite._uid}/cn-attach-device`, {
211
- device_id: installInfo.serialNumber,
212
- allow_overwrite: true,
213
- detach_from_old_site: true,
214
- acquire: true,
215
- create: true
216
- });
217
- this.logger?.info(`Device attached to existing site ${existingSite._uid}`);
218
- return existingSite._uid;
219
- }
220
- catch (error) {
221
- // 304 means device is already attached - that's OK
222
- if (error.message && !error.message.includes('304')) {
223
- this.logger?.warn(`Could not attach device to existing site: ${error.message}`);
224
- }
225
- else {
226
- return existingSite._uid;
227
- }
228
- }
229
- }
230
- }
231
- // Create new site
232
- const { _uid } = await this.fetchJSON(HttpMethod.Post, `/api/1/customers/${customerUid}/sites`, {
233
- name: installInfo.name,
234
- create: true,
235
- force: true,
236
- note: 'This is a Studio development site',
237
- applid: installInfo.applicationId,
238
- device_id: installInfo.serialNumber,
239
- reg_code: registrationCode,
240
- servicetariff: '0000000000000000',
241
- servicetariff_indiv_cost: 0
242
- });
243
- this.logger?.info(`Development site created: ${_uid}`);
244
- return _uid;
245
- }
246
- /**
247
- * Update site name
248
- */
249
- async updateSiteName(siteUid, name) {
250
- try {
251
- await this.fetchJSON(HttpMethod.Put, `/api/1/sites/${siteUid}`, { name });
252
- }
253
- catch {
254
- // Ignore update failures
255
- }
256
- }
257
- }
258
- exports.MyDatanetClient = MyDatanetClient;
259
- /**
260
- * Generate a development APM ID based on a reference string
261
- */
262
- function generateDevApmId(developmentReference) {
263
- return (0, uuid_1.v5)(developmentReference, UUID_NAMESPACE);
264
- }
265
- /**
266
- * Build development installation info from manifest and options
267
- */
268
- async function buildDevelopmentInstallInfo(cwd, fs, logger, serialNumber, userName, customerUid, customSiteName) {
269
- const manifest = await manifest_1.Manifest.read(cwd, fs);
270
- const currentUserId = userName.replaceAll(' ', '_').replace(/[^a-zA-Z0-9-]+/g, '');
271
- const appName = manifest.name.replaceAll(' ', '_').replace(/[^a-zA-Z0-9-]+/g, '');
272
- const hasDlo = await manifest_1.Manifest.isApmPartEnabled(cwd, fs, apm_1.APM.Part.dlo, manifest);
273
- const useDeviceSerial = hasDlo && serialNumber;
274
- const siteName = useDeviceSerial ? serialNumber.toUpperCase() : `${appName}_${currentUserId}`;
275
- const developmentReference = useDeviceSerial ? serialNumber : siteName;
276
- let realSiteName = customSiteName || siteName;
277
- if (realSiteName.length > 50) {
278
- logger.warn(`Site name "${realSiteName}" is too long. Truncating to 50 characters.`);
279
- realSiteName = realSiteName.substring(0, 50);
280
- }
281
- return {
282
- apmId: generateDevApmId(developmentReference),
283
- applicationId: null,
284
- name: realSiteName,
285
- version: 1,
286
- serialNumber: hasDlo ? serialNumber : undefined,
287
- siteUid: null,
288
- customerUid: customerUid
289
- };
290
- }
291
- //# sourceMappingURL=myDatanetClient.js.map
@@ -1,294 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.APM = void 0;
4
- const vscode_uri_1 = require("vscode-uri");
5
- const manifest_1 = require("../manifest");
6
- const defaultFiles_1 = require("../defaultFiles");
7
- const helper_1 = require("../helper");
8
- var bufferToBase64 = helper_1.Helper.bufferToBase64;
9
- const package_1 = require("./package");
10
- const registryAPI_1 = require("../registryAPI");
11
- var APM;
12
- (function (APM) {
13
- let TagPhase;
14
- (function (TagPhase) {
15
- TagPhase["alpha"] = "alpha";
16
- TagPhase["beta"] = "beta";
17
- TagPhase["rc"] = "rc";
18
- TagPhase["release"] = "release";
19
- TagPhase["stage"] = "stage";
20
- TagPhase["passive"] = "passive";
21
- TagPhase["withdrawn"] = "withdrawn";
22
- })(TagPhase = APM.TagPhase || (APM.TagPhase = {}));
23
- /**
24
- * The APM parts that are predefined
25
- */
26
- let Part;
27
- (function (Part) {
28
- Part["dde"] = "dde";
29
- Part["dlo"] = "dlo";
30
- Part["pov"] = "pov";
31
- Part["blo"] = "blo";
32
- Part["dfiles"] = "dfiles";
33
- })(Part = APM.Part || (APM.Part = {}));
34
- function createBaseTagHeader(manifest) {
35
- const { description, name, pov, engines, blo, publisher, type } = manifest;
36
- const projectType = type || manifest_1.Manifest.ProjectTypes.app;
37
- const tagHeader = {
38
- name: name,
39
- abstract: description,
40
- author: publisher || '',
41
- pov_location: manifest_1.Manifest.PovLocation.embedded,
42
- pov_details_lowlevel: false,
43
- required_be: engines?.backend,
44
- required_hwfw: engines?.hwfw?.join(';'),
45
- required_productcode: engines?.productId?.join(';'),
46
- blo_level: blo?.accessLevel || manifest_1.Manifest.BloAccessLevel.restricted,
47
- pip_id: ''
48
- };
49
- if (pov && pov.details) {
50
- tagHeader.pov_location = manifest_1.Manifest.PovLocation.pure;
51
- tagHeader.pov_details_lowlevel = !!pov.details.lowLevel;
52
- }
53
- if (projectType === 'addon') {
54
- tagHeader.required_hwfw = undefined;
55
- tagHeader.required_productcode = undefined;
56
- tagHeader.addon_max_sources = 1;
57
- tagHeader.addon_max_per_site = manifest.maxInstancesPerSite;
58
- }
59
- return tagHeader;
60
- }
61
- APM.createBaseTagHeader = createBaseTagHeader;
62
- /**
63
- * Create new release tag
64
- * @param cwd
65
- * @param fs
66
- * @param phase
67
- */
68
- async function createTag(cwd, fs, phase) {
69
- const manifest = await manifest_1.Manifest.read(cwd, fs);
70
- const baseTagHeader = createBaseTagHeader(manifest);
71
- const tagHeader = {
72
- version: manifest.version,
73
- ...baseTagHeader,
74
- phase: phase
75
- };
76
- return await createBuffer(cwd, fs, manifest, tagHeader);
77
- }
78
- APM.createTag = createTag;
79
- /**
80
- * Create new dev tag.
81
- * @param cwd
82
- * @param fs
83
- */
84
- async function createDevTag(cwd, fs) {
85
- const manifest = await manifest_1.Manifest.read(cwd, fs);
86
- const baseTag = createBaseTagHeader(manifest);
87
- const apmTagHeader = {
88
- ...baseTag,
89
- blo_autostart: false
90
- };
91
- return createBuffer(cwd, fs, manifest, apmTagHeader);
92
- }
93
- APM.createDevTag = createDevTag;
94
- /**
95
- * create FormData object that can be pushed to the store
96
- * @private
97
- * @param cwd
98
- * @param fs
99
- * @param manifest
100
- * @param tagHeader
101
- */
102
- async function createBuffer(cwd, fs, manifest, tagHeader) {
103
- const apmBuffer = new FormData();
104
- apmBuffer.append('tag', JSON.stringify(tagHeader));
105
- apmBuffer.append(`src/${manifest_1.Manifest.fileName}`, new Blob([await manifest_1.Manifest.readAsBlob(cwd, fs)]));
106
- const xmlBlob = new Blob([await fs.readFile(vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.dist.ddeXmlPath))]);
107
- apmBuffer.append('bin/dde/xml', xmlBlob);
108
- if (manifest.icon) {
109
- const appIcon = await fs.readFile(vscode_uri_1.Utils.joinPath(cwd, manifest.icon));
110
- const base64 = bufferToBase64(appIcon);
111
- apmBuffer.append('previews/00.png', new Blob([`data:image/png;base64,${base64}`]));
112
- }
113
- // only validate readme and changelog if the current apm is bundled for a store release
114
- if (Object.hasOwn(tagHeader, 'phase')) {
115
- const readme = await package_1.Package.getReadmeFile(cwd, fs, tagHeader.name);
116
- const changelog = await package_1.Package.getChangelogFile(cwd, fs);
117
- apmBuffer.append(`previews/README.md`, new Blob([readme]));
118
- apmBuffer.append(`previews/CHANGELOG.md`, new Blob([changelog]));
119
- }
120
- if (await manifest_1.Manifest.isApmPartEnabled(cwd, fs, APM.Part.dlo)) {
121
- const amxBlob = new Blob([await fs.readFile(vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.dist.mainAmxPath))]);
122
- apmBuffer.append('bin/dlo/amx', amxBlob);
123
- }
124
- // handle pov binaries
125
- if (await manifest_1.Manifest.isApmPartEnabled(cwd, fs, APM.Part.pov, manifest)) {
126
- // get files in details dir
127
- await insertRelativePathFilesToBuffer(cwd, fs, apmBuffer, defaultFiles_1.DefaultFiles.filePaths.dist.povDetailsPath, 'bin/pov/details');
128
- //site list not supported yet -> add an empty index.html
129
- const emptyIndexHtml = new TextEncoder().encode(`<!DOCTYPE html><html lang="en">`);
130
- apmBuffer.append('bin/pov/list/index.html', new Blob([emptyIndexHtml]));
131
- }
132
- // handle dfiles
133
- const availableDfiles = await fs.findFiles(cwd, `${defaultFiles_1.DefaultFiles.filePaths.dist.dfilesPath}/*`);
134
- for (const fileName of availableDfiles) {
135
- const dfileBlob = new Blob([await fs.readFile(fileName)]);
136
- apmBuffer.append(`bin/dfiles/${vscode_uri_1.Utils.basename(fileName)}`, dfileBlob);
137
- }
138
- // handle blo files
139
- if (await manifest_1.Manifest.isApmPartEnabled(cwd, fs, APM.Part.blo, manifest)) {
140
- // get files in blo dir
141
- await insertRelativePathFilesToBuffer(cwd, fs, apmBuffer, defaultFiles_1.DefaultFiles.filePaths.dist.bloPath, 'bin/blo');
142
- }
143
- await addAdditionalFiles(cwd, fs, apmBuffer);
144
- return apmBuffer;
145
- }
146
- APM.createBuffer = createBuffer;
147
- /**
148
- * Validate if the current user has access to the apm
149
- */
150
- async function validateAccess(cwd, fs, token, preventCreation, env) {
151
- const manifest = await manifest_1.Manifest.read(cwd, fs);
152
- if (!preventCreation) {
153
- // throws if the specific setting is invalid
154
- await package_1.Package.validatePublishSettings(cwd, fs, token, env);
155
- }
156
- const { registry } = manifest;
157
- let applicationId = registry?.id;
158
- if (!applicationId && !preventCreation) {
159
- applicationId = await registerNew(cwd, fs, token, manifest, env);
160
- }
161
- if (applicationId) {
162
- const { publisher } = manifest;
163
- if (!publisher) {
164
- return null;
165
- }
166
- try {
167
- return {
168
- id: applicationId,
169
- ...(await registryAPI_1.Registry.getExistingApplication(token, publisher, applicationId, env))
170
- };
171
- }
172
- catch (e) {
173
- if (e?.message === 'Could not find given application') {
174
- // create the app with the given id!
175
- applicationId = await registerNew(cwd, fs, token, manifest, env);
176
- return {
177
- id: applicationId,
178
- ...(await registryAPI_1.Registry.getExistingApplication(token, publisher, applicationId, env))
179
- };
180
- }
181
- }
182
- }
183
- return null;
184
- }
185
- APM.validateAccess = validateAccess;
186
- /**
187
- *
188
- * @param cwd
189
- * @param fs
190
- * @param token
191
- * @param manifest
192
- * @param env
193
- */
194
- async function registerNew(cwd, fs, token, manifest, env) {
195
- // only myDatanet -> ONE support not needed.
196
- const backendTarget = 'myDatanet';
197
- const { publisher, name, description, registry } = manifest;
198
- const newApplication = {
199
- id: registry?.id,
200
- // @ts-ignore
201
- type: manifest.type || manifest_1.Manifest.ProjectTypes.app,
202
- name: name,
203
- targetSystem: backendTarget,
204
- description: description || '',
205
- allowedBackends: null
206
- };
207
- // initialize allowedApplications for addon
208
- if (manifest_1.Manifest.isAddon(manifest)) {
209
- newApplication.allowedApplications = null;
210
- }
211
- // create new application
212
- const projectId = await registryAPI_1.Registry.createNewApplication(token, publisher, newApplication, env);
213
- if (!projectId) {
214
- throw new Error('Failed to initialize application');
215
- }
216
- manifest.registry = {
217
- id: projectId
218
- };
219
- // write the updated manifest to disk
220
- await manifest_1.Manifest.write(cwd, fs, manifest);
221
- return projectId;
222
- }
223
- APM.registerNew = registerNew;
224
- /**
225
- * Update the APM profile
226
- * - allowedBackends, description and name will be upated
227
- * @param cwd
228
- * @param fs
229
- * @param token
230
- * @param env
231
- */
232
- async function updateProfile(cwd, fs, token, env) {
233
- const { name, publisher, description, registry } = await manifest_1.Manifest.read(cwd, fs);
234
- const applicationId = registry?.id;
235
- await registryAPI_1.Registry.updateExistingApplication(token, publisher, applicationId, {
236
- description: description,
237
- name: name,
238
- targetSystem: 'myDatanet'
239
- }, env);
240
- }
241
- APM.updateProfile = updateProfile;
242
- /**
243
- * Publish a new version to the store
244
- * @param cwd
245
- * @param fs
246
- * @param token
247
- * @param apmTag
248
- * @param env
249
- */
250
- async function publishTag(cwd, fs, token, apmTag, env) {
251
- const { publisher, registry, version } = await manifest_1.Manifest.read(cwd, fs);
252
- return await registryAPI_1.Registry.publishApplicationVersion(token, publisher, registry?.id, version, apmTag, env);
253
- }
254
- APM.publishTag = publishTag;
255
- })(APM || (exports.APM = APM = {}));
256
- /**
257
- * Find files in the given sourcePath and insert it at the correct place within the apmBuffer
258
- * @param cwd
259
- * @param fs
260
- * @param apmBuffer
261
- * @param sourcePath
262
- * @param binPath
263
- */
264
- async function insertRelativePathFilesToBuffer(cwd, fs, apmBuffer, sourcePath, binPath) {
265
- const apmPartFiles = await fs.findFiles(cwd, `${sourcePath}/**`);
266
- for (const apmPartFile of apmPartFiles) {
267
- const apmDistPath = vscode_uri_1.Utils.joinPath(cwd, sourcePath);
268
- const relativePath = apmPartFile.path.substring(apmDistPath.path.length + 1);
269
- const apmFileBlob = new Blob([await fs.readFile(vscode_uri_1.Utils.joinPath(cwd, `${sourcePath}/${relativePath}`))]);
270
- apmBuffer.append(`${binPath}/${relativePath}`, apmFileBlob);
271
- }
272
- }
273
- /**
274
- * Add additional files to the apm buffer
275
- *
276
- * Files:
277
- * - mdn_report_template.json
278
- * @param cwd
279
- * @param fs
280
- * @param apmBuffer
281
- */
282
- async function addAdditionalFiles(cwd, fs, apmBuffer) {
283
- const reportTemplate = vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.dist.reportTemplate);
284
- if (await fs.stat(reportTemplate)) {
285
- const reportTemplateBlob = new Blob([await fs.readFile(reportTemplate)]);
286
- apmBuffer.append(`bin/pov/mdn_report_template.json`, reportTemplateBlob);
287
- }
288
- // pass the current versions history json to the apm tag
289
- const historyPath = vscode_uri_1.Utils.joinPath(cwd, defaultFiles_1.DefaultFiles.filePaths.dist.historyJson);
290
- if (await fs.stat(historyPath)) {
291
- apmBuffer.append(`src/dde/history.json`, new Blob([await fs.readFile(historyPath)]));
292
- }
293
- }
294
- //# sourceMappingURL=apm.js.map