@valon-technologies/gestalt 0.0.1-alpha.1 → 0.0.1-alpha.9
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 +8 -26
- package/gen/v1/{auth_pb.ts → authentication_pb.ts} +51 -17
- package/gen/v1/authorization_pb.ts +857 -0
- package/gen/v1/cache_pb.ts +32 -0
- package/gen/v1/datastore_pb.ts +62 -0
- package/gen/v1/plugin_pb.ts +216 -18
- package/gen/v1/runtime_pb.ts +27 -3
- package/gen/v1/s3_pb.ts +39 -0
- package/gen/v1/secrets_pb.ts +6 -0
- package/gen/v1/workflow_pb.ts +1372 -0
- package/package.json +12 -10
- package/src/api.ts +56 -0
- package/src/auth.ts +67 -16
- package/src/build.ts +37 -21
- package/src/cache.ts +32 -0
- package/src/catalog.ts +27 -0
- package/src/index.ts +87 -18
- package/src/indexeddb.ts +166 -0
- package/src/invoker.ts +124 -0
- package/src/plugin.ts +93 -38
- package/src/provider-kind.ts +107 -0
- package/src/provider.ts +32 -1
- package/src/runtime.ts +233 -218
- package/src/s3.ts +135 -20
- package/src/schema.ts +46 -0
- package/src/secrets.ts +12 -0
- package/src/target.ts +58 -60
- package/src/workflow-manager.ts +131 -0
- package/src/workflow.ts +479 -0
- package/tsconfig.json +1 -0
package/src/target.ts
CHANGED
|
@@ -2,39 +2,39 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { isAbsolute, normalize, resolve } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
|
|
5
|
+
import {
|
|
6
|
+
formatExternalProviderKind,
|
|
7
|
+
isExternalProviderKindToken,
|
|
8
|
+
parseExternalProviderKind,
|
|
9
|
+
} from "./provider-kind.ts";
|
|
5
10
|
import { slugName, type ProviderKind } from "./provider.ts";
|
|
6
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Relative module target with an optional named export.
|
|
14
|
+
*/
|
|
7
15
|
export type ModuleTarget = {
|
|
8
16
|
modulePath: string;
|
|
9
17
|
exportName?: string;
|
|
10
18
|
};
|
|
11
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Provider target with an explicit Gestalt provider kind.
|
|
22
|
+
*/
|
|
12
23
|
export type ProviderTarget = ModuleTarget & {
|
|
13
24
|
kind: ProviderKind;
|
|
14
25
|
};
|
|
15
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Gestalt-specific package metadata read from `package.json`.
|
|
29
|
+
*/
|
|
16
30
|
export type PackageConfig = {
|
|
17
31
|
name?: string;
|
|
18
32
|
providerTarget?: ProviderTarget;
|
|
19
33
|
};
|
|
20
34
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
kind?: string;
|
|
25
|
-
target?: string;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const EXTERNAL_PROVIDER_KIND_TOKENS = new Set<string>([
|
|
29
|
-
"plugin",
|
|
30
|
-
"integration",
|
|
31
|
-
"auth",
|
|
32
|
-
"cache",
|
|
33
|
-
"secrets",
|
|
34
|
-
"s3",
|
|
35
|
-
"telemetry",
|
|
36
|
-
]);
|
|
37
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Parses a relative module target in the form `./file.ts#namedExport`.
|
|
37
|
+
*/
|
|
38
38
|
export function parseModuleTarget(target: string, label = "gestalt provider target"): ModuleTarget {
|
|
39
39
|
const [modulePathRaw, exportNameRaw] = target.split("#", 2);
|
|
40
40
|
const modulePath = modulePathRaw?.trim() ?? "";
|
|
@@ -59,7 +59,12 @@ export function parseModuleTarget(target: string, label = "gestalt provider targ
|
|
|
59
59
|
return parsed;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Parses either a string or object-form provider target from `package.json`.
|
|
64
|
+
*/
|
|
65
|
+
export function parseProviderTarget(
|
|
66
|
+
target: string | { kind?: string; target?: string },
|
|
67
|
+
): ProviderTarget {
|
|
63
68
|
if (typeof target === "string") {
|
|
64
69
|
const prefixed = parseKindPrefixedTarget(target);
|
|
65
70
|
if (prefixed) {
|
|
@@ -71,7 +76,7 @@ export function parseProviderTarget(target: string | PackageProviderConfig): Pro
|
|
|
71
76
|
};
|
|
72
77
|
}
|
|
73
78
|
|
|
74
|
-
const kind =
|
|
79
|
+
const kind = parseExternalProviderKind(target.kind ?? "plugin");
|
|
75
80
|
if (!target.target || typeof target.target !== "string") {
|
|
76
81
|
throw new Error("gestalt.provider.target is required");
|
|
77
82
|
}
|
|
@@ -81,8 +86,9 @@ export function parseProviderTarget(target: string | PackageProviderConfig): Pro
|
|
|
81
86
|
};
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Reads the Gestalt-specific provider metadata from a package directory.
|
|
91
|
+
*/
|
|
86
92
|
export function readPackageConfig(root: string): PackageConfig {
|
|
87
93
|
const packagePath = resolve(root, "package.json");
|
|
88
94
|
const raw = JSON.parse(readFileSync(packagePath, "utf8")) as Record<string, unknown>;
|
|
@@ -94,11 +100,6 @@ export function readPackageConfig(root: string): PackageConfig {
|
|
|
94
100
|
providerTarget = parseProviderTarget(gestalt.provider);
|
|
95
101
|
} else if (isProviderConfigObject(gestalt.provider)) {
|
|
96
102
|
providerTarget = parseProviderTarget(gestalt.provider);
|
|
97
|
-
} else if (typeof gestalt.plugin === "string") {
|
|
98
|
-
providerTarget = {
|
|
99
|
-
kind: "integration",
|
|
100
|
-
...parseModuleTarget(gestalt.plugin, "gestalt.plugin"),
|
|
101
|
-
};
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
const config: PackageConfig = {};
|
|
@@ -111,29 +112,28 @@ export function readPackageConfig(root: string): PackageConfig {
|
|
|
111
112
|
return config;
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Reads and validates the configured provider target from `package.json`.
|
|
117
|
+
*/
|
|
114
118
|
export function readPackageProviderTarget(root: string): ProviderTarget {
|
|
115
119
|
const config = readPackageConfig(root);
|
|
116
120
|
if (!config.providerTarget) {
|
|
117
|
-
throw new Error("package.json gestalt.provider
|
|
121
|
+
throw new Error("package.json gestalt.provider is required");
|
|
118
122
|
}
|
|
119
123
|
return config.providerTarget;
|
|
120
124
|
}
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
throw new Error(`package.json provider kind ${JSON.stringify(target.kind)} is not an integration provider`);
|
|
126
|
-
}
|
|
127
|
-
return formatModuleTarget(target);
|
|
128
|
-
}
|
|
129
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Computes a default provider slug from the package name.
|
|
128
|
+
*/
|
|
130
129
|
export function defaultProviderName(root: string): string {
|
|
131
130
|
const config = readPackageConfig(root);
|
|
132
131
|
return slugName(config.name ?? "");
|
|
133
132
|
}
|
|
134
133
|
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Resolves a provider target to an absolute file path.
|
|
136
|
+
*/
|
|
137
137
|
export function resolveProviderModulePath(root: string, target: ProviderTarget | ModuleTarget): string {
|
|
138
138
|
const absolute = resolve(root, target.modulePath);
|
|
139
139
|
if (!isAbsolute(absolute)) {
|
|
@@ -142,49 +142,47 @@ export function resolveProviderModulePath(root: string, target: ProviderTarget |
|
|
|
142
142
|
return normalize(absolute);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Resolves a provider target to an importable file URL.
|
|
147
|
+
*/
|
|
147
148
|
export function resolveProviderImportUrl(root: string, target: ProviderTarget | ModuleTarget): string {
|
|
148
149
|
return pathToFileURL(resolveProviderModulePath(root, target)).href;
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Formats a provider target using the public `kind:./path#export` syntax.
|
|
154
|
+
*/
|
|
153
155
|
export function formatProviderTarget(target: ProviderTarget): string {
|
|
154
156
|
return `${formatProviderKind(target.kind)}:${formatModuleTarget(target)}`;
|
|
155
157
|
}
|
|
156
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Formats a module target using the public `./path#export` syntax.
|
|
161
|
+
*/
|
|
157
162
|
export function formatModuleTarget(target: ModuleTarget): string {
|
|
158
163
|
return `${target.modulePath}${target.exportName ? `#${target.exportName}` : ""}`;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
166
|
function parseKindPrefixedTarget(target: string): ProviderTarget | undefined {
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
167
|
+
const separator = target.indexOf(":");
|
|
168
|
+
if (separator < 0) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
const kindToken = target.slice(0, separator);
|
|
172
|
+
if (!kindToken || !isExternalProviderKindToken(kindToken)) {
|
|
173
|
+
if (kindToken && !kindToken.startsWith(".") && !kindToken.startsWith("/")) {
|
|
174
|
+
parseExternalProviderKind(kindToken);
|
|
175
|
+
}
|
|
164
176
|
return undefined;
|
|
165
177
|
}
|
|
166
178
|
return {
|
|
167
|
-
kind:
|
|
168
|
-
...parseModuleTarget(
|
|
179
|
+
kind: parseExternalProviderKind(kindToken),
|
|
180
|
+
...parseModuleTarget(target.slice(separator + 1), "provider target"),
|
|
169
181
|
};
|
|
170
182
|
}
|
|
171
183
|
|
|
172
|
-
function parseProviderKind(value: string): ProviderKind {
|
|
173
|
-
const normalized = value.trim().toLowerCase();
|
|
174
|
-
if (!EXTERNAL_PROVIDER_KIND_TOKENS.has(normalized)) {
|
|
175
|
-
throw new Error(`unsupported provider kind ${JSON.stringify(value)}`);
|
|
176
|
-
}
|
|
177
|
-
if (normalized === "plugin") {
|
|
178
|
-
return "integration";
|
|
179
|
-
}
|
|
180
|
-
return normalized as ProviderKind;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
184
|
function formatProviderKind(kind: ProviderKind): string {
|
|
184
|
-
|
|
185
|
-
return "plugin";
|
|
186
|
-
}
|
|
187
|
-
return kind;
|
|
185
|
+
return formatExternalProviderKind(kind);
|
|
188
186
|
}
|
|
189
187
|
|
|
190
188
|
function isProviderConfigObject(value: unknown): value is { kind?: string; target?: string } {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { connect } from "node:net";
|
|
2
|
+
|
|
3
|
+
import type { MessageInitShape } from "@bufbuild/protobuf";
|
|
4
|
+
import { createClient, type Client } from "@connectrpc/connect";
|
|
5
|
+
import { createGrpcTransport } from "@connectrpc/connect-node";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
WorkflowManagerCreateScheduleRequestSchema,
|
|
9
|
+
WorkflowManagerDeleteScheduleRequestSchema,
|
|
10
|
+
WorkflowManagerGetScheduleRequestSchema,
|
|
11
|
+
WorkflowManagerHost as WorkflowManagerHostService,
|
|
12
|
+
WorkflowManagerPauseScheduleRequestSchema,
|
|
13
|
+
WorkflowManagerResumeScheduleRequestSchema,
|
|
14
|
+
WorkflowManagerUpdateScheduleRequestSchema,
|
|
15
|
+
type ManagedWorkflowSchedule,
|
|
16
|
+
} from "../gen/v1/workflow_pb.ts";
|
|
17
|
+
import type { Request } from "./api.ts";
|
|
18
|
+
|
|
19
|
+
export const ENV_WORKFLOW_MANAGER_SOCKET = "GESTALT_WORKFLOW_MANAGER_SOCKET";
|
|
20
|
+
|
|
21
|
+
export type ManagedWorkflowScheduleMessage = ManagedWorkflowSchedule;
|
|
22
|
+
export type WorkflowManagerCreateScheduleInput = MessageInitShape<
|
|
23
|
+
typeof WorkflowManagerCreateScheduleRequestSchema
|
|
24
|
+
>;
|
|
25
|
+
export type WorkflowManagerGetScheduleInput = MessageInitShape<
|
|
26
|
+
typeof WorkflowManagerGetScheduleRequestSchema
|
|
27
|
+
>;
|
|
28
|
+
export type WorkflowManagerUpdateScheduleInput = MessageInitShape<
|
|
29
|
+
typeof WorkflowManagerUpdateScheduleRequestSchema
|
|
30
|
+
>;
|
|
31
|
+
export type WorkflowManagerDeleteScheduleInput = MessageInitShape<
|
|
32
|
+
typeof WorkflowManagerDeleteScheduleRequestSchema
|
|
33
|
+
>;
|
|
34
|
+
export type WorkflowManagerPauseScheduleInput = MessageInitShape<
|
|
35
|
+
typeof WorkflowManagerPauseScheduleRequestSchema
|
|
36
|
+
>;
|
|
37
|
+
export type WorkflowManagerResumeScheduleInput = MessageInitShape<
|
|
38
|
+
typeof WorkflowManagerResumeScheduleRequestSchema
|
|
39
|
+
>;
|
|
40
|
+
|
|
41
|
+
export class WorkflowManager {
|
|
42
|
+
private readonly client: Client<typeof WorkflowManagerHostService>;
|
|
43
|
+
private readonly invocationToken: string;
|
|
44
|
+
|
|
45
|
+
constructor(request: Request);
|
|
46
|
+
constructor(invocationToken: string);
|
|
47
|
+
constructor(requestOrToken: Request | string) {
|
|
48
|
+
this.invocationToken = normalizeInvocationToken(requestOrToken);
|
|
49
|
+
|
|
50
|
+
const socketPath = process.env[ENV_WORKFLOW_MANAGER_SOCKET];
|
|
51
|
+
if (!socketPath) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`workflow manager: ${ENV_WORKFLOW_MANAGER_SOCKET} is not set`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const transport = createGrpcTransport({
|
|
58
|
+
baseUrl: "http://localhost",
|
|
59
|
+
nodeOptions: {
|
|
60
|
+
createConnection: () => connect(socketPath),
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
this.client = createClient(WorkflowManagerHostService, transport);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async createSchedule(
|
|
67
|
+
request: WorkflowManagerCreateScheduleInput,
|
|
68
|
+
): Promise<ManagedWorkflowScheduleMessage> {
|
|
69
|
+
return await this.client.createSchedule({
|
|
70
|
+
...request,
|
|
71
|
+
invocationToken: this.invocationToken,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async getSchedule(
|
|
76
|
+
request: WorkflowManagerGetScheduleInput,
|
|
77
|
+
): Promise<ManagedWorkflowScheduleMessage> {
|
|
78
|
+
return await this.client.getSchedule({
|
|
79
|
+
...request,
|
|
80
|
+
invocationToken: this.invocationToken,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async updateSchedule(
|
|
85
|
+
request: WorkflowManagerUpdateScheduleInput,
|
|
86
|
+
): Promise<ManagedWorkflowScheduleMessage> {
|
|
87
|
+
return await this.client.updateSchedule({
|
|
88
|
+
...request,
|
|
89
|
+
invocationToken: this.invocationToken,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async deleteSchedule(
|
|
94
|
+
request: WorkflowManagerDeleteScheduleInput,
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
await this.client.deleteSchedule({
|
|
97
|
+
...request,
|
|
98
|
+
invocationToken: this.invocationToken,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async pauseSchedule(
|
|
103
|
+
request: WorkflowManagerPauseScheduleInput,
|
|
104
|
+
): Promise<ManagedWorkflowScheduleMessage> {
|
|
105
|
+
return await this.client.pauseSchedule({
|
|
106
|
+
...request,
|
|
107
|
+
invocationToken: this.invocationToken,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async resumeSchedule(
|
|
112
|
+
request: WorkflowManagerResumeScheduleInput,
|
|
113
|
+
): Promise<ManagedWorkflowScheduleMessage> {
|
|
114
|
+
return await this.client.resumeSchedule({
|
|
115
|
+
...request,
|
|
116
|
+
invocationToken: this.invocationToken,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function normalizeInvocationToken(requestOrToken: Request | string): string {
|
|
122
|
+
const invocationToken =
|
|
123
|
+
typeof requestOrToken === "string"
|
|
124
|
+
? requestOrToken
|
|
125
|
+
: requestOrToken.invocationToken;
|
|
126
|
+
const trimmed = invocationToken.trim();
|
|
127
|
+
if (!trimmed) {
|
|
128
|
+
throw new Error("workflow manager: invocation token is not available");
|
|
129
|
+
}
|
|
130
|
+
return trimmed;
|
|
131
|
+
}
|