Files
8cbb6c0130 feat: HITL IM integration (#44864)
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: JzoNg <jzongcode@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-10-30 02:43:31 +00:00
..

@dify/openapi-content-mapper

Import OpenAPI documents as typed, tree-shakable API calls and TanStack Query helpers using TypeScript 7.1 Content Mappers. No generated SDK source or declaration files need to be committed.

Experimental beta: the compiler integration targets TypeScript 7.1.0-beta. The API and compiler protocol may change between prereleases. This package is ESM-only.

Compatibility

Environment Supported setup
Compiler TypeScript 7.1.0-beta, with --runExternalCode
Editor TypeScript 7 extension, workspace compiler and content mappers enabled
Build/runtime tooling Node.js 24+
Vite Official Vite 8.3.5; optional peer dependency
Next.js Next.js 16.4.2, Turbopack and Webpack with the loader below
Browser runtime Modern Fetch, Headers, FormData, Blob and ReadableStream APIs
Specification OpenAPI 3.0/3.1, local JSON Pointer references

Install and try

After the beta is published:

npm install @dify/openapi-content-mapper@beta
npm install --save-dev typescript@7.1.0-beta vite@8.3.5

Before publication, install a locally packed release candidate with npm install /path/to/dify-openapi-content-mapper-0.1.0-beta.0.tgz. See Development and release for packaging and verification.

Create pets.openapi.yaml:

openapi: 3.1.0
info:
  title: Pets
  version: '1'
servers:
  - url: https://api.example.com
paths:
  /pets/{petId}:
    get:
      parameters:
        - name: petId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: A pet
          content:
            application/json:
              schema:
                type: object
                required: [id, name]
                properties:
                  id:
                    type: integer
                  name:
                    type: string

Configure tsconfig.json:

{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "noEmit": true
  },
  "contentMappers": [
    {
      "package": "@dify/openapi-content-mapper",
      "extensions": [".yaml", ".yml", ".openapi"]
    }
  ]
}

Configure vite.config.ts:

import { openapi } from '@dify/openapi-content-mapper/vite'
import { defineConfig } from 'vite'

export default defineConfig({ plugins: [openapi()] })

Then call the API:

import { api, query } from './pets.openapi.yaml'

const pet = await api.pets.byPetId.get({ params: { petId: 1 } })
pet.name // string

const options = query.pets.byPetId.get.queryOptions({
  input: { params: { petId: 1 } },
})
// Pass options to useQuery(), queryClient.fetchQuery(), etc.

Run npx tsc --runExternalCode --noEmit. The compiler supplies types; the Vite plugin supplies runtime modules. Both are required for this setup.

For VS Code, install Microsoft's TypeScript 7 extension (TypeScriptTeam.native-preview), select the workspace TypeScript 7.1 compiler, trust the workspace and enable content mappers. Open a consuming .ts file so the language server discovers its config.

Compiler cache

Successful mapper results are cached in the current user's temporary directory under dify-openapi-content-mapper-<user>, retaining up to 64 documents. Content, implementation and configuration-sidecar presence changes invalidate the cache; sidecar contents are checked by TypeScript. The cache can be deleted safely. Corrupt entries or unavailable storage fall back to transformation, and no cache files are shipped to the browser.

Existing JSON files

The TS 7.1 beta cannot register mappers for built-in .json imports, including .openapi.json. Store JSON in a file ending in .openapi, or symlink an existing JSON file:

ln -s pets.json pets.openapi

Import ./pets.openapi. On platforms where symlinks are unavailable, use a regular .openapi file containing JSON. Vite and Node preserve the logical extension of symlinks.

Local backend sources without generated specification files

Use an authored pets.openapi-source descriptor when the backend can export its OpenAPI document to stdout. The descriptor contains the command, not the schema:

