@valon-technologies/gestalt 0.0.1-alpha.8 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valon-technologies/gestalt",
3
- "version": "0.0.1-alpha.8",
3
+ "version": "0.0.1-alpha.9",
4
4
  "description": "TypeScript SDK for Gestalt executable providers",
5
5
  "type": "module",
6
6
  "repository": {
@@ -29,6 +29,10 @@
29
29
  },
30
30
  "scripts": {
31
31
  "build:proto": "buf generate --template ../proto/buf.typescript.gen.yaml ../proto",
32
+ "docs:lint": "eslint --max-warnings=0 \"src/**/*.ts\" \"docs/entrypoints/**/*.ts\"",
33
+ "docs:build": "typedoc --options typedoc.json --out docs/_build/html",
34
+ "docs:build:deploy": "typedoc --options typedoc.json --out ../../docs/public/api/typescript",
35
+ "docs:check": "bun run docs:lint && bun run docs:build",
32
36
  "typecheck": "tsc --noEmit",
33
37
  "test": "bun test",
34
38
  "check": "bun test && tsc --noEmit"
@@ -40,7 +44,11 @@
40
44
  "yaml": "2.8.1"
41
45
  },
42
46
  "devDependencies": {
47
+ "@typescript-eslint/parser": "8.46.1",
43
48
  "@types/bun": "1.3.2",
49
+ "eslint": "9.38.0",
50
+ "eslint-plugin-tsdoc": "0.4.0",
51
+ "typedoc": "0.28.14",
44
52
  "typescript": "5.9.3"
45
53
  },
