@web-applets/sdk 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,14 @@
1
1
  export interface AppletManifest {
2
2
  name?: string;
3
3
  short_name?: string;
4
- icons: AppletIcons;
4
+ icons: ManifestIcon[];
5
5
  description?: string;
6
- icon?: string;
7
6
  display?: string;
8
7
  start_url?: string;
9
8
  unsafe?: boolean;
10
9
  actions?: AppletAction[];
11
10
  }
12
- export interface AppletIcons {
11
+ export interface ManifestIcon {
13
12
  src: string;
14
13
  purpose?: string;
15
14
  sizes?: string;
@@ -13,7 +13,10 @@ export async function loadManifest(pageUrl) {
13
13
  const manifestUrl = parseUrl(href, pageUrl);
14
14
  const manifestRequest = await fetch(manifestUrl);
15
15
  manifest = await manifestRequest.json();
16
- // TODO: Add verification this is a valid manifest
16
+ manifest.icons = manifest.icons.map((icon) => {
17
+ icon.src = parseUrl(icon.src, pageUrl);
18
+ return icon;
19
+ });
17
20
  }
18
21
  catch (e) {
19
22
  return;
package/dist/utils.js CHANGED
@@ -1,8 +1,24 @@
1
1
  // Adds http/https to URLs, and prepends with window location if relative
2
2
  export function parseUrl(url, base) {
3
- if (url)
4
- url = URL.parse(url, base ?? window.location.href).href;
5
- return trimTrailingSlash(url);
3
+ if (!url)
4
+ return '';
5
+ try {
6
+ // If the base URL is provided, ensure it has a trailing slash for proper path resolution
7
+ if (base) {
8
+ // Don't add trailing slash if the base already ends with a file extension
9
+ if (!base.match(/\.[a-zA-Z0-9]+$/)) {
10
+ base = base.endsWith('/') ? base : base + '/';
11
+ }
12
+ }
13
+ // Use URL constructor to properly resolve relative paths
14
+ const resolvedUrl = new URL(url, base ?? window.location.href);
15
+ return trimTrailingSlash(resolvedUrl.href);
16
+ }
17
+ catch (e) {
18
+ // Return original URL if parsing fails
19
+ console.warn('Failed to parse URL:', e);
20
+ return url;
21
+ }
6
22
  }
7
23
  function trimTrailingSlash(url) {
8
24
  if (url.endsWith('/')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@web-applets/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "The Web Applets SDK, for creating & hosting Web Applets.",
5
5
  "author": "Rupert Manfredi <rupert@unternet.co>",
6
6
  "license": "MIT",
@@ -1,31 +0,0 @@
1
- import { AppletAction, AppletMessage, ActionParams, AppletManifest, AppletDataEvent, AppletResizeEvent, AppletActionsEvent, AppletMessageRelay } from './shared';
2
- interface LoadOpts {
3
- unsafe?: boolean;
4
- }
5
- declare function load(url: string, container?: HTMLIFrameElement, opts?: LoadOpts): Promise<Applet>;
6
- interface AppletOptions {
7
- manifest: AppletManifest;
8
- container: HTMLIFrameElement;
9
- }
10
- declare class Applet<T = any> extends EventTarget {
11
- #private;
12
- messageRelay: AppletMessageRelay;
13
- url: string;
14
- actions: AppletAction[];
15
- container: HTMLIFrameElement;
16
- type: string;
17
- constructor(options: AppletOptions);
18
- initializeListeners(): void;
19
- get data(): T;
20
- set data(data: T);
21
- get manifest(): AppletManifest;
22
- onresize(event: AppletResizeEvent): void;
23
- onactions(event: AppletActionsEvent): void;
24
- ondata(event: AppletDataEvent): void;
25
- disconnect(): void;
26
- dispatchAction(actionId: string, params: ActionParams): Promise<AppletMessage>;
27
- }
28
- export declare const applets: {
29
- load: typeof load;
30
- };
31
- export { Applet };
package/dist/core/host.js DELETED
@@ -1,134 +0,0 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _Applet_manifest, _Applet_data;
13
- import { AppletMessage, AppletDataMessage, AppletInitMessage, AppletDataEvent, AppletResizeEvent, AppletActionsEvent, AppletMessageRelay, } from './shared';
14
- import { parseUrl } from '../lib/utils';
15
- // Container for initializing applets without an explicit container
16
- const hiddenContainer = document.createElement('iframe');
17
- hiddenContainer.style.display = 'none';
18
- document.body.appendChild(hiddenContainer);
19
- const defaultOpts = {
20
- unsafe: false,
21
- };
22
- // Load an applet object from a URL
23
- async function load(url, container, opts) {
24
- const _opts = Object.assign(defaultOpts, opts ?? {});
25
- if (!container)
26
- container = hiddenContainer;
27
- url = parseUrl(url);
28
- const manifest = await loadManifest(`${url}`);
29
- // If unsafe enabled, allow same origin sandbox
30
- // This is required for e.g. YouTube embeds
31
- if (_opts.unsafe && manifest.unsafe) {
32
- container.setAttribute('sandbox', 'allow-scripts allow-forms allow-same-origin');
33
- }
34
- else {
35
- container.setAttribute('sandbox', 'allow-scripts allow-forms');
36
- }
37
- // Load the applet
38
- const applet = new Applet({
39
- manifest,
40
- container,
41
- });
42
- return new Promise((resolve) => {
43
- applet.messageRelay.on('ready', () => {
44
- resolve(applet);
45
- });
46
- });
47
- }
48
- class Applet extends EventTarget {
49
- constructor(options) {
50
- super();
51
- this.actions = [];
52
- _Applet_manifest.set(this, void 0);
53
- this.type = 'host';
54
- _Applet_data.set(this, void 0);
55
- this.container = options.container;
56
- this.container.src = options.manifest.start_url;
57
- this.messageRelay = new AppletMessageRelay(this.container.contentWindow);
58
- __classPrivateFieldSet(this, _Applet_manifest, options.manifest, "f");
59
- this.initializeListeners();
60
- this.messageRelay.on('ready', () => {
61
- this.messageRelay.send(new AppletInitMessage({ manifest: options.manifest }));
62
- });
63
- }
64
- initializeListeners() {
65
- this.messageRelay.on('data', (message) => {
66
- __classPrivateFieldSet(this, _Applet_data, message.data, "f");
67
- const dataEvent = new AppletDataEvent({ data: message.data });
68
- if (typeof this.ondata === 'function')
69
- this.ondata(dataEvent);
70
- this.dispatchEvent(dataEvent);
71
- });
72
- this.messageRelay.on('resize', (message) => {
73
- const resizeEvent = new AppletResizeEvent({
74
- dimensions: message.dimensions,
75
- });
76
- if (typeof this.onresize === 'function')
77
- this.onresize(resizeEvent);
78
- this.dispatchEvent(resizeEvent);
79
- });
80
- this.messageRelay.on('actions', (message) => {
81
- this.actions = message.actions;
82
- const actionsEvent = new AppletActionsEvent({ actions: message.actions });
83
- if (typeof this.onactions === 'function')
84
- this.onactions(actionsEvent);
85
- this.dispatchEvent(actionsEvent);
86
- });
87
- }
88
- get data() {
89
- return __classPrivateFieldGet(this, _Applet_data, "f");
90
- }
91
- set data(data) {
92
- __classPrivateFieldSet(this, _Applet_data, data, "f");
93
- this.messageRelay.send(new AppletDataMessage({ data }));
94
- }
95
- get manifest() {
96
- return __classPrivateFieldGet(this, _Applet_manifest, "f");
97
- }
98
- onresize(event) { }
99
- onactions(event) { }
100
- ondata(event) { }
101
- disconnect() {
102
- this.container.src = 'about:blank';
103
- }
104
- async dispatchAction(actionId, params) {
105
- const actionMessage = new AppletMessage('action', {
106
- actionId,
107
- params,
108
- });
109
- return await this.messageRelay.send(actionMessage);
110
- }
111
- }
112
- _Applet_manifest = new WeakMap(), _Applet_data = new WeakMap();
113
- // Loads a manifest and parses the JSON
114
- async function loadManifest(baseUrl) {
115
- baseUrl = parseUrl(baseUrl);
116
- let manifest;
117
- try {
118
- const request = await fetch(`${baseUrl}/manifest.json`);
119
- manifest = await request.json();
120
- // TODO: Add verification this is a valid manifest
121
- }
122
- catch (e) {
123
- console.error(e.message);
124
- }
125
- manifest.start_url = manifest.start_url
126
- ? parseUrl(manifest.start_url, baseUrl)
127
- : baseUrl;
128
- return manifest;
129
- }
130
- // Exports
131
- export const applets = {
132
- load,
133
- };
134
- export { Applet };
@@ -1,17 +0,0 @@
1
- import { AppletAction } from '../core/shared';
2
- export declare function parseUrl(url: string, base?: string): string;
3
- export declare function createOpenAISchemaForAction(action: AppletAction): {
4
- strict: boolean;
5
- name: string;
6
- schema: {
7
- type: string;
8
- required: string[];
9
- properties: {
10
- id: {
11
- type: string;
12
- };
13
- params: import("../core/shared").JSONSchemaProperties;
14
- };
15
- additionalProperties: boolean;
16
- };
17
- };
package/dist/lib/utils.js DELETED
@@ -1,37 +0,0 @@
1
- // Adds http/https to URLs, and prepends with window location if relative
2
- export function parseUrl(url, base) {
3
- if (['http', 'https'].includes(url.split('://')[0])) {
4
- return url;
5
- }
6
- let path = trimSlashes(url);
7
- url = `${base || window.location.origin}/${path}`;
8
- return url;
9
- }
10
- function trimSlashes(str) {
11
- return str.replace(/^\/+|\/+$/g, '');
12
- }
13
- export function createOpenAISchemaForAction(action) {
14
- return {
15
- strict: true,
16
- name: 'action_schema',
17
- schema: {
18
- type: 'object',
19
- required: Object.keys(action),
20
- properties: {
21
- id: { type: 'string' },
22
- params: action.params,
23
- },
24
- additionalProperties: false,
25
- },
26
- };
27
- }
28
- // export async function loadAppletManifest(url: string): Promise<AppletManifest> {
29
- // url = parseUrl(url);
30
- // const request = await fetch(`${url}/manifest.json`);
31
- // const appletManifest = await request.json();
32
- // if (appletManifest.type !== 'applet') {
33
- // throw new Error("URL doesn't point to a valid applet manifest.");
34
- // }
35
- // appletManifest.entrypoint = parseUrl(appletManifest.entrypoint, url);
36
- // return appletManifest;
37
- // }