@playdrop/playdrop-cli 0.5.5 → 0.5.6
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 +2 -1
- package/config/client-meta.json +4 -4
- package/dist/apps/upload.js +226 -80
- package/dist/assetSpecs.d.ts +1 -0
- package/dist/assetSpecs.js +22 -1
- package/dist/assets/model-artifacts.d.ts +2 -2
- package/dist/assets/model-artifacts.js +1 -1
- package/dist/captureRuntime.d.ts +1 -0
- package/dist/captureRuntime.js +3 -2
- package/dist/catalogue.d.ts +33 -8
- package/dist/catalogue.js +364 -46
- package/dist/commandContext.d.ts +5 -1
- package/dist/commandContext.js +90 -29
- package/dist/commands/browse.d.ts +3 -0
- package/dist/commands/browse.js +90 -17
- package/dist/commands/build.js +1 -1
- package/dist/commands/capture.d.ts +3 -0
- package/dist/commands/capture.js +121 -9
- package/dist/commands/captureListing.d.ts +2 -0
- package/dist/commands/captureListing.js +157 -61
- package/dist/commands/create.js +6 -28
- package/dist/commands/createRemixContent.js +4 -26
- package/dist/commands/creations.js +2 -3
- package/dist/commands/detail.js +24 -2
- package/dist/commands/dev.d.ts +8 -1
- package/dist/commands/dev.js +180 -2
- package/dist/commands/devRuntimeAssets.d.ts +34 -0
- package/dist/commands/devRuntimeAssets.js +308 -0
- package/dist/commands/devServer.d.ts +11 -0
- package/dist/commands/devServer.js +196 -13
- package/dist/commands/init.js +6 -24
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.js +68 -11
- package/dist/commands/upload-content.d.ts +3 -3
- package/dist/commands/upload-content.js +19 -38
- package/dist/commands/upload.js +67 -77
- package/dist/commands/validate.js +13 -20
- package/dist/commands/whoami.js +23 -26
- package/dist/devAuth.d.ts +16 -0
- package/dist/devAuth.js +60 -0
- package/dist/index.js +22 -4
- package/dist/taskSelection.js +4 -3
- package/dist/taskUtils.d.ts +2 -2
- package/dist/taskUtils.js +1 -1
- package/dist/uploadLog.d.ts +1 -1
- package/node_modules/@playdrop/ai-client/package.json +1 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts +43 -114
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +22 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +11 -19
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +116 -106
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +13 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +5 -5
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +8 -8
- package/node_modules/@playdrop/api-client/dist/domains/search.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/search.js +24 -2
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts +13 -1
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/tags.js +52 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +25 -29
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +23 -8
- package/node_modules/@playdrop/api-client/package.json +1 -1
- package/node_modules/@playdrop/boxel-core/package.json +1 -1
- package/node_modules/@playdrop/boxel-three/package.json +1 -1
- package/node_modules/@playdrop/config/client-meta.json +4 -4
- package/node_modules/@playdrop/config/package.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +124 -3
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +23 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.d.ts +24 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.js +72 -0
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +3 -2
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.d.ts +2 -3
- package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.js +1 -1
- package/node_modules/@playdrop/types/dist/index.d.ts +2 -0
- package/node_modules/@playdrop/types/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/index.js +2 -0
- package/node_modules/@playdrop/types/dist/owned-assets.d.ts +21 -0
- package/node_modules/@playdrop/types/dist/owned-assets.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/owned-assets.js +35 -0
- package/node_modules/@playdrop/types/dist/player-meta.d.ts +28 -0
- package/node_modules/@playdrop/types/dist/player-meta.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +111 -1
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +3 -0
- package/node_modules/@playdrop/types/package.json +1 -1
- package/node_modules/@playdrop/vox-three/package.json +1 -1
- package/package.json +1 -1
package/dist/catalogue.js
CHANGED
|
@@ -22,7 +22,7 @@ const BOXEL_GENERATED_FILE_ROLES = new Set(['mesh', 'preview']);
|
|
|
22
22
|
const BOXEL_REQUIRED_FILE_ROLES = ['primary', 'mesh', 'preview'];
|
|
23
23
|
const VOX_GENERATED_FILE_ROLES = new Set(['boxel', 'mesh', 'preview']);
|
|
24
24
|
const VOX_REQUIRED_FILE_ROLES = ['primary', 'boxel', 'mesh', 'preview'];
|
|
25
|
-
const MAX_CONTENT_TAGS_PER_ITEM =
|
|
25
|
+
const MAX_CONTENT_TAGS_PER_ITEM = 20;
|
|
26
26
|
const ASSET_SUBCATEGORY_SET_BY_CATEGORY = types_1.ASSET_SUBCATEGORY_DEFINITIONS.reduce((acc, definition) => {
|
|
27
27
|
if (!acc[definition.category]) {
|
|
28
28
|
acc[definition.category] = new Set();
|
|
@@ -62,6 +62,66 @@ function getGeneratedModel3DFileRoles(format) {
|
|
|
62
62
|
required: BOXEL_REQUIRED_FILE_ROLES,
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
+
function extractGlbJsonChunk(buffer) {
|
|
66
|
+
if (buffer.length < 20) {
|
|
67
|
+
throw new Error('invalid_glb_payload');
|
|
68
|
+
}
|
|
69
|
+
if (buffer.toString('utf8', 0, 4) !== 'glTF') {
|
|
70
|
+
throw new Error('invalid_glb_payload');
|
|
71
|
+
}
|
|
72
|
+
const version = buffer.readUInt32LE(4);
|
|
73
|
+
const declaredLength = buffer.readUInt32LE(8);
|
|
74
|
+
if (version !== 2 || declaredLength !== buffer.length) {
|
|
75
|
+
throw new Error('invalid_glb_payload');
|
|
76
|
+
}
|
|
77
|
+
let offset = 12;
|
|
78
|
+
while (offset + 8 <= buffer.length) {
|
|
79
|
+
const chunkLength = buffer.readUInt32LE(offset);
|
|
80
|
+
const chunkType = buffer.readUInt32LE(offset + 4);
|
|
81
|
+
offset += 8;
|
|
82
|
+
if (offset + chunkLength > buffer.length) {
|
|
83
|
+
throw new Error('invalid_glb_payload');
|
|
84
|
+
}
|
|
85
|
+
const chunk = buffer.subarray(offset, offset + chunkLength);
|
|
86
|
+
offset += chunkLength;
|
|
87
|
+
if (chunkType !== 0x4E4F534A) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const payload = chunk.toString('utf8').replace(/\0+$/, '').trimEnd();
|
|
91
|
+
try {
|
|
92
|
+
const parsed = JSON.parse(payload);
|
|
93
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
94
|
+
throw new Error('invalid_glb_payload');
|
|
95
|
+
}
|
|
96
|
+
return parsed;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw new Error('invalid_glb_payload');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
throw new Error('invalid_glb_payload');
|
|
103
|
+
}
|
|
104
|
+
function validateSelfContainedGlb(filePath) {
|
|
105
|
+
const gltf = extractGlbJsonChunk((0, node_fs_1.readFileSync)(filePath));
|
|
106
|
+
const buffers = Array.isArray(gltf.buffers) ? gltf.buffers : [];
|
|
107
|
+
for (const entry of buffers) {
|
|
108
|
+
const uri = entry && typeof entry === 'object' && typeof entry.uri === 'string'
|
|
109
|
+
? entry.uri.trim()
|
|
110
|
+
: '';
|
|
111
|
+
if (uri && !uri.startsWith('data:')) {
|
|
112
|
+
throw new Error('glb_external_dependency_unsupported');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const images = Array.isArray(gltf.images) ? gltf.images : [];
|
|
116
|
+
for (const entry of images) {
|
|
117
|
+
const uri = entry && typeof entry === 'object' && typeof entry.uri === 'string'
|
|
118
|
+
? entry.uri.trim()
|
|
119
|
+
: '';
|
|
120
|
+
if (uri && !uri.startsWith('data:')) {
|
|
121
|
+
throw new Error('glb_external_dependency_unsupported');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
65
125
|
/**
|
|
66
126
|
* Validates a listing asset path:
|
|
67
127
|
* - Must exist
|
|
@@ -161,6 +221,52 @@ function normalizeCatalogueRelations(value, errors, context) {
|
|
|
161
221
|
}
|
|
162
222
|
return rows.length > 0 ? rows : undefined;
|
|
163
223
|
}
|
|
224
|
+
function normalizeCatalogueAppDependencyAssets(value, errors, context) {
|
|
225
|
+
if (!Array.isArray(value)) {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
const rows = [];
|
|
229
|
+
const seenRefs = new Set();
|
|
230
|
+
const seenRuntimeKeys = new Set();
|
|
231
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
232
|
+
const entry = value[index];
|
|
233
|
+
const ref = typeof entry === 'string'
|
|
234
|
+
? entry.trim()
|
|
235
|
+
: entry && typeof entry === 'object' && !Array.isArray(entry) && typeof entry.ref === 'string'
|
|
236
|
+
? entry.ref.trim()
|
|
237
|
+
: '';
|
|
238
|
+
if (!ref) {
|
|
239
|
+
errors.push(`${context} uses.assets[${index}] must be a non-empty asset ref string or { ref, runtimeKey } object.`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const parsed = (0, types_1.parseContentVersionRef)(ref);
|
|
243
|
+
if (!parsed || parsed.kind !== 'asset') {
|
|
244
|
+
errors.push(`${context} uses.assets[${index}] must be a canonical asset version ref.`);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const normalizedRef = (0, types_1.formatContentVersionRef)(parsed);
|
|
248
|
+
if (seenRefs.has(normalizedRef)) {
|
|
249
|
+
errors.push(`${context} uses.assets contains duplicate ref "${normalizedRef}".`);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const runtimeKey = entry && typeof entry === 'object' && !Array.isArray(entry) && typeof entry.runtimeKey === 'string'
|
|
253
|
+
? entry.runtimeKey.trim()
|
|
254
|
+
: '';
|
|
255
|
+
if (runtimeKey) {
|
|
256
|
+
if (seenRuntimeKeys.has(runtimeKey)) {
|
|
257
|
+
errors.push(`${context} uses.assets contains duplicate runtimeKey "${runtimeKey}".`);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
seenRuntimeKeys.add(runtimeKey);
|
|
261
|
+
}
|
|
262
|
+
seenRefs.add(normalizedRef);
|
|
263
|
+
rows.push({
|
|
264
|
+
ref: normalizedRef,
|
|
265
|
+
...(runtimeKey ? { runtimeKey } : {}),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return rows;
|
|
269
|
+
}
|
|
164
270
|
function rejectLegacyShopPriceCoinsField(value, errors, context) {
|
|
165
271
|
if (Object.prototype.hasOwnProperty.call(value, 'shopPriceCoins')) {
|
|
166
272
|
errors.push(`${context} uses legacy shopPriceCoins. Rename it to shopPriceCredits.`);
|
|
@@ -450,6 +556,16 @@ function normalizeAssetCategoryValue(raw, errors, label) {
|
|
|
450
556
|
return normalized;
|
|
451
557
|
}
|
|
452
558
|
function normalizeAssetSubcategoryValue(raw, category, errors, label) {
|
|
559
|
+
if (category === 'CUSTOM') {
|
|
560
|
+
if (raw === undefined || raw === null) {
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
if (typeof raw === 'string' && raw.trim().length === 0) {
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
errors.push(`${label} must not define subcategory when category is CUSTOM.`);
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
453
569
|
if (typeof raw !== 'string' || raw.trim().length === 0) {
|
|
454
570
|
errors.push(`${label} must define subcategory.`);
|
|
455
571
|
return null;
|
|
@@ -742,12 +858,19 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
742
858
|
errors.push(`[${label}] App entry is missing a name.`);
|
|
743
859
|
continue;
|
|
744
860
|
}
|
|
861
|
+
const ownedAssetNameMatch = filterName
|
|
862
|
+
? Array.isArray(entry.ownedAssets)
|
|
863
|
+
&& entry.ownedAssets.some((ownedAsset) => ownedAsset
|
|
864
|
+
&& typeof ownedAsset === 'object'
|
|
865
|
+
&& typeof ownedAsset.name === 'string'
|
|
866
|
+
&& ownedAsset.name.trim() === filterName)
|
|
867
|
+
: true;
|
|
745
868
|
const fileField = typeof entry.file === 'string' && entry.file.trim().length > 0
|
|
746
869
|
? entry.file.trim()
|
|
747
870
|
: `${rawName}.html`;
|
|
748
871
|
const absoluteFilePath = (0, node_path_1.resolve)(file.directory, fileField);
|
|
749
872
|
const normalizedFile = normalizePathForComparison(absoluteFilePath);
|
|
750
|
-
const matchName = filterName ? rawName === filterName : true;
|
|
873
|
+
const matchName = filterName ? rawName === filterName || ownedAssetNameMatch : true;
|
|
751
874
|
const matchFile = filterFile ? normalizedFile === filterFile : true;
|
|
752
875
|
if (!matchName || !matchFile) {
|
|
753
876
|
continue;
|
|
@@ -1105,9 +1228,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1105
1228
|
}
|
|
1106
1229
|
listing = resolvedListing;
|
|
1107
1230
|
}
|
|
1108
|
-
const usesAssets =
|
|
1109
|
-
? entry.uses.assets.filter((value) => typeof value === 'string' && value.trim().length > 0)
|
|
1110
|
-
: [];
|
|
1231
|
+
const usesAssets = normalizeCatalogueAppDependencyAssets(entry.uses?.assets, errors, `[${label}] App "${rawName}"`);
|
|
1111
1232
|
const usesPacks = Array.isArray(entry.uses?.packs)
|
|
1112
1233
|
? entry.uses.packs.filter((value) => typeof value === 'string' && value.trim().length > 0)
|
|
1113
1234
|
: [];
|
|
@@ -1118,44 +1239,54 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1118
1239
|
if (errors.length > errorCountBeforeTagMetadata) {
|
|
1119
1240
|
continue;
|
|
1120
1241
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1242
|
+
if (Object.prototype.hasOwnProperty.call(entry, 'embeddedAssets')) {
|
|
1243
|
+
errors.push(`[${label}] App "${rawName}" uses legacy embeddedAssets. Rename it to ownedAssets.`);
|
|
1244
|
+
continue;
|
|
1245
|
+
}
|
|
1246
|
+
const ownedAssets = [];
|
|
1247
|
+
const rawOwnedAssets = Array.isArray(entry.ownedAssets)
|
|
1248
|
+
? entry.ownedAssets
|
|
1124
1249
|
: [];
|
|
1125
|
-
for (let
|
|
1126
|
-
const
|
|
1127
|
-
const
|
|
1128
|
-
if (!
|
|
1129
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1250
|
+
for (let ownedIndex = 0; ownedIndex < rawOwnedAssets.length; ownedIndex++) {
|
|
1251
|
+
const owned = rawOwnedAssets[ownedIndex];
|
|
1252
|
+
const ownedName = typeof owned?.name === 'string' ? owned.name.trim() : '';
|
|
1253
|
+
if (!ownedName) {
|
|
1254
|
+
errors.push(`[${label}] Skipping ${rawName}: ownedAssets[${ownedIndex}] is missing a name.`);
|
|
1130
1255
|
continue;
|
|
1131
1256
|
}
|
|
1132
|
-
const
|
|
1257
|
+
const runtimeKey = typeof owned?.runtimeKey === 'string' && owned.runtimeKey.trim().length > 0
|
|
1258
|
+
? owned.runtimeKey.trim()
|
|
1259
|
+
: undefined;
|
|
1260
|
+
const category = normalizeAssetCategoryValue(owned?.category, errors, `[${label}] Skipping ${rawName}: owned asset "${ownedName}"`);
|
|
1133
1261
|
if (!category) {
|
|
1134
1262
|
continue;
|
|
1135
1263
|
}
|
|
1136
|
-
const subcategory = normalizeAssetSubcategoryValue(
|
|
1137
|
-
if (
|
|
1264
|
+
const subcategory = normalizeAssetSubcategoryValue(owned?.subcategory, category, errors, `[${label}] Skipping ${rawName}: owned asset "${ownedName}"`);
|
|
1265
|
+
if (subcategory === null && category !== 'CUSTOM') {
|
|
1138
1266
|
continue;
|
|
1139
1267
|
}
|
|
1140
|
-
const fileEntries =
|
|
1141
|
-
?
|
|
1268
|
+
const fileEntries = owned?.files && typeof owned.files === 'object' && !Array.isArray(owned.files)
|
|
1269
|
+
? owned.files
|
|
1142
1270
|
: null;
|
|
1143
|
-
const
|
|
1144
|
-
|
|
1271
|
+
const assetSpec = (0, assetSpecs_1.normalizeAssetSpecVersionRef)(owned?.assetSpec, errors, `[${label}] App "${rawName}" owned asset "${ownedName}"`);
|
|
1272
|
+
const ownedFormat = typeof owned?.format === 'string' && owned.format.trim().length > 0
|
|
1273
|
+
? owned.format.trim().toUpperCase()
|
|
1145
1274
|
: undefined;
|
|
1146
|
-
const generatedModel3DFormat =
|
|
1275
|
+
const generatedModel3DFormat = subcategory
|
|
1276
|
+
? inferGeneratedModel3DFormat(category, subcategory, ownedFormat, fileEntries)
|
|
1277
|
+
: null;
|
|
1147
1278
|
const generatedModel3DRoles = generatedModel3DFormat ? getGeneratedModel3DFileRoles(generatedModel3DFormat) : null;
|
|
1148
1279
|
if (!fileEntries || Object.keys(fileEntries).length === 0) {
|
|
1149
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1280
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" must define files.`);
|
|
1150
1281
|
continue;
|
|
1151
1282
|
}
|
|
1152
1283
|
const files = {};
|
|
1153
1284
|
const filePaths = {};
|
|
1154
|
-
let
|
|
1285
|
+
let ownedAssetHasError = false;
|
|
1155
1286
|
for (const [role, fileValue] of Object.entries(fileEntries)) {
|
|
1156
1287
|
if (typeof fileValue !== 'string' || !fileValue.trim()) {
|
|
1157
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1158
|
-
|
|
1288
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" file role "${role}" must be a non-empty string path.`);
|
|
1289
|
+
ownedAssetHasError = true;
|
|
1159
1290
|
continue;
|
|
1160
1291
|
}
|
|
1161
1292
|
const relativeEmbeddedPath = fileValue.trim();
|
|
@@ -1168,21 +1299,21 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1168
1299
|
filePaths[role] = absoluteEmbeddedPath;
|
|
1169
1300
|
continue;
|
|
1170
1301
|
}
|
|
1171
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1172
|
-
|
|
1302
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" file not found at ${absoluteEmbeddedPath}.`);
|
|
1303
|
+
ownedAssetHasError = true;
|
|
1173
1304
|
continue;
|
|
1174
1305
|
}
|
|
1175
1306
|
files[role] = relativeEmbeddedPath.replace(/\\/g, '/');
|
|
1176
1307
|
filePaths[role] = absoluteEmbeddedPath;
|
|
1177
1308
|
}
|
|
1178
|
-
if (
|
|
1309
|
+
if (ownedAssetHasError) {
|
|
1179
1310
|
continue;
|
|
1180
1311
|
}
|
|
1181
1312
|
if (generatedModel3DRoles) {
|
|
1182
1313
|
const normalizedRoles = new Set(Object.keys(files).map((role) => normalizeFileRole(role)));
|
|
1183
1314
|
const missingRoles = generatedModel3DRoles.required.filter((role) => !normalizedRoles.has(role));
|
|
1184
1315
|
if (missingRoles.length > 0) {
|
|
1185
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1316
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" with subcategory=${subcategory} must define files.${missingRoles.join(' and files.')}.`);
|
|
1186
1317
|
continue;
|
|
1187
1318
|
}
|
|
1188
1319
|
}
|
|
@@ -1190,35 +1321,86 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1190
1321
|
const hasAtlas = Object.prototype.hasOwnProperty.call(files, 'atlas');
|
|
1191
1322
|
const hasManifest = Object.prototype.hasOwnProperty.call(files, 'manifest');
|
|
1192
1323
|
if (!hasAtlas || !hasManifest) {
|
|
1193
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1324
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" with category=SPRITESHEET must define files.atlas and files.manifest.`);
|
|
1194
1325
|
continue;
|
|
1195
1326
|
}
|
|
1196
1327
|
}
|
|
1197
1328
|
if (category === 'AUDIO') {
|
|
1198
1329
|
const hasPrimary = Object.prototype.hasOwnProperty.call(files, 'primary');
|
|
1199
1330
|
if (!hasPrimary) {
|
|
1200
|
-
errors.push(`[${label}] Skipping ${rawName}:
|
|
1331
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" with category=AUDIO must define files.primary.`);
|
|
1332
|
+
continue;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
if (category === 'MODEL_3D' && ownedFormat === 'GLB') {
|
|
1336
|
+
const primaryPath = filePaths.primary;
|
|
1337
|
+
if (!primaryPath) {
|
|
1338
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" with format=GLB must define files.primary.`);
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
try {
|
|
1342
|
+
validateSelfContainedGlb(primaryPath);
|
|
1343
|
+
}
|
|
1344
|
+
catch (error) {
|
|
1345
|
+
const message = typeof error?.message === 'string' ? error.message : 'invalid_glb_payload';
|
|
1346
|
+
if (message === 'glb_external_dependency_unsupported') {
|
|
1347
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" GLB must embed all buffers and textures instead of referencing external files.`);
|
|
1348
|
+
}
|
|
1349
|
+
else {
|
|
1350
|
+
errors.push(`[${label}] Skipping ${rawName}: owned asset "${ownedName}" primary GLB is invalid.`);
|
|
1351
|
+
}
|
|
1201
1352
|
continue;
|
|
1202
1353
|
}
|
|
1203
1354
|
}
|
|
1204
|
-
if (rejectLegacyShopPriceCoinsField(
|
|
1355
|
+
if (rejectLegacyShopPriceCoinsField(owned, errors, `[${label}] Owned asset "${ownedName}"`)) {
|
|
1205
1356
|
continue;
|
|
1206
1357
|
}
|
|
1207
|
-
|
|
1208
|
-
kind: '
|
|
1358
|
+
ownedAssets.push({
|
|
1359
|
+
kind: 'owned-asset',
|
|
1209
1360
|
appName: rawName,
|
|
1210
|
-
name:
|
|
1361
|
+
name: ownedName,
|
|
1362
|
+
runtimeKey,
|
|
1211
1363
|
cataloguePath: label,
|
|
1212
1364
|
category,
|
|
1213
1365
|
subcategory,
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1366
|
+
assetSpec,
|
|
1367
|
+
format: ownedFormat,
|
|
1368
|
+
visibility: normalizeAssetVisibilityValue(owned?.visibility, errors, `${label} owned asset "${ownedName}"`),
|
|
1369
|
+
shopListed: typeof owned?.shopListed === 'boolean' ? owned.shopListed : undefined,
|
|
1370
|
+
shopPriceCredits: Number.isInteger(owned?.shopPriceCredits) ? Number(owned.shopPriceCredits) : undefined,
|
|
1218
1371
|
files,
|
|
1219
1372
|
filePaths,
|
|
1220
1373
|
});
|
|
1221
1374
|
}
|
|
1375
|
+
const runtimeValidationErrorCount = errors.length;
|
|
1376
|
+
const seenOwnedAssetNames = new Set();
|
|
1377
|
+
const seenOwnedRuntimeKeys = new Set();
|
|
1378
|
+
for (const ownedAsset of ownedAssets) {
|
|
1379
|
+
if (seenOwnedAssetNames.has(ownedAsset.name)) {
|
|
1380
|
+
errors.push(`[${label}] App "${rawName}" ownedAssets contains duplicate name "${ownedAsset.name}".`);
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1383
|
+
seenOwnedAssetNames.add(ownedAsset.name);
|
|
1384
|
+
if (!ownedAsset.runtimeKey) {
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
if (seenOwnedRuntimeKeys.has(ownedAsset.runtimeKey)) {
|
|
1388
|
+
errors.push(`[${label}] App "${rawName}" ownedAssets contains duplicate runtimeKey "${ownedAsset.runtimeKey}".`);
|
|
1389
|
+
continue;
|
|
1390
|
+
}
|
|
1391
|
+
seenOwnedRuntimeKeys.add(ownedAsset.runtimeKey);
|
|
1392
|
+
}
|
|
1393
|
+
for (const dependency of usesAssets) {
|
|
1394
|
+
if (!dependency.runtimeKey) {
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
if (seenOwnedRuntimeKeys.has(dependency.runtimeKey)) {
|
|
1398
|
+
errors.push(`[${label}] App "${rawName}" reuses runtimeKey "${dependency.runtimeKey}" across ownedAssets and uses.assets.`);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
if (errors.length > runtimeValidationErrorCount) {
|
|
1402
|
+
continue;
|
|
1403
|
+
}
|
|
1222
1404
|
tasks.push({
|
|
1223
1405
|
kind: 'app',
|
|
1224
1406
|
name: rawName,
|
|
@@ -1257,7 +1439,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1257
1439
|
achievements,
|
|
1258
1440
|
leaderboards,
|
|
1259
1441
|
remix,
|
|
1260
|
-
|
|
1442
|
+
ownedAssets,
|
|
1261
1443
|
assetSpecSupport,
|
|
1262
1444
|
uses: {
|
|
1263
1445
|
assets: usesAssets,
|
|
@@ -1390,11 +1572,25 @@ function buildAssetSpecTasks(catalogues) {
|
|
|
1390
1572
|
}
|
|
1391
1573
|
return { tasks, warnings, errors };
|
|
1392
1574
|
}
|
|
1393
|
-
function buildAssetTasks(catalogues,
|
|
1575
|
+
function buildAssetTasks(catalogues, assetSpecTasks) {
|
|
1394
1576
|
const tasks = [];
|
|
1395
1577
|
const warnings = [];
|
|
1396
1578
|
const errors = [];
|
|
1397
1579
|
const seen = new Map();
|
|
1580
|
+
const exactAssetSpecTaskByRef = new Map();
|
|
1581
|
+
const uniqueAssetSpecTaskByNameVersion = new Map();
|
|
1582
|
+
for (const task of assetSpecTasks) {
|
|
1583
|
+
if (task.username) {
|
|
1584
|
+
exactAssetSpecTaskByRef.set(`asset-spec:${task.username}/${task.name}@${task.version}`, task);
|
|
1585
|
+
}
|
|
1586
|
+
const nameVersionKey = `${task.name}@${task.version}`;
|
|
1587
|
+
if (!uniqueAssetSpecTaskByNameVersion.has(nameVersionKey)) {
|
|
1588
|
+
uniqueAssetSpecTaskByNameVersion.set(nameVersionKey, task);
|
|
1589
|
+
}
|
|
1590
|
+
else {
|
|
1591
|
+
uniqueAssetSpecTaskByNameVersion.set(nameVersionKey, null);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1398
1594
|
for (const file of catalogues) {
|
|
1399
1595
|
const label = file.relativePath || 'catalogue.json';
|
|
1400
1596
|
const rawAssets = Array.isArray(file.data.assets) ? file.data.assets : [];
|
|
@@ -1520,6 +1716,22 @@ function buildAssetTasks(catalogues, _assetSpecTasks) {
|
|
|
1520
1716
|
if (rejectLegacyShopPriceCoinsField(entry, errors, `[${label}] Asset "${name}"`)) {
|
|
1521
1717
|
continue;
|
|
1522
1718
|
}
|
|
1719
|
+
let assetSpecContract;
|
|
1720
|
+
if (assetSpec) {
|
|
1721
|
+
const directAssetSpecTask = exactAssetSpecTaskByRef.get(assetSpec);
|
|
1722
|
+
if (directAssetSpecTask) {
|
|
1723
|
+
assetSpecContract = directAssetSpecTask.contract;
|
|
1724
|
+
}
|
|
1725
|
+
else {
|
|
1726
|
+
const parsedAssetSpec = (0, types_1.parseAssetSpecVersionRef)(assetSpec);
|
|
1727
|
+
if (parsedAssetSpec) {
|
|
1728
|
+
const fallbackAssetSpecTask = uniqueAssetSpecTaskByNameVersion.get(`${parsedAssetSpec.name}@${parsedAssetSpec.version}`);
|
|
1729
|
+
if (fallbackAssetSpecTask) {
|
|
1730
|
+
assetSpecContract = fallbackAssetSpecTask.contract;
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1523
1735
|
tasks.push({
|
|
1524
1736
|
kind: 'asset',
|
|
1525
1737
|
name,
|
|
@@ -1537,6 +1749,7 @@ function buildAssetTasks(catalogues, _assetSpecTasks) {
|
|
|
1537
1749
|
shopPriceCredits: Number.isInteger(entry.shopPriceCredits) ? Number(entry.shopPriceCredits) : undefined,
|
|
1538
1750
|
files,
|
|
1539
1751
|
filePaths,
|
|
1752
|
+
assetSpecContract,
|
|
1540
1753
|
relations,
|
|
1541
1754
|
});
|
|
1542
1755
|
}
|
|
@@ -1577,6 +1790,110 @@ function buildAssetPackTasks(catalogues) {
|
|
|
1577
1790
|
const assets = Array.isArray(entry.assets)
|
|
1578
1791
|
? entry.assets.filter((value) => typeof value === 'string' && value.trim().length > 0).map((value) => value.trim())
|
|
1579
1792
|
: [];
|
|
1793
|
+
const ownedAssets = [];
|
|
1794
|
+
const rawOwnedAssets = Array.isArray(entry.ownedAssets)
|
|
1795
|
+
? entry.ownedAssets
|
|
1796
|
+
: [];
|
|
1797
|
+
for (let ownedIndex = 0; ownedIndex < rawOwnedAssets.length; ownedIndex++) {
|
|
1798
|
+
const owned = rawOwnedAssets[ownedIndex];
|
|
1799
|
+
const ownedName = typeof owned?.name === 'string' ? owned.name.trim() : '';
|
|
1800
|
+
if (!ownedName) {
|
|
1801
|
+
errors.push(`[${label}] Skipping asset pack "${name}": ownedAssets[${ownedIndex}] is missing a name.`);
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
if (typeof owned?.runtimeKey === 'string' && owned.runtimeKey.trim().length > 0) {
|
|
1805
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" must not define runtimeKey.`);
|
|
1806
|
+
continue;
|
|
1807
|
+
}
|
|
1808
|
+
const category = normalizeAssetCategoryValue(owned?.category, errors, `[${label}] Skipping asset pack "${name}": owned asset "${ownedName}"`);
|
|
1809
|
+
if (!category) {
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1812
|
+
const subcategory = normalizeAssetSubcategoryValue(owned?.subcategory, category, errors, `[${label}] Skipping asset pack "${name}": owned asset "${ownedName}"`);
|
|
1813
|
+
if (subcategory === null && category !== 'CUSTOM') {
|
|
1814
|
+
continue;
|
|
1815
|
+
}
|
|
1816
|
+
const fileEntries = owned?.files && typeof owned.files === 'object' && !Array.isArray(owned.files)
|
|
1817
|
+
? owned.files
|
|
1818
|
+
: null;
|
|
1819
|
+
const assetSpec = (0, assetSpecs_1.normalizeAssetSpecVersionRef)(owned?.assetSpec, errors, `[${label}] Asset pack "${name}" owned asset "${ownedName}"`);
|
|
1820
|
+
const ownedFormat = typeof owned?.format === 'string' && owned.format.trim().length > 0
|
|
1821
|
+
? owned.format.trim().toUpperCase()
|
|
1822
|
+
: undefined;
|
|
1823
|
+
const generatedModel3DFormat = subcategory
|
|
1824
|
+
? inferGeneratedModel3DFormat(category, subcategory, ownedFormat, fileEntries)
|
|
1825
|
+
: null;
|
|
1826
|
+
const generatedModel3DRoles = generatedModel3DFormat ? getGeneratedModel3DFileRoles(generatedModel3DFormat) : null;
|
|
1827
|
+
if (!fileEntries || Object.keys(fileEntries).length === 0) {
|
|
1828
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" must define files.`);
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
const files = {};
|
|
1832
|
+
const filePaths = {};
|
|
1833
|
+
let ownedAssetHasError = false;
|
|
1834
|
+
for (const [role, fileValue] of Object.entries(fileEntries)) {
|
|
1835
|
+
if (typeof fileValue !== 'string' || !fileValue.trim()) {
|
|
1836
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" file role "${role}" must be a non-empty string path.`);
|
|
1837
|
+
ownedAssetHasError = true;
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
const relativeOwnedPath = fileValue.trim();
|
|
1841
|
+
const absoluteOwnedPath = (0, node_path_1.resolve)(file.directory, relativeOwnedPath);
|
|
1842
|
+
const normalizedRole = normalizeFileRole(role);
|
|
1843
|
+
const allowMissingGenerated = Boolean(generatedModel3DRoles?.generated.has(normalizedRole));
|
|
1844
|
+
if (!(0, node_fs_1.existsSync)(absoluteOwnedPath) || !(0, node_fs_1.statSync)(absoluteOwnedPath).isFile()) {
|
|
1845
|
+
if (allowMissingGenerated) {
|
|
1846
|
+
files[role] = relativeOwnedPath.replace(/\\/g, '/');
|
|
1847
|
+
filePaths[role] = absoluteOwnedPath;
|
|
1848
|
+
continue;
|
|
1849
|
+
}
|
|
1850
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" file not found at ${absoluteOwnedPath}.`);
|
|
1851
|
+
ownedAssetHasError = true;
|
|
1852
|
+
continue;
|
|
1853
|
+
}
|
|
1854
|
+
files[role] = relativeOwnedPath.replace(/\\/g, '/');
|
|
1855
|
+
filePaths[role] = absoluteOwnedPath;
|
|
1856
|
+
}
|
|
1857
|
+
if (ownedAssetHasError) {
|
|
1858
|
+
continue;
|
|
1859
|
+
}
|
|
1860
|
+
if (generatedModel3DRoles) {
|
|
1861
|
+
const normalizedRoles = new Set(Object.keys(files).map((role) => normalizeFileRole(role)));
|
|
1862
|
+
const missingRoles = generatedModel3DRoles.required.filter((role) => !normalizedRoles.has(role));
|
|
1863
|
+
if (missingRoles.length > 0) {
|
|
1864
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" with subcategory=${subcategory} must define files.${missingRoles.join(' and files.')}.`);
|
|
1865
|
+
continue;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
if (category === 'SPRITESHEET') {
|
|
1869
|
+
const hasAtlas = Object.prototype.hasOwnProperty.call(files, 'atlas');
|
|
1870
|
+
const hasManifest = Object.prototype.hasOwnProperty.call(files, 'manifest');
|
|
1871
|
+
if (!hasAtlas || !hasManifest) {
|
|
1872
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" with category=SPRITESHEET must define files.atlas and files.manifest.`);
|
|
1873
|
+
continue;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
if (category === 'AUDIO' && !Object.prototype.hasOwnProperty.call(files, 'primary')) {
|
|
1877
|
+
errors.push(`[${label}] Skipping asset pack "${name}": owned asset "${ownedName}" with category=AUDIO must define files.primary.`);
|
|
1878
|
+
continue;
|
|
1879
|
+
}
|
|
1880
|
+
if (rejectLegacyShopPriceCoinsField(owned, errors, `[${label}] Asset pack "${name}" owned asset "${ownedName}"`)) {
|
|
1881
|
+
continue;
|
|
1882
|
+
}
|
|
1883
|
+
ownedAssets.push({
|
|
1884
|
+
name: ownedName,
|
|
1885
|
+
cataloguePath: label,
|
|
1886
|
+
category,
|
|
1887
|
+
subcategory,
|
|
1888
|
+
assetSpec,
|
|
1889
|
+
format: ownedFormat,
|
|
1890
|
+
visibility: normalizeAssetVisibilityValue(owned?.visibility, errors, `${label} asset pack "${name}" owned asset "${ownedName}"`),
|
|
1891
|
+
shopListed: typeof owned?.shopListed === 'boolean' ? owned.shopListed : undefined,
|
|
1892
|
+
shopPriceCredits: Number.isInteger(owned?.shopPriceCredits) ? Number(owned.shopPriceCredits) : undefined,
|
|
1893
|
+
files,
|
|
1894
|
+
filePaths,
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1580
1897
|
let hostingMode;
|
|
1581
1898
|
const rawHostingMode = typeof entry.hostingMode === 'string' ? entry.hostingMode.trim().toUpperCase() : '';
|
|
1582
1899
|
if (rawHostingMode) {
|
|
@@ -1611,7 +1928,7 @@ function buildAssetPackTasks(catalogues) {
|
|
|
1611
1928
|
if (externalUrl && hostingMode !== 'EXTERNAL') {
|
|
1612
1929
|
hostingMode = 'EXTERNAL';
|
|
1613
1930
|
}
|
|
1614
|
-
if (assets.length === 0 && hostingMode !== 'EXTERNAL') {
|
|
1931
|
+
if (assets.length === 0 && ownedAssets.length === 0 && hostingMode !== 'EXTERNAL') {
|
|
1615
1932
|
errors.push(`[${label}] Asset pack "${name}" must reference at least one asset.`);
|
|
1616
1933
|
continue;
|
|
1617
1934
|
}
|
|
@@ -1797,6 +2114,7 @@ function buildAssetPackTasks(catalogues) {
|
|
|
1797
2114
|
username,
|
|
1798
2115
|
remix,
|
|
1799
2116
|
assets,
|
|
2117
|
+
ownedAssets,
|
|
1800
2118
|
hostingMode,
|
|
1801
2119
|
externalUrl,
|
|
1802
2120
|
downloadUrl,
|
|
@@ -1917,7 +2235,7 @@ function resolveCatalogueEntries(rootDir, options = {}) {
|
|
|
1917
2235
|
apps: [],
|
|
1918
2236
|
assetSpecs: [],
|
|
1919
2237
|
assets: [],
|
|
1920
|
-
|
|
2238
|
+
ownedAssets: [],
|
|
1921
2239
|
assetPacks: [],
|
|
1922
2240
|
warnings: [],
|
|
1923
2241
|
errors: discoveryErrors,
|
|
@@ -1930,7 +2248,7 @@ function resolveCatalogueEntries(rootDir, options = {}) {
|
|
|
1930
2248
|
apps: [],
|
|
1931
2249
|
assetSpecs: [],
|
|
1932
2250
|
assets: [],
|
|
1933
|
-
|
|
2251
|
+
ownedAssets: [],
|
|
1934
2252
|
assetPacks: [],
|
|
1935
2253
|
warnings: [],
|
|
1936
2254
|
errors: [
|
|
@@ -1942,14 +2260,14 @@ function resolveCatalogueEntries(rootDir, options = {}) {
|
|
|
1942
2260
|
const { tasks: assetSpecTasks, warnings: assetSpecWarnings, errors: assetSpecErrors } = buildAssetSpecTasks(files);
|
|
1943
2261
|
const { tasks: assetTasks, warnings: assetWarnings, errors: assetErrors } = buildAssetTasks(files, assetSpecTasks);
|
|
1944
2262
|
const { tasks: assetPackTasks, warnings: assetPackWarnings, errors: assetPackErrors } = buildAssetPackTasks(files);
|
|
1945
|
-
const
|
|
2263
|
+
const ownedAssetTasks = appTasks.flatMap((task) => task.ownedAssets);
|
|
1946
2264
|
const warnings = [...appWarnings, ...assetSpecWarnings, ...assetWarnings, ...assetPackWarnings];
|
|
1947
2265
|
const errors = [...appErrors, ...assetSpecErrors, ...assetErrors, ...assetPackErrors];
|
|
1948
2266
|
return {
|
|
1949
2267
|
apps: appTasks,
|
|
1950
2268
|
assetSpecs: assetSpecTasks,
|
|
1951
2269
|
assets: assetTasks,
|
|
1952
|
-
|
|
2270
|
+
ownedAssets: ownedAssetTasks,
|
|
1953
2271
|
assetPacks: assetPackTasks,
|
|
1954
2272
|
warnings,
|
|
1955
2273
|
errors,
|
package/dist/commandContext.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ApiClient } from '@playdrop/api-client';
|
|
|
2
2
|
import type { AiClient } from '@playdrop/ai-client';
|
|
3
3
|
import { type CliAccountSession, type CliConfig } from './config';
|
|
4
4
|
import { type EnvironmentConfig } from './environment';
|
|
5
|
+
import { type ResolvedWorkspaceAuthConfig } from './workspaceAuth';
|
|
5
6
|
export type EnvironmentContext = {
|
|
6
7
|
client: ApiClient;
|
|
7
8
|
aiClient: AiClient;
|
|
@@ -10,11 +11,14 @@ export type EnvironmentContext = {
|
|
|
10
11
|
token: string;
|
|
11
12
|
config: CliConfig;
|
|
12
13
|
account: CliAccountSession | null;
|
|
14
|
+
workspaceAuth: ResolvedWorkspaceAuthConfig | null;
|
|
13
15
|
};
|
|
14
16
|
type EnvironmentCallback = (ctx: EnvironmentContext) => Promise<void> | void;
|
|
15
|
-
type ResolveAuthenticatedEnvironmentOptions = {
|
|
17
|
+
export type ResolveAuthenticatedEnvironmentOptions = {
|
|
16
18
|
workspacePath?: string;
|
|
17
19
|
};
|
|
20
|
+
export declare function resolveAuthenticatedEnvironmentContext(command: string, actionLabel: string, options?: ResolveAuthenticatedEnvironmentOptions): Promise<EnvironmentContext | null>;
|
|
21
|
+
export declare function resolveOptionalEnvironmentContext(command: string, options?: ResolveAuthenticatedEnvironmentOptions): Promise<EnvironmentContext | null>;
|
|
18
22
|
export declare function withEnvironment(command: string, actionLabel: string, callback: EnvironmentCallback, options?: ResolveAuthenticatedEnvironmentOptions): Promise<void>;
|
|
19
23
|
export declare function withPublicEnvironment(command: string, callback: EnvironmentCallback): Promise<void>;
|
|
20
24
|
export {};
|