@automate.ax/integration-contracts 0.124.0 → 0.126.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/apify/index.d.ts +1085 -0
- package/dist/apify/index.js +169 -0
- package/dist/apify/schemas.d.ts +100 -0
- package/dist/apify/schemas.js +203 -0
- package/dist/linear/schemas.d.ts +8 -8
- package/dist/notion/schemas.d.ts +33 -33
- package/dist/reddit/api.d.ts +56 -0
- package/dist/reddit/api.js +135 -0
- package/dist/reddit/events.d.ts +439 -0
- package/dist/reddit/events.js +53 -0
- package/dist/reddit/index.d.ts +3 -0
- package/dist/reddit/index.js +3 -0
- package/dist/reddit/schemas.d.ts +816 -0
- package/dist/reddit/schemas.js +398 -0
- package/dist/triggers.d.ts +3 -1
- package/dist/vercel/index.d.ts +16 -16
- package/dist/vercel/schemas.d.ts +24 -24
- package/package.json +14 -2
- package/src/apify/index.ts +210 -0
- package/src/apify/schemas.ts +214 -0
- package/src/reddit/api.ts +183 -0
- package/src/reddit/events.ts +68 -0
- package/src/reddit/index.ts +3 -0
- package/src/reddit/schemas.ts +442 -0
- package/src/triggers.ts +4 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
|
|
3
|
+
export const APIFY_JOB_STATUS_SCHEMA = z.enum([
|
|
4
|
+
"READY",
|
|
5
|
+
"RUNNING",
|
|
6
|
+
"SUCCEEDED",
|
|
7
|
+
"FAILED",
|
|
8
|
+
"TIMING-OUT",
|
|
9
|
+
"TIMED-OUT",
|
|
10
|
+
"ABORTING",
|
|
11
|
+
"ABORTED",
|
|
12
|
+
])
|
|
13
|
+
|
|
14
|
+
const APIFY_DATE_SCHEMA = z.union([z.date(), z.iso.datetime()])
|
|
15
|
+
const APIFY_RUN_META_SCHEMA = z.looseObject({
|
|
16
|
+
origin: z.string(),
|
|
17
|
+
scheduleId: z.string().nullable().optional(),
|
|
18
|
+
scheduledAt: APIFY_DATE_SCHEMA.nullable().optional(),
|
|
19
|
+
})
|
|
20
|
+
const APIFY_RUN_OPTIONS_SCHEMA = z.looseObject({
|
|
21
|
+
build: z.string(),
|
|
22
|
+
diskMbytes: z.number().int().nonnegative(),
|
|
23
|
+
maxItems: z.number().int().nonnegative().nullable().optional(),
|
|
24
|
+
maxTotalChargeUsd: z.number().nonnegative().nullable().optional(),
|
|
25
|
+
memoryMbytes: z.number().int().min(128).max(32_768),
|
|
26
|
+
timeoutSecs: z.number().int().nonnegative(),
|
|
27
|
+
})
|
|
28
|
+
const APIFY_RUN_STATS_SCHEMA = z.looseObject({
|
|
29
|
+
computeUnits: z.number().nonnegative().optional(),
|
|
30
|
+
durationMillis: z.number().int().nonnegative().optional(),
|
|
31
|
+
runTimeSecs: z.number().nonnegative().optional(),
|
|
32
|
+
})
|
|
33
|
+
const APIFY_BUILD_META_SCHEMA = z.looseObject({ origin: z.string() })
|
|
34
|
+
const APIFY_BUILD_OPTIONS_SCHEMA = z.looseObject({
|
|
35
|
+
betaPackages: z.boolean().optional(),
|
|
36
|
+
diskMbytes: z.number().int().nonnegative().optional(),
|
|
37
|
+
memoryMbytes: z.number().int().min(128).max(32_768).optional(),
|
|
38
|
+
useCache: z.boolean().optional(),
|
|
39
|
+
})
|
|
40
|
+
const APIFY_BUILD_STATS_SCHEMA = z.looseObject({
|
|
41
|
+
computeUnits: z.number().nonnegative(),
|
|
42
|
+
durationMillis: z.number().int().nonnegative(),
|
|
43
|
+
runTimeSecs: z.number().nonnegative(),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const APIFY_RUN_WIRE_SCHEMA = z.looseObject({
|
|
47
|
+
actId: z.string(),
|
|
48
|
+
actorTaskId: z.string().nullable().optional(),
|
|
49
|
+
buildId: z.string(),
|
|
50
|
+
buildNumber: z.string().nullable().optional(),
|
|
51
|
+
defaultDatasetId: z.string(),
|
|
52
|
+
defaultKeyValueStoreId: z.string(),
|
|
53
|
+
defaultRequestQueueId: z.string(),
|
|
54
|
+
exitCode: z.number().int().nullable().optional(),
|
|
55
|
+
finishedAt: APIFY_DATE_SCHEMA.nullable().optional(),
|
|
56
|
+
id: z.string(),
|
|
57
|
+
meta: APIFY_RUN_META_SCHEMA,
|
|
58
|
+
options: APIFY_RUN_OPTIONS_SCHEMA.optional(),
|
|
59
|
+
startedAt: APIFY_DATE_SCHEMA,
|
|
60
|
+
stats: APIFY_RUN_STATS_SCHEMA.optional(),
|
|
61
|
+
status: APIFY_JOB_STATUS_SCHEMA,
|
|
62
|
+
statusMessage: z.string().nullable().optional(),
|
|
63
|
+
usageTotalUsd: z.number().nonnegative().nullable().optional(),
|
|
64
|
+
userId: z.string().optional(),
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const APIFY_BUILD_WIRE_SCHEMA = z.looseObject({
|
|
68
|
+
actId: z.string(),
|
|
69
|
+
buildNumber: z.string(),
|
|
70
|
+
finishedAt: APIFY_DATE_SCHEMA.nullable().optional(),
|
|
71
|
+
id: z.string(),
|
|
72
|
+
meta: APIFY_BUILD_META_SCHEMA.optional(),
|
|
73
|
+
options: APIFY_BUILD_OPTIONS_SCHEMA.nullable().optional(),
|
|
74
|
+
startedAt: APIFY_DATE_SCHEMA,
|
|
75
|
+
stats: APIFY_BUILD_STATS_SCHEMA.nullable().optional(),
|
|
76
|
+
status: APIFY_JOB_STATUS_SCHEMA,
|
|
77
|
+
usageTotalUsd: z.number().nonnegative().nullable().optional(),
|
|
78
|
+
userId: z.string().optional(),
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
export const APIFY_RUN_SCHEMA = z.object({
|
|
82
|
+
actorId: z.string(),
|
|
83
|
+
actorTaskId: z.string().nullable().optional(),
|
|
84
|
+
buildId: z.string(),
|
|
85
|
+
buildNumber: z.string().nullable().optional(),
|
|
86
|
+
defaultDatasetId: z.string(),
|
|
87
|
+
defaultKeyValueStoreId: z.string(),
|
|
88
|
+
defaultRequestQueueId: z.string(),
|
|
89
|
+
exitCode: z.number().int().nullable().optional(),
|
|
90
|
+
finishedAt: z.iso.datetime().nullable().optional(),
|
|
91
|
+
id: z.string(),
|
|
92
|
+
meta: z.object({
|
|
93
|
+
origin: z.string(),
|
|
94
|
+
scheduleId: z.string().nullable().optional(),
|
|
95
|
+
scheduledAt: z.iso.datetime().nullable().optional(),
|
|
96
|
+
}),
|
|
97
|
+
options: z
|
|
98
|
+
.object({
|
|
99
|
+
build: z.string(),
|
|
100
|
+
diskMbytes: z.number().int().nonnegative(),
|
|
101
|
+
maxItems: z.number().int().nonnegative().nullable().optional(),
|
|
102
|
+
maxTotalChargeUsd: z.number().nonnegative().nullable().optional(),
|
|
103
|
+
memoryMbytes: z.number().int().min(128).max(32_768),
|
|
104
|
+
timeoutSecs: z.number().int().nonnegative(),
|
|
105
|
+
})
|
|
106
|
+
.optional(),
|
|
107
|
+
startedAt: z.iso.datetime(),
|
|
108
|
+
stats: z
|
|
109
|
+
.object({
|
|
110
|
+
computeUnits: z.number().nonnegative().optional(),
|
|
111
|
+
durationMillis: z.number().int().nonnegative().optional(),
|
|
112
|
+
runTimeSecs: z.number().nonnegative().optional(),
|
|
113
|
+
})
|
|
114
|
+
.optional(),
|
|
115
|
+
status: APIFY_JOB_STATUS_SCHEMA,
|
|
116
|
+
statusMessage: z.string().nullable().optional(),
|
|
117
|
+
usageTotalUsd: z.number().nonnegative().nullable().optional(),
|
|
118
|
+
userId: z.string().optional(),
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
export const APIFY_BUILD_SCHEMA = z.object({
|
|
122
|
+
actorId: z.string(),
|
|
123
|
+
buildNumber: z.string(),
|
|
124
|
+
finishedAt: z.iso.datetime().nullable().optional(),
|
|
125
|
+
id: z.string(),
|
|
126
|
+
meta: z.object({ origin: z.string() }).optional(),
|
|
127
|
+
options: z
|
|
128
|
+
.object({
|
|
129
|
+
betaPackages: z.boolean().optional(),
|
|
130
|
+
diskMbytes: z.number().int().nonnegative().optional(),
|
|
131
|
+
memoryMbytes: z.number().int().min(128).max(32_768).optional(),
|
|
132
|
+
useCache: z.boolean().optional(),
|
|
133
|
+
})
|
|
134
|
+
.nullable()
|
|
135
|
+
.optional(),
|
|
136
|
+
startedAt: z.iso.datetime(),
|
|
137
|
+
stats: z
|
|
138
|
+
.object({
|
|
139
|
+
computeUnits: z.number().nonnegative(),
|
|
140
|
+
durationMillis: z.number().int().nonnegative(),
|
|
141
|
+
runTimeSecs: z.number().nonnegative(),
|
|
142
|
+
})
|
|
143
|
+
.nullable()
|
|
144
|
+
.optional(),
|
|
145
|
+
status: APIFY_JOB_STATUS_SCHEMA,
|
|
146
|
+
usageTotalUsd: z.number().nonnegative().nullable().optional(),
|
|
147
|
+
userId: z.string().optional(),
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Converts an official Apify Actor run into the public camelCase contract.
|
|
152
|
+
*
|
|
153
|
+
* @param value - Official client or webhook run value.
|
|
154
|
+
*/
|
|
155
|
+
export function mapApifyRun(value: unknown): z.output<typeof APIFY_RUN_SCHEMA> {
|
|
156
|
+
const run = APIFY_RUN_WIRE_SCHEMA.parse(value)
|
|
157
|
+
return APIFY_RUN_SCHEMA.parse({
|
|
158
|
+
actorId: run.actId,
|
|
159
|
+
actorTaskId: run.actorTaskId,
|
|
160
|
+
buildId: run.buildId,
|
|
161
|
+
buildNumber: run.buildNumber,
|
|
162
|
+
defaultDatasetId: run.defaultDatasetId,
|
|
163
|
+
defaultKeyValueStoreId: run.defaultKeyValueStoreId,
|
|
164
|
+
defaultRequestQueueId: run.defaultRequestQueueId,
|
|
165
|
+
exitCode: run.exitCode,
|
|
166
|
+
finishedAt: toIsoDate(run.finishedAt),
|
|
167
|
+
id: run.id,
|
|
168
|
+
meta: {
|
|
169
|
+
origin: run.meta.origin,
|
|
170
|
+
scheduleId: run.meta.scheduleId,
|
|
171
|
+
scheduledAt: toIsoDate(run.meta.scheduledAt),
|
|
172
|
+
},
|
|
173
|
+
options: run.options,
|
|
174
|
+
startedAt: toIsoDate(run.startedAt),
|
|
175
|
+
stats: run.stats,
|
|
176
|
+
status: run.status,
|
|
177
|
+
statusMessage: run.statusMessage,
|
|
178
|
+
usageTotalUsd: run.usageTotalUsd,
|
|
179
|
+
userId: run.userId,
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Converts an official Apify Actor build into the public camelCase contract.
|
|
185
|
+
*
|
|
186
|
+
* @param value - Official client or webhook build value.
|
|
187
|
+
*/
|
|
188
|
+
export function mapApifyBuild(
|
|
189
|
+
value: unknown,
|
|
190
|
+
): z.output<typeof APIFY_BUILD_SCHEMA> {
|
|
191
|
+
const build = APIFY_BUILD_WIRE_SCHEMA.parse(value)
|
|
192
|
+
return APIFY_BUILD_SCHEMA.parse({
|
|
193
|
+
actorId: build.actId,
|
|
194
|
+
buildNumber: build.buildNumber,
|
|
195
|
+
finishedAt: toIsoDate(build.finishedAt),
|
|
196
|
+
id: build.id,
|
|
197
|
+
meta: build.meta,
|
|
198
|
+
options: build.options,
|
|
199
|
+
startedAt: toIsoDate(build.startedAt),
|
|
200
|
+
stats: build.stats,
|
|
201
|
+
status: build.status,
|
|
202
|
+
usageTotalUsd: build.usageTotalUsd,
|
|
203
|
+
userId: build.userId,
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Normalizes an optional provider date without changing nullability.
|
|
209
|
+
*
|
|
210
|
+
* @param value - Provider date value.
|
|
211
|
+
*/
|
|
212
|
+
function toIsoDate(value: Date | string | null | undefined) {
|
|
213
|
+
return value instanceof Date ? value.toISOString() : value
|
|
214
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
|
|
3
|
+
const REDDIT_API_ORIGIN = "https://oauth.reddit.com/"
|
|
4
|
+
const REDDIT_API_URL = new URL(REDDIT_API_ORIGIN)
|
|
5
|
+
|
|
6
|
+
export const REDDIT_OAUTH_SECRET_SCHEMA = z.object({
|
|
7
|
+
accessToken: z.string().min(1),
|
|
8
|
+
expiresAt: z.number().int().positive(),
|
|
9
|
+
refreshToken: z.string().min(1),
|
|
10
|
+
tokenType: z.string().min(1),
|
|
11
|
+
userAgent: z.string().min(1),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const REDDIT_API_ERROR_SCHEMA = z.looseObject({
|
|
15
|
+
error: z.number().int().optional(),
|
|
16
|
+
message: z.string().optional(),
|
|
17
|
+
reason: z.string().optional(),
|
|
18
|
+
})
|
|
19
|
+
export const REDDIT_ERROR_TUPLE_SCHEMA = z.tuple([
|
|
20
|
+
z.string(),
|
|
21
|
+
z.string(),
|
|
22
|
+
z.string().nullable(),
|
|
23
|
+
])
|
|
24
|
+
const REDDIT_JSON_ERRORS_SCHEMA = z.looseObject({
|
|
25
|
+
json: z.object({
|
|
26
|
+
errors: REDDIT_ERROR_TUPLE_SCHEMA.array(),
|
|
27
|
+
}),
|
|
28
|
+
})
|
|
29
|
+
export const REDDIT_JSON_STATUS_SCHEMA = z.object({
|
|
30
|
+
json: z.object({ errors: REDDIT_ERROR_TUPLE_SCHEMA.array() }),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export interface RedditRequestOptions<TSchema extends z.ZodType> {
|
|
34
|
+
body?: Record<string, boolean | number | string | undefined>
|
|
35
|
+
method?: "DELETE" | "GET" | "POST" | "PUT"
|
|
36
|
+
query?: Record<
|
|
37
|
+
string,
|
|
38
|
+
boolean | number | string | readonly string[] | null | undefined
|
|
39
|
+
>
|
|
40
|
+
responseSchema: TSchema
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Error returned by a rejected Reddit Data API request. */
|
|
44
|
+
export class RedditApiError extends Error {
|
|
45
|
+
readonly details:
|
|
46
|
+
| { error?: number; message?: string; reason?: string }
|
|
47
|
+
| { errors: [string, string, null | string][] }
|
|
48
|
+
| { response: string }
|
|
49
|
+
readonly retryAfter?: string
|
|
50
|
+
readonly status: number
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates an error from a rejected Reddit response.
|
|
54
|
+
*
|
|
55
|
+
* @param status - HTTP response status.
|
|
56
|
+
* @param details - Parsed Reddit failure details.
|
|
57
|
+
* @param retryAfter - Provider retry delay in seconds, when present.
|
|
58
|
+
*/
|
|
59
|
+
constructor(
|
|
60
|
+
status: number,
|
|
61
|
+
details: RedditApiError["details"],
|
|
62
|
+
retryAfter?: string,
|
|
63
|
+
) {
|
|
64
|
+
const jsonError = "errors" in details ? details.errors[0]?.[1] : undefined
|
|
65
|
+
super(
|
|
66
|
+
("message" in details
|
|
67
|
+
? (details.message ?? details.reason)
|
|
68
|
+
: undefined) ??
|
|
69
|
+
jsonError ??
|
|
70
|
+
`Reddit API request failed (${status}).`,
|
|
71
|
+
)
|
|
72
|
+
this.name = "RedditApiError"
|
|
73
|
+
this.details = details
|
|
74
|
+
this.retryAfter = retryAfter
|
|
75
|
+
this.status = status
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates an authenticated Reddit Data API client.
|
|
81
|
+
*
|
|
82
|
+
* @param secret - Stored Reddit OAuth credentials and registered User-Agent.
|
|
83
|
+
*/
|
|
84
|
+
export function getRedditApi(secret: unknown) {
|
|
85
|
+
const credentials = REDDIT_OAUTH_SECRET_SCHEMA.parse(secret)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
/**
|
|
89
|
+
* Sends one request below Reddit's OAuth API origin.
|
|
90
|
+
*
|
|
91
|
+
* @param path - Relative Reddit API path.
|
|
92
|
+
* @param options - Request method, parameters, and response contract.
|
|
93
|
+
*/
|
|
94
|
+
async request<TSchema extends z.ZodType>(
|
|
95
|
+
path: string,
|
|
96
|
+
options: RedditRequestOptions<TSchema>,
|
|
97
|
+
): Promise<z.output<TSchema>> {
|
|
98
|
+
const normalizedPath = path.replace(/^\/+/, "")
|
|
99
|
+
if (
|
|
100
|
+
!normalizedPath ||
|
|
101
|
+
normalizedPath.includes("://") ||
|
|
102
|
+
normalizedPath.includes("\\")
|
|
103
|
+
) {
|
|
104
|
+
throw new TypeError("Reddit API paths must be relative.")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const url = new URL(normalizedPath, REDDIT_API_ORIGIN)
|
|
108
|
+
if (url.origin !== REDDIT_API_URL.origin) {
|
|
109
|
+
throw new TypeError("Reddit API paths must remain on oauth.reddit.com.")
|
|
110
|
+
}
|
|
111
|
+
url.searchParams.set("raw_json", "1")
|
|
112
|
+
for (const [key, value] of Object.entries(options.query ?? {})) {
|
|
113
|
+
if (value == null) continue
|
|
114
|
+
url.searchParams.set(
|
|
115
|
+
key,
|
|
116
|
+
Array.isArray(value) ? value.join(",") : String(value),
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const headers = new Headers({
|
|
121
|
+
Accept: "application/json",
|
|
122
|
+
Authorization: `${credentials.tokenType} ${credentials.accessToken}`,
|
|
123
|
+
"User-Agent": credentials.userAgent,
|
|
124
|
+
})
|
|
125
|
+
const body = options.body
|
|
126
|
+
? new URLSearchParams(
|
|
127
|
+
Object.entries(options.body).flatMap(([key, value]) =>
|
|
128
|
+
value === undefined
|
|
129
|
+
? []
|
|
130
|
+
: ([[key, String(value)]] satisfies [string, string][]),
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
: undefined
|
|
134
|
+
if (body) {
|
|
135
|
+
headers.set("Content-Type", "application/x-www-form-urlencoded")
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const response = await fetch(url, {
|
|
139
|
+
body,
|
|
140
|
+
headers,
|
|
141
|
+
method: options.method ?? "GET",
|
|
142
|
+
})
|
|
143
|
+
const text = await response.text()
|
|
144
|
+
const parsed = parseJson(text)
|
|
145
|
+
const jsonErrors = REDDIT_JSON_ERRORS_SCHEMA.safeParse(parsed)
|
|
146
|
+
const retryAfter =
|
|
147
|
+
response.headers.get("Retry-After") ??
|
|
148
|
+
response.headers.get("X-Ratelimit-Reset") ??
|
|
149
|
+
undefined
|
|
150
|
+
if (jsonErrors.success && jsonErrors.data.json.errors.length > 0) {
|
|
151
|
+
throw new RedditApiError(
|
|
152
|
+
response.ok ? 400 : response.status,
|
|
153
|
+
{ errors: jsonErrors.data.json.errors },
|
|
154
|
+
retryAfter,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
const error = REDDIT_API_ERROR_SCHEMA.safeParse(parsed)
|
|
159
|
+
throw new RedditApiError(
|
|
160
|
+
response.status,
|
|
161
|
+
error.success ? error.data : { response: text },
|
|
162
|
+
retryAfter,
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
const result = options.responseSchema.safeParse(parsed)
|
|
166
|
+
if (!result.success) {
|
|
167
|
+
throw new RedditApiError(response.status, { response: text })
|
|
168
|
+
}
|
|
169
|
+
return result.data
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Parses a provider body while preserving non-JSON failure text. */
|
|
175
|
+
/** @param value - Raw provider response body. */
|
|
176
|
+
function parseJson(value: string): unknown {
|
|
177
|
+
if (!value) return undefined
|
|
178
|
+
try {
|
|
179
|
+
return JSON.parse(value)
|
|
180
|
+
} catch {
|
|
181
|
+
return value
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import {
|
|
3
|
+
REDDIT_COMMENT_SCHEMA,
|
|
4
|
+
REDDIT_MESSAGE_SCHEMA,
|
|
5
|
+
REDDIT_POST_SCHEMA,
|
|
6
|
+
REDDIT_SUBREDDIT_NAME_SCHEMA,
|
|
7
|
+
} from "./schemas"
|
|
8
|
+
|
|
9
|
+
export const REDDIT_SUBREDDIT_TRIGGER_CONFIG_SCHEMA = z.object({
|
|
10
|
+
subreddit: REDDIT_SUBREDDIT_NAME_SCHEMA,
|
|
11
|
+
})
|
|
12
|
+
export const REDDIT_ACCOUNT_TRIGGER_CONFIG_SCHEMA = z.object({})
|
|
13
|
+
|
|
14
|
+
export const REDDIT_SUBREDDIT_EVENT_SCHEMA = z.discriminatedUnion("action", [
|
|
15
|
+
z.object({
|
|
16
|
+
action: z.literal("commentCreated"),
|
|
17
|
+
comment: REDDIT_COMMENT_SCHEMA,
|
|
18
|
+
}),
|
|
19
|
+
z.object({ action: z.literal("postCreated"), post: REDDIT_POST_SCHEMA }),
|
|
20
|
+
])
|
|
21
|
+
export const REDDIT_INBOX_EVENT_SCHEMA = z.object({
|
|
22
|
+
action: z.literal("inboxItemCreated"),
|
|
23
|
+
message: REDDIT_MESSAGE_SCHEMA,
|
|
24
|
+
})
|
|
25
|
+
export const REDDIT_MOD_QUEUE_EVENT_SCHEMA = z.discriminatedUnion("kind", [
|
|
26
|
+
z.object({ comment: REDDIT_COMMENT_SCHEMA, kind: z.literal("comment") }),
|
|
27
|
+
z.object({ kind: z.literal("post"), post: REDDIT_POST_SCHEMA }),
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
export const redditTriggerContracts = {
|
|
31
|
+
"reddit.inbox.item.received": {
|
|
32
|
+
configSchema: REDDIT_ACCOUNT_TRIGGER_CONFIG_SCHEMA,
|
|
33
|
+
eventSchema: REDDIT_INBOX_EVENT_SCHEMA,
|
|
34
|
+
},
|
|
35
|
+
"reddit.modQueue.item.received": {
|
|
36
|
+
configSchema: REDDIT_SUBREDDIT_TRIGGER_CONFIG_SCHEMA,
|
|
37
|
+
eventSchema: REDDIT_MOD_QUEUE_EVENT_SCHEMA,
|
|
38
|
+
},
|
|
39
|
+
"reddit.subreddit.comment.created": {
|
|
40
|
+
configSchema: REDDIT_SUBREDDIT_TRIGGER_CONFIG_SCHEMA,
|
|
41
|
+
eventSchema: REDDIT_SUBREDDIT_EVENT_SCHEMA.and(
|
|
42
|
+
z.object({ action: z.literal("commentCreated") }),
|
|
43
|
+
),
|
|
44
|
+
},
|
|
45
|
+
"reddit.subreddit.event": {
|
|
46
|
+
configSchema: REDDIT_SUBREDDIT_TRIGGER_CONFIG_SCHEMA,
|
|
47
|
+
eventSchema: REDDIT_SUBREDDIT_EVENT_SCHEMA,
|
|
48
|
+
},
|
|
49
|
+
"reddit.subreddit.post.created": {
|
|
50
|
+
configSchema: REDDIT_SUBREDDIT_TRIGGER_CONFIG_SCHEMA,
|
|
51
|
+
eventSchema: REDDIT_SUBREDDIT_EVENT_SCHEMA.and(
|
|
52
|
+
z.object({ action: z.literal("postCreated") }),
|
|
53
|
+
),
|
|
54
|
+
},
|
|
55
|
+
} as const
|
|
56
|
+
|
|
57
|
+
/** Returns broad and semantic event types for one subreddit observation. */
|
|
58
|
+
/** @param event - Normalized post or comment event. */
|
|
59
|
+
export function getRedditSubredditEventTypes(
|
|
60
|
+
event: z.output<typeof REDDIT_SUBREDDIT_EVENT_SCHEMA>,
|
|
61
|
+
) {
|
|
62
|
+
return [
|
|
63
|
+
event.action === "postCreated"
|
|
64
|
+
? ("reddit.subreddit.post.created" as const)
|
|
65
|
+
: ("reddit.subreddit.comment.created" as const),
|
|
66
|
+
"reddit.subreddit.event" as const,
|
|
67
|
+
]
|
|
68
|
+
}
|