portals-mcp 1.3.2 → 1.3.4
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/marketplace-client.d.ts +9 -0
- package/dist/marketplace-client.d.ts.map +1 -1
- package/dist/marketplace-client.js +120 -20
- package/dist/resources/index/effects.json +88 -1
- package/dist/resources/index/intents.json +164 -164
- package/dist/resources/index/items.json +59 -8
- package/dist/resources/index/knowledge-map.json +13 -0
- package/dist/resources/index/triggers.json +28 -0
- package/dist/resources/logic/js-function-reference.md +16 -6
- package/dist/resources/logic/js-use-effector.md +60 -7
- package/dist/resources/python/README.md +2 -0
- package/dist/resources/python/lib/portals_core.py +159 -8
- package/dist/resources/python/lib/portals_effects.py +180 -7
- package/dist/resources/python/lib/portals_ops.py +148 -16
- package/dist/resources/python/lib/portals_utils.py +1171 -1170
- package/dist/resources/python/tools/build_reactgui_feature_test_room.py +386 -0
- package/dist/resources/python/tools/validate_room.py +430 -40
- package/dist/resources/python/tools/verify_reactgui_feature_room.py +199 -0
- package/dist/resources/ref/items/camera.json +52 -47
- package/dist/resources/ref/items/cube.json +51 -5
- package/dist/resources/ref/items/effects-vfx.json +171 -115
- package/dist/resources/ref/items/glb.json +97 -64
- package/dist/resources/ref/items/text.json +71 -69
- package/dist/resources/ref/items/trigger-zone.json +4 -0
- package/dist/resources/ref/settings.json +198 -191
- package/dist/resources/ref/systems/function-effector-js.json +9 -6
- package/dist/resources/ref/systems/use-effector.json +74 -73
- package/dist/resources/ref/template-layouts.json +2594 -0
- package/dist/resources/reference/api-cheatsheet.md +16 -3
- package/dist/resources/reference/cameras.md +569 -565
- package/dist/resources/reference/gotchas.md +17 -4
- package/dist/resources/reference/interactions.md +6 -1
- package/dist/resources/reference/items/building.md +52 -0
- package/dist/resources/reference/items/effects.md +110 -170
- package/dist/resources/reference/items/gameplay.md +7 -5
- package/dist/resources/reference/items/models.md +184 -168
- package/dist/resources/reference/reactgui-feature-test-room.md +97 -0
- package/dist/resources/reference/template-layouts.md +167 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +163 -20
- package/package.json +1 -1
|
@@ -24,6 +24,12 @@ export interface MarketplaceItem {
|
|
|
24
24
|
claimCount: number;
|
|
25
25
|
acquireCount: number;
|
|
26
26
|
}
|
|
27
|
+
export interface MarketplaceGlbResolution {
|
|
28
|
+
glb: string | null;
|
|
29
|
+
source: "catalog_direct" | "user_inventory" | "room_build_items" | "unresolved";
|
|
30
|
+
attachedToRoomInventory: boolean;
|
|
31
|
+
reason?: string | undefined;
|
|
32
|
+
}
|
|
27
33
|
export interface MarketplaceFilter {
|
|
28
34
|
query?: string | undefined;
|
|
29
35
|
type?: string | undefined;
|
|
@@ -44,6 +50,8 @@ export interface ClaimResult {
|
|
|
44
50
|
itemId: string;
|
|
45
51
|
message?: string | undefined;
|
|
46
52
|
}
|
|
53
|
+
export declare function isMarketplaceAssetRoute(value: string | null | undefined): boolean;
|
|
54
|
+
export declare function isRuntimeGlbUrl(value: string | null | undefined): boolean;
|
|
47
55
|
export declare function clearMarketplaceCache(): void;
|
|
48
56
|
export declare function searchMarketplace(filter?: MarketplaceFilter): Promise<MarketplaceItem[]>;
|
|
49
57
|
export declare function getPackItems(packId: string): Promise<MarketplaceItem[]>;
|
|
@@ -116,4 +124,5 @@ export interface OwnershipCheck {
|
|
|
116
124
|
export declare function verifyOwnership(cids: string[]): Promise<OwnershipCheck[]>;
|
|
117
125
|
export declare function attachItemsToRoom(roomId: string, itemIds: string[]): Promise<AttachToRoomResult>;
|
|
118
126
|
export declare function claimMarketplaceItem(itemId: string): Promise<ClaimResult>;
|
|
127
|
+
export declare function resolveMarketplaceGlbUrl(item: MarketplaceItem, roomId?: string): Promise<MarketplaceGlbResolution>;
|
|
119
128
|
//# sourceMappingURL=marketplace-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marketplace-client.d.ts","sourceRoot":"","sources":["../src/marketplace-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"marketplace-client.d.ts","sourceRoot":"","sources":["../src/marketplace-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,54 @@
|
|
|
1
1
|
import fetch from "node-fetch";
|
|
2
|
+
import { getAccessKey, isAuthenticated } from "./api.js";
|
|
2
3
|
const API_BASE = process.env.API_BASE || "https://portals.to";
|
|
3
4
|
const CACHE_TTL_MS = 60_000;
|
|
4
5
|
let catalogueCache = null;
|
|
6
|
+
function getRuntimeAccessKey() {
|
|
7
|
+
if (process.env.PORTALS_ACCESS_KEY)
|
|
8
|
+
return process.env.PORTALS_ACCESS_KEY;
|
|
9
|
+
if (!isAuthenticated())
|
|
10
|
+
return null;
|
|
11
|
+
try {
|
|
12
|
+
return getAccessKey();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function authHeaders() {
|
|
19
|
+
const headers = {};
|
|
20
|
+
const token = process.env.PORTALS_USER_TOKEN;
|
|
21
|
+
const accessKey = getRuntimeAccessKey();
|
|
22
|
+
if (token)
|
|
23
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
24
|
+
if (accessKey)
|
|
25
|
+
headers["x-access-key"] = accessKey;
|
|
26
|
+
return headers;
|
|
27
|
+
}
|
|
28
|
+
function jsonAuthHeaders() {
|
|
29
|
+
return { "Content-Type": "application/json", ...authHeaders() };
|
|
30
|
+
}
|
|
31
|
+
export function isMarketplaceAssetRoute(value) {
|
|
32
|
+
if (!value)
|
|
33
|
+
return false;
|
|
34
|
+
try {
|
|
35
|
+
return new URL(value, API_BASE).pathname.startsWith("/api/v2/marketplace/asset/");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return value.startsWith("/api/v2/marketplace/asset/");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function isRuntimeGlbUrl(value) {
|
|
42
|
+
if (!value)
|
|
43
|
+
return false;
|
|
44
|
+
if (isMarketplaceAssetRoute(value))
|
|
45
|
+
return false;
|
|
46
|
+
const trimmed = value.trim();
|
|
47
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("~") || trimmed.startsWith("#")) {
|
|
48
|
+
return /\.glb(?:[?#]|$)/i.test(trimmed);
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
5
52
|
async function fetchCatalogue() {
|
|
6
53
|
if (catalogueCache && Date.now() - catalogueCache.ts < CACHE_TTL_MS) {
|
|
7
54
|
return catalogueCache.items;
|
|
@@ -156,7 +203,7 @@ export async function getUserInventory() {
|
|
|
156
203
|
if (!token)
|
|
157
204
|
return [];
|
|
158
205
|
const res = await fetch(`${API_BASE}/api/v2/marketplace/my-items`, {
|
|
159
|
-
headers:
|
|
206
|
+
headers: authHeaders(),
|
|
160
207
|
});
|
|
161
208
|
if (!res.ok)
|
|
162
209
|
return [];
|
|
@@ -171,17 +218,10 @@ export async function getUserInventory() {
|
|
|
171
218
|
* scene with AI so we know what assets the user actually has.
|
|
172
219
|
*/
|
|
173
220
|
export async function getRoomBuildItems(roomId) {
|
|
174
|
-
const token = process.env.PORTALS_USER_TOKEN;
|
|
175
|
-
const accessKey = process.env.PORTALS_ACCESS_KEY;
|
|
176
221
|
if (!roomId)
|
|
177
222
|
return [];
|
|
178
|
-
const headers = {};
|
|
179
|
-
if (token)
|
|
180
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
181
|
-
if (accessKey)
|
|
182
|
-
headers["x-access-key"] = accessKey;
|
|
183
223
|
try {
|
|
184
|
-
const res = await fetch(`${API_BASE}/api/v2/room/get-build-items?roomId=${encodeURIComponent(roomId)}`, { headers });
|
|
224
|
+
const res = await fetch(`${API_BASE}/api/v2/room/get-build-items?roomId=${encodeURIComponent(roomId)}`, { headers: authHeaders() });
|
|
185
225
|
if (!res.ok)
|
|
186
226
|
return [];
|
|
187
227
|
const json = (await res.json());
|
|
@@ -199,7 +239,7 @@ export async function getRoomBuildItems(roomId) {
|
|
|
199
239
|
*/
|
|
200
240
|
export async function verifyOwnership(cids) {
|
|
201
241
|
const token = process.env.PORTALS_USER_TOKEN;
|
|
202
|
-
const accessKey =
|
|
242
|
+
const accessKey = getRuntimeAccessKey();
|
|
203
243
|
if (!token && !accessKey) {
|
|
204
244
|
// No auth — return unknowns (the caller decides how to proceed).
|
|
205
245
|
return cids.map((cid) => ({
|
|
@@ -210,9 +250,7 @@ export async function verifyOwnership(cids) {
|
|
|
210
250
|
}));
|
|
211
251
|
}
|
|
212
252
|
// Pull catalogue + user inventory in parallel.
|
|
213
|
-
const headers =
|
|
214
|
-
if (token)
|
|
215
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
253
|
+
const headers = authHeaders();
|
|
216
254
|
const [inventoryRes, catalogue] = await Promise.all([
|
|
217
255
|
token ? fetch(`${API_BASE}/api/v2/marketplace/my-items`, { headers }) : Promise.resolve(null),
|
|
218
256
|
fetchCatalogue(),
|
|
@@ -248,18 +286,14 @@ export async function verifyOwnership(cids) {
|
|
|
248
286
|
}
|
|
249
287
|
export async function attachItemsToRoom(roomId, itemIds) {
|
|
250
288
|
const token = process.env.PORTALS_USER_TOKEN;
|
|
251
|
-
const accessKey =
|
|
289
|
+
const accessKey = getRuntimeAccessKey();
|
|
252
290
|
if (!token && !accessKey) {
|
|
253
|
-
return { ok: false, code: "AUTH_REQUIRED", message: "No Firebase token or access key
|
|
291
|
+
return { ok: false, code: "AUTH_REQUIRED", message: "No Firebase token, access key env, or authenticated MCP access key available.", attachedItemIds: [] };
|
|
254
292
|
}
|
|
255
293
|
if (!roomId) {
|
|
256
294
|
return { ok: false, code: "ROOM_ID_REQUIRED", message: "roomId is required.", attachedItemIds: [] };
|
|
257
295
|
}
|
|
258
|
-
const headers =
|
|
259
|
-
if (token)
|
|
260
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
261
|
-
if (accessKey)
|
|
262
|
-
headers["x-access-key"] = accessKey;
|
|
296
|
+
const headers = jsonAuthHeaders();
|
|
263
297
|
let existing = [];
|
|
264
298
|
try {
|
|
265
299
|
const settingsRes = await fetch(`${API_BASE}/api/v2/room/get-settings?roomID=${encodeURIComponent(roomId)}`, { headers });
|
|
@@ -324,3 +358,69 @@ export async function claimMarketplaceItem(itemId) {
|
|
|
324
358
|
message: body.message,
|
|
325
359
|
};
|
|
326
360
|
}
|
|
361
|
+
function matchBuildItem(items, itemId) {
|
|
362
|
+
return items.find((item) => item.id === itemId) ?? null;
|
|
363
|
+
}
|
|
364
|
+
function matchInventoryItem(items, itemId) {
|
|
365
|
+
return items.find((item) => item.itemId === itemId || item.id === itemId) ?? null;
|
|
366
|
+
}
|
|
367
|
+
export async function resolveMarketplaceGlbUrl(item, roomId) {
|
|
368
|
+
if (isRuntimeGlbUrl(item.glb)) {
|
|
369
|
+
return {
|
|
370
|
+
glb: item.glb,
|
|
371
|
+
source: "catalog_direct",
|
|
372
|
+
attachedToRoomInventory: false,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
const inventoryItem = matchInventoryItem(await getUserInventory(), item.id);
|
|
376
|
+
if (inventoryItem?.glb && isRuntimeGlbUrl(inventoryItem.glb)) {
|
|
377
|
+
return {
|
|
378
|
+
glb: inventoryItem.glb,
|
|
379
|
+
source: "user_inventory",
|
|
380
|
+
attachedToRoomInventory: false,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (!roomId) {
|
|
384
|
+
return {
|
|
385
|
+
glb: null,
|
|
386
|
+
source: "unresolved",
|
|
387
|
+
attachedToRoomInventory: false,
|
|
388
|
+
reason: isMarketplaceAssetRoute(item.glb)
|
|
389
|
+
? "Catalog glb is a protected marketplace asset route; pass roomId so MCP can resolve the room build-palette CDN URL."
|
|
390
|
+
: "Catalog item did not include a runtime GLB URL.",
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
let buildItems = await getRoomBuildItems(roomId);
|
|
394
|
+
let buildItem = matchBuildItem(buildItems, item.id);
|
|
395
|
+
if (buildItem?.glb && isRuntimeGlbUrl(buildItem.glb)) {
|
|
396
|
+
return {
|
|
397
|
+
glb: buildItem.glb,
|
|
398
|
+
source: "room_build_items",
|
|
399
|
+
attachedToRoomInventory: false,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
const attachResult = await attachItemsToRoom(roomId, [item.id]);
|
|
403
|
+
if (!attachResult.ok) {
|
|
404
|
+
return {
|
|
405
|
+
glb: null,
|
|
406
|
+
source: "unresolved",
|
|
407
|
+
attachedToRoomInventory: false,
|
|
408
|
+
reason: `Could not attach marketplace item to room inventory for URL resolution (${attachResult.code}${attachResult.message ? `: ${attachResult.message}` : ""}).`,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
buildItems = await getRoomBuildItems(roomId);
|
|
412
|
+
buildItem = matchBuildItem(buildItems, item.id);
|
|
413
|
+
if (buildItem?.glb && isRuntimeGlbUrl(buildItem.glb)) {
|
|
414
|
+
return {
|
|
415
|
+
glb: buildItem.glb,
|
|
416
|
+
source: "room_build_items",
|
|
417
|
+
attachedToRoomInventory: true,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
glb: null,
|
|
422
|
+
source: "unresolved",
|
|
423
|
+
attachedToRoomInventory: true,
|
|
424
|
+
reason: "Item was attached to the room inventory, but get_room_build_items did not return a runtime .glb URL for it.",
|
|
425
|
+
};
|
|
426
|
+
}
|
|
@@ -39,6 +39,16 @@
|
|
|
39
39
|
"Scale in relative mode is ADDITIVE (scale [1,1,1] adds 1 to each axis per trigger)"
|
|
40
40
|
]
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
"$type": "SetTransform",
|
|
44
|
+
"category": "movement",
|
|
45
|
+
"parameters": {
|
|
46
|
+
"position": "array - optional [x,y,z] world position",
|
|
47
|
+
"rotation": "array - optional [x,y,z] Euler degrees",
|
|
48
|
+
"scale": "array - optional [x,y,z] scale"
|
|
49
|
+
},
|
|
50
|
+
"gotchas": ["Immediate local-player transform write. Include at least one of position, rotation, or scale."]
|
|
51
|
+
},
|
|
42
52
|
{
|
|
43
53
|
"$type": "PortalsAnimation",
|
|
44
54
|
"category": "movement",
|
|
@@ -76,6 +86,82 @@
|
|
|
76
86
|
"parameters": {},
|
|
77
87
|
"gotchas": []
|
|
78
88
|
},
|
|
89
|
+
{
|
|
90
|
+
"$type": "AddForceToCubeEffector",
|
|
91
|
+
"category": "physics",
|
|
92
|
+
"parameters": {
|
|
93
|
+
"fx": "float - impulse X",
|
|
94
|
+
"fy": "float - impulse Y",
|
|
95
|
+
"fz": "float - impulse Z",
|
|
96
|
+
"rel": "bool - true=force vector is local to item rotation"
|
|
97
|
+
},
|
|
98
|
+
"gotchas": ["Direct task effector only; not in ReactGUI UseEffector/PrepareEffector map. Works on ResizableCube and GLB-family physics items."]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"$type": "AddTorqueToCubeEffector",
|
|
102
|
+
"category": "physics",
|
|
103
|
+
"parameters": {
|
|
104
|
+
"tx": "float - rotational impulse X",
|
|
105
|
+
"ty": "float - rotational impulse Y",
|
|
106
|
+
"tz": "float - rotational impulse Z",
|
|
107
|
+
"rel": "bool - true=torque vector is local to item rotation"
|
|
108
|
+
},
|
|
109
|
+
"gotchas": ["Direct task effector only; not in ReactGUI UseEffector/PrepareEffector map. Works on ResizableCube and GLB-family physics items."]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"$type": "ExplosionForceCubeEffector",
|
|
113
|
+
"category": "physics",
|
|
114
|
+
"parameters": {
|
|
115
|
+
"f": "float - explosion impulse force",
|
|
116
|
+
"r": "float - explosion radius",
|
|
117
|
+
"u": "float - upward modifier",
|
|
118
|
+
"ox/oy/oz": "floats - origin offset from item position",
|
|
119
|
+
"aff": "bool - true=also affect nearby physics cubes"
|
|
120
|
+
},
|
|
121
|
+
"gotchas": ["Direct task effector only; not in ReactGUI UseEffector/PrepareEffector map."]
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"$type": "SetCubeVelocityEffector",
|
|
125
|
+
"category": "physics",
|
|
126
|
+
"parameters": {
|
|
127
|
+
"vx/vy/vz": "floats - linear velocity",
|
|
128
|
+
"ax/ay/az": "floats - angular velocity",
|
|
129
|
+
"sl": "bool - set linear velocity",
|
|
130
|
+
"sa": "bool - set angular velocity",
|
|
131
|
+
"rel": "bool - true=vectors are local to item rotation"
|
|
132
|
+
},
|
|
133
|
+
"gotchas": ["Direct task effector only. Velocity assignment is most reliable when this client already owns the physics item."]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"$type": "ResetCubeVelocityEffector",
|
|
137
|
+
"category": "physics",
|
|
138
|
+
"parameters": {},
|
|
139
|
+
"gotchas": ["Direct task effector only. Stops linear and angular velocity on the owned physics item."]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"$type": "ToggleCubeGravityEffector",
|
|
143
|
+
"category": "physics",
|
|
144
|
+
"parameters": {
|
|
145
|
+
"g": "bool - true=use gravity, false=float"
|
|
146
|
+
},
|
|
147
|
+
"gotchas": ["Direct task effector only. Ensures physics is attached before changing gravity."]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"$type": "AttachToMouseCubeEffector",
|
|
151
|
+
"category": "physics",
|
|
152
|
+
"parameters": {
|
|
153
|
+
"snap": "bool - true=snap item bottom to placeable surfaces"
|
|
154
|
+
},
|
|
155
|
+
"gotchas": ["JS UseEffector name is AttachToMouse, while direct room-data $type is AttachToMouseCubeEffector."]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"$type": "DetachFromMouseCubeEffector",
|
|
159
|
+
"category": "physics",
|
|
160
|
+
"parameters": {
|
|
161
|
+
"save": "bool - true=persist final drop position when server permissions and item opt-in allow it"
|
|
162
|
+
},
|
|
163
|
+
"gotchas": ["JS UseEffector name is DetachFromMouse, while direct room-data $type is DetachFromMouseCubeEffector."]
|
|
164
|
+
},
|
|
79
165
|
{
|
|
80
166
|
"$type": "AddVelocityToPlayer",
|
|
81
167
|
"category": "player",
|
|
@@ -235,7 +321,8 @@
|
|
|
235
321
|
"category": "camera",
|
|
236
322
|
"parameters": {
|
|
237
323
|
"camState": "string — camera state name (matches CameraObject sn)",
|
|
238
|
-
"
|
|
324
|
+
"smoothTransition": "bool — blend to the new state, default true",
|
|
325
|
+
"transitionSpeed": "float — transition speed, default 6.0"
|
|
239
326
|
},
|
|
240
327
|
"gotchas": []
|
|
241
328
|
},
|