@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
|
@@ -17,6 +17,7 @@ export const CAPABILITY_MAX_RESULT_BYTES = 256 * 1024;
|
|
|
17
17
|
export const CAPABILITY_MAX_CATALOG_BYTES = 2 * 1024 * 1024;
|
|
18
18
|
export const CAPABILITY_QUALIFIED_ID_MAX_LENGTH = 180;
|
|
19
19
|
export const CLOUD_RESOURCE_ID_MAX_LENGTH = 512;
|
|
20
|
+
export const CAPABILITY_APP_ID_MAX_LENGTH = 80;
|
|
20
21
|
|
|
21
22
|
export const CAPABILITY_FRAMEWORK_ERROR_CODES = {
|
|
22
23
|
appUnavailable: "APP_UNAVAILABLE",
|
|
@@ -147,6 +148,7 @@ const CapabilityActionReviewDetailSchema = z
|
|
|
147
148
|
}
|
|
148
149
|
});
|
|
149
150
|
|
|
151
|
+
/** @deprecated the next major release replaces this shape; return CapabilityActionCallReview. */
|
|
150
152
|
export const CapabilityActionReviewSchema = z
|
|
151
153
|
.object({
|
|
152
154
|
message: z.string().min(1).max(1000).describe("Plain-text description of the concrete Action consequence."),
|
|
@@ -156,8 +158,344 @@ export const CapabilityActionReviewSchema = z
|
|
|
156
158
|
})
|
|
157
159
|
.strict();
|
|
158
160
|
|
|
161
|
+
/** @deprecated the next major release replaces this shape; return CapabilityActionCallReview. */
|
|
159
162
|
export type CapabilityActionReview = z.infer<typeof CapabilityActionReviewSchema>;
|
|
160
163
|
|
|
164
|
+
export const CAPABILITY_ASK_REASONS = [
|
|
165
|
+
"sends",
|
|
166
|
+
"deletes",
|
|
167
|
+
"cannot_undo",
|
|
168
|
+
"involves_people",
|
|
169
|
+
"changes_access",
|
|
170
|
+
"keeps_working",
|
|
171
|
+
"sensitive",
|
|
172
|
+
"app_asks",
|
|
173
|
+
] as const;
|
|
174
|
+
export type CapabilityAskReason = (typeof CAPABILITY_ASK_REASONS)[number];
|
|
175
|
+
export const CAPABILITY_REACHES = ["you", "draft", "shared"] as const;
|
|
176
|
+
export type CapabilityReach = (typeof CAPABILITY_REACHES)[number];
|
|
177
|
+
export const CAPABILITY_ACTION_OUTCOMES = ["running", "done", "rejected", "not_run", "unknown"] as const;
|
|
178
|
+
export type CapabilityActionOutcome = (typeof CAPABILITY_ACTION_OUTCOMES)[number];
|
|
179
|
+
export const CAPABILITY_MAX_REVIEW_BYTES = 32 * 1024;
|
|
180
|
+
export const CapabilityActionPolicySchema = z.union([
|
|
181
|
+
z.object({ silent: z.enum(CAPABILITY_REACHES), routines: z.literal(false).optional() }).strict(),
|
|
182
|
+
z.object({ ask: z.enum(CAPABILITY_ASK_REASONS) }).strict(),
|
|
183
|
+
]);
|
|
184
|
+
export type CapabilityActionPolicy = z.infer<typeof CapabilityActionPolicySchema>;
|
|
185
|
+
|
|
186
|
+
const reviewLine = (max: number, min = 1) =>
|
|
187
|
+
z
|
|
188
|
+
.string()
|
|
189
|
+
.min(min)
|
|
190
|
+
.max(max)
|
|
191
|
+
.refine((text) => !/[\p{Cc}\p{Cf}\u2028\u2029]/u.test(text), "Contains unsafe characters");
|
|
192
|
+
const reviewBlock = (max: number) =>
|
|
193
|
+
z
|
|
194
|
+
.string()
|
|
195
|
+
.max(max)
|
|
196
|
+
.refine((text) => !/[\p{Cc}\p{Cf}\u2028\u2029]/u.test(text.replace(/[\n\t]/g, "")), "Contains unsafe characters");
|
|
197
|
+
export const CapabilityPersonSchema = z
|
|
198
|
+
.object({ name: reviewLine(120).optional(), address: reviewLine(320).optional(), userId: z.uuid().optional() })
|
|
199
|
+
.strict()
|
|
200
|
+
.refine((person) => person.name !== undefined || person.address !== undefined, "A person needs a name or address");
|
|
201
|
+
export type CapabilityPerson = z.infer<typeof CapabilityPersonSchema>;
|
|
202
|
+
const reviewTime = z.iso.datetime({ offset: true });
|
|
203
|
+
const reviewDay = z.iso.date();
|
|
204
|
+
const reviewIcon = z.string().regex(/^ti ti-[a-z0-9-]+$/);
|
|
205
|
+
export const CapabilitySlotSchema = z.discriminatedUnion("kind", [
|
|
206
|
+
z
|
|
207
|
+
.object({
|
|
208
|
+
kind: z.literal("object"),
|
|
209
|
+
title: reviewLine(200),
|
|
210
|
+
ref: CloudResourceRefSchema.optional(),
|
|
211
|
+
icon: reviewIcon.optional(),
|
|
212
|
+
gone: z.literal(true).optional(),
|
|
213
|
+
})
|
|
214
|
+
.strict(),
|
|
215
|
+
z
|
|
216
|
+
.object({ kind: z.literal("place"), title: reviewLine(200), ref: CloudResourceRefSchema.optional(), icon: reviewIcon.optional() })
|
|
217
|
+
.strict(),
|
|
218
|
+
z
|
|
219
|
+
.object({
|
|
220
|
+
kind: z.literal("person"),
|
|
221
|
+
people: z.array(CapabilityPersonSchema).min(1).max(20),
|
|
222
|
+
total: z.number().int().min(1).max(100_000).optional(),
|
|
223
|
+
})
|
|
224
|
+
.strict()
|
|
225
|
+
.refine((slot) => slot.total === undefined || slot.total >= slot.people.length, "total is smaller than people"),
|
|
226
|
+
z
|
|
227
|
+
.object({ kind: z.literal("time"), start: z.string(), end: z.string().optional(), format: z.enum(["date", "date-time"]) })
|
|
228
|
+
.strict()
|
|
229
|
+
.superRefine((slot, ctx) => {
|
|
230
|
+
const schema = slot.format === "date" ? reviewDay : reviewTime;
|
|
231
|
+
for (const key of ["start", "end"] as const)
|
|
232
|
+
if (slot[key] !== undefined && !schema.safeParse(slot[key]).success)
|
|
233
|
+
ctx.addIssue({ code: "custom", path: [key], message: "Invalid date or time" });
|
|
234
|
+
if (slot.end && (slot.format === "date" ? slot.end < slot.start : Date.parse(slot.end) < Date.parse(slot.start)))
|
|
235
|
+
ctx.addIssue({ code: "custom", path: ["end"], message: "end precedes start" });
|
|
236
|
+
}),
|
|
237
|
+
z
|
|
238
|
+
.object({
|
|
239
|
+
kind: z.literal("count"),
|
|
240
|
+
value: z.number().int().min(0).max(1_000_000_000),
|
|
241
|
+
noun: z
|
|
242
|
+
.object({
|
|
243
|
+
zero: reviewLine(40).optional(),
|
|
244
|
+
one: reviewLine(40).optional(),
|
|
245
|
+
two: reviewLine(40).optional(),
|
|
246
|
+
few: reviewLine(40).optional(),
|
|
247
|
+
many: reviewLine(40).optional(),
|
|
248
|
+
other: reviewLine(40),
|
|
249
|
+
})
|
|
250
|
+
.strict(),
|
|
251
|
+
})
|
|
252
|
+
.strict(),
|
|
253
|
+
z.object({ kind: z.literal("text"), value: reviewLine(200) }).strict(),
|
|
254
|
+
]);
|
|
255
|
+
export type CapabilitySlot = z.infer<typeof CapabilitySlotSchema>;
|
|
256
|
+
const reviewSlots = z
|
|
257
|
+
.record(z.string().regex(/^[a-z][A-Za-z0-9]{0,31}$/), CapabilitySlotSchema)
|
|
258
|
+
.refine((slots) => Object.keys(slots).length <= 6, "At most 6 slots");
|
|
259
|
+
const reviewTemplate = reviewLine(200).refine(
|
|
260
|
+
(text) => !/[{}]/.test(text.replace(/\{[a-z][A-Za-z0-9]{0,31}\}/g, "")),
|
|
261
|
+
"Invalid placeholder",
|
|
262
|
+
);
|
|
263
|
+
/** Context-free sentence rules, also used for consequence and rule sentences. */
|
|
264
|
+
export const capabilitySentenceIssues = (
|
|
265
|
+
text: string,
|
|
266
|
+
slots: Readonly<Record<string, CapabilitySlot>>,
|
|
267
|
+
complete = true,
|
|
268
|
+
chips = true,
|
|
269
|
+
): string[] => {
|
|
270
|
+
const names = [...text.matchAll(/\{([a-z][A-Za-z0-9]{0,31})\}/g)].map((match) => match[1]!);
|
|
271
|
+
const issues: string[] = [];
|
|
272
|
+
if (/[{}]/.test(text.replace(/\{[a-z][A-Za-z0-9]{0,31}\}/g, ""))) issues.push("Invalid placeholder");
|
|
273
|
+
for (const name of names) if (!Object.hasOwn(slots, name)) issues.push(`Unknown slot ${name}`);
|
|
274
|
+
if (complete) for (const name of Object.keys(slots)) if (!names.includes(name)) issues.push(`Missing slot ${name}`);
|
|
275
|
+
if (
|
|
276
|
+
chips &&
|
|
277
|
+
names.filter((name) => {
|
|
278
|
+
const slot = Object.hasOwn(slots, name) ? slots[name] : undefined;
|
|
279
|
+
return slot && slot.kind !== "text" && slot.kind !== "count";
|
|
280
|
+
}).length > 3
|
|
281
|
+
)
|
|
282
|
+
issues.push("At most 3 chip slots");
|
|
283
|
+
return issues;
|
|
284
|
+
};
|
|
285
|
+
const sentenceShape = { text: reviewTemplate, slots: reviewSlots.readonly().optional() };
|
|
286
|
+
const sentenceRefinement = (sentence: { text: string; slots?: Readonly<Record<string, CapabilitySlot>> }, ctx: z.RefinementCtx) => {
|
|
287
|
+
for (const message of capabilitySentenceIssues(sentence.text, sentence.slots ?? {})) ctx.addIssue({ code: "custom", message });
|
|
288
|
+
};
|
|
289
|
+
export const CapabilitySentenceSchema = z.object(sentenceShape).strict().superRefine(sentenceRefinement);
|
|
290
|
+
export type CapabilitySentence = z.infer<typeof CapabilitySentenceSchema>;
|
|
291
|
+
export const CapabilityConsequenceSchema = z
|
|
292
|
+
.object({ ...sentenceShape, mark: z.enum(["added", "removed"]).optional() })
|
|
293
|
+
.strict()
|
|
294
|
+
.superRefine(sentenceRefinement);
|
|
295
|
+
export type CapabilityConsequence = z.infer<typeof CapabilityConsequenceSchema>;
|
|
296
|
+
const previewPeople = (max: number) => z.array(CapabilityPersonSchema).max(max);
|
|
297
|
+
const extraCount = z.number().int().min(0).max(100_000);
|
|
298
|
+
const previewZone = reviewLine(200).refine((zone) => {
|
|
299
|
+
try {
|
|
300
|
+
new Intl.DateTimeFormat("en", { timeZone: zone });
|
|
301
|
+
return true;
|
|
302
|
+
} catch {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}, "Invalid time zone");
|
|
306
|
+
export const CapabilityPreviewSchema = z.discriminatedUnion("kind", [
|
|
307
|
+
z
|
|
308
|
+
.object({
|
|
309
|
+
kind: z.literal("message"),
|
|
310
|
+
from: CapabilityPersonSchema.optional(),
|
|
311
|
+
to: previewPeople(50),
|
|
312
|
+
cc: previewPeople(50).optional(),
|
|
313
|
+
bcc: previewPeople(50).optional(),
|
|
314
|
+
more: z.object({ to: extraCount.optional(), cc: extraCount.optional(), bcc: extraCount.optional() }).strict().optional(),
|
|
315
|
+
subject: reviewLine(998, 0),
|
|
316
|
+
body: reviewBlock(10_000),
|
|
317
|
+
format: z.enum(["plain", "markdown"]),
|
|
318
|
+
truncated: z.boolean().optional(),
|
|
319
|
+
attachments: z
|
|
320
|
+
.array(
|
|
321
|
+
z
|
|
322
|
+
.object({ name: reviewLine(255), size: z.number().int().nonnegative().optional(), ref: CloudResourceRefSchema.optional() })
|
|
323
|
+
.strict(),
|
|
324
|
+
)
|
|
325
|
+
.max(50)
|
|
326
|
+
.optional(),
|
|
327
|
+
moreAttachments: extraCount.optional(),
|
|
328
|
+
sendAt: reviewTime.optional(),
|
|
329
|
+
warnings: z.array(reviewLine(300)).max(5).optional(),
|
|
330
|
+
})
|
|
331
|
+
.strict()
|
|
332
|
+
.refine(
|
|
333
|
+
(preview) =>
|
|
334
|
+
preview.to.length +
|
|
335
|
+
(preview.cc?.length ?? 0) +
|
|
336
|
+
(preview.bcc?.length ?? 0) +
|
|
337
|
+
(preview.more?.to ?? 0) +
|
|
338
|
+
(preview.more?.cc ?? 0) +
|
|
339
|
+
(preview.more?.bcc ?? 0) >
|
|
340
|
+
0,
|
|
341
|
+
"A message needs a recipient",
|
|
342
|
+
),
|
|
343
|
+
z
|
|
344
|
+
.object({
|
|
345
|
+
kind: z.literal("event"),
|
|
346
|
+
title: reviewLine(200),
|
|
347
|
+
start: z.union([reviewDay, reviewTime]),
|
|
348
|
+
end: z.union([reviewDay, reviewTime]).optional(),
|
|
349
|
+
allDay: z.boolean().optional(),
|
|
350
|
+
timeZone: previewZone.optional(),
|
|
351
|
+
place: reviewLine(200).optional(),
|
|
352
|
+
location: reviewLine(200).optional(),
|
|
353
|
+
recurrence: reviewLine(200).optional(),
|
|
354
|
+
attendees: previewPeople(50).optional(),
|
|
355
|
+
description: reviewBlock(2000).optional(),
|
|
356
|
+
})
|
|
357
|
+
.strict(),
|
|
358
|
+
z
|
|
359
|
+
.object({
|
|
360
|
+
kind: z.literal("task"),
|
|
361
|
+
title: reviewLine(200),
|
|
362
|
+
place: reviewLine(200).optional(),
|
|
363
|
+
due: z.union([reviewDay, reviewTime]).optional(),
|
|
364
|
+
assignees: previewPeople(20).optional(),
|
|
365
|
+
status: reviewLine(60).optional(),
|
|
366
|
+
checklist: z
|
|
367
|
+
.array(z.object({ label: reviewLine(200), done: z.boolean() }).strict())
|
|
368
|
+
.max(20)
|
|
369
|
+
.optional(),
|
|
370
|
+
tags: z.array(reviewLine(60)).max(10).optional(),
|
|
371
|
+
description: reviewBlock(2000).optional(),
|
|
372
|
+
})
|
|
373
|
+
.strict(),
|
|
374
|
+
z
|
|
375
|
+
.object({
|
|
376
|
+
kind: z.literal("page"),
|
|
377
|
+
title: reviewLine(200),
|
|
378
|
+
place: reviewLine(200).optional(),
|
|
379
|
+
body: reviewBlock(10_000),
|
|
380
|
+
format: z.enum(["plain", "markdown"]),
|
|
381
|
+
truncated: z.boolean().optional(),
|
|
382
|
+
changes: z
|
|
383
|
+
.array(z.object({ change: z.enum(["added", "removed"]), text: reviewBlock(2000) }).strict())
|
|
384
|
+
.max(20)
|
|
385
|
+
.optional(),
|
|
386
|
+
})
|
|
387
|
+
.strict(),
|
|
388
|
+
z
|
|
389
|
+
.object({
|
|
390
|
+
kind: z.literal("file"),
|
|
391
|
+
name: reviewLine(255),
|
|
392
|
+
place: reviewLine(200).optional(),
|
|
393
|
+
path: reviewLine(1024).optional(),
|
|
394
|
+
size: z.number().int().nonnegative().optional(),
|
|
395
|
+
mediaType: reviewLine(120).optional(),
|
|
396
|
+
to: reviewLine(1024).optional(),
|
|
397
|
+
})
|
|
398
|
+
.strict(),
|
|
399
|
+
z
|
|
400
|
+
.object({
|
|
401
|
+
kind: z.literal("rule"),
|
|
402
|
+
when: CapabilitySentenceSchema,
|
|
403
|
+
does: reviewBlock(4000),
|
|
404
|
+
may: z.array(CapabilityConsequenceSchema).max(12),
|
|
405
|
+
seesChat: z.boolean(),
|
|
406
|
+
})
|
|
407
|
+
.strict(),
|
|
408
|
+
z
|
|
409
|
+
.object({
|
|
410
|
+
kind: z.literal("fields"),
|
|
411
|
+
rows: z
|
|
412
|
+
.array(
|
|
413
|
+
z
|
|
414
|
+
.object({
|
|
415
|
+
label: reviewLine(60),
|
|
416
|
+
value: reviewBlock(2000),
|
|
417
|
+
before: reviewBlock(2000).optional(),
|
|
418
|
+
format: z.enum(["date", "date-time"]).optional(),
|
|
419
|
+
})
|
|
420
|
+
.strict()
|
|
421
|
+
.superRefine((row, context) => {
|
|
422
|
+
const schema =
|
|
423
|
+
row.format === "date" ? CapabilityReviewDateSchema : row.format === "date-time" ? CapabilityReviewDateTimeSchema : null;
|
|
424
|
+
for (const key of ["value", "before"] as const)
|
|
425
|
+
if (row[key] !== undefined && schema?.safeParse(row[key]).success === false)
|
|
426
|
+
context.addIssue({ code: "custom", path: [key], message: "Invalid date or time" });
|
|
427
|
+
}),
|
|
428
|
+
)
|
|
429
|
+
.min(1)
|
|
430
|
+
.max(12),
|
|
431
|
+
})
|
|
432
|
+
.strict(),
|
|
433
|
+
]);
|
|
434
|
+
export type CapabilityPreview = z.infer<typeof CapabilityPreviewSchema>;
|
|
435
|
+
export const CapabilityActionCallReviewSchema = z
|
|
436
|
+
.object({
|
|
437
|
+
locale: z.string(),
|
|
438
|
+
sentence: z
|
|
439
|
+
.object({
|
|
440
|
+
action: reviewTemplate,
|
|
441
|
+
running: reviewTemplate,
|
|
442
|
+
done: reviewTemplate,
|
|
443
|
+
confirm: reviewTemplate,
|
|
444
|
+
decline: reviewTemplate,
|
|
445
|
+
rejected: reviewTemplate.optional(),
|
|
446
|
+
notRun: reviewTemplate.optional(),
|
|
447
|
+
short: reviewTemplate.refine((text) => text.length <= 60, "short exceeds 60 characters").optional(),
|
|
448
|
+
})
|
|
449
|
+
.strict(),
|
|
450
|
+
slots: reviewSlots.readonly(),
|
|
451
|
+
preview: CapabilityPreviewSchema.optional(),
|
|
452
|
+
consequences: z.array(CapabilityConsequenceSchema).max(6).optional(),
|
|
453
|
+
ask: z.enum(CAPABILITY_ASK_REASONS).optional(),
|
|
454
|
+
reach: z.enum(CAPABILITY_REACHES).optional(),
|
|
455
|
+
effects: z.number().int().min(1).max(1000).optional(),
|
|
456
|
+
check: z
|
|
457
|
+
.object({ query: CapabilityLocalIdSchema, input: z.record(z.string(), z.unknown()) })
|
|
458
|
+
.strict()
|
|
459
|
+
.optional(),
|
|
460
|
+
scope: z.string().min(1).max(200).optional(),
|
|
461
|
+
links: z.array(CapabilitySemanticLinkSchema).max(10).optional(),
|
|
462
|
+
})
|
|
463
|
+
.strict()
|
|
464
|
+
.superRefine((review, ctx) => {
|
|
465
|
+
for (const [form, text] of Object.entries(review.sentence)) {
|
|
466
|
+
if (text === undefined) continue;
|
|
467
|
+
const complete = form === "action" || form === "running" || form === "done";
|
|
468
|
+
for (const message of capabilitySentenceIssues(text, review.slots, complete, form === "action"))
|
|
469
|
+
ctx.addIssue({ code: "custom", path: ["sentence", form], message });
|
|
470
|
+
if ((form === "confirm" || form === "decline") && [...text.matchAll(/\{[a-z][A-Za-z0-9]{0,31}\}/g)].length > 1)
|
|
471
|
+
ctx.addIssue({ code: "custom", path: ["sentence", form], message: "Buttons name at most one slot" });
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
export type CapabilityActionCallReview = z.infer<typeof CapabilityActionCallReviewSchema>;
|
|
475
|
+
export type CapabilityActionReviewData = CapabilityActionCallReview | CapabilityActionReview;
|
|
476
|
+
export const CapabilityActionReviewDataSchema = z
|
|
477
|
+
.unknown()
|
|
478
|
+
.transform((value, ctx) => {
|
|
479
|
+
const schema =
|
|
480
|
+
value !== null && typeof value === "object" && Object.hasOwn(value, "sentence")
|
|
481
|
+
? CapabilityActionCallReviewSchema
|
|
482
|
+
: CapabilityActionReviewSchema;
|
|
483
|
+
const parsed = schema.safeParse(value);
|
|
484
|
+
if (parsed.success) return parsed.data;
|
|
485
|
+
for (const issue of parsed.error.issues) ctx.addIssue({ code: "custom", path: issue.path, message: issue.message });
|
|
486
|
+
return z.NEVER;
|
|
487
|
+
})
|
|
488
|
+
.pipe(z.union([CapabilityActionCallReviewSchema, CapabilityActionReviewSchema]));
|
|
489
|
+
export const CapabilityActionReceiptSchema = z
|
|
490
|
+
.object({ ...sentenceShape, preview: CapabilityPreviewSchema.optional() })
|
|
491
|
+
.strict()
|
|
492
|
+
.superRefine(sentenceRefinement);
|
|
493
|
+
export type CapabilityActionReceipt = z.infer<typeof CapabilityActionReceiptSchema>;
|
|
494
|
+
export const CapabilityActionCheckSchema = z
|
|
495
|
+
.object({ outcome: z.enum(["done", "not_done", "pending"]), receipt: CapabilityActionReceiptSchema.optional() })
|
|
496
|
+
.strict();
|
|
497
|
+
export type CapabilityActionCheck = z.infer<typeof CapabilityActionCheckSchema>;
|
|
498
|
+
|
|
161
499
|
export const CapabilityPageSchema = z.discriminatedUnion("hasMore", [
|
|
162
500
|
z
|
|
163
501
|
.object({
|
|
@@ -215,15 +553,19 @@ export type CapabilityResult<T> = {
|
|
|
215
553
|
stream?: CapabilityStream;
|
|
216
554
|
/** Provider-authored, user-facing summary of the successful result. Render as escaped plain text. */
|
|
217
555
|
summary?: string;
|
|
556
|
+
receipt?: CapabilityActionReceipt;
|
|
218
557
|
refs?: CloudResourceReference[];
|
|
219
558
|
page?: CapabilityPage;
|
|
220
559
|
links?: CapabilitySemanticLink[];
|
|
221
560
|
presentation?: CapabilityTablePresentation;
|
|
222
561
|
};
|
|
223
562
|
|
|
224
|
-
|
|
563
|
+
// Published JSON schemas (Core's result check, each MCP tool's outputSchema) describe a receipt as an opaque object,
|
|
564
|
+
// so they stay as small as before receipts existed; Core then checks it with the shared receipt rules. Zod readers
|
|
565
|
+
// (the producer, stream results, consumers) keep the full receipt shape.
|
|
566
|
+
const resultSchema = <T extends z.ZodType>(
|
|
225
567
|
data: T,
|
|
226
|
-
options
|
|
568
|
+
options: { consumer?: boolean; opaqueReceipt: boolean },
|
|
227
569
|
): z.ZodType<CapabilityResult<z.output<T>>> =>
|
|
228
570
|
z
|
|
229
571
|
.object({
|
|
@@ -231,19 +573,24 @@ export const capabilityResultSchema = <T extends z.ZodType>(
|
|
|
231
573
|
stream: CapabilityStreamSchema.optional(),
|
|
232
574
|
summary: z.string().trim().min(1).max(500).optional(),
|
|
233
575
|
refs: z
|
|
234
|
-
.array(options
|
|
576
|
+
.array(options.consumer ? LinkedCloudResourceReferenceSchema : CloudResourceReferenceSchema)
|
|
235
577
|
.max(100)
|
|
236
578
|
.optional(),
|
|
237
579
|
page: CapabilityPageSchema.optional(),
|
|
238
580
|
links: z.array(CapabilitySemanticLinkSchema).max(20).optional(),
|
|
239
|
-
|
|
581
|
+
receipt: options.opaqueReceipt
|
|
582
|
+
? z.record(z.string(), z.unknown()).optional()
|
|
583
|
+
: options.consumer
|
|
584
|
+
? CapabilityActionReceiptSchema.optional().catch(undefined)
|
|
585
|
+
: CapabilityActionReceiptSchema.optional(),
|
|
586
|
+
presentation: options.consumer
|
|
240
587
|
? CapabilityTablePresentationSchema.optional().catch(undefined)
|
|
241
588
|
: CapabilityTablePresentationSchema.optional(),
|
|
242
589
|
})
|
|
243
590
|
.strict()
|
|
244
591
|
.superRefine((result, context) => {
|
|
245
592
|
if (
|
|
246
|
-
!options
|
|
593
|
+
!options.consumer &&
|
|
247
594
|
result.presentation &&
|
|
248
595
|
!Array.isArray(capabilityDataAtPath(capabilityDataAtPath(result, ["data"]), result.presentation.rowsPath))
|
|
249
596
|
) {
|
|
@@ -255,14 +602,18 @@ export const capabilityResultSchema = <T extends z.ZodType>(
|
|
|
255
602
|
}
|
|
256
603
|
}) as unknown as z.ZodType<CapabilityResult<z.output<T>>>;
|
|
257
604
|
|
|
605
|
+
export const capabilityResultSchema = <T extends z.ZodType>(
|
|
606
|
+
data: T,
|
|
607
|
+
options?: { consumer?: boolean },
|
|
608
|
+
): z.ZodType<CapabilityResult<z.output<T>>> => resultSchema(data, { consumer: options?.consumer, opaqueReceipt: false });
|
|
609
|
+
|
|
258
610
|
export const capabilityResultJsonSchema = (
|
|
259
611
|
dataSchema: Record<string, unknown>,
|
|
260
612
|
options?: { consumer?: boolean },
|
|
261
613
|
): Record<string, unknown> =>
|
|
262
|
-
z.toJSONSchema(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
>;
|
|
614
|
+
z.toJSONSchema(resultSchema(z.fromJSONSchema(structuredClone(dataSchema)), { consumer: options?.consumer, opaqueReceipt: true }), {
|
|
615
|
+
io: "output",
|
|
616
|
+
}) as Record<string, unknown>;
|
|
266
617
|
|
|
267
618
|
export const CapabilityErrorSchema = z
|
|
268
619
|
.object({
|
|
@@ -281,7 +632,7 @@ export type CapabilityError = {
|
|
|
281
632
|
details?: Record<string, unknown>;
|
|
282
633
|
};
|
|
283
634
|
export type CapabilityInvocationResult<T> = { ok: true; data: CapabilityResult<T> } | { ok: false; error: CapabilityError };
|
|
284
|
-
export type CapabilityActionReviewResult = { ok: true; data:
|
|
635
|
+
export type CapabilityActionReviewResult = { ok: true; data: CapabilityActionReviewData } | { ok: false; error: CapabilityError };
|
|
285
636
|
|
|
286
637
|
export const CloudResourceViewSchema = z
|
|
287
638
|
.object({
|
|
@@ -370,6 +721,8 @@ export type CapabilityUniversalSearchDefinition = {
|
|
|
370
721
|
export type CapabilitySchemaPresentation = Readonly<Record<string, string>>;
|
|
371
722
|
|
|
372
723
|
/**
|
|
724
|
+
* @deprecated removed with the next major; return per-call CapabilityActionCallReview sentence forms.
|
|
725
|
+
*
|
|
373
726
|
* What one Action does, in words people read in approvals, receipts, and step rows. Each sentence is a
|
|
374
727
|
* template: `{input.to}` inserts a field of the validated call input by its dotted schema path, and
|
|
375
728
|
* `done` may also read the Action's result data with `{data.id}`. Cloud inserts values as escaped,
|
|
@@ -398,7 +751,7 @@ export type CapabilityOperationPresentationTranslation = {
|
|
|
398
751
|
data?: CapabilitySchemaPresentation;
|
|
399
752
|
/** Search-tag presentation keyed by the stable tag token. */
|
|
400
753
|
searchTags?: Readonly<Record<string, { title?: string; description?: string }>>;
|
|
401
|
-
/**
|
|
754
|
+
/** @deprecated removed with the next major; return per-call review forms. */
|
|
402
755
|
sentences?: CapabilityActionSentences;
|
|
403
756
|
};
|
|
404
757
|
|
|
@@ -406,13 +759,21 @@ export type CapabilityPresentationTranslation = {
|
|
|
406
759
|
types?: Readonly<Record<string, { title?: string; description?: string }>>;
|
|
407
760
|
queries?: Readonly<Record<string, CapabilityOperationPresentationTranslation>>;
|
|
408
761
|
actions?: Readonly<Record<string, CapabilityOperationPresentationTranslation>>;
|
|
409
|
-
commands?: Readonly<
|
|
762
|
+
commands?: Readonly<
|
|
763
|
+
Record<
|
|
764
|
+
string,
|
|
765
|
+
Pick<CapabilityOperationPresentationTranslation, "title" | "description" | "input"> & {
|
|
766
|
+
/** Translated search words, with the same bounds as the base Command keywords. */
|
|
767
|
+
keywords?: readonly string[];
|
|
768
|
+
}
|
|
769
|
+
>
|
|
770
|
+
>;
|
|
410
771
|
};
|
|
411
772
|
|
|
412
773
|
export type CapabilityPresentationCatalog = {
|
|
413
774
|
/** Locale of the complete Type, Query, Action, search-tag, and schema presentation. */
|
|
414
775
|
baseLocale: string;
|
|
415
|
-
/**
|
|
776
|
+
/** @deprecated removed with the next major; return per-call review forms. */
|
|
416
777
|
sentences?: Readonly<Record<string, CapabilityActionSentences>>;
|
|
417
778
|
/** Partial presentation overlays with exact -> ancestor -> base fallback. */
|
|
418
779
|
translations: Readonly<Record<string, CapabilityPresentationTranslation>>;
|
|
@@ -444,7 +805,9 @@ export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>,
|
|
|
444
805
|
openWorld: boolean;
|
|
445
806
|
stream?: CapabilityStreamDefinition;
|
|
446
807
|
idempotency: CapabilityIdempotencyPolicy;
|
|
808
|
+
/** @deprecated removed with the next major; declare policy. */
|
|
447
809
|
approval?: CapabilityActionApprovalPolicy;
|
|
810
|
+
policy?: CapabilityActionPolicy;
|
|
448
811
|
review?: (
|
|
449
812
|
input: z.output<Input>,
|
|
450
813
|
context: CapabilityExecutionContext,
|
|
@@ -549,7 +912,7 @@ export const CapabilityActionManifestSchema = CapabilityOperationManifestBaseSch
|
|
|
549
912
|
export const CapabilityAppIdSchema = z
|
|
550
913
|
.string()
|
|
551
914
|
.min(1)
|
|
552
|
-
.max(
|
|
915
|
+
.max(CAPABILITY_APP_ID_MAX_LENGTH)
|
|
553
916
|
.regex(/^[a-z][a-z0-9-]*$/);
|
|
554
917
|
|
|
555
918
|
const MAX_MANIFEST_ENTRIES = 200;
|
|
@@ -571,8 +934,9 @@ const readEntries = <T extends z.ZodType>(values: unknown, entry: T): z.output<T
|
|
|
571
934
|
/**
|
|
572
935
|
* Reads what this release understands from a manifest that a newer release may have produced.
|
|
573
936
|
*
|
|
574
|
-
* - Unknown top-level fields are ignored.
|
|
575
|
-
*
|
|
937
|
+
* - Unknown top-level fields are ignored. Additions there must retain conservative behavior through
|
|
938
|
+
* existing fields for older readers; Action policies carry the corresponding derived approval.
|
|
939
|
+
* Other restrictions belong inside their entry.
|
|
576
940
|
* - An entry with a field or value from a newer release is left out rather than stripped: its unknown
|
|
577
941
|
* part may change how the entry runs or who may use it, so guessing could widen access.
|
|
578
942
|
* - Entries that depend on an entry that is not there follow it: a Query scoped to a missing type is
|
|
@@ -580,6 +944,9 @@ const readEntries = <T extends z.ZodType>(values: unknown, entry: T): z.output<T
|
|
|
580
944
|
* - A file provider with a field from a newer release is left out. Whether its operations are still
|
|
581
945
|
* there and match the contract is `fileProviderIssues`' job, which Core and consumers run.
|
|
582
946
|
*
|
|
947
|
+
* - An unreadable policy or one inconsistent with derived approval, review, or effect flags leaves
|
|
948
|
+
* out its Action. Policies for unknown Actions are dropped.
|
|
949
|
+
*
|
|
583
950
|
* Every other entry stays available.
|
|
584
951
|
*/
|
|
585
952
|
const readableManifest = (value: unknown): unknown => {
|
|
@@ -593,7 +960,27 @@ const readableManifest = (value: unknown): unknown => {
|
|
|
593
960
|
const typeIds = new Set(types.map((type) => type.localId));
|
|
594
961
|
const readableQueries = queries.filter((query) => query.universalSearch?.scopeTypes?.every((type) => typeIds.has(type)) ?? true);
|
|
595
962
|
const queryIds = new Set(readableQueries.map((query) => query.localId));
|
|
596
|
-
const
|
|
963
|
+
const policies: Record<string, CapabilityActionPolicy> = {};
|
|
964
|
+
const sentPolicies = sent.policies;
|
|
965
|
+
// Not a plain policy map: leave the value to the manifest schema, which rejects it.
|
|
966
|
+
if (
|
|
967
|
+
sentPolicies !== undefined &&
|
|
968
|
+
(sentPolicies === null ||
|
|
969
|
+
typeof sentPolicies !== "object" ||
|
|
970
|
+
(Object.getPrototypeOf(sentPolicies) !== Object.prototype && Object.getPrototypeOf(sentPolicies) !== null))
|
|
971
|
+
)
|
|
972
|
+
return value;
|
|
973
|
+
const readableActions = actions.filter((action) => {
|
|
974
|
+
if (!sentPolicies || typeof sentPolicies !== "object" || !Object.hasOwn(sentPolicies, action.localId)) return true;
|
|
975
|
+
const parsed = CapabilityActionPolicySchema.safeParse(Object.getOwnPropertyDescriptor(sentPolicies, action.localId)?.value);
|
|
976
|
+
if (!parsed.success) return false;
|
|
977
|
+
const policy = parsed.data;
|
|
978
|
+
const approval = "silent" in policy ? "rememberable" : undefined;
|
|
979
|
+
if (action.approval !== approval || !action.review || ("silent" in policy && (action.destructive || action.openWorld))) return false;
|
|
980
|
+
policies[action.localId] = policy;
|
|
981
|
+
return true;
|
|
982
|
+
});
|
|
983
|
+
const { fileProvider: sentProvider, policies: _policies, ...rest } = sent;
|
|
597
984
|
const provider = CapabilityFileProviderManifestSchema.safeParse(sentProvider);
|
|
598
985
|
return {
|
|
599
986
|
...rest,
|
|
@@ -604,7 +991,8 @@ const readableManifest = (value: unknown): unknown => {
|
|
|
604
991
|
return withoutReader;
|
|
605
992
|
}),
|
|
606
993
|
queries: readableQueries,
|
|
607
|
-
actions,
|
|
994
|
+
actions: readableActions,
|
|
995
|
+
...(sentPolicies !== undefined ? { policies } : {}),
|
|
608
996
|
commands,
|
|
609
997
|
};
|
|
610
998
|
};
|
|
@@ -625,6 +1013,7 @@ export const CapabilityManifestSchema = z.preprocess(
|
|
|
625
1013
|
commands: z.array(CapabilityCommandManifestSchema).max(MAX_MANIFEST_ENTRIES),
|
|
626
1014
|
// Optional without a default: a manifest without a provider keeps the shape and hash of earlier releases.
|
|
627
1015
|
fileProvider: CapabilityFileProviderManifestSchema.optional(),
|
|
1016
|
+
policies: z.record(CapabilityLocalIdSchema, CapabilityActionPolicySchema).optional(),
|
|
628
1017
|
}),
|
|
629
1018
|
);
|
|
630
1019
|
|
|
@@ -634,6 +1023,9 @@ export type CapabilityActionManifest = z.infer<typeof CapabilityActionManifestSc
|
|
|
634
1023
|
export type CapabilitySearchTagManifest = z.infer<typeof CapabilitySearchTagManifestSchema>;
|
|
635
1024
|
export type CapabilityManifest = z.infer<typeof CapabilityManifestSchema>;
|
|
636
1025
|
|
|
1026
|
+
export const capabilityActionPolicy = (manifest: CapabilityManifest, localId: string): CapabilityActionPolicy | undefined =>
|
|
1027
|
+
manifest.policies && Object.hasOwn(manifest.policies, localId) ? manifest.policies[localId] : undefined;
|
|
1028
|
+
|
|
637
1029
|
export const cloudResourceRefAppId = (ref: CloudResourceRef): string => ref.type.slice(0, ref.type.indexOf("."));
|
|
638
1030
|
|
|
639
1031
|
/** Resolves a resource reference against one current, validated app manifest. */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type GeoIpKind = "city" | "asn";
|
|
2
|
+
export const GEOIP_MAX_DATABASE_BYTES = 192 * 1024 * 1024;
|
|
3
|
+
export const GEOIP_MAX_REQUEST_BYTES = 128 * 1024 * 1024;
|
|
4
|
+
export const DBIP_ATTRIBUTION = {
|
|
5
|
+
text: "IP Geolocation by DB-IP",
|
|
6
|
+
url: "https://db-ip.com",
|
|
7
|
+
license: "CC BY 4.0",
|
|
8
|
+
licenseUrl: "https://creativecommons.org/licenses/by/4.0/",
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export type GeoIpAdminDatabase = {
|
|
12
|
+
kind: GeoIpKind;
|
|
13
|
+
source: "uploaded" | "bundled" | null;
|
|
14
|
+
/** A bundled snapshot exists for this type, so a reset returns to it. */
|
|
15
|
+
bundled: boolean;
|
|
16
|
+
databaseType: string | null;
|
|
17
|
+
buildDate: string | null;
|
|
18
|
+
stale: boolean;
|
|
19
|
+
dbIp: boolean;
|
|
20
|
+
upload: {
|
|
21
|
+
sha256: string;
|
|
22
|
+
size: number;
|
|
23
|
+
uploadedAt: string;
|
|
24
|
+
uploadedBy: { id: string; name: string } | null;
|
|
25
|
+
} | null;
|
|
26
|
+
};
|
|
27
|
+
export type GeoIpAdminStatus = {
|
|
28
|
+
databases: [GeoIpAdminDatabase, GeoIpAdminDatabase];
|
|
29
|
+
attribution: typeof DBIP_ATTRIBUTION | null;
|
|
30
|
+
limits: { maxDatabaseBytes: number; maxRequestBytes: number };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type GeoIpUploadResult = GeoIpAdminStatus & { kind: GeoIpKind };
|
|
34
|
+
export type GeoIpResetResult = GeoIpAdminStatus & { changed: boolean };
|
|
35
|
+
|
|
36
|
+
export type GeoIpErrorCode =
|
|
37
|
+
| "geoip_request_too_large"
|
|
38
|
+
| "geoip_too_large"
|
|
39
|
+
| "geoip_empty"
|
|
40
|
+
| "geoip_invalid"
|
|
41
|
+
| "geoip_unsupported_type"
|
|
42
|
+
| "geoip_upload_busy";
|
package/src/contracts/index.ts
CHANGED
|
@@ -7,8 +7,10 @@ export * from "./capability-compatibility";
|
|
|
7
7
|
export * from "./commands";
|
|
8
8
|
export * from "./contact-directory";
|
|
9
9
|
export * from "./file-provider";
|
|
10
|
+
export * from "./geoip";
|
|
10
11
|
export * from "./notification-types";
|
|
11
12
|
export * from "./outgoing-mail";
|
|
13
|
+
export * from "./panel-context";
|
|
12
14
|
export * from "./posix";
|
|
13
15
|
export * from "./profile";
|
|
14
16
|
export * from "./pwa";
|
|
@@ -17,6 +19,7 @@ export { RailAccessSchema, type RailAdminEntry, RailAdminInputSchema, RailAdminS
|
|
|
17
19
|
export type { RailShortcut } from "./rail-preferences";
|
|
18
20
|
export * from "./registry";
|
|
19
21
|
export * from "./resource-clipboard";
|
|
22
|
+
export * from "./seen-hints";
|
|
20
23
|
export * from "./shared";
|
|
21
24
|
export * from "./user-notifications";
|
|
22
25
|
export * from "./widgets";
|