46
54
  "peerDependencies": {
package/src/api.ts CHANGED
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Common request and response types shared across authored Gestalt providers.
3
+ */
1
4
  export interface Subject {
2
5
  id: string;
3
6
  kind: string;
@@ -5,6 +8,9 @@ export interface Subject {
5
8
  authSource: string;
6
9
  }
7
10
 
11
+ /**
12
+ * Describes the credential Gestalt used to authorize the current request.
13
+ */
8
14
  export interface Credential {
9
15
  mode: string;
10
16
  subjectId: string;
@@ -12,34 +18,59 @@ export interface Credential {
12
18
  instance: string;
13
19
  }
14
20
 
21
+ /**
22
+ * Describes the access policy and effective role for the current request.
23
+ */
15
24
  export interface Access {
16
25
  policy: string;
17
26
  role: string;
18
27
  }
19
28
 
29
+ /**
30
+ * Request metadata forwarded to provider handlers by the Gestalt runtime.
31
+ */
20
32
  export interface Request {
21
33
  token: string;
22
34
  connectionParams: Record<string, string>;
23
35
  subject: Subject;
24
36
  credential: Credential;
25
37
  access: Access;
38
+ // Workflow callback metadata uses a JSON-style lowerCamelCase object such as
39
+ // runId, target.pluginName, trigger.scheduleId, and trigger.event.specVersion.
40
+ workflow: Record<string, unknown>;
41
+ invocationToken: string;
26
42
  }
27
43
 
44
+ /**
45
+ * Internal discriminator used by {@link response} and {@link ok}.
46
+ */
28
47
  export const responseBrand: unique symbol = Symbol("gestalt.response");
29
48
 
49
+ /**
50
+ * Explicit handler response with an optional HTTP status override.
51
+ */
30
52
  export interface Response<T> {
31
53
  readonly [responseBrand]: true;
32
54
  status?: number;
33
55
  body: T;
34
56
  }
35
57
 
58
+ /**
59
+ * Serialized operation result returned by the protocol runtime.
60
+ */
36
61
  export interface OperationResult {
37
62
  status: number;
38
63
  body: string;
39
64
  }
40
65
 
66
+ /**
67
+ * Value or promise-like return accepted by provider handlers.
68
+ */
41
69
  export type MaybePromise<T> = T | Promise<T>;
42
70
 
71
+ /**
72
+ * Wraps a handler result with an explicit status code.
73
+ */
43
74
  export function response<T>(status: number, body: T): Response<T> {
44
75
  return {
45
76
  [responseBrand]: true,
@@ -48,16 +79,31 @@ export function response<T>(status: number, body: T): Response<T> {
48
79
  };
49
80
  }
50
81
 
82
+ /**
83
+ * Wraps a handler result with the default `200` status code.
84
+ */
51
85
  export function ok<T>(body: T): Response<T> {
52
86
  return response(200, body);
53
87
  }
54
88
 
89
+ /**
90
+ * Creates a request object for local testing or direct provider invocation.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { request } from "@valon-technologies/gestalt";
95
+ *
96
+ * const input = request("token", { region: "us-east-1" }, { id: "usr_123" });
97
+ * ```
98
+ */
55
99
  export function request(
56
100
  token = "",
57
101
  connectionParams: Record<string, string> = {},
58
102
  subject: Partial<Subject> = {},
59
103
  credential: Partial<Credential> = {},
60
104
  access: Partial<Access> = {},
105
+ workflow: Record<string, unknown> = {},
106
+ invocationToken = "",
61
107
  ): Request {
62
108
  return {
63
109
  token,
@@ -80,9 +126,16 @@ export function request(
80
126
  policy: access.policy ?? "",
81
127
  role: access.role ?? "",
82
128
  },
129
+ workflow: {
130
+ ...workflow,
131
+ },
132
+ invocationToken,
83
133
  };
84
134
  }
85
135
 
136
+ /**
137
+ * Looks up a single connection parameter from a request.
138
+ */
86
139
  export function connectionParam(
87
140
  input: Request | undefined,
88
141
  name: string,
@@ -90,6 +143,9 @@ export function connectionParam(
90
143
  return input?.connectionParams[name];
91
144
  }
92
145
 
146
+ /**
147
+ * Normalizes unknown thrown values into a readable error message.
148
+ */
93
149
  export function errorMessage(error: unknown): string {
94
150
  if (error instanceof Error && error.message) {
95
151
  return error.message;
package/src/auth.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { RuntimeProvider, type RuntimeProviderOptions } from "./provider.ts";
2
2
  import type { MaybePromise } from "./api.ts";
3
3
 
4
+ /**
5
+ * Identity payload returned by an authentication provider after a successful
6
+ * login.
7
+ */
4
8
  export interface AuthenticatedUser {
5
9
  subject: string;
6
10
  email?: string;
@@ -10,6 +14,9 @@ export interface AuthenticatedUser {
10
14
  claims?: Record<string, string>;
11
15
  }
12
16
 
17
+ /**
18
+ * Input passed to an authentication provider's `beginLogin` handler.
19
+ */
13
20
  export interface BeginLoginRequest {
14
21
  callbackUrl: string;
15
22
  hostState: string;
@@ -17,22 +24,35 @@ export interface BeginLoginRequest {
17
24
  options: Record<string, string>;
18
25
  }
19
26
 
27
+ /**
28
+ * Response returned by an authentication provider's `beginLogin` handler.
29
+ */
20
30
  export interface BeginLoginResponse {
21
31
  authorizationUrl: string;
22
32
  providerState?: Uint8Array;
23
33
  }
24
34
 
35
+ /**
36
+ * Callback payload passed to an authentication provider's `completeLogin`
37
+ * handler.
38
+ */
25
39
  export interface CompleteLoginRequest {
26
40
  query: Record<string, string>;
27
41
  providerState: Uint8Array;
28
42
  callbackUrl: string;
29
43
  }
30
44
 
31
- export interface AuthSessionSettings {
45
+ /**
46
+ * Session TTL hints exposed by an authentication provider.
47
+ */
48
+ export interface AuthenticationSessionSettings {
32
49
  sessionTtlSeconds: number | bigint;
33
50
  }
34
51
 
35
- export interface AuthProviderOptions extends RuntimeProviderOptions {
52
+ /**
53
+ * Runtime hooks required to implement a Gestalt authentication provider.
54
+ */
55
+ export interface AuthenticationProviderOptions extends RuntimeProviderOptions {
36
56
  beginLogin: (
37
57
  request: BeginLoginRequest,
38
58
  ) => MaybePromise<BeginLoginResponse>;
@@ -42,18 +62,21 @@ export interface AuthProviderOptions extends RuntimeProviderOptions {
42
62
  validateExternalToken?: (
43
63
  token: string,
44
64
  ) => MaybePromise<AuthenticatedUser | null | undefined>;
45
- sessionSettings?: () => MaybePromise<AuthSessionSettings>;
65
+ sessionSettings?: () => MaybePromise<AuthenticationSessionSettings>;
46
66
  }
47
67
 
48
- export class AuthProvider extends RuntimeProvider {
49
- readonly kind = "auth" as const;
68
+ /**
69
+ * Authentication provider implementation consumed by the Gestalt runtime.
70
+ */
71
+ export class AuthenticationProvider extends RuntimeProvider {
72
+ readonly kind = "authentication" as const;
50
73
 
51
- private readonly beginLoginHandler: AuthProviderOptions["beginLogin"];
52
- private readonly completeLoginHandler: AuthProviderOptions["completeLogin"];
53
- private readonly validateExternalTokenHandler: AuthProviderOptions["validateExternalToken"];
54
- private readonly sessionSettingsHandler: AuthProviderOptions["sessionSettings"];
74
+ private readonly beginLoginHandler: AuthenticationProviderOptions["beginLogin"];
75
+ private readonly completeLoginHandler: AuthenticationProviderOptions["completeLogin"];
76
+ private readonly validateExternalTokenHandler: AuthenticationProviderOptions["validateExternalToken"];
77
+ private readonly sessionSettingsHandler: AuthenticationProviderOptions["sessionSettings"];
55
78
 
56
- constructor(options: AuthProviderOptions) {
79
+ constructor(options: AuthenticationProviderOptions) {
57
80
  super(options);
58
81
  this.beginLoginHandler = options.beginLogin;
59
82
  this.completeLoginHandler = options.completeLogin;
@@ -81,22 +104,50 @@ export class AuthProvider extends RuntimeProvider {
81
104
  return this.sessionSettingsHandler !== undefined;
82
105
  }
83
106
 
84
- async sessionSettings(): Promise<AuthSessionSettings | undefined> {
107
+ async sessionSettings(): Promise<AuthenticationSessionSettings | undefined> {
85
108
  return await this.sessionSettingsHandler?.();
86
109
  }
87
110
  }
88
111
 
89
- export function defineAuthProvider(options: AuthProviderOptions): AuthProvider {
90
- return new AuthProvider(options);
112
+ /**
113
+ * Creates an authentication provider with the standard Gestalt runtime
114
+ * contract.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * import { defineAuthenticationProvider } from "@valon-technologies/gestalt";
119
+ *
120
+ * export const authentication = defineAuthenticationProvider({
121
+ * displayName: "Example Authentication",
122
+ * async beginLogin(request) {
123
+ * return {
124
+ * authorizationUrl: new URL("/login", request.callbackUrl).toString(),
125
+ * };
126
+ * },
127
+ * async completeLogin() {
128
+ * return { subject: "usr_123", email: "user@example.com" };
129
+ * },
130
+ * });
131
+ * ```
132
+ */
133
+ export function defineAuthenticationProvider(
134
+ options: AuthenticationProviderOptions,
135
+ ): AuthenticationProvider {
136
+ return new AuthenticationProvider(options);
91
137
  }
92
138
 
93
- export function isAuthProvider(value: unknown): value is AuthProvider {
139
+ /**
140
+ * Runtime type guard for authentication providers loaded from user modules.
141
+ */
142
+ export function isAuthenticationProvider(
143
+ value: unknown,
144
+ ): value is AuthenticationProvider {
94
145
  return (
95
- value instanceof AuthProvider ||
146
+ value instanceof AuthenticationProvider ||
96
147
  (typeof value === "object" &&
97
148
  value !== null &&
98
149
  "kind" in value &&
99
- (value as { kind?: unknown }).kind === "auth" &&
150
+ String((value as { kind?: unknown }).kind ?? "") === "authentication" &&
100
151
  "beginLogin" in value &&
101
152
  "completeLogin" in value)
102
153
  );
package/src/build.ts CHANGED
@@ -3,11 +3,18 @@ import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { homedir, tmpdir } from "node:os";
4
4
  import { join, resolve } from "node:path";
5
5
 
6
+ import { defaultProviderExportNames } from "./provider-kind.ts";
6
7
  import { parseProviderTarget, resolveProviderModulePath, type ProviderTarget } from "./target.ts";
7
8
 
9
+ /**
10
+ * Command-line usage for the bundled build entrypoint.
11
+ */
8
12
  export const USAGE =
9
13
  "usage: bun run build.ts ROOT PROVIDER_TARGET OUTPUT PROVIDER_NAME GOOS GOARCH";
10
14
 
15
+ /**
16
+ * Parsed arguments for the build entrypoint.
17
+ */
11
18
  export type BuildArgs = {
12
19
  root: string;
13
20
  target: string;
@@ -15,8 +22,12 @@ export type BuildArgs = {
15
22
  providerName: string;
16
23
  goos: string;
17
24
  goarch: string;
25
+ compileTarget?: string;
18
26
  };
19
27
 
28
+ /**
29
+ * CLI entrypoint that compiles a provider into a standalone Bun executable.
30
+ */
20
31
  export async function main(argv: string[] = process.argv.slice(2)): Promise<number> {
21
32
  const args = parseBuildArgs(argv);
22
33
  if (!args) {
@@ -27,6 +38,9 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<numb
27
38
  return 0;
28
39
  }
29
40
 
41
+ /**
42
+ * Parses `gestalt-ts-build` CLI arguments.
43
+ */
30
44
  export function parseBuildArgs(argv: string[]): BuildArgs | undefined {
31
45
  if (argv.length !== 6) {
32
46
  return undefined;
@@ -41,6 +55,9 @@ export function parseBuildArgs(argv: string[]): BuildArgs | undefined {
41
55
  };
42
56
  }
43
57
 
58
+ /**
59
+ * Bundles a provider into a standalone executable for the requested target.
60
+ */
44
61
  export function buildProviderBinary(args: BuildArgs): void {
45
62
  const root = resolve(args.root);
46
63
  const outputPath = resolve(args.outputPath);
@@ -49,7 +66,13 @@ export function buildProviderBinary(args: BuildArgs): void {
49
66
 
50
67
  try {
51
68
  const wrapperPath = writeBundledWrapper(workDir, root, target, args.providerName);
52
- const bunCommand = bunBuildCommand(wrapperPath, outputPath, args.goos, args.goarch);
69
+ const bunCommand = bunBuildCommand(
70
+ wrapperPath,
71
+ outputPath,
72
+ args.goos,
73
+ args.goarch,
74
+ args.compileTarget,
75
+ );
53
76
  const result = spawnSync(bunCommand.command, bunCommand.args, {
54
77
  cwd: root,
55
78
  stdio: "inherit",
@@ -65,13 +88,15 @@ export function buildProviderBinary(args: BuildArgs): void {
65
88
  }
66
89
  }
67
90
 
68
- export const buildPluginBinary = buildProviderBinary;
69
-
91
+ /**
92
+ * Constructs the Bun command used to compile a provider binary.
93
+ */
70
94
  export function bunBuildCommand(
71
95
  wrapperPath: string,
72
96
  outputPath: string,
73
97
  goos: string,
74
98
  goarch: string,
99
+ compileTarget = bunTarget(goos, goarch),
75
100
  ): { command: string; args: string[] } {
76
101
  return {
77
102
  command: resolveBunExecutable(),
@@ -79,7 +104,7 @@ export function bunBuildCommand(
79
104
  "build",
80
105
  "--compile",
81
106
  "--target",
82
- bunTarget(goos, goarch),
107
+ compileTarget,
83
108
  "--outfile",
84
109
  outputPath,
85
110
  wrapperPath,
@@ -87,6 +112,9 @@ export function bunBuildCommand(
87
112
  };
88
113
  }
89
114
 
115
+ /**
116
+ * Maps a Go-style `GOOS` / `GOARCH` target into Bun's compile target format.
117
+ */
90
118
  export function bunTarget(goos: string, goarch: string): string {
91
119
  const key = `${goos}/${goarch}`;
92
120
  switch (key) {
@@ -95,9 +123,9 @@ export function bunTarget(goos: string, goarch: string): string {
95
123
  case "darwin/arm64":
96
124
  return "bun-darwin-arm64";
97
125
  case "linux/amd64":
98
- return "bun-linux-x64";
126
+ return "bun-linux-x64-musl";
99
127
  case "linux/arm64":
100
- return "bun-linux-arm64";
128
+ return "bun-linux-arm64-musl";
101
129
  case "windows/amd64":
102
130
  return "bun-windows-x64";
103
131
  case "windows/arm64":
@@ -133,21 +161,9 @@ await runBundledProvider(candidate, ${JSON.stringify(target.kind)}, ${JSON.strin
133
161
  }
134
162
 
135
163
  function defaultBundledCandidateExpression(kind: ProviderTarget["kind"]): string {
136
- switch (kind) {
137
- case "integration":
138
- return "bundledModule.provider ?? bundledModule.plugin ?? bundledModule.default";
139
- case "auth":
140
- return "bundledModule.auth ?? bundledModule.provider ?? bundledModule.default";
141
- case "cache":
142
- return "bundledModule.cache ?? bundledModule.provider ?? bundledModule.default";
143
- case "secrets":
144
- return "bundledModule.secrets ?? bundledModule.provider ?? bundledModule.default";
145
- case "s3":
146
- return "bundledModule.s3 ?? bundledModule.provider ?? bundledModule.default";
147
- case "telemetry":
148
- return "bundledModule.telemetry ?? bundledModule.provider ?? bundledModule.default";
149
- }
150
- throw new Error(`unsupported provider kind: ${kind satisfies never}`);
164
+ return [...defaultProviderExportNames(kind), "default"]
165
+ .map((exportName) => `Reflect.get(bundledModule, ${JSON.stringify(exportName)})`)
166
+ .join(" ?? ");
151
167
  }
152
168
 
153
169
  function resolveBunExecutable(): string {
package/src/cache.ts CHANGED
@@ -9,15 +9,24 @@ import type { MaybePromise } from "./api.ts";
9
9
 
10
10
  const ENV_CACHE_SOCKET = "GESTALT_CACHE_SOCKET";
11
11
 
12
+ /**
13
+ * Single cache entry used by batch cache APIs.
14
+ */
12
15
  export interface CacheEntry {
13
16
  key: string;
14
17
  value: Uint8Array;
15
18
  }
16
19
 
20
+ /**
21
+ * Optional TTL applied when setting cache values.
22
+ */
17
23
  export interface CacheSetOptions {
18
24
  ttlMs?: number;
19
25
  }
20
26
 
27
+ /**
28
+ * Runtime hooks required to implement a Gestalt cache provider.
29
+ */
21
30
  export interface CacheProviderOptions extends RuntimeProviderOptions {
22
31
  get: (key: string) => MaybePromise<Uint8Array | null | undefined>;
23
32
  set: (
@@ -35,6 +44,9 @@ export interface CacheProviderOptions extends RuntimeProviderOptions {
35
44
  deleteMany?: (keys: string[]) => MaybePromise<number | bigint>;
36
45
  }
37
46
 
47
+ /**
48
+ * Returns the environment variable name used to discover a cache socket.
49
+ */
38
50
  export function cacheSocketEnv(name?: string): string {
39
51
  const trimmed = name?.trim() ?? "";
40
52
  if (!trimmed) {
@@ -43,6 +55,17 @@ export function cacheSocketEnv(name?: string): string {
43
55
  return `${ENV_CACHE_SOCKET}_${trimmed.replace(/[^A-Za-z0-9]/gu, "_").toUpperCase()}`;
44
56
  }
45
57
 
58
+ /**
59
+ * Client for invoking a host-provided cache over the Gestalt transport.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * import { Cache } from "@valon-technologies/gestalt";
64
+ *
65
+ * const cache = new Cache();
66
+ * await cache.set("session", new TextEncoder().encode("hello"));
67
+ * ```
68
+ */
46
69
  export class Cache {
47
70
  private readonly client: Client<typeof CacheService>;
48
71
 
@@ -127,6 +150,9 @@ export class Cache {
127
150
  }
128
151
  }
129
152
 
153
+ /**
154
+ * Cache provider implementation consumed by the Gestalt runtime.
155
+ */
130
156
  export class CacheProvider extends RuntimeProvider {
131
157
  readonly kind = "cache" as const;
132
158
 
@@ -219,10 +245,16 @@ export class CacheProvider extends RuntimeProvider {
219
245
  }
220
246
  }
221
247
 
248
+ /**
249
+ * Creates a cache provider from standard CRUD handlers.
250
+ */
222
251
  export function defineCacheProvider(options: CacheProviderOptions): CacheProvider {
223
252
  return new CacheProvider(options);
224
253
  }
225
254
 
255
+ /**
256
+ * Runtime type guard for cache providers loaded from user modules.
257
+ */
226
258
  export function isCacheProvider(value: unknown): value is CacheProvider {
227
259
  return (
228
260
  value instanceof CacheProvider ||
package/src/catalog.ts CHANGED
@@ -4,6 +4,9 @@ import YAML from "yaml";
4
4
 
5
5
  import type { Schema } from "./schema.ts";
6
6
 
7
+ /**
8
+ * Query-style parameter metadata derived from a Gestalt schema.
9
+ */
7
10
  export interface CatalogParameter {
8
11
  name: string;
9
12
  type: string;
@@ -12,6 +15,9 @@ export interface CatalogParameter {
12
15
  default?: unknown;
13
16
  }
14
17
 
18
+ /**
19
+ * JSON-schema-like description used in provider catalogs.
20
+ */
15
21
  export interface CatalogSchema {
16
22
  type: string;
17
23
  description?: string;
@@ -21,6 +27,9 @@ export interface CatalogSchema {
21
27
  items?: CatalogSchema;
22
28
  }
23
29
 
30
+ /**
31
+ * Static operation metadata emitted by a provider catalog.
32
+ */
24
33
  export interface CatalogOperation {
25
34
  id: string;
26
35
  method: string;
@@ -35,6 +44,9 @@ export interface CatalogOperation {
35
44
  allowedRoles?: string[];
36
45
  }
37
46
 
47
+ /**
48
+ * Static provider catalog emitted to the Gestalt host.
49
+ */
38
50
  export interface Catalog {
39
51
  name?: string;
40
52
  displayName?: string;
@@ -43,6 +55,9 @@ export interface Catalog {
43
55
  operations: CatalogOperation[];
44
56
  }
45
57
 
58
+ /**
59
+ * Extracts top-level parameter metadata from an object schema.
60
+ */
46
61
  export function schemaToParameters(
47
62
  schema: Schema<unknown> | undefined,
48
63
  ): CatalogParameter[] {
@@ -67,6 +82,9 @@ export function schemaToParameters(
67
82
  });
68
83
  }
69
84
 
85
+ /**
86
+ * Converts a runtime schema into catalog-friendly metadata.
87
+ */
70
88
  export function schemaToCatalogSchema(
71
89
  schema: Schema<unknown> | undefined,
72
90
  ): CatalogSchema | undefined {
@@ -102,6 +120,9 @@ export function schemaToCatalogSchema(
102
120
  return output;
103
121
  }
104
122
 
123
+ /**
124
+ * Serializes a catalog to JSON for host consumption.
125
+ */
105
126
  export function catalogToJson(
106
127
  catalog: Catalog | Record<string, unknown> | null | undefined,
107
128
  ): string {
@@ -111,12 +132,18 @@ export function catalogToJson(
111
132
  return JSON.stringify(toCatalogJsonObject(catalog));
112
133
  }
113
134
 
135
+ /**
136
+ * Serializes a catalog to YAML for release artifacts.
137
+ */
114
138
  export function catalogToYaml(
115
139
  catalog: Catalog | Record<string, unknown>,
116
140
  ): string {
117
141
  return YAML.stringify(toCatalogJsonObject(catalog));
118
142
  }
119
143
 
144
+ /**
145
+ * Writes a catalog to disk as YAML.
146
+ */
120
147
  export function writeCatalogYaml(
121
148
  path: string,
122
149
  catalog: Catalog | Record<string, unknown>,