@palantir/pack.state.foundry 0.0.1-beta.1 → 0.0.2

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.
@@ -0,0 +1,168 @@
1
+ /*
2
+ * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import type {
18
+ ActivityCollaborativeUpdate,
19
+ ActivityEvent as FoundryActivityEvent,
20
+ } from "@osdk/foundry.pack";
21
+ import { invalidUserRef } from "@palantir/pack.auth";
22
+ import type {
23
+ ActivityEvent,
24
+ ActivityEventData,
25
+ DocumentSchema,
26
+ Model,
27
+ ModelData,
28
+ PresenceEvent,
29
+ PresenceEventData,
30
+ PresenceEventDataArrived,
31
+ PresenceEventDataDeparted,
32
+ UserId,
33
+ } from "@palantir/pack.document-schema.model-types";
34
+ import {
35
+ ActivityEventDataType,
36
+ PresenceEventDataType,
37
+ } from "@palantir/pack.document-schema.model-types";
38
+ import type { PresenceCollaborativeUpdate } from "@palantir/pack.state.foundry-event";
39
+
40
+ export function getActivityEvent(
41
+ documentSchema: DocumentSchema,
42
+ foundryEvent: ActivityCollaborativeUpdate,
43
+ ): ActivityEvent | undefined {
44
+ // TODO: need to handle deletes and ensure exhaustive handling
45
+ if (foundryEvent.type !== "activityCreated") {
46
+ return undefined;
47
+ }
48
+ const { activityEvent } = foundryEvent;
49
+ const eventData = getActivityEventData(documentSchema, activityEvent);
50
+
51
+ return {
52
+ aggregationKey: activityEvent.aggregationKey,
53
+ createdBy: activityEvent.createdBy as UserId,
54
+ createdInstant: new Date(activityEvent.createdTime).getTime(),
55
+ eventData,
56
+ eventId: activityEvent.eventId,
57
+ isRead: activityEvent.isRead,
58
+ };
59
+ }
60
+
61
+ function getActivityEventData(
62
+ docSchema: DocumentSchema,
63
+ { eventData, eventType }: FoundryActivityEvent,
64
+ ): ActivityEventData {
65
+ // TODO: handle standard activity events
66
+ // TODO: validate model is valid for activity events
67
+ const model = docSchema[eventType];
68
+ if (model == null) {
69
+ return {
70
+ rawData: eventData.data,
71
+ rawType: eventType,
72
+ type: ActivityEventDataType.UNKNOWN,
73
+ };
74
+ }
75
+
76
+ // TODO: validate data against model schema
77
+
78
+ return {
79
+ eventData: eventData.data as ModelData<Model>,
80
+ model,
81
+ type: ActivityEventDataType.CUSTOM_EVENT,
82
+ };
83
+ }
84
+
85
+ const ARRIVED_DATA: PresenceEventDataArrived = {
86
+ type: PresenceEventDataType.ARRIVED,
87
+ } as const;
88
+
89
+ const DEPARTED_DATA: PresenceEventDataDeparted = {
90
+ type: PresenceEventDataType.DEPARTED,
91
+ } as const;
92
+
93
+ export function getPresenceEvent(
94
+ documentSchema: DocumentSchema,
95
+ foundryUpdate: PresenceCollaborativeUpdate,
96
+ ): PresenceEvent {
97
+ switch (foundryUpdate.type) {
98
+ case "presenceChangeEvent": {
99
+ const { userId, status } = foundryUpdate.presenceChangeEvent;
100
+ const eventData = status === "PRESENT" ? ARRIVED_DATA : DEPARTED_DATA;
101
+ return {
102
+ eventData,
103
+ userId: userId as UserId,
104
+ };
105
+ }
106
+
107
+ case "customPresenceEvent": {
108
+ const { userId, eventData } = foundryUpdate.customPresenceEvent;
109
+ const presenceEventData = getPresenceEventData(documentSchema, eventData);
110
+ return {
111
+ eventData: presenceEventData,
112
+ userId: userId as UserId,
113
+ };
114
+ }
115
+ default: {
116
+ foundryUpdate satisfies never;
117
+ const unknownUpdate = foundryUpdate as Record<string, unknown>;
118
+ return {
119
+ eventData: {
120
+ rawData: foundryUpdate,
121
+ rawType: typeof unknownUpdate.type === "string" ? unknownUpdate.type : "unknown",
122
+ type: PresenceEventDataType.UNKNOWN,
123
+ },
124
+ // FIXME: try and pull userId from message? Or just fix the platform types to have useful wrappers.
125
+ userId: invalidUserRef().userId,
126
+ };
127
+ }
128
+ }
129
+ }
130
+
131
+ function getPresenceEventData(
132
+ docSchema: DocumentSchema,
133
+ eventData: unknown,
134
+ ): PresenceEventData {
135
+ if (typeof eventData !== "object" || eventData == null) {
136
+ return {
137
+ rawData: eventData,
138
+ rawType: "unknown",
139
+ type: PresenceEventDataType.UNKNOWN,
140
+ };
141
+ }
142
+
143
+ const typedEventData = eventData as Record<string, unknown>;
144
+ const { eventType, eventData: data } = typedEventData;
145
+
146
+ if (typeof eventType !== "string") {
147
+ return {
148
+ rawData: eventData,
149
+ rawType: "unknown",
150
+ type: PresenceEventDataType.UNKNOWN,
151
+ };
152
+ }
153
+
154
+ const model = docSchema[eventType];
155
+ if (model == null) {
156
+ return {
157
+ rawData: data,
158
+ rawType: eventType,
159
+ type: PresenceEventDataType.UNKNOWN,
160
+ };
161
+ }
162
+
163
+ return {
164
+ eventData: data,
165
+ model,
166
+ type: PresenceEventDataType.CUSTOM_EVENT,
167
+ };
168
+ }