{
  "command": ["python", "export_openapi.py"],
  "cwd": "../backend",
  "inputs": ["**/*.py", "pyproject.toml"],
  "exclude": ["tests/**"],
  "optionalInputs": [".env"],
  "env": ["API_EDITION"],
  "timeoutMs": 60000
}

cwd is relative to the descriptor; input glob patterns are relative to cwd. Declare every source/configuration input and any environment variables that affect exported schemas. Input globs must match existing paths; exclude removes glob matches that cannot affect the contract. optionalInputs lists exact paths that may not exist yet, such as .env; their creation, changes and removal invalidate the source. Dependency scanning excludes node_modules, .venv, .git and __pycache__. Commands run without a shell; node uses the current Node executable. Write exactly one OpenAPI JSON document to stdout and send diagnostics to stderr. No running backend is needed if the exporter can construct its schemas without starting services.

Register both the extension and the source in the consuming tsconfig:

{
  "contentMappers": [
    {
      "package": "@dify/openapi-content-mapper",
      "extensions": [".openapi-source", ".openapi", ".yaml", ".yml"],
      "options": { "sources": ["./pets.openapi-source"] }
    }
  ]
}

Source entries are relative to this tsconfig's directory; inherited configurations should declare them in the consuming project. Registration lets TypeScript watch backend inputs and invalidate incremental builds even when the descriptor is unchanged. Keep the descriptor in a package with an SDK dependency so its inferred types can resolve the SDK. Then import it normally:

import { api, query } from './pets.openapi-source'

Vite and Node recognize .openapi-source automatically. Add a matching loader rule for Next.js, as for an ordinary .openapi file. Existing document imports continue to work alongside command sources. Configuration, queries and errors use the same adjacent sidecars, such as pets.openapi-source.config.ts.

The editor, type checker and runtime adapters execute the same command-source resolver. Exported OpenAPI content is cached in process memory until its declared inputs change; the mapper's temporary cache stores derived types, not a committed specification. Each new process needs the backend export environment. The exporter and schema do not ship to the browser. Definitions from a command source have no schema-file location; file imports retain their existing source navigation.

The repository Console exporter additionally shares its in-memory result between compiler, editor and build processes through a local POSIX helper. It starts on demand and exits after two idle minutes. A private Unix socket and empty lifecycle lock are the only IPC files; OpenAPI content is never written to disk. The helper is specific to the Console source, not enabled for arbitrary exporter commands.

On changes, a fresh child imports the current controllers from source, with safe model dependencies preloaded. Changing a preloaded dependency, adding/removing a Python file, changing .env, or changing the environment invalidates that state. Python bytecode caches are bypassed to handle rapid same-size edits. Export errors are surfaced rather than serving the old contract. Refreshes interrupted by more source edits are retried. Console and Community type descriptors track Python sources in api/ and the editable dify-agent/src/ dependency, together with their package configuration. Backend tests are excluded from Console source inputs. Native threads are checked before forking; unsafe snapshots and platforms without fork use a fresh-process export instead. Those refreshes still incur cold startup.

To stop the local helper early, run from the same directory and environment used by the source descriptor:

uv run --project api api/dev/cached_console_openapi.py --stop

The uncached reference exporter remains api/dev/export_console_openapi.py. Command-source JSON is transformed directly, avoiding the YAML syntax tree and source mappings needed only for file-backed documents.

Navigate to backend implementations

An operation can carry optional development metadata:

"x-source-location": { "file": "/checkout/api/controllers/pets.py", "line": 42 }

line is one-based. Relative paths resolve against the imported OpenAPI file or .openapi-source descriptor. The mapper adds an Open backend implementation link to the method's hover documentation, for both api and query. This works with command sources and imported OpenAPI files. Metadata is excluded from runtime operation descriptors and browser bundles.

For F12 / Cmd+click and Go to Implementation, install the optional local VS Code extension. It uses the same hover link to find the backend target. Without source metadata, normal schema navigation is preserved; the extension skips backend files that are not present locally.

