@digipair/skill-web 0.90.0 → 0.91.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/.swcrc ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "jsc": {
3
+ "target": "es2017",
4
+ "parser": {
5
+ "syntax": "typescript",
6
+ "decorators": true,
7
+ "dynamicImport": true
8
+ },
9
+ "transform": {
10
+ "decoratorMetadata": true,
11
+ "legacyDecorator": true
12
+ },
13
+ "keepClassNames": true,
14
+ "externalHelpers": true,
15
+ "loose": true
16
+ },
17
+ "module": {
18
+ "type": "es6"
19
+ },
20
+ "sourceMaps": true,
21
+ "exclude": [
22
+ "jest.config.ts",
23
+ ".*\\.spec.tsx?$",
24
+ ".*\\.test.tsx?$",
25
+ "./src/jest-setup.ts$",
26
+ "./**/jest-setup.ts$"
27
+ ]
28
+ }
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # mylib
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build mylib` to build the library.
@@ -0,0 +1,22 @@
1
+ import baseConfig from '../../eslint.config.mjs';
2
+
3
+ export default [
4
+ ...baseConfig,
5
+ {
6
+ files: ['**/*.json'],
7
+ rules: {
8
+ '@nx/dependency-checks': [
9
+ 'error',
10
+ {
11
+ ignoredFiles: [
12
+ '{projectRoot}/eslint.config.{js,cjs,mjs}',
13
+ '{projectRoot}/rollup.config.{js,ts,mjs,mts,cjs,cts}',
14
+ ],
15
+ },
16
+ ],
17
+ },
18
+ languageOptions: {
19
+ parser: await import('jsonc-eslint-parser'),
20
+ },
21
+ },
22
+ ];
package/package.json CHANGED
@@ -1,14 +1,28 @@
1
1
  {
2
2
  "name": "@digipair/skill-web",
3
- "version": "0.90.0",
3
+ "version": "0.91.0-0",
4
+ "type": "module",
5
+ "main": "dist/libs/skill-web/index.cjs.js",
6
+ "module": "dist/libs/skill-web/index.esm.js",
7
+ "types": "dist/libs/skill-web/index.esm.d.ts",
8
+ "exports": {
9
+ "./package.json": "./libs/skill-web/package.json",
10
+ ".": {
11
+ "development": "./dist/libs/skill-web/src/index.ts",
12
+ "types": "./dist/libs/skill-web/index.esm.d.ts",
13
+ "import": "./dist/libs/skill-web/index.esm.js",
14
+ "default": "./dist/libs/skill-web/index.cjs.js"
15
+ }
16
+ },
4
17
  "keywords": [
5
18
  "digipair",
6
19
  "service",
7
20
  "util"
8
21
  ],
9
- "dependencies": {
10
- "jsdom": "^25.0.1"
22
+ "nx": {
23
+ "name": "skill-web"
11
24
  },
12
- "main": "./index.cjs.js",
13
- "module": "./index.esm.js"
14
- }
25
+ "dependencies": {
26
+ "@digipair/engine": "0.91.0-0"
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ const { withNx } = require('@nx/rollup/with-nx');
2
+
3
+ module.exports = withNx(
4
+ {
5
+ main: 'libs/skill-web/src/index.ts',
6
+ outputPath: 'dist/libs/skill-web',
7
+ tsConfig: 'libs/skill-web/tsconfig.lib.json',
8
+ compiler: 'swc',
9
+ format: ['esm', "cjs"],
10
+ assets: [
11
+ {
12
+ input: 'libs/skill-web/',
13
+ glob: 'package.json',
14
+ output: '.'
15
+ },
16
+ {
17
+ input: 'libs/skill-web/src/',
18
+ glob: '*.json',
19
+ output: '.'
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ // Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
25
+ // e.g.
26
+ // output: { sourcemap: true },
27
+ }
28
+ );
@@ -0,0 +1 @@
1
+ declare module 'handlebars/dist/handlebars.min.js';
package/src/jsdom.d.ts ADDED
@@ -0,0 +1 @@
1
+ declare module 'jsdom';
@@ -0,0 +1,7 @@
1
+ import { skillWeb } from './skill-web';
2
+
3
+ describe('skillWeb', () => {
4
+ it('should work', () => {
5
+ expect(skillWeb()).toEqual('skill-web');
6
+ });
7
+ });
@@ -0,0 +1,296 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import { PinsSettings, executePinsList, generateElementFromPins } from '@digipair/engine';
3
+ import { JSDOM } from 'jsdom';
4
+ import { readFile } from 'fs/promises';
5
+ import { lookup } from 'mime-types';
6
+
7
+ class WebService {
8
+ private filteredWebPinsSettings(item: any, path: string): any {
9
+ if (Array.isArray(item)) {
10
+ return item.map((subItem: any, subIndex: number) =>
11
+ this.filteredWebPinsSettings(subItem, `${path}[${subIndex}]`),
12
+ );
13
+ }
14
+
15
+ if (typeof item !== 'object' || item === null) {
16
+ return item;
17
+ }
18
+
19
+ if (item.library === '@digipair/skill-web' && item.element === 'executeFactory') {
20
+ return {
21
+ library: item.library,
22
+ element: item.element,
23
+ properties: {
24
+ path,
25
+ },
26
+ };
27
+ }
28
+
29
+ const result = {} as any;
30
+ Object.entries(item).forEach(([key, value]) => {
31
+ result[key] = this.filteredWebPinsSettings(value, `${path}.${key}`);
32
+ });
33
+
34
+ return result;
35
+ }
36
+
37
+ private findFactoryPinsSettings(path: string, item: PinsSettings[]): PinsSettings[] {
38
+ const pinsSettings = path.split('.').reduce(
39
+ (acc: any, key: string) => {
40
+ if (key.indexOf('[') !== -1) {
41
+ const index = parseInt((key.match(/\d+/) as any[])[0]);
42
+ return acc[key.split('[')[0]][index];
43
+ }
44
+
45
+ return acc[key];
46
+ },
47
+ { [path.split('[')[0]]: item },
48
+ );
49
+
50
+ return pinsSettings.properties.execute;
51
+ }
52
+
53
+ private prepareBrowserPinsSettings(name: string, pinsSettings: PinsSettings[]): PinsSettings[] {
54
+ const preparedPinsSettings = pinsSettings.map((item: PinsSettings, index: number) =>
55
+ this.filteredWebPinsSettings(item, `${name}[${index}]`),
56
+ ) as PinsSettings[];
57
+
58
+ return preparedPinsSettings;
59
+ }
60
+
61
+ private mergeConttext(context: any, newContext: any) {
62
+ const output = { ...context };
63
+
64
+ for (const key in newContext) {
65
+ if (Object.prototype.hasOwnProperty.call(newContext, key)) {
66
+ if (
67
+ key !== 'protected' &&
68
+ typeof newContext[key] === 'object' &&
69
+ newContext[key] !== null &&
70
+ !Array.isArray(newContext[key]) &&
71
+ Object.prototype.hasOwnProperty.call(context, key)
72
+ ) {
73
+ output[key] = { ...context[key], ...newContext[key] };
74
+ } else if (typeof newContext[key] !== 'undefined') {
75
+ output[key] = newContext[key];
76
+ }
77
+ }
78
+ }
79
+
80
+ return output;
81
+ }
82
+
83
+ private async pins2html(pins: PinsSettings[], context: any): Promise<string> {
84
+ const dom = new JSDOM();
85
+ const element = dom.window.document.createElement('section');
86
+
87
+ await this.generateElementsFromPins(
88
+ pins,
89
+ element,
90
+ {
91
+ config: {
92
+ VERSIONS: context.config.VERSIONS || {},
93
+ },
94
+ variables: context.variables || {},
95
+ request: context.request || {},
96
+ },
97
+ dom.window.document,
98
+ );
99
+
100
+ return element.innerHTML;
101
+ }
102
+
103
+ private async generateElementsFromPins(
104
+ pinsList: PinsSettings[],
105
+ parent: Element,
106
+ context: any,
107
+ document: Document,
108
+ ): Promise<void> {
109
+ for (let i = 0; i < pinsList.length; i++) {
110
+ const item = pinsList[i];
111
+ await generateElementFromPins(item, parent, context, document, { import: false });
112
+ }
113
+ }
114
+
115
+ async page(params: any, _pinsSettingsList: PinsSettings[], context: any): Promise<any> {
116
+ const {
117
+ body,
118
+ head,
119
+ ssr = true,
120
+ styleHtml = '',
121
+ styleBody = '',
122
+ factoryInitialize = [],
123
+ browserInitialize = [],
124
+ browserLoad = [],
125
+ confirmBeforeUnload = 'false',
126
+ } = params;
127
+ const engineVersion = context.config.VERSIONS['@digipair/engine'] || 'latest';
128
+ const preparedData = {} as { [key: string]: PinsSettings };
129
+
130
+ if (context.request.params[0] === '__digipair_www__') {
131
+ let result: any;
132
+
133
+ try {
134
+ const fileUrl = context.protected.req.path.split('__digipair_www__/')[1];
135
+
136
+ if (!fileUrl) {
137
+ context.protected.res.status(404);
138
+ return { status: 'not found' };
139
+ }
140
+
141
+ const regex = /^(.*?[^@]+)@(.*?[^\/]+)\/(.*?.+)$/;
142
+ const match = fileUrl.match(regex);
143
+
144
+ if (!match) {
145
+ context.protected.res.status(404);
146
+ return { status: 'not found' };
147
+ }
148
+
149
+ const library = match[1];
150
+ if (
151
+ library !== '@digipair/engine' &&
152
+ !context.config.VERSIONS[library] &&
153
+ !context.config.WEB_VERSIONS[library]
154
+ ) {
155
+ context.protected.res.status(404);
156
+ return { status: 'not found' };
157
+ }
158
+
159
+ if (context.config.VERSIONS[library]) {
160
+ const infos = require(`${library}/package.json`);
161
+ if (!(infos.keywords?.indexOf('digipair') >= 0 && infos.keywords?.indexOf('web') >= 0)) {
162
+ context.protected.res.status(404);
163
+ return { status: 'not found' };
164
+ }
165
+ }
166
+
167
+ const path = match[3];
168
+ let filePath = require.resolve(`${library}/${path}`);
169
+
170
+ const mimeType = lookup(filePath) || 'application/octet-stream';
171
+ context.protected.res.setHeader('Content-Type', mimeType);
172
+
173
+ result = await readFile(filePath, 'utf8');
174
+ } catch (error) {
175
+ context.protected.res.status(404);
176
+ result = { status: 'not found' };
177
+ }
178
+
179
+ return result;
180
+ }
181
+
182
+ if (
183
+ context.request.method === 'POST' &&
184
+ context.request.body?.type === 'DIGIPAIR_EXECUTE_FACTORY'
185
+ ) {
186
+ const param = context.request.body.params.path.split('[')[0];
187
+ const pinsSettingsList = this.findFactoryPinsSettings(
188
+ context.request.body.params.path,
189
+ params[param],
190
+ );
191
+ return JSON.stringify(
192
+ await executePinsList(
193
+ pinsSettingsList,
194
+ this.mergeConttext(context.request.body.context, context),
195
+ `${context.request.body.params.path}.execute`,
196
+ ),
197
+ );
198
+ }
199
+
200
+ const path = context.protected.req.path.replace(/\/$/g, '');
201
+ const baseUrl =
202
+ (context.request.headers['x-forwarded-proto'] ?? context.protected.req.protocol) +
203
+ '://' +
204
+ context.request.headers.host +
205
+ (context.request.params.length <= 0 || context.request.params[0] === ''
206
+ ? path
207
+ : path.substring(0, path.length - context.request.params.join('/').length - 1)) +
208
+ '/__digipair_www__';
209
+
210
+ await executePinsList(factoryInitialize, context, `${context.__PATH__}.factoryInitialize`);
211
+
212
+ const html = `
213
+ <!DOCTYPE html>
214
+ <html style="${styleHtml}">
215
+ <head>
216
+ ${
217
+ head
218
+ ? await this.pins2html(head, context)
219
+ : `
220
+ <meta charset="UTF-8" />
221
+ <title>Digipair</title>
222
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
223
+ <link rel="icon" type="image/x-icon" href="https://res.cloudinary.com/do87nxq3l/image/upload/fl_preserve_transparency/v1717769492/logo-digipair_oyvvxz.png?_s=public-apps">
224
+ `
225
+ }
226
+ </head>
227
+ <body style="${styleBody}">
228
+ <script type="module">
229
+ import { config, executePinsList, generateElementFromPins, applyTemplate } from '${baseUrl}/@digipair/engine@${engineVersion}/index.esm.js';
230
+
231
+ const skillWeb = {
232
+ executeFactory: async (params, pinsSettingsList, context) => {
233
+ const result = await fetch(window.location, {
234
+ headers: {
235
+ 'content-type': 'application/json',
236
+ },
237
+ body: JSON.stringify({ type: 'DIGIPAIR_EXECUTE_FACTORY', params, pinsSettingsList, context }),
238
+ method: 'POST',
239
+ });
240
+
241
+ return await result.json();
242
+ },
243
+ };
244
+
245
+ config.set('LIBRARIES', { '@digipair/skill-web': skillWeb });
246
+ config.set('BASE_URL', '${baseUrl}');
247
+
248
+ const context = {
249
+ config: {
250
+ VERSIONS: ${JSON.stringify(context.config.VERSIONS || {})},
251
+ },
252
+ variables: ${JSON.stringify(context.variables || {})},
253
+ request: ${JSON.stringify(context.request || {})},
254
+ __PATH__: '${context.__PATH__}',
255
+ };
256
+
257
+ await executePinsList(${JSON.stringify(
258
+ this.prepareBrowserPinsSettings('browserInitialize', browserInitialize),
259
+ )}, context, context.__PATH__ + '.browserInitialize');
260
+
261
+ const pinsList = ${JSON.stringify(this.prepareBrowserPinsSettings('body', body))};
262
+ document.querySelectorAll('body > [data-digipair-pins]').forEach((element) => element.remove()); // Remove SSR elements
263
+ for (let i = 0; i < pinsList.length; i++) {
264
+ const item = pinsList[i];
265
+ await generateElementFromPins(item, document.body, { ...context, data: ${JSON.stringify(
266
+ preparedData,
267
+ )} });
268
+ }
269
+
270
+ setTimeout(async () => {
271
+ await executePinsList(${JSON.stringify(
272
+ this.prepareBrowserPinsSettings('browserLoad', browserLoad),
273
+ )}, context, context.__PATH__ + '.browserLoad');
274
+ }, 1);
275
+
276
+ window.addEventListener('beforeunload', (event) => {
277
+ const showConfirmationMessage = applyTemplate('EVALUATE:' + ${JSON.stringify(confirmBeforeUnload)}, context);
278
+
279
+ if (showConfirmationMessage) {
280
+ event.preventDefault();
281
+ event.returnValue = '';
282
+ }
283
+ });
284
+ </script>
285
+
286
+ ${ssr ? await this.pins2html(body, context) : ''}
287
+ </body>
288
+ </html>
289
+ `;
290
+
291
+ return html;
292
+ }
293
+ }
294
+
295
+ export const page = (params: any, pinsSettingsList: PinsSettings[], context: any) =>
296
+ new WebService().page(params, pinsSettingsList, context);
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "files": [],
4
+ "include": [],
5
+ "references": [
6
+ {
7
+ "path": "../engine"
8
+ },
9
+ {
10
+ "path": "./tsconfig.lib.json"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist",
6
+ "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
7
+ "emitDeclarationOnly": true,
8
+ "module": "esnext",
9
+ "moduleResolution": "node",
10
+ "forceConsistentCasingInFileNames": true,
11
+ "types": ["node"]
12
+ },
13
+ "include": ["src/**/*.ts"],
14
+ "references": [
15
+ {
16
+ "path": "../engine/tsconfig.lib.json"
17
+ }
18
+ ]
19
+ }
package/index.cjs.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/index";