-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The relationship between payment apps and service workers #33
Comments
Thanks for this summary @tommythorsen, this is very helpful. I am not an expert on how browsers operate internally but the architect in me says option 2 is the best way forward at list until we decide we have to go to option 3. I see an advantage in option 1 in that it's simple and means re-using existing primitives which is good. Perhaps we could still follow option 1 but instead of having a payment request event just listen for messages and look at the message to see if it's a payment request? I'd like us to consider carefully the possibility of re-looking at using manifests for payment apps where perhaps the app has no Browsers that see the manifest Worth getting feedback here from @marcoscaceres and @jakearchibald, I suggest we try to meet at TPAC as they will need a lot of context. |
It sounds to me like option 2 is the best option until option 3 clearly becomes a necessity. Polluting the
Having to interpret something based on the context because it happens to "look like" what you want requires that you take on considerably more (unnecessary) knowledge about the underlying architecture and details of the system that has been extended. Let's keep this as simple as we can Edit: That may be overstating it for this particular case (message type checking), but wanted to put those thoughts out there. |
I'm not too worried about this. In fact, it seems worse that users would have to manage the lifecycle of yet another thing. If it's a JS context that wakes up to handle an event, potentially without a page on the origin being open, that's a service worker. This is why things like push, sync, and potentially alarms & geofencing live there. The precedent is already there, and by design. Joining these means developers could use push messages to update a payment app's details etc. |
I don't entirely follow this concern. By "users" did you mean the end users or the users of the API? End users are already going to be managing, installing, removing, and interacting with Payment Apps in a number of ways that may be different from typical service workers -- if for no other reason than in how they are surfaced. In any event, end users likely won't have any understanding of the implementation or architecture details here (nor will they care). If you meant users of the API, what is the extra overhead that they would incur with option 1 vs. option 2? Perhaps this isn't true for all Payment App implementers, but I would expect most to see Payment Apps as their own (sub)class of thing, even if their behavior inherits greatly from service workers. But this is why an inheritance model seems to make sense. It doesn't make sense to me that any service worker may show up in the list of Payment Apps that I could use to complete a payment request. However, that doesn't mean that we necessarily need to establish a new class of thing in order to make that distinction manifest. This is just an explanation for why inheritance seems to make sense to some of us here.
I think only option 3 would cause a Payment App not to be a service worker; for options 1 and 2, it's just a question of how the necessary extensions are achieved. Of course, you link to the extensibility section on service workers which is definitely the primary source of guidance we should attempt to follow here. We should assume that a lot of thought has been put into this previously and try to use the framework put forward. So thank you for the pointer. |
As linked from the service worker extensibility section, the Notifications API is an example of a spec that extends the service worker spec: |
@jakearchibald also mentioned some other APIs that extend service workers: |
This is exactly what it was designed for. There'd need to be a really good reason to create a new worker type for this, and I'd rather look at ways we can change service worker if it doesn't quite fit. |
About option 3 vs actually using service workers:
Clearly in general that’s an anti-pattern we should be trying very hard to avoid for any new features we add to the platform. To me, if we advocate for a mechanism that we know will duplicate a lot of the functionality already provided by service worker, then the burden of proof should be on us (in the Payments WG) to clearly explain to the rest of the people working on features for the platform why we need to create a new parallel thing rather than re-using the work they have already done. [about basing the payment-apps API on service workers]
Me neither. Again I think the burden on proof should be on us in the Payments WG: If we think there is some functionality from standard service workers that we would not want exposed in the payment-apps case, then we have an obligation to clearly identify what that is. [about not basing the payment-apps API on service workers]
It seems to not be clear at all that we need that freedom or that we ever will. So it is not clear that there are any real-world benefits in practice compared to the cost of making users “have to manage the lifecycle of yet another thing” (as @jakearchibald put it). Another clear benefit of basing the payment-apps API on service worker is, if/when deficiencies in SW get identified that require fixes and refinements—which is a very normal thing that happens with core features of the platform—then for the payment-apps API, we automatically get the benefits of those fixes and refinements for free, without needing to port them over to our parallel thing. |
Using this model, I think we would end up with code something like this: // https://example.com/serviceworker.js (the Payment App)
this.onpaymentrequest = function(event) {
// handle the payment request event and return a payment response
};
// https://example.com/webapp.js (the website that registers the Payment App)
navigator.serviceWorker.register('serviceworker.js').then(
function(serviceWorkerRegistration) {
// pass a 'manifest' into the payment app manager interface to indicate
// which payment methods are supported so the payment app can show up
// in the payment mediator when appropriate
serviceWorkerRegistration.paymentAppManager.register(manifest).then(
function(registrationResult) {
// do whatever with the registration result
}, function(error) {
console.log(error);
}
);
}); Obviously, the name |
[About 1. Payment apps are service workers vs 2. Payment apps inherit from service workers] I think we could just go with “payment apps are service workers“. I see no need to go with the kind of “Payment apps inherit from service workers” alternative described. I think that conclusion can be reached pretty clearly from a reading of the Service Workers spec (especially the parts of the SW spec @jakearchibald cites) and from reading other specs for technologies that build on SW (cited by @dlongley).
Yeah, I think there’s no reason to do otherwise, and @dlongley’s snippet shows what it’d look like. [about “payment apps are service workers”]
I think reading of the section of the SW spec @jakearchibald cites and a reading of the specs for the existing built-on-SW specs that @dlongley cites makes it clear that adding a new |
I agree with the others that state that option 1 makes the most sense. The OP expresses concerns about polluting service workers with "unrelated" functionality, but this is very much related to the core service worker mission, of having a ... service ... worker that runs in the background and reacts to events in order to provide a service (whether that be fetch interception, geofencing, push notification reactions, or payment request processing). |
It sounds like there is rough consensus for option 1 which I think is great, it feels like a good extensible web story. The specifics of how we do option 1 is probably still tdb. @adamroach - as the author of the existing payment app proposal your opinion would be highly valued here. I would still like to understand how we could loosely couple the implementation from the registration such that we can handle different registration methods (declarative via a manifest vs through an API call). I hear @jakearchibald say "this is what ServiceWorkers were designed for" which is great, but I'd like to hear also from @marcoscaceres about using manifest. My early proposals for the payment apps API intended to use the extension points of the manifest spec to provide "supported payment method" meta-data and I wonder if that isn't still a good idea. i.e. Could a variation of @dlongley 's suggested code be used to register any ServiceWorker using a manifest instead of just the I am also not convinced that we need a new This also opens up an interesting use case where a site that has it's own payment app installed could pass a payment request directly to that app and bypass the mediator-based app selection completely. This feels like a good thing but need to think about it a bit more. Something like: // https://example.com/serviceworker.js (the Payment App)
this.onmessage = function(event) {
// If message is payment request then process it and return a payment response
};
// https://example.com/webapp.js (the website that registers the Payment App)
var manifest =
{
"name": "Example Payment App",
"start_url": "https://boo", //Not sure what would go here?
"service_worker": "serviceworker.js",
"payment_methods" : ["basic_card", "http://example.com/pay"]
};
navigator.serviceWorker.register(manifest).then(
...
); |
What's the benefit of having this in the manifest? Is there an issue I can read to catch up? |
I have to admit, I was originally in favor of option 2, but now that I see all of your comments, it seems that option 1 is the right way. It would be really great if we could follow the examples of the push, sync and notifications APIs for integrating with service workers.
Passing the payment requests as messages to On the other hand, if the payment requests were HTTP requests, we could use |
A Payment App has some meta-data (the list of payment methods is can handle) that is important to register with the browser during registration. A manifest seems like the right way to do this. That is not so say it's the only way but it seems like there could be better alignment of what's being done to extend @tommythorsen - I don't have a strong personal preference between For example I note that for Notifications two new methods are defined directly on the If this is really is the intended use for ServiceWorker some extensibility guidance would be helpful here. |
Landing stuff in I think the fetch idea may be worth exploring though. If a payment app can be described purely in terms of HTTP requests, then service worker doesn't need to be an explicit dependency, but it becomes beneficial through existing mechanisms. @zkoch - we threw this idea around a few months ago, any existing discussion elsewhere? |
@jakearchibald that was the original proposal I made a few months back which is probably why @tommythorsen is bringing it up. My argument in favor of an HTTP request is that it is less platform specific and so could be handled by non-browsers as easily as a We discussed this at our face to face in June and the consensus was to use ServiceWorkers. The thinking went something like this:
Lots of previous discussion:
The current ED still uses HTTP: |
@jakearchibald, to address your other comment:
That's true and is probably a good reason to not use an HTTP request and The more I think about it it feels like if we're designing a new API in I.e. If we aren't forcing websites to submit a payment request using So, I'm coming around to @dlongley 's proposal. Still keen to hear what @adamroach thinks though. |
If that's the reason, then I haven't looked at it enough to know if fetch or a custom event is better, but |
@adrianhopebailie -- still digging through some of the background material here, but I think the general approach here is pretty sound. In particular, I far prefer the use of a new event rather than message queues (in fact, I argued for a similar design in London). I'll note that going with actual service workers settles the issue of updating payment apps (we leverage the normal SW update mechanism), and makes it so we don't have to re-invent a registration concept for payment apps (in fact, that's one of the things I like most about this approach). As we discussed on the call today, I plan to revise the jsapi proposal to reflect this approach in time for our call next week. I think I have enough information in this issue to do so. |
Happy to take part in these calls if anyone thinks it'd be useful |
@jakearchibald For a link to the call info along with other stuff, see https://github.com/w3c/webpayments/wiki/PaymentApp_Notes There’s an .ics file with the event data but here are the actual details: Time: Wednesdays from 9am to 10am US/East https://mit.webex.com/mit/j.php?MTID=mab3c7a1fb772cbcbf39b054b2ebd9183 +1-617-324-0000 US Toll Number |
Great to see broad consensus on using ServiceWorkers. A question remains: what should we do with manifests, if anything? Let me try to convince you that we need manifests. Here's why I think manifests are useful. Suppose a merchant website at Now that (I hope) you're convinced of usefulness of manifest files, what should be inside of them? These manifests specify payment app restrictions, if any. Restrictions can be expressed as a whitelist of allowed payment apps. How should payment apps be identified? Service Workers can be downloaded from the web. The URLs where they reside can serve as the payment app identifiers. So the service worker at Example {
"externally_supported_apps": ["https://alicepay.xyz", "https://charliepay.xyz"]
} Example {
"externally_supported_apps": ["*"]
} Browsers need to know how to display the payment app Service Workers in UI, so the user can select them. For example, browsers may need the title of a payment app along with its icon in several sizes. The web already has a way to specify this through manifests. Before we get into specifying payment app Service Worker titles and icons, let's not forget native apps, either. Payment apps can be Service Workers, Android apps, iOS apps, Windows apps, etc. Therefore, it's useful to split up
I think you see the pattern. Here's an example of what
{
// Other payment apps that can use "http://bobpay.xyz" payment method.
"externally_supported_apps": ["https://alicepay.xyz", "https://charliepay.xyz"],
// Description of the Service Worker payment app "https://bobpay.xyz".
"web": {
"name": "BobPay - The World's Best Way to Pay",
"short_name": "BobPay",
"icons": []
},
// Descriptions of the Android payment app for "https://bobpay.xyz".
// Using a list here enables support for developer version and
// production version of the Android app, for example.
"android": [{
"platforms": {
// Where the app can be downloaded, if it's not installed.
"play": "https://play.google.com/store/apps/details?id=xyz.bobpay.app1",
"mios": "https://mi.cn/store/id=xyz.bobpay.app1"
},
// Next two fields provide a way to authorize a locally installed app.
"package": "com.example.app1",
"sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50"]
}],
// Descriptions of the iOS payment app for "https://bobpay.xyz".
"ios": "TBD"
// And so on...
} Thoughts? |
@rsolomakhin I agree that manifests are very useful but I think you are conflating payment app manifests and payment method manifests. A payment method manifest (like I think we'd also get some value out of using payment app manifests too and should be leveraging the existing work done on appmanifest. This is where we'd define things like the app icons, label and alternative versions in app stores etc. (This is all already defined for app manifest). App manifest also has extension points which we can use to define payment app meta data like supported payment methods: https://www.w3.org/TR/appmanifest/#extensibility |
That's intentional. We could have separate If we prefer to re-use appmanifest, then let's put
One downside of the related_applications list in appmanifest is lack of authentication information for apps. I would like to add |
@rsolomakhin wrote:
Personally, I am open to the idea of "one manifest". I look forward to discussing further at the FTF meeting. Ian |
I think it's a very bad idea. They are different things so trying to combine them is a bad idea. The app manifest will be fetched when the app is registered whereas the payment method manifest might be fetched during a checkout or during app registration. Note that during app registration fetching and processing manifests is a background process that is not blocking user interactions so the number of round-trips is immaterial.
We can't do that because this is an app manifest (not a payment method manifest).
We should raise that with the app manifest editors |
I don't think it's a bad idea. I think we can think of it not as a payment-method manifest or a payment-app manifest but as a "heres-how-i-participate-in-the-paymentrequest-ecosystem" manifest. |
If @adrianhopebailie and others feel strongly in favor of separation of payment app manifest and payment method manifest, then I can be convinced as well :-). After all, the payment method manifest is extremely simple: {
"externally_supported_apps": ["https://alicepay.xyz", "https://charliepay.xyz"],
} |
Indeed! The point here is that for a the payment method The manifest describing the app I think we're going off topic here though so maybe we need a new thread discussing manifests |
To bring the discussion back on topic: Yay Service Workers! 👍 |
I agree that makes no sense, but I don't think that's whats bring proposed. But I agree we're off topic, so can take this to another issue and/or discuss at TPAC.
👍 |
Due to lack of experience I'm a little confused by this example. Can you give me something more real-world where the merchant, payment handler, & payment method are distinct? The "primary key" of a service worker registration is its scope, which allows for multiple service worker registrations on a single origin. A single service worker registration can update its script URL, but its scope URL is fixed. Seems like the scope should be used to identify a payment app. There's still no update model for manifests, so the more information you put in there, the more updating trouble you'll land in. You'll either have to live with out-of-date info, or request the manifest every time you need the info from it, and that'll slow things down. If this information was set using APIs in a service worker, its updating is in the control of the origin owner. Is it useful to specify Android/iOS in that much detail? As far as I know, native apps can already hijack navigations, so can't they just hijack the payment process in a similar way? The spec could provide hooks for this, eg "If bobpay's native app is install, it can do what it wants as long as it returns to the next step". |
We refer to the "payment handler" as a "payment app". Here's a real world example: You go to expedia.com (the merchant) and book a hotel. When it's time to checkout, Expedia lets you pay with bitcoin (the payment method). Your browser lets you choose your Coinbase wallet (the payment app) to pay. This selection is offered because the Coinbase app indicates that it supports the bitcoin payment method. This new Web Payments architecture allows new payment methods to be created that could potentially be implemented by a variety of different payment apps. The creators of some payment methods will want to restrict which payment apps can implement their method and we're exploring specifying this via a manifest. Other payment methods will not have this sort of restriction. |
But why does bitcoin need to grant permission for Coinbase to use bitcoin? - ah just read the replies above, seems others have pointed out that doesn't make sense |
Also seems I had this tab open for days and wrote my reply without seeing all the intermediate comments, sorry! |
My thoughts in summary (now I've caught up with the rest of the thread): You could have:
self.registration.payments.register({name: 'Foopay'}); Or:
self.registration.payments.register('//manifest.json'); combined with {"name": "Foopay"} The former can be updated whenever page or service worker code runs (eg push message). The latter is dependent on an as-yet-undefined update model for the manifest. |
They don't. But what's being explored is whether some other payment methods may want to restrict the usage of their "proprietary" payment method to certain applications, e.g. PayPal. |
The discussion about "policing" payment apps is related but a bit off topic -- it's taking place over here: I think here we're just discussing the shape/purpose/specification/use of manifests with respect to payment apps as service workers. |
I was thinking of using Cache-Control for manifest expiration. A programmatic way to update this information is also useful. One possibility is to use Service Workers to manage both payment app's manifest and payment method's manifest. That way push messages can be used to update either piece of information. |
So if the manifest expires, is it no longer an installed payment app? Or will every matching stale manifest be refetched when a site calls |
If we use Cache-Control and the manifest expires, the browser would refetch Can Service Workers give more control to the developers as to when their On Sep 11, 2016 7:13 AM, "Jake Archibald" notifications@github.com wrote:
|
FWIW, I'm in support of option 1.
That would be really confusing. "message" events are for "post message". Having a specific payment event is less confusing, and allows the custom payment stuff to be part of the event itself (and avoids polluting the global scope). I see that similar consensus emerged further down the thread, which is good.
This doesn't matter in a H/2 world. It's premature optimization. I'd also like to note that the collaboration across multiple sites to perform a payment feels a bit like "foreign fetch". I also remain somewhat unconvinced that a web manifest has a big role to play here. I'm still trying to digest the use case, but it doesn't feel right to me at first glance. |
But if new PaymentRequest([{
supportedMethods: ["visa", "bitcoin"]
}, {
supportedMethods: ['bobpay.com']
}, {
supportedMethods: ['foopay.com']
}]).show() …and the user has "installed"
It's something that could be added in future, but not right now. However, service worker already gives the developer full control over when service worker registrations and other forms of storage are updated. |
To be clear for @jakearchibald and @marcoscaceres there are two manifests being proposed (although @rsolomakhin would like these combined in cases where the payment method owner only allows their own payment app to be used). The first is a manifest for the payment method which could describe, among other things, which payment apps can be used to pay using the payment method, which origins these apps can come from (and now possibly which merchants can detect for the presence of an app supporting that method - see w3c/payment-request#247) etc. The second is akin to app manifest and describes the payment app itself. Our examples are already re-using numerous concepts from app manifest so it seems like a good fit. The issue is that the relationship between manifests and service workers seems poorly defined at the moment so while we'd like to use manifests we may have to provide imperative versions of everything in a manifest through the service worker registration hook instead. Question to the two of you is, can we come to an agreement about using app manifest with service workers in a way that makes sense for apps where the service worker really is the app or is app manifest just a way to put icons and context on html apps? |
It isn't defined because they're pretty separate. Manifests are taking care of all the things that were previously
I think it's already the latter. If we're already using service worker, what's the justification for adding manifests on top of that? |
If you can avoid having an external JSON resource, please do so. In w3c/payment-request#247, it seems you are already avoiding using JSON - you have just a regular JS object (...and yes, you should not be able to detect the payment method:))
We have a similar issue filed here to do that: Web Manifest predates the extensible web and service workers, which is why we didn't have an API in the first place. If we were to do web manifest today, we would not do it as JSON - but as an API in Service Workers (hence w3c/manifest#472).
What @jakearchibald said and asked. |
One reason for expressing the manifest as JSON is for reuse in other environments. It follows the Rule of Least Power design principle. This manifest will likely specify a title, icon/image, and other basic information about a Payment App. A Payment App may be registered with the browser and may use JavaScript (via a service worker), but it could also potentially provide HTTP endpoints for use with the Web Payments HTTP API. Other APIs could also be specified in the future to access the same Payment App. The manifest could be reused here to provide that same information to a payment mediator or to other applications that wish to render some kind of interface for working with it outside of the browser. By expressing this information as JSON in an external resource -- it means that the Payment App implementer only needs to do so in one place. Now, an argument could be made that Payment Apps that provide multiple APIs could, for example, in their service worker do a fetch to obtain their manifest, parse it, and then provide it as JavaScript to the |
This sounds like the most extensible thing to do. This means the developer could have the data directly in the service worker, or an external JSON resource, or YAML, or whatever they want. |
With the imminent adoption of text by AdamR I believe we are addressing this issue and therefore I propose to close it. We can move the discussion to review of the text and raise smaller issues in doing so. Thanks to all! Ian |
A question came up during our last payment apps task force meeting, regarding what the relationship would be between the payment apps in @adamroach's new payment app proposal, and service workers. The new payment apps in this proposal do have a lot in common with service workers;
The new proposal currently describes payment apps as specializations of the dedicated worker, that just happen to be similar to service workers, but there may be benefits to bringing them closer together. The way I see it, we have at least three options:
1. Payment apps are service workers
Going in this direction would mean that we add more functionality to the
ServiceWorkerGlobalScope
. This added functionality would probably consist of a new Event Handler (onpaymentrequest
) and a function call for registering payment methods or payment options with the user agent. Payment apps are registered exactly the same way as service workers (since they are the same), withnavigator.serviceWorker.register()
.The advantage of this approach, is that it is very simple, both to specify and to implement, and it lets us make use of all the security mechanisms around service workers, The disadvantage is that we would be "polluting" the
ServiceWorkerGlobalScope
class with functionality that isn't strictly service worker related. There may also be functionality in service workers that we don't want for payment apps, although I'm not sure what that might be.2. Payment apps inherit from service workers
Inheriting from
ServiceWorkerGlobalScope
rather than modifying it, should let us make use of most of the advantages of the above approach, while keeping our payment request related API separate from the service worker API. We would have to make our own registration method (PaymentApp.register()
ornavigator.paymentApp.register()
), but this might be considered an advantage, since it would make it clearer what exactly is being registered, and it would let us take additional arguments to theregister
call.3. Payment apps look like service workers
This is the scenario I think the new proposal currently describes. Doing it this way, means that we need to duplicate a lot of the specification (and implementation) from service workers. This way is more work, but gives us the freedom to pick and choose what we borrow from service workers and what we don't.
What do you guys think? You are probably aware of more advantages and disadvantages to some of these options, and it would be interesting to have a discussion on this.
The text was updated successfully, but these errors were encountered: