feat(sdk,client): add edgeframe sdk api
All checks were successful
arcad/edge/pipeline/head This commit looks good

This commit is contained in:
wpetit 2023-04-06 18:16:17 +02:00
parent 68e35bf5a6
commit 240b07af66
10 changed files with 264 additions and 71 deletions

View File

@ -55,7 +55,7 @@ pkg/sdk/client/dist/client.js: tools/esbuild/bin/esbuild node_modules
--global-name=Edge \
--define:global=window \
--platform=browser \
--footer:js="Edge=Edge.default;" \
--footer:js="EdgeFrame=Edge.crossFrameMessenger;Edge=Edge.client" \
--outfile=pkg/sdk/client/dist/client.js
node_modules:

View File

@ -1,68 +1,14 @@
# API Client
## Méthodes
## Usage
### `Edge.connect(): Promise`
Afin de pouvoir utiliser le SDK "client", vous devez inclure dans la page HTML de votre application la balise `<script>` suivante:
> `TODO`
### `Edge.disconnect(): void`
> `TODO`
### `Edge.send(message: Object): void`
> `TODO`
### `Edge.rpc(method: string, params: Object): Promise`
> `TODO`
#### Exemple
**Côté serveur**
```js
function onInit() {
rpc.register(echo);
}
function echo(ctx, params) {
return params;
}
```html
<script src="/edge/sdk/client.js"></script>
```
**Côté client**
Vous pourrez ensuite accéder aux variables globales suivantes:
```js
Edge.connect().then(() => {
Edge.rpc("echo", { hello: "world!" })
.then(result => console.log(result))
.catch(err => console.error(err));
});
```
### `Edge.upload(blob: Blob, metadata: Object): Promise`
> `TODO`
### `Edge.blobUrl(bucketName: string, blobId: string): string`
> `TODO`
### `Edge.externalUrl(url: string): string`
Retourne une URL "locale" permettant d'accéder à une ressource externe, en fonction de règles propres à l'application. Voir module [`fetch`](../server-api/fetch.md).
## Événements
### `"message"`
> `TODO`
#### Exemple
```js
Edge.addEventListener("message", evt => console.log(evt.detail));
```
- [`Edge`](./edge.md) - Client principal d'échange avec le serveur
- [`EdgeFrame`](./edge-frame.md)

View File

@ -0,0 +1,30 @@
# `EdgeFrame`
## Méthodes
### `EdgeFrame.addEventListener(name: string, listener: (event) => void)`
> `TODO`
## Événements
### `"title_changed"`
```typescript
interface TitleChangedEvent {
detail: {
title: string
}
}
```
### `"size_changed"`
```typescript
interface SizeChangedEvent {
detail: {
width: number
height: number
}
}
```

View File

@ -0,0 +1,68 @@
# `Edge`
## Méthodes
### `Edge.connect(): Promise`
> `TODO`
### `Edge.disconnect(): void`
> `TODO`
### `Edge.send(message: Object): void`
> `TODO`
### `Edge.rpc(method: string, params: Object): Promise`
> `TODO`
#### Exemple
**Côté serveur**
```js
function onInit() {
rpc.register(echo);
}
function echo(ctx, params) {
return params;
}
```
**Côté client**
```js
Edge.connect().then(() => {
Edge.rpc("echo", { hello: "world!" })
.then(result => console.log(result))
.catch(err => console.error(err));
});
```
### `Edge.upload(blob: Blob, metadata: Object): Promise`
> `TODO`
### `Edge.blobUrl(bucketName: string, blobId: string): string`
> `TODO`
### `Edge.externalUrl(url: string): string`
Retourne une URL "locale" permettant d'accéder à une ressource externe, en fonction de règles propres à l'application. Voir module [`fetch`](../server-api/fetch.md).
## Événements
### `"message"`
> `TODO`
#### Exemple
```js
Edge.addEventListener("message", evt => console.log(evt.detail));
```

View File

@ -1,4 +1,5 @@
Edge.debug = true;
EdgeFrame.debug = true;
describe('Edge', function() {

View File

@ -3785,7 +3785,8 @@ var Edge = (() => {
// pkg/sdk/client/src/index.ts
var src_exports = {};
__export(src_exports, {
default: () => src_default
client: () => client,
crossFrameMessenger: () => crossFrameMessenger
});
// pkg/sdk/client/src/event-target.ts
@ -4089,9 +4090,73 @@ var Edge = (() => {
}
};
// pkg/sdk/client/src/crossframe-messenger.ts
var CrossFrameMessenger = class extends EventTarget {
constructor() {
super();
this.debug = false;
this._initResizeObserver();
this._initTitleMutationObserver();
this._handleWindowMessage = this._handleWindowMessage.bind(this);
window.addEventListener("message", this._handleWindowMessage);
}
post(message, target = window.parent) {
if (!target)
return;
this._log("sending crossframe message", message);
target.postMessage(message);
}
_log(...args) {
if (!this.debug)
return;
console.log(...args);
}
_handleWindowMessage(evt) {
const message = evt.data;
const event = new CustomEvent(message.type, {
cancelable: true,
detail: message.data
});
this.dispatchEvent(event);
}
_initTitleMutationObserver() {
const titleObserver = new MutationObserver((mutations) => {
const title2 = mutations[0].target.textContent;
this.post({ type: "title_changed" /* TITLE_CHANGED */, data: { title: title2 } });
});
const title = document.querySelector("title");
if (!title)
return;
this.post({ type: "title_changed" /* TITLE_CHANGED */, data: { title: title.textContent } });
titleObserver.observe(title, { subtree: true, characterData: true, childList: true });
}
_initResizeObserver() {
const resizeObserver = new ResizeObserver(() => {
const body = document.body, html = document.documentElement;
const height = Math.max(
body.scrollHeight,
body.offsetHeight,
html.clientHeight,
html.scrollHeight,
html.offsetHeight
);
const width = Math.max(
body.scrollWidth,
body.offsetWidth,
html.clientWidth,
html.scrollWidth,
html.offsetWidth
);
this.post({ type: "size_changed" /* SIZE_CHANGED */, data: { height, width } });
});
resizeObserver.observe(document.body);
}
};
// pkg/sdk/client/src/index.ts
var src_default = new Client();
var client = new Client();
var crossFrameMessenger = new CrossFrameMessenger();
return __toCommonJS(src_exports);
})();
Edge=Edge.default;
EdgeFrame=Edge.crossFrameMessenger;Edge=Edge.client
//# sourceMappingURL=client.js.map

File diff suppressed because one or more lines are too long

View File

@ -19,15 +19,16 @@ export class Client extends EventTarget {
constructor(autoReconnect = true) {
super();
this._conn = null;
this._onConnectionClose = this._onConnectionClose.bind(this);
this._onConnectionMessage = this._onConnectionMessage.bind(this);
this._handleRPCResponse = this._handleRPCResponse.bind(this);
this._rpcID = 0;
this._pendingRPC = {};
this._queue = [];
this._reconnectionDelay = 250;
this._autoReconnect = autoReconnect;
this.debug = false;
this.connect = this.connect.bind(this);

View File

@ -0,0 +1,80 @@
import { EventTarget } from "./event-target";
enum CrossFrameMessageType {
SIZE_CHANGED = "size_changed",
TITLE_CHANGED = "title_changed"
}
interface CrossFrameMessage {
type: CrossFrameMessageType
data: { [key: string]: any }
}
export class CrossFrameMessenger extends EventTarget {
debug: boolean;
constructor() {
super()
this.debug = false;
this._initResizeObserver();
this._initTitleMutationObserver();
this._handleWindowMessage = this._handleWindowMessage.bind(this);
window.addEventListener('message', this._handleWindowMessage)
}
post(message: CrossFrameMessage, target: Window = window.parent) {
if (!target) return;
this._log("sending crossframe message", message);
target.postMessage(message)
}
_log(...args) {
if (!this.debug) return;
console.log(...args);
}
_handleWindowMessage(evt: MessageEvent) {
const message = evt.data;
const event = new CustomEvent(message.type, {
cancelable: true,
detail: message.data
});
this.dispatchEvent(event);
}
_initTitleMutationObserver() {
const titleObserver = new MutationObserver((mutations) => {
const title = mutations[0].target.textContent;
this.post({ type: CrossFrameMessageType.TITLE_CHANGED, data: { title }});
});
const title = document.querySelector('title');
if (!title) return;
this.post({ type: CrossFrameMessageType.TITLE_CHANGED, data: { title: title.textContent }});
titleObserver.observe(title, { subtree: true, characterData: true, childList: true });
}
_initResizeObserver() {
const resizeObserver = new ResizeObserver(() => {
const body = document.body,
html = document.documentElement;
const height = Math.max( body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight );
const width = Math.max( body.scrollWidth, body.offsetWidth,
html.clientWidth, html.scrollWidth, html.offsetWidth );
this.post({ type: CrossFrameMessageType.SIZE_CHANGED, data: { height, width }});
});
resizeObserver.observe(document.body);
}
}

View File

@ -1,3 +1,5 @@
import { Client } from './client.js';
import { CrossFrameMessenger } from './crossframe-messenger.js';
export default new Client();
export const client = new Client();
export const crossFrameMessenger = new CrossFrameMessenger();