@classytic/arc 2.7.3 → 2.7.7
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/{HookSystem-D7lfx--K.mjs → HookSystem-BNYKnrXF.mjs} +3 -2
- package/dist/auth/index.mjs +2 -2
- package/dist/{betterAuthOpenApi-CCw3YX0g.mjs → betterAuthOpenApi-EkPaMWNM.mjs} +1 -1
- package/dist/cli/commands/docs.mjs +1 -1
- package/dist/core/index.mjs +2 -2
- package/dist/{core-BWekSEju.mjs → core-B_zEeA2b.mjs} +1 -1
- package/dist/{defineResource-DZzyl4a4.mjs → defineResource-BW2dMCu9.mjs} +1 -6
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.mjs +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +6 -5
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/mongodb.mjs +1 -3
- package/dist/index.mjs +3 -3
- package/dist/integrations/streamline.d.mts +39 -7
- package/dist/integrations/streamline.mjs +106 -4
- package/dist/{openapi-BBSTVcMm.mjs → openapi-D7Z7VODz.mjs} +1 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{schemaConverter-0TyONAwM.mjs → schemaConverter-Y5EejTnJ.mjs} +1 -4
- package/dist/testing/index.d.mts +1 -1
- package/dist/{types-2FlNl0mL.d.mts → types-CKB47kiu.d.mts} +4 -0
- package/dist/utils/index.mjs +1 -1
- package/package.json +6 -5
|
@@ -5,8 +5,9 @@ var HookSystem = class {
|
|
|
5
5
|
warn;
|
|
6
6
|
constructor(options) {
|
|
7
7
|
this.hooks = /* @__PURE__ */ new Map();
|
|
8
|
-
|
|
9
|
-
this.
|
|
8
|
+
const noop = () => {};
|
|
9
|
+
this.logger = options?.logger ?? { error: noop };
|
|
10
|
+
this.warn = options?.logger?.warn ?? noop;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
13
|
* Generate hook key
|
package/dist/auth/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as normalizeRoles, t as getUserRoles } from "../types-ZUu_h0jp.mjs";
|
|
2
2
|
import { t as ArcError } from "../errors-Cg58SLNi.mjs";
|
|
3
3
|
import { h as requireTeamMembership, l as requireOrgMembership, u as requireOrgRole } from "../permissions-CH4cNwJi.mjs";
|
|
4
|
-
import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi-
|
|
4
|
+
import { n as extractBetterAuthOpenApi } from "../betterAuthOpenApi-EkPaMWNM.mjs";
|
|
5
5
|
import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
6
6
|
import fp from "fastify-plugin";
|
|
7
7
|
//#region src/auth/authPlugin.ts
|
|
@@ -677,7 +677,7 @@ function createBetterAuthAdapter(options) {
|
|
|
677
677
|
if (!fastify.hasDecorator("authenticate")) fastify.decorate("authenticate", authenticate);
|
|
678
678
|
if (!fastify.hasDecorator("optionalAuthenticate")) fastify.decorate("optionalAuthenticate", optionalAuthenticate);
|
|
679
679
|
if (!extractedOpenApi && openapiOpt !== false && auth.api && typeof auth.api === "object") {
|
|
680
|
-
const { extractBetterAuthOpenApi } = await import("../betterAuthOpenApi-
|
|
680
|
+
const { extractBetterAuthOpenApi } = await import("../betterAuthOpenApi-EkPaMWNM.mjs").then((n) => n.t);
|
|
681
681
|
extractedOpenApi = extractBetterAuthOpenApi(auth.api, {
|
|
682
682
|
basePath,
|
|
683
683
|
userFields
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
-
import { a as toJsonSchema } from "./schemaConverter-
|
|
2
|
+
import { a as toJsonSchema } from "./schemaConverter-Y5EejTnJ.mjs";
|
|
3
3
|
//#region src/auth/betterAuthOpenApi.ts
|
|
4
4
|
var betterAuthOpenApi_exports = /* @__PURE__ */ __exportAll({ extractBetterAuthOpenApi: () => extractBetterAuthOpenApi });
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ResourceRegistry } from "../../ResourceRegistry-DsHiG9cL.mjs";
|
|
2
|
-
import { t as buildOpenApiSpec } from "../../openapi-
|
|
2
|
+
import { t as buildOpenApiSpec } from "../../openapi-D7Z7VODz.mjs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { mkdirSync, writeFileSync } from "node:fs";
|
package/dist/core/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as DEFAULT_SORT, c as HOOK_OPERATIONS, d as MAX_REGEX_LENGTH, f as MAX_SEARCH_LENGTH, h as SYSTEM_FIELDS, i as DEFAULT_MAX_LIMIT, l as HOOK_PHASES, m as RESERVED_QUERY_PARAMS, n as DEFAULT_ID_FIELD, o as DEFAULT_TENANT_FIELD, p as MUTATION_OPERATIONS, r as DEFAULT_LIMIT, s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS, u as MAX_FILTER_DEPTH } from "../constants-Cxde4rpC.mjs";
|
|
2
2
|
import { i as AccessControl, n as QueryResolver, r as BodySanitizer, t as BaseController } from "../BaseController-CpMfCXdn.mjs";
|
|
3
|
-
import { n as createActionRouter, t as defineResourceVariants } from "../core-
|
|
4
|
-
import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-
|
|
3
|
+
import { n as createActionRouter, t as defineResourceVariants } from "../core-B_zEeA2b.mjs";
|
|
4
|
+
import { c as createCrudHandlers, d as getControllerContext, f as getControllerScope, l as createFastifyHandler, n as defineResource, o as createCrudRouter, p as sendControllerResponse, s as createPermissionMiddleware, t as ResourceDefinition, u as createRequestContext } from "../defineResource-BW2dMCu9.mjs";
|
|
5
5
|
export { AccessControl, BaseController, BodySanitizer, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, QueryResolver, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, createActionRouter, createCrudHandlers, createCrudRouter, createFastifyHandler, createPermissionMiddleware, createRequestContext, defineResource, defineResourceVariants, getControllerContext, getControllerScope, sendControllerResponse };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as normalizePermissionResult, t as applyPermissionResult } from "./applyPermissionResult-D6GPMsvh.mjs";
|
|
2
|
-
import { n as defineResource } from "./defineResource-
|
|
2
|
+
import { n as defineResource } from "./defineResource-BW2dMCu9.mjs";
|
|
3
3
|
//#region src/core/createActionRouter.ts
|
|
4
4
|
/**
|
|
5
5
|
* Create action-based state transition endpoint
|
|
@@ -7,7 +7,7 @@ import { n as normalizePermissionResult, t as applyPermissionResult } from "./ap
|
|
|
7
7
|
import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
|
|
8
8
|
import { i as getDefaultCrudSchemas } from "./utils-B-l6410F.mjs";
|
|
9
9
|
import { r as ForbiddenError } from "./errors-Cg58SLNi.mjs";
|
|
10
|
-
import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-
|
|
10
|
+
import { n as convertRouteSchema, t as convertOpenApiSchemas } from "./schemaConverter-Y5EejTnJ.mjs";
|
|
11
11
|
import { t as hasEvents } from "./typeGuards-CcFZXgU7.mjs";
|
|
12
12
|
import { r as getAvailablePresets, t as applyPresets } from "./presets-BFrGvvjL.mjs";
|
|
13
13
|
//#region src/pipeline/pipe.ts
|
|
@@ -869,11 +869,6 @@ function assertValidConfig(config, options) {
|
|
|
869
869
|
const errorMsg = formatValidationErrors(config.name ?? "unknown", result);
|
|
870
870
|
throw new Error(errorMsg);
|
|
871
871
|
}
|
|
872
|
-
if (result.warnings.length > 0 && process.env.NODE_ENV !== "production") console.warn(formatValidationErrors(config.name ?? "unknown", {
|
|
873
|
-
valid: true,
|
|
874
|
-
errors: [],
|
|
875
|
-
warnings: result.warnings
|
|
876
|
-
}));
|
|
877
872
|
}
|
|
878
873
|
//#endregion
|
|
879
874
|
//#region src/core/defineResource.ts
|
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as getUserRoles } from "../types-ZUu_h0jp.mjs";
|
|
2
|
-
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-
|
|
2
|
+
import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-D7Z7VODz.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/scalar.ts
|
|
5
5
|
const scalarPlugin = async (fastify, opts = {}) => {
|
package/dist/dynamic/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ArcQueryParser } from "../queryParser-CgCtsjti.mjs";
|
|
2
|
-
import { n as defineResource } from "../defineResource-
|
|
2
|
+
import { n as defineResource } from "../defineResource-BW2dMCu9.mjs";
|
|
3
3
|
import { C as publicRead, T as readOnly, b as fullPublic, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "../permissions-CH4cNwJi.mjs";
|
|
4
4
|
//#region src/dynamic/ArcDynamicLoader.ts
|
|
5
5
|
const VALID_FIELD_TYPES = new Set([
|
package/dist/factory/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-
|
|
1
|
+
import { a as CustomPluginAuthOption, c as RawBodyOptions, d as ResourceLike, f as loadResources, i as CustomAuthenticatorOption, l as UnderPressureOptions, n as BetterAuthOption, o as JwtAuthOption, r as CreateAppOptions, s as MultipartOptions, t as AuthOption, u as LoadResourcesOptions } from "../types-CKB47kiu.mjs";
|
|
2
2
|
import { FastifyInstance } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/factory/createApp.d.ts
|
package/dist/factory/index.mjs
CHANGED
|
@@ -163,14 +163,15 @@ async function loadResources(dir, options = {}) {
|
|
|
163
163
|
}
|
|
164
164
|
resources.push(resource);
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
const log = silent ? void 0 : options?.logger;
|
|
167
|
+
if (log) {
|
|
167
168
|
if (failed.length) {
|
|
168
|
-
|
|
169
|
-
for (const f of failed)
|
|
169
|
+
log.warn(`[arc] loadResources: ${failed.length} file(s) failed to import:`);
|
|
170
|
+
for (const f of failed) log.warn(` - ${f}`);
|
|
170
171
|
}
|
|
171
172
|
if (skipped.length) {
|
|
172
|
-
|
|
173
|
-
for (const f of skipped)
|
|
173
|
+
log.warn(`[arc] loadResources: ${skipped.length} file(s) skipped (no default export with toPlugin):`);
|
|
174
|
+
for (const f of skipped) log.warn(` - ${f}`);
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
return resources;
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-
|
|
1
|
+
import { a as beforeCreate, c as createHookSystem, i as afterUpdate, l as defineHook, n as afterCreate, o as beforeDelete, r as afterDelete, s as beforeUpdate, t as HookSystem } from "../HookSystem-BNYKnrXF.mjs";
|
|
2
2
|
export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, defineHook };
|
|
@@ -9,9 +9,7 @@ var MongoIdempotencyStore = class {
|
|
|
9
9
|
this.connection = options.connection;
|
|
10
10
|
this.collectionName = options.collection ?? "arc_idempotency";
|
|
11
11
|
this.ttlMs = options.ttlMs ?? 864e5;
|
|
12
|
-
if (options.createIndex !== false) this.ensureIndex().catch((
|
|
13
|
-
console.warn("[MongoIdempotencyStore] Failed to create index:", err);
|
|
14
|
-
});
|
|
12
|
+
if (options.createIndex !== false) this.ensureIndex().catch(() => {});
|
|
15
13
|
}
|
|
16
14
|
get collection() {
|
|
17
15
|
return this.connection.db.collection(this.collectionName);
|
package/dist/index.mjs
CHANGED
|
@@ -3,10 +3,10 @@ import { a as createMongooseAdapter, i as MongooseAdapter, r as createPrismaAdap
|
|
|
3
3
|
import { t as BaseController } from "./BaseController-CpMfCXdn.mjs";
|
|
4
4
|
import { envelope } from "./types/index.mjs";
|
|
5
5
|
import { n as applyFieldWritePermissions, r as fields, t as applyFieldReadPermissions } from "./fields-ipsbIRPK.mjs";
|
|
6
|
-
import { t as defineResourceVariants } from "./core-
|
|
6
|
+
import { t as defineResourceVariants } from "./core-B_zEeA2b.mjs";
|
|
7
7
|
import { t as requestContext } from "./requestContext-xHIKedG6.mjs";
|
|
8
8
|
import { d as createDomainError, i as NotFoundError, l as UnauthorizedError, r as ForbiddenError, t as ArcError, u as ValidationError } from "./errors-Cg58SLNi.mjs";
|
|
9
|
-
import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-
|
|
9
|
+
import { a as validateResourceConfig, f as getControllerScope, i as formatValidationErrors, m as pipe, n as defineResource, r as assertValidConfig, t as ResourceDefinition } from "./defineResource-BW2dMCu9.mjs";
|
|
10
10
|
import { C as publicRead, S as presets_exports, T as readOnly, _ as when, a as createOrgPermissions, b as fullPublic, c as requireOrgInScope, d as requireOwnership, f as requireRoles, h as requireTeamMembership, i as createDynamicPermissionMatrix, l as requireOrgMembership, m as requireServiceScope, n as allowPublic, o as denyAll, p as requireScopeContext, r as anyOf, s as requireAuth, t as allOf, u as requireOrgRole, v as adminOnly, w as publicReadAdminWrite, x as ownerWithAdminBypass, y as authenticated } from "./permissions-CH4cNwJi.mjs";
|
|
11
11
|
import { n as configureArcLogger, t as arcLog } from "./logger-DLg8-Ueg.mjs";
|
|
12
12
|
//#region src/middleware/middleware.ts
|
|
@@ -128,6 +128,6 @@ function transform(name, handlerOrOptions) {
|
|
|
128
128
|
}
|
|
129
129
|
//#endregion
|
|
130
130
|
//#region src/index.ts
|
|
131
|
-
const version = "2.7.
|
|
131
|
+
const version = "2.7.7";
|
|
132
132
|
//#endregion
|
|
133
133
|
export { ArcError, BaseController, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MongooseAdapter, NotFoundError, PrismaAdapter, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, defineResourceVariants, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
|
|
@@ -1,28 +1,44 @@
|
|
|
1
1
|
import { FastifyPluginAsync } from "fastify";
|
|
2
2
|
|
|
3
3
|
//#region src/integrations/streamline.d.ts
|
|
4
|
+
/** Start options — matches @classytic/streamline v2.1 StartOptions */
|
|
5
|
+
interface WorkflowStartOptions {
|
|
6
|
+
meta?: Record<string, unknown>;
|
|
7
|
+
idempotencyKey?: string;
|
|
8
|
+
priority?: number;
|
|
9
|
+
}
|
|
4
10
|
/** Minimal workflow interface — matches @classytic/streamline's createWorkflow() return */
|
|
5
11
|
interface WorkflowLike {
|
|
6
12
|
definition: {
|
|
7
13
|
id: string;
|
|
8
14
|
name?: string;
|
|
9
|
-
steps: Record<string, unknown
|
|
15
|
+
steps: Record<string, unknown> | unknown[];
|
|
10
16
|
};
|
|
11
17
|
engine: {
|
|
12
|
-
start(input: unknown,
|
|
18
|
+
start(input: unknown, options?: WorkflowStartOptions): Promise<WorkflowRunLike>;
|
|
13
19
|
execute(runId: string): Promise<WorkflowRunLike>;
|
|
14
20
|
resume(runId: string, payload?: unknown): Promise<WorkflowRunLike>;
|
|
15
21
|
cancel(runId: string): Promise<WorkflowRunLike>;
|
|
16
22
|
pause?(runId: string): Promise<WorkflowRunLike>;
|
|
17
23
|
rewindTo?(runId: string, stepId: string): Promise<WorkflowRunLike>;
|
|
18
24
|
get(runId: string): Promise<WorkflowRunLike | null>;
|
|
25
|
+
waitFor?(runId: string, options?: {
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}): Promise<WorkflowRunLike>;
|
|
19
28
|
shutdown?(): void;
|
|
20
29
|
};
|
|
21
|
-
start(input: unknown,
|
|
30
|
+
start(input: unknown, options?: WorkflowStartOptions): Promise<WorkflowRunLike>;
|
|
22
31
|
resume(runId: string, payload?: unknown): Promise<WorkflowRunLike>;
|
|
23
32
|
cancel(runId: string): Promise<WorkflowRunLike>;
|
|
24
33
|
get(runId: string): Promise<WorkflowRunLike | null>;
|
|
25
34
|
shutdown?(): void;
|
|
35
|
+
/** Streamline container for event bridging (streamline >=2.1) */
|
|
36
|
+
container?: {
|
|
37
|
+
eventBus: {
|
|
38
|
+
on(event: string, listener: (...args: unknown[]) => void): void;
|
|
39
|
+
off(event: string, listener: (...args: unknown[]) => void): void;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
26
42
|
}
|
|
27
43
|
interface WorkflowRunLike {
|
|
28
44
|
_id: string;
|
|
@@ -30,11 +46,14 @@ interface WorkflowRunLike {
|
|
|
30
46
|
status: string;
|
|
31
47
|
context?: unknown;
|
|
32
48
|
input?: unknown;
|
|
33
|
-
steps?:
|
|
49
|
+
steps?: unknown[];
|
|
34
50
|
error?: unknown;
|
|
51
|
+
idempotencyKey?: string;
|
|
52
|
+
priority?: number;
|
|
53
|
+
concurrencyKey?: string;
|
|
54
|
+
stepLogs?: unknown[];
|
|
35
55
|
createdAt?: Date;
|
|
36
56
|
updatedAt?: Date;
|
|
37
|
-
[key: string]: unknown;
|
|
38
57
|
}
|
|
39
58
|
interface StreamlinePluginOptions {
|
|
40
59
|
/** Array of workflows created with createWorkflow() */
|
|
@@ -43,8 +62,21 @@ interface StreamlinePluginOptions {
|
|
|
43
62
|
prefix?: string;
|
|
44
63
|
/** Require authentication for all workflow endpoints (default: true) */
|
|
45
64
|
auth?: boolean;
|
|
46
|
-
/** Connect workflow events to Arc's event bus (default: true) */
|
|
65
|
+
/** Connect workflow lifecycle events to Arc's event bus (default: true) */
|
|
47
66
|
bridgeEvents?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Bridge step-level events (step:started, step:completed, step:failed) to Arc's event bus.
|
|
69
|
+
* Disabled by default — enable for dashboards or monitoring.
|
|
70
|
+
* Requires the workflow to expose `container.eventBus` (streamline >=2.1).
|
|
71
|
+
* @default false
|
|
72
|
+
*/
|
|
73
|
+
bridgeStepEvents?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Enable SSE streaming endpoint: GET /:workflowId/runs/:runId/stream
|
|
76
|
+
* Streams step-level events as Server-Sent Events for live UI updates.
|
|
77
|
+
* @default false
|
|
78
|
+
*/
|
|
79
|
+
enableStreaming?: boolean;
|
|
48
80
|
/** Custom permission check for workflow operations */
|
|
49
81
|
permissions?: {
|
|
50
82
|
start?: (request: unknown) => boolean | Promise<boolean>;
|
|
@@ -57,4 +89,4 @@ interface StreamlinePluginOptions {
|
|
|
57
89
|
/** Pluggable streamline integration for Arc */
|
|
58
90
|
declare const streamlinePlugin: FastifyPluginAsync<StreamlinePluginOptions>;
|
|
59
91
|
//#endregion
|
|
60
|
-
export { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike, streamlinePlugin };
|
|
92
|
+
export { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike, WorkflowStartOptions, streamlinePlugin };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/integrations/streamline.ts
|
|
2
2
|
const streamlinePluginImpl = async (fastify, options) => {
|
|
3
|
-
const { workflows, prefix = "/workflows", auth = true, bridgeEvents = true, permissions: perms } = options;
|
|
3
|
+
const { workflows, prefix = "/workflows", auth = true, bridgeEvents = true, bridgeStepEvents = false, enableStreaming = false, permissions: perms } = options;
|
|
4
4
|
const registry = /* @__PURE__ */ new Map();
|
|
5
5
|
for (const wf of workflows) {
|
|
6
6
|
const id = wf.definition.id;
|
|
@@ -22,8 +22,12 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
22
22
|
success: false,
|
|
23
23
|
error: "Forbidden"
|
|
24
24
|
});
|
|
25
|
-
const { input, meta } = request.body ?? {};
|
|
26
|
-
const run = await wf.start(input,
|
|
25
|
+
const { input, meta, idempotencyKey, priority } = request.body ?? {};
|
|
26
|
+
const run = await wf.start(input, {
|
|
27
|
+
meta,
|
|
28
|
+
idempotencyKey,
|
|
29
|
+
priority
|
|
30
|
+
});
|
|
27
31
|
if (bridgeEvents && fastify.events?.publish) try {
|
|
28
32
|
await fastify.events.publish(`workflow.${id}.started`, {
|
|
29
33
|
runId: run._id,
|
|
@@ -105,6 +109,26 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
105
109
|
data: run
|
|
106
110
|
};
|
|
107
111
|
});
|
|
112
|
+
fastify.post(`${routePrefix}/runs/:runId/execute`, { preHandler: authPreHandler }, async (request, _reply) => {
|
|
113
|
+
const { runId } = request.params;
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
data: await wf.engine.execute(runId)
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
if (wf.engine.waitFor) fastify.get(`${routePrefix}/runs/:runId/wait`, { preHandler: authPreHandler }, async (request, reply) => {
|
|
120
|
+
if (!await checkPerm("get", request)) return reply.status(403).send({
|
|
121
|
+
success: false,
|
|
122
|
+
error: "Forbidden"
|
|
123
|
+
});
|
|
124
|
+
const { runId } = request.params;
|
|
125
|
+
const { timeout } = request.query ?? {};
|
|
126
|
+
const timeoutMs = timeout ? Number.parseInt(timeout, 10) : 3e4;
|
|
127
|
+
return {
|
|
128
|
+
success: true,
|
|
129
|
+
data: await wf.engine.waitFor(runId, { timeout: Math.min(timeoutMs, 12e4) })
|
|
130
|
+
};
|
|
131
|
+
});
|
|
108
132
|
if (wf.engine.pause) fastify.post(`${routePrefix}/runs/:runId/pause`, { preHandler: authPreHandler }, async (request, _reply) => {
|
|
109
133
|
const { runId } = request.params;
|
|
110
134
|
return {
|
|
@@ -124,6 +148,84 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
124
148
|
data: await wf.engine.rewindTo?.(runId, stepId)
|
|
125
149
|
};
|
|
126
150
|
});
|
|
151
|
+
if (bridgeStepEvents && wf.container?.eventBus && fastify.events?.publish) for (const eventName of [
|
|
152
|
+
"step:started",
|
|
153
|
+
"step:completed",
|
|
154
|
+
"step:failed",
|
|
155
|
+
"step:skipped",
|
|
156
|
+
"step:retry-scheduled"
|
|
157
|
+
]) wf.container.eventBus.on(eventName, (payload) => {
|
|
158
|
+
const p = payload;
|
|
159
|
+
fastify.events.publish(`workflow.${id}.${eventName}`, {
|
|
160
|
+
runId: p?.runId,
|
|
161
|
+
stepId: p?.stepId,
|
|
162
|
+
workflowId: id,
|
|
163
|
+
...p
|
|
164
|
+
}).catch((err) => {
|
|
165
|
+
fastify.log.warn({
|
|
166
|
+
err,
|
|
167
|
+
workflowId: id
|
|
168
|
+
}, `Failed to bridge ${eventName}`);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
if (enableStreaming && wf.container?.eventBus) fastify.get(`${routePrefix}/runs/:runId/stream`, { preHandler: authPreHandler }, async (request, reply) => {
|
|
172
|
+
if (!await checkPerm("get", request)) return reply.status(403).send({
|
|
173
|
+
success: false,
|
|
174
|
+
error: "Forbidden"
|
|
175
|
+
});
|
|
176
|
+
const { runId } = request.params;
|
|
177
|
+
if (!await wf.get(runId)) return reply.status(404).send({
|
|
178
|
+
success: false,
|
|
179
|
+
error: "Workflow run not found"
|
|
180
|
+
});
|
|
181
|
+
reply.raw.writeHead(200, {
|
|
182
|
+
"Content-Type": "text/event-stream",
|
|
183
|
+
"Cache-Control": "no-cache",
|
|
184
|
+
Connection: "keep-alive"
|
|
185
|
+
});
|
|
186
|
+
const events = [
|
|
187
|
+
"step:started",
|
|
188
|
+
"step:completed",
|
|
189
|
+
"step:failed",
|
|
190
|
+
"step:skipped",
|
|
191
|
+
"workflow:completed",
|
|
192
|
+
"workflow:failed",
|
|
193
|
+
"workflow:cancelled"
|
|
194
|
+
];
|
|
195
|
+
const listeners = [];
|
|
196
|
+
let closed = false;
|
|
197
|
+
const send = (event, data) => {
|
|
198
|
+
if (closed) return;
|
|
199
|
+
try {
|
|
200
|
+
reply.raw.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
201
|
+
} catch {
|
|
202
|
+
cleanup();
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const cleanup = () => {
|
|
206
|
+
if (closed) return;
|
|
207
|
+
closed = true;
|
|
208
|
+
for (const { event, fn } of listeners) wf.container?.eventBus.off(event, fn);
|
|
209
|
+
listeners.length = 0;
|
|
210
|
+
try {
|
|
211
|
+
reply.raw.end();
|
|
212
|
+
} catch {}
|
|
213
|
+
};
|
|
214
|
+
for (const eventName of events) {
|
|
215
|
+
const fn = (payload) => {
|
|
216
|
+
const p = payload;
|
|
217
|
+
if (p?.runId !== runId) return;
|
|
218
|
+
send(eventName, p);
|
|
219
|
+
if (eventName === "workflow:completed" || eventName === "workflow:failed" || eventName === "workflow:cancelled") cleanup();
|
|
220
|
+
};
|
|
221
|
+
wf.container.eventBus.on(eventName, fn);
|
|
222
|
+
listeners.push({
|
|
223
|
+
event: eventName,
|
|
224
|
+
fn
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
request.raw.on("close", cleanup);
|
|
228
|
+
});
|
|
127
229
|
}
|
|
128
230
|
fastify.get(prefix, { preHandler: authPreHandler }, async () => {
|
|
129
231
|
return {
|
|
@@ -131,7 +233,7 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
131
233
|
data: Array.from(registry.entries()).map(([id, wf]) => ({
|
|
132
234
|
id,
|
|
133
235
|
name: wf.definition.name ?? id,
|
|
134
|
-
steps: Object.keys(wf.definition.steps)
|
|
236
|
+
steps: Array.isArray(wf.definition.steps) ? wf.definition.steps.map((s) => s.id ?? String(s)) : Object.keys(wf.definition.steps)
|
|
135
237
|
}))
|
|
136
238
|
};
|
|
137
239
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as getUserRoles } from "./types-ZUu_h0jp.mjs";
|
|
2
|
-
import { n as convertRouteSchema } from "./schemaConverter-
|
|
2
|
+
import { n as convertRouteSchema } from "./schemaConverter-Y5EejTnJ.mjs";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/docs/openapi.ts
|
|
5
5
|
const openApiPlugin = async (fastify, opts = {}) => {
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { p as MUTATION_OPERATIONS } from "../constants-Cxde4rpC.mjs";
|
|
|
2
2
|
import { o as getOrgId } from "../types-AOD8fxIw.mjs";
|
|
3
3
|
import { t as requestContext } from "../requestContext-xHIKedG6.mjs";
|
|
4
4
|
import { t as hasEvents } from "../typeGuards-CcFZXgU7.mjs";
|
|
5
|
-
import { t as HookSystem } from "../HookSystem-
|
|
5
|
+
import { t as HookSystem } from "../HookSystem-BNYKnrXF.mjs";
|
|
6
6
|
import { t as ResourceRegistry } from "../ResourceRegistry-DsHiG9cL.mjs";
|
|
7
7
|
import { n as caching_default, t as cachingPlugin } from "../caching-5DtLwIqb.mjs";
|
|
8
8
|
import { t as errorHandlerPlugin } from "../errorHandler-CH8wk1eD.mjs";
|
|
@@ -44,7 +44,7 @@ try {
|
|
|
44
44
|
function createTracerProvider(options) {
|
|
45
45
|
if (!isAvailable) return null;
|
|
46
46
|
const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
|
|
47
|
-
const resolvedVersion = serviceVersion ?? "2.7.
|
|
47
|
+
const resolvedVersion = serviceVersion ?? "2.7.7";
|
|
48
48
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
49
49
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
50
50
|
"service.name": serviceName,
|
|
@@ -34,10 +34,7 @@ function toJsonSchema(input) {
|
|
|
34
34
|
if (typeof input !== "object") return void 0;
|
|
35
35
|
if (isJsonSchema(input)) return input;
|
|
36
36
|
if (isZodSchema(input)) {
|
|
37
|
-
if (!_toJSONSchema)
|
|
38
|
-
console.warn("[Arc] Zod schema detected but zod is not installed. Install zod v4: npm install zod");
|
|
39
|
-
return input;
|
|
40
|
-
}
|
|
37
|
+
if (!_toJSONSchema) return input;
|
|
41
38
|
try {
|
|
42
39
|
return _toJSONSchema(input, { target: "openapi-3.0" });
|
|
43
40
|
} catch {
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Ut as CrudRepository, Vt as ResourceDefinition, u as AnyRecord } from "../interface-B91alUzq.mjs";
|
|
2
|
-
import { d as ResourceLike, r as CreateAppOptions } from "../types-
|
|
2
|
+
import { d as ResourceLike, r as CreateAppOptions } from "../types-CKB47kiu.mjs";
|
|
3
3
|
import Fastify, { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
4
4
|
import { Connection } from "mongoose";
|
|
5
5
|
import { Mock } from "vitest";
|
|
@@ -107,6 +107,10 @@ interface LoadResourcesOptions {
|
|
|
107
107
|
* @default false
|
|
108
108
|
*/
|
|
109
109
|
silent?: boolean;
|
|
110
|
+
/** Optional logger for diagnostics. No output when omitted (silent by default). */
|
|
111
|
+
logger?: {
|
|
112
|
+
warn: (msg: string) => void;
|
|
113
|
+
};
|
|
110
114
|
}
|
|
111
115
|
/**
|
|
112
116
|
* Scan a directory for resource files and import their default exports.
|
package/dist/utils/index.mjs
CHANGED
|
@@ -2,6 +2,6 @@ import { n as createQueryParser, t as ArcQueryParser } from "../queryParser-CgCt
|
|
|
2
2
|
import { a as createCircuitBreaker, i as CircuitState, n as CircuitBreakerError, o as createCircuitBreakerRegistry, r as CircuitBreakerRegistry, t as CircuitBreaker } from "../circuitBreaker-l18oRgL5.mjs";
|
|
3
3
|
import { _ as defineCompensation, a as getListQueryParams, c as listResponse, d as paginateWrapper, f as paginationSchema, g as wrapResponse, h as successResponseSchema, i as getDefaultCrudSchemas, l as messageWrapper, m as responses, n as deleteResponse, o as itemResponse, p as queryParams, r as errorResponseSchema, s as itemWrapper, t as createStateMachine, u as mutationResponse, v as withCompensation } from "../utils-B-l6410F.mjs";
|
|
4
4
|
import { a as OrgAccessDeniedError, c as ServiceUnavailableError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-Cg58SLNi.mjs";
|
|
5
|
-
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-
|
|
5
|
+
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-Y5EejTnJ.mjs";
|
|
6
6
|
import { t as hasEvents } from "../typeGuards-CcFZXgU7.mjs";
|
|
7
7
|
export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createError, createQueryParser, createStateMachine, defineCompensation, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, itemWrapper, listResponse, messageWrapper, mutationResponse, paginateWrapper, paginationSchema, queryParams, responses, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.7",
|
|
4
4
|
"description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -221,14 +221,14 @@
|
|
|
221
221
|
"test:e2e": "vitest run tests/e2e",
|
|
222
222
|
"test:unit": "vitest run tests/core tests/hooks tests/utils tests/plugins",
|
|
223
223
|
"smoke": "node scripts/smoke-test.mjs",
|
|
224
|
-
"prepublishOnly": "npm run typecheck && npm run
|
|
224
|
+
"prepublishOnly": "npm run typecheck && npm run lint && npm run build && npm run test:ci && npm run smoke"
|
|
225
225
|
},
|
|
226
226
|
"engines": {
|
|
227
227
|
"node": ">=22"
|
|
228
228
|
},
|
|
229
229
|
"peerDependencies": {
|
|
230
|
-
"@classytic/mongokit": ">=3.5.
|
|
231
|
-
"@classytic/streamline": ">=2.
|
|
230
|
+
"@classytic/mongokit": ">=3.5.6",
|
|
231
|
+
"@classytic/streamline": ">=2.1.0",
|
|
232
232
|
"@fastify/cors": ">=11.0.0",
|
|
233
233
|
"@fastify/helmet": ">=13.0.0",
|
|
234
234
|
"@fastify/jwt": ">=10.0.0",
|
|
@@ -346,7 +346,8 @@
|
|
|
346
346
|
"devDependencies": {
|
|
347
347
|
"@better-auth/mongo-adapter": "^1.6.0",
|
|
348
348
|
"@biomejs/biome": "^2.4.10",
|
|
349
|
-
"@classytic/mongokit": "
|
|
349
|
+
"@classytic/mongokit": "3.5.6",
|
|
350
|
+
"@classytic/streamline": "^2.1.0",
|
|
350
351
|
"@fastify/cors": "^11.2.0",
|
|
351
352
|
"@fastify/helmet": "^13.0.2",
|
|
352
353
|
"@fastify/jwt": "^10.0.0",
|