@pipedream/platform
Version:
Pipedream platform globals (typing and runtime type checking)
223 lines (200 loc) • 5.79 kB
text/typescript
import * as t from "io-ts";
import axios, { transformConfigForOauth } from "./axios";
import { AxiosRequestConfig as AxiosConfig } from "axios";
export {
axios, transformConfigForOauth,
};
export {
cloneSafe, jsonStringifySafe,
} from "./utils";
export {
getFileStreamAndMetadata,
getFileStream,
} from "./file-stream";
export type {
FileMetadata,
} from "./file-stream";
export {
ConfigurationError,
} from "./errors";
export {
default as sqlProp,
} from "./sql-prop";
export type {
ColumnSchema,
DbInfo,
TableInfo,
TableMetadata,
TableSchema,
} from "./sql-prop";
export {
default as sqlProxy,
} from "./sql-proxy";
export {
DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
PD_OFFICIAL_GMAIL_OAUTH_CLIENT_ID,
} from "./constants";
const SendPayload = t.union([
t.string,
t.object,
]);
type SendPayload = t.TypeOf<typeof SendPayload>;
export const SendConfigEmail = t.partial({
html: t.string,
subject: t.string,
text: t.string,
});
export type SendConfigEmail = t.TypeOf<typeof SendConfigEmail>;
export const SendConfigEmit_required = t.strict({
raw_event: t.object,
});
export const SendConfigEmit_optional = t.partial({
event: t.object,
});
export const SendConfigEmit = t.intersection([
SendConfigEmit_required,
SendConfigEmit_optional,
]);
export type SendConfigEmit = t.TypeOf<typeof SendConfigEmit>;
// interface SendConfigHTTPKv {
// [key: string]: string;
// }
const SendConfigHTTPKv = t.object; // XXX should be type above
type SendConfigHTTPKv = t.TypeOf<typeof SendConfigHTTPKv>;
const SendConfigHTTPAuth = t.strict({
password: t.string,
username: t.string,
});
type SendConfigHTTPAuth = t.TypeOf<typeof SendConfigHTTPAuth>;
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
export const HTTP_METHODS = [
"GET",
"HEAD",
"POST",
"PUT",
"DELETE",
"CONNECT",
"OPTIONS",
"TRACE",
"PATCH",
];
// HTTP method must be uppercase (for kotlin in coordinator -- i voted to make it case insensitive, but w.e for now)
const SendConfigHTTPMethod = t.keyof(HTTP_METHODS.reduce((acc, v) => {
acc[v] = null;
return acc;
}, {}));
type SendConfigHTTPMethod = t.TypeOf<typeof SendConfigHTTPMethod>;
const SendConfigHTTP_required = t.strict({
method: SendConfigHTTPMethod,
url: t.string,
});
const SendConfigHTTP_optional = t.partial({
auth: SendConfigHTTPAuth,
data: SendPayload,
headers: SendConfigHTTPKv,
params: SendConfigHTTPKv,
});
export const SendConfigHTTP = t.intersection([
SendConfigHTTP_required,
SendConfigHTTP_optional,
]);
// Mimics axios config. (for now)
export type SendConfigHTTP = t.TypeOf<typeof SendConfigHTTP>;
export const SendConfigS3 = t.strict({
bucket: t.string,
payload: SendPayload,
prefix: t.string,
});
export type SendConfigS3 = t.TypeOf<typeof SendConfigS3>;
export const SendConfigSQL = t.strict({
payload: SendPayload,
table: t.string,
});
export type SendConfigSQL = t.TypeOf<typeof SendConfigSQL>;
export const SendConfigSnowflake = t.strict({
account: t.string,
database: t.string,
host: t.string,
payload: SendPayload,
pipe_name: t.string,
private_key: t.string,
schema: t.string,
stage_name: t.string,
user: t.string,
});
export type SendConfigSnowflake = t.TypeOf<typeof SendConfigSnowflake>;
export const SendConfigSSE = t.strict({
channel: t.string,
payload: SendPayload,
});
export type SendConfigSSE = t.TypeOf<typeof SendConfigSSE>;
// optionals so we can use self-invoking function below
interface SendFunctionsWrapper {
email: (config: SendConfigEmail) => void;
emit: (config: SendConfigEmit) => void;
http: (config: SendConfigHTTP) => void;
s3: (config: SendConfigS3) => void;
sql: (config: SendConfigSQL) => void;
snowflake: (config: SendConfigSnowflake) => void;
sse: (config: SendConfigSSE) => void;
}
// XXX would be cool to have this and SendFunctionsWrapper be more shared
export const sendTypeMap = {
email: SendConfigEmail,
emit: SendConfigEmit,
http: SendConfigHTTP,
s3: SendConfigS3,
sql: SendConfigSQL,
snowflake: SendConfigSnowflake,
sse: SendConfigSSE,
};
// Event object that persists throughout worfklow with observability after each step.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export let $event: any;
export const END_NEEDLE = "__pd_end";
// End workflow with optional message.
export function $end(message?: string): void {
const err = new Error();
err[END_NEEDLE] = {
message,
ts: new Date().toISOString(),
};
throw err;
}
export let $send: SendFunctionsWrapper;
export const $sendConfigRuntimeTypeChecker = (function () {
const ret = {};
for (const [
sendName,
sendConfigType,
] of Object.entries(sendTypeMap)) {
ret[sendName] = function (config) {
const result = sendConfigType.decode(config);
if (!result) throw new Error("io-ts: unexpected decode output");
if (result._tag === "Left") {
for (const err of result.left) {
if (err.message) {
throw new Error(err.message);
} else {
const keyChunks: string[] = [];
for (const ctx of err.context) {
if (!ctx.key) continue;
if (!isNaN(+ctx.key)) continue;
keyChunks.push(ctx.key);
}
throw new Error(`$send.${sendName}: invalid value ${err.value} for ${keyChunks.join(".")}`);
}
}
throw new Error("io-ts: error but could not produce message"); // shouldn't happen...
}
// XXX if result !== config they passed extra fields... but expensive
};
}
return ret;
})();
export interface AxiosRequestConfig extends AxiosConfig {
debug?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
body?: any;
returnFullResponse?: boolean;
}