@mhome/app-facade-protocol 1.111.0 → 1.112.1

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,6 +1,6 @@
1
- # Billing reads v1
1
+ # Billing v1
2
2
 
3
- All three App Facades run in the cloud under UserRead, using the authenticated user's identity. They accept no userId, tenantId or Space selector. A Space/background principal cannot read an owner's private account. These reads do not require an active Space.
3
+ All three read App Facades run in the cloud under UserRead, using the authenticated user's identity. They accept no userId, tenantId or Space selector. A Space/background principal cannot read an owner's private account. These reads do not require an active Space.
4
4
 
5
5
  | Target | Input | Business output |
6
6
  | --- | --- | --- |
@@ -10,4 +10,42 @@ All three App Facades run in the cloud under UserRead, using the authenticated u
10
10
 
11
11
  Summary retains the existing consistent plan/balance read; it does not query payments or daily history. Payment list retains successful invoices and refunds. Daily usage defaults to the 30 days ending today in UTC, permits ordered ranges of at most 366 inclusive days, and clamps the start to tracking availability. Errors are not replaced with zero usage. The existing `/app/agent/credit/usage` is Space-wide and remains distinct.
12
12
 
13
+ ## Account units and plan codes
14
+
15
+ `totalBalance` is the period's credit allowance, not the remaining balance. The
16
+ remaining credits are `totalBalance - usedAutomation - usedChat - usedIntegration`.
17
+ These four summary fields and daily `rows[].credits` are raw account credit units:
18
+ **100 credits = 1 product token displayed by the App**. For example, `100000`
19
+ credits is 1000 product tokens; 100 used credits is 1 used product token. These
20
+ product tokens are not an LLM's input/output tokens. Keep the wire values intact;
21
+ convert only when explaining the product-token amounts to a user.
22
+
23
+ The current tier codes are `E` (Internal), `T` (shown as Free), `V0` (Free), `V1`
24
+ (Go), and `V2` (Plus). `currentTier` describes the current plan; `refreshTier`
25
+ describes the plan at the next refresh. Either field and
26
+ `stripeSubscriptionStatus` can be null; null means unavailable/absent, not a
27
+ confirmed Free plan or active subscription. `nextRefreshTimestamp` is Unix
28
+ milliseconds. Product names such as `plus` are not tier codes.
29
+
30
+ Payment `amount` uses Stripe invoice/refund minor units for the returned
31
+ `currency`, independently of account credits. Preserve the refund sign. Follow
32
+ [Stripe's currency rules](https://docs.stripe.com/currencies), including zero-
33
+ decimal currencies and the ISK/UGX two-decimal API exceptions; do not assume USD
34
+ or divide all amounts by 100.
35
+
13
36
  Full returns the business DTO. Essential encodes the same DTO as YAML without extra reads. UI, Agent, MCP and CLI use these same targets and identity rules. Schemas and fictional examples are in `schema/billing.v1.schema.json` and `fixtures/billing.conformance.json`.
37
+
38
+ ## Subscription commands
39
+
40
+ These cloud-only UserWrite Facades use the authenticated user's account without an active Space. Input cannot select another user. The current UI exposes these commands on Web/desktop, with confirmation before submission; native mobile keeps its existing hidden purchase controls. Agent/MCP tool catalogs and delegated execution do not expose these commands.
41
+
42
+ | Target | Input | Business output |
43
+ | --- | --- | --- |
44
+ | `/app/billing/subscription/checkout/create` | `{productId}` | `{url}` for navigation to Stripe Checkout |
45
+ | `/app/billing/subscription/cancel` | `{}` | Subscription state; cancellation takes effect at period end |
46
+ | `/app/billing/subscription/resume` | `{}` | Subscription state; automatic renewal restored |
47
+ | `/app/billing/subscription/change` | `{productId}` | Subscription state; upgrades start immediately, downgrades start next period, choosing the current tier removes a pending change |
48
+
49
+ Product IDs retain the existing case-insensitive `go`/`plus` and legacy `pro`/`max` aliases. Subscription output contains `currentTier`, `cancelAtPeriodEnd`, `currentPeriodEndTimestamp`, `scheduledTier` and `scheduledTierStartTimestamp`; timestamps are Unix milliseconds. The standard Facade envelope carries success/failure, without a second business `success` flag. Full and Essential project the same command result without additional reads.
50
+
51
+ The UI does not automatically replay writes on reconnect or timeout. Checkout keeps its persistent attempt, frozen parameters, Stripe idempotency key and recoverable session URL. Once accepted, Checkout continues after caller disconnect; a lost response does not prove payment creation failed. Existing subscription management, proration and reconciliation stay owned by the Stripe manager. Stripe SDK calls, hosted Checkout navigation and signed `POST /webhook/stripe` delivery remain HTTP(S); the retired `/api/v1/payment/stripe/*` user command controllers are not webhook endpoints.
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "summary": {
3
3
  "userId": "fictional-user",
4
- "currentTier": "plus",
5
- "refreshTier": "plus",
4
+ "currentTier": "V2",
5
+ "refreshTier": "V2",
6
6
  "stripeSubscriptionStatus": "active",
7
- "totalBalance": 1000,
8
- "usedAutomation": 10,
9
- "usedChat": 20,
10
- "usedIntegration": 30,
7
+ "totalBalance": 300000,
8
+ "usedAutomation": 100,
9
+ "usedChat": 200,
10
+ "usedIntegration": 300,
11
11
  "nextRefreshTimestamp": 1796083200000
12
12
  },
13
13
  "payments": {
@@ -69,5 +69,61 @@
69
69
  "fromDate": 42
70
70
  }
71
71
  ]
