Coder Social home page Coder Social logo

matrix-org / matrix-widget-api Goto Github PK

View Code? Open in Web Editor NEW
56.0 23.0 18.0 625 KB

JavaScript/TypeScript API for widgets & web clients to communicate

License: Apache License 2.0

JavaScript 0.43% TypeScript 99.57%
widgets matrix matrix-widget-api hacktoberfest

matrix-widget-api's Introduction

matrix-widget-api

npm

JavaScript/TypeScript SDK for widgets & clients to communicate.

For help and support, visit #matrix-widgets:matrix.org on Matrix.

Disclaimer: Widgets are not yet in the Matrix spec, so this library may not work with other implementations.

Building

To transpile this project to JavaScript, run:

yarn install
yarn build

Using the API without a bundler

If you're looking to drop the widget-api into a web browser without the use of a bundler, add a script tag similar to the following:

<script src="https://unpkg.com/[email protected]/dist/api.min.js"></script>

Note that the version number may need changing to match the current release.

Once included, the widget-api will be available under mxwidgets. For example, new mxwidgets.WidgetApi(...) to instantiate the WidgetApi class.

Usage for widgets

The general usage for this would be:

const widgetId = null; // if you know the widget ID, supply it.
const api = new WidgetApi(widgetId);

// Before doing anything else, request capabilities:
api.requestCapability(MatrixCapabilities.Screenshots);
api.requestCapabilities(StickerpickerCapabilities);

// Add custom action handlers (if needed)
api.on(`action:${WidgetApiToWidgetAction.UpdateVisibility}`, (ev: CustomEvent<IVisibilityActionRequest>) => {
    ev.preventDefault(); // we're handling it, so stop the widget API from doing something.
    console.log(ev.detail); // custom handling here
    api.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
});
api.on("action:com.example.my_action", (ev: CustomEvent<ICustomActionRequest>) => {
    ev.preventDefault(); // we're handling it, so stop the widget API from doing something.
    console.log(ev.detail); // custom handling here
    api.transport.reply(ev.detail, {custom: "reply"});
});

// Start the messaging
api.start();

// If waitForIframeLoad is false, tell the client that we're good to go
api.sendContentLoaded();

// Later, do something else (if needed)
api.setAlwaysOnScreen(true);
api.transport.send("com.example.my_action", {isExample: true});

For a more complete example, see the examples directory of this repo.

Usage for web clients

This SDK is meant for use in browser-based applications. The concepts may be transferable to other platforms, though currently this SDK is intended to only be used by browsers. In the future it may be possible for this SDK to provide an interface for other platforms.

TODO: Improve this

const driver = new CustomDriver(); // an implementation of WidgetDriver
const api = new ClientWidgetApi(widget, iframe, driver);

// The API is automatically started, so we just have to wait for a ready before doing something
api.on("ready", () => {
    api.updateVisibility(true).then(() => console.log("Widget knows it is visible now"));
    api.transport.send("com.example.my_action", {isExample: true});
});

// Eventually, stop the API handling
api.stop();

matrix-widget-api's People

Contributors

dbkr avatar dhenneke avatar fox32 avatar griffinli avatar johennes avatar jryans avatar kb1rd avatar ldubost avatar riotrobot avatar rkouwenhoven avatar robintown avatar skolmer avatar t3chguy avatar toger5 avatar turt2live avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

matrix-widget-api's Issues

[HELP] How to make a custom widget that receives a matrix user's userid?

Let's say my friend hosts a hypothetical video game that allows users to join without registration, and a URL like https://coolgame.com/?guestname= allows the browser to suggest a pre-filled username (similar to KiwiIRC, some wikis, Jitsi, etherpad, etc). When I simply add $matrix_user_id to the end of the URL (e.g. /addwidget https://coolgame.com/?guestname=$matrix_user_id ) the game website thinks that a guest wants to use the name $matrix_user_id, instead of alice, bob etc

If I host a file, e.g. https://mysite.com/coolgame.html, can I simply use
<script src="https://unpkg.com/[email protected]/dist/api.min.js"></script>
+
<iframe src="https://coolgame.com/?guestname=$matrix_user_id"></iframe>

