Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • applications/etuc/hubl
  • applications/hubl
  • decentral1se/hubl
  • rngadam/hubl
  • jvtrudel/hubl
  • 3wc/hubl
6 results
Show changes
{
"client": {
"name": "Sample of a functional Orbit",
"description": "",
"logo": "https://cdn.startinblox.com/logos/webp/startinblox.webp",
"server": "http://localhost:8000",
"favicon": "/pwa/favicon.ico",
"css": false,
"defaultAvatar": "/images/alien.webp",
"i18n": {
"lang": "en",
"force": false
},
"pwa": {
"dir": "ltr",
"icons": [
{
"src": "/pwa/pwa-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/pwa/pwa-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/pwa/pwa-maskable-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/pwa/pwa-maskable-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#fff",
"theme_color": "#FFFFFF"
}
},
"components": [
{
"type": "routing",
"route": false
},
{
"type": "menu",
"route": false
},
{
"type": "menu-top",
"parameters": {
"isBeta": false
},
"route": false
}
],
"npm": []
}
{
"@startinblox/core": {
"version": "0.19",
"path": "https://cdn.jsdelivr.net/npm/@startinblox/core@0.19/dist/index.js"
},
"@startinblox/router": {
"version": "0.12",
"path": "https://cdn.jsdelivr.net/npm/@startinblox/router@0.12/+esm"
},
"@startinblox/oidc": {
"version": "0.16",
"path": "https://cdn.jsdelivr.net/npm/@startinblox/oidc@0.16/+esm",
"requiredBy": ["autoLogin", "registering"]
},
"@startinblox/component-chat": {
"version": "7.1.5",
"requiredBy": ["chat", "circles", "projects", "spaces"]
},
"@startinblox/component-communities": {
"version": "2.0.4",
"requiredBy": ["communities"]
},
"@startinblox/component-dashboard": {
"requiredBy": ["dashboard"]
},
"@startinblox/component-directory": {
"version": "8.0.2",
"requiredBy": ["directory"]
},
"@startinblox/component-event": {
"version": "5.0.7",
"requiredBy": ["events"]
},
"@startinblox/component-conversation": {
"version": "1.0.2",
"requiredBy": ["events", "polls", "resources"]
},
"@startinblox/component-invoicing": {
"requiredBy": ["invoices"]
},
"@startinblox/component-job-board": {
"requiredBy": ["job-board"]
},
"@startinblox/component-notifications": {
"version": "1.0.2",
"requiredBy": ["notification"]
},
"@startinblox/component-poll": {
"requiredBy": ["polls"]
},
"@startinblox/component-spaces": {
"requiredBy": ["spaces"]
},
"@startinblox/component-sales": {
"requiredBy": ["spaces"]
},
"@startinblox/component-resource": {
"version": "5.0.5",
"requiredBy": ["resources"]
},
"@startinblox/component-babelfish": {
"requiredBy": ["babelfish"]
},
"@startinblox/ontochain-directory": {
"requiredBy": ["ontochain-directory"]
},
"@startinblox/component-piswap": {
"requiredBy": ["piswap"]
},
"@startinblox/component-tamis": {
"requiredBy": [
"tamis-profile",
"tamis-commande",
"tamis-prestation",
"tamis-asset"
]
},
"@startinblox/components-tems": {
"requiredBy": ["tems-catalog"]
},
"moralis": {
"path": "https://unpkg.com/moralis/dist/moralis.js",
"requiredBy": ["piswap"]
}
}
import { defaultComposer } from "default-composer";
import { readdirSync, statSync } from "node:fs";
import { join } from "node:path";
import defaultNpm from "./default.npm.json";
import defaultConfig from "./default.config.json";
import convertStringToBoolean from "../src/helpers/convertStringToBoolean.js";
import generateUniq from "../src/helpers/generateUniq.js";
import generateUrl from "../src/helpers/generateUrl.js";
import rewriteServer from "../src/helpers/rewriteServer.js";
/*
Generate the client config from a combination of client.json, default.client.json, default.npm.json
Provide local federations and collision-free routes to each component.
*/
let userConfig;
try {
userConfig = (await import("../config.json")).default;
} catch {
userConfig = {};
}
try {
userConfig.context = (await import("../src/context.json")).default;
} catch {
userConfig.context = {};
}
const config = defaultComposer(defaultConfig, userConfig);
const componentSet = new Set(
[...defaultConfig.components, ...config.components].map((c) => c.type),
);
config.components.map((c) => {
if (c.extensions) {
for (const e of c.extensions) {
componentSet.add(e.type);
}
}
});
const defaultPackage = {
package: "",
version: "latest",
path: false,
};
// Those attributes will not be serialized on a component
const ignoredAttributes = ["replacement", "menu"];
const requiredPackages = Object.keys(defaultNpm)
.map((mod) => {
const replaced = config.npm.findIndex((e) => e.package === mod);
if (replaced === -1) {
const p = defaultNpm[mod];
if (!p.requiredBy || p.requiredBy?.some((dep) => componentSet.has(dep))) {
return defaultComposer(defaultPackage, {
package: mod,
version: p.version,
// path: p.path || `https://cdn.jsdelivr.net/npm/${mod}@${p.version || "latest"}`,
path: p.path,
});
}
} else {
return config.npm.splice(replaced, 1)[0];
}
return false;
})
.filter((p) => p);
const routes = new Set();
const federations = {};
const components = config.components.map((component) => {
if (typeof component.route === "undefined") {
component.route = component.type;
}
component.uniq = generateUniq();
if (component.route) {
let route = component.route;
if (routes.has(component.route)) {
route += `-${component.uniq}`;
}
routes.add(route);
component.route = route;
}
if (component.extensions) {
for (const extension of component.extensions) {
if (typeof extension.route === "undefined") {
extension.route = extension.type;
}
extension.uniq = generateUniq();
if (extension.route) {
let route = extension.route;
if (routes.has(extension.route)) {
route += `-${extension.uniq}`;
}
routes.add(route);
extension.route = route;
}
}
}
if (component.parameters) {
const federation = new Set();
if (config.client.server) {
federation.add(config.client.server);
}
if (config.client.servers) {
for (const server of config.client.servers) {
federation.add(server);
}
}
if (component.federation) {
for (const target of component.federation) {
federation.add(target);
}
}
component.federation = [...federation];
for (const [attribute, path] of Object.entries(component.parameters)) {
if (typeof path === "string") {
if (path.startsWith("federation://")) {
const contains = generateUrl(federation, path);
if (contains.length > 1) {
federations[`store://local.${component.uniq}/${attribute}/`] = {
"@cache": "false",
"@context": "https://cdn.startinblox.com/owl/context.jsonld",
"@type": "ldp:Container",
"@id": `store://local.${component.uniq}/${attribute}/`,
"ldp:contains": contains,
permissions: [{ mode: { "@type": "view" } }],
};
component.parameters[attribute] =
`store://local.${component.uniq}/${attribute}/`;
} else {
component.parameters[attribute] =
federation.values().next().value +
path.replace(/federation:\//, "");
}
}
}
component.parameters[attribute] = rewriteServer(component.parameters[attribute], {client: {server: config.client.server}});
}
/* Rewrite every parameters to kebab-case */
const rewriteParameters = {};
for (const [attribute, value] of Object.entries(component.parameters)) {
const attributeName = attribute.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, "-$1").toLowerCase();
if(!ignoredAttributes.includes(attributeName)) {
rewriteParameters[attributeName] = value;
}
}
component.attributes = rewriteParameters;
component.attributes.route = component.route;
component.attributes.uniq = component.uniq;
}
if (component.extensions) {
component.extensions = component.extensions.map((extension) => {
if (extension.parameters) {
const federation = new Set();
if (config.client.server) {
federation.add(config.client.server);
}
if (config.client.servers) {
for (const server of config.client.servers) {
federation.add(server);
}
}
if (component.federation) {
for (const target of component.federation) {
federation.add(target);
}
}
if (extension.federation) {
for (const target of extension.federation) {
federation.add(target);
}
}
extension.federation = [...federation];
for (const [attribute, path] of Object.entries(extension.parameters)) {
if (typeof path === "string") {
if (path.startsWith("federation://")) {
const contains = generateUrl(federation, path);
if (contains.length > 1) {
federations[`store://local.${extension.uniq}/${attribute}/`] = {
"@cache": "false",
"@context": "https://cdn.startinblox.com/owl/context.jsonld",
"@type": "ldp:Container",
"@id": `store://local.${extension.uniq}/${attribute}/`,
"ldp:contains": contains,
permissions: [{ mode: { "@type": "view" } }],
};
extension.parameters[attribute] =
`store://local.${extension.uniq}/${attribute}/`;
} else {
component.parameters[attribute] =
federation.values().next().value +
path.replace(/federation:\//, "");
}
}
}
component.parameters[attribute] = rewriteServer(component.parameters[attribute], {client: {server: config.client.server}});
}
/* Rewrite every parameters to kebab-case */
const rewriteParameters = {};
for (const [attribute, value] of Object.entries(extension.parameters)) {
const attributeName = attribute.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, "-$1").toLowerCase();
if(!ignoredAttributes.includes(attributeName)) {
rewriteParameters[attributeName] = value;
}
}
extension.attributes = rewriteParameters;
extension.attributes.uniq = extension.uniq;
}
return extension;
});
}
// Legacy: component.experimental to component.integration
if (component.experimental) {
component.integration = component.experimental;
}
return component;
});
const getRoute = (type, returnFirst = false, ignoreError = false) => {
const availables = components.filter(
(c) => c.type === type || c.uniq === type,
);
for (const c of components) {
if (c.extensions) {
for (const e of c.extensions) {
if (e.type === type || e.uniq === type) {
availables.push(e);
}
}
}
}
if (availables.length > 1) {
if (returnFirst) {
return availables[0].route;
}
return availables[availables.length - 1].route;
}
if (availables.length < 1) {
if (!ignoreError && import.meta.env.DEV)
console.error(`No component found for route ${type}`);
} else {
return availables[0].route;
}
return false;
};
const getDefaultRoute = () => {
const defaultComponent = components.filter(
(e) => e.defaultRoute !== undefined,
);
let defaultRoute = "dashboard";
if (defaultComponent.length === 1) {
defaultRoute = defaultComponent[0].route;
}
return defaultRoute;
};
const listFiles = (directory, subfolder) => {
try {
const files = readdirSync(directory);
const fileNames = files.filter((filePath) =>
statSync(join(directory, filePath)).isFile(),
);
return fileNames.map(
(file) => () => `${subfolder}/${file.replace(".hbs", "")}`,
);
} catch (err) {
console.error(err);
return [];
}
};
const notifications = listFiles(
"./src/partials/notifications",
"notifications",
);
const widgets = listFiles("./src/partials/widgets", "widgets");
const mandatoryComponents = defaultConfig.components.filter(
(component) =>
!config.components.some((c) => component["type"] === c["type"]),
);
const definitiveConfig = {
client: Object.fromEntries(
Object.entries(config.client).map(([k, c]) => [
k,
convertStringToBoolean(rewriteServer(c, config)),
]),
),
components: [...mandatoryComponents, ...config.components],
// Both handlebars and vite does not handle Set properly
componentSet: [...componentSet],
npm: requiredPackages.concat(config.npm),
federations,
files: {
notifications: notifications,
widgets: widgets,
},
helpers: {
getDefaultRoute,
getRoute,
listFiles,
},
};
export default definitiveConfig;