@fungi.computer/oyster 0.2.0 → 0.3.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 +376 -72
- package/dist/agents.d.ts +3 -2
- package/dist/agents.js +4 -2
- package/dist/app-builds.d.ts +81 -8
- package/dist/app-builds.js +210 -60
- package/dist/app-storage.d.ts +3 -3
- package/dist/approval-capability.d.ts +5 -0
- package/dist/approval-capability.js +46 -0
- package/dist/approval-home.d.ts +51 -0
- package/dist/approval-home.js +226 -0
- package/dist/apps/catalog.d.ts +335 -0
- package/dist/apps/catalog.js +46 -0
- package/dist/apps/gate.d.ts +20 -6
- package/dist/apps/gate.js +42 -16
- package/dist/apps/index.d.ts +3 -1
- package/dist/apps/index.js +3 -1
- package/dist/apps/installation.d.ts +132 -51
- package/dist/apps/installation.js +176 -70
- package/dist/apps/permissions.d.ts +247 -0
- package/dist/apps/permissions.js +255 -0
- package/dist/boot-capability-route.d.ts +15 -0
- package/dist/boot-capability-route.js +196 -0
- package/dist/boot-capability.d.ts +103 -0
- package/dist/boot-capability.js +141 -0
- package/dist/boot-construction.d.ts +12 -0
- package/dist/boot-construction.js +175 -0
- package/dist/boot-gate.d.ts +267 -0
- package/dist/boot-gate.js +236 -0
- package/dist/boot-host-script.d.ts +2 -0
- package/dist/boot-host-script.js +1 -0
- package/dist/boot-mount.d.ts +21 -0
- package/dist/boot-mount.js +65 -0
- package/dist/browser/boot.d.ts +73 -0
- package/dist/browser/boot.js +502 -0
- package/dist/browser/browser.d.ts +104 -0
- package/dist/browser/browser.js +374 -0
- package/dist/browser/capability-source.d.ts +76 -0
- package/dist/browser/capability-source.js +338 -0
- package/dist/browser/cdp-client.d.ts +56 -0
- package/dist/browser/cdp-client.js +184 -0
- package/dist/browser/errors.d.ts +79 -0
- package/dist/browser/errors.js +32 -0
- package/dist/browser/index.d.ts +16 -0
- package/dist/browser/index.js +14 -0
- package/dist/browser/lease-registry.d.ts +61 -0
- package/dist/browser/lease-registry.js +101 -0
- package/dist/browser/operations.d.ts +225 -0
- package/dist/browser/operations.js +137 -0
- package/dist/browser/page.d.ts +25 -0
- package/dist/browser/page.js +172 -0
- package/dist/browser/quick-reads.d.ts +29 -0
- package/dist/browser/quick-reads.js +160 -0
- package/dist/browser/sessions.d.ts +52 -0
- package/dist/browser/sessions.js +118 -0
- package/dist/browser/url-policy.d.ts +18 -0
- package/dist/browser/url-policy.js +58 -0
- package/dist/build/app-imports.d.ts +12 -0
- package/dist/build/app-imports.js +105 -0
- package/dist/build/build-policy.d.ts +5 -3
- package/dist/build/build-policy.js +5 -3
- package/dist/build/candidate-builder.d.ts +1 -1
- package/dist/build/candidate-cli.mjs +8375 -334
- package/dist/build/local-build.d.ts +2 -0
- package/dist/build/local-build.js +28 -6
- package/dist/build/snapshot-package-store.d.ts +1 -1
- package/dist/build/snapshot-package-store.js +7 -2
- package/dist/build/workspace-build.d.ts +92 -5
- package/dist/build/workspace-build.js +93 -19
- package/dist/build.d.ts +1 -1
- package/dist/build.js +1 -1
- package/dist/catalog-frame.js +1 -1
- package/dist/cloudflare.d.ts +13 -3
- package/dist/cloudflare.js +102 -4
- package/dist/frame-binding-wire-script.js +1 -1
- package/dist/frame-binding-wire.js +4 -2
- package/dist/git-auth.d.ts +0 -2
- package/dist/git-auth.js +0 -2
- package/dist/git.d.ts +0 -1
- package/dist/git.js +0 -2
- package/dist/host.d.ts +39 -13
- package/dist/host.js +268 -142
- package/dist/index.d.ts +25 -15
- package/dist/index.js +39 -16
- package/dist/install-release-cli.d.ts +2 -0
- package/dist/install-release-cli.js +46 -0
- package/dist/installation-client.d.ts +43 -0
- package/dist/installation-client.js +178 -0
- package/dist/installation-execution.d.ts +11 -0
- package/dist/installation-execution.js +184 -0
- package/dist/installation-operations.d.ts +1437 -0
- package/dist/installation-operations.js +664 -0
- package/dist/installation-store-generation.d.ts +3 -0
- package/dist/installation-store-generation.js +16 -0
- package/dist/instance-id.d.ts +10 -0
- package/dist/instance-id.js +10 -0
- package/dist/instance-refusal.d.ts +11 -0
- package/dist/instance-refusal.js +21 -0
- package/dist/internal/delivery.js +4 -2
- package/dist/internal/host-gate.js +7 -1
- package/dist/internal/registry-installations.js +4 -4
- package/dist/keys.d.ts +5 -1
- package/dist/keys.js +10 -2
- package/dist/machine-link/authority.d.ts +89 -0
- package/dist/machine-link/authority.js +37 -0
- package/dist/machine-link/client.d.ts +66 -0
- package/dist/machine-link/client.js +94 -0
- package/dist/machine-link/delivery.d.ts +18 -0
- package/dist/machine-link/delivery.js +55 -0
- package/dist/machine-link/enrollment.d.ts +111 -0
- package/dist/machine-link/enrollment.js +286 -0
- package/dist/machine-link/fences.d.ts +37 -0
- package/dist/machine-link/fences.js +166 -0
- package/dist/machine-link/home.d.ts +20 -0
- package/dist/machine-link/home.js +24 -0
- package/dist/machine-link/host.d.ts +43 -0
- package/dist/machine-link/host.js +189 -0
- package/dist/machine-link/index.d.ts +15 -0
- package/dist/machine-link/index.js +15 -0
- package/dist/machine-link/link.d.ts +48 -0
- package/dist/machine-link/link.js +223 -0
- package/dist/machine-link/presence.d.ts +10 -0
- package/dist/machine-link/presence.js +25 -0
- package/dist/machine-link/workers.d.ts +6 -0
- package/dist/machine-link/workers.js +6 -0
- package/dist/mcp-owner.d.ts +2 -2
- package/dist/mcp-owner.js +41 -33
- package/dist/mcp.d.ts +15 -3
- package/dist/mcp.js +146 -25
- package/dist/pack.d.ts +14 -3
- package/dist/pack.js +44 -19
- package/dist/page/app-access.d.ts +7 -0
- package/dist/page/app-access.js +75 -0
- package/dist/page/boot-host.js +57 -0
- package/dist/page/capabilities.d.ts +3 -3
- package/dist/page/capabilities.js +16 -12
- package/dist/page/computer-handles.d.ts +3 -3
- package/dist/page/computer-target.d.ts +3 -0
- package/dist/page/computer-target.js +9 -0
- package/dist/page/mount.d.ts +23 -3
- package/dist/page/mount.js +152 -16
- package/dist/page-assets.d.ts +22 -0
- package/dist/page-assets.js +28 -0
- package/dist/page-script.d.ts +3 -0
- package/dist/page-script.js +5 -4
- package/dist/release.d.ts +13 -6
- package/dist/release.js +10 -7
- package/dist/root-data.d.ts +16 -6
- package/dist/root-data.js +2 -2
- package/dist/source/index.d.ts +1 -1
- package/dist/source/team-source.d.ts +20 -8
- package/dist/source/team-source.js +39 -10
- package/dist/source/template-seed.d.ts +2 -2
- package/dist/standalone/agent-mail.d.ts +24 -0
- package/dist/standalone/agent-mail.js +62 -0
- package/dist/standalone/agent-store.d.ts +9 -0
- package/dist/standalone/agent-store.js +30 -0
- package/dist/standalone/agents.d.ts +68 -9
- package/dist/standalone/agents.js +428 -56
- package/dist/standalone/app-builds-binding.d.ts +20 -2
- package/dist/standalone/app-builds-binding.js +147 -23
- package/dist/standalone/app-set.d.ts +5 -2
- package/dist/standalone/app-set.js +174 -143
- package/dist/standalone/browser.d.ts +11 -0
- package/dist/standalone/browser.js +72 -0
- package/dist/standalone/builds.d.ts +13 -4
- package/dist/standalone/builds.js +28 -44
- package/dist/standalone/computer-egress.d.ts +2 -0
- package/dist/standalone/computer-egress.js +13 -4
- package/dist/standalone/computer-fleet.d.ts +43 -0
- package/dist/standalone/computer-fleet.js +200 -0
- package/dist/standalone/computer.d.ts +44 -9
- package/dist/standalone/computer.js +129 -22
- package/dist/standalone/install-apps-cli.js +43 -6
- package/dist/standalone/instance.d.ts +2 -2
- package/dist/standalone/instance.js +8 -11
- package/dist/standalone/machine-link.d.ts +354 -0
- package/dist/standalone/machine-link.js +368 -0
- package/dist/standalone/media.d.ts +2 -2
- package/dist/standalone/media.js +19 -16
- package/dist/standalone/preview.d.ts +2 -2
- package/dist/standalone/preview.js +37 -10
- package/dist/standalone/registry.d.ts +149 -9
- package/dist/standalone/registry.js +299 -8
- package/dist/standalone/worker.d.ts +19 -5
- package/dist/standalone/worker.js +90 -54
- package/dist/standalone/workflow-binding.d.ts +18 -22
- package/dist/standalone/workflow-binding.js +18 -18
- package/dist/standalone/workflow-control.d.ts +4 -0
- package/dist/standalone/workflow-control.js +40 -0
- package/dist/standalone/workflow-events.d.ts +2 -2
- package/dist/standalone/workflow-events.js +9 -10
- package/dist/standalone/workflow-git-capture.js +4 -3
- package/dist/standalone/workflow-host.d.ts +162 -161
- package/dist/standalone/workflow-host.js +101 -21
- package/dist/standalone/workflow-node-capture.js +11 -4
- package/dist/standalone/workflow-schedules.d.ts +5 -2
- package/dist/standalone/workflow-schedules.js +9 -10
- package/dist/standalone/workflow-trigger-host.d.ts +65 -5
- package/dist/standalone/workflow-trigger-host.js +2 -2
- package/dist/standalone/workflow-webhooks.d.ts +22 -0
- package/dist/standalone/workflow-webhooks.js +39 -0
- package/dist/standalone/workflows.d.ts +140 -43
- package/dist/standalone/workflows.js +198 -39
- package/dist/storage-frame.d.ts +6 -6
- package/dist/testing/capabilities.js +14 -3
- package/dist/testing/installation.js +26 -2
- package/dist/testing/worker.js +1 -1
- package/dist/testing/workers-runtime.d.ts +8 -2
- package/dist/testing/workers-runtime.js +20 -2
- package/dist/webhook-abuse.d.ts +25 -0
- package/dist/webhook-abuse.js +54 -0
- package/dist/webhook-custody.d.ts +144 -0
- package/dist/webhook-custody.js +222 -0
- package/dist/webhook-ingress.d.ts +36 -0
- package/dist/webhook-ingress.js +146 -0
- package/dist/webhooks.d.ts +111 -0
- package/dist/webhooks.js +189 -0
- package/dist/workers-git.d.ts +12 -17
- package/dist/workers-git.js +60 -52
- package/dist/workers.d.ts +224 -13
- package/dist/workers.js +351 -51
- package/dist/workflow-agent-authority.d.ts +8 -0
- package/dist/workflow-agent-authority.js +42 -0
- package/dist/workflows.d.ts +66 -0
- package/dist/workflows.js +97 -0
- package/docs/api/README.md +63 -37
- package/docs/api/agents.md +17 -0
- package/docs/api/app-storage.md +1 -1
- package/docs/api/apps.md +1394 -543
- package/docs/api/browser/boot.md +132 -0
- package/docs/api/browser.md +1440 -0
- package/docs/api/build-contract.md +38 -25
- package/docs/api/build.md +263 -84
- package/docs/api/cloudflare.md +93 -7
- package/docs/api/git.md +3 -13
- package/docs/api/host.md +944 -118
- package/docs/api/index.md +320 -18
- package/docs/api/keys.md +24 -1
- package/docs/api/mcp.md +59 -12
- package/docs/api/modules.md +33 -40
- package/docs/api/pack.md +57 -8
- package/docs/api/page/mount.md +92 -4
- package/docs/api/workers-git.md +103 -24
- package/docs/api/workers.md +1581 -244
- package/docs/site/agent-quickstart.mdx +28 -14
- package/examples/standalone/worker.ts +3 -1
- package/examples/standalone/wrangler.jsonc +2 -0
- package/package.json +73 -71
- package/dist/installation-consent.d.ts +0 -81
- package/dist/installation-consent.js +0 -84
- package/dist/shell/app-directory.d.ts +0 -542
- package/dist/shell/app-directory.js +0 -196
- package/dist/shell/browser-actions.d.ts +0 -7
- package/dist/shell/browser-actions.js +0 -56
- package/dist/shell/command-host.d.ts +0 -112
- package/dist/shell/command-host.js +0 -502
- package/dist/shell/commands.d.ts +0 -25
- package/dist/shell/commands.js +0 -78
- package/dist/shell/index.d.ts +0 -8
- package/dist/shell/index.js +0 -8
- package/dist/shell/keys.d.ts +0 -41
- package/dist/shell/keys.js +0 -134
- package/dist/shell/shell-module.d.ts +0 -55
- package/dist/shell/shell-module.js +0 -86
- package/dist/shell/window-manager.d.ts +0 -128
- package/dist/shell/window-manager.js +0 -730
- package/dist/shell/workbench-contract.d.ts +0 -68
- package/dist/shell/workbench-directory.d.ts +0 -332
- package/dist/shell/workbench-directory.js +0 -35
- package/dist/shell/workbench-host-types.d.ts +0 -96
- package/dist/shell/workbench-host-types.js +0 -1
- package/dist/shell/workbench-host.d.ts +0 -34
- package/dist/shell/workbench-host.js +0 -352
- package/dist/shell/workbench-model.d.ts +0 -194
- package/dist/shell/workbench-model.js +0 -53
- package/dist/shell/workbench.d.ts +0 -4
- package/dist/shell/workbench.js +0 -2
- package/docs/api/shell/app-directory.md +0 -599
- package/docs/api/shell/command-host.md +0 -224
- package/docs/api/shell/commands.md +0 -197
- package/docs/api/shell/keys.md +0 -183
- package/docs/api/shell/shell-module.md +0 -204
- package/docs/api/shell/window-manager.md +0 -267
- package/docs/api/shell/workbench-directory.md +0 -119
- package/docs/api/shell/workbench.md +0 -205
- package/docs/api/shell.md +0 -1915
- /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
|
@@ -4,7 +4,8 @@ import * as Result from "effect/Result";
|
|
|
4
4
|
import { appCapabilityIdSchema, appApiMethodNameSchema, } from "@fungi.computer/puffball/app";
|
|
5
5
|
import { hostActorSchema } from "@fungi.computer/puffball/app-method-runtime";
|
|
6
6
|
import { appIdSchema, releaseSchema, sha256DigestSchema, } from "@fungi.computer/puffball/effect";
|
|
7
|
-
import { instanceIdSchema } from "../
|
|
7
|
+
import { instanceIdSchema } from "../instance-id.js";
|
|
8
|
+
import { permissionCatalog } from "./catalog.js";
|
|
8
9
|
/** Reuse the owning Effect codec at a JSON/storage boundary. */
|
|
9
10
|
export function ownerCodec(schema) {
|
|
10
11
|
const decode = Schema.decodeUnknownResult(schema, {
|
|
@@ -22,7 +23,7 @@ export function ownerCodec(schema) {
|
|
|
22
23
|
/** Installation names cannot contain the tenant separator. */
|
|
23
24
|
export const installationIdSchema = z.lazy(() => z.string().regex(/^[a-z](?:[a-z0-9]|-(?!-)){0,62}$/u));
|
|
24
25
|
/** A resource identity minted and resolved by the host, never by this module. */
|
|
25
|
-
const resourceRefSchema = z.lazy(() => z
|
|
26
|
+
export const resourceRefSchema = z.lazy(() => z
|
|
26
27
|
.strictObject({
|
|
27
28
|
kind: z.string().min(1),
|
|
28
29
|
id: z.string().min(1),
|
|
@@ -38,10 +39,10 @@ const operationsSchema = z.lazy(() => z
|
|
|
38
39
|
* no new consent; a new capability does. Release selection intersects stored
|
|
39
40
|
* operations instead of adding approvals. Each Worker call is still restricted
|
|
40
41
|
* to that method's declared requires, never the App's complete capability set.
|
|
41
|
-
* Only an approved install or
|
|
42
|
+
* Only an approved install or change-grants command mints capabilityApproved.
|
|
42
43
|
* Empty operation rows retain that consent; removing the capability revokes it.
|
|
43
44
|
* route:app.methods rows record approval detail, not a method allowlist: narrowing
|
|
44
|
-
* them in
|
|
45
|
+
* them in change-grants does not restrict methods using an approved capability.
|
|
45
46
|
* Exact operation rows are enforced for capability routes and backend bindings.
|
|
46
47
|
*/
|
|
47
48
|
export const approvedGrantSchema = z
|
|
@@ -60,18 +61,23 @@ const approvedGrantsSchema = z.lazy(() => z
|
|
|
60
61
|
.array(approvedGrantSchema)
|
|
61
62
|
.refine((grants) => new Set(grants.map((grant) => grant.capability)).size === grants.length, "Capabilities must be unique")
|
|
62
63
|
.readonly());
|
|
63
|
-
/**
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.array(approvedGrantSchema
|
|
64
|
+
/** A bounded owner edit. Unnamed approvals are not part of the command. */
|
|
65
|
+
export const grantChangeSchema = z
|
|
66
|
+
.strictObject({
|
|
67
|
+
capability: ownerCodec(appCapabilityIdSchema),
|
|
68
|
+
grant: approvedGrantSchema
|
|
69
69
|
.unwrap()
|
|
70
|
-
.omit({ capabilityApproved: true })
|
|
71
|
-
.readonly()
|
|
72
|
-
.
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
.omit({ capabilityApproved: true, capability: true })
|
|
71
|
+
.readonly()
|
|
72
|
+
.nullable(),
|
|
73
|
+
})
|
|
74
|
+
.readonly();
|
|
75
|
+
const grantChangesSchema = z
|
|
76
|
+
.array(grantChangeSchema)
|
|
77
|
+
.min(1)
|
|
78
|
+
.refine((changes) => new Set(changes.map((change) => change.capability)).size ===
|
|
79
|
+
changes.length, "Capabilities must be unique")
|
|
80
|
+
.readonly();
|
|
75
81
|
const versionSchema = z.lazy(() => z.number().int().positive());
|
|
76
82
|
/** An owner's approval of a fixed operation snapshot. */
|
|
77
83
|
const approvalSchema = z.lazy(() => z
|
|
@@ -81,6 +87,109 @@ const approvalSchema = z.lazy(() => z
|
|
|
81
87
|
authorityVersion: versionSchema,
|
|
82
88
|
})
|
|
83
89
|
.readonly());
|
|
90
|
+
/** The complete grant state. Hosts own storage and compare-and-set commits. */
|
|
91
|
+
export const appAuthoritySchema = z.strictObject({
|
|
92
|
+
authorityVersion: versionSchema,
|
|
93
|
+
declaredOperationsDigest: ownerCodec(sha256DigestSchema),
|
|
94
|
+
approvedGrants: approvedGrantsSchema,
|
|
95
|
+
approval: approvalSchema.nullable(),
|
|
96
|
+
});
|
|
97
|
+
export const grantCommandSchema = z.discriminatedUnion("kind", [
|
|
98
|
+
z.strictObject({ kind: z.literal("install") }),
|
|
99
|
+
z.strictObject({
|
|
100
|
+
kind: z.literal("change-grants"),
|
|
101
|
+
changes: grantChangesSchema,
|
|
102
|
+
}),
|
|
103
|
+
z.strictObject({ kind: z.literal("select-release") }),
|
|
104
|
+
z.strictObject({ kind: z.literal("delete") }),
|
|
105
|
+
]);
|
|
106
|
+
/** One host-independent approval policy; selection only intersects existing grants. */
|
|
107
|
+
export function applyGrantCommand(current, rawCommand, context) {
|
|
108
|
+
const refuse = (code) => Result.fail({ kind: "refused", code });
|
|
109
|
+
const parsed = grantCommandSchema.safeParse(rawCommand);
|
|
110
|
+
if (!parsed.success)
|
|
111
|
+
return refuse("invalid_command");
|
|
112
|
+
const command = parsed.data;
|
|
113
|
+
if ((current === null && command.kind !== "install") ||
|
|
114
|
+
(current !== null && command.kind === "install"))
|
|
115
|
+
return refuse("invalid_command");
|
|
116
|
+
if ((context.expectedVersion ?? 0) !== (current?.authorityVersion ?? 0) ||
|
|
117
|
+
(current !== null &&
|
|
118
|
+
command.kind !== "select-release" &&
|
|
119
|
+
current.declaredOperationsDigest !== context.declaredOperations.digest))
|
|
120
|
+
return refuse("stale_authority");
|
|
121
|
+
if (context.principal.role === null ||
|
|
122
|
+
context.principal.actor.kind === "visitor" ||
|
|
123
|
+
(command.kind === "change-grants" && context.principal.role !== "owner"))
|
|
124
|
+
return refuse("not_owner");
|
|
125
|
+
const declared = (capability) => context.declaredOperations.capabilities.find((row) => row.capability === capability)?.operations ?? [];
|
|
126
|
+
const version = (current?.authorityVersion ?? 0) + 1;
|
|
127
|
+
let grants = current?.approvedGrants ?? [];
|
|
128
|
+
let approval = current?.approval ?? null;
|
|
129
|
+
switch (command.kind) {
|
|
130
|
+
case "install":
|
|
131
|
+
grants =
|
|
132
|
+
context.principal.role === "owner"
|
|
133
|
+
? context.declaration.capabilities
|
|
134
|
+
.filter((capability) => permissionCatalog[capability].consent === "install")
|
|
135
|
+
.map((capability) => ({
|
|
136
|
+
capability,
|
|
137
|
+
capabilityApproved: true,
|
|
138
|
+
operations: declared(capability),
|
|
139
|
+
resources: "tenant-scope",
|
|
140
|
+
}))
|
|
141
|
+
: [];
|
|
142
|
+
break;
|
|
143
|
+
case "change-grants": {
|
|
144
|
+
for (const { capability, grant } of command.changes) {
|
|
145
|
+
if (!context.declaration.capabilities.includes(capability) ||
|
|
146
|
+
grant?.operations.some((operation) => !declared(capability).includes(operation)))
|
|
147
|
+
return refuse("not_declared");
|
|
148
|
+
const scope = permissionCatalog[capability].scope;
|
|
149
|
+
if (grant !== null &&
|
|
150
|
+
grant.resources !== "tenant-scope" &&
|
|
151
|
+
(scope === null ||
|
|
152
|
+
grant.resources.some((resource) => resource.kind !== scope)))
|
|
153
|
+
return refuse("invalid_command");
|
|
154
|
+
}
|
|
155
|
+
const changed = new Map(command.changes.map((change) => [change.capability, change.grant]));
|
|
156
|
+
grants = [
|
|
157
|
+
...grants.filter((grant) => !changed.has(grant.capability)),
|
|
158
|
+
...command.changes.flatMap(({ capability, grant }) => grant === null ||
|
|
159
|
+
(grant.resources !== "tenant-scope" && grant.resources.length === 0)
|
|
160
|
+
? []
|
|
161
|
+
: [{ capability, ...grant, capabilityApproved: true }]),
|
|
162
|
+
];
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case "select-release":
|
|
166
|
+
grants = grants
|
|
167
|
+
.filter((grant) => context.declaration.capabilities.includes(grant.capability))
|
|
168
|
+
.map((grant) => ({
|
|
169
|
+
...grant,
|
|
170
|
+
operations: grant.operations.filter((operation) => declared(grant.capability).includes(operation)),
|
|
171
|
+
}));
|
|
172
|
+
break;
|
|
173
|
+
case "delete":
|
|
174
|
+
grants = [];
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (grants.length === 0)
|
|
178
|
+
approval = null;
|
|
179
|
+
else if (command.kind === "install" || command.kind === "change-grants") {
|
|
180
|
+
approval = {
|
|
181
|
+
by: context.principal.actor,
|
|
182
|
+
at: context.now,
|
|
183
|
+
authorityVersion: version,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return Result.succeed({
|
|
187
|
+
authorityVersion: version,
|
|
188
|
+
declaredOperationsDigest: context.declaredOperations.digest,
|
|
189
|
+
approvedGrants: grants,
|
|
190
|
+
approval,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
84
193
|
const anonymousMethodsSchema = z
|
|
85
194
|
.array(z
|
|
86
195
|
.strictObject({
|
|
@@ -115,12 +224,9 @@ export const installationSchema = z
|
|
|
115
224
|
appId: ownerCodec(appIdSchema),
|
|
116
225
|
release: ownerCodec(releaseSchema),
|
|
117
226
|
releasePin: z.enum(["pinned", "floating"]),
|
|
118
|
-
|
|
227
|
+
authority: appAuthoritySchema,
|
|
119
228
|
status: z.enum(["enabled", "disabled", "deleted"]),
|
|
120
229
|
visibility: z.enum(["private", "public"]),
|
|
121
|
-
declaredOperationsDigest: ownerCodec(sha256DigestSchema),
|
|
122
|
-
approvedGrants: approvedGrantsSchema,
|
|
123
|
-
approval: approvalSchema.nullable(),
|
|
124
230
|
approvedAnonymousMethods: anonymousMethodsSchema,
|
|
125
231
|
anonymousApproval: approvalSchema.nullable(),
|
|
126
232
|
})
|
|
@@ -132,7 +238,7 @@ export const installationSchema = z
|
|
|
132
238
|
: installation.status !== "deleted" &&
|
|
133
239
|
installation.approvedAnonymousMethods.length > 0 &&
|
|
134
240
|
approval.by.kind === "member" &&
|
|
135
|
-
approval.authorityVersion <= installation.authorityVersion;
|
|
241
|
+
approval.authorityVersion <= installation.authority.authorityVersion;
|
|
136
242
|
}, "Anonymous authority requires a retained human approval receipt");
|
|
137
243
|
const releaseFields = {
|
|
138
244
|
release: ownerCodec(releaseSchema),
|
|
@@ -143,7 +249,6 @@ export const installationCommandSchema = z.lazy(() => z.discriminatedUnion("kind
|
|
|
143
249
|
z.strictObject({
|
|
144
250
|
kind: z.literal("install"),
|
|
145
251
|
...releaseFields,
|
|
146
|
-
grants: grantRequestSchema,
|
|
147
252
|
}),
|
|
148
253
|
z.strictObject({ kind: z.literal("select-release"), ...releaseFields }),
|
|
149
254
|
z.strictObject({
|
|
@@ -155,8 +260,8 @@ export const installationCommandSchema = z.lazy(() => z.discriminatedUnion("kind
|
|
|
155
260
|
visibility: installationSchema.shape.visibility,
|
|
156
261
|
}),
|
|
157
262
|
z.strictObject({
|
|
158
|
-
kind: z.literal("
|
|
159
|
-
|
|
263
|
+
kind: z.literal("change-grants"),
|
|
264
|
+
changes: grantChangesSchema,
|
|
160
265
|
}),
|
|
161
266
|
z.strictObject({
|
|
162
267
|
kind: z.literal("approve-anonymous"),
|
|
@@ -191,12 +296,10 @@ export function applyInstallationCommand(current, rawCommand, context) {
|
|
|
191
296
|
return refuse("stale_authority");
|
|
192
297
|
}
|
|
193
298
|
else if (command.kind === "install" ||
|
|
194
|
-
context.expectedVersion !== current.authorityVersion) {
|
|
299
|
+
context.expectedVersion !== current.authority.authorityVersion) {
|
|
195
300
|
return refuse("stale_authority");
|
|
196
301
|
}
|
|
197
|
-
if (
|
|
198
|
-
(command.kind === "install" && command.grants !== "none")) &&
|
|
199
|
-
context.role !== "owner")
|
|
302
|
+
if (command.kind === "change-grants" && context.role !== "owner")
|
|
200
303
|
return refuse("not_owner");
|
|
201
304
|
const anonymousConsent = context.by.kind === "member" &&
|
|
202
305
|
context.anonymousConsent?.memberId === context.by.memberId;
|
|
@@ -216,14 +319,38 @@ export function applyInstallationCommand(current, rawCommand, context) {
|
|
|
216
319
|
release.artifact.artifactDigest ||
|
|
217
320
|
(current !== null &&
|
|
218
321
|
command.kind !== "select-release" &&
|
|
219
|
-
context.declaredOperations.digest !==
|
|
322
|
+
context.declaredOperations.digest !==
|
|
323
|
+
current.authority.declaredOperationsDigest))
|
|
220
324
|
return refuse("stale_authority");
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
325
|
+
const version = (current?.authority.authorityVersion ?? 0) + 1;
|
|
326
|
+
const grantCommand = command.kind === "install" || command.kind === "select-release"
|
|
327
|
+
? { kind: command.kind }
|
|
328
|
+
: command.kind === "change-grants"
|
|
329
|
+
? command
|
|
330
|
+
: command.kind === "set-status" && command.status === "deleted"
|
|
331
|
+
? { kind: "delete" }
|
|
332
|
+
: null;
|
|
333
|
+
const authority = grantCommand === null
|
|
334
|
+
? current === null
|
|
335
|
+
? Result.fail({
|
|
336
|
+
kind: "refused",
|
|
337
|
+
code: "invalid_command",
|
|
338
|
+
})
|
|
339
|
+
: Result.succeed({
|
|
340
|
+
authorityVersion: version,
|
|
341
|
+
declaredOperationsDigest: current.authority.declaredOperationsDigest,
|
|
342
|
+
approvedGrants: current.authority.approvedGrants,
|
|
343
|
+
approval: current.authority.approval,
|
|
344
|
+
})
|
|
345
|
+
: applyGrantCommand(current?.authority ?? null, grantCommand, {
|
|
346
|
+
principal: { actor: context.by, role: context.role },
|
|
347
|
+
expectedVersion: context.expectedVersion,
|
|
348
|
+
declaration: context.declaration,
|
|
349
|
+
declaredOperations: context.declaredOperations,
|
|
350
|
+
now: context.now,
|
|
351
|
+
});
|
|
352
|
+
if (Result.isFailure(authority))
|
|
353
|
+
return refuse(authority.failure.code);
|
|
227
354
|
let anonymousMethods = current?.approvedAnonymousMethods ?? [];
|
|
228
355
|
let anonymousApproval = current?.anonymousApproval ?? null;
|
|
229
356
|
if (command.kind === "approve-anonymous") {
|
|
@@ -240,44 +367,12 @@ export function applyInstallationCommand(current, rawCommand, context) {
|
|
|
240
367
|
authorityVersion: version,
|
|
241
368
|
};
|
|
242
369
|
}
|
|
243
|
-
if (command.kind === "install" || command.kind === "set-grants") {
|
|
244
|
-
grants =
|
|
245
|
-
command.grants === "none"
|
|
246
|
-
? []
|
|
247
|
-
: command.grants === "declared"
|
|
248
|
-
? context.declaredOperations.capabilities
|
|
249
|
-
.filter((row) => context.declaration.capabilities.includes(row.capability))
|
|
250
|
-
.map((row) => ({
|
|
251
|
-
...row,
|
|
252
|
-
capabilityApproved: true,
|
|
253
|
-
resources: "tenant-scope",
|
|
254
|
-
}))
|
|
255
|
-
: command.grants.map((grant) => ({
|
|
256
|
-
...grant,
|
|
257
|
-
capabilityApproved: true,
|
|
258
|
-
}));
|
|
259
|
-
if (grants.some((grant) => !context.declaration.capabilities.includes(grant.capability) ||
|
|
260
|
-
grant.operations.some((operation) => !declared(grant.capability).includes(operation))))
|
|
261
|
-
return refuse("not_declared");
|
|
262
|
-
approval =
|
|
263
|
-
command.grants === "none"
|
|
264
|
-
? null
|
|
265
|
-
: { by: context.by, at: context.now, authorityVersion: version };
|
|
266
|
-
}
|
|
267
370
|
if (command.kind === "select-release") {
|
|
268
371
|
anonymousMethods = anonymousMethods.filter((method) => context.declaredOperations.anonymousMethods.some((declared) => declared.name === method.name && declared.digest === method.digest));
|
|
269
372
|
if (anonymousMethods.length === 0)
|
|
270
373
|
anonymousApproval = null;
|
|
271
|
-
grants = grants
|
|
272
|
-
.map((grant) => ({
|
|
273
|
-
...grant,
|
|
274
|
-
operations: grant.operations.filter((operation) => declared(grant.capability).includes(operation)),
|
|
275
|
-
}))
|
|
276
|
-
.filter((grant) => context.declaration.capabilities.includes(grant.capability));
|
|
277
374
|
}
|
|
278
375
|
if (command.kind === "set-status" && command.status === "deleted") {
|
|
279
|
-
grants = [];
|
|
280
|
-
approval = null;
|
|
281
376
|
anonymousMethods = [];
|
|
282
377
|
anonymousApproval = null;
|
|
283
378
|
}
|
|
@@ -289,16 +384,13 @@ export function applyInstallationCommand(current, rawCommand, context) {
|
|
|
289
384
|
releasePin: command.kind === "install" || command.kind === "select-release"
|
|
290
385
|
? command.releasePin
|
|
291
386
|
: current?.releasePin,
|
|
292
|
-
authorityVersion: version,
|
|
293
387
|
status: command.kind === "set-status"
|
|
294
388
|
? command.status
|
|
295
389
|
: (current?.status ?? "enabled"),
|
|
296
390
|
visibility: command.kind === "set-visibility"
|
|
297
391
|
? command.visibility
|
|
298
392
|
: (current?.visibility ?? "private"),
|
|
299
|
-
|
|
300
|
-
approvedGrants: grants,
|
|
301
|
-
approval,
|
|
393
|
+
authority: authority.success,
|
|
302
394
|
approvedAnonymousMethods: anonymousMethods,
|
|
303
395
|
anonymousApproval,
|
|
304
396
|
});
|
|
@@ -306,3 +398,17 @@ export function applyInstallationCommand(current, rawCommand, context) {
|
|
|
306
398
|
? Result.succeed({ next: next.data, authorityChanged: true })
|
|
307
399
|
: refuse("invalid_command");
|
|
308
400
|
}
|
|
401
|
+
/** Only the committed installation may activate this exact owner selection. */
|
|
402
|
+
export function isCommittedInstallation(current, state, release) {
|
|
403
|
+
return (current !== null &&
|
|
404
|
+
state.owner.kind === "installation" &&
|
|
405
|
+
current.installationId === state.owner.id &&
|
|
406
|
+
current.instanceId === state.instanceId &&
|
|
407
|
+
current.appId === state.appId &&
|
|
408
|
+
current.authority.authorityVersion === state.authorityVersion &&
|
|
409
|
+
current.status === state.status &&
|
|
410
|
+
current.release.releaseId === state.releaseId &&
|
|
411
|
+
release.releaseId === state.releaseId &&
|
|
412
|
+
release.appId === state.appId &&
|
|
413
|
+
current.release.artifact.artifactDigest === release.artifact.artifactDigest);
|
|
414
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import type { AppPermissionRequest } from "@fungi.computer/agar";
|
|
3
|
+
import { type AppDeclaration, type AppCapabilityId } from "@fungi.computer/puffball/app";
|
|
4
|
+
import { type PermissionCatalogEntry } from "./catalog.js";
|
|
5
|
+
import type { SigilName } from "@fungi.computer/sigils";
|
|
6
|
+
import { type AppAuthority, type DeclaredOperations, type GrantCommand, type GrantChange, type ResourceRef } from "./installation.js";
|
|
7
|
+
/** A host-provided resource identity and its display label. */
|
|
8
|
+
export type ResourceOption = {
|
|
9
|
+
kind: string;
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
};
|
|
13
|
+
/** Includes newly declared operations and capabilities the owner has narrowed. */
|
|
14
|
+
export declare function pendingCapabilities(authority: Pick<AppAuthority, "approvedGrants">, declaration: Pick<AppDeclaration, "capabilities">, declaredOperations: DeclaredOperations): AppDeclaration["capabilities"];
|
|
15
|
+
/** How an App's runtime permission request relates to the owner's stored grants. */
|
|
16
|
+
export type GrantRequestDecision = Readonly<{
|
|
17
|
+
kind: "covered";
|
|
18
|
+
}> | Readonly<{
|
|
19
|
+
kind: "customize";
|
|
20
|
+
}> | Readonly<{
|
|
21
|
+
kind: "refused";
|
|
22
|
+
code: "not_declared" | "stale_authority" | "window_scope_unavailable";
|
|
23
|
+
}> | Readonly<{
|
|
24
|
+
kind: "ask";
|
|
25
|
+
adds: readonly GrantChange[];
|
|
26
|
+
command: Extract<GrantCommand, {
|
|
27
|
+
kind: "change-grants";
|
|
28
|
+
}>;
|
|
29
|
+
}>;
|
|
30
|
+
/** Bound the real SDK request; an Allow never silently widens selected resources. */
|
|
31
|
+
export declare function grantRequestFor(authority: AppAuthority, facts: Readonly<{
|
|
32
|
+
declaration: Pick<AppDeclaration, "capabilities">;
|
|
33
|
+
declaredOperations: DeclaredOperations;
|
|
34
|
+
}>, request: AppPermissionRequest, window: Readonly<{
|
|
35
|
+
computerId: string | null;
|
|
36
|
+
}>): GrantRequestDecision;
|
|
37
|
+
/**
|
|
38
|
+
* A draft contains approvals, never the broader declared-operation projection.
|
|
39
|
+
* @inline
|
|
40
|
+
*/
|
|
41
|
+
export type PermissionGrant = Readonly<{
|
|
42
|
+
operations: readonly string[];
|
|
43
|
+
resources: "tenant-scope" | readonly ResourceRef[];
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Capability approvals being edited; null removes the capability's grant.
|
|
47
|
+
* @inlineType PermissionGrant
|
|
48
|
+
*/
|
|
49
|
+
export type PermissionDraft = ReadonlyMap<AppCapabilityId, PermissionGrant | null>;
|
|
50
|
+
/** One switch, scope, resource or operation change applied to a draft. */
|
|
51
|
+
export type PermissionEdit = Readonly<{
|
|
52
|
+
kind: "switch" | "all";
|
|
53
|
+
capability: AppCapabilityId;
|
|
54
|
+
on: boolean;
|
|
55
|
+
}> | Readonly<{
|
|
56
|
+
kind: "resource";
|
|
57
|
+
capability: AppCapabilityId;
|
|
58
|
+
resource: ResourceRef;
|
|
59
|
+
on: boolean;
|
|
60
|
+
}> | Readonly<{
|
|
61
|
+
kind: "operation";
|
|
62
|
+
capability: AppCapabilityId;
|
|
63
|
+
operation: string;
|
|
64
|
+
on: boolean;
|
|
65
|
+
}>;
|
|
66
|
+
/** The saved operation ceiling is the starting point, including empty operation rows. */
|
|
67
|
+
export declare function draftOf(authority: AppAuthority): PermissionDraft;
|
|
68
|
+
/** An edit changes one capability; unrelated saved operations and scopes are retained. */
|
|
69
|
+
export declare function editPermissions(draft: PermissionDraft, edit: PermissionEdit, declared: DeclaredOperations): PermissionDraft;
|
|
70
|
+
/** Only touched capability rows cross the save boundary. */
|
|
71
|
+
export declare function planGrantChange(baseline: AppAuthority, draft: PermissionDraft): readonly GrantChange[];
|
|
72
|
+
/** A conflict preserves the person's edits while taking fresh untouched capabilities. */
|
|
73
|
+
export declare function rebaseDraft(draft: PermissionDraft, baseline: AppAuthority, current: AppAuthority): PermissionDraft;
|
|
74
|
+
/** Serializable host facts; the browser derives presentation, never authority. */
|
|
75
|
+
export declare const appPermissionsWireSchema: z.ZodObject<{
|
|
76
|
+
authority: z.ZodObject<{
|
|
77
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
78
|
+
declaredOperationsDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
79
|
+
approvedGrants: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
80
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
81
|
+
capabilityApproved: z.ZodLiteral<true>;
|
|
82
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
83
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
84
|
+
kind: z.ZodString;
|
|
85
|
+
id: z.ZodString;
|
|
86
|
+
}, z.core.$strict>>>>>]>;
|
|
87
|
+
}, z.core.$strict>>>>>;
|
|
88
|
+
approval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
89
|
+
by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
|
|
90
|
+
kind: import("zod/mini").ZodMiniLiteral<"member">;
|
|
91
|
+
memberId: import("zod/mini").ZodMiniString<string>;
|
|
92
|
+
}, z.core.$strip>, import("zod/mini").ZodMiniObject<{
|
|
93
|
+
kind: import("zod/mini").ZodMiniLiteral<"agent">;
|
|
94
|
+
agentId: import("zod/mini").ZodMiniString<string>;
|
|
95
|
+
}, z.core.$strip>, import("zod/mini").ZodMiniObject<{
|
|
96
|
+
kind: import("zod/mini").ZodMiniLiteral<"team-key">;
|
|
97
|
+
keyId: import("zod/mini").ZodMiniString<string>;
|
|
98
|
+
}, z.core.$strip>], "kind">;
|
|
99
|
+
at: z.ZodNumber;
|
|
100
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
101
|
+
}, z.core.$strict>>>>;
|
|
102
|
+
}, z.core.$strict>;
|
|
103
|
+
declaredOperations: z.ZodLazy<z.ZodObject<{
|
|
104
|
+
artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
105
|
+
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
106
|
+
anonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
107
|
+
name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
|
|
108
|
+
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
109
|
+
}, z.core.$strict>>>>;
|
|
110
|
+
capabilities: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
111
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
112
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
113
|
+
}, z.core.$strict>>>>;
|
|
114
|
+
}, z.core.$strict>>;
|
|
115
|
+
}, z.core.$strict>;
|
|
116
|
+
/** Host-supplied authority and declared operations used to derive permission UI. */
|
|
117
|
+
export type AppPermissionsWire = z.output<typeof appPermissionsWireSchema>;
|
|
118
|
+
export type PermissionCellState = "on" | "off" | "via-all";
|
|
119
|
+
/**
|
|
120
|
+
* Catalog copy and pending status shared by a group's scoped and switch columns.
|
|
121
|
+
* @inline
|
|
122
|
+
*/
|
|
123
|
+
export type PermissionColumn = Readonly<{
|
|
124
|
+
capability: AppCapabilityId;
|
|
125
|
+
label: string;
|
|
126
|
+
caption: string;
|
|
127
|
+
description: string;
|
|
128
|
+
sigil: SigilName;
|
|
129
|
+
warning: string | null;
|
|
130
|
+
pending: boolean;
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* Catalog-derived permission groups, resource cells and operation switches.
|
|
134
|
+
* @inlineType PermissionColumn
|
|
135
|
+
*/
|
|
136
|
+
export type PermissionScreen = Readonly<{
|
|
137
|
+
canEdit: boolean;
|
|
138
|
+
pending: readonly AppCapabilityId[];
|
|
139
|
+
groups: readonly Readonly<{
|
|
140
|
+
id: PermissionCatalogEntry["group"];
|
|
141
|
+
scope: "computer" | "agent" | null;
|
|
142
|
+
columns: readonly PermissionColumn[];
|
|
143
|
+
rows: readonly Readonly<{
|
|
144
|
+
resource: ResourceRef | "all";
|
|
145
|
+
label: string;
|
|
146
|
+
cells: readonly Readonly<{
|
|
147
|
+
capability: AppCapabilityId;
|
|
148
|
+
state: PermissionCellState;
|
|
149
|
+
}>[];
|
|
150
|
+
}>[];
|
|
151
|
+
switches: readonly (PermissionColumn & Readonly<{
|
|
152
|
+
on: boolean;
|
|
153
|
+
}>)[];
|
|
154
|
+
operations: readonly Readonly<{
|
|
155
|
+
capability: "apps.call";
|
|
156
|
+
operation: string;
|
|
157
|
+
on: boolean;
|
|
158
|
+
}>[];
|
|
159
|
+
}>[];
|
|
160
|
+
}>;
|
|
161
|
+
/** Every declared permission is visible, including removable saved resources no longer listed by the host. */
|
|
162
|
+
export declare function permissionScreen(input: AppPermissionsWire & Readonly<{
|
|
163
|
+
resources: readonly ResourceOption[];
|
|
164
|
+
canEdit: boolean;
|
|
165
|
+
}>): PermissionScreen;
|
|
166
|
+
/** Owner-direct permission page and JSON projection. Copy stays in the catalog. */
|
|
167
|
+
export declare const permissionPinsSchema: z.ZodObject<{
|
|
168
|
+
storeGeneration: z.ZodString;
|
|
169
|
+
authorityVersion: z.ZodNumber;
|
|
170
|
+
artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
171
|
+
}, z.core.$strict>;
|
|
172
|
+
/** Generation, authority version and artifact digest fencing a permission edit. */
|
|
173
|
+
export type PermissionPins = z.output<typeof permissionPinsSchema>;
|
|
174
|
+
/** Permission edit command coupled to the version pins read by the owner. */
|
|
175
|
+
export declare const permissionSaveSchema: z.ZodObject<{
|
|
176
|
+
storeGeneration: z.ZodString;
|
|
177
|
+
authorityVersion: z.ZodNumber;
|
|
178
|
+
artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
179
|
+
command: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
180
|
+
kind: z.ZodLiteral<"install">;
|
|
181
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
182
|
+
kind: z.ZodLiteral<"change-grants">;
|
|
183
|
+
changes: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
184
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
185
|
+
grant: z.ZodNullable<z.ZodReadonly<z.ZodObject<{
|
|
186
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
187
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
188
|
+
kind: z.ZodString;
|
|
189
|
+
id: z.ZodString;
|
|
190
|
+
}, z.core.$strict>>>>>]>;
|
|
191
|
+
}, z.core.$strict>>>;
|
|
192
|
+
}, z.core.$strict>>>>;
|
|
193
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
194
|
+
kind: z.ZodLiteral<"select-release">;
|
|
195
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
196
|
+
kind: z.ZodLiteral<"delete">;
|
|
197
|
+
}, z.core.$strict>], "kind">;
|
|
198
|
+
}, z.core.$strict>;
|
|
199
|
+
/** Owner permission-page identity, artifact and current permission facts. */
|
|
200
|
+
export declare const appPermissionPageSchema: z.ZodObject<{
|
|
201
|
+
storeGeneration: z.ZodString;
|
|
202
|
+
installationId: z.ZodString;
|
|
203
|
+
appId: z.ZodString;
|
|
204
|
+
appName: z.ZodString;
|
|
205
|
+
artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
206
|
+
permissions: z.ZodObject<{
|
|
207
|
+
authority: z.ZodObject<{
|
|
208
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
209
|
+
declaredOperationsDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
210
|
+
approvedGrants: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
211
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
212
|
+
capabilityApproved: z.ZodLiteral<true>;
|
|
213
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
214
|
+
resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
215
|
+
kind: z.ZodString;
|
|
216
|
+
id: z.ZodString;
|
|
217
|
+
}, z.core.$strict>>>>>]>;
|
|
218
|
+
}, z.core.$strict>>>>>;
|
|
219
|
+
approval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
|
|
220
|
+
by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
|
|
221
|
+
kind: import("zod/mini").ZodMiniLiteral<"member">;
|
|
222
|
+
memberId: import("zod/mini").ZodMiniString<string>;
|
|
223
|
+
}, z.core.$strip>, import("zod/mini").ZodMiniObject<{
|
|
224
|
+
kind: import("zod/mini").ZodMiniLiteral<"agent">;
|
|
225
|
+
agentId: import("zod/mini").ZodMiniString<string>;
|
|
226
|
+
}, z.core.$strip>, import("zod/mini").ZodMiniObject<{
|
|
227
|
+
kind: import("zod/mini").ZodMiniLiteral<"team-key">;
|
|
228
|
+
keyId: import("zod/mini").ZodMiniString<string>;
|
|
229
|
+
}, z.core.$strip>], "kind">;
|
|
230
|
+
at: z.ZodNumber;
|
|
231
|
+
authorityVersion: z.ZodLazy<z.ZodNumber>;
|
|
232
|
+
}, z.core.$strict>>>>;
|
|
233
|
+
}, z.core.$strict>;
|
|
234
|
+
declaredOperations: z.ZodLazy<z.ZodObject<{
|
|
235
|
+
artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
236
|
+
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
237
|
+
anonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
238
|
+
name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
|
|
239
|
+
digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
|
|
240
|
+
}, z.core.$strict>>>>;
|
|
241
|
+
capabilities: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
|
|
242
|
+
capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
|
|
243
|
+
operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
|
|
244
|
+
}, z.core.$strict>>>>;
|
|
245
|
+
}, z.core.$strict>>;
|
|
246
|
+
}, z.core.$strict>;
|
|
247
|
+
}, z.core.$strict>;
|