retold-data-service 2.0.21 → 2.0.23

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.
Files changed (37) hide show
  1. package/.quackage-comprehension-loader.json +19 -0
  2. package/bin/retold-data-service-clone.js +4 -1
  3. package/generate-bookstore-comprehension.js +645 -0
  4. package/package.json +7 -7
  5. package/source/Retold-Data-Service.js +30 -2
  6. package/source/services/comprehension-loader/ComprehensionLoader-Command-Load.js +345 -0
  7. package/source/services/comprehension-loader/ComprehensionLoader-Command-Schema.js +97 -0
  8. package/source/services/comprehension-loader/ComprehensionLoader-Command-Session.js +221 -0
  9. package/source/services/comprehension-loader/ComprehensionLoader-Command-WebUI.js +57 -0
  10. package/source/services/comprehension-loader/Retold-Data-Service-ComprehensionLoader.js +536 -0
  11. package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader-Configuration.json +9 -0
  12. package/source/services/comprehension-loader/pict-app/Pict-Application-ComprehensionLoader.js +86 -0
  13. package/source/services/comprehension-loader/pict-app/Pict-ComprehensionLoader-Bundle.js +6 -0
  14. package/source/services/comprehension-loader/pict-app/providers/Pict-Provider-ComprehensionLoader.js +760 -0
  15. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Layout.js +360 -0
  16. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Load.js +472 -0
  17. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Schema.js +119 -0
  18. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Session.js +269 -0
  19. package/source/services/comprehension-loader/pict-app/views/PictView-ComprehensionLoader-Source.js +330 -0
  20. package/source/services/comprehension-loader/web/comprehension-loader.js +6794 -0
  21. package/source/services/comprehension-loader/web/comprehension-loader.js.map +1 -0
  22. package/source/services/comprehension-loader/web/comprehension-loader.min.js +2 -0
  23. package/source/services/comprehension-loader/web/comprehension-loader.min.js.map +1 -0
  24. package/source/services/comprehension-loader/web/index.html +17 -0
  25. package/source/services/data-cloner/DataCloner-Command-Schema.js +407 -15
  26. package/source/services/data-cloner/Retold-Data-Service-DataCloner.js +59 -1
  27. package/source/services/data-cloner/pict-app/Pict-Application-DataCloner.js +1 -0
  28. package/source/services/data-cloner/pict-app/providers/Pict-Provider-DataCloner.js +125 -5
  29. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Connection.js +18 -8
  30. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Deploy.js +104 -1
  31. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Export.js +1 -1
  32. package/source/services/data-cloner/pict-app/views/PictView-DataCloner-Layout.js +12 -0
  33. package/source/services/data-cloner/web/data-cloner.js +201 -139
  34. package/source/services/data-cloner/web/data-cloner.js.map +1 -1
  35. package/source/services/data-cloner/web/data-cloner.min.js +1 -1
  36. package/source/services/data-cloner/web/data-cloner.min.js.map +1 -1
  37. package/test/RetoldDataService_tests.js +225 -0
