@steadlake/run 0.2.0 → 0.3.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/adapters/generic.d.ts +23 -2
- package/dist/adapters/generic.d.ts.map +1 -1
- package/dist/adapters/generic.js +27 -4
- package/dist/adapters/next.d.ts +21 -2
- package/dist/adapters/next.d.ts.map +1 -1
- package/dist/adapters/next.js +25 -4
- package/dist/adapters/utils/register.d.ts +3 -0
- package/dist/adapters/utils/register.d.ts.map +1 -0
- package/dist/adapters/utils/register.js +18 -0
- package/dist/adapters/worker.d.ts +31 -0
- package/dist/adapters/worker.d.ts.map +1 -0
- package/dist/adapters/worker.js +41 -0
- package/dist/client.d.ts +11 -8
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +39 -20
- package/dist/default.d.ts +6 -0
- package/dist/default.d.ts.map +1 -0
- package/dist/default.js +13 -0
- package/dist/errors.d.ts +4 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -2
- package/dist/handler.d.ts +1 -1
- package/dist/handler.d.ts.map +1 -1
- package/dist/handler.js +19 -27
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/step.d.ts +6 -2
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +34 -22
- package/dist/task.d.ts +3 -2
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +14 -7
- package/dist/types.d.ts +42 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -7
- package/dist/adapters/register.d.ts +0 -3
- package/dist/adapters/register.d.ts.map +0 -1
- package/dist/adapters/register.js +0 -18
|
@@ -1,3 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { Steadlake } from "../client.js";
|
|
2
|
+
import type { Task } from "../types.js";
|
|
3
|
+
export interface HandlerOptions {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
tasks?: Task<unknown, unknown>[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Creates a generic fetch handler compatible with any framework that uses
|
|
9
|
+
* the standard Web API Request/Response interface (Hono, Fastify, Express, etc).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Hono
|
|
13
|
+
* import { createHandler } from '@steadlake/run/adapters/generic'
|
|
14
|
+
* import { sendEmail } from './tasks/send-email'
|
|
15
|
+
*
|
|
16
|
+
* const dewHandler = createHandler({
|
|
17
|
+
* baseUrl: process.env.APP_URL!,
|
|
18
|
+
* tasks: [sendEmail],
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* app.post('/api/steadlake', (c) => dewHandler(c.req.raw))
|
|
22
|
+
*/
|
|
23
|
+
export declare function createHandler(clientOrOptions: Steadlake | HandlerOptions, options?: HandlerOptions): (req: Request) => Promise<Response>;
|
|
3
24
|
//# sourceMappingURL=generic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic.d.ts","sourceRoot":"","sources":["../../src/adapters/generic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"generic.d.ts","sourceRoot":"","sources":["../../src/adapters/generic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;CACjC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,eAAe,EAAE,SAAS,GAAG,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,uCAWlG"}
|
package/dist/adapters/generic.js
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { getDefaultClient } from "../default.js";
|
|
2
|
+
import { registerWithRetry } from "./utils/register.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a generic fetch handler compatible with any framework that uses
|
|
5
|
+
* the standard Web API Request/Response interface (Hono, Fastify, Express, etc).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Hono
|
|
9
|
+
* import { createHandler } from '@steadlake/run/adapters/generic'
|
|
10
|
+
* import { sendEmail } from './tasks/send-email'
|
|
11
|
+
*
|
|
12
|
+
* const dewHandler = createHandler({
|
|
13
|
+
* baseUrl: process.env.APP_URL!,
|
|
14
|
+
* tasks: [sendEmail],
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* app.post('/api/steadlake', (c) => dewHandler(c.req.raw))
|
|
18
|
+
*/
|
|
19
|
+
export function createHandler(clientOrOptions, options) {
|
|
20
|
+
const isClient = clientOrOptions instanceof Object && "_registry" in clientOrOptions;
|
|
21
|
+
const c = isClient ? clientOrOptions : getDefaultClient();
|
|
22
|
+
const opts = isClient ? options : clientOrOptions;
|
|
23
|
+
for (const task of opts.tasks ?? []) {
|
|
24
|
+
c._registry.set(task.id, task);
|
|
25
|
+
}
|
|
26
|
+
registerWithRetry(c, opts.baseUrl);
|
|
27
|
+
return c._createHandler();
|
|
5
28
|
}
|
package/dist/adapters/next.d.ts
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { Steadlake } from "../client.js";
|
|
2
|
+
import type { Task } from "../types.js";
|
|
3
|
+
export interface NextHandlerOptions {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
tasks?: Task<unknown, unknown>[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Creates a route handler for Next.js App Router.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // app/api/steadlake/route.ts
|
|
12
|
+
* import { createNextHandler } from '@steadlake/run/adapters/next'
|
|
13
|
+
* import { sendEmail } from './tasks/send-email'
|
|
14
|
+
* import { processOrder } from './tasks/process-order'
|
|
15
|
+
*
|
|
16
|
+
* export const { POST } = createNextHandler({
|
|
17
|
+
* baseUrl: process.env.APP_URL!,
|
|
18
|
+
* tasks: [sendEmail, processOrder],
|
|
19
|
+
* })
|
|
20
|
+
*/
|
|
21
|
+
export declare function createNextHandler(clientOrOptions: Steadlake | NextHandlerOptions, options?: NextHandlerOptions): {
|
|
3
22
|
POST: (req: Request) => Promise<Response>;
|
|
4
23
|
};
|
|
5
24
|
//# sourceMappingURL=next.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../src/adapters/next.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../src/adapters/next.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,SAAS,GAAG,kBAAkB,EAAE,OAAO,CAAC,EAAE,kBAAkB;gBAWzF,OAAO;EAC5B"}
|
package/dist/adapters/next.js
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { getDefaultClient } from "../default.js";
|
|
2
|
+
import { registerWithRetry } from "./utils/register.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a route handler for Next.js App Router.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // app/api/steadlake/route.ts
|
|
8
|
+
* import { createNextHandler } from '@steadlake/run/adapters/next'
|
|
9
|
+
* import { sendEmail } from './tasks/send-email'
|
|
10
|
+
* import { processOrder } from './tasks/process-order'
|
|
11
|
+
*
|
|
12
|
+
* export const { POST } = createNextHandler({
|
|
13
|
+
* baseUrl: process.env.APP_URL!,
|
|
14
|
+
* tasks: [sendEmail, processOrder],
|
|
15
|
+
* })
|
|
16
|
+
*/
|
|
17
|
+
export function createNextHandler(clientOrOptions, options) {
|
|
18
|
+
const isClient = clientOrOptions instanceof Object && "_registry" in clientOrOptions;
|
|
19
|
+
const c = isClient ? clientOrOptions : getDefaultClient();
|
|
20
|
+
const opts = isClient ? options : clientOrOptions;
|
|
21
|
+
for (const task of opts.tasks ?? []) {
|
|
22
|
+
c._registry.set(task.id, task);
|
|
23
|
+
}
|
|
24
|
+
registerWithRetry(c, opts.baseUrl);
|
|
25
|
+
const handle = c._createHandler();
|
|
5
26
|
return { POST: (req) => handle(req) };
|
|
6
27
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/adapters/utils/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,SAAI,iBAoBxF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export async function registerWithRetry(client, baseUrl, attempts = 3) {
|
|
2
|
+
for (let i = 1; i <= attempts; i++) {
|
|
3
|
+
try {
|
|
4
|
+
await client._autoRegister(baseUrl);
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
catch (err) {
|
|
8
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9
|
+
if (i === attempts) {
|
|
10
|
+
console.error(`[steadlake] Auto-registration failed after ${attempts} attempts: ${msg}. Tasks will not be dispatched by DEW until registration succeeds.`);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const delay = 1000 * 2 ** (i - 1);
|
|
14
|
+
console.warn(`[steadlake] Auto-registration attempt ${i} failed, retrying in ${delay}ms: ${msg}`);
|
|
15
|
+
await new Promise((res) => setTimeout(res, delay));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Steadlake } from "../client.js";
|
|
2
|
+
import type { Task } from "../types.js";
|
|
3
|
+
export interface WorkerEnv {
|
|
4
|
+
STEADLAKE_API_KEY: string;
|
|
5
|
+
STEADLAKE_PROJECT_ID: string;
|
|
6
|
+
STEADLAKE_API_URL?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WorkerHandlerOptions {
|
|
9
|
+
tasks?: Task<unknown, unknown>[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates a handler for Cloudflare Workers.
|
|
13
|
+
* Reads STEADLAKE_API_KEY, STEADLAKE_PROJECT_ID from worker env bindings.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { createWorkerHandler } from '@steadlake/run/adapters/worker'
|
|
17
|
+
* import { sendEmail } from './tasks/send-email'
|
|
18
|
+
*
|
|
19
|
+
* const dewHandler = createWorkerHandler({ tasks: [sendEmail] })
|
|
20
|
+
*
|
|
21
|
+
* export default {
|
|
22
|
+
* fetch(req: Request, env: Env) {
|
|
23
|
+
* if (new URL(req.url).pathname === '/api/steadlake') {
|
|
24
|
+
* return dewHandler(req, env, env.WORKER_URL)
|
|
25
|
+
* }
|
|
26
|
+
* return app.fetch(req, env)
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
export declare function createWorkerHandler<TEnv extends WorkerEnv>(clientOrOptions?: Steadlake | WorkerHandlerOptions): (req: Request, env: TEnv, baseUrl: string) => Promise<Response>;
|
|
31
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/adapters/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,WAAW,SAAS;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,SAAS,SAAS,EACzD,eAAe,CAAC,EAAE,SAAS,GAAG,oBAAoB,IAEpC,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,SAAS,MAAM,KAAG,OAAO,CAAC,QAAQ,CAAC,CAoB1E"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Steadlake } from "../client.js";
|
|
2
|
+
import { configure, getDefaultClient } from "../default.js";
|
|
3
|
+
import { registerWithRetry } from "./utils/register.js";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a handler for Cloudflare Workers.
|
|
6
|
+
* Reads STEADLAKE_API_KEY, STEADLAKE_PROJECT_ID from worker env bindings.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { createWorkerHandler } from '@steadlake/run/adapters/worker'
|
|
10
|
+
* import { sendEmail } from './tasks/send-email'
|
|
11
|
+
*
|
|
12
|
+
* const dewHandler = createWorkerHandler({ tasks: [sendEmail] })
|
|
13
|
+
*
|
|
14
|
+
* export default {
|
|
15
|
+
* fetch(req: Request, env: Env) {
|
|
16
|
+
* if (new URL(req.url).pathname === '/api/steadlake') {
|
|
17
|
+
* return dewHandler(req, env, env.WORKER_URL)
|
|
18
|
+
* }
|
|
19
|
+
* return app.fetch(req, env)
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*/
|
|
23
|
+
export function createWorkerHandler(clientOrOptions) {
|
|
24
|
+
return async (req, env, baseUrl) => {
|
|
25
|
+
const isClient = clientOrOptions instanceof Steadlake;
|
|
26
|
+
const c = isClient ? clientOrOptions : getDefaultClient();
|
|
27
|
+
const opts = isClient ? undefined : clientOrOptions;
|
|
28
|
+
if (!isClient) {
|
|
29
|
+
configure({
|
|
30
|
+
apiKey: env.STEADLAKE_API_KEY,
|
|
31
|
+
projectId: env.STEADLAKE_PROJECT_ID,
|
|
32
|
+
apiUrl: env.STEADLAKE_API_URL,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
for (const task of opts?.tasks ?? []) {
|
|
36
|
+
c._registry.set(task.id, task);
|
|
37
|
+
}
|
|
38
|
+
await registerWithRetry(c, baseUrl);
|
|
39
|
+
return c._createHandler()(req);
|
|
40
|
+
};
|
|
41
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Task, TaskConfig } from "
|
|
3
|
-
export declare class
|
|
1
|
+
import { Steadlake as SteadlakeClient } from "@steadlake/core";
|
|
2
|
+
import type { Task, TaskConfig } from "./types.js";
|
|
3
|
+
export declare class Steadlake {
|
|
4
4
|
_registry: Map<string, Task<unknown, unknown>>;
|
|
5
|
-
_client:
|
|
6
|
-
_signingSecret?: string;
|
|
5
|
+
_client: SteadlakeClient;
|
|
7
6
|
_projectId: string;
|
|
7
|
+
_apiUrl?: string;
|
|
8
|
+
_apiKey: string;
|
|
8
9
|
_registrationLock: Promise<void> | null;
|
|
9
10
|
_registrationComplete: boolean;
|
|
10
11
|
constructor(config?: {
|
|
11
12
|
apiKey?: string;
|
|
12
13
|
apiUrl?: string;
|
|
13
|
-
signingSecret?: string;
|
|
14
14
|
projectId?: string;
|
|
15
15
|
});
|
|
16
16
|
task<TPayload = unknown, TResult = unknown>(config: TaskConfig<TPayload, TResult>): Task<TPayload, TResult>;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
sendEvent(runId: string, event: string, data?: unknown): Promise<void>;
|
|
18
|
+
resolveApproval(runId: string, stepId: string, approved: boolean, approvedBy?: string): Promise<void>;
|
|
19
|
+
_api(method: string, path: string, body?: unknown): Promise<unknown>;
|
|
20
|
+
_autoRegister(baseUrl?: string): Promise<void>;
|
|
21
|
+
init(baseUrl?: string): Promise<void>;
|
|
19
22
|
_createHandler(): (req: Request) => Promise<Response>;
|
|
20
23
|
}
|
|
21
24
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAG/D,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGnD,qBAAa,SAAS;IACrB,SAAS,sCAA6C;IACtD,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAQ;IAC/C,qBAAqB,UAAS;gBAElB,MAAM,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB;IAsBD,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACzC,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,GACnC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC;IAMpB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAcpE,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4D9C,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,cAAc;CAGd"}
|
package/dist/client.js
CHANGED
|
@@ -1,42 +1,60 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Steadlake as SteadlakeClient } from "@steadlake/core";
|
|
2
2
|
import { createHandler } from "./handler.js";
|
|
3
3
|
import { createTask } from "./task.js";
|
|
4
|
-
export class
|
|
4
|
+
export class Steadlake {
|
|
5
5
|
_registry = new Map();
|
|
6
6
|
_client;
|
|
7
|
-
_signingSecret;
|
|
8
7
|
_projectId;
|
|
8
|
+
_apiUrl;
|
|
9
|
+
_apiKey;
|
|
9
10
|
_registrationLock = null;
|
|
10
11
|
_registrationComplete = false;
|
|
11
12
|
constructor(config) {
|
|
12
|
-
const apiKey = config?.apiKey ?? process.env.
|
|
13
|
-
const apiUrl = config?.apiUrl ?? process.env.
|
|
14
|
-
const
|
|
15
|
-
const projectId = config?.projectId ?? process.env.STEPPLER_PROJECT_ID ?? "";
|
|
13
|
+
const apiKey = config?.apiKey ?? process.env.STEADLAKE_API_KEY ?? "";
|
|
14
|
+
const apiUrl = config?.apiUrl ?? process.env.STEADLAKE_API_URL;
|
|
15
|
+
const projectId = config?.projectId ?? process.env.STEADLAKE_PROJECT_ID ?? "";
|
|
16
16
|
if (!apiKey) {
|
|
17
|
-
console.warn("[
|
|
17
|
+
console.warn("[steadlake] No API key set — provide apiKey or set STEADLAKE_API_KEY");
|
|
18
18
|
}
|
|
19
19
|
if (!projectId) {
|
|
20
|
-
console.warn("[
|
|
20
|
+
console.warn("[steadlake] No project ID set — provide projectId or set STEADLAKE_PROJECT_ID");
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
this._signingSecret = signingSecret;
|
|
22
|
+
this._apiKey = apiKey;
|
|
23
|
+
this._apiUrl = apiUrl;
|
|
26
24
|
this._projectId = projectId;
|
|
27
|
-
this._client = new
|
|
25
|
+
this._client = new SteadlakeClient({
|
|
28
26
|
bearerAuth: apiKey,
|
|
29
27
|
...(apiUrl ? { serverURL: apiUrl } : {}),
|
|
30
28
|
});
|
|
31
29
|
}
|
|
32
30
|
task(config) {
|
|
33
|
-
const t = createTask(config, this._client);
|
|
31
|
+
const t = createTask(config, this._client, this);
|
|
34
32
|
this._registry.set(config.id, t);
|
|
35
33
|
return t;
|
|
36
34
|
}
|
|
37
|
-
async
|
|
35
|
+
async sendEvent(runId, event, data) {
|
|
36
|
+
await this._api("POST", `/v1/runs/${runId}/events`, { event, data });
|
|
37
|
+
}
|
|
38
|
+
async resolveApproval(runId, stepId, approved, approvedBy) {
|
|
39
|
+
await this._api("POST", `/v1/runs/${runId}/approve`, { stepId, approved, approvedBy });
|
|
40
|
+
}
|
|
41
|
+
async _api(method, path, body) {
|
|
42
|
+
const baseUrl = this._apiUrl ?? "https://api.warplake.com";
|
|
43
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
44
|
+
method,
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
48
|
+
},
|
|
49
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok)
|
|
52
|
+
throw new Error(`API ${method} ${path} failed: ${res.status}`);
|
|
53
|
+
return res.json();
|
|
54
|
+
}
|
|
55
|
+
async _autoRegister(baseUrl) {
|
|
38
56
|
if (!this._projectId) {
|
|
39
|
-
console.warn("[
|
|
57
|
+
console.warn("[steadlake] No projectId set — skipping auto-registration");
|
|
40
58
|
return;
|
|
41
59
|
}
|
|
42
60
|
if (this._registrationLock) {
|
|
@@ -79,16 +97,17 @@ export class Steppler {
|
|
|
79
97
|
});
|
|
80
98
|
await this._client.triggers.register({
|
|
81
99
|
projectId: this._projectId,
|
|
100
|
+
...(baseUrl ? { apiUrl: baseUrl } : {}),
|
|
82
101
|
triggers,
|
|
83
102
|
});
|
|
84
103
|
this._registrationComplete = true;
|
|
85
104
|
})();
|
|
86
105
|
await this._registrationLock;
|
|
87
106
|
}
|
|
88
|
-
async init() {
|
|
89
|
-
await this._autoRegister();
|
|
107
|
+
async init(baseUrl) {
|
|
108
|
+
await this._autoRegister(baseUrl);
|
|
90
109
|
}
|
|
91
110
|
_createHandler() {
|
|
92
|
-
return createHandler(this._registry
|
|
111
|
+
return createHandler(this._registry);
|
|
93
112
|
}
|
|
94
113
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Steadlake } from "./client.js";
|
|
2
|
+
import type { TaskConfig, Task } from "./types.js";
|
|
3
|
+
export declare function getDefaultClient(): Steadlake;
|
|
4
|
+
export declare function configure(config: ConstructorParameters<typeof Steadlake>[0]): void;
|
|
5
|
+
export declare function task<TPayload = unknown, TResult = unknown>(config: TaskConfig<TPayload, TResult>): Task<TPayload, TResult>;
|
|
6
|
+
//# sourceMappingURL=default.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../src/default.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,gBAAgB,IAAI,SAAS,CAG5C;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAElF;AAED,wBAAgB,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACzD,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,GACnC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAEzB"}
|
package/dist/default.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Steadlake } from "./client.js";
|
|
2
|
+
let _default = null;
|
|
3
|
+
export function getDefaultClient() {
|
|
4
|
+
if (!_default)
|
|
5
|
+
_default = new Steadlake();
|
|
6
|
+
return _default;
|
|
7
|
+
}
|
|
8
|
+
export function configure(config) {
|
|
9
|
+
_default = new Steadlake(config);
|
|
10
|
+
}
|
|
11
|
+
export function task(config) {
|
|
12
|
+
return getDefaultClient().task(config);
|
|
13
|
+
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export declare class FatalError extends Error {
|
|
2
2
|
constructor(message: string);
|
|
3
3
|
}
|
|
4
|
-
export declare class
|
|
4
|
+
export declare class RetryableError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class SteadlakeError extends Error {
|
|
5
8
|
constructor(message: string);
|
|
6
9
|
}
|
|
7
10
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI3B;AAED,qBAAa,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI3B;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI3B;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI3B"}
|
package/dist/errors.js
CHANGED
|
@@ -4,9 +4,15 @@ export class FatalError extends Error {
|
|
|
4
4
|
this.name = "FatalError";
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
-
export class
|
|
7
|
+
export class RetryableError extends Error {
|
|
8
8
|
constructor(message) {
|
|
9
9
|
super(message);
|
|
10
|
-
this.name = "
|
|
10
|
+
this.name = "RetryableError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class SteadlakeError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "SteadlakeError";
|
|
11
17
|
}
|
|
12
18
|
}
|
package/dist/handler.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Task } from "./types.js";
|
|
2
|
-
export declare function createHandler(registry: Map<string, Task<unknown, unknown
|
|
2
|
+
export declare function createHandler(registry: Map<string, Task<unknown, unknown>>): (req: Request) => Promise<Response>;
|
|
3
3
|
//# sourceMappingURL=handler.d.ts.map
|
package/dist/handler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAoB,MAAM,YAAY,CAAC;AAEzD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAC7C,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAkE7D"}
|
package/dist/handler.js
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FatalError } from "./errors.js";
|
|
1
|
+
import { FatalError, RetryableError } from "./errors.js";
|
|
3
2
|
import { createStepHelpers } from "./step.js";
|
|
4
|
-
export function createHandler(registry
|
|
3
|
+
export function createHandler(registry) {
|
|
5
4
|
return async function handle(req) {
|
|
6
5
|
const body = await req.text();
|
|
7
|
-
if (signingSecret) {
|
|
8
|
-
const signature = req.headers.get("X-Steppler-Signature");
|
|
9
|
-
const expected = `sha256=${sign(body, signingSecret)}`;
|
|
10
|
-
if (signature !== expected) {
|
|
11
|
-
return new Response("Unauthorized", { status: 401 });
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
6
|
let parsed;
|
|
15
7
|
try {
|
|
16
8
|
parsed = JSON.parse(body);
|
|
@@ -21,41 +13,41 @@ export function createHandler(registry, signingSecret) {
|
|
|
21
13
|
const { runId, handler, payload, attempt = 1, state = {} } = parsed;
|
|
22
14
|
const task = registry.get(handler);
|
|
23
15
|
if (!task) {
|
|
24
|
-
return new Response(`No handler registered for "${handler}"`, {
|
|
25
|
-
status: 404,
|
|
26
|
-
});
|
|
16
|
+
return new Response(`No handler registered for "${handler}"`, { status: 404 });
|
|
27
17
|
}
|
|
28
18
|
if (task._config.schema) {
|
|
29
19
|
const result = task._config.schema.safeParse(payload);
|
|
30
20
|
if (!result.success) {
|
|
31
|
-
return
|
|
32
|
-
error: "Payload validation failed",
|
|
33
|
-
issues: result.error.issues,
|
|
34
|
-
}), { status: 400, headers: { "Content-Type": "application/json" } });
|
|
21
|
+
return Response.json({ error: "Payload validation failed", issues: result.error.issues }, { status: 400 });
|
|
35
22
|
}
|
|
36
23
|
}
|
|
37
24
|
const pendingEvents = [];
|
|
38
|
-
const
|
|
25
|
+
const emittedEvents = [];
|
|
26
|
+
const step = createStepHelpers(state, pendingEvents, emittedEvents, task._config.hooks);
|
|
39
27
|
try {
|
|
40
28
|
const result = await task._config.run({ payload, runId, attempt, step });
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
events: pendingEvents,
|
|
44
|
-
}, { status: 200 });
|
|
29
|
+
task._config.hooks?.onComplete?.(result);
|
|
30
|
+
return Response.json({ result, events: pendingEvents, emittedEvents }, { status: 200 });
|
|
45
31
|
}
|
|
46
32
|
catch (err) {
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
return Response.json({ suspend: true,
|
|
33
|
+
if (isSuspension(err)) {
|
|
34
|
+
task._config.hooks?.onSuspend?.(err.step, err.reason);
|
|
35
|
+
return Response.json({ suspend: true, step: err.step, reason: err.reason, events: pendingEvents, emittedEvents }, { status: 202 });
|
|
50
36
|
}
|
|
51
37
|
if (err instanceof FatalError) {
|
|
38
|
+
task._config.hooks?.onError?.(err, attempt);
|
|
52
39
|
return Response.json({ error: err.message, runId, fatal: true }, { status: 400 });
|
|
53
40
|
}
|
|
41
|
+
if (err instanceof RetryableError) {
|
|
42
|
+
task._config.hooks?.onError?.(err, attempt);
|
|
43
|
+
return Response.json({ error: err.message, runId, fatal: false, retryable: true }, { status: 500 });
|
|
44
|
+
}
|
|
54
45
|
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
task._config.hooks?.onError?.(err instanceof Error ? err : new Error(message), attempt);
|
|
55
47
|
return Response.json({ error: message, runId, fatal: false }, { status: 500 });
|
|
56
48
|
}
|
|
57
49
|
};
|
|
58
50
|
}
|
|
59
|
-
function
|
|
60
|
-
return
|
|
51
|
+
function isSuspension(err) {
|
|
52
|
+
return typeof err === "object" && err !== null && "__steadlake_suspend" in err;
|
|
61
53
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { createHandler } from "
|
|
2
|
-
export { createNextHandler } from "
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export
|
|
1
|
+
export { createHandler } from "./adapters/generic.js";
|
|
2
|
+
export { createNextHandler } from "./adapters/next.js";
|
|
3
|
+
export { Steadlake } from "./client.js";
|
|
4
|
+
export { task, configure, getDefaultClient } from "./default.js";
|
|
5
|
+
export { FatalError, RetryableError, SteadlakeError } from "./errors.js";
|
|
6
|
+
export type { Run, RunContext, RunResult, RunStatus, StepHelpers, SuspendReason, SuspensionSignal, Task, TaskConfig, TaskHooks, TriggerOptions, } from "./types.js";
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,YAAY,EACX,GAAG,EACH,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,IAAI,EACJ,UAAU,EACV,SAAS,EACT,cAAc,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createHandler } from "./adapters/generic.js";
|
|
2
2
|
export { createNextHandler } from "./adapters/next.js";
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
3
|
+
export { Steadlake } from "./client.js";
|
|
4
|
+
export { task, configure, getDefaultClient } from "./default.js";
|
|
5
|
+
export { FatalError, RetryableError, SteadlakeError } from "./errors.js";
|
package/dist/step.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type { StepHelpers } from "./types.js";
|
|
1
|
+
import type { StepHelpers, TaskHooks } from "./types.js";
|
|
2
2
|
export type PendingEvent = {
|
|
3
3
|
type: string;
|
|
4
4
|
metadata: Record<string, unknown>;
|
|
5
5
|
};
|
|
6
|
-
export
|
|
6
|
+
export type EmittedEvent = {
|
|
7
|
+
event: string;
|
|
8
|
+
data: unknown;
|
|
9
|
+
};
|
|
10
|
+
export declare function createStepHelpers(state: Record<string, unknown>, pendingEvents: PendingEvent[], emittedEvents: EmittedEvent[], hooks?: TaskHooks): StepHelpers;
|
|
7
11
|
//# sourceMappingURL=step.d.ts.map
|
package/dist/step.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAmC,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1F,MAAM,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACd,CAAC;AAMF,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,aAAa,EAAE,YAAY,EAAE,EAC7B,aAAa,EAAE,YAAY,EAAE,EAC7B,KAAK,CAAC,EAAE,SAAS,GACf,WAAW,CA4Cb"}
|
package/dist/step.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
function suspend(step, reason) {
|
|
2
|
+
throw { __steadlake_suspend: true, step, reason };
|
|
3
|
+
}
|
|
4
|
+
export function createStepHelpers(state, pendingEvents, emittedEvents, hooks) {
|
|
2
5
|
return {
|
|
3
6
|
async run(id, fn) {
|
|
4
|
-
if (id in state)
|
|
7
|
+
if (id in state)
|
|
5
8
|
return state[id];
|
|
6
|
-
|
|
9
|
+
// Persist step_started BEFORE executing fn — protects against double-execution
|
|
10
|
+
// on replay if process crashes mid-step (at-least-once guarantee)
|
|
7
11
|
pendingEvents.push({ type: "step_started", metadata: { step: id } });
|
|
8
12
|
const output = await fn();
|
|
9
|
-
pendingEvents.push({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
13
|
+
pendingEvents.push({ type: "step_completed", metadata: { step: id, output } });
|
|
14
|
+
state[id] = output;
|
|
15
|
+
hooks?.onStepComplete?.(id, output);
|
|
13
16
|
return output;
|
|
14
17
|
},
|
|
15
18
|
async sleep(id, duration) {
|
|
@@ -17,26 +20,35 @@ export function createStepHelpers(state, pendingEvents) {
|
|
|
17
20
|
return;
|
|
18
21
|
const ms = parseDuration(duration);
|
|
19
22
|
const resumeAt = new Date(Date.now() + ms).toISOString();
|
|
20
|
-
pendingEvents.push({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
pendingEvents.push({ type: "step_completed", metadata: { step: id, output: null } });
|
|
24
|
+
suspend(id, { type: "sleep", resumeAt });
|
|
25
|
+
},
|
|
26
|
+
async sleepUntil(id, date) {
|
|
27
|
+
if (id in state)
|
|
28
|
+
return;
|
|
29
|
+
const resumeAt = typeof date === "string" ? date : date.toISOString();
|
|
30
|
+
pendingEvents.push({ type: "step_completed", metadata: { step: id, output: null } });
|
|
31
|
+
suspend(id, { type: "sleepUntil", resumeAt });
|
|
32
|
+
},
|
|
33
|
+
async waitForEvent(id, opts) {
|
|
34
|
+
if (id in state)
|
|
35
|
+
return state[id];
|
|
36
|
+
suspend(id, { type: "waitForEvent", event: opts.event, timeout: opts.timeout });
|
|
37
|
+
},
|
|
38
|
+
async approve(id, opts) {
|
|
39
|
+
if (id in state)
|
|
40
|
+
return state[id];
|
|
41
|
+
suspend(id, { type: "approve", title: opts?.title, timeout: opts?.timeout });
|
|
42
|
+
},
|
|
43
|
+
emit(event, data) {
|
|
44
|
+
emittedEvents.push({ event, data });
|
|
25
45
|
},
|
|
26
46
|
};
|
|
27
47
|
}
|
|
28
48
|
function parseDuration(duration) {
|
|
29
|
-
const units = {
|
|
30
|
-
ms: 1,
|
|
31
|
-
s: 1000,
|
|
32
|
-
m: 60_000,
|
|
33
|
-
h: 3_600_000,
|
|
34
|
-
d: 86_400_000,
|
|
35
|
-
};
|
|
49
|
+
const units = { ms: 1, s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 };
|
|
36
50
|
const match = duration.match(/^(\d+)(ms|s|m|h|d)$/);
|
|
37
51
|
if (!match)
|
|
38
52
|
throw new Error(`Invalid duration format: "${duration}". Use e.g. "30s", "5m", "2h"`);
|
|
39
|
-
|
|
40
|
-
const unit = match[2];
|
|
41
|
-
return value * units[unit];
|
|
53
|
+
return parseInt(match[1], 10) * units[match[2]];
|
|
42
54
|
}
|
package/dist/task.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Steadlake as SteadlakeClient } from "@steadlake/core";
|
|
2
2
|
import type { Task, TaskConfig } from "./types.js";
|
|
3
|
-
|
|
3
|
+
import type { Steadlake } from "./client.js";
|
|
4
|
+
export declare function createTask<TPayload, TResult>(config: TaskConfig<TPayload, TResult>, client: SteadlakeClient, steadlake: Steadlake): Task<TPayload, TResult>;
|
|
4
5
|
//# sourceMappingURL=task.d.ts.map
|
package/dist/task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,KAAK,EAAkB,IAAI,EAAE,UAAU,EAAkB,MAAM,YAAY,CAAC;AAEnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM7C,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAC3C,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,EACrC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,SAAS,GAClB,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAoFzB"}
|
package/dist/task.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SteadlakeError } from "./errors.js";
|
|
2
2
|
function sleep(ms) {
|
|
3
3
|
return new Promise((res) => setTimeout(res, ms));
|
|
4
4
|
}
|
|
5
|
-
export function createTask(config, client) {
|
|
5
|
+
export function createTask(config, client, steadlake) {
|
|
6
6
|
return {
|
|
7
7
|
id: config.id,
|
|
8
8
|
_config: config,
|
|
@@ -22,7 +22,7 @@ export function createTask(config, client) {
|
|
|
22
22
|
}
|
|
23
23
|
catch (err) {
|
|
24
24
|
const msg = err instanceof Error ? err.message : String(err);
|
|
25
|
-
throw new
|
|
25
|
+
throw new SteadlakeError(`Failed to trigger task "${config.id}": ${msg}. Check your STEADLAKE_API_KEY and network connectivity.`);
|
|
26
26
|
}
|
|
27
27
|
return {
|
|
28
28
|
id: run.id,
|
|
@@ -35,9 +35,12 @@ export function createTask(config, client) {
|
|
|
35
35
|
}
|
|
36
36
|
catch (err) {
|
|
37
37
|
const msg = err instanceof Error ? err.message : String(err);
|
|
38
|
-
throw new
|
|
38
|
+
throw new SteadlakeError(`Failed to cancel run "${run.id}": ${msg}`);
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
+
sendEvent: async (event, data) => {
|
|
42
|
+
await steadlake.sendEvent(run.id, event, data);
|
|
43
|
+
},
|
|
41
44
|
};
|
|
42
45
|
},
|
|
43
46
|
async triggerAndWait(payload, options = {}) {
|
|
@@ -45,13 +48,13 @@ export function createTask(config, client) {
|
|
|
45
48
|
const deadline = options.timeoutMs ? Date.now() + options.timeoutMs : null;
|
|
46
49
|
while (true) {
|
|
47
50
|
if (deadline && Date.now() > deadline) {
|
|
48
|
-
throw new
|
|
51
|
+
throw new SteadlakeError(`triggerAndWait timed out after ${options.timeoutMs}ms (run ${run.id} is ${run.status})`);
|
|
49
52
|
}
|
|
50
53
|
let status;
|
|
51
54
|
try {
|
|
52
55
|
status = await client.runs.status({ id: run.id });
|
|
53
56
|
}
|
|
54
|
-
catch
|
|
57
|
+
catch {
|
|
55
58
|
await sleep(1000 + Math.random() * 500);
|
|
56
59
|
continue;
|
|
57
60
|
}
|
|
@@ -64,7 +67,11 @@ export function createTask(config, client) {
|
|
|
64
67
|
finishedAt: status.finishedAt ?? null,
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
|
-
|
|
70
|
+
// pending, running, suspended — keep polling, but back off more for suspended
|
|
71
|
+
const pollInterval = status.status === "suspended"
|
|
72
|
+
? 5000 + Math.random() * 1000
|
|
73
|
+
: 800 + Math.random() * 500;
|
|
74
|
+
await sleep(pollInterval);
|
|
68
75
|
}
|
|
69
76
|
},
|
|
70
77
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ZodSchema } from "zod";
|
|
2
|
-
export type RunStatus = "pending" | "running" | "success" | "failed";
|
|
2
|
+
export type RunStatus = "pending" | "running" | "suspended" | "success" | "failed";
|
|
3
3
|
export type Run = {
|
|
4
4
|
id: string;
|
|
5
5
|
status: RunStatus;
|
|
6
6
|
triggerId: string;
|
|
7
7
|
createdAt: string;
|
|
8
8
|
cancel: () => Promise<void>;
|
|
9
|
+
sendEvent: (event: string, data?: unknown) => Promise<void>;
|
|
9
10
|
};
|
|
10
11
|
export type RunResult = {
|
|
11
12
|
id: string;
|
|
@@ -25,6 +26,19 @@ export type TriggerOptions = {
|
|
|
25
26
|
export type StepHelpers = {
|
|
26
27
|
run: <T>(id: string, fn: () => Promise<T>) => Promise<T>;
|
|
27
28
|
sleep: (id: string, duration: string) => Promise<void>;
|
|
29
|
+
sleepUntil: (id: string, date: Date | string) => Promise<void>;
|
|
30
|
+
waitForEvent: <T = unknown>(id: string, opts: {
|
|
31
|
+
event: string;
|
|
32
|
+
timeout?: string;
|
|
33
|
+
}) => Promise<T>;
|
|
34
|
+
approve: (id: string, opts?: {
|
|
35
|
+
title?: string;
|
|
36
|
+
timeout?: string;
|
|
37
|
+
}) => Promise<{
|
|
38
|
+
approved: boolean;
|
|
39
|
+
approvedBy?: string;
|
|
40
|
+
}>;
|
|
41
|
+
emit: (event: string, data: unknown) => void;
|
|
28
42
|
};
|
|
29
43
|
export type RunContext<TPayload = unknown> = {
|
|
30
44
|
payload: TPayload;
|
|
@@ -32,6 +46,12 @@ export type RunContext<TPayload = unknown> = {
|
|
|
32
46
|
attempt: number;
|
|
33
47
|
step: StepHelpers;
|
|
34
48
|
};
|
|
49
|
+
export type TaskHooks = {
|
|
50
|
+
onStepComplete?: (stepId: string, result: unknown) => void;
|
|
51
|
+
onSuspend?: (stepId: string, reason: SuspendReason) => void;
|
|
52
|
+
onComplete?: (result: unknown) => void;
|
|
53
|
+
onError?: (error: Error, attempt: number) => void;
|
|
54
|
+
};
|
|
35
55
|
export type TaskConfig<TPayload = unknown, TResult = unknown> = {
|
|
36
56
|
id: string;
|
|
37
57
|
name?: string;
|
|
@@ -56,6 +76,7 @@ export type TaskConfig<TPayload = unknown, TResult = unknown> = {
|
|
|
56
76
|
maxTimeoutInMs?: number;
|
|
57
77
|
};
|
|
58
78
|
timeout?: number;
|
|
79
|
+
hooks?: TaskHooks;
|
|
59
80
|
run: (context: RunContext<TPayload>) => Promise<TResult>;
|
|
60
81
|
};
|
|
61
82
|
export type Task<TPayload = unknown, TResult = unknown> = {
|
|
@@ -64,4 +85,24 @@ export type Task<TPayload = unknown, TResult = unknown> = {
|
|
|
64
85
|
trigger: (payload: TPayload, options?: TriggerOptions) => Promise<Run>;
|
|
65
86
|
triggerAndWait: (payload: TPayload, options?: TriggerOptions) => Promise<RunResult>;
|
|
66
87
|
};
|
|
88
|
+
export type SuspendReason = {
|
|
89
|
+
type: "sleep";
|
|
90
|
+
resumeAt: string;
|
|
91
|
+
} | {
|
|
92
|
+
type: "sleepUntil";
|
|
93
|
+
resumeAt: string;
|
|
94
|
+
} | {
|
|
95
|
+
type: "waitForEvent";
|
|
96
|
+
event: string;
|
|
97
|
+
timeout?: string;
|
|
98
|
+
} | {
|
|
99
|
+
type: "approve";
|
|
100
|
+
title?: string;
|
|
101
|
+
timeout?: string;
|
|
102
|
+
};
|
|
103
|
+
export type SuspensionSignal = {
|
|
104
|
+
__steadlake_suspend: true;
|
|
105
|
+
step: string;
|
|
106
|
+
reason: SuspendReason;
|
|
107
|
+
};
|
|
67
108
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steadlake/run",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Durable task execution SDK for Steadlake — define tasks with steps, retries, scheduling, and event-driven workflows.",
|
|
4
5
|
"files": [
|
|
5
6
|
"dist"
|
|
6
7
|
],
|
|
@@ -12,13 +13,17 @@
|
|
|
12
13
|
"import": "./dist/index.js",
|
|
13
14
|
"types": "./dist/index.d.ts"
|
|
14
15
|
},
|
|
15
|
-
"./next": {
|
|
16
|
+
"./adapters/next": {
|
|
16
17
|
"import": "./dist/adapters/next.js",
|
|
17
18
|
"types": "./dist/adapters/next.d.ts"
|
|
18
19
|
},
|
|
19
|
-
"./
|
|
20
|
+
"./adapters/generic": {
|
|
20
21
|
"import": "./dist/adapters/generic.js",
|
|
21
22
|
"types": "./dist/adapters/generic.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./adapters/worker": {
|
|
25
|
+
"import": "./dist/adapters/worker.js",
|
|
26
|
+
"types": "./dist/adapters/worker.d.ts"
|
|
22
27
|
}
|
|
23
28
|
},
|
|
24
29
|
"publishConfig": {
|
|
@@ -28,14 +33,18 @@
|
|
|
28
33
|
"build": "tsc",
|
|
29
34
|
"dev": "tsc --watch",
|
|
30
35
|
"format": "oxfmt .",
|
|
31
|
-
"format:check": "oxfmt --check ."
|
|
36
|
+
"format:check": "oxfmt --check .",
|
|
37
|
+
"changeset": "changeset",
|
|
38
|
+
"version": "changeset version",
|
|
39
|
+
"release": "npm run build && npm publish"
|
|
32
40
|
},
|
|
33
41
|
"dependencies": {
|
|
34
|
-
"@
|
|
42
|
+
"@steadlake/core": "^0.3.2",
|
|
35
43
|
"oxfmt": "^0.44.0"
|
|
36
44
|
},
|
|
37
45
|
"devDependencies": {
|
|
38
|
-
"@
|
|
39
|
-
"
|
|
46
|
+
"@changesets/cli": "^2.27.12",
|
|
47
|
+
"@types/node": "^25.9.3",
|
|
48
|
+
"typescript": "^6.0.3"
|
|
40
49
|
}
|
|
41
50
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/adapters/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,SAAI,iBAoBrE"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export async function registerWithRetry(client, attempts = 3) {
|
|
2
|
-
for (let i = 1; i <= attempts; i++) {
|
|
3
|
-
try {
|
|
4
|
-
await client._autoRegister();
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
catch (err) {
|
|
8
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
9
|
-
if (i === attempts) {
|
|
10
|
-
console.error(`[steppler] Auto-registration failed after ${attempts} attempts: ${msg}. Tasks will not be dispatched by DEW until registration succeeds.`);
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const delay = 1000 * 2 ** (i - 1);
|
|
14
|
-
console.warn(`[steppler] Auto-registration attempt ${i} failed, retrying in ${delay}ms: ${msg}`);
|
|
15
|
-
await new Promise((res) => setTimeout(res, delay));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|