@nodaro/shared 2.15.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +178 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +378 -16
- package/dist/index.d.ts +378 -16
- package/dist/index.js +167 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/entity-mention-slug.test.ts +380 -0
- package/src/__tests__/image-mention-slug.test.ts +303 -0
- package/src/__tests__/producer-types.test.ts +22 -0
- package/src/__tests__/prompt-length-limits.test.ts +2 -2
- package/src/__tests__/to-connected-references.test.ts +45 -0
- package/src/animals.ts +57 -0
- package/src/character-voice.ts +4 -3
- package/src/entity-mention-slug.ts +203 -0
- package/src/image-mention-slug.ts +187 -0
- package/src/index.ts +27 -0
- package/src/mention-token-grammar.ts +167 -0
- package/src/model-catalog.ts +12 -9
- package/src/model-constants.ts +8 -6
- package/src/model-tree.ts +1 -0
- package/src/producer-types.ts +6 -0
- package/src/to-connected-references.ts +16 -2
- package/src/types.ts +11 -5
- package/src/workflow-export.ts +34 -0
package/src/model-constants.ts
CHANGED
|
@@ -211,16 +211,18 @@ export const TTS_TEXT_MAX = 5000
|
|
|
211
211
|
|
|
212
212
|
/**
|
|
213
213
|
* Per-model Text-to-Speech character cap (PER REQUEST), from official ElevenLabs
|
|
214
|
-
* docs. turbo/multilingual accept FAR more than the old flat 5000; v3
|
|
215
|
-
*
|
|
216
|
-
* hard-
|
|
217
|
-
*
|
|
214
|
+
* docs. turbo/multilingual accept FAR more than the old flat 5000; v3 matches
|
|
215
|
+
* the official 5000 (probed live 2026-08-30: 4,500 AND 5,200 chars both
|
|
216
|
+
* returned 200 — the old "API hard-limits v3 at 3000" report no longer holds).
|
|
217
|
+
* Dialogue's documented 2,000 is a recommendation, not a limit (2,500 and
|
|
218
|
+
* 5,000 total chars both probed 200); we cap at 5000 like v3 — same model
|
|
219
|
+
* underneath. Absent → {@link TTS_TEXT_MAX}.
|
|
218
220
|
*/
|
|
219
221
|
export const MAX_TTS_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
220
222
|
"elevenlabs-turbo": 40000, // == eleven_flash_v2_5 (functionally equivalent)
|
|
221
223
|
"elevenlabs-multilingual": 10000, // eleven_multilingual_v2
|
|
222
|
-
"elevenlabs-v3":
|
|
223
|
-
"elevenlabs-dialogue":
|
|
224
|
+
"elevenlabs-v3": 5000, // official cap (probed: 5,200 chars accepted; keep the clamp)
|
|
225
|
+
"elevenlabs-dialogue": 5000, // total across lines; ≤2,000 recommended for best quality
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
/** Max TTS text length (chars) for a provider: verified override, else {@link TTS_TEXT_MAX}. */
|
package/src/model-tree.ts
CHANGED
|
@@ -62,6 +62,7 @@ const MODE_TO_NODE: Readonly<Partial<Record<ModelMode, string>>> = {
|
|
|
62
62
|
"lip-sync": "lip-sync", "tts": "text-to-speech", "sfx": "text-to-audio",
|
|
63
63
|
"music": "suno-generate", "voice-design": "voice-design", "voice-changer": "voice-changer",
|
|
64
64
|
"isolation": "audio-isolation", "dubbing": "dubbing", "forced-alignment": "forced-alignment", "stt": "transcribe",
|
|
65
|
+
"dialogue": "text-to-dialogue",
|
|
65
66
|
"video-analysis": "video-analysis",
|
|
66
67
|
}
|
|
67
68
|
|
package/src/producer-types.ts
CHANGED
|
@@ -130,6 +130,12 @@ export const DYNAMIC_PRODUCER_TYPES: ReadonlySet<string> = new Set([
|
|
|
130
130
|
// EVERY producer set or its outputs can't connect (was the "cannot connect
|
|
131
131
|
// the outputs of voice-changer-pro" bug). Guarded by producer-types.test.ts.
|
|
132
132
|
"voice-changer-pro",
|
|
133
|
+
// Dubbing joined the dual-mode family with the full-surface upgrade:
|
|
134
|
+
// audio in → dubbed audio; video in (or a video sourceUrl) → dubbed VIDEO
|
|
135
|
+
// (+ audio sidecar). Same wiring contract as voice-changer; stays in
|
|
136
|
+
// AUDIO_PRODUCER_TYPES as its default. Explicitly asserted in
|
|
137
|
+
// producer-types.test.ts (the suite does not fail on omission).
|
|
138
|
+
"dubbing",
|
|
133
139
|
"reduce",
|
|
134
140
|
// Dual-output time chunker (UI label "Split into Chunks"; type id stays
|
|
135
141
|
// "split-media"): video in → video chunks, audio in → audio chunks — two
|
|
@@ -12,7 +12,7 @@ import { locationMentionSlug } from "./location-mention-slug.js"
|
|
|
12
12
|
export interface EntityReferenceInput {
|
|
13
13
|
/** The entity row id. */
|
|
14
14
|
readonly id: string
|
|
15
|
-
readonly kind: "character" | "location" | "creature"
|
|
15
|
+
readonly kind: "character" | "location" | "creature" | "image"
|
|
16
16
|
/** Display name — the slug is derived from this. */
|
|
17
17
|
readonly name: string
|
|
18
18
|
/** Resolved thumbnail/source URL; null/undefined → "" (placeholder-safe). */
|
|
@@ -30,7 +30,9 @@ export interface EntityReferenceInput {
|
|
|
30
30
|
* `locationMentionSlug`), creature → `wired-creature` (no mention-slug machinery
|
|
31
31
|
* — like `wired-object`, a bound creature AUTO-ATTACHES and gets a canonical-style
|
|
32
32
|
* creature/animal-subject directive with zero typing; `{image:N:creature}` tokens
|
|
33
|
-
* also resolve against it)
|
|
33
|
+
* also resolve against it), image → `wired-image` (a plain media reference; it
|
|
34
|
+
* AUTO-ATTACHES, and an `@<name-slug>:<index>[:<role>]` mention re-seats it at the
|
|
35
|
+
* position it was typed). Canonical-description fields are null here (a binding
|
|
34
36
|
* captures only name+variant; the picker/full-row path supplies descriptions).
|
|
35
37
|
*/
|
|
36
38
|
export function toConnectedReference(entity: EntityReferenceInput): ConnectedReference {
|
|
@@ -47,6 +49,18 @@ export function toConnectedReference(entity: EntityReferenceInput): ConnectedRef
|
|
|
47
49
|
variantDisplayName: entity.variant ?? "canonical",
|
|
48
50
|
}
|
|
49
51
|
}
|
|
52
|
+
if (entity.kind === "image") {
|
|
53
|
+
// No slug field — the resolver derives it from `defaultName` at prompt time
|
|
54
|
+
// (`knownImageSlugsFromRefs`), so a client cannot drift from the grammar and
|
|
55
|
+
// nothing changes on the wire.
|
|
56
|
+
return {
|
|
57
|
+
id: entity.id,
|
|
58
|
+
defaultName: entity.name,
|
|
59
|
+
source: "wired-image",
|
|
60
|
+
url: entity.url ?? "",
|
|
61
|
+
...(entity.description ? { description: entity.description } : {}),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
50
64
|
if (entity.kind === "creature") {
|
|
51
65
|
return {
|
|
52
66
|
id: entity.id,
|
package/src/types.ts
CHANGED
|
@@ -163,13 +163,19 @@ export interface ConnectedReference {
|
|
|
163
163
|
*/
|
|
164
164
|
readonly defaultUsageMode?: UsageMode
|
|
165
165
|
/**
|
|
166
|
-
*
|
|
167
|
-
* `REFERENCE_ROLE_PRESETS[
|
|
168
|
-
*
|
|
166
|
+
* The reference's HYBRID `defaultRole` (the role-dropdown pick: a
|
|
167
|
+
* `REFERENCE_ROLE_PRESETS[source]` value or a sanitized Custom slug)
|
|
168
|
+
* propagated into every entry derived from that node. Read via
|
|
169
169
|
* `resolveDefaultRole(defaultRole, defaultUsageMode, source)` at the hybrid
|
|
170
170
|
* resolver sites — it takes precedence over `defaultUsageMode`. Absent for
|
|
171
|
-
*
|
|
172
|
-
*
|
|
171
|
+
* nodes that never set a role (fall back to the `defaultUsageMode`-derived
|
|
172
|
+
* role, then the source default).
|
|
173
|
+
*
|
|
174
|
+
* Written by the character node's role dropdown, and accepted from any source
|
|
175
|
+
* on the wire (`connectedReferenceSchema`). The LOCATION paths read it through
|
|
176
|
+
* their own `resolveLocationRole` chain rather than `resolveDefaultRole` — the
|
|
177
|
+
* location role vocabulary is mode-derived and slug-normalized — so it is NOT
|
|
178
|
+
* a character-only field: do not re-narrow this doc to characters.
|
|
173
179
|
*/
|
|
174
180
|
readonly defaultRole?: string
|
|
175
181
|
/**
|
package/src/workflow-export.ts
CHANGED
|
@@ -96,6 +96,22 @@ export interface WorkflowPortability {
|
|
|
96
96
|
unreachableMedia: WorkflowMediaRef[]
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/** The four entity kinds a bundle's `assets` can carry. */
|
|
100
|
+
export type WorkflowAssetKind = "character" | "object" | "creature" | "location"
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A bundled entity the import declined to re-create (#1088). The workflow
|
|
104
|
+
* still lands — the film is the thing the importer asked for — so this is how
|
|
105
|
+
* they hear that an `@` chip arrived unbound.
|
|
106
|
+
*/
|
|
107
|
+
export interface WorkflowImportSkippedAsset {
|
|
108
|
+
kind: WorkflowAssetKind
|
|
109
|
+
/** The entity's id IN THE BUNDLE (the exporter's row id). */
|
|
110
|
+
id: string
|
|
111
|
+
name: string
|
|
112
|
+
reason: string
|
|
113
|
+
}
|
|
114
|
+
|
|
99
115
|
/**
|
|
100
116
|
* What the importer did about the bundle's media (#866). Publicly reachable
|
|
101
117
|
* media that is not already on the importing instance's own storage is
|
|
@@ -103,11 +119,29 @@ export interface WorkflowPortability {
|
|
|
103
119
|
* a host the importer cannot reach is left as-is and listed (`unreachable`);
|
|
104
120
|
* anything declined for another reason (too large, not a media type, over
|
|
105
121
|
* the per-import cap, upload failed) is listed with the reason (`skipped`).
|
|
122
|
+
*
|
|
123
|
+
* The bundle's ENTITY images (`assets`) ride the same walk (#1088) — with one
|
|
124
|
+
* rule of their own: they are copied even when they already sit on this
|
|
125
|
+
* instance, because they are the EXPORTER's bytes and the two accounts'
|
|
126
|
+
* lifecycles are uncorrelated (their delete, their quarantine sweep, their
|
|
127
|
+
* retention reaper). Only bytes the importer already owns are left alone.
|
|
106
128
|
*/
|
|
107
129
|
export interface WorkflowImportReport {
|
|
108
130
|
rehosted: number
|
|
109
131
|
unreachable: WorkflowMediaRef[]
|
|
110
132
|
skipped: Array<WorkflowMediaRef & { reason: string }>
|
|
133
|
+
/**
|
|
134
|
+
* Bundled entity id (the EXPORTER's) → the row created under the importer,
|
|
135
|
+
* for every entity the import re-created. Present whenever the bundle
|
|
136
|
+
* carried `assets`. A client that holds chips outside the graph — a
|
|
137
|
+
* timeline, a copy-a-shared-production path that never posts to
|
|
138
|
+
* `/v1/workflows/import` — re-points them with this; the server has already
|
|
139
|
+
* re-pointed every `references[]` entry inside the nodes it stored.
|
|
140
|
+
*/
|
|
141
|
+
assetIdMap?: Record<string, string>
|
|
142
|
+
/** Entities the import declined to create (storage quota). The workflow
|
|
143
|
+
* still landed; chips bound to these arrive unresolvable. */
|
|
144
|
+
assetsSkipped?: WorkflowImportSkippedAsset[]
|
|
111
145
|
/** Anything else the importer should know, e.g. copies were made but the
|
|
112
146
|
* workflow could not be updated to use them. */
|
|
113
147
|
notes?: string[]
|