then in Element enter /addwidget https://mysite.com/coolgame.html to allow my Matrix users to open the game widget with their name pre-filled for them?

I tried to ask about this kind of scenario in the Matrix room and am still a bit lost. I think that asking this as an issue is useful, because if other people wonder how to do this hypothetical scenario in the future (it will become more common as Matrix and Element, etc grow) this issue / future documentation should be able to cover this hypothetical usecase: help someone who's not a webdev or JS person make a custom widget that listens to Matrix suggestions (eg: room name, username) with as little work as possible.

Sorry to be a nuisance, and I am very grateful for any support 🙏

Given example is not working

The given example given in https://github.com/matrix-org/matrix-widget-api/tree/master/examples/widget, gives 404 for api.js.
By replacing https://github.com/matrix-org/matrix-widget-api/blob/master/examples/widget/index.html#L50 with <script src="https://unpkg.com/[email protected]/dist/api.min.js"></script>, I get the following errors when opening the Custom Widget:

 Action:notify_capabilities failed with message: The postMessage was unhandled generic-f65725513b138597c58f.bundle.js:77:8220
    value https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:77
    value https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:77
    value https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:77
    (Async: EventListener.handleEvent)
    value https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:77
    t https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:77
    value https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:79
    Tr https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    oi https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    unstable_runWithPriority https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:77
    Wt https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    ii https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    Wr https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    zr https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    Pi https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    Di https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    Qr https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    Di https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:61
    render https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:69
    <anonymous> https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:79
    t https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:1
    <anonymous> https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:1
    <anonymous> https://scalar.vector.im/api/widgets/generic-f65725513b138597c58f.bundle.js:1

and

 Error: widgetId is not present in URL - cannot load widget
    assertParam https://my.homeserver.com/matrix-widget-api/examples/widget/utils.js:24
    <anonymous> https://my.homeserver.com/matrix-widget-api/examples/widget/index.html:59
utils.js:29:13
    handleError https://my.homeserver.com/matrix-widget-api/examples/widget/utils.js:29
    <anonymous> https://my.homeserver.com/matrix-widget-api/examples/widget/index.html:102

Would be great to have a working boilerplate to experiment with.

mxwidgets is a function, not an object (dist/api.min.js)

Describe the bug
I cannot create my WidgetApi using new mxwidgets.WidgetApi(widgetId); because mxwidgets is a function.

To Reproduce
Steps to reproduce the behavior:

  1. Copy the example.
  2. Change the import of the api <script src="https://unpkg.com/[email protected]/dist/api.min.js"></script>.
  3. Host it on a https endpoint
  4. Post this in a room /addwidget https://localhost:8080/#/?widgetId=$matrix_widget_id&userId=$matrix_user_id (adapt it to your address)
  5. See the error in the JS terminal of your browser.

Expected behavior
mxwidgets should be an object, containing at least WidgetApi and MatrixCapabilities.

Peek 2020-12-16 18-41

Screenshots
Screenshot_2020-12-16_18-40-11

Desktop (please complete the following information):

  • OS: Manjaro Linux
  • Browser Firefox Dev
  • Version 84b

Reports that the example doesn't work anymore

https://matrix.to/#/!rDkLtgRQarvieuFHBA:t2l.io/$M5vvMdiNrsNxh4eB8_S8Z-S17TrUns3KE-qXX71dYBk?via=matrix.org&via=element.io&via=envs.net

Yes you are right. You could try to pass either the client origin (i.e. the Element URL) of "*" to the WidgetApi constructor.

The problem was introduced in version 1.2.0: Before, the targetOrigin defaulted to "*" here. That was refactored to a default value here. However, the constructor of the WidgetApi overrides it with null, so it won't work anymore.

Unhandled promise rejection in requestOpenIDConnectToken

Describe the bug
requestOpenIDConnectToken creates a new Promise that does not handle exceptions thrown by sendComplete.
https://github.com/matrix-org/matrix-widget-api/blob/master/src/WidgetApi.ts#L128

To Reproduce
Call requestOpenIDConnectToken without correctly initializing the WidgetApi.

Expected behavior
The call of sendComplete should be followed by a catch that calls reject of the newly created promise.