The Dify Console stdout exporter adds these locations automatically, including unwrapping decorated handlers. This affects only the local in-memory export; live API schemas and retained Enterprise snapshots are unchanged.

API and transport

Documents export api and query at runtime, plus the type-only Schemas, Inputs and Outputs maps; operation IDs are not exports. /pets/{petId} becomes pets.byPetId, hyphenated segments become camelCase and HTTP methods are leaf functions. Colon actions such as /chat:run become chat.run. key is reserved as a route segment for query helpers. Unresolvable member collisions fail during compilation.

An operation may set x-client-path to an explicit array such as ["enterprise", "access", "getEnvironmentApi"] to preserve an existing public API. This replaces its entire client member path, including the method leaf, and also determines its query key. HTTP methods, URLs and per-operation sidecar keys still use the OpenAPI operation. Colliding or reserved member names fail during compilation.

The first argument contains params, query, headers, cookie, body and contentType as declared by the specification. The optional second argument accepts client, signal, additional transport headers, credentials and document context.

import { createClient } from '@dify/openapi-content-mapper'
import { api } from './pets.openapi.yaml'

const transport = createClient({
  baseUrl: 'https://api.example.com/v1',
  headers: { Authorization: 'Bearer …' },
  fetch: globalThis.fetch,
})

await api.pets.byPetId.get(
  { params: { petId: 1 } },
  { client: transport, signal: AbortSignal.timeout(5000) },
)

A client override takes precedence over document configuration. Otherwise the document's servers URL is used; relative server URLs require a browser origin or an explicit absolute baseUrl in Node. The exported shared client also supports setConfig(), but request-specific credentials should use independent clients.

Successful calls return decoded response data. Non-2xx responses throw ApiError with response and decoded data; network and cancellation failures propagate. Responses are not runtime-validated and schema defaults are not filled in. JSON binary-formatted fields remain strings; binary response media return Blob objects (File with the response filename when Content-Disposition is present); SSE returns a raw ReadableStream<Uint8Array>.

