@modainteract/moda-interact-shared
v2.5.1
Published
Shared TypeScript contracts and reusable platform primitives used by multiple Moda Interact services.
Readme
@modainteract/moda-interact-shared
Shared TypeScript contracts and reusable platform primitives used by multiple Moda Interact services.
This package is a library, not a deployable service. It does not own business transports, persistence, background workers, provider SDK integration, or application business workflows.
Install
npm install @modainteract/moda-interact-sharedProduction services should use the exact package version selected by the corresponding Moda Interact architecture/release task rather than relying on a floating version.
Public entry points
This reference covers the source API at package version 0.13.1. Prefer the
specific entry point for the contract you consume. Only paths listed in
package.json exports are public imports; a file under src or dist is not
necessarily a supported package subpath. Type-only exports require import type.
| Import suffix after @modainteract/moda-interact-shared | Use it for |
|---|---|
| (none) | Convenience re-exports of internationalization, billing, merchant communications, recovery policy and Shopify contracts only. |
| /internationalization | Language/country/currency/time-zone normalization, international context and ICU message catalogue validation/rendering. |
| /billing | Billing plan/usage contracts, provider-status normalization, subscription-reconciliation jobs, purchased-credit counters and deterministic billing identifiers. |
| /recovery-policy | Recovery offer modes and validation of an already-resolved effective recovery policy. Does not retrieve or decide merchant entitlements. |
| /whatsapp | Normalized inbound WhatsApp content/message schemas and parsers. Provider delivery statuses are in /billing. |
| /whatsapp-template-events | ARCH-047 v2 Meta template-status observations: strict nine-field schema and pure occurrence UUID v4 event/job ID formatters. |
| /whatsapp-template-events/fixtures | Portable JSON golden vectors for v2 status observations and expected BullMQ job IDs. |
| /merchant-communications | Merchant communication and translation job contracts, constants and validation. |
| /merchant-communications/node | Node-only deterministic translation queue-job identifiers. |
| /shopify | Shopify commerce/recovery event schemas, parsers, event versions and shared queue contracts. |
| /shopify/node | Node-only hashed webhook, checkout, order, recovery and discount-sync job identifiers. |
| /logging | Structured logger, levels, redaction and bounded serialization, with logger/sink types. |
| /logging/node | Node logging bootstrap, configuration and flushing for process-owned destinations. |
| /observability | Lightweight active-trace and observed-span helpers using installed global providers. |
| /observability/node | Node OpenTelemetry initialization and lifecycle; import from process preload. |
| /observability/bullmq | BullMQ telemetry adapter and options. Use in Node queue/worker configuration. |
| /observability/genai | Conversation, agent and tool observation helpers with bounded metrics and span metadata. |
| /testing/node | Node-only disposable PostgreSQL/Redis test infrastructure and command helpers; not application startup or production provisioning. |
| /commerce | Commerce schemas, definitions, selection helpers, response validation, canonical hashing inputs and synthetic examples. |
| /commerce/runner | Dependency-injected Commerce turn runner and model/tool adapter types. |
| /commerce/model | Runtime-safe model catalogue, selection, OpenRouter configuration and credential AAD contracts. |
| /commerce/model/node | Node-only OpenRouter chat-model adapter for the Commerce runner. |
The root entry does not re-export WhatsApp, Commerce, the runner, logging,
observability or Node helpers. Do not replace a documented subpath import with a
root import without checking its exports. /node entries and the BullMQ adapter
belong in server processes; keep them out of browser bundles.
The complete export inventory below includes runtime values and TypeScript types for every public entry point. Existing logging, observability and Shopify examples follow the Commerce guide.
Contract parsing and identifiers
Import the producer/consumer's matching schema, then validate untrusted input at the boundary. A TypeScript type alone does not validate a received payload.
import { NormalizedWhatsAppInboundMessageSchema } from
"@modainteract/moda-interact-shared/whatsapp";
// rawPayload is the normalized contract, not a raw Meta webhook body.
function acceptNormalizedMessage(rawPayload: unknown) {
const parsed = NormalizedWhatsAppInboundMessageSchema.safeParse(rawPayload);
if (!parsed.success) return { ok: false as const, issues: parsed.error.issues };
return { ok: true as const, message: parsed.data };
}Schemas expose Zod parse (throws on invalid input) and safeParse (discriminated
success/error result). Named parse… / safeParse… helpers are available only
where listed in the inventory. Producers and consumers must agree on the event
version; the existence of legacy and newer Shopify exports is not an instruction
to mix their shapes. Use the queue/job identifier helper for the particular
business operation, rather than treating all identifiers as interchangeable.
Internationalization provides normalization and message rendering, not the application's decision about when to change a conversation language. Effective recovery policy validation likewise does not load a merchant's current policy.
Commerce definitions, grants and execution
Commerce is exposed through two explicit imports:
import {
CommerceToolDefinitionSchema,
CommerceManifestSchema,
CommerceConversationGrantSchema,
selectCapabilities,
deduplicateTools,
} from "@modainteract/moda-interact-shared/commerce";
import { runCommerceTurn, type RunnerTool } from
"@modainteract/moda-interact-shared/commerce/runner";Which structure goes where
| Structure / API | Meaning and owner |
|---|---|
| CommerceToolDraftDefinitionSchema | Allows structurally bounded incomplete Tool-authoring data. Passing it does not make a Tool draft publishable. |
| CommerceToolDefinitionSchema | Full Tool name, version, description, input schema, execution definition and response template. Stored/executed by Commerce. |
| validateDefinitionForPublication | Uses a supplied CommerceDefinitionCompiler to check the full definition, mapped arguments and response-template paths. Commerce supplies schema-backed compilation. |
| ToolDescriptorSchema, definitionToMcpDescriptor | Full versioned Tool descriptor versus the MCP-facing name/description/inputSchema projection. The server-only execution definition is not exposed as model instructions. |
| CommerceManifestSchema | Resolved immutable release contract. Each selected Capability identifies one Feature and one exact Tool descriptor; featureBehaviours contains one behaviour prompt for each represented Feature. Commerce provides the manifest; callers validate it. |
| GrantedToolSchema, GrantedToolsSchema | Pinned Tool identity, exact Tool revision, name/version and sorted originating Capability keys selected for a conversation. One Tool reused by several Capabilities is emitted once with all Capability provenance. |
| CommerceConversationGrantSchema | Persisted conversation permission snapshot. Background stores the resolved release, selected Capability keys and granted Tools and reuses them on later turns. Empty Capability/Tool selections are valid. |
| CommerceTurnIdentitySchema, CommerceAssertionSchema | Turn identity and resolve/execute assertion shapes. These do not sign or verify JWT signatures; transport/authentication belongs to the services. |
| selectCapabilities | Pure selection over ordinary Feature Capabilities plus caller-supplied Feature eligibility facts. There is no BASE/RECOVERY_POLICY Capability kind or mandatory conversation_core. |
| deduplicateTools | Builds the granted-Tool union from one Tool descriptor per selected Capability while retaining deterministic Capability provenance. |
| manifestMatchesGrant, currentlyGrantedTools | Compare pinned selection and current availability. Do not replace signature, tenant, lease or persistence checks. |
| CommerceToolInputs, CommerceToolOutputs | Named supported operation contracts; custom authored inputs still use the validated Tool definition's schema. |
| CommerceBasketSchema, CommerceProductSchema, CommerceOfferSchema, CommerceEvidenceSchema, CommerceAlternativeSchema | Bounded commerce facts/evidence exchanged between services. Parsing does not prove external facts are true or current. |
| CommerceToolResultSchema, commerceToolResultSchema | Standard result envelope; the factory accepts a specific data schema. |
The direct release contract is Feature/Capability/Tool based. A selected Capability
contains exactly one featureId and one exact toolDescriptor; Feature behaviour
is carried separately and exactly once for each represented Feature. For example:
const manifest = CommerceManifestSchema.parse({
contractVersion: "commerce.v1",
releaseId: "release_123",
runnerCompatibility: "^1.0.0",
capabilities: [
{
capabilityId: "capability_product_read",
key: "product_read",
featureId: "feature_product_information",
position: 0,
toolDescriptor: {
toolId: "tool_product_read",
toolRevisionId: "tool_revision_7",
name: "read_product",
definitionVersion: "1.0.0",
description: "Read verified product information.",
inputSchema: {
type: "object",
properties: {},
required: [],
additionalProperties: false,
},
},
},
],
featureBehaviours: [
{
featureId: "feature_product_information",
behaviourPrompt: "Use verified product information when answering.",
},
],
selectedCapabilityKeys: ["product_read"],
grantedTools: [
{
toolId: "tool_product_read",
toolRevisionId: "tool_revision_7",
toolName: "read_product",
definitionVersion: "1.0.0",
capabilityKeys: ["product_read"],
},
],
responseContract: {
version: "response.v1",
instructions: "Write a concise reply supported by verified facts.",
detailsSchema: {
type: "object",
properties: {},
required: [],
additionalProperties: false,
},
},
responseContractHash: "0".repeat(64),
});The identifiers and hash above are illustrative. Publication/manifest assembly must prove that the Capability belongs to the Feature, the pinned Tool revision belongs to the Tool and is published, and the Feature behaviour snapshot belongs to the same immutable release. Shared schema parsing cannot prove those database relationships.
The normal flow is:
- Commerce Studio associates an ordinary Feature Capability with one Tool; release creation pins the exact published Tool revision and snapshots Feature behaviour.
- Commerce resolves eligible Feature Capabilities using authoritative merchant facts and builds a manifest whose Capability entries are position ordered.
featureBehaviourscontains exactly one entry per represented Feature, ordered by that Feature's first Capability position. Blank behaviour text is valid.- Background receives the manifest and persists its
grantedTools, release and selected Capability keys in a conversation grant. Zero selected Capabilities and zero granted Tools are valid. - Background checks MCP descriptors against that manifest/grant and constructs
runtime
RunnerTooladapters. The model chooses a Tool and supplies arguments; the adapter forwards execution to Commerce. - Later turns reuse the original grant. A new release cannot add Tools to that conversation; current revocation may remove execution permission.
Turn runner integration
RunnerTool is an in-memory adapter, distinct from durable Capability/Tool
associations:
import type { ToolDescriptor, GrantedTool, CommerceToolResult } from
"@modainteract/moda-interact-shared/commerce";
// Shape of the exported RunnerTool interface, shown for explanation.
type RunnerToolShape = {
descriptor: ToolDescriptor;
isAuthorized: (tool: GrantedTool, signal: AbortSignal) => Promise<boolean>;
execute: (
arguments_: Record<string, unknown>,
signal: AbortSignal,
) => Promise<CommerceToolResult>;
extractEvidence?: (result: CommerceToolResult) => unknown[];
};Import RunnerTool rather than copying this explanatory shape. runCommerceTurn
takes RunCommerceTurnInput: turn, grant, manifest, host instructions, trusted
context, history, resolved language, abort signal and dependencies. Feature
behaviour is consumed from manifest.featureBehaviours; callers do not pass a
parallel Capability-prompt array. The host provides model.invoke, tools, now
and a canonical-string digest function. Optional budgets bound model steps,
remote calls, deadline and output tokens. The model adapter returns ModelStep
Tool calls and output-token usage; it does not send a WhatsApp message itself.
The return type is discriminated:
import type { CommerceFinalResponse } from
"@modainteract/moda-interact-shared/commerce";
import type { RunnerErrorCode } from
"@modainteract/moda-interact-shared/commerce/runner";
// Shape of RunCommerceTurnResult, shown for explanation.
type TurnResultShape =
| { ok: true; result: CommerceFinalResponse;
usage: { modelSteps: number; remoteCalls: number } }
| { ok: false; error: { code: RunnerErrorCode; retryable: boolean } };The runner owns bounded orchestration, authorization callbacks and final-response
validation. It does not own an MCP HTTP client, a model SDK, Prisma, conversation
leases or WhatsApp delivery. Background owns those production adapters; preview
can inject isolated fixture/model adapters. Never replace an unavailable
production adapter with example* data.
runnerVersion describes runner compatibility independently of the npm package
version. PLATFORM_INSTRUCTIONS is the runner's fixed grounding, authorization,
language and finalization guidance. Feature behaviour, response guidance and other
authored release text cannot expand permissions or override those rules.
Model catalogue and OpenRouter adapter
Use /commerce/model for the environment, availability, catalogue, selection,
extensible OpenRouter configuration, resolved-model and credential AAD contracts.
The configuration schema bounds ordinary JSON and blocks runtime-owned fields;
unknown non-reserved OpenRouter options remain available for forward-compatible
provider features. createCommerceOpenRouterCredentialAad returns the canonical
string that each service UTF-8 encodes for its own encrypted-credential handling.
Server-side Commerce and Background adapters may use /commerce/model/node to
bridge a resolved model and runtime credential to the existing
CommerceModelInvoker. This adapter does not resolve model assignments, store or
decrypt credentials, execute remote Tools, or own the Commerce turn loop. The
runner remains the authority for Tool visibility, authorization, retries and
final-response validation.
Response contracts and final responses
CommerceResponseContractSchema validates the release-owned
{version: "response.v1", instructions, detailsSchema} definition.
EMPTY_RESPONSE_CONTRACT is the empty-details baseline. Use the supported
DetailsSchemaSchema / InputSchemaSchema subset rather than assuming arbitrary
JSON Schema keywords are accepted; validateSubset, matchesSubset and
compileSubset expose the same subset validation/matching machinery.
CommerceFinalResponseSchema validates the fixed envelope: answerKind,
replyText, referralReason, detectedLanguageTag,
detectedLanguageConfidence, evidenceIds and details.
finalResponseSchema(definition) additionally validates the selected release's
details schema. finalResponseToolSchema(definition) produces the host-local
finalization Tool's input schema. verifyResponseContract checks the definition
against its hash using the caller's digest implementation.
An ANSWER requires null referral reason; a REFER_TO_STORE response requires the appropriate reason, empty evidence IDs and empty details. Language detection fields are either both null or a valid pair. Only reply text is customer-facing; structured details never authorize actions or replace delivery/routing decisions.
Use canonicalJson, responseContractCanonicalJson and toolHashInput for their
specific canonicalization/hashing boundaries. Do not hash arbitrary object
serialization in place of these helpers. mapToolArguments maps validated authored
inputs/fixed values; it does not call Shopify. POLICY_OPERATIONS and
POLICY_OPERATION_DESCRIPTORS describe supported operation identities; actual
provider implementations remain in Commerce.
exampleTool, exampleDefinition, exampleTurn, exampleManifest,
exampleGrant and exampleFinal are synthetic fixtures for examples and tests,
not seeds for a merchant's production configuration.
What this package owns
The package contains code that genuinely belongs at a cross-service boundary, including:
- runtime-validated cross-service event contracts;
- TypeScript types shared by producers and consumers;
- schema and event-version constants;
- canonical queue/job-name constants where multiple repositories must agree;
- deterministic correlation/job identifier helpers;
- small pure utilities used by more than one service;
- reusable structured application logging primitives;
- the reusable base Node OpenTelemetry runtime, including tracing and metrics providers, exporters, sampling, HTTP/Undici instrumentation, lifecycle, and generic observability helpers.
The package deliberately keeps framework and runtime dependencies small.
Commerce contracts
The browser-safe Commerce contract entrypoint is:
import {
CommerceToolDefinitionSchema,
ExternalHttpExecutionSchema,
ExternalHttpResultDataSchema,
ResponseProcessingSchema,
ConnectionViewSchema,
} from "@modainteract/moda-interact-shared/commerce";The public /commerce inventory includes the canonical JSON, subset, primitive,
definition, schema, response, selection, fixture and external contract exports.
External contracts include ExternalQueryValueSchema,
ExternalQueryMappingSchema, ExternalQueryMappingsSchema,
ExternalPathSchema, ExternalResponseFormatSchema,
FieldProjectionSchema, ResponseFilterSchema,
VisualResponseProcessingSchema, ResponseProcessingSchema,
TransformResponseSchema, TransformSampleSchema,
ExternalHttpResultDataSchema, ConnectionRevisionViewSchema,
ConnectionViewSchema, CredentialStatusSchema, ConnectionCommandSchema,
RevisionInputSchema, ConnectionIssueSchema, and ConnectionResultSchema,
plus their corresponding TypeScript types and the external execution,
publication, mapping and descriptor helpers from definitions.
The Node-only /commerce/runner entrypoint exports the Commerce runner version,
platform instructions, manifest/grant/result schemas, response-contract helpers,
and runner request/step/result types. It owns protocol validation helpers only;
provider transport, credentials, response processing and persistence remain in
their service-owned repositories.
Node observability runtime
The package provides a browser-safe semantic observability entry and a Node-only runtime entry:
import {
getActiveTraceId,
withObservedSpan,
} from "@modainteract/moda-interact-shared/observability";
import {
initNodeObservability,
} from "@modainteract/moda-interact-shared/observability/node";Import ./observability/node only from a process preload. It installs tracing,
metrics, HTTP/HTTPS and Undici/fetch instrumentation before framework or worker
modules load:
node --import ./observability.mjs <framework-or-worker-entrypoint>// observability.mjs
import { initNodeObservability } from
"@modainteract/moda-interact-shared/observability/node";
initNodeObservability({
serviceName: "moda-interact-messaging",
environment: process.env.DEPLOYMENT_ENVIRONMENT_NAME,
instrument: { http: true, fetch: true, prisma: false },
});Set prisma: true only for processes that load Prisma, and keep the preload
before the first Prisma application import.
The runtime uses the canonical service.namespace, service.name, and
deployment.environment.name resource attributes. It honors
OTEL_TRACES_SAMPLER, ratio arguments for ratio samplers, signal-specific or
generic OTLP endpoints, and bounded batch/export settings. With no trace or
metric endpoint those pipelines are no-ops while structured stdout logging
continues.
forceFlush() covers traces, metrics, OpenTelemetry Logs, and direct Loki.
Initialization, export, flush, and shutdown failures are best-effort and do not
become application startup or business-operation failures.
BullMQ telemetry
Create the shared BullMQ telemetry adapter once per Queue or Worker options
object and pass it through BullMQ's native telemetry option:
import { createBullMQTelemetry } from
"@modainteract/moda-interact-shared/observability/bullmq";
const telemetry = createBullMQTelemetry({
serviceName: "moda-messaging-worker",
enableMetrics: true,
});
new Worker(queueName, processor, { connection, telemetry });The adapter uses the global trace and meter providers installed by the Node runtime. BullMQ owns propagation metadata in its job options; applications must not copy or mutate queue payloads solely to carry trace context. BullMQ metrics use queue name, bounded job name, and job state dimensions, never Moda job, shop, checkout, conversation, or message IDs.
GenAI active spans
Use the GenAI helpers to model one inbound conversation turn as an independent trace with active agent, tool, and automatically instrumented child spans:
import {
observeAgentInvocation,
observeAgentTool,
observeConversationTurn,
} from "@modainteract/moda-interact-shared/observability/genai";
await observeConversationTurn("whatsapp", () =>
observeAgentInvocation({ agentName: "commerce-agent" }, () =>
observeAgentTool("lookup-products", executeTool),
),
);Pass recordMetrics: false to activate a helper's span without recording its
GenAI metrics. The option applies only to that helper invocation, so pass it to
each nested helper whose metrics should be suppressed:
const spansOnly = { recordMetrics: false } as const;
await observeConversationTurn("whatsapp", () =>
observeAgentInvocation({ agentName: "commerce-agent" }, () =>
observeAgentTool("lookup-products", executeTool, spansOnly),
spansOnly,
),
spansOnly,
);An optional mapException callback can replace the application failure with a
bounded telemetry-safe representation for span.recordException. The original
thrown value is still rethrown unchanged. If the mapper throws or returns no
usable fields, the exception event is omitted and the span remains ERROR;
the original value is never recorded as fallback. Apply the mapper to every
nested helper that may observe the same rethrown failure:
const safeObservation = {
recordMetrics: false,
mapException: () => ({
name: "ProviderError",
message: "Provider operation failed",
}),
} as const;
await observeAgentTool("lookup-products", executeTool, safeObservation);The helpers use only the global tracer and meter providers installed by the
Node runtime. They create no SDK, provider, exporter, or network request, and
remain lightweight no-ops when providers are absent. Six module-singleton
instruments record turn, agent, and tool duration and operation outcomes.
Metric attributes are limited to outcome=success|error; turn metrics also use
the closed channel=whatsapp|other vocabulary. Arbitrary agent, provider,
model, tool, and Moda business identifiers never become metric dimensions.
Agent, provider, model, and tool names are trimmed and bounded on spans only. Prompt, completion, message, and tool payload bodies are never accepted or captured by default.
What this package does not own
This package does not own:
- Prisma models or database migrations;
- PostgreSQL persistence;
- BullMQ/Redis clients or worker processes;
- Shopify or Meta webhook HTTP handlers;
- Shopify or Meta SDK integration;
- application recovery/business logic;
- service/domain-specific span names, business attributes, or application metrics;
- deployment OTLP endpoint/credential wiring or observability backends;
- Render deployment configuration.
Those service-specific semantics and deployment concerns remain in the repository that owns the corresponding runtime.
Shopify contracts
Moda Interact uses the shared Shopify package boundary so webhook producers and background consumers do not independently invent compatible-looking event types.
Import Shopify contracts from:
import {
// schemas, parsers, constants and types
} from "@modainteract/moda-interact-shared/shopify";Node-only Shopify helpers are isolated under:
import {
createShopifyWebhookJobId,
} from "@modainteract/moda-interact-shared/shopify/node";The Node-only subpath prevents node: built-ins from being accidentally pulled
into consumers that only need the browser-safe Shopify contract entry point.
Recovery-focused events
The current recovery architecture defines distinct event meanings for:
checkout.created
checkout.updated
order.completedPre-recovery checkout events deliberately avoid transporting customer identity, line-item, pricing and address data merely because those values existed in the provider webhook.
Consumers must parse/validate cross-service data with the shared runtime contracts before acting on it. TypeScript types alone are not a trust boundary.
Contract versioning
Serialized event schema versions and the npm package version are separate concepts.
A breaking change to an existing serialized event contract requires an appropriate event-schema version change and coordinated producer/consumer rollout.
An additive npm package capability, such as a new independent package export, does not by itself require changing an unrelated serialized event schema.
Structured logging
Moda Interact runtime services use one reusable structured logging primitive:
import {
createLogger,
type StructuredLogger,
type LogFields,
} from "@modainteract/moda-interact-shared/logging";Create a logger
Each deployable service/process supplies its own identity and environment:
const logger = createLogger({
serviceName: "moda-interact",
environment: "test",
});The default namespace is:
moda-interactLogs contain the canonical identity:
service.namespace=moda-interact
service.name=<service/process name>
deployment.environment.name=<environment>For deployed Moda Interact environments, the expected environment values are:
test
productionThe shared library does not read a service's environment variables for it.
The owning service resolves its configuration and passes the resulting
environment to createLogger.
Write logs
logger.info("shopify.webhook.outcome", {
topic: "checkouts/create",
outcome: "ENQUEUED",
ackMs: 18,
});
logger.warn("queue.job.retry", {
queue: "recovery",
attempt: 2,
});
logger.error("recovery.failed", {
recoveryId,
error,
});The default sink emits one structured JSON record per console call.
Example:
{
"timestamp": "2026-08-30T12:00:00.000Z",
"level": "info",
"event": "shopify.webhook.outcome",
"service.namespace": "moda-interact",
"service.name": "moda-interact",
"deployment.environment.name": "test",
"data": {
"topic": "checkouts/create",
"outcome": "ENQUEUED",
"ackMs": 18
}
}Log levels
Available levels are:
debug
info
warn
errorUse stable, machine-readable event names such as:
shopify.webhook.outcome
meta.webhook.outcome
queue.job.started
queue.job.completed
queue.job.failed
recovery.materializedChild loggers
child() is optional.
It creates another logger with some repeated fields already attached. It does not create a worker, queue, process, connection, or logging service.
Instead of repeatedly writing:
logger.info("queue.job.started", {
queue: "recovery",
jobId,
});
logger.info("queue.job.completed", {
queue: "recovery",
jobId,
});you may write:
const recoveryLogger = logger.child({
queue: "recovery",
});
recoveryLogger.info("queue.job.started", {
jobId,
});
recoveryLogger.info("queue.job.completed", {
jobId,
});Both records automatically contain:
{
"queue": "recovery"
}Use child context only for stable, safe operational fields.
Sensitive data
The logger provides defense-in-depth redaction and bounded serialization, but callers remain responsible for constructing safe, explicit log fields.
Do not intentionally log:
- access or refresh tokens;
- authorization headers;
- cookies;
- OAuth codes;
- passwords or API keys;
- private keys;
- webhook verification secrets;
- complete webhook/request/response payloads;
- customer names, email addresses, phone numbers or postal addresses;
- payment/card data.
Do not pass a complete provider/customer object to the logger and rely on redaction to make it safe.
Errors
Errors can be logged as values:
logger.error("queue.job.failed", {
jobId,
error,
});The shared logger safely serializes Error objects without emitting stack
traces by default.
Logging is best-effort: a logger sink or serialization failure must not alter the success/failure semantics of the business operation being logged.
Logging destinations
Every call to the shared logger:
logger.debug(...)
logger.info(...)
logger.warn(...)
logger.error(...)emits the same already-sanitized canonical record to up to three independent, best-effort destinations:
- canonical structured JSON to the configured sink (default: console);
- the OpenTelemetry Logs API via the global
LoggerProvider, if one has been installed; - a direct Grafana Loki transport, if the Node process bootstrap has installed the Loki emitter.
Each destination is failure-isolated: a failure in one must not suppress another and must never affect application/business correctness.
The OpenTelemetry API is a no-op when no provider is installed, so stdout logging continues to work in local/test environments without any backend.
The heavy Node SDK/exporter and the Winston/winston-loki transport are isolated in:
@modainteract/moda-interact-shared/logging/nodeand must be imported and initialized only from the Node process bootstrap — never through Vite/application/browser bundles.
application module
|
v
@modainteract/moda-interact-shared/logging
|
+--> canonical JSON stdout
|
+--> @opentelemetry/api-logs
| |
| | global LoggerProvider
| v
| ./logging/node
| |
| +--> LoggerProvider
| +--> BatchLogRecordProcessor
| +--> OTLPLogExporter
| |
| v
| /v1/logs
|
+--> lightweight Loki bridge (globalThis emitter)
|
v
./logging/node
|
+--> Winston + winston-loki
|
v
Grafana LokiWinston and winston-loki exist only in the Node-only package graph. The
normal ./logging entry contains no Winston, winston-loki or Node networking
imports.
Node bootstrap
Process bootstrap code installs the optional destinations once:
import {
initNodeLokiLogging,
initNodeOpenTelemetryLogging,
} from "@modainteract/moda-interact-shared/logging/node";
initNodeLokiLogging({
serviceName: "moda-interact",
environment: "production",
});
initNodeOpenTelemetryLogging({
serviceName: "moda-interact",
environment: "production",
});Each destination is independently configurable, so a deployment may use:
console only
console + Loki
console + OTel Logs
console + Loki + OTel LogsEither Node destination may be omitted entirely; without an installed provider/emitter the logger remains a safe stdout-only logger.
The bootstrap supports the standard OpenTelemetry environment variables:
OTEL_SDK_DISABLED
OTEL_LOGS_EXPORTER
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
OTEL_EXPORTER_OTLP_ENDPOINT
OTEL_EXPORTER_OTLP_LOGS_HEADERS
OTEL_EXPORTER_OTLP_HEADERS
OTEL_BLRP_MAX_QUEUE_SIZE
OTEL_BLRP_MAX_EXPORT_BATCH_SIZE
OTEL_BLRP_SCHEDULE_DELAY
OTEL_BLRP_EXPORT_TIMEOUT
OTEL_LOG_EXPORT_CONCURRENCY_LIMITEndpoint rules:
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
exact signal endpoint; do not append /v1/logs
OTEL_EXPORTER_OTLP_ENDPOINT
generic endpoint; append /v1/logsModa deliberately does not export to the OpenTelemetry default localhost endpoint. Without an explicitly configured endpoint the logger remains stdout-only.
Direct Loki transport
The direct Loki transport is a lightweight bridge: the normal ./logging entry
stores an emitter on globalThis and the Node bootstrap installs it. Records
still pass through the same shared redaction/sanitization used for stdout and
OpenTelemetry.
The Loki environment contract is:
LOKI_ENABLED
LOKI_URL
LOKI_USERNAME
LOKI_PASSWORD
LOKI_BATCHING
LOKI_BATCH_INTERVAL_SECONDS
LOKI_TIMEOUT_MS
LOKI_CLEAR_ON_ERRORRules:
no LOKI_URL
-> direct Loki disabled
LOKI_ENABLED=false
-> direct Loki disabled
LOKI_URL present
-> direct Loki enabled by defaultCredentials are Node-bootstrap configuration only. Never log LOKI_URL
credentials, LOKI_USERNAME, LOKI_PASSWORD, Basic Auth values or connection
headers.
Default transport behavior:
batching=true
bounded timeout (LOKI_TIMEOUT_MS)
clearOnError=true
replaceTimestamp=true
gracefulShutdown=falseThe owning process bootstrap is responsible for explicit flush/shutdown via the
returned runtime (forceFlush/shutdown). If Loki is unavailable, log records
may be dropped but application processing must continue. Connection errors are
not recursively written back through the shared logger.
Loki labels and cardinality
Moda explicitly configures exactly three canonical low-cardinality labels:
service_namespace
service_name
environment[email protected] additionally adds its own low-cardinality level label
to every pushed stream, so a stream carries the three Moda labels plus
level. This is transport-library behaviour and does not change Moda's label
configuration.
Dynamic/high-cardinality identifiers must not be promoted to Loki stream
labels. The implementation explicitly retains
useWinstonMetaAsLabels: false, so winston metadata is never promoted to
labels. In particular, do not label by:
traceId
spanId
requestId
jobId
deliveryId
eventId
recoveryId
checkoutToken
cartToken
shop
shopDomain
customerId
phone
emailSafe high-cardinality operational identifiers may remain in the sanitized JSON log body where justified, but they must never become indexed stream labels.
Duplicate-delivery warning
Do not route the OpenTelemetry Logs destination back into the same Loki instance while direct Loki is also enabled, unless duplicate storage is intentional:
direct Loki ON
+
OTel Logs ultimately routed to same Loki
=
duplicate log storageThe library does not guess backend topology; deployment configuration owns this choice.
Log-signal data safety and correlation
The OpenTelemetry log body is
JSON.stringifyof the same canonical sanitizedLogRecordwritten to stdout, so the same redaction boundary applies to both destinations.Queryable OTel attributes are limited to:
event.name log.level service.namespace service.name deployment.environment.nameThe shared logger never manufactures trace IDs. If an active trace/span context exists, the OpenTelemetry Logs SDK associates the emitted record with that active context automatically.
stdout and OpenTelemetry emission are isolated and best-effort: a failure in either must not change application/business correctness.
Tracing/metrics ownership
The shared logger does not create spans, counters or histograms.
The shared observability runtime owns the generic Node SDK, tracing and metrics provider mechanics, exporters, sampling, HTTP/Undici instrumentation, generic helpers, and lifecycle. Service repositories own their span names, business attributes, application-specific metrics, and domain semantics, for example:
Shopify operation
|
+--> shared structured logger (stdout + OTel Logs)
|
+--> Shopify-specific OpenTelemetry (spans/metrics)This separation is intentional. Fields that are useful in diagnostic logs can have very different cardinality constraints from metric attributes.
Package exports
The public package exposes independent entry points.
@modainteract/moda-interact-shared
existing root exports
@modainteract/moda-interact-shared/shopify
Shopify cross-service contracts, schemas, constants and pure helpers
@modainteract/moda-interact-shared/shopify/node
Node-only Shopify helpers
@modainteract/moda-interact-shared/logging
reusable structured logging API
(stdout + OTel Logs + direct Loki fan-out)
@modainteract/moda-interact-shared/logging/node
Node-only logging bootstrap
(OpenTelemetry LoggerProvider, batching, OTLP HTTP exporter;
Winston + winston-loki direct transport)
@modainteract/moda-interact-shared/observability
browser-safe generic observability helpers
@modainteract/moda-interact-shared/observability/node
reusable Node OpenTelemetry SDK, tracing/metrics providers, exporters,
sampling, HTTP/Undici instrumentation, and lifecycle
@modainteract/moda-interact-shared/observability/bullmq
Node-only BullMQ native telemetry adapter
@modainteract/moda-interact-shared/observability/genai
Node/runtime GenAI conversation-turn, agent, and tool active-span helpersConsumers should prefer the narrowest appropriate subpath.
Ownership boundary
Examples of repository ownership:
moda-interact
- authenticates Shopify ingress;
- normalizes/validates Shopify events;
- publishes the appropriate queue jobs;
- uses the shared structured logger for generic log mechanics;
- uses the shared observability runtime for generic OpenTelemetry mechanics;
- owns Shopify-specific observability semantics and application metrics.
moda-interact-background
- parses shared cross-service contracts before acting;
- runs BullMQ workers and recovery workflows;
- uses the shared logger for generic structured logging;
- uses the shared observability runtime for generic OpenTelemetry mechanics;
- owns worker/recovery observability semantics and application metrics.
moda-interact-messaging
- owns Meta/WhatsApp ingress;
- uses the shared logger for generic structured logging;
- uses the shared observability runtime for generic OpenTelemetry mechanics;
- owns Meta/WhatsApp-specific observability semantics and application metrics.
moda-interact-admin
- owns the internal admin application;
- may use the same shared logger where server-side operational logging is required;
- uses the shared observability runtime for generic OpenTelemetry mechanics;
- owns admin-specific observability semantics and application metrics.
moda-interact-database
- owns Prisma schema/migrations and database artifacts;
- does not duplicate shared TypeScript transport contracts.
Development
Typecheck
npm run typecheckBuild
npm run buildTest
npm testInspect the publish artifact
Before publishing:
npm pack --dry-runVerify that the intended JavaScript and type declarations for every public subpath are included.
Release policy
The npm package version follows semantic versioning.
Examples:
patch
backwards-compatible fix to an existing package capability
minor
backwards-compatible new public capability/export
major
breaking public API/package compatibility changeThe addition of the independent ./logging public API is an additive package
capability and should therefore be released as a minor version increment.
Publishing the package and changing consuming services are coordinated tasks; a consuming service must not assume an unpublished local shared export exists in the npm artifact it installs.
Complete export inventory
Enumerated from the TypeScript module exports for every package.json public
entry point, including re-exports and type-only symbols. Source files are linked
for exact signatures, fields, defaults and validation constraints. This inventory
does not make internal modules into public import paths. When changing exports,
update both the entry-point guide and this inventory.
Import: @modainteract/moda-interact-shared.
From src/billing.ts:
Runtime exports:
APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MSARCH007_BILLING_CONTRACT_SCHEMA_VERSIONavailablePurchasedRecoveryCreditsBILLING_PLAN_KINDSBILLING_SUBSCRIPTION_RECONCILE_JOB_NAMEBILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAMEBILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSIONBILLING_SYSTEM_MESSAGE_CODESBILLING_USAGE_METRICSBillingPlanKindSchemaBillingSubscriptionReconcileJobSchemaBillingSystemMessageCodeSchemaBillingUsageMetricSchemacreateBillingSubscriptionReconcileJobIdcreateMerchantBillingSystemSourceKeycreateRecoveryIdempotencyKeycreateShopifyUsageIdempotencyKeyderiveShopifyProviderContextIdentityisSameShopifyPurchaseProviderContextNormalizedWhatsAppStatusSchemaparseBillingSubscriptionReconcileJobparseNormalizedWhatsAppStatussafeParseBillingSubscriptionReconcileJobsafeParseNormalizedWhatsAppStatusWHATSAPP_PROVIDER_STATUS_SCHEMA_VERSIONWHATSAPP_PROVIDER_STATUSESWhatsAppProviderPricingMetadataSchemaWhatsAppProviderStatusSchema
Type-only exports:
BillingPlanKindBillingSubscriptionReconcileJobBillingSystemMessageCodeBillingUsageMetricNormalizedWhatsAppStatusPurchasedRecoveryCreditCounterSnapshotShopifyCurrentProviderContextShopifyProviderContextIdentityInputShopifyPurchaseProviderContextWhatsAppProviderPricingMetadataWhatsAppProviderStatus
From src/internationalization.ts:
Runtime exports:
canonicaliseLanguageTagCountryCodeSchemacreateInternationalizationRuntimeCurrencyCodeSchemaInternationalContextSchemaLanguageSourceSchemaLanguageTagSchemamergeInternationalContextnormalizeCountryCodenormalizeCurrencyCodenormalizeTimeZoneresolveLocaleDirectionTimeZoneIdSchemavalidateIcuCatalogue
Type-only exports:
CatalogueValidationOptionsCountryCodeCurrencyCodeIcuMessageCatalogueIcuMessageValuesInternationalContextInternationalizationRuntimeInternationalizationRuntimeOptionsLanguageSourceLanguageTagTimeZoneId
From src/merchant-communications.ts:
Runtime exports:
AuthoredSupportBodySchemacountUnicodeGraphemesMERCHANT_COMMUNICATIONS_JOB_NAMESMERCHANT_COMMUNICATIONS_QUEUE_NAMEMERCHANT_COMMUNICATIONS_SCHEMA_VERSIONMerchantMessageTranslationContractSchemaMerchantMessageTranslationStatusSchemaMerchantSupportMessageContractSchemaMerchantSupportMessageKindSchemaMerchantSupportMessageStateSchemaMerchantTranslationBatchContractSchemaMerchantTranslationBatchStatusSchemaMerchantTranslationDirectionSchemaMerchantTranslationReconciliationRequestContractSchemaMerchantTranslationReconciliationScopeSchemaMerchantTranslationReconciliationStatusSchemaPLATFORM_SUPPORT_LANGUAGE_TAGrequiresMerchantTranslationTranslatedSupportBodySchemaTranslationBatchPollJobSchemaTranslationBatchResultsJobSchemaTranslationBatchSubmitJobSchemaTranslationDispatchJobSchemaTranslationReconcileJobSchema
Type-only exports:
MerchantMessageTranslationContractMerchantMessageTranslationStatusMerchantSupportMessageContractMerchantSupportMessageKindMerchantSupportMessageStateMerchantTranslationBatchContractMerchantTranslationBatchStatusMerchantTranslationDirectionMerchantTranslationReconciliationRequestContractMerchantTranslationReconciliationScopeMerchantTranslationReconciliationStatusTranslationBatchPollJobTranslationBatchResultsJobTranslationBatchSubmitJobTranslationDispatchJobTranslationReconcileJob
From src/recovery-policy.ts:
Runtime exports:
EffectiveRecoveryPolicySchemaparseEffectiveRecoveryPolicyRECOVERY_OFFER_MODESRecoveryOfferModeSchemasafeParseEffectiveRecoveryPolicy
Type-only exports:
EffectiveRecoveryPolicyRecoveryOfferMode
From src/shopify/common.schema.ts:
Runtime exports:
MAX_LINE_ITEMSMAX_URL_LENGTHShopifyCheckoutLineItemSchemaShopifyCheckoutLineItemsSchemaShopifyCustomerReferenceSchemaShopifyMoneySchemaShopifyTenantSchema
Type-only exports:
ShopifyCheckoutLineItemShopifyCustomerReferenceShopifyMoneyShopifyTenant
From src/shopify/constants.ts:
Runtime exports:
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSIONSHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION_V1SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION_V2SHOPIFY_COMMERCE_EVENT_TYPESSHOPIFY_RECOVERY_EVENT_TYPES_V2SHOPIFY_WEBHOOK_OUTBOX_DESTINATIONS
From src/shopify/queue-contracts.ts:
Runtime exports:
parseShopifyDiscountSyncJobsafeParseShopifyDiscountSyncJobSHOPIFY_DISCOUNT_SYNC_REASONSSHOPIFY_DISCOUNT_SYNC_WEBHOOK_TOPICSSHOPIFY_WEBHOOK_QUEUE_CONTRACTSShopifyDiscountSyncJobSchemaShopifyDiscountSyncReasonSchemaShopifyDiscountSyncWebhookTopicSchema
Type-only exports:
ShopifyDiscountSyncJob
From src/shopify/v1/checkout-observed.schema.ts:
Runtime exports:
CheckoutObservedPayloadSchema
Type-only exports:
CheckoutObservedPayload
From src/shopify/v1/commerce-event.schema.ts:
Runtime exports:
createShopifyCommerceOrderingKeycreateShopifyOrderOrderingKeyisCheckoutObservedEventisOrderCompletedEventparseShopifyCommerceEventsafeParseShopifyCommerceEventShopifyCheckoutObservedEventSchemaShopifyCommerceEventSchemaShopifyOrderCompletedEventSchema
Type-only exports:
ShopifyCheckoutObservedEventShopifyCommerceEventShopifyCommerceEventTypeShopifyOrderCompletedEvent
From src/shopify/v1/order-completed.schema.ts:
Runtime exports:
OrderCompletedPayloadSchema
Type-only exports:
OrderCompletedPayload
From src/shopify/v2/cart-activity.schema.ts:
Runtime exports:
ShopifyCartActivityPayloadV2Schema
Type-only exports:
ShopifyCartActivityPayloadV2
From src/shopify/v2/checkout-created.schema.ts:
Runtime exports:
CheckoutCreatedPayloadV2Schema
Type-only exports:
CheckoutCreatedPayloadV2
From src/shopify/v2/checkout-updated.schema.ts:
Runtime exports:
CheckoutUpdatedPayloadV2Schema
Type-only exports:
CheckoutUpdatedPayloadV2
From src/shopify/v2/order-completed.schema.ts:
Runtime exports:
OrderCompletedPayloadV2Schema
Type-only exports:
OrderCompletedPayloadV2
From src/shopify/v2/recovery-event.schema.ts:
Runtime exports:
createShopifyCartActivityOrderingKeycreateShopifyOrderCorrelationOrderingKeycreateShopifyPendingRecoveryOrderingKeyisCartActivityEventV2isCheckoutCreatedEventV2isCheckoutUpdatedEventV2isOrderCompletedEventV2parseShopifyRecoveryEventV2safeParseShopifyRecoveryEventV2ShopifyCartActivityEventV2SchemaShopifyCheckoutCreatedEventV2SchemaShopifyCheckoutUpdatedEventV2SchemaShopifyOrderCompletedEventV2SchemaShopifyRecoveryEventV2Schema
Type-only exports:
ShopifyCartActivityEventV2ShopifyCheckoutCreatedEventV2ShopifyCheckoutUpdatedEventV2ShopifyOrderCompletedEventV2ShopifyRecoveryEventTypeV2ShopifyRecoveryEventV2
Import: @modainteract/moda-interact-shared/internationalization.
From src/internationalization.ts:
Runtime exports:
canonicaliseLanguageTagCountryCodeSchemacreateInternationalizationRuntimeCurrencyCodeSchemaInternationalContextSchemaLanguageSourceSchemaLanguageTagSchemamergeInternationalContextnormalizeCountryCodenormalizeCurrencyCodenormalizeTimeZoneresolveLocaleDirectionTimeZoneIdSchemavalidateIcuCatalogue
Type-only exports:
CatalogueValidationOptionsCountryCodeCurrencyCodeIcuMessageCatalogueIcuMessageValuesInternationalContextInternationalizationRuntimeInternationalizationRuntimeOptionsLanguageSourceLanguageTagTimeZoneId
Import: @modainteract/moda-interact-shared/billing.
From src/billing.ts:
Runtime exports:
APP_PRICING_BILLING_PERIOD_DRAIN_WINDOW_MSARCH007_BILLING_CONTRACT_SCHEMA_VERSIONavailablePurchasedRecoveryCreditsBILLING_PLAN_KINDSBILLING_SUBSCRIPTION_RECONCILE_JOB_NAMEBILLING_SUBSCRIPTION_RECONCILE_QUEUE_NAMEBILLING_SUBSCRIPTION_RECONCILE_SCHEMA_VERSIONBILLING_SYSTEM_MESSAGE_CODESBILLING_USAGE_METRICSBillingPlanKindSchemaBillingSubscriptionReconcileJobSchemaBillingSystemMessageCodeSchemaBillingUsageMetricSchemacreateBillingSubscriptionReconcileJobIdcreateMerchantBillingSystemSourceKeycreateRecoveryIdempotencyKeycreateShopifyUsageIdempotencyKeyderiveShopifyProviderContextIdentityisSameShopifyPurchaseProviderContextNormalizedWhatsAppStatusSchemaparseBillingSubscriptionReconcileJobparseNormalizedWhatsAppStatussafeParseBillingSubscriptionReconcileJobsafeParseNormalizedWhatsAppStatusWHATSAPP_PROVIDER_STATUS_SCHEMA_VERSIONWHATSAPP_PROVIDER_STATUSESWhatsAppProviderPricingMetadataSchemaWhatsAppProviderStatusSchema
Type-only exports:
BillingPlanKindBillingSubscriptionReconcileJobBillingSystemMessageCodeBillingUsageMetricNormalizedWhatsAppStatusPurchasedRecoveryCreditCounterSnapshotShopifyCurrentProviderContextShopifyProviderContextIdentityInputShopifyPurchaseProviderContextWhatsAppProviderPricingMetadataWhatsAppProviderStatus
Import: @modainteract/moda-interact-shared/recovery-policy.
From src/recovery-policy.ts:
Runtime exports:
EffectiveRecoveryPolicySchemaparseEffectiveRecoveryPolicyRECOVERY_OFFER_MODESRecoveryOfferModeSchemasafeParseEffectiveRecoveryPolicy
Type-only exports:
EffectiveRecoveryPolicyRecoveryOfferMode
Import: @modainteract/moda-interact-shared/whatsapp.
From src/whatsapp.ts:
Runtime exports:
NormalizedWhatsAppInboundMessageSchemaparseNormalizedWhatsAppInboundMessagesafeParseNormalizedWhatsAppInboundMessageWHATSAPP_INBOUND_MESSAGE_SCHEMA_VERSIONWhatsAppInboundContentSchema
Type-only exports:
NormalizedWhatsAppInboundMessageWhatsAppInboundContent
Import: @modainteract/moda-interact-shared/whatsapp-template-events.
From src/whatsapp-template-events.ts:
Runtime exports:
META_TEMPLATE_STATUS_QUEUEMETA_TEMPLATE_STATUS_JOBMETA_TEMPLATE_STATUS_SCHEMA_VERSIONMetaTemplateStatusObservationV2SchemaformatMetaTemplateStatusEventIdentityformatMetaTemplateStatusJobId
Type-only export:
MetaTemplateStatusObservationV2
Messaging must verify the complete webhook batch before generating a fresh
cryptographically random UUID v4 for every matching observation. Shared formats
that UUID without generating randomness. Both ingress and Background must parse
events with MetaTemplateStatusObservationV2Schema; it checks the exact nine own
fields and the 4096-byte UTF-8 JSON limit. Neither event UUID nor receivedAt
orders provider statuses, which remain Background-owned policy. Repeated Meta
status values can correspond to separate event occurrences.
Compatibility vectors: fixtures/meta-template-status-v2.json,
published at /whatsapp-template-events/fixtures. The fixture is test data,
not a provider webhook payload.
Import: @modainteract/moda-interact-shared/merchant-communications.
From src/merchant-communications.ts:
Runtime exports:
AuthoredSupportBodySchemacountUnicodeGraphemesMERCHANT_COMMUNICATIONS_JOB_NAMESMERCHANT_COMMUNICATIONS_QUEUE_NAMEMERCHANT_COMMUNICATIONS_SCHEMA_VERSIONMerchantMessageTranslationContractSchemaMerchantMessageTranslationStatusSchemaMerchantSupportMessageContractSchemaMerchantSupportMessageKindSchemaMerchantSupportMessageStateSchemaMerchantTranslationBatchContractSchemaMerchantTranslationBatchStatusSchemaMerchantTranslationDirectionSchemaMerchantTranslationReconciliationRequestContractSchemaMerchantTranslationReconciliationScopeSchemaMerchantTranslationReconciliationStatusSchemaPLATFORM_SUPPORT_LANGUAGE_TAGrequiresMerchantTranslationTranslatedSupportBodySchemaTranslationBatchPollJobSchemaTranslationBatchResultsJobSchemaTranslationBatchSubmitJobSchemaTranslationDispatchJobSchemaTranslationReconcileJobSchema
Type-only exports:
MerchantMessageTranslationContractMerchantMessageTranslationStatusMerchantSupportMessageContractMerchantSupportMessageKindMerchantSupportMessageStateMerchantTranslationBatchContractMerchantTranslationBatchStatusMerchantTranslationDirectionMerchantTranslationReconciliationRequestContractMerchantTranslationReconciliationScopeMerchantTranslationReconciliationStatusTranslationBatchPollJobTranslationBatchResultsJobTranslationBatchSubmitJobTranslationDispatchJobTranslationReconcileJob
Import: @modainteract/moda-interact-shared/merchant-communications/node.
From src/merchant-communications.node.ts:
Runtime exports:
createTranslationBatchPollJobIdcreateTranslationBatchResultsJobIdcreateTranslationBatchSubmitJobIdcreateTranslationDispatchJobIdcreateTranslationReconcileJobId
Import: @modainteract/moda-interact-shared/testing/node.
From src/testing/node.ts:
Runtime exports:
createCommandRunnercreateDockerRunnerDEFAULT_COMMAND_TIMEOUT_MSDEFAULT_DOCKER_COMMAND_TIMEOUT_MSDEFAULT_HOSTDEFAULT_POLL_INTERVAL_MSDEFAULT_POSTGRES_IMAGEDEFAULT_POSTGRES_STARTUP_TIMEOUT_MSDEFAULT_REDIS_IMAGEDEFAULT_REDIS_STARTUP_TIMEOUT_MSdeployPrismaMigrationsEphemeralPostgresEphemeralRediswithDisposableIntegrationInfrastructure
Type-only exports:
CommandOptionsCommandResultCommandRunnerDisposableEnvironmentDisposableIntegrationCallbackDisposableIntegrationInfrastructureDisposableIntegrationInfrastructureOptionsDockerRunnerEphemeralPostgresOptionsEphemeralRedisOptionsMigrationDeployOptionsPostgresConnectionDetailsRedisConnectionDetails
Import: @modainteract/moda-interact-shared/shopify.
From src/shopify/common.schema.ts:
Runtime exports:
MAX_LINE_ITEMSMAX_URL_LENGTHShopifyCheckoutLineItemSchemaShopifyCheckoutLineItemsSchemaShopifyCustomerReferenceSchemaShopifyMoneySchemaShopifyTenantSchema
Type-only exports:
ShopifyCheckoutLineItemShopifyCustomerReferenceShopifyMoneyShopifyTenant
From src/shopify/constants.ts:
Runtime exports:
SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSIONSHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION_V1SHOPIFY_COMMERCE_EVENT_SCHEMA_VERSION_V2SHOPIFY_COMMERCE_EVENT_TYPESSHOPIFY_RECOVERY_EVENT_TYPES_V2SHOPIFY_WEBHOOK_OUTBOX_DESTINATIONS
From src/shopify/queue-contracts.ts:
Runtime exports:
parseShopifyDiscountSyncJobsafeParseShopifyDiscountSyncJobSHOPIFY_DISCOUNT_SYNC_REASONSSHOPIFY_DISCOUNT_SYNC_WEBHOOK_TOPICSSHOPIFY_WEBHOOK_QUEUE_CONTRACTSShopifyDiscountSyncJobSchemaShopifyDiscountSyncReasonSchemaShopifyDiscountSyncWebhookTopicSchema
Type-only exports:
ShopifyDiscountSyncJob
From src/shopify/v1/checkout-observed.schema.ts:
Runtime exports:
CheckoutObservedPayloadSchema
Type-only exports:
CheckoutObservedPayload
From src/shopify/v1/commerce-event.schema.ts:
Runtime exports:
createShopifyCommerceOrderingKeycreateShopifyOrderOrderingKeyisCheckoutObservedEventisOrderCompletedEventparseShopifyCommerceEventsafeParseShopifyCommerceEventShopifyCheckoutObservedEventSchemaShopifyCommerceEventSchemaShopifyOrderCompletedEventSchema
Type-only exports:
ShopifyCheckoutObservedEventShopifyCommerceEventShopifyCommerceEventTypeShopifyOrderCompletedEvent
From src/shopify/v1/order-completed.schema.ts:
Runtime exports:
OrderCompletedPayloadSchema
Type-only exports:
OrderCompletedPayload
From src/shopify/v2/cart-activity.schema.ts:
Runtime exports:
ShopifyCartActivityPayloadV2Schema
Type-only exports:
ShopifyCartActivityPayloadV2
From src/shopify/v2/checkout-created.schema.ts:
Runtime exports:
CheckoutCreatedPayloadV2Schema
Type-only exports:
CheckoutCreatedPayloadV2
From src/shopify/v2/checkout-updated.schema.ts:
Runtime exports:
CheckoutUpdatedPayloadV2Schema
Type-only exports:
CheckoutUpdatedPayloadV2
From src/shopify/v2/order-completed.schema.ts:
Runtime exports:
OrderCompletedPayloadV2Schema
Type-only exports:
OrderCompletedPayloadV2
From src/shopify/v2/recovery-event.schema.ts:
Runtime exports:
createShopifyCartActivityOrderingKeycreateShopifyOrderCorrelationOrderingKeycreateShopifyPendingRecoveryOrderingKeyisCartActivityEventV2isCheckoutCreatedEventV2isCheckoutUpdatedEventV2isOrderCompletedEventV2parseShopifyRecoveryEventV2safeParseShopifyRecoveryEventV2ShopifyCartActivityEventV2SchemaShopifyCheckoutCreatedEventV2SchemaShopifyCheckoutUpdatedEventV2SchemaShopifyOrderCompletedEventV2SchemaShopifyRecoveryEventV2Schema
Type-only exports:
ShopifyCartActivityEventV2ShopifyCheckoutCreatedEventV2ShopifyCheckoutUpdatedEventV2ShopifyOrderCompletedEventV2ShopifyRecoveryEventTypeV2ShopifyRecoveryEventV2
Import: @modainteract/moda-interact-shared/shopify/node.
From src/shopify/node.ts:
Runtime exports:
createPendingRecoveryCandidateJobIdcreateShopifyCheckoutJobIdcreateShopifyDiscountSyncJobIdcreateShopifyOrderJobIdcreateShopifyWebhookJobId
Import: @modainteract/moda-interact-shared/logging.
From src/logging/logger.ts:
Runtime exports:
createLogger
From src/logging/redaction.ts:
Runtime exports:
CIRCULARisSensitiveLogKeyLOG_VALUE_LIMITSMAX_DEPTH_REACHEDREDACTEDsanitizeLogFieldsTRUNCATED
From src/logging/types.ts:
Runtime exports:
LOG_LEVELS
Type-only exports:
LogFieldsLoggerOptionsLogLevelLogRecordLogSinkStructuredLogger
Import: @modainteract/moda-interact-shared/logging/node.
From src/logging/node.ts:
Runtime exports:
getNodeOpenTelemetryLoggingRuntimeinitNodeOpenTelemetryLoggingparseOtlpHeadersresolveLogsEndpoint
Type-only exports:
NodeOpenTelemetryLoggingOptionsNodeOpenTelemetryLoggingRuntime
From src/logging/node/loki.ts:
Runtime exports:
getNodeLokiLoggingRuntimeinitNodeLokiLogging
Type-only exports:
NodeLokiLoggingOptionsNodeLokiLoggingRuntime
Import: @modainteract/moda-interact-shared/observability.
From src/observability/index.ts:
Runtime exports:
getActiveTraceIdwithObservedSpan
Type-only exports:
ObservedSpanOptionsSpanExceptionMapper
Import: @modainteract/moda-interact-shared/observability/node.
From src/observability/node.ts:
Runtime exports:
getNodeObservabilityRuntimeinitNodeObservabilityresolveDeploymentEnvironmentNameresolveSampler
Type-only exports:
NodeInstrumentProfileNodeObservabilityOptionsNodeObservabilityRuntime
Import: @modainteract/moda-interact-shared/observability/bullmq.
From src/observability/bullmq.ts:
Runtime exports:
createBullMQTelemetry
Type-only exports:
BullMQTelemetryOptions
Import: @modainteract/moda-interact-shared/observability/genai.
From src/observability/genai.ts:
Runtime exports:
observeAgentInvocationobserveAgentToolobserveConversationTurn
Type-only exports:
AgentObservationGenAIObservationOptions
From src/observability/index.ts:
Type-only exports:
ObservedSpanOptionsSpanExceptionMapper
Import: @modainteract/moda-interact-shared/commerce.
From src/commerce/canonical-json.ts:
Runtime exports:
canonicalJsonjsonBytesresponseContractCanonicalJson
Type-only exports:
Digest
From src/commerce/definitions.ts:
Runtime exports:
ToolNameSchemaGrantedToolSchemaGrantedToolsSchemaToolDescriptorSchemaPOLICY_OPERATIONSExternalHttpExecutionSchemaCommerceExecutionSchemaResponseTemplateSchemaCommerceToolDefinitionSchemaCommerceToolDraftDefinitionSchemavalidateDefinitionForPublicationdefinitionToMcpDescriptormapToolArgumentstoolHashInputvalidateDefinitionVersionCommerceToolIdentitySchemaCommerceToolRevisionIdentitySchemaPOLICY_OPERATION_DESCRIPTORS
Type-only exports:
ExternalHttpExecutionCommerceToolDefinitionCommerceToolDraftDefinitionGrantedToolToolDescriptorCommerceDefinitionCompiler
From src/commerce/external.ts:
Runtime exports:
ExternalQueryValueSchemaExternalQueryMappingSchemaExternalQueryMappingsSchemaExternalPathSchema- `Exter