72
+ },
73
+ "productInput": {
74
+ "valid": [
75
+ {
76
+ "productId": "go"
77
+ },
78
+ {
79
+ "productId": "plus"
80
+ },
81
+ {
82
+ "productId": "pro"
83
+ },
84
+ {
85
+ "productId": "max"
86
+ },
87
+ {
88
+ "productId": "Go"
89
+ },
90
+ {
91
+ "productId": "PLUS"
92
+ }
93
+ ],
94
+ "invalid": [
95
+ {},
96
+ null,
97
+ {
98
+ "productId": null
99
+ },
100
+ {
101
+ "productId": 42
102
+ },
103
+ {
104
+ "productId": ""
105
+ },
106
+ {
107
+ "productId": "free"
108
+ },
109
+ {
110
+ "productId": "go",
111
+ "userId": "other"
112
+ },
113
+ {
114
+ "productId": "go",
115
+ "scopeId": "home"
116
+ }
117
+ ]
118
+ },
119
+ "checkout": {
120
+ "url": "https://checkout.stripe.com/c/pay/cs_test_fictional"
121
+ },
122
+ "subscription": {
123
+ "currentTier": "V2",
124
+ "cancelAtPeriodEnd": false,
125
+ "currentPeriodEndTimestamp": 1796083200000,
126
+ "scheduledTier": "V1",
127
+ "scheduledTierStartTimestamp": 1796083200000
72
128
  }
73
129
  }
@@ -990,5 +990,133 @@
990
990
  "hubReady": false,
991
991
  "cloudReady": false,
992
992
  "entry": "unavailable"