And just to be sure: I'm currently calling this function every time I need a token. Is my assumption correct that the token lifetime is already handled by the Element client and I don't have to cache the token and check the expiration time myself? #13

Define supported browsers

It's currently unclear which browsers are meant to be supported here. We should try to define something more specific than "lots of them" so that it's easier to know what can and cannot be used, etc.

#4 contains a few thoughts on this, mentioning at least Android webviews, IE 11, etc.

`handleMessage` default behaviour leads to superfluous errors

On each side of the widget transport, there are handleMessage functions such as:

    private handleMessage(ev: CustomEvent<IWidgetApiRequest>) {
        const actionEv = new CustomEvent(`action:${ev.detail.action}`, {
            detail: ev.detail,
            cancelable: true,
        });
        this.emit(`action:${ev.detail.action}`, actionEv);
        if (!actionEv.defaultPrevented) {
            switch (ev.detail.action) {
                case WidgetApiToWidgetAction.SupportedApiVersions:
                    return this.replyVersions(<ISupportedVersionsActionRequest>ev.detail);
                case WidgetApiToWidgetAction.Capabilities:
                    return this.handleCapabilities(<ICapabilitiesActionRequest>ev.detail);
                case WidgetApiToWidgetAction.UpdateVisibility:
                    return this.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{}); // ack to avoid error spam
                case WidgetApiToWidgetAction.NotifyCapabilities:
                    return this.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{}); // ack to avoid error spam
                default:
                    return this.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
                        error: {
                            message: "Unknown or unsupported action: " + ev.detail.action,
                        },
                    });
            }
        }
    }

At the moment, the library seems setup (based on the guide on the repo home page) to require widget developers to call ev.preventDefault() on anything they listen to and craft their own reply, even when it's effectively a one way notification and an empty reply is just fine.

As shown above a few random notification-like actions (UpdateVisibility, NotifyCapabilities) are auto-replied, while all others (e.g. SendEvent) default to sending back an error, even though the data was emitted and probably processed by the widget anyway.

I would suggest flipping around the default behaviour to sending empty data and dropping the error path. After all, the data has been emitted already, and (most likely) processed.

Cannot use actions from within a modal widget

Describe the bug
When calling API functions like requestOpenIDConnectToken() from within a modal widget we get an error message that the action is unknown or unsupported.

To Reproduce
Steps to reproduce the behavior:

  1. Add a widget to your room that uses the new openModalWidget function to open a subpage of the widget in a modal
  2. Inside of the modal use the same widget-api initialization function as provided in the examples. (Use the widget id from url for initialization)
  3. Call another action like requestOpenIDConnectToken() or setModalButtonEnabled()
  4. See error Unknown or unsupported action: widget_config or Unknown or unsupported action: set_button_enabled
PostmessageTransport.js:93 [PostmessageTransport] Sending object to https://element.some.domain:  {api: "fromWidget", widgetId: "modal_!shZJSWfZaqJCgokLcs%3Asynapse.dev.nordeck.sy…olmer%3Asynapse.some.domain_1605884505973", requestId: "widgetapi-1606142880777", action: "get_openid", data: {…}}
rageshake.js:65 [PostmessageTransport] Sending object to https://localhost:3000:  {api: "fromWidget", widgetId: "modal_!shZJSWfZaqJCgokLcs%3Asynapse.some.domain%3Asynapse.some.domain_1605884505973", requestId: "widgetapi-1606142880777", action: "get_openid", data: {…}, …}
PostmessageTransport.js:225 Uncaught (in promise) Error: Unknown or unsupported action: get_openid
    at PostmessageTransport.handleResponse (PostmessageTransport.js:225)
    at PostmessageTransport.handleMessage (PostmessageTransport.js:196)
    at PostmessageTransport.js:164

Expected behavior
The API functions should work the same as in sidepanel or room widgets.

Desktop (please complete the following information):

  • OS: Windows
  • Browser Chrome

Additional context
We are using the latest Element Build including all commits on matrix-react/js-sdk and element-web up to Nov 21, 2020

Consider a less confusing package name

Is your feature request related to a problem? Please describe.
The name 'matrix-widget-api' causes the package to frequently get confused with the The Widget API when talking to people about widgets

Describe the solution you'd like
Something like matrix-widget-sdk?

