@web-applets/sdk 0.1.1 → 0.1.3
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/README.md +67 -61
- package/dist/core/context.d.ts +2 -2
- package/dist/core/shared.d.ts +11 -8
- package/dist/core/shared.js +4 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +0 -16
- package/dist/utils.js +19 -19
- package/package.json +1 -1
- package/dist/core/host.d.ts +0 -31
- package/dist/core/host.js +0 -134
- package/dist/lib/utils.d.ts +0 -17
- package/dist/lib/utils.js +0 -37
package/README.md
CHANGED
@@ -1,29 +1,44 @@
|
|
1
1
|
# Web Applets
|
2
2
|
|
3
|
-
> An open spec & SDK for creating apps that agents can use.
|
3
|
+
> An open spec & SDK for creating web apps that agents can use.
|
4
4
|
|
5
|
-
💌 [Mailing List](https://groups.google.com/a/unternet.co/g/community)
|
5
|
+
👾 [Community Discord](https://discord.gg/2aUvMe8HrC) | 💌 [Mailing List](https://groups.google.com/a/unternet.co/g/community)
|
6
6
|
|
7
|
-
|
7
|
+
[](https://builders.mozilla.org/)
|
8
|
+
|
9
|
+
Web Applets is a [Mozilla Builders](https://builders.mozilla.org/) project.
|
8
10
|
|
9
|
-
|
11
|
+
## What is it?
|
10
12
|
|
11
|
-
|
13
|
+
**Web Applets is an open specification for building software that both humans and AI can understand and use together.** Instead of forcing AI to operate traditional point-and-click apps built for humans, Web Applets creates a new kind of web software designed for human-AI collaboration.
|
12
14
|
|
13
15
|

|
14
16
|
|
15
|
-
|
17
|
+
## Why?
|
18
|
+
|
19
|
+
[Unternet](https://unternet.co) is building a new, intelligent user agent that can do things for you across the web. As part of that effort, we needed a way to actuate an embedded web app. You can do this with a computer use model, but for many use cases it's not suitable to point and click around in a virtual browser. Why make a computer talk to another computer via a clumsy web interface when they can just talk directly?
|
20
|
+
|
21
|
+
Web Applets lets you define a simple, computer-readable API for a web app running in a browser, webview, or iframe. You can send it actions as JSON objects, which an LLM can easily create (see [OpenAI's structured JSON endpoint](https://openai.com/index/introducing-structured-outputs-in-the-api/)), and they can update their UI instantly in-place. Plus, you can expose the internal state of the applets to the model so you can do cool stuff like chat to a map.
|
22
|
+
|
23
|
+
We wanted anyone to be able to build these actions into their own third-party applets and distribute them. So, we extended the web & made it available to everyone!
|
24
|
+
|
25
|
+
## Getting started
|
26
|
+
|
27
|
+
Create a new web app using our CLI:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
npx @web-applets/create
|
31
|
+
```
|
32
|
+
|
33
|
+
Inside the generated folder, you'll find a basic web app setup:
|
16
34
|
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
20
|
-
- **Local-First:** Runs in your environment, keeping your data under your control
|
21
|
-
- **Composable:** Applets can work together, sharing context and state
|
22
|
-
- **Open Standard:** Designed for interoperability across clients, not platform lock-in
|
35
|
+
- `public/manifest.json`: A web app manifest, where you can define initial actions, add icons, etc.
|
36
|
+
- `index.html`: Much like a website, this holds the main page for your applet
|
37
|
+
- `src/main.ts`: Declares functions that respond to each action, and a render function that updates the view based on state
|
23
38
|
|
24
|
-
|
39
|
+
> Want to use React? Svelte? Vue? – No problem, just install the dependencies and create an app the way you normally would in a website. So long as you're receiving the action events, it will all just work.
|
25
40
|
|
26
|
-
|
41
|
+
Now let's build out a basic web applet that will say hello when we send it an action:
|
27
42
|
|
28
43
|
`index.html`:
|
29
44
|
|
@@ -37,7 +52,29 @@ Let's say we have a simple website that says hello. It might look something like
|
|
37
52
|
</html>
|
38
53
|
```
|
39
54
|
|
40
|
-
Let's add some Web Applets functionality, so this can respond to a `set_name`
|
55
|
+
Let's add some Web Applets functionality, so this can respond to a `set_name` action:
|
56
|
+
|
57
|
+
`public/manifest.json`:
|
58
|
+
|
59
|
+
```json
|
60
|
+
{
|
61
|
+
// ...
|
62
|
+
"actions": [
|
63
|
+
{
|
64
|
+
"id": "set_name",
|
65
|
+
"description": "Sets the name of the user.",
|
66
|
+
"parameters": {
|
67
|
+
"type": "object",
|
68
|
+
"properties": {
|
69
|
+
"name": {
|
70
|
+
"type": "string"
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
```
|
41
78
|
|
42
79
|
`main.js`:
|
43
80
|
|
@@ -47,60 +84,30 @@ import { applets } from '@web-applets/sdk';
|
|
47
84
|
const context = applets.getContext();
|
48
85
|
|
49
86
|
// Define a 'set_name' action, and make it update the shared data object with the new name
|
50
|
-
context.
|
51
|
-
|
52
|
-
name: {
|
53
|
-
type: string,
|
54
|
-
description: 'The name of the person to be greeted.',
|
55
|
-
},
|
56
|
-
},
|
57
|
-
handler: ({ name }) => applet.data = { name };
|
87
|
+
context.addActionHandler('set_name', ({ name }) => {
|
88
|
+
context.data = { name };
|
58
89
|
});
|
59
90
|
|
60
91
|
// Whenever the data is updated, update the view
|
61
92
|
context.ondata = () => {
|
62
|
-
document.getElementById('name')
|
93
|
+
const nameElement = document.getElementById('name');
|
94
|
+
if (nameElement) {
|
95
|
+
nameElement.innerText = context.data.name;
|
96
|
+
}
|
63
97
|
};
|
64
98
|
```
|
65
99
|
|
66
|
-
|
67
|
-
|
68
|
-
To use this applet, we need to load it in our host web app using the SDK. Assuming the applet lives in our public directory, here's what that might look like:
|
69
|
-
|
70
|
-
```js
|
71
|
-
const applet = await applets.load('/helloworld.applet');
|
72
|
-
applet.onstateupdated = (state) => console.log(state);
|
73
|
-
applet.dispatchAction('set_name', { name: 'Web Applets' });
|
74
|
-
// { name: 'Web Applets' }
|
75
|
-
```
|
76
|
-
|
77
|
-
For a live example you can download and play with now, check out the [applets chat demo](https://github.com/unternet-co/applets-chat).
|
78
|
-
|
79
|
-
## Getting started
|
80
|
-
|
81
|
-
Create a new web app with the applets SDK installed. You can do this quickly using our CLI:
|
82
|
-
|
83
|
-
```bash
|
84
|
-
npx @web-applets/create
|
85
|
-
```
|
86
|
-
|
87
|
-
Inside the generated folder, you'll find a basic web app setup:
|
88
|
-
|
89
|
-
- `public/manifest.json`: A web app manifest, useful when publishing your applet, adding icons, etc.
|
90
|
-
- `index.html`: Much like a website, this holds the main page for your applet
|
91
|
-
- `src/main.ts`: Declares functions that respond to each action, and a render function that updates the view based on state
|
92
|
-
|
93
|
-
> Want to use React? Svelte? Vue? – No problem, just install the dependencies and create an app the way you normally would in a website. So long as you're receiving the action events, it will all just work.
|
94
|
-
|
95
|
-
Now if you run `npx @web-applets/inspector`, you should be able to test out your new applet directly. This applet will now work in any environment where the SDK is installed.
|
100
|
+
To test out this applet, first start the dev server with `npm run dev`, and take note of the dev server URL. Then, fire up the Web Applets inspector by running `npx @web-applets/inspector`, and enter the dev URL into the URL bar up the top.
|
96
101
|
|
97
102
|

|
98
103
|
|
104
|
+
You can build this applet, by running `npm run build`, and host it on any static site host. This applet will now work in any environment where the SDK is installed.
|
105
|
+
|
99
106
|
## Integrating Web Applets into your client
|
100
107
|
|
101
|
-
|
108
|
+
In order to run, web applets need to be embedded in an environment that supports the Web Applets protocol. This might look like a browser (email me if you're interested!), or an electron app with `<webview>` tags, or sometthing as simple as a web-based AI chat client using iframes.
|
102
109
|
|
103
|
-
|
110
|
+
First, install & import the applets SDK in your client app:
|
104
111
|
|
105
112
|
```bash
|
106
113
|
npm install @web-applets/sdk
|
@@ -110,12 +117,12 @@ npm install @web-applets/sdk
|
|
110
117
|
import { applets } from '@web-applets/sdk';
|
111
118
|
```
|
112
119
|
|
113
|
-
Now you can import your applets from wherever they're being served from (note – you can also host them anywhere on the web):
|
120
|
+
Now you can import your applets from wherever they're being served from (note – you can also host them locally, or anywhere on the web):
|
114
121
|
|
115
122
|
```js
|
116
|
-
const applet = await applets.load('/
|
123
|
+
const applet = await applets.load('https://applets.unternet.co/maps');
|
117
124
|
applet.ondata = (e) => console.log(e.data);
|
118
|
-
applet.dispatchAction('set_name', { name: 'Web Applets' });
|
125
|
+
applet.dispatchAction('set_name', { name: 'Web Applets' }); // console.log: { name: "Ada Lovelace" }
|
119
126
|
```
|
120
127
|
|
121
128
|
The above applet is actually running headless, but we can get it to display by attaching it to a container. For the loading step, instead run:
|
@@ -129,8 +136,7 @@ const applet = await applets.load(`/helloworld.applet`, container);
|
|
129
136
|
To load pre-existing saved data into an applet, simply set the data property:
|
130
137
|
|
131
138
|
```js
|
132
|
-
applet.data = { name: 'Ada Lovelace' };
|
133
|
-
// console.log: { name: "Ada Lovelace" }
|
139
|
+
applet.data = { name: 'Ada Lovelace' }; // console.log: { name: "Ada Lovelace" }
|
134
140
|
```
|
135
141
|
|
136
142
|
## Feedback & Community
|
package/dist/core/context.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ActionParams, AppletDataEvent, AppletLoadEvent, AppletReadyEvent,
|
1
|
+
import { ActionParams, AppletDataEvent, AppletLoadEvent, AppletReadyEvent, JSONSchema, AppletManifest, AppletAction, AppletMessageRelay } from './shared';
|
2
2
|
export type ActionHandler<T extends ActionParams> = (params: T) => void | Promise<void>;
|
3
3
|
export type ActionHandlerDict = {
|
4
4
|
[key: string]: ActionHandler<any>;
|
@@ -25,7 +25,7 @@ export declare class AppletContext extends EventTarget {
|
|
25
25
|
ondata(event: AppletDataEvent): void;
|
26
26
|
}
|
27
27
|
interface ActionDefinition<T> extends Omit<AppletAction, 'id'> {
|
28
|
-
|
28
|
+
parameters?: JSONSchema;
|
29
29
|
handler?: ActionHandler<T>;
|
30
30
|
}
|
31
31
|
export declare function getContext(): AppletContext;
|
package/dist/core/shared.d.ts
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
export interface AppletManifest {
|
2
2
|
name?: string;
|
3
3
|
short_name?: string;
|
4
|
-
icons:
|
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
|
11
|
+
export interface ManifestIcon {
|
13
12
|
src: string;
|
14
13
|
purpose?: string;
|
15
14
|
sizes?: string;
|
@@ -19,13 +18,17 @@ export interface AppletAction {
|
|
19
18
|
id: string;
|
20
19
|
name?: string;
|
21
20
|
description?: string;
|
22
|
-
|
21
|
+
parameters?: JSONSchema;
|
23
22
|
}
|
24
|
-
export
|
25
|
-
type: string;
|
23
|
+
export interface JSONSchema {
|
24
|
+
type: 'object' | 'string' | 'number' | 'integer' | 'array' | 'boolean' | 'null';
|
26
25
|
description?: string;
|
27
|
-
properties?:
|
28
|
-
|
26
|
+
properties?: {
|
27
|
+
[key: string]: JSONSchema;
|
28
|
+
};
|
29
|
+
required?: string[];
|
30
|
+
additionalProperties?: boolean;
|
31
|
+
}
|
29
32
|
export type ActionParams = Record<string, any>;
|
30
33
|
export declare function loadManifest(pageUrl: string): Promise<AppletManifest>;
|
31
34
|
interface SendMessageOptions {
|
package/dist/core/shared.js
CHANGED
@@ -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
|
-
|
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/types.d.ts
ADDED
package/dist/types.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
CHANGED
@@ -1,17 +1 @@
|
|
1
|
-
import { AppletAction } from './core/shared';
|
2
1
|
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/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
|
-
|
5
|
-
|
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('/')) {
|
@@ -10,19 +26,3 @@ function trimTrailingSlash(url) {
|
|
10
26
|
}
|
11
27
|
return url;
|
12
28
|
}
|
13
|
-
// Creates an OpenAI-compatible schema declaration for an action
|
14
|
-
export function createOpenAISchemaForAction(action) {
|
15
|
-
return {
|
16
|
-
strict: true,
|
17
|
-
name: 'action_schema',
|
18
|
-
schema: {
|
19
|
-
type: 'object',
|
20
|
-
required: Object.keys(action),
|
21
|
-
properties: {
|
22
|
-
id: { type: 'string' },
|
23
|
-
params: action.params,
|
24
|
-
},
|
25
|
-
additionalProperties: false,
|
26
|
-
},
|
27
|
-
};
|
28
|
-
}
|
package/package.json
CHANGED
package/dist/core/host.d.ts
DELETED
@@ -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 };
|
package/dist/lib/utils.d.ts
DELETED
@@ -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
|
-
// }
|