993
+ },
994
+ {
995
+ "target": "/app/billing/subscription/checkout/create",
996
+ "execution": "cloud",
997
+ "placement": null,
998
+ "hubReady": true,
999
+ "cloudReady": true,
1000
+ "entry": "cloud"
1001
+ },
1002
+ {
1003
+ "target": "/app/billing/subscription/checkout/create",
1004
+ "execution": "cloud",
1005
+ "placement": null,
1006
+ "hubReady": true,
1007
+ "cloudReady": false,
1008
+ "entry": "unavailable"
1009
+ },
1010
+ {
1011
+ "target": "/app/billing/subscription/checkout/create",
1012
+ "execution": "cloud",
1013
+ "placement": null,
1014
+ "hubReady": false,
1015
+ "cloudReady": true,
1016
+ "entry": "cloud"
1017
+ },
1018
+ {
1019
+ "target": "/app/billing/subscription/checkout/create",
1020
+ "execution": "cloud",
1021
+ "placement": null,
1022
+ "hubReady": false,
1023
+ "cloudReady": false,
1024
+ "entry": "unavailable"
1025
+ },
1026
+ {
1027
+ "target": "/app/billing/subscription/cancel",
1028
+ "execution": "cloud",
1029
+ "placement": null,
1030
+ "hubReady": true,
1031
+ "cloudReady": true,
1032
+ "entry": "cloud"
1033
+ },
1034
+ {
1035
+ "target": "/app/billing/subscription/cancel",
1036
+ "execution": "cloud",
1037
+ "placement": null,
1038
+ "hubReady": true,
1039
+ "cloudReady": false,
1040
+ "entry": "unavailable"
1041
+ },
1042
+ {
1043
+ "target": "/app/billing/subscription/cancel",
1044
+ "execution": "cloud",
1045
+ "placement": null,
1046
+ "hubReady": false,
1047
+ "cloudReady": true,
1048
+ "entry": "cloud"
1049
+ },
1050
+ {
1051
+ "target": "/app/billing/subscription/cancel",
1052
+ "execution": "cloud",
1053
+ "placement": null,
1054
+ "hubReady": false,
1055
+ "cloudReady": false,
1056
+ "entry": "unavailable"
1057
+ },
1058
+ {
1059
+ "target": "/app/billing/subscription/resume",
1060
+ "execution": "cloud",
1061
+ "placement": null,
1062
+ "hubReady": true,
1063
+ "cloudReady": true,
1064
+ "entry": "cloud"
1065
+ },
1066
+ {
1067
+ "target": "/app/billing/subscription/resume",
1068
+ "execution": "cloud",
1069
+ "placement": null,
1070
+ "hubReady": true,
1071
+ "cloudReady": false,
1072
+ "entry": "unavailable"
1073
+ },
1074
+ {
1075
+ "target": "/app/billing/subscription/resume",
1076
+ "execution": "cloud",
1077
+ "placement": null,
1078
+ "hubReady": false,
1079
+ "cloudReady": true,
1080
+ "entry": "cloud"
1081
+ },
1082
+ {
1083
+ "target": "/app/billing/subscription/resume",
1084
+ "execution": "cloud",
1085
+ "placement": null,
1086
+ "hubReady": false,
1087
+ "cloudReady": false,
1088
+ "entry": "unavailable"
1089
+ },
1090
+ {
1091
+ "target": "/app/billing/subscription/change",
1092
+ "execution": "cloud",
1093
+ "placement": null,
1094
+ "hubReady": true,
1095
+ "cloudReady": true,
1096
+ "entry": "cloud"
1097
+ },
1098
+ {
1099
+ "target": "/app/billing/subscription/change",
1100
+ "execution": "cloud",
1101
+ "placement": null,
1102
+ "hubReady": true,
1103
+ "cloudReady": false,
1104
+ "entry": "unavailable"
1105
+ },
1106
+ {
1107
+ "target": "/app/billing/subscription/change",
1108
+ "execution": "cloud",
1109
+ "placement": null,
1110
+ "hubReady": false,
1111
+ "cloudReady": true,
1112
+ "entry": "cloud"
1113
+ },
1114
+ {
1115
+ "target": "/app/billing/subscription/change",
1116
+ "execution": "cloud",
1117
+ "placement": null,
1118
+ "hubReady": false,
1119
+ "cloudReady": false,
1120
+ "entry": "unavailable"
993
1121
  }
994
1122
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.v1",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "callSchema": "schema/facade-call.v1.schema.json",
5
5
  "routing": "manifest/routing.v1.json",
6
6
  "routingSchema": "schema/routing.v1.schema.json",
@@ -406,7 +406,11 @@
406
406
  "requestTargets": [
407
407
  "/app/billing/summary/get",
408
408
  "/app/billing/payment/list",
409
- "/app/billing/credit/usage"
409
+ "/app/billing/credit/usage",
410
+ "/app/billing/subscription/checkout/create",
411
+ "/app/billing/subscription/cancel",
412
+ "/app/billing/subscription/resume",
413
+ "/app/billing/subscription/change"
410
414
  ]
411
415
  }
