@anchrd/intel-contract 0.25.0 → 0.27.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/dist/contract/feed.d.ts +70 -0
- package/dist/contract/feed.js +84 -0
- package/dist/contract/node.d.ts +22 -0
- package/dist/contract/node.js +18 -0
- package/package.json +5 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const FeedAction: z.ZodEnum<{
|
|
3
|
+
"node.create": "node.create";
|
|
4
|
+
"node.save": "node.save";
|
|
5
|
+
"node.update": "node.update";
|
|
6
|
+
"node.append": "node.append";
|
|
7
|
+
"node.archive": "node.archive";
|
|
8
|
+
"node.share": "node.share";
|
|
9
|
+
"node.revoke": "node.revoke";
|
|
10
|
+
}>;
|
|
11
|
+
export type FeedAction = z.infer<typeof FeedAction>;
|
|
12
|
+
export declare const FeedPathSegment: z.ZodObject<{
|
|
13
|
+
id: z.ZodString;
|
|
14
|
+
title: z.ZodString;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export type FeedPathSegment = z.infer<typeof FeedPathSegment>;
|
|
17
|
+
export declare const FeedEvent: z.ZodObject<{
|
|
18
|
+
id: z.ZodString;
|
|
19
|
+
actorId: z.ZodString;
|
|
20
|
+
action: z.ZodEnum<{
|
|
21
|
+
"node.create": "node.create";
|
|
22
|
+
"node.save": "node.save";
|
|
23
|
+
"node.update": "node.update";
|
|
24
|
+
"node.append": "node.append";
|
|
25
|
+
"node.archive": "node.archive";
|
|
26
|
+
"node.share": "node.share";
|
|
27
|
+
"node.revoke": "node.revoke";
|
|
28
|
+
}>;
|
|
29
|
+
nodeId: z.ZodString;
|
|
30
|
+
nodeTitle: z.ZodString;
|
|
31
|
+
path: z.ZodArray<z.ZodObject<{
|
|
32
|
+
id: z.ZodString;
|
|
33
|
+
title: z.ZodString;
|
|
34
|
+
}, z.core.$strict>>;
|
|
35
|
+
metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
36
|
+
occurredAt: z.ZodISODateTime;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
export type FeedEvent = z.infer<typeof FeedEvent>;
|
|
39
|
+
export declare const FeedCursor: z.ZodString;
|
|
40
|
+
export declare const FeedListRequest: z.ZodObject<{
|
|
41
|
+
actor: z.ZodOptional<z.ZodString>;
|
|
42
|
+
before: z.ZodOptional<z.ZodString>;
|
|
43
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
export type FeedListRequest = z.infer<typeof FeedListRequest>;
|
|
46
|
+
export declare const FeedListResponse: z.ZodObject<{
|
|
47
|
+
events: z.ZodArray<z.ZodObject<{
|
|
48
|
+
id: z.ZodString;
|
|
49
|
+
actorId: z.ZodString;
|
|
50
|
+
action: z.ZodEnum<{
|
|
51
|
+
"node.create": "node.create";
|
|
52
|
+
"node.save": "node.save";
|
|
53
|
+
"node.update": "node.update";
|
|
54
|
+
"node.append": "node.append";
|
|
55
|
+
"node.archive": "node.archive";
|
|
56
|
+
"node.share": "node.share";
|
|
57
|
+
"node.revoke": "node.revoke";
|
|
58
|
+
}>;
|
|
59
|
+
nodeId: z.ZodString;
|
|
60
|
+
nodeTitle: z.ZodString;
|
|
61
|
+
path: z.ZodArray<z.ZodObject<{
|
|
62
|
+
id: z.ZodString;
|
|
63
|
+
title: z.ZodString;
|
|
64
|
+
}, z.core.$strict>>;
|
|
65
|
+
metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
66
|
+
occurredAt: z.ZodISODateTime;
|
|
67
|
+
}, z.core.$strict>>;
|
|
68
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
69
|
+
}, z.core.$strict>;
|
|
70
|
+
export type FeedListResponse = z.infer<typeof FeedListResponse>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { IntelId, IsoDateTime } from "./contract.js";
|
|
3
|
+
// What a person did, in the words a person would use. This is a POSITIVE LIST and not the set of
|
|
4
|
+
// actions the journal carries (#740).
|
|
5
|
+
//
|
|
6
|
+
// ⚠️ Two omissions are the point of the list, not an oversight. `node.version` is written by the
|
|
7
|
+
// same batch as `node.save`, so admitting both would show every edit twice — and because this feed
|
|
8
|
+
// does not group anything yet, twice means two cards. `node.link` and `node.import` are machine
|
|
9
|
+
// traces of a save rather than something anybody did.
|
|
10
|
+
//
|
|
11
|
+
// ⚠️ And it stays a positive list. "Everything except" would silently admit whatever the next
|
|
12
|
+
// migration starts writing, on a surface whose whole job is to be readable.
|
|
13
|
+
export const FeedAction = z.enum([
|
|
14
|
+
"node.create",
|
|
15
|
+
"node.save",
|
|
16
|
+
"node.update",
|
|
17
|
+
"node.append",
|
|
18
|
+
"node.archive",
|
|
19
|
+
"node.share",
|
|
20
|
+
"node.revoke",
|
|
21
|
+
]);
|
|
22
|
+
// One step on the way down to the node, from the root. It carries the id as well as the title
|
|
23
|
+
// because the surface links each step, and two folders may share a name.
|
|
24
|
+
export const FeedPathSegment = z.strictObject({
|
|
25
|
+
id: IntelId,
|
|
26
|
+
title: z.string().min(1),
|
|
27
|
+
});
|
|
28
|
+
// One card's worth of journal.
|
|
29
|
+
//
|
|
30
|
+
// ⚠️ `nodeTitle` and `path` are read from `nodes` at query time, so they are TODAY's title and
|
|
31
|
+
// today's place — not the ones the node had when the event happened. That is the right answer for a
|
|
32
|
+
// feed (the reader wants to find the thing now) and the wrong one for an audit trail, which is one
|
|
33
|
+
// more reason these are two doors and not one.
|
|
34
|
+
//
|
|
35
|
+
// `metadata` is whatever the write site recorded, untyped on purpose: a schema per action would
|
|
36
|
+
// have to be kept in step with eleven write sites and would go stale in silence. What the surface
|
|
37
|
+
// needs from it today is `sequence` on a `node.save`, which is the version number behind the card's
|
|
38
|
+
// button.
|
|
39
|
+
export const FeedEvent = z.strictObject({
|
|
40
|
+
id: IntelId,
|
|
41
|
+
actorId: z.string().min(1),
|
|
42
|
+
action: FeedAction,
|
|
43
|
+
nodeId: IntelId,
|
|
44
|
+
nodeTitle: z.string().min(1),
|
|
45
|
+
path: z.array(FeedPathSegment),
|
|
46
|
+
metadata: z.record(z.string(), z.unknown()),
|
|
47
|
+
occurredAt: IsoDateTime,
|
|
48
|
+
});
|
|
49
|
+
// ⚠️ Opaque BY CONTRACT, like the audit cursor and for the same reason: it is a PAIR
|
|
50
|
+
// (`occurredAt`, `id`), and a timestamp alone cannot separate two events written in the same
|
|
51
|
+
// millisecond — the normal case inside one batch. A reader continuing on the timestamp alone skips
|
|
52
|
+
// the second one with no error and no log.
|
|
53
|
+
//
|
|
54
|
+
// ⚠️ It is deliberately NOT interchangeable with an audit cursor, although both encode the same
|
|
55
|
+
// pair. The two doors walk the journal in opposite directions, so handing one's position to the
|
|
56
|
+
// other reads on from the wrong end — and would look like a feed that suddenly starts at the
|
|
57
|
+
// beginning of time rather than like a mistake. The encoding therefore carries its own marker and
|
|
58
|
+
// the other door's cursor is refused.
|
|
59
|
+
export const FeedCursor = z.string().min(1).max(400);
|
|
60
|
+
export const FeedListRequest = z.strictObject({
|
|
61
|
+
actor: z
|
|
62
|
+
.string()
|
|
63
|
+
.min(1)
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("Show only what this person or agent did. Omit it for everybody whose work you may see anyway."),
|
|
66
|
+
before: FeedCursor.optional().describe("Where to continue: the `nextCursor` of a previous answer, passed back unchanged. Omit it to start at the most recent event. Do not build one — it is opaque on purpose, and a cursor from `audit_list` is refused rather than followed backwards."),
|
|
67
|
+
limit: z
|
|
68
|
+
.number()
|
|
69
|
+
.int()
|
|
70
|
+
.min(1)
|
|
71
|
+
.max(100)
|
|
72
|
+
.default(30)
|
|
73
|
+
.describe("How many events to return at most. The answer may be shorter."),
|
|
74
|
+
});
|
|
75
|
+
// `nextCursor` is present exactly when another page may exist, and it is the cursor of the LAST
|
|
76
|
+
// returned row.
|
|
77
|
+
//
|
|
78
|
+
// ⚠️ Present does not promise the next page is non-empty: the rows a reader may see can shrink
|
|
79
|
+
// between calls. Treating "cursor present" as "there is more" is fair; treating an empty answer as
|
|
80
|
+
// "you have reached the beginning of the journal" is not.
|
|
81
|
+
export const FeedListResponse = z.strictObject({
|
|
82
|
+
events: z.array(FeedEvent),
|
|
83
|
+
nextCursor: FeedCursor.nullable(),
|
|
84
|
+
});
|
package/dist/contract/node.d.ts
CHANGED
|
@@ -120,9 +120,31 @@ export declare const PurgeNodePreviewInput: z.ZodObject<{
|
|
|
120
120
|
nodeId: z.ZodString;
|
|
121
121
|
}, z.core.$strict>;
|
|
122
122
|
export type PurgeNodePreviewInput = z.infer<typeof PurgeNodePreviewInput>;
|
|
123
|
+
/**
|
|
124
|
+
* ⚠️ **A count is not an answer before a deletion that cannot be undone** (D71, #733). `totalItems`
|
|
125
|
+
* alone reads as "82 items" for a folder holding somebody's whole memory, and `destructive.md` asks
|
|
126
|
+
* for the number to be named BEFORE the confirmation — one step more precise is the difference
|
|
127
|
+
* between a number and something a person can decide on.
|
|
128
|
+
*
|
|
129
|
+
* `items` is capped, and the cap is visible rather than silent: `totalItems` keeps counting past it,
|
|
130
|
+
* so a caller can always say "and 40 more". A list of ten thousand rows would be an answer nobody
|
|
131
|
+
* reads and a response nobody can render.
|
|
132
|
+
*/
|
|
123
133
|
export declare const PurgeNodePreview: z.ZodObject<{
|
|
124
134
|
inboundLinks: z.ZodNumber;
|
|
125
135
|
totalItems: z.ZodNumber;
|
|
136
|
+
items: z.ZodArray<z.ZodObject<{
|
|
137
|
+
id: z.ZodString;
|
|
138
|
+
kind: z.ZodUnion<readonly [z.ZodEnum<{
|
|
139
|
+
folder: "folder";
|
|
140
|
+
document: "document";
|
|
141
|
+
table: "table";
|
|
142
|
+
attachment: "attachment";
|
|
143
|
+
board: "board";
|
|
144
|
+
task: "task";
|
|
145
|
+
}>, z.ZodLiteral<"flow">]>;
|
|
146
|
+
title: z.ZodString;
|
|
147
|
+
}, z.core.$strict>>;
|
|
126
148
|
}, z.core.$strict>;
|
|
127
149
|
export type PurgeNodePreview = z.infer<typeof PurgeNodePreview>;
|
|
128
150
|
export declare const PurgeNodeResult: z.ZodObject<{
|
package/dist/contract/node.js
CHANGED
|
@@ -187,9 +187,27 @@ export const PurgeNodeInput = z.strictObject({
|
|
|
187
187
|
export const PurgeNodePreviewInput = z.strictObject({
|
|
188
188
|
nodeId: IntelId.describe("Archived node a purge would delete. Answers how many items would go with it and how many documents link to it from outside, and changes nothing. A node that is not archived is refused here for the same reason node_purge refuses it."),
|
|
189
189
|
});
|
|
190
|
+
/**
|
|
191
|
+
* ⚠️ **A count is not an answer before a deletion that cannot be undone** (D71, #733). `totalItems`
|
|
192
|
+
* alone reads as "82 items" for a folder holding somebody's whole memory, and `destructive.md` asks
|
|
193
|
+
* for the number to be named BEFORE the confirmation — one step more precise is the difference
|
|
194
|
+
* between a number and something a person can decide on.
|
|
195
|
+
*
|
|
196
|
+
* `items` is capped, and the cap is visible rather than silent: `totalItems` keeps counting past it,
|
|
197
|
+
* so a caller can always say "and 40 more". A list of ten thousand rows would be an answer nobody
|
|
198
|
+
* reads and a response nobody can render.
|
|
199
|
+
*/
|
|
190
200
|
export const PurgeNodePreview = z.strictObject({
|
|
191
201
|
inboundLinks: z.number().int().nonnegative(),
|
|
192
202
|
totalItems: z.number().int().positive(),
|
|
203
|
+
// ⚠️ `flow` beside the node kinds, because a flow filed in the folder goes with it and is counted
|
|
204
|
+
// in `totalItems`. Naming everything except flows would leave out the one thing the cascade had to
|
|
205
|
+
// be widened for (#733).
|
|
206
|
+
items: z.array(z.strictObject({
|
|
207
|
+
id: IntelId,
|
|
208
|
+
kind: z.union([NodeKind, z.literal("flow")]),
|
|
209
|
+
title: z.string(),
|
|
210
|
+
})),
|
|
193
211
|
});
|
|
194
212
|
// The title travels back because after this call nothing can look it up any more — not the row, not
|
|
195
213
|
// a version, not the index. A caller that wants to say what it just deleted has this one chance.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anchrd/intel-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"types": "./dist/contract/bundle.d.ts",
|
|
29
29
|
"default": "./dist/contract/bundle.js"
|
|
30
30
|
},
|
|
31
|
+
"./feed": {
|
|
32
|
+
"types": "./dist/contract/feed.d.ts",
|
|
33
|
+
"default": "./dist/contract/feed.js"
|
|
34
|
+
},
|
|
31
35
|
"./flow": {
|
|
32
36
|
"types": "./dist/contract/flow.d.ts",
|
|
33
37
|
"default": "./dist/contract/flow.js"
|