@automate.ax/api-contract 0.7.1 → 0.9.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/deployment.d.ts +0 -1
- package/dist/deployment.js +0 -12
- package/dist/index.d.ts +10 -3
- package/dist/project.d.ts +3 -0
- package/dist/project.js +8 -2
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/package.json +8 -3
- package/src/api-key.ts +84 -0
- package/src/auth.ts +39 -0
- package/src/authorization.ts +151 -0
- package/src/deployment.ts +89 -0
- package/src/events/gmail.ts +34 -0
- package/src/events/google-calendar.ts +18 -0
- package/src/events/google-forms.ts +41 -0
- package/src/events/index.ts +9 -0
- package/src/index.ts +100 -0
- package/src/org.ts +205 -0
- package/src/project.ts +113 -0
- package/src/runtime.ts +113 -0
- package/src/schemas.ts +3 -0
package/dist/deployment.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ export declare const deploymentContract: {
|
|
|
14
14
|
create: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
|
|
15
15
|
artifact: z.ZodCustom<Blob, Blob>;
|
|
16
16
|
manifest: z.ZodArray<z.ZodObject<{
|
|
17
|
-
entrypoint: z.ZodString;
|
|
18
17
|
identityKey: z.ZodString;
|
|
19
18
|
}, z.core.$strip>>;
|
|
20
19
|
mode: z.ZodEnum<{
|
package/dist/deployment.js
CHANGED
|
@@ -18,7 +18,6 @@ export const deploymentContract = {
|
|
|
18
18
|
artifact: z.instanceof(Blob),
|
|
19
19
|
manifest: z
|
|
20
20
|
.object({
|
|
21
|
-
entrypoint: z.string().min(1),
|
|
22
21
|
identityKey: z.string().min(1),
|
|
23
22
|
})
|
|
24
23
|
.array()
|
|
@@ -34,17 +33,6 @@ export const deploymentContract = {
|
|
|
34
33
|
});
|
|
35
34
|
}
|
|
36
35
|
identityKeys.add(entry.identityKey);
|
|
37
|
-
if (entry.entrypoint.includes("\\") ||
|
|
38
|
-
entry.entrypoint.startsWith("/") ||
|
|
39
|
-
entry.entrypoint
|
|
40
|
-
.split("/")
|
|
41
|
-
.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
42
|
-
context.addIssue({
|
|
43
|
-
code: "custom",
|
|
44
|
-
message: "Entrypoint must be a safe relative POSIX path.",
|
|
45
|
-
path: [index, "entrypoint"],
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
36
|
}
|
|
49
37
|
}),
|
|
50
38
|
mode: z.enum(["reconcile", "upsert"]),
|
package/dist/index.d.ts
CHANGED
|
@@ -210,6 +210,9 @@ export declare const publicContract: {
|
|
|
210
210
|
id: import("zod").ZodString;
|
|
211
211
|
name: import("zod").ZodString;
|
|
212
212
|
}, import("zod/v4/core").$strip>;
|
|
213
|
+
activeAutomations: import("zod").ZodArray<import("zod").ZodObject<{
|
|
214
|
+
identityKey: import("zod").ZodString;
|
|
215
|
+
}, import("zod/v4/core").$strip>>;
|
|
213
216
|
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
214
217
|
list: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<import("zod").ZodOptional<import("zod").ZodObject<{
|
|
215
218
|
organizationId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
@@ -344,7 +347,6 @@ export declare const firstPartyContract: {
|
|
|
344
347
|
create: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<import("zod").ZodObject<{
|
|
345
348
|
artifact: import("zod").ZodCustom<Blob, Blob>;
|
|
346
349
|
manifest: import("zod").ZodArray<import("zod").ZodObject<{
|
|
347
|
-
entrypoint: import("zod").ZodString;
|
|
348
350
|
identityKey: import("zod").ZodString;
|
|
349
351
|
}, import("zod/v4/core").$strip>>;
|
|
350
352
|
mode: import("zod").ZodEnum<{
|
|
@@ -560,6 +562,9 @@ export declare const firstPartyContract: {
|
|
|
560
562
|
id: import("zod").ZodString;
|
|
561
563
|
name: import("zod").ZodString;
|
|
562
564
|
}, import("zod/v4/core").$strip>;
|
|
565
|
+
activeAutomations: import("zod").ZodArray<import("zod").ZodObject<{
|
|
566
|
+
identityKey: import("zod").ZodString;
|
|
567
|
+
}, import("zod/v4/core").$strip>>;
|
|
563
568
|
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
564
569
|
list: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<import("zod").ZodOptional<import("zod").ZodObject<{
|
|
565
570
|
organizationId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
@@ -826,7 +831,7 @@ export declare const contract: {
|
|
|
826
831
|
sendEmail: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<import("zod").ZodObject<{
|
|
827
832
|
subject: import("zod").ZodString;
|
|
828
833
|
text: import("zod").ZodString;
|
|
829
|
-
to: import("zod").ZodEmail
|
|
834
|
+
to: import("zod").ZodUnion<readonly [import("zod").ZodEmail, import("zod").ZodLiteral<"*">]>;
|
|
830
835
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
831
836
|
id: import("zod").ZodNullable<import("zod").ZodString>;
|
|
832
837
|
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
@@ -835,7 +840,6 @@ export declare const contract: {
|
|
|
835
840
|
create: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<import("zod").ZodObject<{
|
|
836
841
|
artifact: import("zod").ZodCustom<Blob, Blob>;
|
|
837
842
|
manifest: import("zod").ZodArray<import("zod").ZodObject<{
|
|
838
|
-
entrypoint: import("zod").ZodString;
|
|
839
843
|
identityKey: import("zod").ZodString;
|
|
840
844
|
}, import("zod/v4/core").$strip>>;
|
|
841
845
|
mode: import("zod").ZodEnum<{
|
|
@@ -1051,6 +1055,9 @@ export declare const contract: {
|
|
|
1051
1055
|
id: import("zod").ZodString;
|
|
1052
1056
|
name: import("zod").ZodString;
|
|
1053
1057
|
}, import("zod/v4/core").$strip>;
|
|
1058
|
+
activeAutomations: import("zod").ZodArray<import("zod").ZodObject<{
|
|
1059
|
+
identityKey: import("zod").ZodString;
|
|
1060
|
+
}, import("zod/v4/core").$strip>>;
|
|
1054
1061
|
}, import("zod/v4/core").$strip>, Record<never, never>, Record<never, never>>;
|
|
1055
1062
|
list: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<import("zod").ZodOptional<import("zod").ZodObject<{
|
|
1056
1063
|
organizationId: import("zod").ZodOptional<import("zod").ZodString>;
|
package/dist/project.d.ts
CHANGED
|
@@ -57,6 +57,9 @@ export declare const projectContract: {
|
|
|
57
57
|
id: z.ZodString;
|
|
58
58
|
name: z.ZodString;
|
|
59
59
|
}, z.core.$strip>;
|
|
60
|
+
activeAutomations: z.ZodArray<z.ZodObject<{
|
|
61
|
+
identityKey: z.ZodString;
|
|
62
|
+
}, z.core.$strip>>;
|
|
60
63
|
}, z.core.$strip>, Record<never, never>, Record<never, never>>;
|
|
61
64
|
update: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
|
|
62
65
|
projectId: z.ZodString;
|
package/dist/project.js
CHANGED
|
@@ -56,11 +56,17 @@ export const projectContract = {
|
|
|
56
56
|
path: "/projects/{projectId}",
|
|
57
57
|
operationId: "getProject",
|
|
58
58
|
summary: "Get project",
|
|
59
|
-
description: "Returns project details and
|
|
59
|
+
description: "Returns project details, its organization, and active automations.",
|
|
60
60
|
tags: ["Projects"],
|
|
61
61
|
})
|
|
62
62
|
.input(z.object({ projectId: z.string() }))
|
|
63
|
-
.output(projectWithOrganizationOutputSchema
|
|
63
|
+
.output(projectWithOrganizationOutputSchema.extend({
|
|
64
|
+
activeAutomations: z
|
|
65
|
+
.object({
|
|
66
|
+
identityKey: z.string(),
|
|
67
|
+
})
|
|
68
|
+
.array(),
|
|
69
|
+
})),
|
|
64
70
|
update: oc
|
|
65
71
|
.route({
|
|
66
72
|
method: "PATCH",
|
package/dist/runtime.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ export declare const runtimeContract: {
|
|
|
64
64
|
sendEmail: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
|
|
65
65
|
subject: z.ZodString;
|
|
66
66
|
text: z.ZodString;
|
|
67
|
-
to: z.ZodEmail
|
|
67
|
+
to: z.ZodUnion<readonly [z.ZodEmail, z.ZodLiteral<"*">]>;
|
|
68
68
|
}, z.core.$strip>, z.ZodObject<{
|
|
69
69
|
id: z.ZodNullable<z.ZodString>;
|
|
70
70
|
}, z.core.$strip>, Record<never, never>, Record<never, never>>;
|
package/dist/runtime.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automate.ax/api-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Public oRPC contract for the Automate.ax API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,10 +20,13 @@
|
|
|
20
20
|
"exports": {
|
|
21
21
|
".": "./src/index.ts"
|
|
22
22
|
},
|
|
23
|
-
"cjs": false
|
|
23
|
+
"cjs": false,
|
|
24
|
+
"conditions": {
|
|
25
|
+
"bun": "src"
|
|
26
|
+
}
|
|
24
27
|
},
|
|
25
28
|
"dependencies": {
|
|
26
|
-
"@automate.ax/codec": "0.
|
|
29
|
+
"@automate.ax/codec": "0.9.0",
|
|
27
30
|
"@orpc/contract": "1.13.14",
|
|
28
31
|
"zod": "^4.3.6"
|
|
29
32
|
},
|
|
@@ -48,6 +51,7 @@
|
|
|
48
51
|
},
|
|
49
52
|
"files": [
|
|
50
53
|
"dist",
|
|
54
|
+
"src",
|
|
51
55
|
"README.md",
|
|
52
56
|
"LICENSE"
|
|
53
57
|
],
|
|
@@ -59,6 +63,7 @@
|
|
|
59
63
|
},
|
|
60
64
|
"exports": {
|
|
61
65
|
".": {
|
|
66
|
+
"bun": "./src/index.ts",
|
|
62
67
|
"types": "./dist/index.d.ts",
|
|
63
68
|
"default": "./dist/index.js"
|
|
64
69
|
}
|
package/src/api-key.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import { reasonableNameSchema } from "./schemas"
|
|
4
|
+
|
|
5
|
+
export const organizationApiKeyOutputSchema = z.object({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
name: z.string().nullable(),
|
|
8
|
+
start: z.string().nullable(),
|
|
9
|
+
createdAt: z.date(),
|
|
10
|
+
updatedAt: z.date(),
|
|
11
|
+
expiresAt: z.date().nullable(),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export const createdOrganizationApiKeyOutputSchema =
|
|
15
|
+
organizationApiKeyOutputSchema.extend({
|
|
16
|
+
key: z.string(),
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export const apiKeyContract = {
|
|
20
|
+
create: oc
|
|
21
|
+
.route({
|
|
22
|
+
method: "POST",
|
|
23
|
+
path: "/organizations/{organizationId}/api-keys",
|
|
24
|
+
operationId: "createOrganizationApiKey",
|
|
25
|
+
summary: "Create organization API key",
|
|
26
|
+
description:
|
|
27
|
+
"Creates an API key owned by the organization. The secret is returned once.",
|
|
28
|
+
successStatus: 201,
|
|
29
|
+
successDescription: "API key created.",
|
|
30
|
+
tags: ["API Keys"],
|
|
31
|
+
})
|
|
32
|
+
.input(
|
|
33
|
+
z.object({
|
|
34
|
+
organizationId: z.string(),
|
|
35
|
+
name: reasonableNameSchema,
|
|
36
|
+
}),
|
|
37
|
+
)
|
|
38
|
+
.output(createdOrganizationApiKeyOutputSchema),
|
|
39
|
+
delete: oc
|
|
40
|
+
.route({
|
|
41
|
+
method: "DELETE",
|
|
42
|
+
path: "/organizations/{organizationId}/api-keys/{keyId}",
|
|
43
|
+
operationId: "deleteOrganizationApiKey",
|
|
44
|
+
summary: "Delete organization API key",
|
|
45
|
+
description: "Permanently revokes an organization API key.",
|
|
46
|
+
successStatus: 204,
|
|
47
|
+
tags: ["API Keys"],
|
|
48
|
+
})
|
|
49
|
+
.input(
|
|
50
|
+
z.object({
|
|
51
|
+
keyId: z.string(),
|
|
52
|
+
organizationId: z.string(),
|
|
53
|
+
}),
|
|
54
|
+
)
|
|
55
|
+
.output(z.void()),
|
|
56
|
+
list: oc
|
|
57
|
+
.route({
|
|
58
|
+
method: "GET",
|
|
59
|
+
path: "/organizations/{organizationId}/api-keys",
|
|
60
|
+
operationId: "listOrganizationApiKeys",
|
|
61
|
+
summary: "List organization API keys",
|
|
62
|
+
description: "Lists API keys owned by an organization.",
|
|
63
|
+
tags: ["API Keys"],
|
|
64
|
+
})
|
|
65
|
+
.input(z.object({ organizationId: z.string() }))
|
|
66
|
+
.output(organizationApiKeyOutputSchema.array()),
|
|
67
|
+
update: oc
|
|
68
|
+
.route({
|
|
69
|
+
method: "PATCH",
|
|
70
|
+
path: "/organizations/{organizationId}/api-keys/{keyId}",
|
|
71
|
+
operationId: "updateOrganizationApiKey",
|
|
72
|
+
summary: "Update organization API key",
|
|
73
|
+
description: "Updates an organization API key's display name.",
|
|
74
|
+
tags: ["API Keys"],
|
|
75
|
+
})
|
|
76
|
+
.input(
|
|
77
|
+
z.object({
|
|
78
|
+
keyId: z.string(),
|
|
79
|
+
name: reasonableNameSchema,
|
|
80
|
+
organizationId: z.string(),
|
|
81
|
+
}),
|
|
82
|
+
)
|
|
83
|
+
.output(organizationApiKeyOutputSchema),
|
|
84
|
+
}
|
package/src/auth.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export const userOutputSchema = z.object({
|
|
5
|
+
id: z.string(),
|
|
6
|
+
name: z.string(),
|
|
7
|
+
email: z.email(),
|
|
8
|
+
emailVerified: z.boolean(),
|
|
9
|
+
image: z.string().nullable().optional(),
|
|
10
|
+
createdAt: z.date(),
|
|
11
|
+
updatedAt: z.date(),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export const authContract = {
|
|
15
|
+
me: oc
|
|
16
|
+
.route({
|
|
17
|
+
method: "GET",
|
|
18
|
+
path: "/me",
|
|
19
|
+
operationId: "getCurrentUser",
|
|
20
|
+
summary: "Get current user",
|
|
21
|
+
description:
|
|
22
|
+
"Returns the authenticated user for the current bearer token or cookie session.",
|
|
23
|
+
tags: ["Session"],
|
|
24
|
+
})
|
|
25
|
+
.output(userOutputSchema),
|
|
26
|
+
linkDeviceSession: oc
|
|
27
|
+
.route({
|
|
28
|
+
method: "POST",
|
|
29
|
+
path: "/me/session/link-device",
|
|
30
|
+
operationId: "linkDeviceSession",
|
|
31
|
+
summary: "Link device session",
|
|
32
|
+
description:
|
|
33
|
+
"Migrates anonymous-session data into authenticated user context.",
|
|
34
|
+
tags: ["Session"],
|
|
35
|
+
successStatus: 204,
|
|
36
|
+
})
|
|
37
|
+
.input(z.object({ newAccessToken: z.string() }))
|
|
38
|
+
.output(z.void()),
|
|
39
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
const integrationFormFieldBaseSchema = z.object({
|
|
5
|
+
description: z.string().optional(),
|
|
6
|
+
label: z.string().min(1),
|
|
7
|
+
name: z.string().min(1),
|
|
8
|
+
required: z.boolean(),
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const INTEGRATION_FORM_FIELD_SCHEMA = z.discriminatedUnion("input", [
|
|
12
|
+
integrationFormFieldBaseSchema.extend({
|
|
13
|
+
default: z.string().optional(),
|
|
14
|
+
input: z.enum(["email", "text", "url"]),
|
|
15
|
+
placeholder: z.string().optional(),
|
|
16
|
+
}),
|
|
17
|
+
integrationFormFieldBaseSchema.extend({
|
|
18
|
+
input: z.literal("password"),
|
|
19
|
+
placeholder: z.string().optional(),
|
|
20
|
+
}),
|
|
21
|
+
integrationFormFieldBaseSchema.extend({
|
|
22
|
+
default: z.number().optional(),
|
|
23
|
+
input: z.literal("number"),
|
|
24
|
+
placeholder: z.string().optional(),
|
|
25
|
+
}),
|
|
26
|
+
integrationFormFieldBaseSchema.extend({
|
|
27
|
+
default: z.boolean().optional(),
|
|
28
|
+
input: z.literal("boolean"),
|
|
29
|
+
}),
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
export const integrationServiceManifestSchema = z.object({
|
|
33
|
+
connection: z.discriminatedUnion("type", [
|
|
34
|
+
z.object({
|
|
35
|
+
type: z.literal("redirect"),
|
|
36
|
+
}),
|
|
37
|
+
z.object({
|
|
38
|
+
fields: INTEGRATION_FORM_FIELD_SCHEMA.array().min(1),
|
|
39
|
+
type: z.literal("form"),
|
|
40
|
+
}),
|
|
41
|
+
]),
|
|
42
|
+
description: z.string().optional(),
|
|
43
|
+
name: z.string().min(1),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
export type IntegrationServiceManifest = z.infer<
|
|
47
|
+
typeof integrationServiceManifestSchema
|
|
48
|
+
>
|
|
49
|
+
|
|
50
|
+
type ScopeRequirement =
|
|
51
|
+
| string
|
|
52
|
+
| {
|
|
53
|
+
requirements: ScopeRequirement[]
|
|
54
|
+
type: "and" | "or"
|
|
55
|
+
}
|
|
56
|
+
const SCOPE_REQUIREMENT_SCHEMA: z.ZodType<ScopeRequirement> = z.lazy(() =>
|
|
57
|
+
z.union([
|
|
58
|
+
z.string(),
|
|
59
|
+
z.strictObject({
|
|
60
|
+
requirements: SCOPE_REQUIREMENT_SCHEMA.array(),
|
|
61
|
+
type: z.enum(["and", "or"]),
|
|
62
|
+
}),
|
|
63
|
+
]),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export const authorizationContract = {
|
|
67
|
+
beginConnection: oc
|
|
68
|
+
.input(
|
|
69
|
+
z.object({
|
|
70
|
+
binding: z.string().min(1),
|
|
71
|
+
deploymentId: z.string(),
|
|
72
|
+
serviceId: z.string().min(1),
|
|
73
|
+
}),
|
|
74
|
+
)
|
|
75
|
+
.output(z.object({ url: z.url() })),
|
|
76
|
+
callback: oc
|
|
77
|
+
.route({
|
|
78
|
+
method: "GET",
|
|
79
|
+
path: "/integrations/{serviceId}/callback",
|
|
80
|
+
operationId: "completeIntegrationAuthorization",
|
|
81
|
+
summary: "Complete integration authorization",
|
|
82
|
+
description: "Completes a redirect-based integration authorization flow.",
|
|
83
|
+
tags: ["Integrations"],
|
|
84
|
+
})
|
|
85
|
+
.input(z.object({ serviceId: z.string().min(1) }))
|
|
86
|
+
.output(z.string()),
|
|
87
|
+
get: oc
|
|
88
|
+
.input(
|
|
89
|
+
z.object({
|
|
90
|
+
deploymentId: z.string(),
|
|
91
|
+
}),
|
|
92
|
+
)
|
|
93
|
+
.output(
|
|
94
|
+
z.object({
|
|
95
|
+
accounts: z
|
|
96
|
+
.object({
|
|
97
|
+
checkedAt: z.date().nullable(),
|
|
98
|
+
error: z
|
|
99
|
+
.object({
|
|
100
|
+
code: z.string(),
|
|
101
|
+
message: z.string(),
|
|
102
|
+
})
|
|
103
|
+
.nullable(),
|
|
104
|
+
id: z.string(),
|
|
105
|
+
label: z.string(),
|
|
106
|
+
scopes: z.string().array(),
|
|
107
|
+
serviceId: z.string(),
|
|
108
|
+
serviceSub: z.string(),
|
|
109
|
+
})
|
|
110
|
+
.array(),
|
|
111
|
+
requirements: z
|
|
112
|
+
.object({
|
|
113
|
+
accountId: z.string().nullable(),
|
|
114
|
+
binding: z.string(),
|
|
115
|
+
eligibleAccountIds: z.string().array(),
|
|
116
|
+
minimalScopes: z.string().array(),
|
|
117
|
+
requiredScopes: SCOPE_REQUIREMENT_SCHEMA.array(),
|
|
118
|
+
satisfied: z.boolean(),
|
|
119
|
+
serviceId: z.string(),
|
|
120
|
+
})
|
|
121
|
+
.array(),
|
|
122
|
+
services: integrationServiceManifestSchema
|
|
123
|
+
.extend({
|
|
124
|
+
id: z.string().min(1),
|
|
125
|
+
})
|
|
126
|
+
.array(),
|
|
127
|
+
}),
|
|
128
|
+
),
|
|
129
|
+
submitCredentials: oc
|
|
130
|
+
.input(
|
|
131
|
+
z.object({
|
|
132
|
+
binding: z.string().min(1),
|
|
133
|
+
data: z.record(
|
|
134
|
+
z.string(),
|
|
135
|
+
z.union([z.string(), z.number(), z.boolean()]),
|
|
136
|
+
),
|
|
137
|
+
deploymentId: z.string(),
|
|
138
|
+
serviceId: z.string().min(1),
|
|
139
|
+
}),
|
|
140
|
+
)
|
|
141
|
+
.output(z.void()),
|
|
142
|
+
selectAccount: oc
|
|
143
|
+
.input(
|
|
144
|
+
z.object({
|
|
145
|
+
accountId: z.string(),
|
|
146
|
+
binding: z.string().min(1),
|
|
147
|
+
deploymentId: z.string(),
|
|
148
|
+
}),
|
|
149
|
+
)
|
|
150
|
+
.output(z.void()),
|
|
151
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
/** SDK compatibility version used to select the immutable runtime image. */
|
|
5
|
+
export const AUTOMATION_SDK_VERSION = "1"
|
|
6
|
+
|
|
7
|
+
export const deploymentTriggerInfoSchema = z.object({
|
|
8
|
+
details: z
|
|
9
|
+
.object({
|
|
10
|
+
label: z.string(),
|
|
11
|
+
value: z.string(),
|
|
12
|
+
})
|
|
13
|
+
.array(),
|
|
14
|
+
name: z.string(),
|
|
15
|
+
type: z.string(),
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export type DeploymentTriggerInfo = z.infer<typeof deploymentTriggerInfoSchema>
|
|
19
|
+
|
|
20
|
+
export const deploymentContract = {
|
|
21
|
+
create: oc
|
|
22
|
+
.input(
|
|
23
|
+
z.object({
|
|
24
|
+
artifact: z.instanceof(Blob),
|
|
25
|
+
manifest: z
|
|
26
|
+
.object({
|
|
27
|
+
identityKey: z.string().min(1),
|
|
28
|
+
})
|
|
29
|
+
.array()
|
|
30
|
+
.min(1, "Deployment must include at least one automation.")
|
|
31
|
+
.superRefine((manifest, context) => {
|
|
32
|
+
const identityKeys = new Set<string>()
|
|
33
|
+
|
|
34
|
+
for (const [index, entry] of manifest.entries()) {
|
|
35
|
+
if (identityKeys.has(entry.identityKey)) {
|
|
36
|
+
context.addIssue({
|
|
37
|
+
code: "custom",
|
|
38
|
+
message: "Automation identity keys must be unique.",
|
|
39
|
+
path: [index, "identityKey"],
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
identityKeys.add(entry.identityKey)
|
|
43
|
+
}
|
|
44
|
+
}),
|
|
45
|
+
mode: z.enum(["reconcile", "upsert"]),
|
|
46
|
+
projectId: z.string(),
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
49
|
+
.output(z.object({ id: z.string() })),
|
|
50
|
+
get: oc
|
|
51
|
+
.input(
|
|
52
|
+
z.object({
|
|
53
|
+
deploymentId: z.string(),
|
|
54
|
+
projectId: z.string(),
|
|
55
|
+
}),
|
|
56
|
+
)
|
|
57
|
+
.output(
|
|
58
|
+
z.object({
|
|
59
|
+
automations: z
|
|
60
|
+
.object({
|
|
61
|
+
description: z.string(),
|
|
62
|
+
identityKey: z.string(),
|
|
63
|
+
triggers: deploymentTriggerInfoSchema.array(),
|
|
64
|
+
})
|
|
65
|
+
.array(),
|
|
66
|
+
id: z.string(),
|
|
67
|
+
job: z
|
|
68
|
+
.object({
|
|
69
|
+
attempts: z.number().int().nonnegative(),
|
|
70
|
+
error: z.string().nullable(),
|
|
71
|
+
maxAttempts: z.number().int().positive(),
|
|
72
|
+
nextRunAt: z.date(),
|
|
73
|
+
})
|
|
74
|
+
.nullable(),
|
|
75
|
+
project: z.object({
|
|
76
|
+
id: z.string(),
|
|
77
|
+
name: z.string(),
|
|
78
|
+
}),
|
|
79
|
+
status: z.enum([
|
|
80
|
+
"planning",
|
|
81
|
+
"awaiting_authorization",
|
|
82
|
+
"configuring",
|
|
83
|
+
"publishing",
|
|
84
|
+
"succeeded",
|
|
85
|
+
"failed",
|
|
86
|
+
]),
|
|
87
|
+
}),
|
|
88
|
+
),
|
|
89
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export const gmailEventsContract = {
|
|
5
|
+
gmailPush: oc
|
|
6
|
+
.route({
|
|
7
|
+
method: "POST",
|
|
8
|
+
path: "/events/gmail",
|
|
9
|
+
operationId: "receiveGmailPush",
|
|
10
|
+
summary: "Receive a Gmail push notification",
|
|
11
|
+
description:
|
|
12
|
+
"Receives and authenticates Gmail mailbox notifications delivered by Google Cloud Pub/Sub.",
|
|
13
|
+
tags: ["Events"],
|
|
14
|
+
successStatus: 204,
|
|
15
|
+
})
|
|
16
|
+
.input(
|
|
17
|
+
z.object({
|
|
18
|
+
/** Pub/Sub message containing the encoded Gmail notification. */
|
|
19
|
+
message: z.object({
|
|
20
|
+
/** Base64-encoded Gmail mailbox notification. */
|
|
21
|
+
data: z.string().min(1),
|
|
22
|
+
|
|
23
|
+
/** Provider-assigned identifier used to deduplicate delivery. */
|
|
24
|
+
messageId: z.string().min(1),
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
/** Pub/Sub subscription that delivered the message. */
|
|
28
|
+
subscription: z.literal(
|
|
29
|
+
"projects/opkitty/subscriptions/automate-ax-gmail-push",
|
|
30
|
+
),
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
33
|
+
.output(z.void()),
|
|
34
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export const googleCalendarEventsContract = {
|
|
5
|
+
googleCalendarPush: oc
|
|
6
|
+
.route({
|
|
7
|
+
method: "POST",
|
|
8
|
+
path: "/events/google-calendar",
|
|
9
|
+
operationId: "receiveGoogleCalendarPush",
|
|
10
|
+
summary: "Receive a Google Calendar push notification",
|
|
11
|
+
description:
|
|
12
|
+
"Receives header-only Google Calendar resource-change notifications.",
|
|
13
|
+
tags: ["Events"],
|
|
14
|
+
successStatus: 204,
|
|
15
|
+
})
|
|
16
|
+
.input(z.void())
|
|
17
|
+
.output(z.void()),
|
|
18
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export const googleFormsEventsContract = {
|
|
5
|
+
googleFormsPush: oc
|
|
6
|
+
.route({
|
|
7
|
+
method: "POST",
|
|
8
|
+
path: "/events/google-forms",
|
|
9
|
+
operationId: "receiveGoogleFormsPush",
|
|
10
|
+
summary: "Receive a Google Forms push notification",
|
|
11
|
+
description:
|
|
12
|
+
"Receives and authenticates Google Forms notifications delivered by Google Cloud Pub/Sub.",
|
|
13
|
+
tags: ["Events"],
|
|
14
|
+
successStatus: 204,
|
|
15
|
+
})
|
|
16
|
+
.input(
|
|
17
|
+
z.object({
|
|
18
|
+
/** Pub/Sub message containing Google Forms notification attributes. */
|
|
19
|
+
message: z.object({
|
|
20
|
+
/** Provider routing fields for the watched form. */
|
|
21
|
+
attributes: z.object({
|
|
22
|
+
eventType: z.enum(["SCHEMA", "RESPONSES"]),
|
|
23
|
+
formId: z.string().min(1),
|
|
24
|
+
watchId: z.string().min(1),
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
/** Provider-assigned identifier used to deduplicate delivery. */
|
|
28
|
+
messageId: z.string().min(1),
|
|
29
|
+
|
|
30
|
+
/** RFC 3339 time at which Pub/Sub published the notification. */
|
|
31
|
+
publishTime: z.iso.datetime({ offset: true }),
|
|
32
|
+
}),
|
|
33
|
+
|
|
34
|
+
/** Pub/Sub subscription that delivered the message. */
|
|
35
|
+
subscription: z.literal(
|
|
36
|
+
"projects/opkitty/subscriptions/automate-ax-google-forms-push",
|
|
37
|
+
),
|
|
38
|
+
}),
|
|
39
|
+
)
|
|
40
|
+
.output(z.void()),
|
|
41
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { googleCalendarEventsContract } from "./google-calendar"
|
|
2
|
+
import { googleFormsEventsContract } from "./google-forms"
|
|
3
|
+
import { gmailEventsContract } from "./gmail"
|
|
4
|
+
|
|
5
|
+
export const eventsContract = {
|
|
6
|
+
...googleCalendarEventsContract,
|
|
7
|
+
...googleFormsEventsContract,
|
|
8
|
+
...gmailEventsContract,
|
|
9
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { apiKeyContract } from "./api-key"
|
|
2
|
+
import { authContract } from "./auth"
|
|
3
|
+
import { authorizationContract } from "./authorization"
|
|
4
|
+
import { deploymentContract } from "./deployment"
|
|
5
|
+
import { eventsContract } from "./events"
|
|
6
|
+
import { orgContract } from "./org"
|
|
7
|
+
import { projectContract } from "./project"
|
|
8
|
+
import { runtimeContract } from "./runtime"
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
AUTOMATION_SDK_VERSION,
|
|
12
|
+
deploymentTriggerInfoSchema,
|
|
13
|
+
type DeploymentTriggerInfo,
|
|
14
|
+
} from "./deployment"
|
|
15
|
+
export { runtimeContract } from "./runtime"
|
|
16
|
+
export {
|
|
17
|
+
createdOrganizationApiKeyOutputSchema,
|
|
18
|
+
organizationApiKeyOutputSchema,
|
|
19
|
+
} from "./api-key"
|
|
20
|
+
export {
|
|
21
|
+
integrationServiceManifestSchema,
|
|
22
|
+
type IntegrationServiceManifest,
|
|
23
|
+
} from "./authorization"
|
|
24
|
+
export {
|
|
25
|
+
activeSubscriptionOutputSchema,
|
|
26
|
+
createdInvitationOutputSchema,
|
|
27
|
+
organizationDetailsOutputSchema,
|
|
28
|
+
organizationInvitationOutputSchema,
|
|
29
|
+
organizationMemberOutputSchema,
|
|
30
|
+
organizationProjectOutputSchema,
|
|
31
|
+
organizationRoleSchema,
|
|
32
|
+
organizationSummaryOutputSchema,
|
|
33
|
+
publicOrganizationOutputSchema,
|
|
34
|
+
} from "./org"
|
|
35
|
+
export {
|
|
36
|
+
projectOutputSchema,
|
|
37
|
+
projectWithOrganizationOutputSchema,
|
|
38
|
+
} from "./project"
|
|
39
|
+
export { reasonableNameSchema } from "./schemas"
|
|
40
|
+
export { userOutputSchema } from "./auth"
|
|
41
|
+
|
|
42
|
+
/** Procedures exposed by the public Node client and OpenAPI document. */
|
|
43
|
+
export const publicContract = {
|
|
44
|
+
apiKey: apiKeyContract,
|
|
45
|
+
org: {
|
|
46
|
+
create: orgContract.create,
|
|
47
|
+
delete: orgContract.delete,
|
|
48
|
+
get: orgContract.get,
|
|
49
|
+
invite: orgContract.invite,
|
|
50
|
+
leave: orgContract.leave,
|
|
51
|
+
list: orgContract.list,
|
|
52
|
+
remove: orgContract.remove,
|
|
53
|
+
update: orgContract.update,
|
|
54
|
+
},
|
|
55
|
+
project: {
|
|
56
|
+
create: projectContract.create,
|
|
57
|
+
delete: projectContract.delete,
|
|
58
|
+
get: projectContract.get,
|
|
59
|
+
list: projectContract.list,
|
|
60
|
+
update: projectContract.update,
|
|
61
|
+
},
|
|
62
|
+
session: {
|
|
63
|
+
me: authContract.me,
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Procedures used by first-party control-plane clients. */
|
|
68
|
+
export const firstPartyContract = {
|
|
69
|
+
...publicContract,
|
|
70
|
+
authorization: {
|
|
71
|
+
beginConnection: authorizationContract.beginConnection,
|
|
72
|
+
get: authorizationContract.get,
|
|
73
|
+
selectAccount: authorizationContract.selectAccount,
|
|
74
|
+
submitCredentials: authorizationContract.submitCredentials,
|
|
75
|
+
},
|
|
76
|
+
deployment: deploymentContract,
|
|
77
|
+
org: {
|
|
78
|
+
...publicContract.org,
|
|
79
|
+
canInvite: orgContract.canInvite,
|
|
80
|
+
},
|
|
81
|
+
project: {
|
|
82
|
+
...publicContract.project,
|
|
83
|
+
canCreate: projectContract.canCreate,
|
|
84
|
+
},
|
|
85
|
+
session: {
|
|
86
|
+
...publicContract.session,
|
|
87
|
+
linkDeviceSession: authContract.linkDeviceSession,
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Complete contract implemented by the API service. */
|
|
92
|
+
export const contract = {
|
|
93
|
+
...firstPartyContract,
|
|
94
|
+
authorization: {
|
|
95
|
+
...firstPartyContract.authorization,
|
|
96
|
+
callback: authorizationContract.callback,
|
|
97
|
+
},
|
|
98
|
+
events: eventsContract,
|
|
99
|
+
runtime: runtimeContract,
|
|
100
|
+
}
|
package/src/org.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import { reasonableNameSchema } from "./schemas"
|
|
4
|
+
|
|
5
|
+
export const organizationRoleSchema = z.enum(["member", "admin", "owner"])
|
|
6
|
+
|
|
7
|
+
export const publicOrganizationOutputSchema = z.object({
|
|
8
|
+
id: z.string(),
|
|
9
|
+
name: z.string(),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export const activeSubscriptionOutputSchema = z.object({
|
|
13
|
+
id: z.string(),
|
|
14
|
+
plan: z.string(),
|
|
15
|
+
status: z.string(),
|
|
16
|
+
periodEnd: z.date().nullable(),
|
|
17
|
+
cancelAtPeriodEnd: z.boolean(),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export const organizationSummaryOutputSchema = z.object({
|
|
21
|
+
id: z.string(),
|
|
22
|
+
name: z.string(),
|
|
23
|
+
logo: z.string().nullable(),
|
|
24
|
+
metadata: z.string().nullable(),
|
|
25
|
+
createdAt: z.date(),
|
|
26
|
+
role: organizationRoleSchema,
|
|
27
|
+
memberCount: z.number(),
|
|
28
|
+
pendingInvitationCount: z.number(),
|
|
29
|
+
projectCount: z.number(),
|
|
30
|
+
activeSubscription: activeSubscriptionOutputSchema.nullable(),
|
|
31
|
+
plan: z.enum(["free", "pro", "enterprise"]),
|
|
32
|
+
limits: z.object({
|
|
33
|
+
projects: z.number(),
|
|
34
|
+
seats: z.number(),
|
|
35
|
+
}),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const organizationMemberOutputSchema = z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
userId: z.string(),
|
|
41
|
+
role: organizationRoleSchema,
|
|
42
|
+
createdAt: z.date(),
|
|
43
|
+
email: z.email(),
|
|
44
|
+
name: z.string(),
|
|
45
|
+
image: z.string().nullable(),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export const organizationInvitationOutputSchema = z.object({
|
|
49
|
+
id: z.string(),
|
|
50
|
+
email: z.email(),
|
|
51
|
+
role: organizationRoleSchema.nullable(),
|
|
52
|
+
status: z.string(),
|
|
53
|
+
createdAt: z.date(),
|
|
54
|
+
expiresAt: z.date(),
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export const organizationProjectOutputSchema = z.object({
|
|
58
|
+
id: z.string(),
|
|
59
|
+
name: z.string(),
|
|
60
|
+
createdAt: z.date(),
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
export const organizationDetailsOutputSchema =
|
|
64
|
+
organizationSummaryOutputSchema.extend({
|
|
65
|
+
members: organizationMemberOutputSchema.array(),
|
|
66
|
+
invitations: organizationInvitationOutputSchema.array(),
|
|
67
|
+
projects: organizationProjectOutputSchema.array(),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
export const createdInvitationOutputSchema = z.object({
|
|
71
|
+
id: z.string(),
|
|
72
|
+
email: z.email(),
|
|
73
|
+
role: organizationRoleSchema.nullable(),
|
|
74
|
+
status: z.string(),
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
export const orgContract = {
|
|
78
|
+
canInvite: oc
|
|
79
|
+
.input(z.object({ organizationId: z.string() }))
|
|
80
|
+
.output(z.boolean()),
|
|
81
|
+
create: oc
|
|
82
|
+
.route({
|
|
83
|
+
method: "POST",
|
|
84
|
+
path: "/organizations",
|
|
85
|
+
operationId: "createOrganization",
|
|
86
|
+
summary: "Create organization",
|
|
87
|
+
description: "Creates an organization owned by the authenticated user.",
|
|
88
|
+
successStatus: 201,
|
|
89
|
+
successDescription: "Organization created.",
|
|
90
|
+
tags: ["Organizations"],
|
|
91
|
+
})
|
|
92
|
+
.input(z.object({ name: reasonableNameSchema }))
|
|
93
|
+
.output(publicOrganizationOutputSchema),
|
|
94
|
+
delete: oc
|
|
95
|
+
.route({
|
|
96
|
+
method: "DELETE",
|
|
97
|
+
path: "/organizations/{organizationId}",
|
|
98
|
+
operationId: "deleteOrganization",
|
|
99
|
+
summary: "Delete organization",
|
|
100
|
+
description:
|
|
101
|
+
"Deletes an organization. Caller must be the organization owner.",
|
|
102
|
+
tags: ["Organizations"],
|
|
103
|
+
successStatus: 204,
|
|
104
|
+
})
|
|
105
|
+
.input(z.object({ organizationId: z.string() }))
|
|
106
|
+
.output(z.void()),
|
|
107
|
+
get: oc
|
|
108
|
+
.route({
|
|
109
|
+
method: "GET",
|
|
110
|
+
path: "/organizations/{organizationId}",
|
|
111
|
+
operationId: "getOrganization",
|
|
112
|
+
summary: "Get organization",
|
|
113
|
+
description:
|
|
114
|
+
"Returns organization details, members, invitations, projects, plan, and usage.",
|
|
115
|
+
tags: ["Organizations"],
|
|
116
|
+
})
|
|
117
|
+
.input(z.object({ organizationId: z.string().min(1) }))
|
|
118
|
+
.output(organizationDetailsOutputSchema),
|
|
119
|
+
invite: oc
|
|
120
|
+
.route({
|
|
121
|
+
method: "POST",
|
|
122
|
+
path: "/organizations/{organizationId}/invitations",
|
|
123
|
+
operationId: "createOrganizationInvitation",
|
|
124
|
+
summary: "Invite organization member",
|
|
125
|
+
description:
|
|
126
|
+
"Creates a pending invitation for an email address. Caller must be an organization admin or owner.",
|
|
127
|
+
successStatus: 201,
|
|
128
|
+
successDescription: "Invitation created.",
|
|
129
|
+
tags: ["Organizations"],
|
|
130
|
+
})
|
|
131
|
+
.input(
|
|
132
|
+
z.object({
|
|
133
|
+
organizationId: z.string(),
|
|
134
|
+
email: z.email(),
|
|
135
|
+
role: organizationRoleSchema.default("member"),
|
|
136
|
+
}),
|
|
137
|
+
)
|
|
138
|
+
.output(createdInvitationOutputSchema),
|
|
139
|
+
leave: oc
|
|
140
|
+
.route({
|
|
141
|
+
method: "DELETE",
|
|
142
|
+
path: "/organizations/{organizationId}/membership",
|
|
143
|
+
operationId: "leaveOrganization",
|
|
144
|
+
summary: "Leave organization",
|
|
145
|
+
description:
|
|
146
|
+
"Removes the current user from an organization. Owners must transfer ownership or delete the organization instead.",
|
|
147
|
+
tags: ["Organizations"],
|
|
148
|
+
successStatus: 204,
|
|
149
|
+
})
|
|
150
|
+
.input(z.object({ organizationId: z.string() }))
|
|
151
|
+
.output(z.void()),
|
|
152
|
+
list: oc
|
|
153
|
+
.route({
|
|
154
|
+
method: "GET",
|
|
155
|
+
path: "/organizations",
|
|
156
|
+
operationId: "listOrganizations",
|
|
157
|
+
summary: "List organizations",
|
|
158
|
+
description:
|
|
159
|
+
"Lists organizations the authenticated user belongs to, optionally filtered by name or ID.",
|
|
160
|
+
tags: ["Organizations"],
|
|
161
|
+
})
|
|
162
|
+
.input(
|
|
163
|
+
z
|
|
164
|
+
.object({
|
|
165
|
+
query: z.string().min(1).optional(),
|
|
166
|
+
})
|
|
167
|
+
.default({}),
|
|
168
|
+
)
|
|
169
|
+
.output(organizationSummaryOutputSchema.array()),
|
|
170
|
+
remove: oc
|
|
171
|
+
.route({
|
|
172
|
+
method: "DELETE",
|
|
173
|
+
path: "/organizations/{organizationId}/members/{memberIdOrEmail}",
|
|
174
|
+
operationId: "removeOrganizationMember",
|
|
175
|
+
summary: "Remove organization member",
|
|
176
|
+
description:
|
|
177
|
+
"Removes a member from an organization by member ID or email.",
|
|
178
|
+
tags: ["Organizations"],
|
|
179
|
+
successStatus: 204,
|
|
180
|
+
})
|
|
181
|
+
.input(
|
|
182
|
+
z.object({
|
|
183
|
+
organizationId: z.string(),
|
|
184
|
+
memberIdOrEmail: z.string().min(1),
|
|
185
|
+
}),
|
|
186
|
+
)
|
|
187
|
+
.output(z.void()),
|
|
188
|
+
update: oc
|
|
189
|
+
.route({
|
|
190
|
+
method: "PATCH",
|
|
191
|
+
path: "/organizations/{organizationId}",
|
|
192
|
+
operationId: "updateOrganization",
|
|
193
|
+
summary: "Update organization",
|
|
194
|
+
description: "Updates organization fields the caller can manage.",
|
|
195
|
+
successStatus: 204,
|
|
196
|
+
tags: ["Organizations"],
|
|
197
|
+
})
|
|
198
|
+
.input(
|
|
199
|
+
z.object({
|
|
200
|
+
organizationId: z.string(),
|
|
201
|
+
name: reasonableNameSchema,
|
|
202
|
+
}),
|
|
203
|
+
)
|
|
204
|
+
.output(z.void()),
|
|
205
|
+
}
|
package/src/project.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import { reasonableNameSchema } from "./schemas"
|
|
4
|
+
|
|
5
|
+
export const projectOutputSchema = z.object({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
name: z.string(),
|
|
8
|
+
organizationId: z.string(),
|
|
9
|
+
createdAt: z.date(),
|
|
10
|
+
createdBy: z.string().nullable(),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export const projectWithOrganizationOutputSchema = projectOutputSchema.extend({
|
|
14
|
+
org: z.object({
|
|
15
|
+
id: z.string(),
|
|
16
|
+
name: z.string(),
|
|
17
|
+
}),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export const projectContract = {
|
|
21
|
+
canCreate: oc
|
|
22
|
+
.input(z.object({ organizationId: z.string() }))
|
|
23
|
+
.output(z.boolean()),
|
|
24
|
+
create: oc
|
|
25
|
+
.route({
|
|
26
|
+
method: "POST",
|
|
27
|
+
path: "/organizations/{organizationId}/projects",
|
|
28
|
+
operationId: "createProject",
|
|
29
|
+
summary: "Create project",
|
|
30
|
+
description:
|
|
31
|
+
"Creates a project inside an organization the user belongs to.",
|
|
32
|
+
successStatus: 201,
|
|
33
|
+
successDescription: "Project created.",
|
|
34
|
+
tags: ["Projects"],
|
|
35
|
+
})
|
|
36
|
+
.input(
|
|
37
|
+
z.object({
|
|
38
|
+
organizationId: z.string(),
|
|
39
|
+
name: reasonableNameSchema,
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
.output(projectOutputSchema),
|
|
43
|
+
list: oc
|
|
44
|
+
.route({
|
|
45
|
+
method: "GET",
|
|
46
|
+
path: "/projects",
|
|
47
|
+
operationId: "listProjects",
|
|
48
|
+
summary: "List projects",
|
|
49
|
+
description:
|
|
50
|
+
"Lists projects visible to the authenticated user, optionally filtered by organization or query.",
|
|
51
|
+
tags: ["Projects"],
|
|
52
|
+
})
|
|
53
|
+
.input(
|
|
54
|
+
z
|
|
55
|
+
.object({
|
|
56
|
+
organizationId: z.string().optional(),
|
|
57
|
+
query: z.string().min(1).optional(),
|
|
58
|
+
})
|
|
59
|
+
.optional(),
|
|
60
|
+
)
|
|
61
|
+
.output(projectWithOrganizationOutputSchema.array()),
|
|
62
|
+
get: oc
|
|
63
|
+
.route({
|
|
64
|
+
method: "GET",
|
|
65
|
+
path: "/projects/{projectId}",
|
|
66
|
+
operationId: "getProject",
|
|
67
|
+
summary: "Get project",
|
|
68
|
+
description:
|
|
69
|
+
"Returns project details, its organization, and active automations.",
|
|
70
|
+
tags: ["Projects"],
|
|
71
|
+
})
|
|
72
|
+
.input(z.object({ projectId: z.string() }))
|
|
73
|
+
.output(
|
|
74
|
+
projectWithOrganizationOutputSchema.extend({
|
|
75
|
+
activeAutomations: z
|
|
76
|
+
.object({
|
|
77
|
+
identityKey: z.string(),
|
|
78
|
+
})
|
|
79
|
+
.array(),
|
|
80
|
+
}),
|
|
81
|
+
),
|
|
82
|
+
update: oc
|
|
83
|
+
.route({
|
|
84
|
+
method: "PATCH",
|
|
85
|
+
path: "/projects/{projectId}",
|
|
86
|
+
operationId: "updateProject",
|
|
87
|
+
summary: "Update project",
|
|
88
|
+
description:
|
|
89
|
+
"Updates project fields. Caller must be an organization admin or owner.",
|
|
90
|
+
successStatus: 204,
|
|
91
|
+
tags: ["Projects"],
|
|
92
|
+
})
|
|
93
|
+
.input(
|
|
94
|
+
z.object({
|
|
95
|
+
projectId: z.string(),
|
|
96
|
+
name: reasonableNameSchema,
|
|
97
|
+
}),
|
|
98
|
+
)
|
|
99
|
+
.output(z.void()),
|
|
100
|
+
delete: oc
|
|
101
|
+
.route({
|
|
102
|
+
method: "DELETE",
|
|
103
|
+
path: "/projects/{projectId}",
|
|
104
|
+
operationId: "deleteProject",
|
|
105
|
+
summary: "Delete project",
|
|
106
|
+
description:
|
|
107
|
+
"Deletes a project. Caller must be an organization admin or owner.",
|
|
108
|
+
tags: ["Projects"],
|
|
109
|
+
successStatus: 204,
|
|
110
|
+
})
|
|
111
|
+
.input(z.object({ projectId: z.string() }))
|
|
112
|
+
.output(z.void()),
|
|
113
|
+
}
|
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { encodableSchema } from "@automate.ax/codec"
|
|
2
|
+
import { oc } from "@orpc/contract"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
export const runtimeContract = {
|
|
6
|
+
commit: oc
|
|
7
|
+
.input(
|
|
8
|
+
z.object({
|
|
9
|
+
actionInvocations: z
|
|
10
|
+
.object({
|
|
11
|
+
actionDependencyIds: z.string().array(),
|
|
12
|
+
description: z.string().nullable(),
|
|
13
|
+
eventDependencyIds: z.string().array(),
|
|
14
|
+
inputHash: z.string(),
|
|
15
|
+
name: z.string(),
|
|
16
|
+
slot: z.number().int().nonnegative(),
|
|
17
|
+
})
|
|
18
|
+
.array()
|
|
19
|
+
.default([]),
|
|
20
|
+
}),
|
|
21
|
+
)
|
|
22
|
+
.output(z.void()),
|
|
23
|
+
completeInvocation: oc
|
|
24
|
+
.input(
|
|
25
|
+
z.object({
|
|
26
|
+
output: encodableSchema,
|
|
27
|
+
}),
|
|
28
|
+
)
|
|
29
|
+
.output(z.void()),
|
|
30
|
+
loadInvocation: oc.output(
|
|
31
|
+
z.object({
|
|
32
|
+
context: z.object({
|
|
33
|
+
actionOutputs: z
|
|
34
|
+
.object({
|
|
35
|
+
actionInvocationId: z.string(),
|
|
36
|
+
output: encodableSchema,
|
|
37
|
+
slot: z.number().int(),
|
|
38
|
+
})
|
|
39
|
+
.array(),
|
|
40
|
+
contextId: z.string(),
|
|
41
|
+
events: z
|
|
42
|
+
.object({
|
|
43
|
+
automationEventId: z.string(),
|
|
44
|
+
payload: encodableSchema,
|
|
45
|
+
slot: z.number().int(),
|
|
46
|
+
})
|
|
47
|
+
.array(),
|
|
48
|
+
}),
|
|
49
|
+
id: z.string(),
|
|
50
|
+
slot: z.number().int(),
|
|
51
|
+
}),
|
|
52
|
+
),
|
|
53
|
+
nextBatch: oc.output(
|
|
54
|
+
z.object({
|
|
55
|
+
context: z.object({
|
|
56
|
+
actionOutputs: z
|
|
57
|
+
.object({
|
|
58
|
+
actionDependencyIds: z.string().array(),
|
|
59
|
+
actionInvocationId: z.string(),
|
|
60
|
+
eventDependencyIds: z.string().array(),
|
|
61
|
+
inputHash: z.string(),
|
|
62
|
+
name: z.string(),
|
|
63
|
+
slot: z.number().int(),
|
|
64
|
+
})
|
|
65
|
+
.array(),
|
|
66
|
+
contextId: z.string(),
|
|
67
|
+
events: z
|
|
68
|
+
.object({
|
|
69
|
+
automationEventId: z.string(),
|
|
70
|
+
slot: z.number().int(),
|
|
71
|
+
})
|
|
72
|
+
.array(),
|
|
73
|
+
}),
|
|
74
|
+
}),
|
|
75
|
+
),
|
|
76
|
+
resolveAccountInput: oc
|
|
77
|
+
.input(
|
|
78
|
+
z.strictObject({
|
|
79
|
+
binding: z.string().min(1),
|
|
80
|
+
serviceId: z.string().min(1),
|
|
81
|
+
}),
|
|
82
|
+
)
|
|
83
|
+
.output(
|
|
84
|
+
z.object({
|
|
85
|
+
secret: z.record(z.string(), z.unknown()),
|
|
86
|
+
serviceId: z.string(),
|
|
87
|
+
}),
|
|
88
|
+
),
|
|
89
|
+
sendOutput: oc
|
|
90
|
+
.input(
|
|
91
|
+
z.object({
|
|
92
|
+
output: z.object({
|
|
93
|
+
data: encodableSchema,
|
|
94
|
+
type: z.string().min(1),
|
|
95
|
+
}),
|
|
96
|
+
outputIndex: z.number().int().nonnegative(),
|
|
97
|
+
}),
|
|
98
|
+
)
|
|
99
|
+
.output(z.void()),
|
|
100
|
+
sendEmail: oc
|
|
101
|
+
.input(
|
|
102
|
+
z.object({
|
|
103
|
+
subject: z.string().min(1),
|
|
104
|
+
text: z.string().min(1),
|
|
105
|
+
to: z.union([z.email(), z.literal("*")]),
|
|
106
|
+
}),
|
|
107
|
+
)
|
|
108
|
+
.output(
|
|
109
|
+
z.object({
|
|
110
|
+
id: z.string().nullable(),
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
}
|
package/src/schemas.ts
ADDED