412
416
  },
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractVersion": "1.111.0",
2
+ "contractVersion": "1.112.1",
3
3
  "operations": {
4
4
  "/app/agent/context/get": "spaceRead",
5
5
  "/app/agent/credit/usage": "spaceRead",
@@ -355,7 +355,11 @@
355
355
  "/pod/talk/request/get": "spaceRead",
356
356
  "/pod/talk/speech/prepare": "spaceWrite",
357
357
  "/pod/talk/turn/submit": "spaceWrite",
358
- "/pod/talk/view/get": "spaceRead"
358
+ "/pod/talk/view/get": "spaceRead",
359
+ "/app/billing/subscription/checkout/create": "userWrite",
360
+ "/app/billing/subscription/cancel": "userWrite",
361
+ "/app/billing/subscription/resume": "userWrite",
362
+ "/app/billing/subscription/change": "userWrite"
359
363
  },
360
364
  "nodePrefix": "/app/plugin/",
361
365
  "serviceOperations": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.host-provision.targets.v1",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "contract": "contract/host-provisioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/host/provision/start",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.hub.targets.v1",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "appTargets": [
5
5
  "/app/hub/get",
6
6
  "/app/hub/remove",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.pod.targets.v1",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "contract": "contract/pod-commissioning-v1.md",
5
5
  "localTargets": [
6
6
  "/local/pod/discovery/start",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.app-facade.routing.v1",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "targetPrefix": "/app/",
5
5
  "default": {
6
6
  "execution": "scopeMode"
@@ -41,7 +41,11 @@
41
41
  "/app/nfc/sources/list",
42
42
  "/app/billing/summary/get",
43
43
  "/app/billing/payment/list",
44
- "/app/billing/credit/usage"
44
+ "/app/billing/credit/usage",
45
+ "/app/billing/subscription/checkout/create",
46
+ "/app/billing/subscription/cancel",
47
+ "/app/billing/subscription/resume",
48
+ "/app/billing/subscription/change"
45
49
  ],
46
50
  "scopeModeTargets": [
47
51
  "/app/artifact/resolve",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "manifest": "mhome.messaging.targets.v1",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "requestTargets": [
5
5
  "/app/messaging/provider/list",
6
6
  "/app/messaging/provider-account/list",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhome/app-facade-protocol",
3
- "version": "1.111.0",
3
+ "version": "1.112.1",
4
4
  "description": "Build-time protocol artifacts for mhome.app-facade",
5
5
  "license": "MIT",
6
6
  "repository": {
package/protocol.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "protocol": "mhome.app-facade",
3
- "contractVersion": "1.111.0",
3
+ "contractVersion": "1.112.1",
4
4
  "manifest": "manifest/app-facade.v1.json",
5
5
  "schemas": {
6
6
  "storage": "schema/storage.v1.schema.json",
@@ -170,6 +170,66 @@
170
170
  "trackedFrom",
171
171
  "rows"
172
172
  ]
173
+ },
174
+ "productInput": {
175
+ "type": "object",
176
+ "additionalProperties": false,
177
+ "properties": {
178
+ "productId": {
179
+ "type": "string",
180
+ "pattern": "^([gG][oO]|[pP][rR][oO]|[pP][lL][uU][sS]|[mM][aA][xX])$"
181
+ }
182
+ },
183
+ "required": [
184
+ "productId"
185
+ ]
186
+ },
187
+ "checkout": {
188
+ "type": "object",
189
+ "additionalProperties": false,
190
+ "properties": {
191
+ "url": {
192
+ "type": "string",
193
+ "minLength": 1
194
+ }
195
+ },
196
+ "required": [
197
+ "url"
198
+ ]
199
+ },
200
+ "subscription": {
201
+ "type": "object",
202
+ "additionalProperties": false,
203
+ "properties": {
204
+ "currentTier": {
205
+ "type": [
206
+ "string",
207
+ "null"
208
+ ]
209
+ },
210
+ "cancelAtPeriodEnd": {
211
+ "type": "boolean"
212
+ },
213
+ "currentPeriodEndTimestamp": {
214
+ "type": "integer"
215
+ },
216
+ "scheduledTier": {
217
+ "type": [
218
+ "string",
219
+ "null"
220
+ ]
221
+ },
222
+ "scheduledTierStartTimestamp": {
223
+ "type": "integer"
224
+ }
225
+ },
226
+ "required": [
227
+ "currentTier",
228
+ "cancelAtPeriodEnd",
229
+ "currentPeriodEndTimestamp",
230
+ "scheduledTier",
231
+ "scheduledTierStartTimestamp"
232
+ ]
173
233
  }
174
234
  }
175
235
  }