Describe alternatives you've considered
Unsure

Additional context
Add any other context or screenshots about the feature request here.

Send message

Hello,
Do you know if I can send a message in the current room ? Or this is not possible ?

Thank you !

Add token cache to requestOpenIDConnectToken function

Currently the requestOpenIDConnectToken() function requests a new token on every call of the function. It might be better to add some token lifetime handling to this API function.
If the implementing widget has to do this it needs some good documentation what exactly needs to be done otherwise it might cause load issues with 3rd party widgets.

Add exitModalWidget function and string constants

Is your feature request related to a problem? Please describe.
We have a cancel button in our modal that is basically doing the same as the "x" in the upper right corner of the modal. We want to use the same code that is running when the "x" is clicked to get the exact same result data in our CloseModalWidget event.

Describe the solution you'd like
Currently we just duplicated some logic and extended the WidgetApi with a function.

widgetApi.exitModalWidget = () => widgetApi.closeModalWidget({ "m.exited": true });

It would be nice if the exit function that is used by the "x" could be used instead. It would also be good to have constants for magic strings like m.exited.

Another small feature request is to have a function that basically does (widgetAction: WidgetApiToWidgetAction) => `action:${widgetAction}`; instead of writing code like this const actionButtonClicked = `action:${WidgetApiToWidgetAction.ButtonClicked}`; to get the correct event handler name as expected by the API.

If you are ok with this I could provide a PR.

Permission issues in the release tarball

Describe the bug
The compressed tarball for this package in the Yarn registry has some permission issues preventing it from being correctly extracted.

To Reproduce
Steps to reproduce the behavior:

  1. With an unprivileged user initialize a package.json file:
    yarn init -y
  2. Add this project as a dependency:
    yarn add matrix-widget-api
  3. Get the URL in the Yarn registry and download the tarball:
$ pkg_url=$(cat yarn.lock | grep ".com/matrix-widget-api" | awk -F'"' '{ print $2 }')
$ wget "${pkg_url}"
  1. Extract the archive:
$ mkdir extracted
$ tar zxvf matrix-widget-api-*.tgz -C extracted/
  1. Lots of errors will appear:
package/src/models/validation/utils.ts
tar: package/src/models/validation/utils.ts: Cannot open: Permission denied
tar: Exiting with failure status due to previous errors
  1. If you retry the extract command with the --delay-directory-restore flag, it works at first, but a few directories will miss the execute attribute:
$ tar zxvf matrix-widget-api-*.tgz --delay-directory-restore -C extracted/
$ rm -rf extracted/
rm: cannot remove 'extracted/package/src': Permission denied
rm: cannot remove 'extracted/package/LICENSE': Permission denied
rm: cannot remove 'extracted/package/lib': Permission denied
rm: cannot remove 'extracted/package/README.md': Permission denied
rm: cannot remove 'extracted/package/dist': Permission denied
rm: cannot remove 'extracted/package/CONTRIBUTING.rst': Permission denied
rm: cannot remove 'extracted/package/package.json': Permission denied
  1. It's possible to fix the errors from (6) by adjusting the attributes:
$ find extracted/ -type d -exec chmod a+x {} \;
$ rm -rf extracted/
# works now

Expected behavior
Extraction was expected to work correctly without the need for extra flags and operations, similarly to other projects. For example, matrix-js-sdk:

$ yarn add matrix-js-sdk
$ pkg_url=$(cat yarn.lock | grep ".com/matrix-js-sdk" | awk -F'"' '{ print $2 }')
$ wget "${pkg_url}"

$ mkdir extracted
$ tar zxvf matrix-js-sdk-*.tgz -C extracted/
$ rm -rf extracted
# works right away

Desktop (please complete the following information):

  • OS: Linux Mint 19.3 Tricia
  • Yarn: 1.7.0
  • tar: GNU tar 1.29

NavigateTo msc2931

Hello
Tell me, please, what is the status of navigateTo?

  • @deprecated This currently relies on an unstable MSC (MSC2931).
  • @deprecated It is not recommended to rely on this existing - it can be removed without notice.
    */
    MSC2931Navigate = "org.matrix.msc2931.navigate",

Can I use it in the prod?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.