mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
[api] 2025 inventions
This commit is contained in:
+187
-1
@@ -420,6 +420,10 @@ export const InventionVersionDto = z.object({
|
||||
ChipsCost: z.int(),
|
||||
CloudVariablesCost: z.int(),
|
||||
AICost: z.int(),
|
||||
HasBetaContent: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Set from `v9/save` on — absent on a version saved through `v6/save`'),
|
||||
})
|
||||
|
||||
/** A tag on an invention. `Type` 0 = custom (creator-submitted), 2 = auto-derived. */
|
||||
@@ -456,10 +460,30 @@ export const InventionDto = z.object({
|
||||
AllowTrial: z.boolean(),
|
||||
HideFromPlayer: z.boolean(),
|
||||
ReferencedInventions: z.array(z.int()),
|
||||
ReferencedUnityAssetIds: z
|
||||
.array(z.string())
|
||||
.optional()
|
||||
.describe('Set from `v9/save` on — absent on an invention saved through `v6/save`'),
|
||||
UgcVersion: z
|
||||
.int()
|
||||
.optional()
|
||||
.describe('An invention field, not a version one — set from `v9/save` on'),
|
||||
LongDescription: z.string().optional().describe('Set from `v9/save` on, when non-empty'),
|
||||
DisplayMetadataJson: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('The client’s own display state, stored as the opaque string it sent'),
|
||||
ConvertedFromInventionId: z
|
||||
.int()
|
||||
.optional()
|
||||
.describe('The invention this one was converted from, when `v9/save` named one'),
|
||||
Tags: z
|
||||
.array(InventionTagDto)
|
||||
.optional()
|
||||
.describe('Unset on save — the real RRInvention carries no Tags field'),
|
||||
.describe(
|
||||
'The real RRInvention carries no Tags field. Unset by `v6/save`; set by `v9/save` ' +
|
||||
'when its `tagsRequest` names at least one tag'
|
||||
),
|
||||
})
|
||||
|
||||
/** The `{ Status, Invention, InventionVersion }` envelope every invention write answers. */
|
||||
@@ -469,6 +493,88 @@ export const InventionSaveResult = z.object({
|
||||
InventionVersion: InventionVersionDto,
|
||||
})
|
||||
|
||||
/**
|
||||
* The `Invention` a v9 save answers with — the newer client's own `RRInvention`, which is
|
||||
* not the record this server stores or the read endpoints serve: no nested
|
||||
* `CurrentVersion` (the version rides beside it), no `Referenced*` (those moved onto the
|
||||
* version), no `IsPublished`.
|
||||
*/
|
||||
export const InventionV9Dto = z.object({
|
||||
InventionId: z.int(),
|
||||
ReplicationId: z.string(),
|
||||
CreatorPlayerId: z.int(),
|
||||
Name: z.string(),
|
||||
Description: z.string(),
|
||||
ImageName: z.string(),
|
||||
UgcVersion: z.int().describe('The UGC format the blob was written in; 0 when unsent'),
|
||||
CurrentVersionNumber: z.int(),
|
||||
LatestVersionNumber: z.int().describe('The same as CurrentVersionNumber on a fresh save'),
|
||||
Accessibility: z.int(),
|
||||
ForceCannotPublish: z.boolean().describe('Always false — nothing here forbids publishing'),
|
||||
ModifiedAt: z.string(),
|
||||
CreatedAt: z.string(),
|
||||
FirstPublishedAt: z.string().nullable(),
|
||||
CreationRoomId: z.int().nullable(),
|
||||
NumPlayersHaveUsedInRoom: z.int(),
|
||||
NumDownloads: z.int(),
|
||||
CheerCount: z.int(),
|
||||
CreatorPermission: z.int(),
|
||||
GeneralPermission: z.int(),
|
||||
IsAGInvention: z.boolean(),
|
||||
IsCertifiedInvention: z.boolean(),
|
||||
IsRecRoomApproved: z.boolean().describe('Always false — nothing here approves an invention'),
|
||||
AllowTrial: z.boolean(),
|
||||
Price: z.int().nullable(),
|
||||
HideFromPlayer: z.boolean(),
|
||||
DisplayMetadataJson: z.string().nullable(),
|
||||
})
|
||||
|
||||
/**
|
||||
* The `InventionVersion` a v9 save answers with. It carries `HasBetaContent`, a `CreatedAt`
|
||||
* of its own and a nullable `UgcAccessibility`, and notably no `AICost` — which the request
|
||||
* still sends and this server still stores.
|
||||
*/
|
||||
export const InventionVersionV9Dto = z.object({
|
||||
InventionId: z.int(),
|
||||
ReplicationId: z.string(),
|
||||
VersionNumber: z.int(),
|
||||
HasBetaContent: z.boolean(),
|
||||
InstantiationCost: z.int(),
|
||||
LightsCost: z.int(),
|
||||
ChipsCost: z.int(),
|
||||
CloudVariablesCost: z.int(),
|
||||
BlobName: z.string(),
|
||||
BlobHash: z.string().nullable(),
|
||||
CreatedAt: z.string(),
|
||||
UgcAccessibility: z.int().nullable().describe('Always null — versions carry no accessibility'),
|
||||
ReferencedInventions: z.array(z.int()),
|
||||
ReferencedUnityAssetIds: z.array(z.string()),
|
||||
})
|
||||
|
||||
/**
|
||||
* What `v9/save` answers — the enveloped result. The client checks `Success` and then reads
|
||||
* `Value.Invention.InventionId`; `Error` is the only text it shows a human, and `Status`,
|
||||
* `InventionVersion` and `TagsResponse` are deserialized and never read. `Success: true`
|
||||
* with a null `Value` crashes it, so a refusal is `Success: false` with `Value: null`.
|
||||
*/
|
||||
export const InventionSaveV9Result = z.object({
|
||||
Value: z
|
||||
.object({
|
||||
Status: z.int().describe('0 = success; the client never reads it on this route'),
|
||||
Invention: InventionV9Dto,
|
||||
InventionVersion: InventionVersionV9Dto,
|
||||
TagsResponse: z.object({
|
||||
Result: z.int().describe('0 = success; non-zero when a tag broke the tag rule'),
|
||||
Tags: z.array(z.string()).describe('The stored tag NAMES, auto first, then custom'),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.describe('Null when Success is false — and only then'),
|
||||
Success: z.boolean(),
|
||||
Error: z.string().nullable().describe('The refusal message; the only text the client shows'),
|
||||
error_id: z.string().nullable().describe('Always null'),
|
||||
})
|
||||
|
||||
/** The tag filter chips on a browse screen, derived from the tags actually in use. */
|
||||
export const TagFilters = z.object({
|
||||
PinnedFilters: z.array(z.string()),
|
||||
@@ -506,6 +612,58 @@ export const SetTagsResponse = z.object({
|
||||
Tags: z.array(z.string()).describe('Auto tags first, then custom'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `PUT /api/inventions/v2/metadata` JSON body — PascalCase, and every field but the id is
|
||||
* NULLABLE: the newer client sends the whole shape on every edit and marks the fields it
|
||||
* isn't touching as null. An empty string is not a null — it clears the field.
|
||||
*/
|
||||
export const UpdateInventionMetadataRequest = z.object({
|
||||
InventionId: z.int(),
|
||||
Name: z
|
||||
.string()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe('3–24 chars, letters/digits/spaces/dashes/colons; null leaves it alone'),
|
||||
Description: z.string().nullable().optional().describe('Max 512 chars; empty clears it'),
|
||||
LongDescription: z.string().nullable().optional().describe('Empty clears it'),
|
||||
ImageName: z.string().nullable().optional().describe('New thumbnail; empty clears it'),
|
||||
TagsRequest: z
|
||||
.object({
|
||||
AutoTags: z.array(z.string()).nullable().optional(),
|
||||
CustomTags: z.array(z.string()).nullable().optional(),
|
||||
})
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe('Replaces both lists wholesale, as `v1/settags` does; null leaves them alone'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `POST /api/inventions/v4/publish` JSON body — PascalCase, and nullable the way
|
||||
* `v2/metadata`'s is: a null field keeps what the invention already has.
|
||||
*/
|
||||
export const PublishInventionRequest = z.object({
|
||||
InventionId: z.int(),
|
||||
Permission: z
|
||||
.int()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
'The `GeneralPermission` other players get, as a raw ladder number: Unassigned 0, ' +
|
||||
'LimitedOneUseOnly 10, DisallowKeyLock 15, UseOnly 20, EditAndSave 40, Publish 60, ' +
|
||||
'Charge 80, Unlimited 100. Null publishes as UseOnly'
|
||||
),
|
||||
Accessibility: z
|
||||
.int()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe('Private 0, Public 1, Unlisted 2. Unlisted stays out of browse and search'),
|
||||
Price: z
|
||||
.int()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe('Price in tokens; null leaves it as it is, and a negative one is ignored'),
|
||||
})
|
||||
|
||||
/** `POST /api/inventions/v1/updateprice` JSON body. */
|
||||
export const UpdatePriceRequest = z.object({
|
||||
InventionId: z.int(),
|
||||
@@ -533,6 +691,34 @@ export const SaveInventionRequest = z.object({
|
||||
aiCost: z.int().optional(),
|
||||
creationRoomId: z.int().optional(),
|
||||
referencedInventions: z.array(z.int()).optional(),
|
||||
creatorAccountRole: z
|
||||
.int()
|
||||
.optional()
|
||||
.describe('Accepted and ignored — a room role, not a permission over the invention'),
|
||||
})
|
||||
|
||||
/**
|
||||
* `POST /api/inventions/v9/save` JSON body — `v6`’s fields plus what the invention
|
||||
* points at, what it says about itself, and the tags that used to need a second
|
||||
* `v1/settags` call.
|
||||
*/
|
||||
export const SaveInventionV9Request = SaveInventionRequest.extend({
|
||||
ugcVersion: z.int().optional().describe('The UGC format the blob was written in'),
|
||||
hasBetaContent: z.boolean().optional(),
|
||||
referencedUnityAssetIds: z.array(z.string()).optional(),
|
||||
longDescription: z.string().optional().describe('Stored when non-empty'),
|
||||
displayMetadataJson: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Opaque client display state, e.g. `{"0":0,"99":0}`; stored verbatim'),
|
||||
convertedFromInventionId: z.int().nullable().optional(),
|
||||
tagsRequest: z
|
||||
.object({
|
||||
AutoTags: z.array(z.string()).nullable().optional(),
|
||||
CustomTags: z.array(z.string()).nullable().optional(),
|
||||
})
|
||||
.optional()
|
||||
.describe('The same two lists `v1/settags` takes, folded into the save'),
|
||||
})
|
||||
|
||||
// ---- Avatar / custom avatar items ------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user