@financial-times/custom-code-component 2.0.1-alpha.11 → 2.0.1-alpha.5
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/dist/{CustomCodeComponent.js → custom-code-component.js} +156 -157
- package/dist/webcomponent/src/custom-code-component.d.ts +55 -0
- package/dist/webcomponent/src/environment.d.ts +15 -0
- package/dist/webcomponent/src/errors.d.ts +27 -0
- package/dist/webcomponent/src/events.d.ts +10 -0
- package/dist/webcomponent/src/get-trace.d.ts +8 -0
- package/dist/{CustomCodeComponent.d.ts → webcomponent/src/index.d.ts} +1 -3
- package/dist/webcomponent/src/logger.d.ts +20 -0
- package/dist/webcomponent/src/path.d.ts +23 -0
- package/dist/webcomponent/src/tracking.d.ts +32 -0
- package/dist/webcomponent/src/util.d.ts +33 -0
- package/dist/webcomponent/test/environment.test.d.ts +1 -0
- package/dist/webcomponent/test/error-handling.test.d.ts +8 -0
- package/dist/webcomponent/test/example.d.ts +11 -0
- package/dist/webcomponent/test/generate-readable-stream.d.ts +8 -0
- package/dist/webcomponent/test/path.test.d.ts +5 -0
- package/dist/webcomponent/test/ssr.test.d.ts +4 -0
- package/dist/webcomponent/test/utils.test.d.ts +1 -0
- package/dist/webcomponent/vite.config.d.ts +2 -0
- package/dist/webcomponent/vitest.config.d.ts +2 -0
- package/package.json +5 -5
- package/src/custom-code-component.ts +66 -72
- package/src/environment.ts +3 -3
- package/dist/CustomCodeComponent.js.map +0 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* Main component definition for custom-code-component
|
|
4
|
+
*/
|
|
5
|
+
import type { ContentTree } from "@financial-times/content-tree";
|
|
6
|
+
import { BaseRenderer } from "../../ccc-sdk/src/renderers/BaseRenderer";
|
|
7
|
+
import Tracking from "./tracking";
|
|
8
|
+
import { Logger } from "./logger";
|
|
9
|
+
import { ComponentPath } from "./path";
|
|
10
|
+
export declare class FTCustomCodeComponent extends HTMLElement {
|
|
11
|
+
app?: typeof BaseRenderer.prototype.render;
|
|
12
|
+
mode: "closed" | "open";
|
|
13
|
+
RESERVED_ATTRS: Set<string>;
|
|
14
|
+
source?: string;
|
|
15
|
+
tracking?: Tracking;
|
|
16
|
+
lightRoot: ChildNode[];
|
|
17
|
+
component: ComponentPath;
|
|
18
|
+
log: Logger;
|
|
19
|
+
constructor();
|
|
20
|
+
connectedCallback(): Promise<void>;
|
|
21
|
+
emitError(error: Error): void;
|
|
22
|
+
disconnectedCallback(): void;
|
|
23
|
+
channel: MessageChannel;
|
|
24
|
+
onmessage(): void;
|
|
25
|
+
onunmount(root?: any): void;
|
|
26
|
+
onready(app: Promise<void>): Promise<void>;
|
|
27
|
+
postMessage(event: any): void;
|
|
28
|
+
mount(prerendered?: ShadowRoot | null): Promise<void>;
|
|
29
|
+
unmount(e: Error): void;
|
|
30
|
+
load(): Promise<(shadowRoot: ShadowRoot, attrs: any, ssr?: boolean) => {
|
|
31
|
+
unmount: (root: any) => void;
|
|
32
|
+
onmessage: {
|
|
33
|
+
(...data: any[]): void;
|
|
34
|
+
(message?: any, ...optionalParams: any[]): void;
|
|
35
|
+
};
|
|
36
|
+
ready: Promise<void>;
|
|
37
|
+
}>;
|
|
38
|
+
initTracking: () => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export interface CustomCodeComponent extends ContentTree.Node {
|
|
41
|
+
type: "CustomCodeComponent";
|
|
42
|
+
path: string;
|
|
43
|
+
versionRange: string;
|
|
44
|
+
altText: string;
|
|
45
|
+
lastModified: string;
|
|
46
|
+
fallbackImage?: ContentTree.Image;
|
|
47
|
+
displayFallbackText: boolean;
|
|
48
|
+
layout: "in-line" | "mid-grid" | "full-grid" | "full-bleed";
|
|
49
|
+
attributes: {
|
|
50
|
+
[key: string]: string | boolean | undefined;
|
|
51
|
+
} | {
|
|
52
|
+
children?: CustomCodeComponent | Array<CustomCodeComponent>;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export type { FTCustomCodeComponent as CCCHTMLElement };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assigns a test URL based on the provided testEnv value.
|
|
3
|
+
*
|
|
4
|
+
* @param testEnv - A string indicating test environment setting
|
|
5
|
+
* @returns A `URL` object if valid and safe, or `undefined` if invalid.
|
|
6
|
+
*/
|
|
7
|
+
export declare function assignTestURL(testEnv: string | null): URL | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Checks whether the given test URL can establish a successful WebSocket connection,
|
|
10
|
+
* which indicates a live test environment (e.g., Vite HMR is active).
|
|
11
|
+
*
|
|
12
|
+
* @param testUrl - The test environment URL to check.
|
|
13
|
+
* @returns A promise that resolves to true if WebSocket connection is open, otherwise false.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useComponentTestEnv(testUrl?: URL): Promise<boolean>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the base CCC component error class. These are raised when the component being loaded errors
|
|
3
|
+
*/
|
|
4
|
+
import { ComponentPath, DetailType } from "./path";
|
|
5
|
+
export declare class CCCError extends Error {
|
|
6
|
+
component: ComponentPath | null;
|
|
7
|
+
source?: string;
|
|
8
|
+
constructor(message: string | null, detail?: DetailType);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* This class is used to raise errors that occur during the import of the CCC component app
|
|
12
|
+
*/
|
|
13
|
+
export declare class CCCImportError extends CCCError {
|
|
14
|
+
constructor(message: string, detail: DetailType);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* This class is used to raise errors that occur during the rendering of the CCC component app
|
|
18
|
+
*/
|
|
19
|
+
export declare class CCCRenderError extends CCCError {
|
|
20
|
+
constructor(message: string, detail: DetailType);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This class is used to raise errors that occur as a result of the CCC component app timing out
|
|
24
|
+
*/
|
|
25
|
+
export declare class CCCTimeoutError extends CCCError {
|
|
26
|
+
constructor(detail: DetailType);
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComponentPath } from "./path";
|
|
2
|
+
export declare class CCCConnectedEvent extends Event {
|
|
3
|
+
static eventType: string;
|
|
4
|
+
component: ComponentPath;
|
|
5
|
+
source?: string;
|
|
6
|
+
constructor(detail: {
|
|
7
|
+
component: ComponentPath;
|
|
8
|
+
source?: string;
|
|
9
|
+
}, opts?: EventInit);
|
|
10
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const LogLevel: Readonly<{
|
|
2
|
+
DEBUG: 0;
|
|
3
|
+
INFO: 1;
|
|
4
|
+
WARN: 2;
|
|
5
|
+
ERROR: 3;
|
|
6
|
+
TEST: 4;
|
|
7
|
+
DEFAULT: 2;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function convertStringLogLevel(value: string | null): 0 | 2 | 1 | 3 | 4;
|
|
10
|
+
export declare class Logger {
|
|
11
|
+
level: number;
|
|
12
|
+
constructor({ level }?: {
|
|
13
|
+
level: number;
|
|
14
|
+
});
|
|
15
|
+
debug(...args: any[]): void;
|
|
16
|
+
log: (...args: any[]) => void;
|
|
17
|
+
info(...args: any[]): void;
|
|
18
|
+
warn(...args: any[]): void;
|
|
19
|
+
error(...args: any[]): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ComponentPathType = {
|
|
2
|
+
org: string;
|
|
3
|
+
repo: string;
|
|
4
|
+
component: string;
|
|
5
|
+
versionRange: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class ComponentPath {
|
|
8
|
+
org: string;
|
|
9
|
+
repo: string;
|
|
10
|
+
component: string;
|
|
11
|
+
versionRange: string;
|
|
12
|
+
constructor(path: ComponentPathType | string);
|
|
13
|
+
set path(path: ComponentPathType | string);
|
|
14
|
+
get path(): string;
|
|
15
|
+
toString(): string;
|
|
16
|
+
static fromString(path: string | null, v?: string | null): ComponentPath;
|
|
17
|
+
}
|
|
18
|
+
export type DetailType = {
|
|
19
|
+
component: ComponentPath;
|
|
20
|
+
source?: string;
|
|
21
|
+
cause?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function isValidComponentPathObject(value: unknown): value is ComponentPathType;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Logger } from "./logger";
|
|
2
|
+
declare class Tracking {
|
|
3
|
+
cccId: string;
|
|
4
|
+
cccName: string;
|
|
5
|
+
subtype: string;
|
|
6
|
+
teamName: string;
|
|
7
|
+
shadowRoot: ShadowRoot | null;
|
|
8
|
+
category: string;
|
|
9
|
+
elements: string | string[];
|
|
10
|
+
isInitialised: boolean;
|
|
11
|
+
log: Logger;
|
|
12
|
+
constructor({ id, name, subtype, teamName, shadowRoot, category, elements, logger, }: {
|
|
13
|
+
id?: string;
|
|
14
|
+
name: string;
|
|
15
|
+
subtype: string;
|
|
16
|
+
teamName?: string;
|
|
17
|
+
shadowRoot: ShadowRoot | null;
|
|
18
|
+
category?: string;
|
|
19
|
+
elements?: string | string[];
|
|
20
|
+
logger: Logger;
|
|
21
|
+
});
|
|
22
|
+
getEventProperties(event: any): {
|
|
23
|
+
[k: string]: any;
|
|
24
|
+
};
|
|
25
|
+
handleClickEvent(eventData: {
|
|
26
|
+
action: string;
|
|
27
|
+
category: string;
|
|
28
|
+
}, root: Element): (clickEvent: Event, clickElement: HTMLElement) => void;
|
|
29
|
+
sendSpoorEvent(triggerAction: any, extraDetail: any): void;
|
|
30
|
+
init(id: string): void;
|
|
31
|
+
}
|
|
32
|
+
export default Tracking;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Used to convert camelCase to kebab-case
|
|
3
|
+
* @param str
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
export declare const kebabize: (str: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Checks if the provided host is part of the allowed test environments.
|
|
9
|
+
*
|
|
10
|
+
* @param host - The hostname to check.
|
|
11
|
+
* @returns True if the hostname is a safe test environment, false otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isSafeTestEnv(host: string | undefined): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Checks if the current window location hostname is considered a local environment.
|
|
16
|
+
*
|
|
17
|
+
* @returns True if the hostname is local, false otherwise.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isLocalEnv(): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Checks if the current window location host is one of the Spark environments.
|
|
22
|
+
*
|
|
23
|
+
* @returns True if the host is spark.ft.com or spark-staging.ft.com, false otherwise.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isSparkEnv(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if the given hostname is in the provided allowlist.
|
|
28
|
+
*
|
|
29
|
+
* @param allowlist - A list of allowed hostnames or RegExp matchers.
|
|
30
|
+
* @param hostname - The hostname to validate.
|
|
31
|
+
* @returns True if the hostname matches any item in the allowlist, false otherwise.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isAllowed(allowlist: (string | RegExp)[], hostname: string | undefined): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactRenderer } from "../../ccc-sdk/src/renderers/react/ReactRenderer";
|
|
2
|
+
export declare const renderer: ReactRenderer;
|
|
3
|
+
declare const _default: (shadowRoot: ShadowRoot, attrs: any, ssr?: boolean) => {
|
|
4
|
+
unmount: (root: any) => void;
|
|
5
|
+
onmessage: {
|
|
6
|
+
(...data: any[]): void;
|
|
7
|
+
(message?: any, ...optionalParams: any[]): void;
|
|
8
|
+
};
|
|
9
|
+
ready: Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/custom-code-component",
|
|
3
|
-
"version": "2.0.1-alpha.
|
|
3
|
+
"version": "2.0.1-alpha.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"import": "./dist/custom-code-component.js",
|
|
8
|
+
"types": "./dist/custom-code-component.d.ts"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"msw": "^2.7.3",
|
|
31
31
|
"playwright": "^1.50.1",
|
|
32
32
|
"typescript": "^5.2.2",
|
|
33
|
-
"vite": "^
|
|
34
|
-
"vite-plugin-dts": "^
|
|
33
|
+
"vite": "^4.4.9",
|
|
34
|
+
"vite-plugin-dts": "^3.6.0",
|
|
35
35
|
"vitest": "^3.0.6"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
@@ -34,17 +34,25 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
34
34
|
|
|
35
35
|
source?: string;
|
|
36
36
|
tracking?: Tracking;
|
|
37
|
-
lightRoot
|
|
38
|
-
component
|
|
37
|
+
lightRoot: ChildNode[];
|
|
38
|
+
component: ComponentPath;
|
|
39
39
|
|
|
40
40
|
log: Logger;
|
|
41
41
|
|
|
42
42
|
constructor() {
|
|
43
43
|
super();
|
|
44
|
+
|
|
44
45
|
this.log = new Logger({
|
|
45
46
|
level: convertStringLogLevel(this.getAttribute("log")),
|
|
46
47
|
});
|
|
47
48
|
|
|
49
|
+
const path = this.getAttribute("path");
|
|
50
|
+
const versionRange = this.getAttribute("version");
|
|
51
|
+
this.component = ComponentPath.fromString(path, versionRange);
|
|
52
|
+
|
|
53
|
+
// Backup the light root to restore in case of error
|
|
54
|
+
this.lightRoot = Array.from(this.childNodes);
|
|
55
|
+
|
|
48
56
|
const supportsDeclarative =
|
|
49
57
|
HTMLElement.prototype.hasOwnProperty("attachInternals");
|
|
50
58
|
|
|
@@ -57,12 +65,6 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
57
65
|
|
|
58
66
|
async connectedCallback() {
|
|
59
67
|
try {
|
|
60
|
-
const path = this.getAttribute("path");
|
|
61
|
-
const versionRange = this.getAttribute("version");
|
|
62
|
-
this.component = ComponentPath.fromString(path, versionRange);
|
|
63
|
-
|
|
64
|
-
// Backup the light root to restore in case of error
|
|
65
|
-
this.lightRoot = Array.from(this.childNodes);
|
|
66
68
|
this.app = await this.load();
|
|
67
69
|
await this.mount();
|
|
68
70
|
await this.initTracking();
|
|
@@ -127,64 +129,61 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
127
129
|
try {
|
|
128
130
|
this.mode =
|
|
129
131
|
this.getAttribute("shadow-open") == "false" ? "closed" : "open";
|
|
130
|
-
if (this.component) {
|
|
131
|
-
|
|
132
|
-
this.dispatchEvent(
|
|
133
|
-
new CCCConnectedEvent({
|
|
134
|
-
component: this.component,
|
|
135
|
-
source: this.source,
|
|
136
|
-
})
|
|
137
|
-
);
|
|
138
132
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
this.dispatchEvent(
|
|
134
|
+
new CCCConnectedEvent({
|
|
135
|
+
component: this.component,
|
|
136
|
+
source: this.source,
|
|
137
|
+
})
|
|
138
|
+
);
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
140
|
+
this.dataset.cccReady = "true";
|
|
141
|
+
delete this.dataset.cccError;
|
|
146
142
|
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
if (!this.app) {
|
|
144
|
+
throw new Error("CCC mounted without App");
|
|
145
|
+
}
|
|
149
146
|
|
|
150
|
-
|
|
147
|
+
const ssr = this.shadowRoot !== null;
|
|
148
|
+
const shadow = this.shadowRoot ?? this.attachShadow({ mode: this.mode });
|
|
151
149
|
|
|
152
|
-
|
|
153
|
-
[...this.attributes]
|
|
154
|
-
.filter((attribute) => !this.RESERVED_ATTRS.has(attribute.name))
|
|
155
|
-
.map((attribute) => [attribute.name, attribute.value])
|
|
156
|
-
);
|
|
150
|
+
const data = JSON.parse(this.getAttribute("data-component-props")!);
|
|
157
151
|
|
|
158
|
-
|
|
159
|
-
this.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
shadowRoot: this.shadowRoot,
|
|
164
|
-
logger: this.log,
|
|
165
|
-
});
|
|
152
|
+
const extraProps = Object.fromEntries(
|
|
153
|
+
[...this.attributes]
|
|
154
|
+
.filter((attribute) => !this.RESERVED_ATTRS.has(attribute.name))
|
|
155
|
+
.map((attribute) => [attribute.name, attribute.value])
|
|
156
|
+
);
|
|
166
157
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
158
|
+
// Create tracking instance
|
|
159
|
+
this.tracking = new Tracking({
|
|
160
|
+
name: this.component.toString(),
|
|
161
|
+
subtype: "interactive",
|
|
162
|
+
teamName: "djd",
|
|
163
|
+
shadowRoot: this.shadowRoot,
|
|
164
|
+
logger: this.log,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const { unmount, onmessage, ready } =
|
|
168
|
+
this.app(
|
|
169
|
+
shadow,
|
|
170
|
+
{
|
|
171
|
+
...extraProps,
|
|
172
|
+
data,
|
|
173
|
+
port: this.channel.port2,
|
|
174
|
+
tracking: this.tracking,
|
|
175
|
+
prerendered: !!prerendered,
|
|
176
|
+
children: this.children,
|
|
177
|
+
},
|
|
178
|
+
ssr
|
|
179
|
+
) || {};
|
|
180
|
+
|
|
181
|
+
if (unmount) this.onunmount = unmount;
|
|
182
|
+
if (onmessage) this.onmessage = onmessage;
|
|
183
|
+
if (ready) this.onready(ready);
|
|
185
184
|
} catch (err) {
|
|
186
185
|
this.log.info(
|
|
187
|
-
`<custom-code-component> uncaught error during mount from ${this.component
|
|
186
|
+
`<custom-code-component> uncaught error during mount from ${this.component.toString()}`
|
|
188
187
|
);
|
|
189
188
|
this.log.error(err);
|
|
190
189
|
|
|
@@ -195,20 +194,15 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
195
194
|
// Called in top-level error handler
|
|
196
195
|
// Replace shadow root with light DOM children on error
|
|
197
196
|
unmount(e: Error) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
delete this.dataset.cccReady;
|
|
205
|
-
}
|
|
197
|
+
this.onunmount();
|
|
198
|
+
this.shadowRoot?.replaceChildren(...this.lightRoot);
|
|
199
|
+
|
|
200
|
+
if (!this.dataset.cccError)
|
|
201
|
+
this.dataset.cccError = kebabize(e.name.replace("CCC", ""));
|
|
202
|
+
delete this.dataset.cccReady;
|
|
206
203
|
}
|
|
207
204
|
|
|
208
205
|
async load() {
|
|
209
|
-
if (!this.component) {
|
|
210
|
-
throw new Error("No path found")
|
|
211
|
-
}
|
|
212
206
|
const path = this.getAttribute("path");
|
|
213
207
|
const componentVersionRange = this.getAttribute("version");
|
|
214
208
|
const timeout = Number(this.getAttribute("load-timeout") || 10000);
|
|
@@ -231,7 +225,7 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
231
225
|
this.log.error("CCC import timeout error");
|
|
232
226
|
reject(
|
|
233
227
|
new CCCTimeoutError({
|
|
234
|
-
component: this.component
|
|
228
|
+
component: this.component,
|
|
235
229
|
source: this.source,
|
|
236
230
|
})
|
|
237
231
|
);
|
|
@@ -247,7 +241,7 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
247
241
|
throw new CCCImportError(
|
|
248
242
|
"No component renderer default export found",
|
|
249
243
|
{
|
|
250
|
-
component: this.component
|
|
244
|
+
component: this.component,
|
|
251
245
|
source: this.source,
|
|
252
246
|
}
|
|
253
247
|
);
|
|
@@ -258,7 +252,7 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
258
252
|
if (e instanceof Error && !(e instanceof CCCImportError)) {
|
|
259
253
|
reject(
|
|
260
254
|
new CCCImportError(e.message, {
|
|
261
|
-
component: this.component
|
|
255
|
+
component: this.component,
|
|
262
256
|
source: this.source,
|
|
263
257
|
})
|
|
264
258
|
);
|
|
@@ -269,7 +263,7 @@ export class FTCustomCodeComponent extends HTMLElement {
|
|
|
269
263
|
} else {
|
|
270
264
|
clearTimeout(to);
|
|
271
265
|
throw new CCCImportError(`Unable to mount ${path}`, {
|
|
272
|
-
component: this.component
|
|
266
|
+
component: this.component,
|
|
273
267
|
source: this.source,
|
|
274
268
|
});
|
|
275
269
|
}
|
package/src/environment.ts
CHANGED
|
@@ -8,16 +8,15 @@ import { isLocalEnv, isSafeTestEnv, isSparkEnv } from "./util"
|
|
|
8
8
|
* @returns A `URL` object if valid and safe, or `undefined` if invalid.
|
|
9
9
|
*/
|
|
10
10
|
export function assignTestURL(testEnv: string | null): URL | undefined {
|
|
11
|
-
if (testEnv
|
|
11
|
+
if (!testEnv) {
|
|
12
12
|
return
|
|
13
13
|
}
|
|
14
|
-
|
|
15
14
|
let testUrl
|
|
16
15
|
const defaultTestUrl = new URL('http://localhost:5173')
|
|
17
16
|
|
|
18
17
|
try {
|
|
19
18
|
if (typeof testEnv === 'string') {
|
|
20
|
-
if (
|
|
19
|
+
if (testEnv === 'true' && isLocalEnv()) {
|
|
21
20
|
testUrl = defaultTestUrl
|
|
22
21
|
} else {
|
|
23
22
|
const hasProtocol = testEnv.startsWith('http://') || testEnv.startsWith('https://')
|
|
@@ -67,6 +66,7 @@ export async function useComponentTestEnv(testUrl?: URL): Promise<boolean> {
|
|
|
67
66
|
}, { once: true });
|
|
68
67
|
});
|
|
69
68
|
} catch (err) {
|
|
69
|
+
console.error("WebSocket creation failed:", err);
|
|
70
70
|
return Promise.resolve(false);
|
|
71
71
|
}
|
|
72
72
|
}
|