PSA/shared/workflow/runtime/jsonSchemaMetadata.ts
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

111 lines
3.4 KiB
TypeScript

import type { ZodSchema, ZodTypeAny } from 'zod';
import {
jsonDescription,
zodToJsonSchema,
type Options,
type PostProcessCallback,
} from 'zod-to-json-schema';
export type WorkflowPickerJsonSchemaMetadata = {
'x-workflow-picker-kind'?: string;
'x-workflow-picker-dependencies'?: string[];
'x-workflow-picker-fixed-value-hint'?: string;
'x-workflow-picker-allow-dynamic-reference'?: boolean;
};
export type WorkflowEditorKind = 'text' | 'picker' | 'color' | 'json' | 'custom';
export type WorkflowEditorInlineMode = 'input' | 'textarea' | 'picker-summary' | 'swatch';
export type WorkflowEditorDialogMode = 'large-text';
export type WorkflowEditorSoftEnumMetadata = {
component: 'soft-enum-combobox';
suggestionKind: 'workflow-data-store-namespace' | 'workflow-entity-type' | 'workflow-link-relation';
suggestionActionIds?: string[];
namespaceField?: string;
curatedValues?: string[];
allowCustomValue?: boolean;
};
export type WorkflowEditorJsonSchemaMetadata = {
kind: WorkflowEditorKind;
inline?: {
mode: WorkflowEditorInlineMode;
};
dialog?: {
mode: WorkflowEditorDialogMode;
};
dependencies?: string[];
allowsDynamicReference?: boolean;
fixedValueHint?: string;
picker?: {
resource: string;
};
softEnum?: WorkflowEditorSoftEnumMetadata;
};
export type WorkflowJsonSchemaMetadata = WorkflowPickerJsonSchemaMetadata & {
'x-workflow-editor'?: WorkflowEditorJsonSchemaMetadata;
};
type WorkflowJsonSchemaDescriptionPayload = WorkflowJsonSchemaMetadata & {
description?: string;
};
const hasWorkflowJsonSchemaMetadata = (metadata: WorkflowJsonSchemaDescriptionPayload): boolean =>
Object.values(metadata).some((value) => value !== undefined);
export const buildWorkflowJsonDescription = (
description: string | undefined,
metadata: WorkflowJsonSchemaMetadata = {}
): string => {
const payload: WorkflowJsonSchemaDescriptionPayload = {
description,
...metadata,
};
if (!hasWorkflowJsonSchemaMetadata(payload)) {
return description ?? '';
}
return JSON.stringify(payload);
};
export const withWorkflowJsonSchemaMetadata = <T extends ZodTypeAny>(
schema: T,
description: string,
metadata: WorkflowJsonSchemaMetadata = {}
): T => schema.describe(buildWorkflowJsonDescription(description, metadata)) as T;
export const buildWorkflowJsonSchemaPostProcess = (
next?: PostProcessCallback
): PostProcessCallback => {
return (jsonSchema, def, refs) => {
const described = jsonDescription(jsonSchema, def, refs);
return next ? next(described, def, refs) : described;
};
};
export const zodToWorkflowJsonSchema = (
schema: ZodSchema<unknown>,
options?: string | Partial<Options>
): Record<string, unknown> => {
// Inline subschemas instead of emitting `$ref`s. The designer's field editor
// does not resolve `$ref`, so a schema reused across fields (e.g. links.upsert's
// `left`/`right` both using entityRefSchema) would otherwise render the second
// occurrence as an unresolved ref (shown as a bare "string").
if (typeof options === 'string') {
return zodToJsonSchema(schema, {
name: options,
$refStrategy: 'none',
postProcess: buildWorkflowJsonSchemaPostProcess(),
}) as Record<string, unknown>;
}
const nextPostProcess = options?.postProcess;
return zodToJsonSchema(schema, {
$refStrategy: 'none',
...options,
postProcess: buildWorkflowJsonSchemaPostProcess(nextPostProcess),
}) as Record<string, unknown>;
};