Wildcard response media follow the most specific matching declaration for the response status: */* and application/* return Blob, while text/* returns text. An explicit application/json or text/event-stream declaration takes precedence over a wildcard. HTTP errors are decoded from their actual Content-Type.

With one request media type, contentType can be omitted. With multiple media types, only application/json is implicit; other alternatives require an explicit matching contentType. Multipart accepts flat objects with scalar, Blob/File or repeated array fields, plus explicit JSON part encodings. Fetch supplies its boundary. Optional request bodies may be omitted entirely.

Reuse model, input and output types

See Petstore type examples for reusable aliases and a legacy request envelope, and the runnable demo for typed HTTP calls. Run pnpm --filter @dify/openapi-content-mapper type-check to check the examples, or pnpm --filter @dify/openapi-content-mapper demo to execute them against a local server started by the demo.

Import types from the same document as the API. This works for YAML, JSON .openapi files and .openapi-source command sources, without generating files:

import type { Schemas, Inputs, Outputs } from './pets.openapi.yaml'

type Pet = Schemas['Pet']
type CreatePetBody = Inputs['pets']['post']['body']
type GetPetInput = Inputs['pets']['byPetId']['get']
type PetList = Outputs['pets']['get']
type ListQuery = NonNullable<Inputs['pets']['get']>['query']

Schemas contains every components.schemas entry under its original name, including unused and recursive models. Names containing / or ~ are accessed with their original spelling. It describes JSON values: binary-formatted strings remain string. For a multipart body, use Inputs to get the appropriate Blob/File-compatible fields. Documents without component schemas export an empty Schemas map.

Inputs and Outputs follow the api member paths, including x-client-path overrides. Each input is the operation's first argument, equivalent to Parameters<typeof api.pets.get>[0]; optional inputs include undefined. It does not include the second argument's transport options or context. Each output is the awaited successful result, equivalent to Awaited<ReturnType<...>>, including void for empty responses, Blob for binary responses and streams for SSE. Inline schemas and media-type discrimination are preserved. All three exports are erased from JavaScript; use import type or export type to consume them.

Dify contract type subpaths

Inside the Dify repository, import compatible contract types directly from this package's subpaths. Existing type names and structures are preserved; only the module specifier changes:

import type {
  DatasetCreatePayload,
  PostDatasetsData,
  PostDatasetsResponses,
  PostDatasetsResponse,
  PostDatasetsErrors,
  PostDatasetsError,
} from '@dify/openapi-content-mapper/console/datasets'

const body: DatasetCreatePayload = { name: 'Documentation' }
const request: PostDatasetsData = { url: '/datasets', body }
type Created = PostDatasetsResponses[201]
type Conflict = PostDatasetsErrors[409]

Available subpaths are /console/*, /service, /web, /openapi, /enterprise and /enterprise-app-deploy. They provide models, ClientOptions, legacy *Data request envelopes, status-indexed *Responses / *Errors, and the singular response/error unions. Same-named types stay isolated in their modules. The original @dify/contracts exports remain unchanged; no customConditions or conditional overrides of those paths are needed.

These subpaths are type-only. For runtime enum objects, continue to import the original contracts module, while the mapper subpath can supply the type:

import type { AccessMode } from '@dify/openapi-content-mapper/enterprise'
import { AccessMode as AccessModes } from '@dify/contracts/enterprise/types.gen'

const mode: AccessMode = AccessModes.ACCESS_MODE_PRIVATE

Enable .openapi-types in the consuming project's mapper settings. The mapper automatically registers the contract sources shipped in its workspace package:

{
  "contentMappers": [
    {
      "package": "@dify/openapi-content-mapper",
      "extensions": [".openapi", ".openapi-source", ".openapi-types"]
    }
  ]
}

No options.sources or paths entries are needed for these package subpaths. Registration watches descriptors and backend inputs without running exporters; exporters run when their modules are imported. Modules sharing inputs reuse one filesystem scan per registration. Custom .openapi-source and .openapi-types files outside the package's contracts/ directory still require options.sources, with paths relative to the consuming tsconfig. Explicit sources are combined with the automatic sources. Run TypeScript 7.1 with --runExternalCode, and enable content mappers in the editor. The repository compatibility example and its tsconfig already use these subpaths:

pnpm --filter @dify/openapi-content-mapper type-check:contracts

The compatibility exporter reuses the same Community document normalization, Console module splitting and Hey API TypeScript plugin as regular generation. It exports current Python schemas into memory and runs Hey API with disk output and cleanup disabled. Request path/url, status maps, writable variants, recursive models, binary types and enum naming therefore follow the existing contracts rules, rather than the mapper RPC Inputs/Outputs rules. Backend contract changes still change the inferred types.

Type hovers include Open backend implementation links for registered Community Python models and API request/response/error envelopes. With the local VS Code extension, F12 / Cmd+click and Go to Implementation follow these links, including through import aliases and re-exports. In the example, DatasetCreatePayload opens its Python class and PostDatasetsData opens DatasetListApi.post. Synthetic models and snapshots without source metadata have no backend target; the exporter does not guess by type name.

Enterprise and App Deploy use the retained OpenAPI snapshots. These snapshots omit some non-Console models; missing exports are re-exported from the existing complete contracts modules. Those retained types update with regular Enterprise generation, rather than with unavailable private backend sources.

The three contracts generation commands also regenerate the mapper's thin subpath selectors and .d.ts entry points. To refresh them alone after adding modules, run pnpm --filter @dify/contracts gen-compatibility-sources. Each selector contains only an extends path and module argument; exporter commands and watched inputs live in two shared source configurations. Each declaration entry contains only an export type * pointing to its selector; model declarations remain virtual and new names are discovered automatically. No additional OpenAPI snapshots are written.

Package exports resolve through these standard .d.ts entries so TypeScript 7's language service does not report a missing-declaration hint for the custom source extension. Consumers need no compilerOptions.paths overrides or ambient module declarations; they only enable the mapper and extension as shown above.

Dify-specific subpaths require the repository's Python and JavaScript development dependencies, but no running API or database. They are workspace integrations and are excluded from the standalone npm SDK's published exports and files. The standalone package continues to support generic OpenAPI imports. Production consumers of @dify/contracts are unaffected.

Type-only command sources

.openapi-types uses the same descriptor shape, watched-input validation and cache invalidation as .openapi-source. Its exporter writes JSON of the form {"typescript":"export type Example = { id: string };"} to stdout. The mapper uses this TypeScript module as virtual compiler input. Exporter logs belong on stderr, and empty or malformed results are diagnostics, not cached successes. These files are for type resolution, not runtime imports. Dify subpaths expose only a types target; runtime imports continue to use the original contracts. Ordinary OpenAPI imports still export Schemas, Inputs, Outputs, api and query as described above.

Descriptors can share a configuration with extends. extends and cwd paths are resolved from the descriptor that defines them; input patterns are relative to the effective cwd. Other fields replace inherited values, and args is appended to the effective command. Every inherited descriptor is watched and included in cache invalidation. For example:

{
  "extends": "../community.source.json",
  "args": ["api/console/datasets"]
}

Document configuration

Place pets.openapi.yaml.config.ts next to pets.openapi.yaml:

import type { RuntimeConfig } from '@dify/openapi-content-mapper'
import { createClient } from '@dify/openapi-content-mapper'

export type Context = { token?: string }

const runtime: RuntimeConfig<Context> = {
  createClient: ({ context }) =>
    createClient({
      baseUrl: 'https://api.example.com',
      headers: context?.token ? { Authorization: `Bearer ${context.token}` } : {},
    }),
  queryKeyPrefix: ['pets'],
}
export default runtime

Both api and query infer Context. The factory runs per call. An optional onError(error) hook observes failures; avoid throwing from it if you want the original error to propagate. Restart the development server after adding or removing a sidecar; edits to existing files follow normal HMR.

Per-operation query defaults and typed errors

Export defaults from <document>.queries.ts under the exact METHOD /path name:

// pets.openapi.queries.ts
import type { experimental_RouterUtilsDefaults } from '@orpc/tanstack-query'
import type { api } from './pets.openapi'

const list: experimental_RouterUtilsDefaults<typeof api.pets.get> = {
  queryOptions: { staleTime: 30_000, retry: false },
}
export { list as 'GET /pets' }

Defaults use oRPC's query helpers, including mutation callbacks and infinite queries. Caller options override defaults, including callbacks; they are not composed. Return cache invalidation promises from mutation callbacks when the mutation must remain pending until refresh completes. Keep policy dependencies independent of a complete runtime router: importing or enumerating a whole client can retain unrelated operations.

An optional <document>.errors.ts exports oRPC error maps with the same names:

// pets.openapi.errors.ts
import type { ErrorMap } from '@orpc/contract'
import { conflictSchema } from './error-schemas'

const conflicts = {
  CONFLICT: { status: 409, data: conflictSchema },
} satisfies ErrorMap
export { conflicts as 'POST /pets' }

The data validator can use any Standard Schema implementation. API calls and query helpers infer the map's error union, so safe and isDefinedError narrow the code and validated payload. HTTP status and schema validation must match before an error is marked defined. Network/cancellation failures keep their identity. Bare HTTP errors with a code envelope are converted to ORPCError when an error map is configured; existing transport ORPCErrors are preserved and validated.

Each operation imports its own defaults and lazy error module. Error validators load on HTTP failure, and unused maps/defaults can be removed by the bundler. Vite application builds group retained error modules by document to avoid a tiny chunk per operation, while keeping validators lazy and respecting custom chunk groups. Strict library exports and legacy manual chunk configurations keep the bundler's existing chunking behavior. A validator chunk that fails to load leaves the original HTTP error undefined. Serve the emitted chunks together with the entry bundle. Keep validators free of module-level side effects; schema construction must be removable when its map is unused. Named re-exports and export * are supported; sidecars are inspected without executing them. Vite and Next track sidecar changes; Node imports follow normal module caching. Sidecar star re-exports use the consuming bundler's resolver. Vite supports aliases and TypeScript extension resolution (such as ./defaults.js resolving to defaults.ts); Next.js Webpack requires the same experimental.extensionAlias configuration as ordinary imports for that convention. For Turbopack, use explicit relative source paths such as ./defaults.ts: its loader resolver does not support those aliases. Native Node execution retains Node's ESM resolution rules and requires executable import paths.

Query helpers and bundles

Import query directly for queryOptions, mutationOptions, queryKey and namespace key() helpers. Give each document a distinct queryKeyPrefix when routes overlap. For an application-level entry, preserve direct ESM re-exports:

export { api as apiClient, query as apiQuery } from './pets.openapi.yaml'

Static calls retain only used operations. Dynamic indexing, enumeration or passing whole namespaces to opaque functions can retain other operations. The runtime does not bundle response schemas or the YAML parser.

Comparison with oRPC

This package consumes OpenAPI directly and prunes statically used operations while keeping oRPC-shaped calls and reusing its TanStack Query helpers. It requires the TS 7.1 beta toolchain. Per-operation defaults and error maps are opt-in; arbitrary oRPC Links and interceptors still require an application transport adapter.

Other runtime adapters

Node.js

node --import @dify/openapi-content-mapper/register app.ts

The hook loads YAML, .openapi and .openapi-source files; Node's native TypeScript support loads configuration sidecars. Native execution does not replace the separate type check.

Next.js

For pets.openapi linked to pets.json, configure next.config.mjs:

const loader = {
  loader: '@dify/openapi-content-mapper/loader',
  // Optional; relative to the resolved specification, not this config file.
  options: {
    runtime: './pets.openapi.config.ts',
    sidecars: './pets.openapi',
  },
}

export default {
  turbopack: {
    rules: {
      '*pets.json': { loaders: [loader], as: '*.js' },
      '*openapi-namespace.js': { loaders: ['@dify/openapi-content-mapper/loader'], as: '*.js' },
    },
  },
  webpack(config) {
    config.module.rules.push({
      test: /pets\.json$/,
      type: 'javascript/auto',
      use: [loader],
    })
    config.module.rules.push({
      test: /openapi-namespace\.js$/,
      type: 'javascript/auto',
      use: ['@dify/openapi-content-mapper/loader'],
    })
    return config
  },
}

Merge these rules into existing configuration. Match the resolved JSON filename for symlinks; match the actual .openapi or YAML filename for regular files. Apply the loader to openapi-namespace.js too, without document-specific options. Each document carries its own runtime and sidecar bindings into its child namespaces, so multiple documents can use different transports in one build. Omit options.runtime to discover <resolved specification filename>.config.ts. Set options.sidecars to the logical document path (relative to the resolved specification) when its .queries.ts and .errors.ts files live beside a symlink. Without this option they are discovered beside the resolved specification. Next.js runtime options do not change compiler context discovery, which uses the imported document's adjacent sidecar.

The loader uses a tiny shared resource for child namespaces so the full specification is not copied into every bundler module. Adapters use internal subpaths (runtime, query-runtime, namespace, mapper); application code should use the root, vite, loader and register entry points.

Limitations

External references, Swagger 2, URL-encoded forms, advanced parameter serialization, nested multipart file dictionaries and YAML aliases are unsupported. Inline schema inference has a 24-step fallback; local referenced schemas use recursive aliases. Unsupported request serialization fails explicitly. Missing or inaccurate OpenAPI declarations cannot be repaired by inference.

Existing oRPC Links and interceptors require explicit transport adapters; query policies and typed errors require the per-operation sidecars above. Browser Fetch governs cookie headers. Supported schema features include required/optional properties, enum/const, arrays and dictionaries, oneOf, anyOf, allOf, and nullable types.

Repository setup

The Dify workspace configures TypeScript 7.1, VS Code, Vite and Next.js to support future OpenAPI imports. Production Console and Marketplace calls continue to use their existing oRPC clients. Application transports, query-policy migration and business call-site changes are deferred.

The repository Console source descriptor lives in examples/repository/console.openapi-source. Its command exports community Console and FastOpenAPI schemas from local Python code into memory, then composes them with the retained Enterprise and App Deploy snapshots. Community specifications and the composed document are not committed or written during workspace installation. Ordinary installation and production application builds do not execute the exporter; consuming the experimental Console source requires Python dependencies:

uv sync --project api --frozen
pnpm --filter @dify/openapi-content-mapper build
pnpm --filter @dify/openapi-content-mapper check:console

No running API, database or private source checkout is needed. CI installs the Python environment before the standalone Console checks. compose:console now prints the composed OpenAPI JSON to stdout instead of creating a file.

Open the real Dify type examples to inspect dataset models, list/create inputs and outputs, multipart file uploads, and compatibility aliases retaining existing contracts names and request envelopes. The example imports Schemas, Inputs and Outputs from the live Console source descriptor; its sample values do not send requests. Check all repository examples with:

pnpm --filter @dify/openapi-content-mapper exec tsc --runExternalCode --noEmit -p examples/repository/tsconfig.json

The package uses vp pack and builds through prepare during workspace installation, like @langgenius/dev-proxy. Web's prebuild and prebuild:vinext hooks also build the SDK so production builds work after an installation with --ignore-scripts, including the unchanged Docker build flow.

The Console audit checks every generated procedure against a reviewed per-operation type-difference baseline. Standalone fixtures verify bundle pruning, error maps and workspace editor support without importing a production mapper client. The broader test:repository suite also needs the ignored API specifications generated with pnpm --dir packages/contracts gen-api-contract.

Regenerate existing oRPC contracts when backend schemas change. Enterprise snapshot regeneration still uses the matching source checkout through DIFY_ENTERPRISE_SERVER; those snapshots remain tracked because community checkouts cannot regenerate them. Inspect the comparison report before accepting intentional baseline changes with compare:orpc -- --console --update-baseline.

Development and release

From the repository root, build and verify the package:

pnpm --filter @dify/openapi-content-mapper build
pnpm --filter @dify/openapi-content-mapper type-check
pnpm --filter @dify/openapi-content-mapper test
OPENAPI_PACKAGE_TARBALL=/tmp/dify-openapi-content-mapper.tgz \
  pnpm --filter @dify/openapi-content-mapper test:package

The independent package check packs and installs the tarball outside the monorepo, then exercises its declarations, compiler mapper, Node runtime and official Vite adapter. It requires network access and performs no publication. Full application and Next.js builds run in CI.

Update the package version and CHANGELOG together before release. Use pnpm to pack: it resolves workspace catalog: dependencies, while prepack cleans and rebuilds dist. The package contains compiled ESM/declarations, README, changelog and license; consumers do not build it during installation.

A maintainer with npm access can publish the same verified artifact after confirming its name, version, license and registry:

npm publish /tmp/dify-openapi-content-mapper.tgz --access public --tag beta

The default tag is beta. Publication is manual; merging changes or creating a Dify release does not publish the package. Verify new compiler versions before changing the supported TS 7.1 beta protocol.

License

This package retains the repository's modified Apache 2.0 terms, including its additional conditions. See LICENSE; it is not licensed under unmodified Apache-2.0 or MIT.