diff --git a/typegraph/node/sdk/src/runtimes/deno.ts b/typegraph/node/sdk/src/runtimes/deno.ts index 660e45e36..273ec2aee 100644 --- a/typegraph/node/sdk/src/runtimes/deno.ts +++ b/typegraph/node/sdk/src/runtimes/deno.ts @@ -44,14 +44,13 @@ export class DenoRuntime extends Runtime { } func< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, { code, secrets = [], effect = fx.read() }: DenoFunc, - ): t.Func { + ): t.Func { const matId = runtimes.registerDenoFunc({ code, secrets }, effect); const mat: FunMat = { _id: matId, @@ -63,14 +62,13 @@ export class DenoRuntime extends Runtime { } import< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, { name, module, effect = fx.read(), secrets = [] }: DenoImport, - ): t.Func { + ): t.Func { const matId = runtimes.importDenoFunction({ funcName: name, module, @@ -87,9 +85,8 @@ export class DenoRuntime extends Runtime { } identity< - P extends Record = Record, - I extends t.Struct

= t.Struct

, - >(inp: I): t.Func { + I extends t.Typedef = t.Typedef, + >(inp: I): t.Func { const mat: PredefinedFuncMat = { _id: runtimes.getPredefinedDenoFunc({ name: "identity" }), name: "identity", diff --git a/typegraph/node/sdk/src/runtimes/graphql.ts b/typegraph/node/sdk/src/runtimes/graphql.ts index 219e00c42..0c66eb433 100644 --- a/typegraph/node/sdk/src/runtimes/graphql.ts +++ b/typegraph/node/sdk/src/runtimes/graphql.ts @@ -15,10 +15,9 @@ export class GraphQLRuntime extends Runtime { } query< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, - >(inp: I, out: O, path?: string[]): t.Func { + >(inp: I, out: O, path?: string[]): t.Func { const matId = runtimes.graphqlQuery({ runtime: this._id, effect: fx.read(), @@ -33,15 +32,14 @@ export class GraphQLRuntime extends Runtime { } mutation< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, effect: Effect, path?: string[], - ): t.Func { + ): t.Func { const matId = runtimes.graphqlMutation({ runtime: this._id, effect, diff --git a/typegraph/node/sdk/src/runtimes/http.ts b/typegraph/node/sdk/src/runtimes/http.ts index 6ffe82b10..bb43cadea 100644 --- a/typegraph/node/sdk/src/runtimes/http.ts +++ b/typegraph/node/sdk/src/runtimes/http.ts @@ -33,8 +33,7 @@ export class HttpRuntime extends Runtime { #request< M extends HttpMethod, - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( method: M, @@ -42,7 +41,7 @@ export class HttpRuntime extends Runtime { out: O, options: Omit, effect: Effect, - ): t.Func { + ): t.Func { const matId = runtimes.httpRequest({ runtime: this._id, effect, @@ -57,66 +56,61 @@ export class HttpRuntime extends Runtime { } get< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, options: Omit, - ): t.Func { + ): t.Func { return this.#request("get", inp, out, options, fx.read()); } post< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, options: Omit, effect?: Effect, - ): t.Func { + ): t.Func { return this.#request("get", inp, out, options, effect ?? fx.create()); } put< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, options: Omit, effect?: Effect, - ): t.Func { + ): t.Func { return this.#request("get", inp, out, options, effect ?? fx.update()); } patch< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, options: Omit, effect?: Effect, - ): t.Func { + ): t.Func { return this.#request("patch", inp, out, options, effect ?? fx.update()); } delete_< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, options: Omit, effect?: Effect, - ): t.Func { + ): t.Func { return this.#request("get", inp, out, options, effect ?? fx.delete_()); } } diff --git a/typegraph/node/sdk/src/runtimes/python.ts b/typegraph/node/sdk/src/runtimes/python.ts index 63cfe00c4..51f840c40 100644 --- a/typegraph/node/sdk/src/runtimes/python.ts +++ b/typegraph/node/sdk/src/runtimes/python.ts @@ -85,14 +85,13 @@ export class PythonRuntime extends Runtime { } import< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, { name, module, effect = fx.read(), secrets = [] }: PythonImport, - ): t.Func { + ): t.Func { const base = { runtime: this._id, effect, diff --git a/typegraph/node/sdk/src/runtimes/wasmedge.ts b/typegraph/node/sdk/src/runtimes/wasmedge.ts index 7355b25de..76a636607 100644 --- a/typegraph/node/sdk/src/runtimes/wasmedge.ts +++ b/typegraph/node/sdk/src/runtimes/wasmedge.ts @@ -19,8 +19,7 @@ export class WasmEdgeRuntime extends Runtime { } wasi< - P extends Record = Record, - I extends t.Struct

= t.Struct

, + I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, @@ -30,7 +29,7 @@ export class WasmEdgeRuntime extends Runtime { wasm: string; effect?: Effect; }, - ): t.Func { + ): t.Func { const matId = runtimes.fromWasiModule( { runtime: this._id, diff --git a/typegraph/node/sdk/src/typegraph.ts b/typegraph/node/sdk/src/typegraph.ts index fd2d7b94c..73a021aa9 100644 --- a/typegraph/node/sdk/src/typegraph.ts +++ b/typegraph/node/sdk/src/typegraph.ts @@ -29,7 +29,37 @@ interface TypegraphArgs { disableAutoSerialization?: boolean; } -export interface TypegraphBuilderArgs { +export class ApplyFromArg { + constructor(public name: string | null) { } +} + +export class ApplyFromStatic { + constructor(public value: any) { } +} + +export class ApplyFromSecret { + constructor(public key: string) { } +} + +export class ApplyFromContext { + constructor(public key: string) { } +} + +export class ApplyFromParent { + constructor(public typeName: string) { } +} + +const InjectionSource = { + asArg: (name?: string) => new ApplyFromArg(name ?? null), + set: (value: any) => new ApplyFromStatic(value), + fromSecret: (key: string) => new ApplyFromSecret(key), + fromContext: (key: string) => new ApplyFromContext(key), + fromParent: (typeName: string) => new ApplyFromParent(typeName), +} as const; + +type InjectionSourceType = typeof InjectionSource; + +export interface TypegraphBuilderArgs extends InjectionSourceType { expose: (exports: Exports, defaultPolicy?: Policy) => void; inherit: () => InheritDef; rest: (graphql: string) => number; @@ -68,7 +98,7 @@ export class InheritDef { export type TypegraphBuilder = (g: TypegraphBuilderArgs) => void; export class RawAuth { - constructor(readonly jsonStr: string) {} + constructor(readonly jsonStr: string) { } } export interface TypegraphOutput { @@ -164,6 +194,7 @@ export function typegraph( ref: (name: string) => { return genRef(name); }, + ...InjectionSource, }; builder(g); diff --git a/typegraph/node/sdk/src/types.ts b/typegraph/node/sdk/src/types.ts index 430ac1661..2eafc31b8 100644 --- a/typegraph/node/sdk/src/types.ts +++ b/typegraph/node/sdk/src/types.ts @@ -14,6 +14,8 @@ import { TypeOptional, TypeString, TypeUnion, + TypeId, + ParameterTransform, } from "./gen/interfaces/metatype-typegraph-core.js"; import { Reduce } from "./gen/interfaces/metatype-typegraph-utils.js"; import { FuncParams } from "./gen/interfaces/metatype-typegraph-runtimes.js"; @@ -27,7 +29,7 @@ import { serializeStaticInjection, } from "./utils/injection_utils.js"; import { InjectionValue } from "./utils/type_utils.js"; -import { InheritDef } from "./typegraph.js"; +import { ApplyFromArg, ApplyFromContext, ApplyFromParent, ApplyFromSecret, ApplyFromStatic, InheritDef } from "./typegraph.js"; export type PolicySpec = Policy | PolicyPerEffectObject | { none: Policy; @@ -510,21 +512,57 @@ export function struct

( ); } +// `Record` does work... +type ApplyParamObjectNode = { + [key: string]: ApplyParamNode; +}; +type ApplyParamArrayNode = Array; +type ApplyParamLeafNode = ApplyFromArg | ApplyFromStatic | ApplyFromContext | ApplyFromSecret | ApplyFromParent; +type ApplyParamNode = ApplyParamObjectNode | ApplyParamArrayNode | ApplyParamLeafNode; + +function serializeApplyParamNode(node: ApplyParamNode): Record { + if (node instanceof ApplyFromArg) { + return { source: "arg", name: node.name }; + } else if (node instanceof ApplyFromStatic) { + return { source: "static", value: JSON.stringify(node.value) }; + } else if (node instanceof ApplyFromContext) { + return { source: "context", key: node.key }; + } else if (node instanceof ApplyFromSecret) { + return { source: "secret", key: node.key }; + } else if (node instanceof ApplyFromParent) { + return { source: "parent", typeName: node.typeName }; + } else if (Array.isArray(node)) { + return { + type: "array", + items: node.map(serializeApplyParamNode), + }; + } else if (typeof node === "object" && node !== null) { + return { + type: "object", + fields: mapValues(node, serializeApplyParamNode), + }; + } + throw new Error(`Unexpected node type: ${node}`); +} + export class Func< - P extends { [key: string]: Typedef } = Record, - I extends Struct

= Struct

, + I extends Typedef = Typedef, O extends Typedef = Typedef, M extends Materializer = Materializer, > extends Typedef { inp: I; out: O; mat: M; + parameterTransform: ParameterTransform | null; + config: FuncConfig | null; - constructor(_id: number, inp: I, out: O, mat: M) { + constructor(_id: number, inp: I, out: O, mat: M, parameterTransform: ParameterTransform | null = null, config: FuncConfig | null = null) { super(_id, {}); this.inp = inp; this.out = out; this.mat = mat; + this.parameterTransform = parameterTransform; + this.config = config; } reduce(value: Record) { @@ -538,19 +576,37 @@ export class Func< ); return func( - new Typedef(reducedId, {}) as Struct

, + new Typedef(reducedId, {}), this.out, this.mat, ); } + apply(value: ApplyParamObjectNode): Func { + const serialized = serializeApplyParamNode(value); + if (typeof serialized !== "object" || serialized == null || serialized.type !== "object") { + throw new Error("Invalid apply value: root must be an object"); + } + const transformTree = JSON.stringify(serialized.fields); + const transformData = core.getTransformData(this.inp._id, transformTree); + + return func( + new Typedef(transformData.queryInput, {}), + this.out, + this.mat, + transformData.parameterTransform, + this.config, + ) + } + rate( inp: { calls: boolean; weight?: number }, - ): Func { + ): Func { return func( this.inp, this.out, this.mat, + this.parameterTransform, { rateCalls: inp.calls ?? false, rateWeight: inp.weight }, ); } @@ -570,26 +626,31 @@ type FuncConfig = { }; export function func< - P extends { [key: string]: Typedef }, - I extends Struct

= Struct

, + I extends Typedef = Typedef, O extends Typedef = Typedef, M extends Materializer = Materializer, >( inp: I, out: O, mat: M, - { rateCalls = false, rateWeight = undefined }: FuncConfig = {}, + transformData: ParameterTransform | null = null, + config: FuncConfig | null = null, ) { - return new Func( + const rateCalls = config?.rateCalls ?? false; + const rateWeight = config?.rateWeight ?? undefined; + return new Func( core.funcb({ inp: inp._id, out: out._id, mat: mat._id, + parameterTransform: transformData ?? undefined, rateCalls, rateWeight, }) as number, inp, out, mat, + transformData, + config, ); }