@gxp-dev/tools 2.0.56 → 2.0.58
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.
|
@@ -8,7 +8,6 @@ const path = require("path");
|
|
|
8
8
|
const fs = require("fs");
|
|
9
9
|
const shell = require("shelljs");
|
|
10
10
|
const archiver = require("archiver");
|
|
11
|
-
const { exportCmd } = require("../constants");
|
|
12
11
|
const { findProjectRoot, resolveGxPaths } = require("../utils");
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -310,8 +309,6 @@ async function buildCommand(argv) {
|
|
|
310
309
|
|
|
311
310
|
console.log("🔨 Building plugin...\n");
|
|
312
311
|
|
|
313
|
-
const envVars = [];
|
|
314
|
-
|
|
315
312
|
// check if vite.config.js exists locally
|
|
316
313
|
let viteConfigPath = paths.viteConfigPath;
|
|
317
314
|
const localViteConfigPath = path.join(projectPath, "vite.config.js");
|
|
@@ -320,24 +317,18 @@ async function buildCommand(argv) {
|
|
|
320
317
|
console.log(`📁 Using local vite.config.js: ${viteConfigPath}`);
|
|
321
318
|
}
|
|
322
319
|
|
|
323
|
-
// Set variables
|
|
320
|
+
// Set environment variables directly on process.env for cross-platform compatibility.
|
|
321
|
+
// Using shell-level "export"/"set" syntax breaks on Windows due to cmd.exe quote parsing.
|
|
324
322
|
if (!process.env.NODE_LOG_LEVEL) {
|
|
325
|
-
|
|
326
|
-
`${exportCmd} NODE_LOG_LEVEL=${argv["node-log-level"] || "error"}`
|
|
327
|
-
);
|
|
323
|
+
process.env.NODE_LOG_LEVEL = argv["node-log-level"] || "error";
|
|
328
324
|
}
|
|
329
325
|
if (!process.env.COMPONENT_PATH) {
|
|
330
|
-
|
|
331
|
-
`${exportCmd} COMPONENT_PATH=${
|
|
332
|
-
argv["component-path"] || "./src/Plugin.vue"
|
|
333
|
-
}`
|
|
334
|
-
);
|
|
326
|
+
process.env.COMPONENT_PATH = argv["component-path"] || "./src/Plugin.vue";
|
|
335
327
|
}
|
|
336
328
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
].join(" && ");
|
|
329
|
+
// Normalize path separators to forward slashes for cross-platform shell compatibility
|
|
330
|
+
const normalizedViteConfigPath = viteConfigPath.replace(/\\/g, "/");
|
|
331
|
+
const command = `npx vite build --config "${normalizedViteConfigPath}"`;
|
|
341
332
|
|
|
342
333
|
const result = shell.exec(command);
|
|
343
334
|
|
package/bin/lib/commands/dev.js
CHANGED
|
@@ -9,7 +9,6 @@ const path = require("path");
|
|
|
9
9
|
const fs = require("fs");
|
|
10
10
|
const shell = require("shelljs");
|
|
11
11
|
const dotenv = require("dotenv");
|
|
12
|
-
const { exportCmd } = require("../constants");
|
|
13
12
|
const {
|
|
14
13
|
findProjectRoot,
|
|
15
14
|
resolveGxPaths,
|
|
@@ -82,10 +81,13 @@ function getBrowserExtensionConfig(browser, projectPath, paths, options = {}) {
|
|
|
82
81
|
return null;
|
|
83
82
|
}
|
|
84
83
|
|
|
84
|
+
// Normalize path separators for cross-platform shell compatibility
|
|
85
|
+
const normalizedScriptPath = scriptPath.replace(/\\/g, "/");
|
|
85
86
|
return {
|
|
86
87
|
name: "CHROME",
|
|
87
88
|
color: "blue",
|
|
88
|
-
|
|
89
|
+
// Inline KEY=VALUE env syntax doesn't work on Windows; env vars are set on process.env before exec
|
|
90
|
+
command: `node "${normalizedScriptPath}"`,
|
|
89
91
|
extensionPath,
|
|
90
92
|
startUrl,
|
|
91
93
|
};
|
|
@@ -200,34 +202,26 @@ function devCommand(argv) {
|
|
|
200
202
|
console.log("📦 Using runtime dev files (publish to customize)");
|
|
201
203
|
}
|
|
202
204
|
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
// Set variables only if not already defined in environment
|
|
205
|
+
// Set environment variables directly on process.env for cross-platform compatibility.
|
|
206
|
+
// Using shell-level "export"/"set" syntax breaks on Windows due to cmd.exe quote parsing.
|
|
207
207
|
if (!process.env.NODE_LOG_LEVEL) {
|
|
208
|
-
|
|
209
|
-
`${exportCmd} NODE_LOG_LEVEL=${argv["node-log-level"] || "info"}`
|
|
210
|
-
);
|
|
208
|
+
process.env.NODE_LOG_LEVEL = argv["node-log-level"] || "info";
|
|
211
209
|
}
|
|
212
210
|
if (!process.env.NODE_PORT) {
|
|
213
|
-
|
|
211
|
+
process.env.NODE_PORT = String(finalPort);
|
|
214
212
|
}
|
|
215
213
|
if (!process.env.COMPONENT_PATH) {
|
|
216
|
-
|
|
217
|
-
`${exportCmd} COMPONENT_PATH=${
|
|
218
|
-
argv["component-path"] || "./src/Plugin.vue"
|
|
219
|
-
}`
|
|
220
|
-
);
|
|
214
|
+
process.env.COMPONENT_PATH = argv["component-path"] || "./src/Plugin.vue";
|
|
221
215
|
}
|
|
222
216
|
|
|
223
217
|
// Always set HTTPS-related variables (these are dynamic)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
218
|
+
process.env.USE_HTTPS = useHttps ? "true" : "false";
|
|
219
|
+
process.env.CERT_PATH = certPath;
|
|
220
|
+
process.env.KEY_PATH = keyPath;
|
|
227
221
|
|
|
228
222
|
// Set mock API flag if requested
|
|
229
223
|
if (withMock) {
|
|
230
|
-
|
|
224
|
+
process.env.MOCK_API_ENABLED = "true";
|
|
231
225
|
}
|
|
232
226
|
|
|
233
227
|
// Check for browser extension flags
|
|
@@ -266,6 +260,11 @@ function devCommand(argv) {
|
|
|
266
260
|
}
|
|
267
261
|
}
|
|
268
262
|
|
|
263
|
+
// Set CHROME_EXTENSION_PATH on process.env so launch-chrome.js inherits it
|
|
264
|
+
if (chromeConfig) {
|
|
265
|
+
process.env.CHROME_EXTENSION_PATH = chromeConfig.extensionPath;
|
|
266
|
+
}
|
|
267
|
+
|
|
269
268
|
// Build the command based on what's requested
|
|
270
269
|
let command;
|
|
271
270
|
|
|
@@ -274,18 +273,19 @@ function devCommand(argv) {
|
|
|
274
273
|
const names = [];
|
|
275
274
|
const colors = [];
|
|
276
275
|
|
|
276
|
+
// Normalize path separators to forward slashes for cross-platform shell compatibility
|
|
277
|
+
const normalizedViteConfigPath = viteConfigPath.replace(/\\/g, "/");
|
|
278
|
+
|
|
277
279
|
// Vite is always included
|
|
278
|
-
const viteCommand =
|
|
279
|
-
...envVars,
|
|
280
|
-
`npx vite dev --config "${viteConfigPath}"`,
|
|
281
|
-
].join(" && ");
|
|
280
|
+
const viteCommand = `npx vite dev --config "${normalizedViteConfigPath}"`;
|
|
282
281
|
processes.push(`"${viteCommand}"`);
|
|
283
282
|
names.push("VITE");
|
|
284
283
|
colors.push("cyan");
|
|
285
284
|
|
|
286
285
|
// Socket server (on by default, skip if --no-socket or server.js not found)
|
|
287
286
|
if (serverJsPath) {
|
|
288
|
-
|
|
287
|
+
const normalizedServerPath = serverJsPath.replace(/\\/g, "/");
|
|
288
|
+
processes.push(`"npx nodemon \\"${normalizedServerPath}\\""`);
|
|
289
289
|
names.push("SOCKET");
|
|
290
290
|
colors.push("green");
|
|
291
291
|
}
|
|
@@ -312,9 +312,7 @@ function devCommand(argv) {
|
|
|
312
312
|
)}" --prefix-colors "${colors.join(",")}" ${processes.join(" ")}`;
|
|
313
313
|
} else {
|
|
314
314
|
// Just run Vite dev server alone
|
|
315
|
-
command =
|
|
316
|
-
" && "
|
|
317
|
-
);
|
|
315
|
+
command = `npx vite dev --config "${normalizedViteConfigPath}"`;
|
|
318
316
|
}
|
|
319
317
|
|
|
320
318
|
shell.exec(command);
|
package/package.json
CHANGED
|
@@ -313,7 +313,55 @@ export const useGxpStore = defineStore("gxp-portal-app", () => {
|
|
|
313
313
|
console.warn(`[GxP Store] Unknown SOCKET_DRIVER "${socketDriver}", sockets not initialized`);
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Initialize API operations registry from OpenAPI spec
|
|
318
|
+
*/
|
|
319
|
+
async function initializeApiOperations() {
|
|
320
|
+
// Operations are built from OpenAPI spec paths
|
|
321
|
+
// Structure: { [operationId]: { method, path, parameters } }
|
|
322
|
+
try {
|
|
323
|
+
const specUrl = `${apiBaseUrl.value}/api-specs/openapi.json`
|
|
324
|
+
const response = await axios.get(specUrl)
|
|
325
|
+
const spec = response.data
|
|
326
|
+
|
|
327
|
+
const operations = {}
|
|
328
|
+
const httpMethods = ["get", "post", "put", "patch", "delete"]
|
|
329
|
+
|
|
330
|
+
// Parse paths from OpenAPI spec
|
|
331
|
+
if (spec.paths) {
|
|
332
|
+
for (const [path, pathItem] of Object.entries(spec.paths)) {
|
|
333
|
+
for (const method of httpMethods) {
|
|
334
|
+
if (pathItem[method] && pathItem[method].operationId) {
|
|
335
|
+
const operation = pathItem[method]
|
|
336
|
+
const operationId = operation.operationId
|
|
337
|
+
|
|
338
|
+
// Extract path parameters from the path string
|
|
339
|
+
const pathParams = []
|
|
340
|
+
const paramMatches = path.matchAll(/\{([^}]+)\}/g)
|
|
341
|
+
for (const match of paramMatches) {
|
|
342
|
+
pathParams.push(match[1])
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
operations[operationId] = {
|
|
346
|
+
method,
|
|
347
|
+
path,
|
|
348
|
+
parameters: pathParams,
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
316
354
|
|
|
355
|
+
apiOperations.value = operations
|
|
356
|
+
console.log(
|
|
357
|
+
`Loaded ${Object.keys(operations).length} API operations from OpenAPI spec`,
|
|
358
|
+
)
|
|
359
|
+
} catch (error) {
|
|
360
|
+
console.error("Failed to load OpenAPI spec:", error.message)
|
|
361
|
+
// Initialize with empty operations on failure
|
|
362
|
+
apiOperations.value = {}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
317
365
|
/**
|
|
318
366
|
* Initialize dependency-based sockets
|
|
319
367
|
* Called after manifest loads to set up dependency-specific listeners
|
|
@@ -329,43 +377,43 @@ export const useGxpStore = defineStore("gxp-portal-app", () => {
|
|
|
329
377
|
dependency.operations &&
|
|
330
378
|
Object.keys(dependency.operations).length > 0
|
|
331
379
|
) {
|
|
332
|
-
Object.keys(dependency.operations).forEach((operation) => {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
});
|
|
380
|
+
// Object.keys(dependency.operations).forEach((operation) => {
|
|
381
|
+
// if (
|
|
382
|
+
// Object.keys(apiOperations.value[dependency.identifier]).every(
|
|
383
|
+
// (key) =>
|
|
384
|
+
// [
|
|
385
|
+
// "identifier",
|
|
386
|
+
// "model",
|
|
387
|
+
// "permissionKey",
|
|
388
|
+
// "operations",
|
|
389
|
+
// ].includes(key)
|
|
390
|
+
// )
|
|
391
|
+
// ) {
|
|
392
|
+
// let method = "get";
|
|
393
|
+
// let path = dependency.operations[operation];
|
|
394
|
+
// if (path.includes(":")) {
|
|
395
|
+
// let pathSplit = path.split(":");
|
|
396
|
+
// method = pathSplit[0];
|
|
397
|
+
// path = pathSplit[1];
|
|
398
|
+
// }
|
|
399
|
+
// path = path.replace(
|
|
400
|
+
// "{teamSlug}/{projectSlug}",
|
|
401
|
+
// pluginVars.value.projectId
|
|
402
|
+
// );
|
|
403
|
+
// path = path.replace(
|
|
404
|
+
// `{${dependency.permissionKey}}`,
|
|
405
|
+
// dependencyList.value[dependency.identifier]
|
|
406
|
+
// );
|
|
407
|
+
// if (!apiOperations.value[dependency.identifier]) {
|
|
408
|
+
// apiOperations.value[dependency.identifier] = {};
|
|
409
|
+
// }
|
|
410
|
+
// apiOperations.value[dependency.identifier][operation] = {
|
|
411
|
+
// method: method,
|
|
412
|
+
// path: path,
|
|
413
|
+
// model_key: dependency.permissionKey,
|
|
414
|
+
// };
|
|
415
|
+
// }
|
|
416
|
+
// });
|
|
369
417
|
}
|
|
370
418
|
if (dependency.events && Object.keys(dependency.events).length > 0) {
|
|
371
419
|
// Create socket listeners for each event type
|
|
@@ -445,20 +493,133 @@ export const useGxpStore = defineStore("gxp-portal-app", () => {
|
|
|
445
493
|
throw new Error(`DELETE ${endpoint}: ${error.message}`);
|
|
446
494
|
}
|
|
447
495
|
}
|
|
448
|
-
async function callApi(
|
|
449
|
-
|
|
450
|
-
|
|
496
|
+
async function callApi(operationId, identifier, data = {}) {
|
|
497
|
+
// Initialize operations if not done
|
|
498
|
+
if (Object.keys(apiOperations.value).length === 0) {
|
|
499
|
+
await initializeApiOperations()
|
|
500
|
+
}
|
|
501
|
+
let operationConfig = apiOperations.value[operationId]
|
|
502
|
+
if (!operationConfig) {
|
|
503
|
+
operationConfig =
|
|
504
|
+
apiOperations.value["portal.v1.project." + operationId]
|
|
451
505
|
if (!operationConfig) {
|
|
452
|
-
throw new Error(`Operation not found:
|
|
506
|
+
throw new Error(`Operation not found: portal.v1.${operationId}`)
|
|
453
507
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const { method, path, parameters } = operationConfig
|
|
511
|
+
|
|
512
|
+
// Build the URL by substituting path parameters
|
|
513
|
+
let resolvedPath = path
|
|
514
|
+
|
|
515
|
+
// Build context parameters from multiple sources:
|
|
516
|
+
// 1. Auto-inject teamSlug and projectSlug from portal context
|
|
517
|
+
// 2. Look up identifier value from dependencyList (if identifier provided)
|
|
518
|
+
// 3. Merge in additional data parameters
|
|
519
|
+
|
|
520
|
+
let projectTeamId = pluginVars.value?.projectId?.split("/")
|
|
521
|
+
if (!projectTeamId || projectTeamId.length !== 2) {
|
|
522
|
+
return []
|
|
523
|
+
}
|
|
524
|
+
let teamSlug = projectTeamId[0]
|
|
525
|
+
let projectSlug = projectTeamId[1]
|
|
526
|
+
|
|
527
|
+
const contextParams = {
|
|
528
|
+
teamSlug: teamSlug,
|
|
529
|
+
projectSlug: projectSlug,
|
|
530
|
+
}
|
|
531
|
+
if (parameters.includes("form") && pluginVars.value?.formId) {
|
|
532
|
+
contextParams["form"] = pluginVars.value?.formId
|
|
533
|
+
}
|
|
534
|
+
// If identifier is provided, look up its value from dependencyList
|
|
535
|
+
// dependencyList stores parent object IDs as { 'identifier': idValue }
|
|
536
|
+
if (identifier !== null && identifier !== undefined) {
|
|
537
|
+
const identifierValue = dependencyList.value?.[identifier]
|
|
538
|
+
if (identifierValue !== undefined) {
|
|
539
|
+
// Add the identifier value using the identifier key as the param name
|
|
540
|
+
// e.g., identifier='form' with dependencyList.form='quiz-123' adds { form: 'quiz-123' }
|
|
541
|
+
contextParams[identifier] = identifierValue
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
const parsedData = {}
|
|
545
|
+
for (const key in data) {
|
|
546
|
+
if (data[key] !== undefined && data[key] !== null) {
|
|
547
|
+
if (data[key].toString().startsWith("pluginVars")) {
|
|
548
|
+
const pluginVarKey = data[key].split(".")[1]
|
|
549
|
+
|
|
550
|
+
parsedData[key] = pluginVars.value[pluginVarKey]
|
|
551
|
+
continue
|
|
552
|
+
}
|
|
553
|
+
parsedData[key] = data[key]
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Merge in additional data (can override dependencyList values if needed)
|
|
558
|
+
Object.assign(contextParams, parsedData)
|
|
559
|
+
|
|
560
|
+
// Replace path parameters
|
|
561
|
+
for (const param of parameters) {
|
|
562
|
+
const value = contextParams[param]
|
|
563
|
+
if (value === undefined || value === null) {
|
|
564
|
+
throw new Error(
|
|
565
|
+
`Missing required parameter: ${param} for operation ${operationId}`,
|
|
566
|
+
)
|
|
567
|
+
}
|
|
568
|
+
resolvedPath = resolvedPath.replace(
|
|
569
|
+
`{${param}}`,
|
|
570
|
+
encodeURIComponent(value),
|
|
571
|
+
)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Separate path params from body data
|
|
575
|
+
const bodyData = { ...parsedData }
|
|
576
|
+
for (const param of parameters) {
|
|
577
|
+
delete bodyData[param]
|
|
578
|
+
}
|
|
579
|
+
// Also remove identifier from body if it was in data
|
|
580
|
+
if (identifier && bodyData[identifier] !== undefined) {
|
|
581
|
+
delete bodyData[identifier]
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
try {
|
|
585
|
+
let response
|
|
586
|
+
if (method === "get" || method === "delete") {
|
|
587
|
+
// GET/DELETE: params go in query string
|
|
588
|
+
response = await apiClient[method]("/api" + resolvedPath, {
|
|
589
|
+
params: bodyData,
|
|
590
|
+
})
|
|
591
|
+
} else {
|
|
592
|
+
// POST/PUT/PATCH: params go in body
|
|
593
|
+
response = await apiClient[method]("/api" + resolvedPath, bodyData)
|
|
594
|
+
}
|
|
595
|
+
return response.data
|
|
459
596
|
} catch (error) {
|
|
460
|
-
|
|
597
|
+
const message =
|
|
598
|
+
error.response?.data?.message ||
|
|
599
|
+
error.response?.data?.error ||
|
|
600
|
+
error.message
|
|
601
|
+
console.error(
|
|
602
|
+
`API Error [${operationId}]:`,
|
|
603
|
+
message,
|
|
604
|
+
error.response?.data,
|
|
605
|
+
)
|
|
606
|
+
throw new Error(`${method.toUpperCase()} ${resolvedPath}: ${message}`)
|
|
461
607
|
}
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
// try {
|
|
611
|
+
// const operationConfig = apiOperations.value[identifier][operation];
|
|
612
|
+
// if (!operationConfig) {
|
|
613
|
+
// throw new Error(`Operation not found: ${operation}`);
|
|
614
|
+
// }
|
|
615
|
+
// const response = await apiClient[operationConfig.method](
|
|
616
|
+
// operationConfig.path,
|
|
617
|
+
// data
|
|
618
|
+
// );
|
|
619
|
+
// return response.data;
|
|
620
|
+
// } catch (error) {
|
|
621
|
+
// throw new Error(`${method} ${endpoint}: ${error.message}`);
|
|
622
|
+
// }
|
|
462
623
|
}
|
|
463
624
|
|
|
464
625
|
// Utility methods
|
|
@@ -563,7 +724,7 @@ export const useGxpStore = defineStore("gxp-portal-app", () => {
|
|
|
563
724
|
// Initialize sockets SYNCHRONOUSLY when store is created
|
|
564
725
|
// This ensures sockets is available immediately
|
|
565
726
|
initializeSockets();
|
|
566
|
-
|
|
727
|
+
initializeApiOperations()
|
|
567
728
|
// Load manifest ASYNCHRONOUSLY in the background
|
|
568
729
|
// This allows the store to be used immediately while manifest loads
|
|
569
730
|
loadManifest();
|
package/runtime/vite.config.js
CHANGED
|
@@ -332,8 +332,8 @@ export default defineConfig(({ mode }) => {
|
|
|
332
332
|
? {
|
|
333
333
|
protocol: env.HMR_PROTOCOL || "wss",
|
|
334
334
|
host: env.HMR_HOST,
|
|
335
|
-
port: parseInt(env.HMR_PORT) ||
|
|
336
|
-
clientPort: parseInt(env.
|
|
335
|
+
port: parseInt(env.HMR_PORT) || parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
|
|
336
|
+
clientPort: parseInt(env.HMR_CLIENT_PORT) || parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
|
|
337
337
|
}
|
|
338
338
|
: {
|
|
339
339
|
clientPort:
|
package/template/vite.config.js
CHANGED
|
@@ -320,7 +320,7 @@ export default defineConfig(({ mode }) => {
|
|
|
320
320
|
},
|
|
321
321
|
build: {
|
|
322
322
|
lib: {
|
|
323
|
-
entry: [env.COMPONENT_PATH || "./src/Plugin.vue"],
|
|
323
|
+
entry: [path.resolve(process.cwd(), env.COMPONENT_PATH || "./src/Plugin.vue")],
|
|
324
324
|
name: libName,
|
|
325
325
|
fileName: (format) => `plugin.${format}.js`,
|
|
326
326
|
formats: ["es"],
|