@pb33f/cowboy-components 0.7.5 → 0.7.6

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 (53) hide show
  1. package/dist/components/auth/login-button.d.ts +2 -0
  2. package/dist/components/auth/login-button.js +15 -3
  3. package/dist/components/auth/login-panel.js +1 -1
  4. package/dist/components/auth/oauth-login.d.ts +1 -0
  5. package/dist/components/auth/oauth-login.js +11 -5
  6. package/dist/components/editor/editor-breadcrumb.css.js +1 -1
  7. package/dist/components/model-renderer/rendered-node.d.ts +2 -0
  8. package/dist/components/model-renderer/rendered-node.js +18 -0
  9. package/dist/components/model-renderer/responses.d.ts +11 -0
  10. package/dist/components/model-renderer/responses.js +46 -0
  11. package/dist/components/model-tree/tree.js +1 -1
  12. package/dist/components/rodeo/rodeo.js +1 -1
  13. package/dist/components/the-doctor/the-doctor.css.js +1 -1
  14. package/dist/components/the-doctor/the-doctor.d.ts +112 -120
  15. package/dist/components/the-doctor/the-doctor.js +134 -1735
  16. package/dist/components/the-doctor/upload-archive.d.ts +1 -0
  17. package/dist/components/the-doctor/upload-archive.js +29 -12
  18. package/dist/controllers/auth-controller.d.ts +25 -0
  19. package/dist/controllers/auth-controller.js +154 -0
  20. package/dist/controllers/broker-controller.d.ts +22 -0
  21. package/dist/controllers/broker-controller.js +107 -0
  22. package/dist/controllers/diagnostic-controller.d.ts +6 -0
  23. package/dist/controllers/diagnostic-controller.js +262 -0
  24. package/dist/controllers/docs-controller.d.ts +8 -0
  25. package/dist/controllers/docs-controller.js +143 -0
  26. package/dist/controllers/model-controller.d.ts +8 -0
  27. package/dist/controllers/model-controller.js +87 -0
  28. package/dist/controllers/node-clicker-controller.d.ts +11 -0
  29. package/dist/controllers/node-clicker-controller.js +362 -0
  30. package/dist/controllers/problem-controller.d.ts +7 -0
  31. package/dist/controllers/problem-controller.js +46 -0
  32. package/dist/controllers/rolodex-controller.d.ts +10 -0
  33. package/dist/controllers/rolodex-controller.js +126 -0
  34. package/dist/controllers/rule-controller.d.ts +19 -0
  35. package/dist/controllers/rule-controller.js +264 -0
  36. package/dist/controllers/spec-controller.d.ts +8 -0
  37. package/dist/controllers/spec-controller.js +78 -0
  38. package/dist/controllers/state-controller.d.ts +9 -0
  39. package/dist/controllers/state-controller.js +279 -0
  40. package/dist/cowboy-components.umd.cjs +1152 -1121
  41. package/dist/css/shared.css.js +5 -0
  42. package/dist/events/doctor.d.ts +10 -0
  43. package/dist/events/doctor.js +2 -0
  44. package/dist/model/api-response.d.ts +7 -0
  45. package/dist/model/api-response.js +2 -0
  46. package/dist/services/auth-service.d.ts +1 -0
  47. package/dist/services/auth-service.js +28 -0
  48. package/dist/services/linting-service.js +11 -2
  49. package/dist/services/model-service.d.ts +2 -1
  50. package/dist/services/model-service.js +31 -5
  51. package/package.json +1 -1
  52. package/dist/controllers/auth.d.ts +0 -20
  53. package/dist/controllers/auth.js +0 -101
@@ -21,6 +21,7 @@ export declare class UploadArchiveComponent extends LitElement {
21
21
  fileSize: number;
22
22
  fileTooBig: boolean;
23
23
  noSpecFilesFound: boolean;
24
+ cannotParseSpecError: string;
24
25
  constructor();
25
26
  show(): void;
26
27
  hide(): void;
@@ -33,6 +33,13 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
33
33
  }
34
34
  hide() {
35
35
  this.visible = false;
36
+ this.file = null;
37
+ this.files = [];
38
+ this.fileSize = 0;
39
+ this.fileTooBig = false;
40
+ this.noSpecFilesFound = false;
41
+ this.cannotParseSpecError = '';
42
+ this.invalid = false;
36
43
  this.dialog?.hide();
37
44
  }
