@liforma/publisher 0.5.0 → 0.7.1
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/README.md +47 -4
- package/dist/createPublisher.d.ts +3 -1
- package/dist/createPublisher.d.ts.map +1 -1
- package/dist/createPublisher.js +2 -0
- package/dist/createPublisher.js.map +1 -1
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -1
- package/dist/imageSource.d.ts +28 -0
- package/dist/imageSource.d.ts.map +1 -0
- package/dist/imageSource.js +155 -0
- package/dist/imageSource.js.map +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/publishStart.d.ts +9 -0
- package/dist/publishStart.d.ts.map +1 -1
- package/dist/publishStart.js +10 -2
- package/dist/publishStart.js.map +1 -1
- package/dist/resources/characters.d.ts +2 -0
- package/dist/resources/characters.d.ts.map +1 -1
- package/dist/resources/characters.js +2 -0
- package/dist/resources/characters.js.map +1 -1
- package/dist/resources/costumes.d.ts +19 -0
- package/dist/resources/costumes.d.ts.map +1 -0
- package/dist/resources/costumes.js +43 -0
- package/dist/resources/costumes.js.map +1 -0
- package/dist/resources/createFrom.d.ts +93 -0
- package/dist/resources/createFrom.d.ts.map +1 -0
- package/dist/resources/createFrom.js +494 -0
- package/dist/resources/createFrom.js.map +1 -0
- package/dist/resources/experiences.d.ts +6 -1
- package/dist/resources/experiences.d.ts.map +1 -1
- package/dist/resources/experiences.js +5 -1
- package/dist/resources/experiences.js.map +1 -1
- package/dist/resources/sets.d.ts +2 -0
- package/dist/resources/sets.d.ts.map +1 -1
- package/dist/resources/sets.js +2 -0
- package/dist/resources/sets.js.map +1 -1
- package/dist/schemas.d.ts +369 -20
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +55 -1
- package/dist/schemas.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { projectPath, publisherRequest } from '../http.js';
|
|
2
|
+
import { waitForJob } from '../jobs.js';
|
|
3
|
+
import { startJobFromEnvelope } from '../publishStart.js';
|
|
4
|
+
import { wardrobePublishBody } from './clothes.js';
|
|
5
|
+
import { createCostumePublishResponseSchema, deletedResourceResponseSchema, getCostumeResponseSchema } from '../schemas.js';
|
|
6
|
+
export function createCostumesClient(http) {
|
|
7
|
+
const get = async (id, options) => {
|
|
8
|
+
const { data } = await publisherRequest(http, projectPath(http, `/costumes/${encodeURIComponent(id)}`), getCostumeResponseSchema, { method: 'GET', signal: options?.signal, retry: true });
|
|
9
|
+
return data.costume;
|
|
10
|
+
};
|
|
11
|
+
const startCreate = async (input, options) => startJobFromEnvelope(http, '/costumes', createCostumePublishResponseSchema, wardrobePublishBody(input), options?.signal);
|
|
12
|
+
return {
|
|
13
|
+
startCreate,
|
|
14
|
+
create: async (input, options = {}) => {
|
|
15
|
+
const started = await startCreate(input, options);
|
|
16
|
+
const completed = await waitForJob(http, started.id, options);
|
|
17
|
+
return get(completed.targetId, options);
|
|
18
|
+
},
|
|
19
|
+
get,
|
|
20
|
+
update: async (id, patch, options) => {
|
|
21
|
+
const { data } = await publisherRequest(http, projectPath(http, `/costumes/${encodeURIComponent(id)}`), getCostumeResponseSchema, {
|
|
22
|
+
method: 'PATCH',
|
|
23
|
+
body: { name: patch.name },
|
|
24
|
+
signal: options?.signal,
|
|
25
|
+
retry: true
|
|
26
|
+
});
|
|
27
|
+
return data.costume;
|
|
28
|
+
},
|
|
29
|
+
archive: async (id, options) => {
|
|
30
|
+
const { data } = await publisherRequest(http, projectPath(http, `/costumes/${encodeURIComponent(id)}/archive`), getCostumeResponseSchema, { method: 'POST', signal: options?.signal });
|
|
31
|
+
return data.costume;
|
|
32
|
+
},
|
|
33
|
+
restore: async (id, options) => {
|
|
34
|
+
const { data } = await publisherRequest(http, projectPath(http, `/costumes/${encodeURIComponent(id)}/restore`), getCostumeResponseSchema, { method: 'POST', signal: options?.signal });
|
|
35
|
+
return data.costume;
|
|
36
|
+
},
|
|
37
|
+
delete: async (id, options) => {
|
|
38
|
+
const { data } = await publisherRequest(http, projectPath(http, `/costumes/${encodeURIComponent(id)}`), deletedResourceResponseSchema, { method: 'DELETE', signal: options?.signal });
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=costumes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costumes.js","sourceRoot":"","sources":["../../src/resources/costumes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type PublisherHttp } from '../http.js';
|
|
2
|
+
import { type ImageSource } from '../imageSource.js';
|
|
3
|
+
import { type BackdropResource, type CharacterResource, type ClothesResource, type CostumeResource, type ExperienceResource, type ExperienceInteractionInput, type HairResource, type PersonaEthnicity, type PersonaGender, type PublishJob, type SetResource } from '../schemas.js';
|
|
4
|
+
import type { BackgroundMode } from './clothes.js';
|
|
5
|
+
export type PlateCreate = {
|
|
6
|
+
readonly image: ImageSource;
|
|
7
|
+
readonly name?: string;
|
|
8
|
+
readonly backgroundMode?: BackgroundMode;
|
|
9
|
+
readonly externalId?: string;
|
|
10
|
+
readonly forceNew?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type PlateOrId = {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
} | PlateCreate;
|
|
15
|
+
export type BackdropCreate = {
|
|
16
|
+
readonly image: ImageSource;
|
|
17
|
+
readonly name?: string;
|
|
18
|
+
readonly externalId?: string;
|
|
19
|
+
readonly forceNew?: boolean;
|
|
20
|
+
readonly depth?: {
|
|
21
|
+
readonly image: ImageSource;
|
|
22
|
+
readonly depthMapType?: 'disparity';
|
|
23
|
+
readonly metersPerDepth?: number;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export type CreateFromBackdropInput = {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
} | BackdropCreate;
|
|
29
|
+
export type CreateFromCharacterCreate = {
|
|
30
|
+
readonly avatarId: string;
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly voice: string;
|
|
33
|
+
readonly sttLang: string;
|
|
34
|
+
readonly costume?: PlateOrId;
|
|
35
|
+
readonly clothes?: PlateOrId;
|
|
36
|
+
readonly hair?: PlateOrId;
|
|
37
|
+
readonly personality?: string;
|
|
38
|
+
readonly generalInstructions?: string;
|
|
39
|
+
readonly gender?: PersonaGender;
|
|
40
|
+
readonly age?: number;
|
|
41
|
+
readonly ethnicity?: PersonaEthnicity;
|
|
42
|
+
readonly externalId?: string;
|
|
43
|
+
};
|
|
44
|
+
export type CreateFromCharacterInput = {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
} | CreateFromCharacterCreate;
|
|
47
|
+
export type CreateFromExperienceInput = {
|
|
48
|
+
readonly title: string;
|
|
49
|
+
readonly backdrop: CreateFromBackdropInput;
|
|
50
|
+
readonly character: CreateFromCharacterInput;
|
|
51
|
+
readonly set?: {
|
|
52
|
+
readonly name?: string;
|
|
53
|
+
readonly externalId?: string;
|
|
54
|
+
};
|
|
55
|
+
readonly slug?: string;
|
|
56
|
+
readonly attributes?: Record<string, string>;
|
|
57
|
+
readonly startingMessage?: string;
|
|
58
|
+
readonly systemInstructions?: string;
|
|
59
|
+
readonly introduction?: string;
|
|
60
|
+
readonly interaction?: ExperienceInteractionInput;
|
|
61
|
+
readonly publish?: boolean;
|
|
62
|
+
readonly externalId?: string;
|
|
63
|
+
};
|
|
64
|
+
export type CreateFromStage = 'backdrop' | 'costume' | 'clothes' | 'hair';
|
|
65
|
+
export type CreateFromProgress = {
|
|
66
|
+
readonly stage: CreateFromStage;
|
|
67
|
+
readonly job: PublishJob;
|
|
68
|
+
};
|
|
69
|
+
export type CreateFromOptions = {
|
|
70
|
+
readonly signal?: AbortSignal;
|
|
71
|
+
readonly timeoutMs?: number;
|
|
72
|
+
readonly onProgress?: (progress: CreateFromProgress) => void;
|
|
73
|
+
};
|
|
74
|
+
export type CreateFromResult = {
|
|
75
|
+
readonly experience: ExperienceResource;
|
|
76
|
+
readonly character: CharacterResource;
|
|
77
|
+
readonly set: SetResource;
|
|
78
|
+
readonly backdrop: BackdropResource;
|
|
79
|
+
readonly costume?: CostumeResource;
|
|
80
|
+
readonly clothes?: ClothesResource;
|
|
81
|
+
readonly hair?: HairResource;
|
|
82
|
+
readonly created: {
|
|
83
|
+
readonly experience: boolean;
|
|
84
|
+
readonly character: boolean;
|
|
85
|
+
readonly set: boolean;
|
|
86
|
+
readonly backdrop: boolean;
|
|
87
|
+
readonly costume?: boolean;
|
|
88
|
+
readonly clothes?: boolean;
|
|
89
|
+
readonly hair?: boolean;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
export declare function createExperienceFrom(http: PublisherHttp, input: CreateFromExperienceInput, options?: CreateFromOptions): Promise<CreateFromResult>;
|
|
93
|
+
//# sourceMappingURL=createFrom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createFrom.d.ts","sourceRoot":"","sources":["../../src/resources/createFrom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { LiformaPublisherError } from '../errors.js';
|
|
2
|
+
import { projectPath, publisherRequest } from '../http.js';
|
|
3
|
+
import { resolveImageSource } from '../imageSource.js';
|
|
4
|
+
import { waitForJob } from '../jobs.js';
|
|
5
|
+
import { startJobWithOutcome } from '../publishStart.js';
|
|
6
|
+
import { createBackdropPublishResponseSchema, createCharacterResponseSchema, createClothesPublishResponseSchema, createCostumePublishResponseSchema, createHairPublishResponseSchema, createSetResponseSchema, experienceResponseSchema, getBackdropResponseSchema, getClothesResponseSchema, getCostumeResponseSchema, getHairResponseSchema } from '../schemas.js';
|
|
7
|
+
import { requireInput, requiredString } from '../validate.js';
|
|
8
|
+
import { wardrobePublishBody } from './clothes.js';
|
|
9
|
+
/** Prefer explicit `{ id }` reuse when both id and create fields are present. */
|
|
10
|
+
function reuseId(value) {
|
|
11
|
+
if (!('id' in value))
|
|
12
|
+
return null;
|
|
13
|
+
const id = value.id;
|
|
14
|
+
if (typeof id !== 'string' || !id.trim())
|
|
15
|
+
return null;
|
|
16
|
+
return id.trim();
|
|
17
|
+
}
|
|
18
|
+
function withContext(error, step) {
|
|
19
|
+
if (error instanceof LiformaPublisherError) {
|
|
20
|
+
if (error.context?.operation === 'experiences.createFrom') {
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
return new LiformaPublisherError(error.message, {
|
|
24
|
+
code: error.code,
|
|
25
|
+
status: error.status,
|
|
26
|
+
requestId: error.requestId,
|
|
27
|
+
details: error.details,
|
|
28
|
+
retryable: error.retryable,
|
|
29
|
+
job: error.job,
|
|
30
|
+
cause: error,
|
|
31
|
+
context: {
|
|
32
|
+
operation: 'experiences.createFrom',
|
|
33
|
+
step
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return new LiformaPublisherError(error instanceof Error ? error.message : 'experiences.createFrom failed.', {
|
|
38
|
+
code: 'UNKNOWN',
|
|
39
|
+
cause: error,
|
|
40
|
+
context: { operation: 'experiences.createFrom', step }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function runStep(step, fn) {
|
|
44
|
+
try {
|
|
45
|
+
return await fn();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw withContext(error, step);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function resolveUpload(http, image, options, purpose = 'colour') {
|
|
52
|
+
return runStep('resolveImage', () => resolveImageSource(http, image, { signal: options.signal, purpose }));
|
|
53
|
+
}
|
|
54
|
+
async function waitPlate(http, jobId, stage, options) {
|
|
55
|
+
return waitForJob(http, jobId, {
|
|
56
|
+
signal: options.signal,
|
|
57
|
+
timeoutMs: options.timeoutMs,
|
|
58
|
+
onProgress: options.onProgress
|
|
59
|
+
? (job) => {
|
|
60
|
+
options.onProgress?.({ stage, job });
|
|
61
|
+
}
|
|
62
|
+
: undefined
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async function getBackdrop(http, id, options) {
|
|
66
|
+
const { data } = await publisherRequest(http, projectPath(http, `/backdrops/${encodeURIComponent(id)}`), getBackdropResponseSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
67
|
+
return data.backdrop;
|
|
68
|
+
}
|
|
69
|
+
async function getSet(http, id, options) {
|
|
70
|
+
const { data } = await publisherRequest(http, projectPath(http, `/sets/${encodeURIComponent(id)}`), createSetResponseSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
71
|
+
return data.set;
|
|
72
|
+
}
|
|
73
|
+
async function getCharacter(http, id, options) {
|
|
74
|
+
const { data } = await publisherRequest(http, projectPath(http, `/characters/${encodeURIComponent(id)}`), createCharacterResponseSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
75
|
+
return data.character;
|
|
76
|
+
}
|
|
77
|
+
async function resolveBackdrop(http, input, options, defaultName) {
|
|
78
|
+
const id = reuseId(input);
|
|
79
|
+
if (id) {
|
|
80
|
+
return runStep('backdrop', async () => ({
|
|
81
|
+
backdrop: await getBackdrop(http, id, options),
|
|
82
|
+
created: false
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
if (!('image' in input)) {
|
|
86
|
+
throw new LiformaPublisherError('backdrop must be { id } or include image.', { code: 'INVALID_BODY' });
|
|
87
|
+
}
|
|
88
|
+
const create = input;
|
|
89
|
+
return runStep('backdrop', async () => {
|
|
90
|
+
const image = await resolveUpload(http, create.image, options, 'colour');
|
|
91
|
+
const depth = create.depth
|
|
92
|
+
? {
|
|
93
|
+
image: await resolveUpload(http, create.depth.image, options, 'depth'),
|
|
94
|
+
...(create.depth.depthMapType !== undefined
|
|
95
|
+
? { depthMapType: create.depth.depthMapType }
|
|
96
|
+
: {}),
|
|
97
|
+
...(create.depth.metersPerDepth !== undefined
|
|
98
|
+
? { metersPerDepth: create.depth.metersPerDepth }
|
|
99
|
+
: {})
|
|
100
|
+
}
|
|
101
|
+
: undefined;
|
|
102
|
+
const metersPerDepth = depth?.metersPerDepth;
|
|
103
|
+
if (metersPerDepth !== undefined && (!Number.isFinite(metersPerDepth) || metersPerDepth <= 0)) {
|
|
104
|
+
throw new LiformaPublisherError('depth.metersPerDepth must be a positive number.', {
|
|
105
|
+
code: 'INVALID_BODY'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const started = await startJobWithOutcome(http, '/backdrops', createBackdropPublishResponseSchema, {
|
|
109
|
+
name: create.name?.trim() || defaultName,
|
|
110
|
+
uploadId: typeof image === 'string' ? image : image.uploadId,
|
|
111
|
+
...(create.externalId !== undefined ? { externalId: create.externalId } : {}),
|
|
112
|
+
...(create.forceNew !== undefined ? { forceNew: create.forceNew } : {}),
|
|
113
|
+
...(depth
|
|
114
|
+
? {
|
|
115
|
+
depth: {
|
|
116
|
+
uploadId: typeof depth.image === 'string' ? depth.image : depth.image.uploadId,
|
|
117
|
+
...(depth.depthMapType !== undefined
|
|
118
|
+
? { depthMapType: depth.depthMapType }
|
|
119
|
+
: {}),
|
|
120
|
+
...(metersPerDepth !== undefined ? { metersPerDepth } : {})
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
: {})
|
|
124
|
+
}, options.signal);
|
|
125
|
+
const completed = await waitPlate(http, started.job.id, 'backdrop', options);
|
|
126
|
+
return {
|
|
127
|
+
backdrop: await getBackdrop(http, completed.targetId, options),
|
|
128
|
+
created: started.created
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async function resolveWardrobePlate(http, args) {
|
|
133
|
+
const { plate, stage, options } = args;
|
|
134
|
+
const id = reuseId(plate);
|
|
135
|
+
if (id) {
|
|
136
|
+
return runStep(stage, async () => {
|
|
137
|
+
const { data } = await publisherRequest(http, projectPath(http, args.getPath(id)), args.getSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
138
|
+
return { resource: args.pick(data), created: false };
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (!('image' in plate)) {
|
|
142
|
+
throw new LiformaPublisherError(`${stage} must be { id } or include image.`, {
|
|
143
|
+
code: 'INVALID_BODY'
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const create = plate;
|
|
147
|
+
return runStep(stage, async () => {
|
|
148
|
+
const image = await resolveUpload(http, create.image, options, 'colour');
|
|
149
|
+
const started = await startJobWithOutcome(http, args.path, args.startSchema, wardrobePublishBody({
|
|
150
|
+
avatarId: args.avatarId,
|
|
151
|
+
image,
|
|
152
|
+
name: create.name,
|
|
153
|
+
backgroundMode: create.backgroundMode ?? 'remove',
|
|
154
|
+
externalId: create.externalId,
|
|
155
|
+
forceNew: create.forceNew
|
|
156
|
+
}), options.signal);
|
|
157
|
+
const completed = await waitPlate(http, started.job.id, stage, options);
|
|
158
|
+
const { data } = await publisherRequest(http, projectPath(http, args.getPath(completed.targetId)), args.getSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
159
|
+
return { resource: args.pick(data), created: started.created };
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function assertAppearanceExclusive(character) {
|
|
163
|
+
const hasCostume = character.costume !== undefined;
|
|
164
|
+
const hasClothes = character.clothes !== undefined;
|
|
165
|
+
const hasHair = character.hair !== undefined;
|
|
166
|
+
if (hasCostume && (hasClothes || hasHair)) {
|
|
167
|
+
throw new LiformaPublisherError('Provide costume or clothes+hair, not both.', {
|
|
168
|
+
code: 'INVALID_BODY'
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (hasClothes !== hasHair) {
|
|
172
|
+
throw new LiformaPublisherError('clothes and hair must both be provided, or both omitted.', { code: 'INVALID_BODY' });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function resolveAppearance(http, character, options) {
|
|
176
|
+
assertAppearanceExclusive(character);
|
|
177
|
+
if (character.costume) {
|
|
178
|
+
const costume = await resolveWardrobePlate(http, {
|
|
179
|
+
plate: character.costume,
|
|
180
|
+
stage: 'costume',
|
|
181
|
+
avatarId: character.avatarId,
|
|
182
|
+
path: '/costumes',
|
|
183
|
+
startSchema: createCostumePublishResponseSchema,
|
|
184
|
+
getPath: (id) => `/costumes/${encodeURIComponent(id)}`,
|
|
185
|
+
getSchema: getCostumeResponseSchema,
|
|
186
|
+
pick: (data) => data.costume,
|
|
187
|
+
options
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
costume: costume.resource,
|
|
191
|
+
costumeId: costume.resource.id,
|
|
192
|
+
created: { costume: costume.created }
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (character.clothes && character.hair) {
|
|
196
|
+
const [clothes, hair] = await Promise.all([
|
|
197
|
+
resolveWardrobePlate(http, {
|
|
198
|
+
plate: character.clothes,
|
|
199
|
+
stage: 'clothes',
|
|
200
|
+
avatarId: character.avatarId,
|
|
201
|
+
path: '/clothes',
|
|
202
|
+
startSchema: createClothesPublishResponseSchema,
|
|
203
|
+
getPath: (id) => `/clothes/${encodeURIComponent(id)}`,
|
|
204
|
+
getSchema: getClothesResponseSchema,
|
|
205
|
+
pick: (data) => data.clothes,
|
|
206
|
+
options
|
|
207
|
+
}),
|
|
208
|
+
resolveWardrobePlate(http, {
|
|
209
|
+
plate: character.hair,
|
|
210
|
+
stage: 'hair',
|
|
211
|
+
avatarId: character.avatarId,
|
|
212
|
+
path: '/hair',
|
|
213
|
+
startSchema: createHairPublishResponseSchema,
|
|
214
|
+
getPath: (id) => `/hair/${encodeURIComponent(id)}`,
|
|
215
|
+
getSchema: getHairResponseSchema,
|
|
216
|
+
pick: (data) => data.hair,
|
|
217
|
+
options
|
|
218
|
+
})
|
|
219
|
+
]);
|
|
220
|
+
return {
|
|
221
|
+
clothes: clothes.resource,
|
|
222
|
+
hair: hair.resource,
|
|
223
|
+
clothesId: clothes.resource.id,
|
|
224
|
+
hairId: hair.resource.id,
|
|
225
|
+
created: { clothes: clothes.created, hair: hair.created }
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
return { created: {} };
|
|
229
|
+
}
|
|
230
|
+
function characterCreateBody(body, appearance) {
|
|
231
|
+
return {
|
|
232
|
+
avatarId: requiredString(body.avatarId, 'character.avatarId'),
|
|
233
|
+
name: requiredString(body.name, 'character.name'),
|
|
234
|
+
voice: requiredString(body.voice, 'character.voice'),
|
|
235
|
+
sttLang: requiredString(body.sttLang, 'character.sttLang'),
|
|
236
|
+
...(appearance?.costumeId !== undefined ? { costumeId: appearance.costumeId } : {}),
|
|
237
|
+
...(appearance?.clothesId !== undefined ? { clothesId: appearance.clothesId } : {}),
|
|
238
|
+
...(appearance?.hairId !== undefined ? { hairId: appearance.hairId } : {}),
|
|
239
|
+
...(body.personality !== undefined ? { personality: body.personality } : {}),
|
|
240
|
+
...(body.generalInstructions !== undefined
|
|
241
|
+
? { generalInstructions: body.generalInstructions }
|
|
242
|
+
: {}),
|
|
243
|
+
...(body.gender !== undefined ? { gender: body.gender } : {}),
|
|
244
|
+
...(body.age !== undefined ? { age: body.age } : {}),
|
|
245
|
+
...(body.ethnicity !== undefined ? { ethnicity: body.ethnicity } : {}),
|
|
246
|
+
...(body.externalId !== undefined ? { externalId: body.externalId } : {})
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function parseCharacterInput(input) {
|
|
250
|
+
const id = reuseId(input);
|
|
251
|
+
if (id) {
|
|
252
|
+
return { reuseId: id, create: null };
|
|
253
|
+
}
|
|
254
|
+
if (!('avatarId' in input)) {
|
|
255
|
+
throw new LiformaPublisherError('character must be { id } or include avatarId, name, voice, and sttLang.', { code: 'INVALID_BODY' });
|
|
256
|
+
}
|
|
257
|
+
requiredString(input.avatarId, 'character.avatarId');
|
|
258
|
+
requiredString(input.name, 'character.name');
|
|
259
|
+
requiredString(input.voice, 'character.voice');
|
|
260
|
+
requiredString(input.sttLang, 'character.sttLang');
|
|
261
|
+
assertAppearanceExclusive(input);
|
|
262
|
+
return { reuseId: null, create: input };
|
|
263
|
+
}
|
|
264
|
+
async function loadAppearanceFromCharacter(http, character, options) {
|
|
265
|
+
const created = {};
|
|
266
|
+
const out = { created };
|
|
267
|
+
if (character.costumeId) {
|
|
268
|
+
const { data } = await publisherRequest(http, projectPath(http, `/costumes/${encodeURIComponent(character.costumeId)}`), getCostumeResponseSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
269
|
+
out.costume = data.costume;
|
|
270
|
+
out.costumeId = data.costume.id;
|
|
271
|
+
created.costume = false;
|
|
272
|
+
}
|
|
273
|
+
if (character.clothesId) {
|
|
274
|
+
const { data } = await publisherRequest(http, projectPath(http, `/clothes/${encodeURIComponent(character.clothesId)}`), getClothesResponseSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
275
|
+
out.clothes = data.clothes;
|
|
276
|
+
out.clothesId = data.clothes.id;
|
|
277
|
+
created.clothes = false;
|
|
278
|
+
}
|
|
279
|
+
if (character.hairId) {
|
|
280
|
+
const { data } = await publisherRequest(http, projectPath(http, `/hair/${encodeURIComponent(character.hairId)}`), getHairResponseSchema, { method: 'GET', signal: options.signal, retry: true });
|
|
281
|
+
out.hair = data.hair;
|
|
282
|
+
out.hairId = data.hair.id;
|
|
283
|
+
created.hair = false;
|
|
284
|
+
}
|
|
285
|
+
return out;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Resolve character with externalId-safe wardrobe:
|
|
289
|
+
* - reuse `{ id }` → GET, no wardrobe create
|
|
290
|
+
* - create with externalId → probe create without appearance; on reuse skip wardrobe;
|
|
291
|
+
* on new create, build wardrobe then PATCH appearance
|
|
292
|
+
* - create without externalId → wardrobe first, then create with appearance
|
|
293
|
+
*/
|
|
294
|
+
async function resolveCharacter(http, parsed, options, appearanceFactory) {
|
|
295
|
+
return runStep('character', async () => {
|
|
296
|
+
if (parsed.reuseId) {
|
|
297
|
+
const character = await getCharacter(http, parsed.reuseId, options);
|
|
298
|
+
const appearance = await loadAppearanceFromCharacter(http, character, options);
|
|
299
|
+
return { character, created: false, appearance };
|
|
300
|
+
}
|
|
301
|
+
const body = parsed.create;
|
|
302
|
+
const wantsAppearance = body.costume !== undefined || body.clothes !== undefined || body.hair !== undefined;
|
|
303
|
+
if (body.externalId) {
|
|
304
|
+
const { data, status } = await publisherRequest(http, projectPath(http, '/characters'), createCharacterResponseSchema, {
|
|
305
|
+
method: 'POST',
|
|
306
|
+
body: characterCreateBody(body),
|
|
307
|
+
signal: options.signal
|
|
308
|
+
});
|
|
309
|
+
const created = status === 201;
|
|
310
|
+
if (!created) {
|
|
311
|
+
const appearance = await loadAppearanceFromCharacter(http, data.character, options);
|
|
312
|
+
return { character: data.character, created: false, appearance };
|
|
313
|
+
}
|
|
314
|
+
if (!wantsAppearance) {
|
|
315
|
+
return { character: data.character, created: true, appearance: { created: {} } };
|
|
316
|
+
}
|
|
317
|
+
const appearance = await appearanceFactory();
|
|
318
|
+
const { data: patched } = await publisherRequest(http, projectPath(http, `/characters/${encodeURIComponent(data.character.id)}`), createCharacterResponseSchema, {
|
|
319
|
+
method: 'PATCH',
|
|
320
|
+
body: {
|
|
321
|
+
...(appearance.costumeId !== undefined
|
|
322
|
+
? { costumeId: appearance.costumeId }
|
|
323
|
+
: {}),
|
|
324
|
+
...(appearance.clothesId !== undefined
|
|
325
|
+
? { clothesId: appearance.clothesId }
|
|
326
|
+
: {}),
|
|
327
|
+
...(appearance.hairId !== undefined ? { hairId: appearance.hairId } : {})
|
|
328
|
+
},
|
|
329
|
+
signal: options.signal,
|
|
330
|
+
retry: true
|
|
331
|
+
});
|
|
332
|
+
return { character: patched.character, created: true, appearance };
|
|
333
|
+
}
|
|
334
|
+
const appearance = wantsAppearance
|
|
335
|
+
? await appearanceFactory()
|
|
336
|
+
: { created: {} };
|
|
337
|
+
const { data, status } = await publisherRequest(http, projectPath(http, '/characters'), createCharacterResponseSchema, {
|
|
338
|
+
method: 'POST',
|
|
339
|
+
body: characterCreateBody(body, appearance),
|
|
340
|
+
signal: options.signal
|
|
341
|
+
});
|
|
342
|
+
return {
|
|
343
|
+
character: data.character,
|
|
344
|
+
created: status === 201,
|
|
345
|
+
appearance
|
|
346
|
+
};
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
export async function createExperienceFrom(http, input, options = {}) {
|
|
350
|
+
requireInput(input);
|
|
351
|
+
const title = requiredString(input.title, 'title');
|
|
352
|
+
if (!input.backdrop || typeof input.backdrop !== 'object') {
|
|
353
|
+
throw new LiformaPublisherError('backdrop is required.', { code: 'INVALID_BODY' });
|
|
354
|
+
}
|
|
355
|
+
if (!input.character || typeof input.character !== 'object') {
|
|
356
|
+
throw new LiformaPublisherError('character is required.', { code: 'INVALID_BODY' });
|
|
357
|
+
}
|
|
358
|
+
const defaultName = title;
|
|
359
|
+
let parsedCharacter;
|
|
360
|
+
try {
|
|
361
|
+
parsedCharacter = parseCharacterInput(input.character);
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
throw withContext(error, 'character');
|
|
365
|
+
}
|
|
366
|
+
const appearanceFactory = () => {
|
|
367
|
+
if (!parsedCharacter.create) {
|
|
368
|
+
return Promise.resolve({ created: {} });
|
|
369
|
+
}
|
|
370
|
+
return resolveAppearance(http, parsedCharacter.create, options);
|
|
371
|
+
};
|
|
372
|
+
// Backdrop can run in parallel with character probe / wardrobe when safe.
|
|
373
|
+
// Character with externalId probes first (inside resolveCharacter) before wardrobe.
|
|
374
|
+
const backdropPromise = resolveBackdrop(http, input.backdrop, options, defaultName);
|
|
375
|
+
const characterNeedsWardrobeFirst = parsedCharacter.create &&
|
|
376
|
+
!parsedCharacter.create.externalId &&
|
|
377
|
+
(parsedCharacter.create.costume !== undefined ||
|
|
378
|
+
parsedCharacter.create.clothes !== undefined ||
|
|
379
|
+
parsedCharacter.create.hair !== undefined);
|
|
380
|
+
let backdropOutcome;
|
|
381
|
+
let characterOutcome;
|
|
382
|
+
if (characterNeedsWardrobeFirst) {
|
|
383
|
+
const [backdrop, appearance] = await Promise.all([
|
|
384
|
+
backdropPromise,
|
|
385
|
+
appearanceFactory()
|
|
386
|
+
]);
|
|
387
|
+
backdropOutcome = backdrop;
|
|
388
|
+
characterOutcome = await resolveCharacter(http, parsedCharacter, options, async () => appearance);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
const [backdrop, character] = await Promise.all([
|
|
392
|
+
backdropPromise,
|
|
393
|
+
resolveCharacter(http, parsedCharacter, options, appearanceFactory)
|
|
394
|
+
]);
|
|
395
|
+
backdropOutcome = backdrop;
|
|
396
|
+
characterOutcome = character;
|
|
397
|
+
}
|
|
398
|
+
const setOutcome = await runStep('set', async () => {
|
|
399
|
+
const { data, status } = await publisherRequest(http, projectPath(http, '/sets'), createSetResponseSchema, {
|
|
400
|
+
method: 'POST',
|
|
401
|
+
body: {
|
|
402
|
+
backdropId: backdropOutcome.backdrop.id,
|
|
403
|
+
...(input.set?.name !== undefined
|
|
404
|
+
? { name: input.set.name }
|
|
405
|
+
: { name: defaultName }),
|
|
406
|
+
...(input.set?.externalId !== undefined
|
|
407
|
+
? { externalId: input.set.externalId }
|
|
408
|
+
: {})
|
|
409
|
+
},
|
|
410
|
+
signal: options.signal
|
|
411
|
+
});
|
|
412
|
+
const created = status === 201;
|
|
413
|
+
if (!created) {
|
|
414
|
+
// Idempotent set reuse: return the set's real backdrop for a coherent snapshot.
|
|
415
|
+
const set = data.set;
|
|
416
|
+
const backdrop = await getBackdrop(http, set.backdropId, options);
|
|
417
|
+
backdropOutcome = { backdrop, created: false };
|
|
418
|
+
return { set, created: false };
|
|
419
|
+
}
|
|
420
|
+
return { set: data.set, created: true };
|
|
421
|
+
});
|
|
422
|
+
const experienceOutcome = await runStep('experience', async () => {
|
|
423
|
+
const { data, status } = await publisherRequest(http, projectPath(http, '/experiences'), experienceResponseSchema, {
|
|
424
|
+
method: 'POST',
|
|
425
|
+
body: {
|
|
426
|
+
title,
|
|
427
|
+
characterId: characterOutcome.character.id,
|
|
428
|
+
setId: setOutcome.set.id,
|
|
429
|
+
...(input.slug !== undefined ? { slug: input.slug } : {}),
|
|
430
|
+
...(input.attributes !== undefined ? { attributes: input.attributes } : {}),
|
|
431
|
+
...(input.startingMessage !== undefined
|
|
432
|
+
? { startingMessage: input.startingMessage }
|
|
433
|
+
: {}),
|
|
434
|
+
...(input.systemInstructions !== undefined
|
|
435
|
+
? { systemInstructions: input.systemInstructions }
|
|
436
|
+
: {}),
|
|
437
|
+
...(input.introduction !== undefined ? { introduction: input.introduction } : {}),
|
|
438
|
+
...(input.interaction !== undefined ? { interaction: input.interaction } : {}),
|
|
439
|
+
...(input.publish !== undefined ? { publish: input.publish } : {}),
|
|
440
|
+
...(input.externalId !== undefined ? { externalId: input.externalId } : {})
|
|
441
|
+
},
|
|
442
|
+
signal: options.signal
|
|
443
|
+
});
|
|
444
|
+
return { experience: data.experience, created: status === 201 };
|
|
445
|
+
});
|
|
446
|
+
// Experience externalId reuse: rebuild composition from the returned experience
|
|
447
|
+
// so the snapshot matches what is actually live (not orphans from this call).
|
|
448
|
+
if (!experienceOutcome.created) {
|
|
449
|
+
const experience = experienceOutcome.experience;
|
|
450
|
+
const characterId = experience.characterId;
|
|
451
|
+
const setId = experience.setId ?? experience.placeId;
|
|
452
|
+
if (!characterId || !setId) {
|
|
453
|
+
throw new LiformaPublisherError('Reused experience is missing characterId or setId.', { code: 'INVALID_RESPONSE' });
|
|
454
|
+
}
|
|
455
|
+
const character = await getCharacter(http, characterId, options);
|
|
456
|
+
const set = await getSet(http, setId, options);
|
|
457
|
+
const backdrop = await getBackdrop(http, set.backdropId, options);
|
|
458
|
+
const appearance = await loadAppearanceFromCharacter(http, character, options);
|
|
459
|
+
return {
|
|
460
|
+
experience,
|
|
461
|
+
character,
|
|
462
|
+
set,
|
|
463
|
+
backdrop,
|
|
464
|
+
...(appearance.costume ? { costume: appearance.costume } : {}),
|
|
465
|
+
...(appearance.clothes ? { clothes: appearance.clothes } : {}),
|
|
466
|
+
...(appearance.hair ? { hair: appearance.hair } : {}),
|
|
467
|
+
created: {
|
|
468
|
+
experience: false,
|
|
469
|
+
character: false,
|
|
470
|
+
set: false,
|
|
471
|
+
backdrop: false,
|
|
472
|
+
...appearance.created
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const appearance = characterOutcome.appearance;
|
|
477
|
+
return {
|
|
478
|
+
experience: experienceOutcome.experience,
|
|
479
|
+
character: characterOutcome.character,
|
|
480
|
+
set: setOutcome.set,
|
|
481
|
+
backdrop: backdropOutcome.backdrop,
|
|
482
|
+
...(appearance.costume ? { costume: appearance.costume } : {}),
|
|
483
|
+
...(appearance.clothes ? { clothes: appearance.clothes } : {}),
|
|
484
|
+
...(appearance.hair ? { hair: appearance.hair } : {}),
|
|
485
|
+
created: {
|
|
486
|
+
experience: experienceOutcome.created,
|
|
487
|
+
character: characterOutcome.created,
|
|
488
|
+
set: setOutcome.created,
|
|
489
|
+
backdrop: backdropOutcome.created,
|
|
490
|
+
...appearance.created
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
//# sourceMappingURL=createFrom.js.map
|