@web-applets/sdk 0.1.1 → 0.1.2

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.
@@ -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
- // }