@k2b/cloud 0.39.0 → 0.40.0
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 +8 -0
- package/package.json +8 -4
- package/src/_internal/app-favicon.ts +4 -2
- package/src/_internal/capabilities.ts +72 -48
- package/src/_internal/capability-reviews.ts +81 -0
- package/src/_internal/capability-schemas.ts +29 -0
- package/src/_internal/capability-sentences.ts +216 -1
- package/src/_internal/capability-streams.ts +7 -0
- package/src/_internal/define-app.ts +36 -15
- package/src/_internal/font-preloads.ts +2 -1
- package/src/_internal/runtime-watcher.ts +6 -0
- package/src/_internal/static-assets.ts +52 -3
- package/src/_internal/status-preserving-ssr.ts +2 -0
- package/src/access/PermissionEditor.tsx +2 -2
- package/src/account/EntitySearch.tsx +1 -1
- package/src/ai/action-review.ts +101 -0
- package/src/ai/background-review.ts +72 -0
- package/src/ai/capabilities.ts +29 -11
- package/src/ai/capability-execution.ts +76 -43
- package/src/ai/capability-result.ts +95 -0
- package/src/ai/chat/action-card.ts +398 -0
- package/src/ai/chat/action-messages.ts +129 -0
- package/src/ai/chat/action-question.browser-harness.tsx +245 -0
- package/src/ai/chat/action-question.fixtures.ts +733 -0
- package/src/ai/chat/action-question.tsx +669 -0
- package/src/ai/chat/blocks.tsx +19 -25
- package/src/ai/chat/message-actions.tsx +6 -0
- package/src/ai/chat/tool-action.tsx +481 -0
- package/src/ai/chat/turn-view.tsx +10 -160
- package/src/ai/chat/view-block.tsx +15 -5
- package/src/ai/chat-task-contracts.ts +4 -1
- package/src/ai/chat-task-reasons-migrate.ts +7 -0
- package/src/ai/chat-task-reasons.ts +1 -1
- package/src/ai/chat-tasks.ts +55 -25
- package/src/ai/client/controller.ts +59 -0
- package/src/ai/default-tools.ts +9 -1
- package/src/ai/executor.ts +190 -39
- package/src/ai/index.ts +2 -0
- package/src/ai/migrate.ts +11 -2
- package/src/ai/projects-routes.ts +3 -0
- package/src/ai/protocol.ts +14 -2
- package/src/ai/recent-resources.ts +240 -0
- package/src/ai/recent-sent-refs.ts +38 -0
- package/src/ai/routes.ts +145 -1
- package/src/ai/runtime.ts +1 -0
- package/src/ai/skills-routes.ts +3 -0
- package/src/ai/skills.ts +10 -1
- package/src/ai/store.ts +227 -24
- package/src/ai/tool-audit.ts +8 -0
- package/src/ai/tool-wording.ts +24 -2
- package/src/ai/types.ts +28 -3
- package/src/api/accounts-entities.ts +2 -1
- package/src/api/admin-ai-projects.ts +2 -0
- package/src/api/admin-ai-skills.ts +2 -0
- package/src/api/admin-ai-usage.ts +2 -0
- package/src/api/admin-geoip.ts +80 -0
- package/src/api/admin-identity.ts +3 -0
- package/src/api/admin-lifecycle.ts +3 -0
- package/src/api/admin-outgoing-mail.ts +2 -0
- package/src/api/app-approval.ts +46 -5
- package/src/api/approvals-loader.ts +23 -1
- package/src/api/approvals.ts +2 -0
- package/src/api/auth.ts +25 -6
- package/src/api/capabilities.ts +44 -11
- package/src/api/capability-streams.ts +12 -0
- package/src/api/help.ts +4 -28
- package/src/api/index.ts +6 -1
- package/src/api/lasting-access-messages.ts +17 -0
- package/src/api/mcp.ts +3 -0
- package/src/api/me-panel-consent.ts +71 -0
- package/src/api/me.ts +80 -33
- package/src/api/search.ts +3 -1
- package/src/api/sync-ops.ts +2 -0
- package/src/api/widgets.ts +3 -0
- package/src/approvals/Approvals.tsx +180 -238
- package/src/approvals/messages.ts +12 -24
- package/src/browser/CloudResourceSearch.browser-harness.tsx +10 -2
- package/src/browser/app-approval.ts +54 -5
- package/src/browser/commands.ts +22 -6
- package/src/browser/composer-catalog.ts +45 -3
- package/src/browser/composer-insert.ts +10 -0
- package/src/browser/composer-open-messages.ts +17 -0
- package/src/browser/composer-open.ts +110 -0
- package/src/browser/discoverable-command.ts +6 -0
- package/src/browser/hints.ts +6 -0
- package/src/browser/live-connection.ts +26 -2
- package/src/browser/navigation-apps.ts +7 -0
- package/src/browser/panel-context-bridge.ts +30 -0
- package/src/browser/panel-context-receiver.ts +53 -0
- package/src/browser/panel-menu.tsx +56 -0
- package/src/browser/panel-messages.ts +11 -0
- package/src/browser/panel-shortcuts.ts +31 -0
- package/src/browser/panel-slot.ts +412 -10
- package/src/browser/panel.ts +37 -0
- package/src/browser/search-commands.ts +6 -3
- package/src/capabilities/client.ts +8 -2
- package/src/capabilities/reviews.ts +205 -0
- package/src/capabilities/server.ts +10 -3
- package/src/capabilities/testing.ts +47 -0
- package/src/capabilities/types.ts +2 -2
- package/src/cli/account.ts +13 -3
- package/src/cli/admin/geoip.ts +115 -0
- package/src/cli/admin/index.ts +3 -0
- package/src/contracts/app-approval.ts +120 -13
- package/src/contracts/approvals.ts +2 -2
- package/src/contracts/capabilities.ts +410 -18
- package/src/contracts/geoip.ts +42 -0
- package/src/contracts/index.ts +3 -0
- package/src/contracts/panel-context-plain.ts +99 -0
- package/src/contracts/panel-context.ts +93 -0
- package/src/contracts/seen-hints.ts +35 -0
- package/src/server/client-ip.ts +5 -0
- package/src/server/help-payload.ts +38 -0
- package/src/server/middleware/auth.ts +11 -1
- package/src/server/middleware/middleware.ts +9 -0
- package/src/server/middleware/no-transform.ts +19 -0
- package/src/server/middleware/rate-limit.ts +4 -6
- package/src/server/request-context/address.ts +45 -0
- package/src/server/request-context/geoip.ts +380 -0
- package/src/server/request-context/index.ts +33 -0
- package/src/server/request-context/user-agent.ts +95 -0
- package/src/services/app-approval.ts +382 -59
- package/src/services/approvals/device.ts +7 -5
- package/src/services/approvals/index.ts +6 -5
- package/src/services/approvals/list.ts +26 -5
- package/src/services/auth-flows/notification-sender.ts +3 -0
- package/src/services/geoip/index.ts +164 -0
- package/src/services/geoip/store.ts +30 -0
- package/src/services/geoip/upload.ts +150 -0
- package/src/services/identity/routes.ts +5 -1
- package/src/services/index.ts +11 -0
- package/src/services/known-browsers.ts +312 -0
- package/src/services/login-address-store.ts +51 -0
- package/src/services/login-context.ts +118 -0
- package/src/services/mandates/index.ts +3 -0
- package/src/services/mandates/policy.ts +15 -3
- package/src/services/notifications/email-frame.ts +1 -1
- package/src/services/oauth-tokens.ts +16 -2
- package/src/services/panel-context-consent.ts +58 -0
- package/src/services/service-account-credentials.ts +21 -0
- package/src/services/session/index.ts +97 -16
- package/src/services/session/recent.ts +13 -0
- package/src/services/webauthn.ts +12 -0
- package/src/shared/email-html.ts +2 -0
- package/src/shared/help.ts +3 -0
- package/src/shared-text/cursor.ts +22 -0
- package/src/shared-text/documents.ts +142 -0
- package/src/shared-text/events.ts +43 -0
- package/src/shared-text/index.ts +12 -0
- package/src/shared-text/log.ts +48 -0
- package/src/shared-text/text-diff.ts +23 -0
- package/src/shared-text/types.ts +41 -0
- package/src/ssr/AdminLayout.tsx +2 -0
- package/src/ssr/AppLaunchpadPanel.tsx +2 -2
- package/src/ssr/CloudShell.island.tsx +10 -2
- package/src/ssr/Layout.tsx +25 -2
- package/src/ssr/LayoutHelp.browser-harness.tsx +2 -0
- package/src/ssr/LayoutHelp.tsx +435 -274
- package/src/ssr/LayoutHelpPanel.browser-harness.tsx +136 -0
- package/src/ssr/LayoutHelpTrigger.tsx +27 -2
- package/src/ssr/MobileNavigation.tsx +2 -2
- package/src/ssr/PanelLayout.tsx +9 -1
- package/src/ssr/PanelRuntime.island.tsx +7 -0
- package/src/ssr/PanelSlot.tsx +53 -3
- package/src/ssr/ShellRuntime.island.tsx +11 -2
- package/src/ssr/app-color.ts +14 -9
- package/src/ssr/app-navigation.ts +16 -3
- package/src/ssr/compact-shell.browser-harness.ts +30 -22
- package/src/ssr/dialog-app-colors.browser-harness.tsx +43 -0
- package/src/ssr/help-messages.ts +4 -0
- package/src/ssr/help.ts +20 -0
- package/src/ssr/hints.ts +25 -0
- package/src/ssr/index.ts +2 -0
- package/src/ssr/islands/index.ts +4 -3
- package/src/ssr/layout-context.ts +2 -0
- package/src/ssr/layout-help-article.server.ts +50 -0
- package/src/ssr/layout-help-start.ts +33 -7
- package/src/ssr/panel-consent.ts +29 -0
- package/src/ssr/panel-context.ts +10 -0
- package/src/ssr/panel-slot.browser-harness.tsx +53 -4
- package/src/ssr/platform-messages.ts +18 -0
- package/src/ssr/shell-data.tsx +2 -1
- package/src/styles/effects.css +198 -9
- package/src/styles/file-chooser.css +2 -1
- package/src/styles/global.css +49 -12
- package/src/styles/panel.css +47 -4
- package/src/styles/resource-search.css +6 -2
- package/src/styles/tokens.css +17 -11
- package/src/styles/utilities-buttons.css +3 -2
- package/src/styles/utilities-data.css +2 -1
- package/src/styles/utilities-feedback.css +2 -2
- package/src/styles/utilities-layout.css +3 -13
- package/src/styles/utilities-markdown-editor.css +6 -6
- package/src/styles/utilities-navigation.css +17 -22
|
@@ -30,10 +30,23 @@ export const APP_ACTION_LIMITS = {
|
|
|
30
30
|
valueChars: 300,
|
|
31
31
|
} as const;
|
|
32
32
|
/** Commands a Cloud serves beyond the first version, announced in `/info` as `features`. */
|
|
33
|
-
export const APP_APPROVAL_FEATURES = ["actions", "terminal-logins"] as const;
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
export const APP_APPROVAL_FEATURES = ["actions", "terminal-logins", "login-context", "device-changes"] as const;
|
|
34
|
+
/**
|
|
35
|
+
* Optional inbox parts a device asks for in its signed `inbox` command. Without `accept`, the command, its
|
|
36
|
+
* signed message and the inbox answer keep their first form byte for byte.
|
|
37
|
+
*/
|
|
38
|
+
export const APP_APPROVAL_ACCEPT = ["terminal-logins", "login-context", "device-changes"] as const;
|
|
36
39
|
export type AppApprovalAccept = (typeof APP_APPROVAL_ACCEPT)[number];
|
|
40
|
+
export const APP_APPROVAL_PENDING_ACCEPT = ["login-context"] as const;
|
|
41
|
+
export type AppApprovalPendingAccept = (typeof APP_APPROVAL_PENDING_ACCEPT)[number];
|
|
42
|
+
|
|
43
|
+
const acceptList = <T extends readonly [string, ...string[]]>(values: T) =>
|
|
44
|
+
z
|
|
45
|
+
.array(z.enum(values))
|
|
46
|
+
.min(1)
|
|
47
|
+
.max(8)
|
|
48
|
+
.refine((entries) => new Set(entries).size === entries.length)
|
|
49
|
+
.optional();
|
|
37
50
|
|
|
38
51
|
const Id = z.string().uuid();
|
|
39
52
|
const Secret = z.string().regex(/^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/);
|
|
@@ -70,10 +83,14 @@ export const AppLoginStartSchema = z
|
|
|
70
83
|
export const AppLoginReferenceSchema = z.object({ requestId: Id, browserSecret: Secret }).strict();
|
|
71
84
|
export const AppDeviceMutationSchema = z.discriminatedUnion("operation", [
|
|
72
85
|
z.object({ operation: z.literal("rename"), deviceId: Id, name: z.string().trim().min(1).max(80) }).strict(),
|
|
73
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Asks the account's paired devices to approve removing this device. `endSessions` (default `true`) also ends
|
|
88
|
+
* the sign-ins this device approved, except the requesting session.
|
|
89
|
+
*/
|
|
90
|
+
z.object({ operation: z.literal("revoke"), deviceId: Id, endSessions: z.boolean().optional() }).strict(),
|
|
74
91
|
]);
|
|
75
92
|
export const AppDeviceCommandSchema = z.discriminatedUnion("operation", [
|
|
76
|
-
z.object({ operation: z.literal("pending") }).strict(),
|
|
93
|
+
z.object({ operation: z.literal("pending"), accept: acceptList(APP_APPROVAL_PENDING_ACCEPT) }).strict(),
|
|
77
94
|
z.object({ operation: z.literal("revoke") }).strict(),
|
|
78
95
|
/** Reads the signing device's own account and device record, e.g. to show which account it signs in. */
|
|
79
96
|
z.object({ operation: z.literal("account") }).strict(),
|
|
@@ -83,18 +100,25 @@ export const AppDeviceCommandSchema = z.discriminatedUnion("operation", [
|
|
|
83
100
|
z
|
|
84
101
|
.object({
|
|
85
102
|
operation: z.literal("inbox"),
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.min(1)
|
|
89
|
-
.max(8)
|
|
90
|
-
.refine((values) => new Set(values).size === values.length)
|
|
91
|
-
.optional(),
|
|
103
|
+
/** Optional inbox parts this device shows; only send values the Cloud lists in `/info` `features`. */
|
|
104
|
+
accept: acceptList(APP_APPROVAL_ACCEPT),
|
|
92
105
|
})
|
|
93
106
|
.strict(),
|
|
94
107
|
/** One open Action approval as the device shows it, with the digest the device recomputes before it decides. */
|
|
95
108
|
z.object({ operation: z.literal("action"), actionId: Id }).strict(),
|
|
96
109
|
/** Decides an Action approval. `digest` binds the decision to exactly the view the person saw. */
|
|
97
110
|
z.object({ operation: z.literal("act"), actionId: Id, digest: Digest, decision: z.enum(["approve", "deny"]) }).strict(),
|
|
111
|
+
/** Decides a request to pair or remove a device of the signing device's account. Binds every fact the device showed. */
|
|
112
|
+
z
|
|
113
|
+
.object({
|
|
114
|
+
operation: z.literal("change"),
|
|
115
|
+
changeId: Id,
|
|
116
|
+
kind: z.enum(["pair", "revoke"]),
|
|
117
|
+
targetId: Id,
|
|
118
|
+
endSessions: z.boolean(),
|
|
119
|
+
decision: z.enum(["approve", "deny"]),
|
|
120
|
+
})
|
|
121
|
+
.strict(),
|
|
98
122
|
z
|
|
99
123
|
.object({
|
|
100
124
|
operation: z.literal("decide"),
|
|
@@ -134,7 +158,8 @@ export const appDeviceProofMessage = (proof: AppDeviceProof): string => {
|
|
|
134
158
|
c.operation,
|
|
135
159
|
...(c.operation === "decide" ? [c.requestId, c.challenge, c.comparison, c.decision] : []),
|
|
136
160
|
...(c.operation === "push" ? [c.token] : []),
|
|
137
|
-
...(c.operation === "inbox" && c.accept !== undefined ? [c.accept] : []),
|
|
161
|
+
...((c.operation === "inbox" || c.operation === "pending") && c.accept !== undefined ? [c.accept] : []),
|
|
162
|
+
...(c.operation === "change" ? [c.changeId, c.kind, c.targetId, c.endSessions, c.decision] : []),
|
|
138
163
|
...(c.operation === "action" ? [c.actionId] : []),
|
|
139
164
|
...(c.operation === "act" ? [c.actionId, c.digest, c.decision] : []),
|
|
140
165
|
]);
|
|
@@ -190,6 +215,44 @@ export const AppTerminalLoginSchema = z
|
|
|
190
215
|
})
|
|
191
216
|
.strict();
|
|
192
217
|
export type AppTerminalLogin = z.infer<typeof AppTerminalLoginSchema>;
|
|
218
|
+
export const APP_LOGIN_CONTEXT_BROWSERS = ["firefox", "chrome", "safari", "edge", "samsung", "opera", "other"] as const;
|
|
219
|
+
export const APP_LOGIN_CONTEXT_OSES = ["windows", "macos", "mac-or-ipad", "ios", "android", "linux", "chromeos", "other"] as const;
|
|
220
|
+
const ContextName = PlainText(96)
|
|
221
|
+
.min(1)
|
|
222
|
+
.refine((value) => new TextEncoder().encode(value).length <= 96);
|
|
223
|
+
/** Core alone computes the level. The app displays it and never derives its own.
|
|
224
|
+
* Terminal logins never carry context. Opted-in browser logins carry it unless
|
|
225
|
+
* started before the upgrade or omitted to fit the response budget.
|
|
226
|
+
* History is null during introduction; sameNetwork is a positive, transient hint. */
|
|
227
|
+
export const AppLoginContextSchema = z
|
|
228
|
+
.object({
|
|
229
|
+
/** Computed by Core only; descriptive signals never change it. */
|
|
230
|
+
level: z.enum(["info", "hint", "warn"]),
|
|
231
|
+
browser: z.enum(APP_LOGIN_CONTEXT_BROWSERS),
|
|
232
|
+
os: z.enum(APP_LOGIN_CONTEXT_OSES),
|
|
233
|
+
country: z
|
|
234
|
+
.string()
|
|
235
|
+
.regex(/^[A-Z]{2}$/)
|
|
236
|
+
.nullable(),
|
|
237
|
+
city: ContextName.nullable(),
|
|
238
|
+
/** Operator name, never a VPN or data-center classification. */
|
|
239
|
+
network: ContextName.nullable(),
|
|
240
|
+
history: z
|
|
241
|
+
.object({
|
|
242
|
+
/** This browser's first_seen_at for the account, or null when unknown. */
|
|
243
|
+
knownSince: DateTime.nullable(),
|
|
244
|
+
/** A request country, geoip_since set, and no sign-in from it inside the 90-day window. */
|
|
245
|
+
newCountry: z.boolean(),
|
|
246
|
+
/** geoip_since only when less than 90 days ago; the app can say "since {date}". */
|
|
247
|
+
countriesSince: DateTime.nullable(),
|
|
248
|
+
})
|
|
249
|
+
.strict()
|
|
250
|
+
.nullable(),
|
|
251
|
+
sameNetwork: z.literal(true).optional(),
|
|
252
|
+
})
|
|
253
|
+
.strict();
|
|
254
|
+
export type AppLoginContext = z.infer<typeof AppLoginContextSchema>;
|
|
255
|
+
|
|
193
256
|
export const AppPendingLoginSchema = z
|
|
194
257
|
.object({
|
|
195
258
|
requestId: Id,
|
|
@@ -198,6 +261,7 @@ export const AppPendingLoginSchema = z
|
|
|
198
261
|
createdAt: DateTime,
|
|
199
262
|
expiresAt: DateTime,
|
|
200
263
|
terminal: AppTerminalLoginSchema.optional(),
|
|
264
|
+
context: AppLoginContextSchema.optional(),
|
|
201
265
|
})
|
|
202
266
|
.strict();
|
|
203
267
|
export const AppPairingPayloadSchema = z
|
|
@@ -251,8 +315,29 @@ export const AppPairingClaimResultSchema = z.object({ deviceId: Id, comparison:
|
|
|
251
315
|
export const AppPairingResultSchema = z
|
|
252
316
|
.object({ state: z.enum(["pending", "claimed", "confirmed", "cancelled"]), deviceId: Id.nullable(), comparison: Comparison.nullable() })
|
|
253
317
|
.strict();
|
|
318
|
+
/** Approval of a pairing by one of the account's paired devices, as the initiating browser follows it. */
|
|
319
|
+
export const AppDeviceChangeStatusSchema = z
|
|
320
|
+
.object({ state: z.enum(["pending", "approved", "denied", "cancelled", "expired"]), expiresAt: DateTime })
|
|
321
|
+
.strict();
|
|
322
|
+
export type AppDeviceChangeStatus = z.infer<typeof AppDeviceChangeStatusSchema>;
|
|
254
323
|
/** Initiating Cloud session only; never returned to an unpaired device. */
|
|
255
|
-
export const AppPairingInspectionSchema = AppPairingResultSchema.extend({
|
|
324
|
+
export const AppPairingInspectionSchema = AppPairingResultSchema.extend({
|
|
325
|
+
name: z.string().nullable(),
|
|
326
|
+
userId: Id,
|
|
327
|
+
/** Set once the code was confirmed while the account already had a paired device: one of them approves. */
|
|
328
|
+
approval: AppDeviceChangeStatusSchema.nullable(),
|
|
329
|
+
});
|
|
330
|
+
/** `approval` is set when one of the account's paired devices must approve before the device is paired. */
|
|
331
|
+
export const AppPairingConfirmResultSchema = z.object({ deviceId: Id, approval: AppDeviceChangeStatusSchema.nullable() }).strict();
|
|
332
|
+
export const AppDeviceChangeReferenceSchema = z.object({ changeId: Id }).strict();
|
|
333
|
+
/** A removal by its id, or this session's newest removal of a device, e.g. after the answer that named it was lost. */
|
|
334
|
+
export const AppDeviceChangeLookupSchema = z.union([AppDeviceChangeReferenceSchema, z.object({ deviceId: Id }).strict()]);
|
|
335
|
+
export const AppDeviceRemovalStatusSchema = AppDeviceChangeStatusSchema.extend({ changeId: Id, endSessions: z.boolean() }).strict();
|
|
336
|
+
/** A device that is already revoked answers `revoked`; an active one waits for approval on a paired device. */
|
|
337
|
+
export const AppDeviceRevokeResultSchema = z.union([
|
|
338
|
+
z.object({ state: z.literal("revoked") }).strict(),
|
|
339
|
+
z.object({ state: z.literal("pending"), changeId: Id, expiresAt: DateTime }).strict(),
|
|
340
|
+
]);
|
|
256
341
|
/** Answer to the `account` command: only the signing device's own account, never secrets or other users. */
|
|
257
342
|
export const AppDeviceAccountSchema = z
|
|
258
343
|
.object({
|
|
@@ -316,6 +401,27 @@ export const AppDeviceInboxSchema = z
|
|
|
316
401
|
})
|
|
317
402
|
.strict();
|
|
318
403
|
export type AppDeviceInbox = z.infer<typeof AppDeviceInboxSchema>;
|
|
404
|
+
/** A request to pair or remove a device of this account, shown to the account's paired devices. */
|
|
405
|
+
export const AppDeviceChangeSchema = z
|
|
406
|
+
.object({
|
|
407
|
+
changeId: Id,
|
|
408
|
+
kind: z.enum(["pair", "revoke"]),
|
|
409
|
+
/** The device to pair or remove, with the name the account gave it. The name may be empty. */
|
|
410
|
+
device: z.object({ id: Id, name: PlainText(80) }).strict(),
|
|
411
|
+
/** Removal only: also end the sign-ins this device approved. Always `false` for a pairing. */
|
|
412
|
+
endSessions: z.boolean(),
|
|
413
|
+
createdAt: DateTime,
|
|
414
|
+
expiresAt: DateTime,
|
|
415
|
+
})
|
|
416
|
+
.strict();
|
|
417
|
+
export type AppDeviceChange = z.infer<typeof AppDeviceChangeSchema>;
|
|
418
|
+
/** The inbox for a device that sent `accept: ["device-changes"]`. Oldest first. */
|
|
419
|
+
export const AppDeviceInboxWithChangesSchema = AppDeviceInboxSchema.extend({
|
|
420
|
+
changes: z.array(AppDeviceChangeSchema).max(APP_APPROVAL_LIMITS.pendingPerAccount),
|
|
421
|
+
/** Pending device changes omitted to fit the response budget. */
|
|
422
|
+
moreChanges: z.number().int().nonnegative().max(APP_APPROVAL_LIMITS.pendingPerAccount),
|
|
423
|
+
}).strict();
|
|
424
|
+
export type AppDeviceInboxWithChanges = z.infer<typeof AppDeviceInboxWithChangesSchema>;
|
|
319
425
|
|
|
320
426
|
/** UTF-8 of this exact JSON array is hashed into an Action's `digest`. Every field the device shows is part of it. */
|
|
321
427
|
export const appActionDigestMessage = (issuer: string, view: Omit<AppActionView, "digest">): string =>
|
|
@@ -356,6 +462,7 @@ export const AppDeviceResponseSchema = z.union([
|
|
|
356
462
|
z.object({ state: z.enum(["approved", "denied", "revoked", "updated"]) }).strict(),
|
|
357
463
|
AppDeviceAccountSchema,
|
|
358
464
|
AppDeviceInboxSchema,
|
|
465
|
+
AppDeviceInboxWithChangesSchema,
|
|
359
466
|
AppActionViewSchema,
|
|
360
467
|
]);
|
|
361
468
|
export const AppLoginStartResultSchema = z
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { APP_APPROVAL_LIMITS } from "./app-approval";
|
|
3
|
-
import {
|
|
3
|
+
import { CapabilityActionReviewDataSchema, CapabilityAppIdSchema } from "./capabilities";
|
|
4
4
|
|
|
5
5
|
export { APPROVAL_COUNTS_PATH, APPROVALS_API_PATH, APPROVALS_PAGE_PATH } from "./approval-paths";
|
|
6
6
|
|
|
@@ -42,7 +42,7 @@ export const PendingApprovalSchema = z
|
|
|
42
42
|
/** What the person reads: the first line names the app and the Action, later lines add `Label: value` details. */
|
|
43
43
|
sentence: z.string(),
|
|
44
44
|
/** The owning app's review as the person saw it when Cloud asked. */
|
|
45
|
-
review:
|
|
45
|
+
review: CapabilityActionReviewDataSchema.nullable(),
|
|
46
46
|
/** Where the request waits. The title is chat content, written by a person or a model, never Cloud's own words. */
|
|
47
47
|
requester: z.object({ kind: z.literal("chat"), appId: z.string(), title: z.string().nullable(), href: z.string() }).strict(),
|
|
48
48
|
/** Ways the person may remember this approval, the same the chat card offers. */
|