38
45
  handleFileChange(event) {
@@ -40,6 +47,7 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
40
47
  if (file) {
41
48
  this.noSpecFilesFound = false;
42
49
  // check if the file is over 5mb (which is too big for free tier)
50
+ // TODO: prompt user to auth, and then skip this check for authenticated users.
43
51
  if (file.size > 5242880) {
44
52
  this.invalid = true;
45
53
  this.fileName = file.name;
@@ -65,10 +73,9 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
65
73
  ModelService.uploadArchive(formData).then((response) => {
66
74
  // count the number of openapi files, if there is only one - automatically select it to avoid
67
75
  // a step. Thanks to @francois for the suggestion.
68
- this.files = response.files;
69
76
  let count = 0;
70
77
  let found = [];
71
- this.files.forEach((file) => {
78
+ response.files.forEach((file) => {
72
79
  if (file.isOpenAPI) {
73
80
  count++;
74
81
  found.push(file);
@@ -83,6 +90,7 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
83
90
  this.selectFile(found[0].name);
84
91
  return;
85
92
  }
93
+ this.files = found;
86
94
  }).catch((error) => {
87
95
  console.error(error);
88
96
  });
@@ -106,7 +114,8 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
106
114
  this.files = [];
107
115
  this.hide();
108
116
  }).catch((error) => {
109
- console.error(error);
117
+ this.invalid = true;
118
+ this.cannotParseSpecError = error.detail;
110
119
  });
111
120
  }
112
121
  fetchUrl() {
@@ -161,9 +170,9 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
161
170
  `;
162
171
  }
163
172
  render() {
164
- let files = html ``;
165
- if (this.files.length > 0) {
166
- files = html `
173
+ let renderFiles = html ``;
174
+ if (this.files.length > 0 && !this.cannotParseSpecError) {
175
+ renderFiles = html `
167
176
  <div class="files">
168
177
  <h4>Select the Entry Document</h4>
169
178
  <p>
@@ -185,7 +194,7 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
185
194
  </div>`;
186
195
  }
187
196
  if (this.noSpecFilesFound) {
188
- files = html ` <p class="invalid"><strong>No OpenAPI files found in archive!</strong></p>
197
+ renderFiles = html ` <p class="invalid"><strong>No OpenAPI files found in archive!</strong></p>
189
198
  <p class="invalid">The doctor was unable to detect any OpenAPI YAML or JSON files in the archive you selected.</p>
190
199
  <p>Try another file, or check your archive.</p>`;
191
200
  }
@@ -220,17 +229,25 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
220
229
  <label for="fileInput" class="upload-archive-button">
221
230
  Upload .zip or .tar.gz
222
231
  </label>
223
- <input ${this.invalid ? 'invalid-file invalid' : ''}" type="file" id="fileInput"
224
- @change="${this.handleFileChange}"/>
232
+ <input ${this.invalid ? 'invalid-file invalid' : ''}" type="file" id="fileInput" @change="${this.handleFileChange}"/>
225
233
 
226
- ${this.invalid && !this.fileTooBig ? html `
234
+ ${this.invalid && this.cannotParseSpecError != '' ? html `
235
+ <p class="invalid">Oh dear, '<strong>${this.fileName}</strong>' is very sick.</p>
236
+ <p class="invalid">I'm unable to proceed with this file:
237
+ <br/>
238
+ <br/>
239
+ ${this.cannotParseSpecError}
240
+ </p>
241
+ ` : ''}
242
+
243
+ ${this.invalid && !this.fileTooBig && this.cannotParseSpecError == '' ? html `
227
244
  <p class="invalid">'<strong>${this.fileName}</strong>' has a type of
228
245
  '<strong>${this.fileType}</strong>'
229
246
  which is an invalid file type.</p>
230
247
  <p class="invalid">Please upload a <strong>valid</strong> zip archive or a tarball.</p>
231
248
  ` : ''}
232
249
 
233
- ${this.invalid && this.fileTooBig ? html `
250
+ ${this.invalid && this.fileTooBig && this.cannotParseSpecError == '' ? html `
234
251
  <p class="invalid">'<strong>${this.fileName}</strong>' is too big!
235
252
  '<strong>
236
253
  <sl-format-bytes value="${this.fileSize}"></sl-format-bytes>
@@ -244,7 +261,7 @@ let UploadArchiveComponent = class UploadArchiveComponent extends LitElement {
244
261
  </div>
245
262
  </div>
246
263
 
247
- ${files}
264
+ ${renderFiles}
248
265
  <sl-button slot="footer" variant="primary" @click="${this.hide}">Close</sl-button>
249
266
  </sl-dialog>
250
267
  `;
@@ -0,0 +1,25 @@
1
+ import { AuthenticationMeta } from "../events/doctor.js";
2
+ import { AuthenticationState } from "../model/auth.js";
3
+ import { Session } from "../model/session.js";
4
+ export declare class AuthController extends EventTarget {
5
+ private static _instance;
6
+ static getInstance(): AuthController | null;
7
+ doctorEndpoint: string;
8
+ state: AuthenticationState | null;
9
+ authenticated: boolean;
10
+ urlCapture: string | null;
11
+ session: Session;
12
+ sessionCallback: Function;
13
+ startSessionAutomatically: boolean;
14
+ brokerStarted: boolean;
15
+ hosts: any[];
16
+ callbackIdx: number;
17
+ constructor(host: any, sessionCallback?: Function, autoStart?: boolean);
18
+ start(): void;
19
+ private startSession;
20
+ associateBroker(brokerId: string): Promise<boolean>;
21
+ authGithub(e: CustomEvent<AuthenticationMeta>): void;
22
+ logout(e: CustomEvent<AuthenticationMeta>): void;
23
+ private notifyStateChange;
24
+ checkState(): Promise<AuthenticationState>;
25
+ }
@@ -0,0 +1,154 @@
1
+ import { AuthenticationGithubRequested, AuthenticationStateChange, LogoutRequested, NukeWorkspaceEvent, StartSessionFailed } from "../events/doctor.js";
2
+ import { AuthService } from "../services/auth-service.js";
3
+ import { HeaderService } from "../services/header-service";
4
+ export class AuthController extends EventTarget {
5
+ static getInstance() {
6
+ const t = AuthController._instance;
7
+ if (t) {
8
+ return t;
9
+ }
10
+ return null;
11
+ }
12
+ constructor(host, sessionCallback, autoStart = false) {
13
+ super();
14
+ if (AuthController._instance) {
15
+ const t = AuthController._instance;
16
+ t.hosts.push(host);
17
+ if (sessionCallback) {
18
+ t.sessionCallback = sessionCallback;
19
+ t.callbackIdx = t.hosts.length - 1;
20
+ }
21
+ t.startSessionAutomatically = autoStart;
22
+ t.brokerStarted = false;
23
+ t.start();
24
+ return t;
25
+ }
26
+ this.doctorEndpoint = 'https://doctor.pb33f.io';
27
+ const sessionEndpoint = sessionStorage.getItem("doctor-endpoint");
28
+ if (sessionEndpoint) {
29
+ this.doctorEndpoint = sessionEndpoint;
30
+ }
31
+ AuthService.doctorEndpoint = this.doctorEndpoint;
32
+ if (sessionCallback) {
33
+ this.sessionCallback = sessionCallback;
34
+ }
35
+ this.startSessionAutomatically = autoStart;
36
+ this.brokerStarted = false;
37
+ this.hosts = [host];
38
+ if (sessionCallback) {
39
+ this.start();
40
+ }
41
+ // cache the one and only instance
42
+ AuthController._instance = this;
43
+ // @ts-ignore
44
+ window.addEventListener(AuthenticationGithubRequested, this.authGithub.bind(this));
45
+ // @ts-ignore
46
+ window.addEventListener(LogoutRequested, this.logout.bind(this));
47
+ }
48
+ start() {
49
+ if (!this.brokerStarted) {
50
+ const startBroker = () => {
51
+ this.brokerStarted = true;
52
+ this.startSession().then((session) => {
53
+ this.session = session;
54
+ if (this.sessionCallback) {
55
+ // call back if defined.
56
+ this.sessionCallback.call(this.hosts[this.callbackIdx], session);
57
+ this.hosts[this.callbackIdx].requestUpdate();
58
+ }
59
+ }).catch((err) => {
60
+ console.error("something went wrong with starting session", err);
61
+ this.dispatchEvent(new Event(StartSessionFailed));
62
+ });
63
+ };
64
+ this.checkState().then((state) => {
65
+ this.authenticated = true;
66
+ this.state = state;
67
+ this.hosts.forEach(host => {
68
+ host.requestUpdate();
69
+ });
70
+ startBroker();
71
+ if (this.urlCapture) {
72
+ const c = this.urlCapture;
73
+ this.urlCapture = null;
74
+ window.location.href = c;
75
+ }
76
+ }).catch(() => {
77
+ if (this.startSessionAutomatically) {
78
+ startBroker();
79
+ }
80
+ });
81
+ }
82
+ }
83
+ async startSession() {
84
+ return new Promise(async (resolve, reject) => {
85
+ try {
86
+ const sessionJSON = await fetch(this.doctorEndpoint + '/start-session', {
87
+ method: 'GET',
88
+ credentials: 'include',
89
+ });
90
+ const session = await sessionJSON.json();
91
+ if (session.type && session.title && session.status) {
92
+ reject();
93
+ }
94
+ resolve(session);
95
+ }
96
+ catch (e) {
97
+ reject({ detail: "the pb33f platform returned an error: " + e });
98
+ }
99
+ });
100
+ }
101
+ async associateBroker(brokerId) {
102
+ return new Promise(async (resolve, reject) => {
103
+ try {
104
+ const headers = HeaderService.buildDefaultHeaders(brokerId);
105
+ const sessionJSON = await fetch(this.doctorEndpoint + '/associate-broker', {
106
+ method: 'GET',
107
+ credentials: 'include',
108
+ headers: headers
109
+ });
110
+ if (!sessionJSON.ok) {
111
+ reject(false);
112
+ }
113
+ resolve(true);
114
+ }
115
+ catch (e) {
116
+ reject({ detail: "cannot associate broker with session" });
117
+ }
118
+ });
119
+ }
120
+ authGithub(e) {
121
+ if (e.detail.redirectURL != '') {
122
+ window.location.href = this.doctorEndpoint + '/auth/github/start?returnUrl=' + e.detail.redirectURL;
123
+ }
124
+ else {
125
+ window.location.href = this.doctorEndpoint + '/auth/github/start';
126
+ }
127
+ }
128
+ logout(e) {
129
+ AuthService.logout().then(() => {
130
+ if (e.detail.redirectURL != '') {
131
+ this.dispatchEvent(new CustomEvent(NukeWorkspaceEvent, {
132
+ bubbles: true,
133
+ composed: true,
134
+ detail: {
135
+ resetFiles: false
136
+ }
137
+ }));
138
+ }
139
+ });
140
+ }
141
+ notifyStateChange(state) {
142
+ const event = new CustomEvent(AuthenticationStateChange, {
143
+ detail: { state }
144
+ });
145
+ this.dispatchEvent(event);
146
+ }
147
+ async checkState() {
148
+ return AuthService.checkAuth().then(state => {
149
+ this.notifyStateChange(state);
150
+ return state;
151
+ });
152
+ }
153
+ }
154
+ AuthController._instance = null;
@@ -0,0 +1,22 @@
1
+ import { TheDoctor } from "../components/the-doctor/the-doctor.js";
2
+ import { BusCallback, CommandResponse } from "@pb33f/ranch";
3
+ export declare class BrokerController extends EventTarget {
4
+ private readonly specStreamChannel;
5
+ private readonly creditStreamChannel;
6
+ private readonly doctorServiceChannel;
7
+ private readonly busPort;
8
+ private readonly busHost;
9
+ private readonly busVersion;
10
+ private readonly bus;
11
+ readonly doc: TheDoctor;
12
+ readonly useTLS: boolean;
13
+ brokerConnectionId: string;
14
+ currentVersion: string;
15
+ constructor(doc: TheDoctor);
16
+ connectToBroker(): void;
17
+ doctorServiceHandler(): BusCallback<CommandResponse>;
18
+ whoAmI(): void;
19
+ startTheDoctor(): void;
20
+ specStreamHandler(): BusCallback<CommandResponse>;
21
+ creditStreamHandler(): BusCallback<CommandResponse>;
22
+ }
@@ -0,0 +1,107 @@
1
+ import { DefaultDocument } from "../components/the-doctor/the-doctor.js";
2
+ import { Command, CreditStreamChannel, DoctorServiceChannel, isBrokerResponse, QueuePrefix, SpecStreamChannel } from "../model/channels.js";
3
+ export class BrokerController extends EventTarget {
4
+ constructor(doc) {
5
+ super();
6
+ this.useTLS = false;
7
+ this.doc = doc;
8
+ this.bus = doc.bus;
9
+ this.doctorServiceChannel = this.bus.createChannel(DoctorServiceChannel);
10
+ this.specStreamChannel = this.bus.createChannel(SpecStreamChannel);
11
+ this.creditStreamChannel = this.bus.createChannel(CreditStreamChannel);
12
+ this.bus.mapChannelToBrokerDestination(QueuePrefix + DoctorServiceChannel, DoctorServiceChannel);
13
+ this.doctorServiceChannel.subscribe(this.doctorServiceHandler());
14
+ // extract port from session storage.
15
+ this.busPort = sessionStorage.getItem("pb33f-doctor-port");
16
+ this.busHost = sessionStorage.getItem("pb33f-doctor-host");
17
+ if (!this.busPort) {
18
+ this.busPort = "443"; // default port
19
+ }
20
+ if (!this.busHost) {
21
+ this.busHost = "doctor.pb33f.io"; // default host
22
+ }
23
+ const useTLS = sessionStorage.getItem("pb33f-doctor-tls");
24
+ if (useTLS && useTLS == 'true') {
25
+ this.useTLS = true;
26
+ }
27
+ }
28
+ connectToBroker() {
29
+ let protocol = "ws://";
30
+ if (this.useTLS) {
31
+ protocol = "wss://";
32
+ }
33
+ // configure wiretap broker.
34
+ const config = {
35
+ brokerURL: protocol + this.busHost + ':' + this.busPort + '/ranch',
36
+ heartbeatIncoming: 0,
37
+ heartbeatOutgoing: 0,
38
+ onConnect: () => {
39
+ console.log("💊 Connected to the %cOpenAPI Doctor%c, we are ready to communicate.", 'background: #0d1117; color: #62C4FFFF; font-weight: bold', 'color: default');
40
+ this.bus.mapChannels();
41
+ this.whoAmI();
42
+ }
43
+ };
44
+ this.bus.connectToBroker(config);
45
+ }
46
+ doctorServiceHandler() {
47
+ return (msg) => {
48
+ if (msg.payload?.payload != null) {
49
+ if (isBrokerResponse(msg.payload.payload)) {
50
+ this.brokerConnectionId = msg.payload.payload.broker;
51
+ this.doc.authController.associateBroker(this.brokerConnectionId).then(() => {
52
+ // check version from the server
53
+ const version = msg.payload.payload.version;
54
+ if (version !== "") {
55
+ this.currentVersion = version;
56
+ }
57
+ const memVersion = localStorage.getItem("pb33f-doctor-version");
58
+ if (memVersion) {
59
+ if (this.currentVersion != memVersion) {
60
+ this.doc.nukeWorkspaceHandler();
61
+ return;
62
+ }
63
+ }
64
+ else {
65
+ localStorage.setItem("pb33f-doctor-version", this.currentVersion);
66
+ }
67
+ console.log("💊 Welcome to the clinic, the %cdoctor %cis ready to see you. [" + "v" + version + "]", 'color: #62C4FFFF; font-weight: bold', 'color: default');
68
+ this.startTheDoctor();
69
+ });
70
+ }
71
+ }
72
+ };
73
+ }
74
+ whoAmI() {
75
+ this.bus.publish({
76
+ destination: "/p/q/" + DoctorServiceChannel,
77
+ body: JSON.stringify({ request: Command.WhoAmI }),
78
+ });
79
+ }
80
+ startTheDoctor() {
81
+ this.specStreamChannel.subscribe(this.specStreamHandler());
82
+ this.creditStreamChannel.subscribe(this.creditStreamHandler());
83
+ this.bus.mapChannelToBrokerDestination(QueuePrefix + SpecStreamChannel, SpecStreamChannel);
84
+ this.bus.mapChannelToBrokerDestination(QueuePrefix + CreditStreamChannel, CreditStreamChannel);
85
+ this.doc.boostrap();
86
+ }
87
+ specStreamHandler() {
88
+ return (msg) => {
89
+ if (msg.payload?.payload != null) {
90
+ // base64 decode the payload and update the editor!
91
+ const decoded = atob(msg.payload.payload);
92
+ if (this.doc.docBag) {
93
+ this.doc.docBag.set(DefaultDocument, decoded);
94
+ }
95
+ this.doc.editor?.setValue(decoded, true);
96
+ this.doc.requestUpdate();
97
+ }
98
+ };
99
+ }
100
+ creditStreamHandler() {
101
+ return (msg) => {
102
+ if (msg.payload?.payload != null) {
103
+ this.doc.creditTicker.credits = parseInt(msg.payload.payload);
104
+ }
105
+ };
106
+ }
107
+ }
@@ -0,0 +1,6 @@
1
+ import { TheDoctor } from "../components/the-doctor/the-doctor.js";
2
+ export declare class DiagnosticController extends EventTarget {
3
+ doc: TheDoctor;
4
+ constructor(doc: TheDoctor);
5
+ lintSpec(value: string, url?: string): void;
6
+ }