agentic-drive 0.9.0 → 0.10.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/CHANGELOG.md +33 -0
- package/README.md +26 -4
- package/dist/account.d.ts +28 -0
- package/dist/account.js +7 -0
- package/dist/{chunk-R2DUVOJT.js → chunk-DB4F5EWD.js} +146 -216
- package/dist/chunk-ECVUDAHL.js +49 -0
- package/dist/chunk-HJXRMOUY.js +204 -0
- package/dist/{chunk-IMWV5QEH.js → chunk-NHHBNW64.js} +1 -1
- package/dist/{chunk-LELTSSZF.js → chunk-SEHT5Q5L.js} +4 -0
- package/dist/cli.js +17 -6
- package/dist/client.d.ts +7 -2
- package/dist/client.js +1 -1
- package/dist/{drive-Dxy0gL0_.d.ts → drive-BhMTeQ-s.d.ts} +28 -4
- package/dist/embed.css +15 -0
- package/dist/embed.js +150 -99
- package/dist/index.d.ts +4 -3
- package/dist/index.js +15 -9
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +8 -5
- package/dist/worker.d.ts +2 -2
- package/dist/worker.js +12 -4
- package/package.json +10 -4
- package/ui-dist/assets/{index-Dg9jF2oJ.js → index-BiYPMlrf.js} +16 -16
- package/ui-dist/assets/index-oybSrFGW.css +1 -0
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/index-Cb1lY2Sf.css +0 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DriveError,
|
|
3
|
+
safeMime
|
|
4
|
+
} from "./chunk-DB4F5EWD.js";
|
|
5
|
+
|
|
6
|
+
// src/upload.ts
|
|
7
|
+
var DEFAULT_MAX_BYTES = 25 * 1024 * 1024;
|
|
8
|
+
var SIGNATURES = [
|
|
9
|
+
[[137, 80, 78, 71, 13, 10, 26, 10], "image/png"],
|
|
10
|
+
[[255, 216, 255], "image/jpeg"],
|
|
11
|
+
[[71, 73, 70, 56], "image/gif"],
|
|
12
|
+
[[37, 80, 68, 70, 45], "application/pdf"],
|
|
13
|
+
[[80, 75, 3, 4], "application/zip"],
|
|
14
|
+
[[31, 139], "application/gzip"]
|
|
15
|
+
];
|
|
16
|
+
function sniffMime(head) {
|
|
17
|
+
const hit = SIGNATURES.find(([sig]) => sig.every((byte, i) => head[i] === byte));
|
|
18
|
+
if (hit) return hit[1];
|
|
19
|
+
const isWebp = [..."RIFF"].every((c, i) => head[i] === c.charCodeAt(0)) && [..."WEBP"].every((c, i) => head[8 + i] === c.charCodeAt(0));
|
|
20
|
+
return isWebp ? "image/webp" : null;
|
|
21
|
+
}
|
|
22
|
+
function looksLikeText(head) {
|
|
23
|
+
if (head.includes(0)) return false;
|
|
24
|
+
for (let cut = 0; cut < 4 && cut <= head.length; cut++) {
|
|
25
|
+
try {
|
|
26
|
+
new TextDecoder("utf-8", { fatal: true }).decode(head.subarray(0, head.length - cut));
|
|
27
|
+
return true;
|
|
28
|
+
} catch {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
async function* iterate(source) {
|
|
35
|
+
if (Symbol.asyncIterator in source) {
|
|
36
|
+
yield* source;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const reader = source.getReader();
|
|
40
|
+
try {
|
|
41
|
+
for (; ; ) {
|
|
42
|
+
const { done, value } = await reader.read();
|
|
43
|
+
if (done) return;
|
|
44
|
+
yield value;
|
|
45
|
+
}
|
|
46
|
+
} finally {
|
|
47
|
+
reader.releaseLock();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function upload(drive, ctx, path, source, opts = {}) {
|
|
51
|
+
const max = opts.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
52
|
+
const parts = [];
|
|
53
|
+
let size = 0;
|
|
54
|
+
for await (const chunk of iterate(source)) {
|
|
55
|
+
size += chunk.byteLength;
|
|
56
|
+
if (size > max) throw new DriveError("TOO_LARGE", `upload is over the limit of ${max} bytes`);
|
|
57
|
+
parts.push(chunk);
|
|
58
|
+
}
|
|
59
|
+
const data = new Uint8Array(size);
|
|
60
|
+
for (let at = 0, i = 0; i < parts.length; at += parts[i].byteLength, i++) data.set(parts[i], at);
|
|
61
|
+
const head = data.subarray(0, 512);
|
|
62
|
+
const mime = sniffMime(head) ?? (opts.mime !== void 0 ? safeMime(opts.mime) : looksLikeText(head) ? "text/plain" : "application/octet-stream");
|
|
63
|
+
return drive.putFile(ctx, path, data, { mime, parents: opts.parents, onConflict: opts.onConflict });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/zip.ts
|
|
67
|
+
var CRC_TABLE = Array.from({ length: 256 }, (_, n) => {
|
|
68
|
+
let c = n;
|
|
69
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
70
|
+
return c >>> 0;
|
|
71
|
+
});
|
|
72
|
+
function crc32(data) {
|
|
73
|
+
let crc = 4294967295;
|
|
74
|
+
for (const byte of data) crc = CRC_TABLE[(crc ^ byte) & 255] ^ crc >>> 8;
|
|
75
|
+
return (crc ^ 4294967295) >>> 0;
|
|
76
|
+
}
|
|
77
|
+
function safeEntryName(name) {
|
|
78
|
+
if (name === "" || /[\\\u0000]/.test(name) || name.startsWith("/") || /^[a-zA-Z]:/.test(name)) return false;
|
|
79
|
+
return name.split("/").every((part) => part !== "" && part !== "." && part !== "..");
|
|
80
|
+
}
|
|
81
|
+
function writeZip(entries, at) {
|
|
82
|
+
for (const { name } of entries) if (!safeEntryName(name)) throw new Error(`zip: unsafe entry name ${JSON.stringify(name)}`);
|
|
83
|
+
const d = new Date(at);
|
|
84
|
+
const time = d.getUTCHours() << 11 | d.getUTCMinutes() << 5 | d.getUTCSeconds() >> 1;
|
|
85
|
+
const date = Math.max(d.getUTCFullYear(), 1980) - 1980 << 9 | d.getUTCMonth() + 1 << 5 | d.getUTCDate();
|
|
86
|
+
const parts = [];
|
|
87
|
+
const central = [];
|
|
88
|
+
let offset = 0;
|
|
89
|
+
const u16 = (v, o, n) => v.setUint16(o, n, true);
|
|
90
|
+
const u32 = (v, o, n) => v.setUint32(o, n, true);
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const name = new TextEncoder().encode(entry.name);
|
|
93
|
+
const crc = crc32(entry.data);
|
|
94
|
+
if (entry.data.byteLength >= 4294967295 || offset >= 4294967295 || entries.length >= 65535) throw new Error("zip: export is too large for a plain zip");
|
|
95
|
+
const local = new DataView(new ArrayBuffer(30));
|
|
96
|
+
u32(local, 0, 67324752);
|
|
97
|
+
u16(local, 4, 20);
|
|
98
|
+
u16(local, 6, 2048);
|
|
99
|
+
u16(local, 8, 0);
|
|
100
|
+
u16(local, 10, time);
|
|
101
|
+
u16(local, 12, date);
|
|
102
|
+
u32(local, 14, crc);
|
|
103
|
+
u32(local, 18, entry.data.byteLength);
|
|
104
|
+
u32(local, 22, entry.data.byteLength);
|
|
105
|
+
u16(local, 26, name.length);
|
|
106
|
+
u16(local, 28, 0);
|
|
107
|
+
const head = new DataView(new ArrayBuffer(46));
|
|
108
|
+
u32(head, 0, 33639248);
|
|
109
|
+
u16(head, 4, 20);
|
|
110
|
+
u16(head, 6, 20);
|
|
111
|
+
u16(head, 8, 2048);
|
|
112
|
+
u16(head, 10, 0);
|
|
113
|
+
u16(head, 12, time);
|
|
114
|
+
u16(head, 14, date);
|
|
115
|
+
u32(head, 16, crc);
|
|
116
|
+
u32(head, 20, entry.data.byteLength);
|
|
117
|
+
u32(head, 24, entry.data.byteLength);
|
|
118
|
+
u16(head, 28, name.length);
|
|
119
|
+
u32(head, 42, offset);
|
|
120
|
+
parts.push(new Uint8Array(local.buffer), name, entry.data);
|
|
121
|
+
central.push(new Uint8Array(head.buffer), name);
|
|
122
|
+
offset += 30 + name.length + entry.data.byteLength;
|
|
123
|
+
}
|
|
124
|
+
const size = central.reduce((n, p) => n + p.byteLength, 0);
|
|
125
|
+
const end = new DataView(new ArrayBuffer(22));
|
|
126
|
+
u32(end, 0, 101010256);
|
|
127
|
+
u16(end, 8, entries.length);
|
|
128
|
+
u16(end, 10, entries.length);
|
|
129
|
+
u32(end, 12, size);
|
|
130
|
+
u32(end, 16, offset);
|
|
131
|
+
const all = [...parts, ...central, new Uint8Array(end.buffer)];
|
|
132
|
+
const out = new Uint8Array(all.reduce((n, p) => n + p.byteLength, 0));
|
|
133
|
+
let at2 = 0;
|
|
134
|
+
for (const p of all) {
|
|
135
|
+
out.set(p, at2);
|
|
136
|
+
at2 += p.byteLength;
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
function readZip(bytes) {
|
|
141
|
+
const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
142
|
+
let end = bytes.byteLength - 22;
|
|
143
|
+
while (end >= 0 && v.getUint32(end, true) !== 101010256) end--;
|
|
144
|
+
if (end < 0) throw new Error("zip: no end signature");
|
|
145
|
+
const count = v.getUint16(end + 10, true);
|
|
146
|
+
const out = /* @__PURE__ */ new Map();
|
|
147
|
+
for (let i = 0, at = v.getUint32(end + 16, true); i < count; i++) {
|
|
148
|
+
if (v.getUint32(at, true) !== 33639248) throw new Error("zip: bad central signature");
|
|
149
|
+
if (v.getUint16(at + 10, true) !== 0) throw new Error("zip: compressed entries are not supported");
|
|
150
|
+
const crc = v.getUint32(at + 16, true);
|
|
151
|
+
const size = v.getUint32(at + 24, true);
|
|
152
|
+
const nameLen = v.getUint16(at + 28, true);
|
|
153
|
+
const local = v.getUint32(at + 42, true);
|
|
154
|
+
const name = new TextDecoder().decode(bytes.subarray(at + 46, at + 46 + nameLen));
|
|
155
|
+
if (v.getUint32(local, true) !== 67324752) throw new Error("zip: bad local signature");
|
|
156
|
+
const start = local + 30 + v.getUint16(local + 26, true) + v.getUint16(local + 28, true);
|
|
157
|
+
const data = bytes.slice(start, start + size);
|
|
158
|
+
if (crc32(data) !== crc) throw new Error(`zip: crc mismatch in ${name}`);
|
|
159
|
+
out.set(name, data);
|
|
160
|
+
at += 46 + nameLen + v.getUint16(at + 30, true) + v.getUint16(at + 32, true);
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/export.ts
|
|
166
|
+
async function buildExport(drive, ctx, now = Date.now) {
|
|
167
|
+
const entries = [];
|
|
168
|
+
const items = (await drive.exportData(ctx)).map(({ node, path, data, missing }) => {
|
|
169
|
+
const file = data ? `files/${node.id}` : null;
|
|
170
|
+
if (data && file) entries.push({ name: file, data });
|
|
171
|
+
return {
|
|
172
|
+
id: node.id,
|
|
173
|
+
owner: node.owner,
|
|
174
|
+
path,
|
|
175
|
+
parentId: node.parentId,
|
|
176
|
+
kind: node.kind,
|
|
177
|
+
name: node.name,
|
|
178
|
+
size: node.size,
|
|
179
|
+
mime: node.mime,
|
|
180
|
+
hash: node.hash,
|
|
181
|
+
ref: node.ref,
|
|
182
|
+
createdAt: node.createdAt,
|
|
183
|
+
updatedAt: node.updatedAt,
|
|
184
|
+
createdBy: node.createdBy,
|
|
185
|
+
updatedBy: node.updatedBy,
|
|
186
|
+
trashed: node.trashed,
|
|
187
|
+
trashedAt: node.trashedAt,
|
|
188
|
+
file,
|
|
189
|
+
...missing ? { missing: true } : {}
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
const person = await drive.exportPerson(ctx);
|
|
193
|
+
const manifest = { format: "agentic-drive-export", version: 2, exportedAt: now(), owner: ctx.owner, subject: person.subject, partial: person.partial, items, authored: person.authored, agents: person.agents, shares: person.shares, audit: person.audit, activity: person.activity };
|
|
194
|
+
return writeZip([{ name: "manifest.json", data: new TextEncoder().encode(JSON.stringify(manifest, null, 2)) }, ...entries], now());
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export {
|
|
198
|
+
DEFAULT_MAX_BYTES,
|
|
199
|
+
sniffMime,
|
|
200
|
+
upload,
|
|
201
|
+
writeZip,
|
|
202
|
+
readZip,
|
|
203
|
+
buildExport
|
|
204
|
+
};
|
|
@@ -48,6 +48,8 @@ var ROLES = ["viewer", "commenter", "editor", "owner"];
|
|
|
48
48
|
var oneOf = (list) => (v) => typeof v === "string" && list.includes(v);
|
|
49
49
|
var actor = (v) => record(v) && text(v.id) && oneOf(Object.keys(ACTOR_KINDS))(v.kind);
|
|
50
50
|
var isItem = (v) => record(v) && text(v.id) && text(v.owner) && text(v.parentId) && text(v.name) && (v.kind === "folder" || v.kind === "file" || v.kind === "ref") && num(v.size) && orNull(text)(v.mime) && orNull(text)(v.hash) && orNull(text)(v.ref) && num(v.createdAt) && num(v.updatedAt) && actor(v.createdBy) && actor(v.updatedBy) && text(v.createdById) && text(v.updatedById) && typeof v.trashed === "boolean" && orNull(num)(v.trashedAt) && typeof v.machineMade === "boolean";
|
|
51
|
+
var ACTIVITY_ACTIONS = ["create", "rename", "move", "update", "share", "unshare", "delete", "restore"];
|
|
52
|
+
var isActivity = (v) => record(v) && text(v.id) && text(v.itemId) && oneOf(ACTIVITY_ACTIONS)(v.action) && record(v.actor) && text(v.actor.id) && oneOf(["human", "agent"])(v.actor.kind) && oneOf(Object.keys(ACTOR_KINDS))(v.principalKind) && num(v.at) && (v.detail === void 0 || record(v.detail));
|
|
51
53
|
var isPathItem = (v) => isItem(v) && typeof v.path === "string";
|
|
52
54
|
var listOf = (check) => (v) => Array.isArray(v) && v.every(check);
|
|
53
55
|
var shape = (test) => (v) => record(v) && test(v);
|
|
@@ -186,6 +188,8 @@ function createClient(options) {
|
|
|
186
188
|
return {
|
|
187
189
|
/** The live items of a folder. */
|
|
188
190
|
list: (path = "/", o = {}) => json("GET", `/items${query({ path })}`, o, listOf(isItem)),
|
|
191
|
+
/** The changes made to an item, newest first. `idOrPath` is an id or a path. */
|
|
192
|
+
listActivity: (idOrPath, opts = {}) => json("GET", `/items/${encodeURIComponent(idOrPath)}/activity${query({ limit: opts.limit })}`, opts, listOf(isActivity)),
|
|
189
193
|
stat: (path, o = {}) => json("GET", `/stat${query({ path })}`, o, isItem),
|
|
190
194
|
mkdir: (path, opts = {}, o = {}) => json("POST", "/folders", { json: { path, parents: opts.parents === true }, ...o }, isItem),
|
|
191
195
|
/** Writes a file. A `ReadableStream` body streams in runtimes that allow it. */
|
package/dist/cli.js
CHANGED
|
@@ -4,13 +4,16 @@ import {
|
|
|
4
4
|
} from "./chunk-AB2RTTHJ.js";
|
|
5
5
|
import {
|
|
6
6
|
VERSION
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NHHBNW64.js";
|
|
8
|
+
import {
|
|
9
|
+
buildExport,
|
|
10
|
+
upload
|
|
11
|
+
} from "./chunk-HJXRMOUY.js";
|
|
8
12
|
import {
|
|
9
13
|
AuthError,
|
|
10
14
|
DriveError,
|
|
11
15
|
NO_TOKEN,
|
|
12
16
|
addPrincipal,
|
|
13
|
-
buildExport,
|
|
14
17
|
ensureSharing,
|
|
15
18
|
inviteIdentity,
|
|
16
19
|
issueKey,
|
|
@@ -18,9 +21,8 @@ import {
|
|
|
18
21
|
publicNode,
|
|
19
22
|
resolveToken,
|
|
20
23
|
revokeKey,
|
|
21
|
-
revokePrincipal
|
|
22
|
-
|
|
23
|
-
} from "./chunk-R2DUVOJT.js";
|
|
24
|
+
revokePrincipal
|
|
25
|
+
} from "./chunk-DB4F5EWD.js";
|
|
24
26
|
|
|
25
27
|
// src/cli.ts
|
|
26
28
|
import { createReadStream, realpathSync, writeFileSync } from "fs";
|
|
@@ -36,6 +38,7 @@ Usage: agentic-drive <command> [flags]
|
|
|
36
38
|
Commands:
|
|
37
39
|
ls [path] List a folder.
|
|
38
40
|
stat <path|id> Show one item.
|
|
41
|
+
activity <path|id> [--limit] List the changes to an item: who (person or AI agent), what, when.
|
|
39
42
|
mkdir <path> [-p] Make a folder.
|
|
40
43
|
upload <local> <remote> Upload a file. End remote with "/" to keep the name.
|
|
41
44
|
download <remote> [out] Save a file. Use "-" for stdout.
|
|
@@ -78,7 +81,7 @@ Flags:
|
|
|
78
81
|
|
|
79
82
|
Exit codes: 0 done, 1 error, 2 bad usage, 3 no principal or an invalid key.
|
|
80
83
|
`;
|
|
81
|
-
var COMMANDS = ["ls", "stat", "mkdir", "upload", "download", "mv", "rm", "trash", "restore", "purge", "search", "export", "home", "register", "find-ref", "claim-ref", "forget", "shares", "share", "unshare", "invite", "accept-invite", "link-create", "link-revoke", "delete-all", "mcp", "principal", "key"];
|
|
84
|
+
var COMMANDS = ["ls", "stat", "activity", "mkdir", "upload", "download", "mv", "rm", "trash", "restore", "purge", "search", "export", "home", "register", "find-ref", "claim-ref", "forget", "shares", "share", "unshare", "invite", "accept-invite", "link-create", "link-revoke", "delete-all", "mcp", "principal", "key"];
|
|
82
85
|
var UsageError = class extends Error {
|
|
83
86
|
};
|
|
84
87
|
var options = {
|
|
@@ -166,6 +169,14 @@ async function runCli(argv, io) {
|
|
|
166
169
|
need(1, "stat <path|id>");
|
|
167
170
|
print(publicNode(await drive.stat(ctx, args[0])));
|
|
168
171
|
break;
|
|
172
|
+
case "activity":
|
|
173
|
+
need(1, "activity <path|id> [--limit n]");
|
|
174
|
+
{
|
|
175
|
+
const limit = num(values.limit, "limit");
|
|
176
|
+
if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1)) throw new UsageError("--limit needs a whole number of 1 or more");
|
|
177
|
+
print(await drive.listActivity(ctx, args[0], { limit }));
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
169
180
|
case "mkdir":
|
|
170
181
|
need(1, "mkdir <path> [-p]");
|
|
171
182
|
print(publicNode(await drive.mkdir(ctx, args[0], { parents: values.parents })));
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { E as ErrorCode, N as Node, S as SearchQuery } from './drive-
|
|
1
|
+
import { E as ErrorCode, N as Node, A as ActivityEntry, S as SearchQuery } from './drive-BhMTeQ-s.js';
|
|
2
|
+
export { a as ActivityAction } from './drive-BhMTeQ-s.js';
|
|
2
3
|
import 'agentic-identity';
|
|
3
4
|
|
|
4
5
|
type Role = "viewer" | "commenter" | "editor" | "owner";
|
|
@@ -49,6 +50,10 @@ interface Downloaded {
|
|
|
49
50
|
declare function createClient(options: ClientOptions): {
|
|
50
51
|
/** The live items of a folder. */
|
|
51
52
|
list: (path?: string, o?: CallOptions) => Promise<Item[]>;
|
|
53
|
+
/** The changes made to an item, newest first. `idOrPath` is an id or a path. */
|
|
54
|
+
listActivity: (idOrPath: string, opts?: {
|
|
55
|
+
limit?: number;
|
|
56
|
+
} & CallOptions) => Promise<ActivityEntry[]>;
|
|
52
57
|
stat: (path: string, o?: CallOptions) => Promise<Item>;
|
|
53
58
|
mkdir: (path: string, opts?: {
|
|
54
59
|
parents?: boolean;
|
|
@@ -186,4 +191,4 @@ declare function createClient(options: ClientOptions): {
|
|
|
186
191
|
};
|
|
187
192
|
type DriveClient = ReturnType<typeof createClient>;
|
|
188
193
|
|
|
189
|
-
export { type ApiErrorCode, type CallOptions, type ClientErrorCode, type ClientOptions, type Downloaded, DriveApiError, type DriveClient, ErrorCode, type Item, Node, type OnConflict, type PathItem, type Role, type Subject, type SubjectKind, type UploadBody, createClient };
|
|
194
|
+
export { ActivityEntry, type ApiErrorCode, type CallOptions, type ClientErrorCode, type ClientOptions, type Downloaded, DriveApiError, type DriveClient, ErrorCode, type Item, Node, type OnConflict, type PathItem, type Role, type Subject, type SubjectKind, type UploadBody, createClient };
|
package/dist/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as agentic_identity from 'agentic-identity';
|
|
2
|
-
import { PrincipalKind,
|
|
2
|
+
import { PrincipalKind, Store, Blobs, PrincipalContext, createSharing, Subject, Role, SubjectKind } from 'agentic-identity';
|
|
3
3
|
|
|
4
4
|
declare const ROOT_ID = "root";
|
|
5
5
|
declare const ACTOR_KINDS: readonly ["human", "agent_of_human", "agent_of_agent", "agent", "user_token"];
|
|
@@ -8,6 +8,22 @@ type Actor = {
|
|
|
8
8
|
id: string;
|
|
9
9
|
kind: ActorKind;
|
|
10
10
|
};
|
|
11
|
+
type ActivityAction = "create" | "rename" | "move" | "update" | "share" | "unshare" | "delete" | "restore";
|
|
12
|
+
/** One change to an item. `actor.kind` is `agent` for every principal that is not a person, so a reader can label machine-made changes. */
|
|
13
|
+
type ActivityEntry = {
|
|
14
|
+
id: string;
|
|
15
|
+
itemId: string;
|
|
16
|
+
action: ActivityAction;
|
|
17
|
+
actor: {
|
|
18
|
+
id: string;
|
|
19
|
+
kind: "human" | "agent";
|
|
20
|
+
};
|
|
21
|
+
/** The kind of principal behind the change, such as `agent_of_human`. */
|
|
22
|
+
principalKind: ActorKind;
|
|
23
|
+
at: number;
|
|
24
|
+
/** What changed, such as `{ from, to }` for a rename. Never file content. */
|
|
25
|
+
detail?: Record<string, string | number | null>;
|
|
26
|
+
};
|
|
11
27
|
/**
|
|
12
28
|
* `owner` is the drive's owner, and the root of the caller's chain. `actor` is who acts for them.
|
|
13
29
|
* `principal` is the resolved caller. Drive needs it to check roles when `sharing` is set.
|
|
@@ -98,6 +114,13 @@ declare function subjectKindOf(kind: unknown): SubjectKind;
|
|
|
98
114
|
declare function parseSubject(input: unknown): Subject;
|
|
99
115
|
declare function createDrive(deps: DriveDeps): {
|
|
100
116
|
stat(ctx: Ctx, loc: string): Promise<Node>;
|
|
117
|
+
/**
|
|
118
|
+
* The changes made to one item, newest first: who (a person or an agent), what, and when. Anyone who may read
|
|
119
|
+
* the item may read its log. A trashed item can be named by id, so its log can be read before a restore.
|
|
120
|
+
*/
|
|
121
|
+
listActivity(ctx: Ctx, loc: string, opts?: {
|
|
122
|
+
limit?: number;
|
|
123
|
+
}): Promise<ActivityEntry[]>;
|
|
101
124
|
/** Live children, sorted by name. */
|
|
102
125
|
list(ctx: Ctx, loc?: string): Promise<Node[]>;
|
|
103
126
|
mkdir(ctx: Ctx, path: string, opts?: {
|
|
@@ -219,8 +242,8 @@ declare function createDrive(deps: DriveDeps): {
|
|
|
219
242
|
* What drive holds about the person behind a call, besides their own drive (`exportData` has that). It is
|
|
220
243
|
* only for the person in person: an agent gets `partial: true` and nothing else. It holds the ids of the
|
|
221
244
|
* items they or their agents made or changed in other drives (no names, and nothing of the people who own
|
|
222
|
-
* them), the shares they hold
|
|
223
|
-
* did. Invitee emails and link tokens are not in it.
|
|
245
|
+
* them), the shares they hold and the invites they sent on drive items, and the audit entries of what they and
|
|
246
|
+
* their agents did. Invitee emails and link tokens are not in it.
|
|
224
247
|
*/
|
|
225
248
|
exportPerson(ctx: Ctx): Promise<{
|
|
226
249
|
subject: {
|
|
@@ -274,6 +297,7 @@ declare function createDrive(deps: DriveDeps): {
|
|
|
274
297
|
principalKind: unknown;
|
|
275
298
|
machineMade: unknown;
|
|
276
299
|
}[];
|
|
300
|
+
activity: ActivityEntry[];
|
|
277
301
|
}>;
|
|
278
302
|
/**
|
|
279
303
|
* Erases a person for good. Only the person in person may. Their drive and its shares go. So do the shares
|
|
@@ -356,4 +380,4 @@ declare function createDrive(deps: DriveDeps): {
|
|
|
356
380
|
}>;
|
|
357
381
|
};
|
|
358
382
|
|
|
359
|
-
export { type
|
|
383
|
+
export { type ActivityEntry as A, type Ctx as C, type Drive as D, type ErrorCode as E, type Node as N, type OnConflict as O, ROOT_ID as R, type SearchQuery as S, type ActivityAction as a, type Actor as b, ACTOR_KINDS as c, type Action as d, type ActorKind as e, type Can as f, type DriveDeps as g, DriveError as h, ERROR_STATUS as i, createDrive as j, parseSubject as k, parseName as p, subjectKindOf as s };
|
package/dist/embed.css
CHANGED
|
@@ -289,3 +289,18 @@ html:has(.drive-bulk) {
|
|
|
289
289
|
background-repeat: no-repeat;
|
|
290
290
|
background-position: center;
|
|
291
291
|
}
|
|
292
|
+
.drive-activity {
|
|
293
|
+
list-style: none;
|
|
294
|
+
margin: 0;
|
|
295
|
+
padding: 0;
|
|
296
|
+
display: grid;
|
|
297
|
+
gap: var(--agd-space-2);
|
|
298
|
+
}
|
|
299
|
+
.drive-activity li {
|
|
300
|
+
padding: var(--agd-space-2) 0;
|
|
301
|
+
border-bottom: 1px solid var(--agd-color-border);
|
|
302
|
+
}
|
|
303
|
+
.drive-activity time {
|
|
304
|
+
color: var(--agd-color-text-muted);
|
|
305
|
+
font-size: 0.875em;
|
|
306
|
+
}
|