@@ -0,0 +1,221 @@
1
+ /**
2
+ * ComprehensionLoader Session Management Routes
3
+ *
4
+ * Registers /comprehension_load/session/* endpoints for remote session
5
+ * configuration, authentication, check, and deauthentication via
6
+ * pict-sessionmanager.
7
+ *
8
+ * @param {Object} pComprehensionLoaderService - The RetoldDataServiceComprehensionLoader instance
9
+ * @param {Object} pOratorServiceServer - The Orator ServiceServer instance
10
+ */
11
+ module.exports = (pComprehensionLoaderService, pOratorServiceServer) =>
12
+ {
13
+ let tmpFable = pComprehensionLoaderService.fable;
14
+ let tmpLoadState = pComprehensionLoaderService.loadState;
15
+ let tmpPict = pComprehensionLoaderService.pict;
16
+ let tmpPrefix = pComprehensionLoaderService.routePrefix;
17
+
18
+ // POST /comprehension_load/session/configure
19
+ pOratorServiceServer.post(`${tmpPrefix}/session/configure`,
20
+ (pRequest, pResponse, fNext) =>
21
+ {
22
+ let tmpBody = pRequest.body || {};
23
+ let tmpServerURL = tmpBody.ServerURL;
24
+
25
+ if (!tmpServerURL)
26
+ {
27
+ pResponse.send(400, { Success: false, Error: 'ServerURL is required.' });
28
+ return fNext();
29
+ }
30
+
31
+ tmpLoadState.RemoteServerURL = tmpServerURL;
32
+
33
+ // Remove existing session if reconfiguring
34
+ if (tmpPict.SessionManager.getSession('Remote'))
35
+ {
36
+ tmpPict.SessionManager.deauthenticate('Remote');
37
+ delete tmpPict.SessionManager.sessions['Remote'];
38
+ }
39
+
40
+ // Extract domain from ServerURL for cookie matching
41
+ let tmpDomainMatch = tmpBody.DomainMatch;
42
+ if (!tmpDomainMatch)
43
+ {
44
+ try
45
+ {
46
+ let tmpURL = new URL(tmpServerURL);
47
+ tmpDomainMatch = tmpURL.hostname;
48
+ }
49
+ catch (pParseError)
50
+ {
51
+ tmpDomainMatch = tmpServerURL;
52
+ }
53
+ }
54
+
55
+ // Helper: ensure a URI template is fully qualified with the server URL
56
+ let fQualifyURI = (pTemplate, pDefault) =>
57
+ {
58
+ let tmpTemplate = pTemplate || pDefault;
59
+ if (tmpTemplate.indexOf('://') > -1)
60
+ {
61
+ return tmpTemplate;
62
+ }
63
+ let tmpPath = tmpTemplate.replace(/^\//, '');
64
+ let tmpVersionMatch = tmpServerURL.match(/\/(\d+\.\d+)\/?$/);
65
+ if (tmpVersionMatch)
66
+ {
67
+ let tmpURLPrefix = tmpVersionMatch[1] + '/';
68
+ if (tmpPath.indexOf(tmpURLPrefix) === 0)
69
+ {
70
+ tmpPath = tmpPath.substring(tmpURLPrefix.length);
71
+ }
72
+ }
73
+ return tmpServerURL + tmpPath;
74
+ };
75
+
76
+ let tmpSessionConfig = (
77
+ {
78
+ Type: 'Cookie',
79
+
80
+ AuthenticationMethod: tmpBody.AuthenticationMethod || 'get',
81
+ AuthenticationURITemplate: fQualifyURI(tmpBody.AuthenticationURITemplate, 'Authenticate/{~D:Record.UserName~}/{~D:Record.Password~}'),
82
+ AuthenticationRetryCount: 2,
83
+ AuthenticationRetryDebounce: 200,
84
+
85
+ CheckSessionURITemplate: fQualifyURI(tmpBody.CheckSessionURITemplate, 'CheckSession'),
86
+ CheckSessionLoginMarkerType: tmpBody.CheckSessionLoginMarkerType || 'boolean',
87
+ CheckSessionLoginMarker: tmpBody.CheckSessionLoginMarker || 'LoggedIn',
88
+
89
+ DomainMatch: tmpDomainMatch,
90
+ CookieName: tmpBody.CookieName || 'SessionID',
91
+ CookieValueAddress: tmpBody.CookieValueAddress || 'SessionID',
92
+ CookieValueTemplate: tmpBody.CookieValueTemplate || false
93
+ });
94
+
95
+ if (tmpBody.AuthenticationMethod === 'post')
96
+ {
97
+ tmpSessionConfig.AuthenticationRequestBody = tmpBody.AuthenticationRequestBody || (
98
+ {
99
+ username: '{~D:Record.UserName~}',
100
+ password: '{~D:Record.Password~}'
101
+ });
102
+ }
103
+
104
+ tmpPict.SessionManager.addSession('Remote', tmpSessionConfig);
105
+ tmpPict.SessionManager.connectToRestClient();
106
+
107
+ tmpLoadState.SessionConfigured = true;
108
+ tmpLoadState.SessionAuthenticated = false;
109
+
110
+ tmpFable.log.info(`Comprehension Loader: Session configured for ${tmpServerURL} (domain: ${tmpDomainMatch})`);
111
+
112
+ pResponse.send(200,
113
+ {
114
+ Success: true,
115
+ ServerURL: tmpServerURL,
116
+ DomainMatch: tmpDomainMatch,
117
+ AuthenticationMethod: tmpSessionConfig.AuthenticationMethod
118
+ });
119
+ return fNext();
120
+ });
121
+
122
+ // POST /comprehension_load/session/authenticate
123
+ pOratorServiceServer.post(`${tmpPrefix}/session/authenticate`,
124
+ (pRequest, pResponse, fNext) =>
125
+ {
126
+ if (!tmpLoadState.SessionConfigured)
127
+ {
128
+ pResponse.send(400, { Success: false, Error: 'Session not configured. Call POST /comprehension_load/session/configure first.' });
129
+ return fNext();
130
+ }
131
+
132
+ let tmpBody = pRequest.body || {};
133
+ let tmpCredentials = (
134
+ {
135
+ UserName: tmpBody.UserName || tmpBody.username,
136
+ Password: tmpBody.Password || tmpBody.password
137
+ });
138
+
139
+ if (!tmpCredentials.UserName || !tmpCredentials.Password)
140
+ {
141
+ pResponse.send(400, { Success: false, Error: 'UserName and Password are required.' });
142
+ return fNext();
143
+ }
144
+
145
+ tmpFable.log.info(`Comprehension Loader: Authenticating as ${tmpCredentials.UserName}...`);
146
+
147
+ tmpPict.SessionManager.authenticate('Remote', tmpCredentials,
148
+ (pAuthError, pSessionState) =>
149
+ {
150
+ if (pAuthError)
151
+ {
152
+ tmpFable.log.error(`Comprehension Loader: Authentication failed: ${pAuthError.message || pAuthError}`);
153
+ tmpLoadState.SessionAuthenticated = false;
154
+ pResponse.send(401,
155
+ {
156
+ Success: false,
157
+ Error: `Authentication failed: ${pAuthError.message || pAuthError}`
158
+ });
159
+ return fNext();
160
+ }
161
+
162
+ tmpLoadState.SessionAuthenticated = pSessionState && pSessionState.Authenticated;
163
+
164
+ tmpFable.log.info(`Comprehension Loader: Authentication ${tmpLoadState.SessionAuthenticated ? 'succeeded' : 'failed'}.`);
165
+
166
+ pResponse.send(200,
167
+ {
168
+ Success: tmpLoadState.SessionAuthenticated,
169
+ Authenticated: tmpLoadState.SessionAuthenticated,
170
+ SessionData: pSessionState ? pSessionState.SessionData : {}
171
+ });
172
+ return fNext();
173
+ });
174
+ });
175
+
176
+ // GET /comprehension_load/session/check
177
+ pOratorServiceServer.get(`${tmpPrefix}/session/check`,
178
+ (pRequest, pResponse, fNext) =>
179
+ {
180
+ if (!tmpLoadState.SessionConfigured)
181
+ {
182
+ pResponse.send(200,
183
+ {
184
+ Configured: false,
185
+ Authenticated: false
186
+ });
187
+ return fNext();
188
+ }
189
+
190
+ tmpPict.SessionManager.checkSession('Remote',
191
+ (pCheckError, pAuthenticated, pCheckData) =>
192
+ {
193
+ tmpLoadState.SessionAuthenticated = pAuthenticated;
194
+
195
+ pResponse.send(200,
196
+ {
197
+ Configured: tmpLoadState.SessionConfigured,
198
+ Authenticated: pAuthenticated,
199
+ ServerURL: tmpLoadState.RemoteServerURL,
200
+ CheckData: pCheckData || {}
201
+ });
202
+ return fNext();
203
+ });
204
+ });
205
+
206
+ // POST /comprehension_load/session/deauthenticate
207
+ pOratorServiceServer.post(`${tmpPrefix}/session/deauthenticate`,
208
+ (pRequest, pResponse, fNext) =>
209
+ {
210
+ if (tmpLoadState.SessionConfigured)
211
+ {
212
+ tmpPict.SessionManager.deauthenticate('Remote');
213
+ }
214
+ tmpLoadState.SessionAuthenticated = false;
215
+
216
+ tmpFable.log.info('Comprehension Loader: Session deauthenticated.');
217
+
218
+ pResponse.send(200, { Success: true, Authenticated: false });
219
+ return fNext();
220
+ });
221
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ComprehensionLoader Web UI Routes
3
+ *
4
+ * Serves the Pict-application-based comprehension loader web UI.
5
+ * The HTML entry point loads pict.min.js (from node_modules) and the
6
+ * Quackage-built application bundle.
7
+ *
8
+ * @param {Object} pComprehensionLoaderService - The RetoldDataServiceComprehensionLoader instance
9
+ * @param {Object} pOratorServiceServer - The Orator ServiceServer instance
10
+ */
11
+ module.exports = (pComprehensionLoaderService, pOratorServiceServer) =>
12
+ {
13
+ let libFs = require('fs');
14
+ let libPath = require('path');
15
+
16
+ let tmpPrefix = pComprehensionLoaderService.routePrefix;
17
+ let tmpWebDir = libPath.join(__dirname, 'web');
18
+
19
+ // Helper: serve a static file with the given content type
20
+ let fServeFile = (pFilePath, pContentType) =>
21
+ {
22
+ return (pRequest, pResponse, fNext) =>
23
+ {
24
+ try
25
+ {
26
+ let tmpContent = libFs.readFileSync(pFilePath, 'utf8');
27
+ pResponse.writeHead(200, { 'Content-Type': pContentType + '; charset=utf-8' });
28
+ pResponse.write(tmpContent);
29
+ pResponse.end();
30
+ }
31
+ catch (pReadError)
32
+ {
33
+ pResponse.send(500, { Success: false, Error: 'Failed to load ' + libPath.basename(pFilePath) });
34
+ }
35
+ return fNext();
36
+ };
37
+ };
38
+
39
+ // ---- HTML ----
40
+ pOratorServiceServer.get(`${tmpPrefix}/`,
41
+ fServeFile(libPath.join(tmpWebDir, 'index.html'), 'text/html'));
42
+
43
+ // Redirect /comprehension_load -> /comprehension_load/
44
+ pOratorServiceServer.get(`${tmpPrefix}`,
45
+ (pRequest, pResponse, fNext) =>
46
+ {
47
+ pResponse.redirect(`${tmpPrefix}/`, fNext);
48
+ });
49
+
50
+ // ---- Pict library (from node_modules) ----
51
+ pOratorServiceServer.get(`${tmpPrefix}/pict.min.js`,
52
+ fServeFile(require.resolve('pict/dist/pict.min.js'), 'application/javascript'));
53
+
54
+ // ---- Application bundle ----
55
+ pOratorServiceServer.get(`${tmpPrefix}/comprehension-loader.js`,
56
+ fServeFile(libPath.join(tmpWebDir, 'comprehension-loader.js'), 'application/javascript'));
57
+ };