@ixo/topic-protocol 0.2.0 → 0.4.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 +14 -2
- package/dist/schemas/topic-capsule.schema.json +2 -1
- package/dist/schemas/topic-file-attachment.schema.json +23 -0
- package/dist/schemas/topic-index-entry.schema.json +34 -1
- package/dist/schemas/topic-index.schema.json +39 -0
- package/dist/schemas/topic-operation.schema.json +1 -1
- package/dist/schemas/topic-root.schema.json +13 -1
- package/dist/schemas/topic-state.schema.json +10 -1
- package/dist/src/contracts/schemas.d.ts +212 -1
- package/dist/src/contracts/schemas.js +4 -0
- package/dist/src/contracts/schemas.js.map +1 -1
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.js +5 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexing/rank.d.ts +2 -0
- package/dist/src/indexing/rank.js +31 -0
- package/dist/src/indexing/rank.js.map +1 -0
- package/dist/src/indexing/reconcile.d.ts +3 -0
- package/dist/src/indexing/reconcile.js +58 -0
- package/dist/src/indexing/reconcile.js.map +1 -0
- package/dist/src/indexing/search.d.ts +2 -0
- package/dist/src/indexing/search.js +37 -0
- package/dist/src/indexing/search.js.map +1 -0
- package/dist/src/indexing/types.d.ts +75 -0
- package/dist/src/indexing/types.js +22 -0
- package/dist/src/indexing/types.js.map +1 -0
- package/dist/src/matrix/content.d.ts +1 -1
- package/dist/src/matrix/content.js +8 -0
- package/dist/src/matrix/content.js.map +1 -1
- package/dist/src/projector/payload.d.ts +7 -1
- package/dist/src/projector/payload.js +86 -2
- package/dist/src/projector/payload.js.map +1 -1
- package/dist/src/projector/state.js +41 -0
- package/dist/src/projector/state.js.map +1 -1
- package/dist/src/projector/types.d.ts +32 -1
- package/dist/src/projector/types.js +18 -0
- package/dist/src/projector/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { compareText } from "../shared/compare.js";
|
|
2
|
+
const COMPLETENESS_RANK = {
|
|
3
|
+
complete: 4,
|
|
4
|
+
"partial-history": 3,
|
|
5
|
+
"metadata-pending": 2,
|
|
6
|
+
"decryption-pending": 1,
|
|
7
|
+
};
|
|
8
|
+
function compareEntries(left, right) {
|
|
9
|
+
return compareText(left.indexedAt, right.indexedAt)
|
|
10
|
+
|| COMPLETENESS_RANK[left.completeness] - COMPLETENESS_RANK[right.completeness]
|
|
11
|
+
|| compareText(right.roomId, left.roomId)
|
|
12
|
+
|| compareText(right.rootEventId, left.rootEventId);
|
|
13
|
+
}
|
|
14
|
+
function latestEntries(entries) {
|
|
15
|
+
const byTopic = new Map();
|
|
16
|
+
entries.forEach((entry) => {
|
|
17
|
+
const current = byTopic.get(entry.topicId);
|
|
18
|
+
if (current === undefined || compareEntries(current, entry) < 0)
|
|
19
|
+
byTopic.set(entry.topicId, entry);
|
|
20
|
+
});
|
|
21
|
+
return byTopic;
|
|
22
|
+
}
|
|
23
|
+
function latestTombstones(tombstones) {
|
|
24
|
+
const byRoom = new Map();
|
|
25
|
+
tombstones.forEach((tombstone) => {
|
|
26
|
+
const current = byRoom.get(tombstone.roomId);
|
|
27
|
+
if (current === undefined || compareText(current.removedAt, tombstone.removedAt) < 0)
|
|
28
|
+
byRoom.set(tombstone.roomId, tombstone);
|
|
29
|
+
});
|
|
30
|
+
return byRoom;
|
|
31
|
+
}
|
|
32
|
+
function isAfterTombstone(entry, tombstones) {
|
|
33
|
+
const tombstone = tombstones.get(entry.roomId);
|
|
34
|
+
return tombstone === undefined || compareText(tombstone.removedAt, entry.indexedAt) < 0;
|
|
35
|
+
}
|
|
36
|
+
export function emptyTopicIndexSnapshot(updatedAt) {
|
|
37
|
+
return { version: 1, updatedAt, entries: [], tombstones: [] };
|
|
38
|
+
}
|
|
39
|
+
export function reconcileTopicIndex(snapshot, input) {
|
|
40
|
+
const removed = new Set(input.leftRoomIds ?? []);
|
|
41
|
+
const tombstones = latestTombstones([
|
|
42
|
+
...snapshot.tombstones,
|
|
43
|
+
...[...removed].map((roomId) => ({ roomId, removedAt: input.reconciledAt })),
|
|
44
|
+
]);
|
|
45
|
+
const observed = input.observations
|
|
46
|
+
.filter(({ canonicalAnchor }) => canonicalAnchor)
|
|
47
|
+
.map(({ entry }) => entry);
|
|
48
|
+
const entries = [...latestEntries([...snapshot.entries, ...observed]).values()]
|
|
49
|
+
.filter((entry) => !removed.has(entry.roomId) && isAfterTombstone(entry, tombstones))
|
|
50
|
+
.sort((left, right) => compareText(left.topicId, right.topicId));
|
|
51
|
+
return {
|
|
52
|
+
version: 1,
|
|
53
|
+
updatedAt: input.reconciledAt,
|
|
54
|
+
entries,
|
|
55
|
+
tombstones: [...tombstones.values()].sort((left, right) => compareText(left.roomId, right.roomId)),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../../src/indexing/reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { compareText } from "../shared/compare.js";
|
|
2
|
+
function includesAny(value, accepted) {
|
|
3
|
+
return accepted === undefined || accepted.length === 0 || (value !== undefined && accepted.includes(value));
|
|
4
|
+
}
|
|
5
|
+
function includesSource(entry, accepted) {
|
|
6
|
+
return accepted === undefined || accepted.length === 0 || accepted.some((kind) => entry.sourceKinds?.includes(kind));
|
|
7
|
+
}
|
|
8
|
+
function searchText(entry) {
|
|
9
|
+
return [
|
|
10
|
+
entry.title,
|
|
11
|
+
entry.currentState,
|
|
12
|
+
entry.domain?.name,
|
|
13
|
+
entry.domain?.id,
|
|
14
|
+
...(entry.context?.flatMap(({ type, id }) => [type, id]) ?? []),
|
|
15
|
+
].filter((value) => value !== undefined).join(" ").toLowerCase();
|
|
16
|
+
}
|
|
17
|
+
function matchesQuery(entry, query) {
|
|
18
|
+
const tokens = query?.trim().toLowerCase().split(/\s+/).filter(Boolean) ?? [];
|
|
19
|
+
if (tokens.length === 0)
|
|
20
|
+
return true;
|
|
21
|
+
const haystack = searchText(entry);
|
|
22
|
+
return tokens.every((token) => haystack.includes(token));
|
|
23
|
+
}
|
|
24
|
+
function matchesFollowing(entry, following, preferences) {
|
|
25
|
+
if (following === undefined)
|
|
26
|
+
return true;
|
|
27
|
+
return (preferences[entry.topicId]?.notificationMode === "follow") === following;
|
|
28
|
+
}
|
|
29
|
+
export function searchTopicIndex(entries, filters = {}, preferences = {}) {
|
|
30
|
+
return entries.filter((entry) => matchesQuery(entry, filters.query)
|
|
31
|
+
&& includesAny(entry.status, filters.statuses)
|
|
32
|
+
&& includesAny(entry.domain?.id, filters.domainIds)
|
|
33
|
+
&& includesAny(entry.kind, filters.kinds)
|
|
34
|
+
&& includesSource(entry, filters.sourceKinds)
|
|
35
|
+
&& matchesFollowing(entry, filters.following, preferences)).sort((left, right) => compareText(left.title ?? "", right.title ?? "") || compareText(left.topicId, right.topicId));
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/indexing/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { TopicSourceKind } from "../matrix/cards.js";
|
|
2
|
+
import type { TopicContext, TopicKind, TopicStatus } from "../projector/types.js";
|
|
3
|
+
export declare const TOPIC_INDEX_COMPLETENESS: readonly ["complete", "partial-history", "metadata-pending", "decryption-pending"];
|
|
4
|
+
export declare const TOPIC_INDEX_UNREAD_STATES: readonly ["unread", "read", "unknown"];
|
|
5
|
+
export declare const TOPIC_INDEX_STORAGE_STATES: readonly ["encrypted", "memory-only", "locked", "unavailable"];
|
|
6
|
+
export declare const TOPIC_NOTIFICATION_MODES: readonly ["follow", "default", "mute"];
|
|
7
|
+
export declare const TOPIC_INDEX_RANK_REASONS: readonly ["pinned", "direct-attention", "followed-unread", "participated", "recent"];
|
|
8
|
+
export type TopicIndexCompleteness = (typeof TOPIC_INDEX_COMPLETENESS)[number];
|
|
9
|
+
export type TopicIndexUnreadState = (typeof TOPIC_INDEX_UNREAD_STATES)[number];
|
|
10
|
+
export type TopicIndexStorageState = (typeof TOPIC_INDEX_STORAGE_STATES)[number];
|
|
11
|
+
export type TopicNotificationMode = (typeof TOPIC_NOTIFICATION_MODES)[number];
|
|
12
|
+
export type TopicIndexRankReason = (typeof TOPIC_INDEX_RANK_REASONS)[number];
|
|
13
|
+
export interface TopicIndexDomain {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly name?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TopicIndexEntry {
|
|
18
|
+
readonly topicId: string;
|
|
19
|
+
readonly roomId: string;
|
|
20
|
+
readonly rootEventId: string;
|
|
21
|
+
readonly title?: string;
|
|
22
|
+
readonly currentState?: string;
|
|
23
|
+
readonly status: TopicStatus;
|
|
24
|
+
readonly kind?: TopicKind;
|
|
25
|
+
readonly domain?: TopicIndexDomain;
|
|
26
|
+
readonly context?: readonly TopicContext[];
|
|
27
|
+
readonly sourceKinds?: readonly TopicSourceKind[];
|
|
28
|
+
readonly latestActivityAt: string;
|
|
29
|
+
readonly latestEventId?: string;
|
|
30
|
+
readonly participated: boolean;
|
|
31
|
+
readonly unread: TopicIndexUnreadState;
|
|
32
|
+
readonly completeness: TopicIndexCompleteness;
|
|
33
|
+
readonly indexedAt: string;
|
|
34
|
+
}
|
|
35
|
+
export interface TopicIndexTombstone {
|
|
36
|
+
readonly roomId: string;
|
|
37
|
+
readonly removedAt: string;
|
|
38
|
+
}
|
|
39
|
+
export interface TopicIndexSnapshot {
|
|
40
|
+
readonly version: 1;
|
|
41
|
+
readonly updatedAt: string;
|
|
42
|
+
readonly entries: readonly TopicIndexEntry[];
|
|
43
|
+
readonly tombstones: readonly TopicIndexTombstone[];
|
|
44
|
+
}
|
|
45
|
+
export interface TopicPreference {
|
|
46
|
+
readonly notificationMode: TopicNotificationMode;
|
|
47
|
+
readonly pinned: boolean;
|
|
48
|
+
readonly markedUnreadFrom?: string | null;
|
|
49
|
+
}
|
|
50
|
+
export type TopicPreferenceMap = Readonly<Record<string, TopicPreference>>;
|
|
51
|
+
export interface TopicIndexObservation {
|
|
52
|
+
readonly entry: TopicIndexEntry;
|
|
53
|
+
readonly canonicalAnchor: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface TopicIndexReconciliation {
|
|
56
|
+
readonly observations: readonly TopicIndexObservation[];
|
|
57
|
+
readonly leftRoomIds?: readonly string[];
|
|
58
|
+
readonly reconciledAt: string;
|
|
59
|
+
}
|
|
60
|
+
export interface TopicIndexSearchFilters {
|
|
61
|
+
readonly query?: string;
|
|
62
|
+
readonly statuses?: readonly TopicStatus[];
|
|
63
|
+
readonly domainIds?: readonly string[];
|
|
64
|
+
readonly following?: boolean;
|
|
65
|
+
readonly kinds?: readonly TopicKind[];
|
|
66
|
+
readonly sourceKinds?: readonly TopicSourceKind[];
|
|
67
|
+
}
|
|
68
|
+
export interface TopicAttentionSignals {
|
|
69
|
+
readonly directAttention?: boolean;
|
|
70
|
+
}
|
|
71
|
+
export type TopicAttentionSignalMap = Readonly<Record<string, TopicAttentionSignals>>;
|
|
72
|
+
export interface RankedTopicIndexEntry {
|
|
73
|
+
readonly entry: TopicIndexEntry;
|
|
74
|
+
readonly reason: TopicIndexRankReason;
|
|
75
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const TOPIC_INDEX_COMPLETENESS = [
|
|
2
|
+
"complete",
|
|
3
|
+
"partial-history",
|
|
4
|
+
"metadata-pending",
|
|
5
|
+
"decryption-pending",
|
|
6
|
+
];
|
|
7
|
+
export const TOPIC_INDEX_UNREAD_STATES = ["unread", "read", "unknown"];
|
|
8
|
+
export const TOPIC_INDEX_STORAGE_STATES = [
|
|
9
|
+
"encrypted",
|
|
10
|
+
"memory-only",
|
|
11
|
+
"locked",
|
|
12
|
+
"unavailable",
|
|
13
|
+
];
|
|
14
|
+
export const TOPIC_NOTIFICATION_MODES = ["follow", "default", "mute"];
|
|
15
|
+
export const TOPIC_INDEX_RANK_REASONS = [
|
|
16
|
+
"pinned",
|
|
17
|
+
"direct-attention",
|
|
18
|
+
"followed-unread",
|
|
19
|
+
"participated",
|
|
20
|
+
"recent",
|
|
21
|
+
];
|
|
22
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/indexing/types.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,UAAU;IACV,iBAAiB;IACjB,kBAAkB;IAClB,oBAAoB;CACZ,CAAC;AACX,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAChF,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW;IACX,aAAa;IACb,QAAQ;IACR,aAAa;CACL,CAAC;AACX,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,QAAQ;IACR,kBAAkB;IAClB,iBAAiB;IACjB,cAAc;IACd,QAAQ;CACA,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type MatrixAnchor, type TopicOperation, type TopicRoot } from "../projector/types.js";
|
|
2
2
|
import { MATRIX_ROOM_MESSAGE, TOPIC_OPERATION_EVENT_TYPE, type MatrixEventContent, type TopicRootContentOptions } from "./types.js";
|
|
3
3
|
export declare function createTopicId(): string;
|
|
4
4
|
export declare function createTopicOperationId(): string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { v7 as uuidv7 } from "uuid";
|
|
2
2
|
import { assertContract } from "../contracts/validator.js";
|
|
3
3
|
import { TopicProtocolError } from "../errors.js";
|
|
4
|
+
import { parsePayload } from "../projector/payload.js";
|
|
5
|
+
import { isCanonicalTopicContextType, } from "../projector/types.js";
|
|
4
6
|
import { MATRIX_ROOM_MESSAGE, TOPIC_ANCHOR_KEY, TOPIC_METADATA_KEY, TOPIC_OPERATION_EVENT_TYPE, } from "./types.js";
|
|
5
7
|
export function createTopicId() {
|
|
6
8
|
return `ixo:topic:${uuidv7()}`;
|
|
@@ -29,6 +31,11 @@ export function assertTopicMessageContent(message) {
|
|
|
29
31
|
}
|
|
30
32
|
export function buildTopicRootContent(root, options = {}) {
|
|
31
33
|
assertContract("topic-root", root);
|
|
34
|
+
for (const context of root.context ?? []) {
|
|
35
|
+
if (isCanonicalTopicContextType(context.type))
|
|
36
|
+
continue;
|
|
37
|
+
throw new TopicProtocolError("INVALID_CONTEXT_TYPE", "New Topic roots require core or dotted vendor context types", { type: context.type });
|
|
38
|
+
}
|
|
32
39
|
if (options.replaces !== undefined)
|
|
33
40
|
assertMatrixAnchor(options.replaces);
|
|
34
41
|
return {
|
|
@@ -55,6 +62,7 @@ export function buildTopicMessageContent(anchor, message) {
|
|
|
55
62
|
export function buildTopicOperationContent(anchor, operation) {
|
|
56
63
|
assertMatrixAnchor(anchor);
|
|
57
64
|
assertContract("topic-operation", operation);
|
|
65
|
+
parsePayload(operation);
|
|
58
66
|
return {
|
|
59
67
|
operation,
|
|
60
68
|
"m.relates_to": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/matrix/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../../src/matrix/content.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type TopicContext, type TopicOperation, type TopicOverview, type TopicStatus } from "./types.js";
|
|
1
|
+
import { type TopicContext, type TopicFileAttachmentIdentity, type TopicOperation, type TopicOverview, type TopicStatus, type TopicVfsFileReference } from "./types.js";
|
|
2
2
|
interface DecisionPayload {
|
|
3
3
|
readonly id: string;
|
|
4
4
|
readonly summary: string;
|
|
@@ -16,6 +16,12 @@ export type ParsedPayload = {
|
|
|
16
16
|
} | {
|
|
17
17
|
readonly kind: "link-context" | "unlink-context";
|
|
18
18
|
readonly context: TopicContext;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: "attach-files";
|
|
21
|
+
readonly files: readonly TopicVfsFileReference[];
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "detach-files";
|
|
24
|
+
readonly files: readonly TopicFileAttachmentIdentity[];
|
|
19
25
|
} | {
|
|
20
26
|
readonly kind: "record-decision";
|
|
21
27
|
readonly decision: DecisionPayload;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TopicProtocolError } from "../errors.js";
|
|
2
2
|
import { isJsonDateTime } from "../contracts/validator.js";
|
|
3
|
-
import { TOPIC_STATUSES, } from "./types.js";
|
|
3
|
+
import { isCanonicalTopicContextType, TOPIC_STATUSES, TOPIC_VFS_FILE_PROVIDER, } from "./types.js";
|
|
4
4
|
function invalid(operation, message) {
|
|
5
5
|
throw new TopicProtocolError("INVALID_OPERATION_PAYLOAD", `${operation.type} ${operation.operationId}: ${message}`, { operationId: operation.operationId, operationType: operation.type });
|
|
6
6
|
}
|
|
@@ -11,6 +11,13 @@ function recordValue(operation, key) {
|
|
|
11
11
|
}
|
|
12
12
|
return value;
|
|
13
13
|
}
|
|
14
|
+
function arrayValue(operation, key) {
|
|
15
|
+
const value = operation.payload[key];
|
|
16
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
17
|
+
return invalid(operation, `${key} must be a non-empty array`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
14
21
|
function stringValue(operation, source, key) {
|
|
15
22
|
const value = source[key];
|
|
16
23
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
@@ -32,11 +39,84 @@ function topicIdValue(operation, key) {
|
|
|
32
39
|
}
|
|
33
40
|
function contextValue(operation) {
|
|
34
41
|
const context = recordValue(operation, "context");
|
|
42
|
+
const type = stringValue(operation, context, "type");
|
|
43
|
+
if (!isCanonicalTopicContextType(type)) {
|
|
44
|
+
return invalid(operation, "context.type must be a core or dotted vendor namespace");
|
|
45
|
+
}
|
|
35
46
|
return {
|
|
36
|
-
type
|
|
47
|
+
type,
|
|
37
48
|
id: stringValue(operation, context, "id"),
|
|
38
49
|
};
|
|
39
50
|
}
|
|
51
|
+
function positiveIntegerValue(operation, source, key) {
|
|
52
|
+
const value = source[key];
|
|
53
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
54
|
+
return invalid(operation, `${key} must be a positive integer`);
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
function nonNegativeIntegerValue(operation, source, key) {
|
|
59
|
+
const value = source[key];
|
|
60
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
61
|
+
return invalid(operation, `${key} must be a non-negative integer`);
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
function attachmentIdentityValue(operation, value) {
|
|
66
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
67
|
+
return invalid(operation, "files entries must be objects");
|
|
68
|
+
}
|
|
69
|
+
const source = value;
|
|
70
|
+
const provider = stringValue(operation, source, "provider");
|
|
71
|
+
if (provider !== TOPIC_VFS_FILE_PROVIDER)
|
|
72
|
+
return invalid(operation, "provider must be ixo.vfs");
|
|
73
|
+
return {
|
|
74
|
+
provider: TOPIC_VFS_FILE_PROVIDER,
|
|
75
|
+
resource: stringValue(operation, source, "resource"),
|
|
76
|
+
fileId: stringValue(operation, source, "fileId"),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function attachmentValue(operation, value) {
|
|
80
|
+
const identity = attachmentIdentityValue(operation, value);
|
|
81
|
+
const source = value;
|
|
82
|
+
const contentHash = stringValue(operation, source, "contentHash");
|
|
83
|
+
if (!/^[0-9a-f]{64}$/u.test(contentHash)) {
|
|
84
|
+
return invalid(operation, "contentHash must be a lowercase SHA-256 digest");
|
|
85
|
+
}
|
|
86
|
+
const path = stringValue(operation, source, "path");
|
|
87
|
+
if (!path.startsWith("/") || path.split("/").includes("..")) {
|
|
88
|
+
return invalid(operation, "path must be an absolute VFS path without traversal");
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
...identity,
|
|
92
|
+
version: positiveIntegerValue(operation, source, "version"),
|
|
93
|
+
cid: stringValue(operation, source, "cid"),
|
|
94
|
+
contentHash,
|
|
95
|
+
path,
|
|
96
|
+
name: stringValue(operation, source, "name"),
|
|
97
|
+
mimeType: stringValue(operation, source, "mimeType"),
|
|
98
|
+
size: nonNegativeIntegerValue(operation, source, "size"),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function attachmentKey(identity) {
|
|
102
|
+
return `${identity.provider}\u0000${identity.resource}\u0000${identity.fileId}`;
|
|
103
|
+
}
|
|
104
|
+
function uniqueFiles(operation, files) {
|
|
105
|
+
const keys = new Set();
|
|
106
|
+
for (const file of files) {
|
|
107
|
+
const key = attachmentKey(file);
|
|
108
|
+
if (keys.has(key))
|
|
109
|
+
return invalid(operation, "files must not contain duplicate VFS identities");
|
|
110
|
+
keys.add(key);
|
|
111
|
+
}
|
|
112
|
+
return files;
|
|
113
|
+
}
|
|
114
|
+
function attachmentsValue(operation) {
|
|
115
|
+
return uniqueFiles(operation, arrayValue(operation, "files").map((value) => attachmentValue(operation, value)));
|
|
116
|
+
}
|
|
117
|
+
function attachmentIdentitiesValue(operation) {
|
|
118
|
+
return uniqueFiles(operation, arrayValue(operation, "files").map((value) => attachmentIdentityValue(operation, value)));
|
|
119
|
+
}
|
|
40
120
|
function decisionValue(operation) {
|
|
41
121
|
const decision = recordValue(operation, "decision");
|
|
42
122
|
return {
|
|
@@ -112,6 +192,10 @@ export function parsePayload(operation) {
|
|
|
112
192
|
case "link-context":
|
|
113
193
|
case "unlink-context":
|
|
114
194
|
return { kind: operation.type, context: contextValue(operation) };
|
|
195
|
+
case "attach-files":
|
|
196
|
+
return { kind: operation.type, files: attachmentsValue(operation) };
|
|
197
|
+
case "detach-files":
|
|
198
|
+
return { kind: operation.type, files: attachmentIdentitiesValue(operation) };
|
|
115
199
|
case "record-decision":
|
|
116
200
|
return { kind: operation.type, decision: decisionValue(operation) };
|
|
117
201
|
case "redirect":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload.js","sourceRoot":"","sources":["../../../src/projector/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACL,cAAc,
|
|
1
|
+
{"version":3,"file":"payload.js","sourceRoot":"","sources":["../../../src/projector/payload.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ export function initialState(root, anchor) {
|
|
|
9
9
|
title: root.title,
|
|
10
10
|
status: root.status,
|
|
11
11
|
context: uniqueContexts(root.context ?? []),
|
|
12
|
+
attachments: [],
|
|
12
13
|
decisions: [],
|
|
13
14
|
...(root.overview === undefined
|
|
14
15
|
? {}
|
|
@@ -50,6 +51,45 @@ function applyContext(state, payload) {
|
|
|
50
51
|
context: payload.kind === "link-context" ? uniqueContexts([...contexts, payload.context]) : contexts,
|
|
51
52
|
};
|
|
52
53
|
}
|
|
54
|
+
function attachmentKey(attachment) {
|
|
55
|
+
return `${attachment.provider}\u0000${attachment.resource}\u0000${attachment.fileId}`;
|
|
56
|
+
}
|
|
57
|
+
function sameReference(attachment, reference) {
|
|
58
|
+
return attachment.resource === reference.resource
|
|
59
|
+
&& attachment.fileId === reference.fileId
|
|
60
|
+
&& attachment.version === reference.version
|
|
61
|
+
&& attachment.cid === reference.cid
|
|
62
|
+
&& attachment.contentHash === reference.contentHash
|
|
63
|
+
&& attachment.path === reference.path
|
|
64
|
+
&& attachment.name === reference.name
|
|
65
|
+
&& attachment.mimeType === reference.mimeType
|
|
66
|
+
&& attachment.size === reference.size;
|
|
67
|
+
}
|
|
68
|
+
function sortedAttachments(attachments) {
|
|
69
|
+
return [...attachments].sort((left, right) => compareText(attachmentKey(left), attachmentKey(right)));
|
|
70
|
+
}
|
|
71
|
+
function applyAttachments(state, operation) {
|
|
72
|
+
const payload = operation.parsedPayload;
|
|
73
|
+
if (payload.kind === "detach-files") {
|
|
74
|
+
const removed = new Set(payload.files.map(attachmentKey));
|
|
75
|
+
return { ...state, attachments: state.attachments.filter((attachment) => !removed.has(attachmentKey(attachment))) };
|
|
76
|
+
}
|
|
77
|
+
if (payload.kind !== "attach-files")
|
|
78
|
+
return state;
|
|
79
|
+
const attachments = new Map(state.attachments.map((attachment) => [attachmentKey(attachment), attachment]));
|
|
80
|
+
for (const file of payload.files) {
|
|
81
|
+
const existing = attachments.get(attachmentKey(file));
|
|
82
|
+
if (existing !== undefined && sameReference(existing, file))
|
|
83
|
+
continue;
|
|
84
|
+
attachments.set(attachmentKey(file), {
|
|
85
|
+
...file,
|
|
86
|
+
attachedBy: operation.actor,
|
|
87
|
+
attachedAt: operation.createdAt,
|
|
88
|
+
operationId: operation.operationId,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { ...state, attachments: sortedAttachments([...attachments.values()]) };
|
|
92
|
+
}
|
|
53
93
|
function applyDecision(state, operation) {
|
|
54
94
|
const payload = operation.parsedPayload;
|
|
55
95
|
if (payload.kind !== "record-decision")
|
|
@@ -96,6 +136,7 @@ export function applyOperation(state, operation) {
|
|
|
96
136
|
updated = { ...updated, status: payload.status };
|
|
97
137
|
updated = applyOverview(updated, operation);
|
|
98
138
|
updated = applyContext(updated, payload);
|
|
139
|
+
updated = applyAttachments(updated, operation);
|
|
99
140
|
updated = applyDecision(updated, operation);
|
|
100
141
|
updated = applyGraphRelation(updated, operation);
|
|
101
142
|
updated = applyRedirect(updated, operation);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/projector/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/projector/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAuBnD,MAAM,UAAU,YAAY,CAAC,IAAe,EAAE,MAAoB;IAChE,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,MAAM,CAAC,WAAW;QAC5B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QAC3C,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,EAAE;QACb,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS;YAC7B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QAC7F,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;KACd,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAsB,EAAE,SAA4B;IACzE,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,QAAQ,GAAG;QACf,GAAG,OAAO,CAAC,QAAQ;QACnB,SAAS,EAAE,SAAS,CAAC,KAAK;QAC1B,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,WAAW,EAAE,SAAS,CAAC,WAAW;KACnC,CAAC;IACF,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;AACrG,CAAC;AAED,SAAS,UAAU,CAAC,OAAqB;IACvC,OAAO,GAAG,OAAO,CAAC,IAAI,SAAS,OAAO,CAAC,EAAE,EAAE,CAAC;AAC9C,CAAC;AAED,SAAS,cAAc,CAAC,QAAiC;IACvD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IACzF,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAC/C,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CACjD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,KAAsB,EACtB,SAA4B,EAC5B,IAAoC,EACpC,aAAqB;IAErB,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;IAC7E,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,SAAS,YAAY,CAAC,KAAsB,EAAE,OAAsB;IAClE,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAC;IACvF,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;IAChF,OAAO;QACL,GAAG,KAAK;QACR,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,GAAG,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ;KACrG,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,UAAuC;IAC5D,OAAO,GAAG,UAAU,CAAC,QAAQ,SAAS,UAAU,CAAC,QAAQ,SAAS,UAAU,CAAC,MAAM,EAAE,CAAC;AACxF,CAAC;AAED,SAAS,aAAa,CACpB,UAAoC,EACpC,SAAgC;IAEhC,OAAO,UAAU,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ;WAC5C,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;WACtC,UAAU,CAAC,OAAO,KAAK,SAAS,CAAC,OAAO;WACxC,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,GAAG;WAChC,UAAU,CAAC,WAAW,KAAK,SAAS,CAAC,WAAW;WAChD,UAAU,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI;WAClC,UAAU,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI;WAClC,UAAU,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ;WAC1C,UAAU,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC;AAC1C,CAAC;AAED,SAAS,iBAAiB,CAAC,WAAgD;IACzE,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxG,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAsB,EAAE,SAA4B;IAC5E,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1D,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACtH,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5G,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QACtD,IAAI,QAAQ,KAAK,SAAS,IAAI,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC;YAAE,SAAS;QACtE,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;YACnC,GAAG,IAAI;YACP,UAAU,EAAE,SAAS,CAAC,KAAK;YAC3B,UAAU,EAAE,SAAS,CAAC,SAAS;YAC/B,WAAW,EAAE,SAAS,CAAC,WAAW;SACnC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,SAAS,aAAa,CAAC,KAAsB,EAAE,SAA4B;IACzE,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3F,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;IAC7E,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC,GAAG,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,aAAa,CAAC,KAAsB,EAAE,SAA4B;IACzE,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACzF,OAAO,EAAE,GAAG,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC;AACpF,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAsB,EAAE,SAA4B;IAC9E,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC7B,OAAO,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,KAAsB,EAAE,OAAsB;IACrE,IAAI,OAAO,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CACnC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,gBAAgB,KAAK,OAAO,CAAC,gBAAgB,CACvE,CAAC;IACF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,kBAAkB,CAAC,kBAAkB,EAAE,qBAAqB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACpG,CAAC;IACD,IAAI,QAAQ,CAAC,oBAAoB,KAAK,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAClE,MAAM,IAAI,kBAAkB,CAC1B,kCAAkC,EAClC,uEAAuE,EACvE,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CACrD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,QAAQ,CAAC,EAAE,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAAsB,EACtB,SAA4B;IAE5B,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9E,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe;QAAE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IACvF,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5C,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/C,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5C,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACjD,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5C,OAAO,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;AACzD,CAAC"}
|
|
@@ -1,12 +1,42 @@
|
|
|
1
1
|
export declare const TOPIC_STATUSES: readonly ["draft", "active", "waiting", "blocked", "resolved", "archived", "redirected"];
|
|
2
2
|
export declare const TOPIC_KINDS: readonly ["discussion", "question", "decision", "proposal", "task", "incident", "flow"];
|
|
3
|
+
export declare const TOPIC_CONTEXT_TYPES: readonly ["ixo.flow", "ixo.resource", "ixo.service", "ixo.authority", "ixo.domain", "ixo.account", "ixo.entity"];
|
|
4
|
+
export declare const TOPIC_VFS_FILE_PROVIDER = "ixo.vfs";
|
|
3
5
|
export type TopicStatus = (typeof TOPIC_STATUSES)[number];
|
|
4
6
|
export type TopicKind = (typeof TOPIC_KINDS)[number];
|
|
5
|
-
export type
|
|
7
|
+
export type TopicContextType = (typeof TOPIC_CONTEXT_TYPES)[number];
|
|
8
|
+
export type TopicOperationType = "rename" | "change-status" | "update-overview" | "link-context" | "unlink-context" | "attach-files" | "detach-files" | "record-decision" | "redirect" | "branch" | "merge" | "resolve-conflict";
|
|
6
9
|
export interface TopicContext {
|
|
7
10
|
readonly type: string;
|
|
8
11
|
readonly id: string;
|
|
9
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns whether a context type uses the Topic Protocol's current writer
|
|
15
|
+
* vocabulary. Readers intentionally retain support for legacy free-form types.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isCanonicalTopicContextType(value: string): boolean;
|
|
18
|
+
export interface TopicVfsFileReference {
|
|
19
|
+
readonly provider: typeof TOPIC_VFS_FILE_PROVIDER;
|
|
20
|
+
readonly resource: string;
|
|
21
|
+
readonly fileId: string;
|
|
22
|
+
readonly version: number;
|
|
23
|
+
readonly cid: string;
|
|
24
|
+
readonly contentHash: string;
|
|
25
|
+
readonly path: string;
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly mimeType: string;
|
|
28
|
+
readonly size: number;
|
|
29
|
+
}
|
|
30
|
+
export interface TopicFileAttachmentIdentity {
|
|
31
|
+
readonly provider: typeof TOPIC_VFS_FILE_PROVIDER;
|
|
32
|
+
readonly resource: string;
|
|
33
|
+
readonly fileId: string;
|
|
34
|
+
}
|
|
35
|
+
export interface ProjectedTopicAttachment extends TopicVfsFileReference {
|
|
36
|
+
readonly attachedBy: string;
|
|
37
|
+
readonly attachedAt: string;
|
|
38
|
+
readonly operationId: string;
|
|
39
|
+
}
|
|
10
40
|
export interface TopicNextStep {
|
|
11
41
|
readonly summary: string;
|
|
12
42
|
readonly assignee?: string;
|
|
@@ -76,6 +106,7 @@ export interface TopicProjection {
|
|
|
76
106
|
readonly title: string;
|
|
77
107
|
readonly status: TopicStatus;
|
|
78
108
|
readonly context: readonly TopicContext[];
|
|
109
|
+
readonly attachments: readonly ProjectedTopicAttachment[];
|
|
79
110
|
readonly decisions: readonly TopicDecision[];
|
|
80
111
|
readonly overview?: ProjectedTopicOverview;
|
|
81
112
|
readonly relations: readonly ProjectedTopicRelation[];
|
|
@@ -16,4 +16,22 @@ export const TOPIC_KINDS = [
|
|
|
16
16
|
"incident",
|
|
17
17
|
"flow",
|
|
18
18
|
];
|
|
19
|
+
export const TOPIC_CONTEXT_TYPES = [
|
|
20
|
+
"ixo.flow",
|
|
21
|
+
"ixo.resource",
|
|
22
|
+
"ixo.service",
|
|
23
|
+
"ixo.authority",
|
|
24
|
+
"ixo.domain",
|
|
25
|
+
"ixo.account",
|
|
26
|
+
"ixo.entity",
|
|
27
|
+
];
|
|
28
|
+
export const TOPIC_VFS_FILE_PROVIDER = "ixo.vfs";
|
|
29
|
+
/**
|
|
30
|
+
* Returns whether a context type uses the Topic Protocol's current writer
|
|
31
|
+
* vocabulary. Readers intentionally retain support for legacy free-form types.
|
|
32
|
+
*/
|
|
33
|
+
export function isCanonicalTopicContextType(value) {
|
|
34
|
+
return TOPIC_CONTEXT_TYPES.includes(value)
|
|
35
|
+
|| /^(?!ixo\.)[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/u.test(value);
|
|
36
|
+
}
|
|
19
37
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/projector/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,OAAO;IACP,QAAQ;IACR,SAAS;IACT,SAAS;IACT,UAAU;IACV,UAAU;IACV,YAAY;CACJ,CAAC;AACX,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,YAAY;IACZ,UAAU;IACV,UAAU;IACV,UAAU;IACV,MAAM;IACN,UAAU;IACV,MAAM;CACE,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/projector/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,OAAO;IACP,QAAQ;IACR,SAAS;IACT,SAAS;IACT,UAAU;IACV,UAAU;IACV,YAAY;CACJ,CAAC;AACX,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,YAAY;IACZ,UAAU;IACV,UAAU;IACV,UAAU;IACV,MAAM;IACN,UAAU;IACV,MAAM;CACE,CAAC;AACX,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,UAAU;IACV,cAAc;IACd,aAAa;IACb,eAAe;IACf,YAAY;IACZ,aAAa;IACb,YAAY;CACJ,CAAC;AACX,MAAM,CAAC,MAAM,uBAAuB,GAAG,SAAS,CAAC;AAwBjD;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,KAAa;IACvD,OAAO,mBAAmB,CAAC,QAAQ,CAAC,KAAyB,CAAC;WACzD,mDAAmD,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC"}
|