gamedev 0.2.2 → 0.2.3
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/app-server/cliAuth.js +24 -224
- package/app-server/commands.js +7 -7
- package/bin/gamedev.mjs +11 -5
- package/build/index.js +9 -52
- package/build/index.js.map +2 -2
- package/build/public/admin.html +2 -2
- package/build/public/index.html +2 -2
- package/docs/App-server.md +3 -2
- package/package.json +1 -1
- package/src/server/cliAuth.js +7 -46
- package/src/server/index.js +2 -6
package/app-server/cliAuth.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import crypto from 'crypto'
|
|
2
|
-
import http from 'http'
|
|
3
1
|
import { spawn } from 'child_process'
|
|
4
2
|
|
|
5
3
|
import { joinUrl, normalizeWorldAdminBaseUrl } from './helpers.js'
|
|
@@ -58,138 +56,6 @@ export async function fetchCliAuthStatus({ worldUrl, authToken }) {
|
|
|
58
56
|
return data
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
function createCallbackServer({ worldId, worldUrl, state, timeoutMs = 10 * 60 * 1000 } = {}) {
|
|
62
|
-
const expectedState = typeof state === 'string' && state.trim() ? state.trim() : crypto.randomUUID()
|
|
63
|
-
let settled = false
|
|
64
|
-
let timeoutId = null
|
|
65
|
-
let server = null
|
|
66
|
-
let startupResolve = null
|
|
67
|
-
let startupReject = null
|
|
68
|
-
let startupState = 'pending'
|
|
69
|
-
const startup = new Promise((resolve, reject) => {
|
|
70
|
-
startupResolve = resolve
|
|
71
|
-
startupReject = reject
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const close = async () => {
|
|
75
|
-
if (!server) return
|
|
76
|
-
const target = server
|
|
77
|
-
server = null
|
|
78
|
-
await new Promise(resolve => target.close(() => resolve()))
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const result = new Promise((resolve, reject) => {
|
|
82
|
-
server = http.createServer(async (req, res) => {
|
|
83
|
-
res.setHeader('Access-Control-Allow-Origin', '*')
|
|
84
|
-
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
85
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
|
|
86
|
-
if (req.method === 'OPTIONS') {
|
|
87
|
-
res.statusCode = 204
|
|
88
|
-
res.end()
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (req.method !== 'POST' || req.url !== '/callback') {
|
|
93
|
-
res.statusCode = 404
|
|
94
|
-
res.end('Not found')
|
|
95
|
-
return
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const chunks = []
|
|
99
|
-
req.on('data', chunk => {
|
|
100
|
-
chunks.push(chunk)
|
|
101
|
-
})
|
|
102
|
-
req.on('error', async error => {
|
|
103
|
-
if (settled) return
|
|
104
|
-
settled = true
|
|
105
|
-
clearTimeout(timeoutId)
|
|
106
|
-
res.statusCode = 500
|
|
107
|
-
res.end(JSON.stringify({ error: 'callback_read_failed' }))
|
|
108
|
-
await close()
|
|
109
|
-
reject(error instanceof Error ? error : createError('callback_read_failed'))
|
|
110
|
-
})
|
|
111
|
-
req.on('end', async () => {
|
|
112
|
-
let payload
|
|
113
|
-
try {
|
|
114
|
-
payload = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}')
|
|
115
|
-
} catch {
|
|
116
|
-
res.statusCode = 400
|
|
117
|
-
res.end(JSON.stringify({ error: 'invalid_payload' }))
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const receivedState = typeof payload?.state === 'string' ? payload.state.trim() : ''
|
|
122
|
-
const authToken = typeof payload?.authToken === 'string' ? payload.authToken.trim() : ''
|
|
123
|
-
const receivedWorldId = typeof payload?.worldId === 'string' ? payload.worldId.trim() : ''
|
|
124
|
-
const receivedWorldUrl = typeof payload?.worldUrl === 'string' ? payload.worldUrl.trim() : ''
|
|
125
|
-
|
|
126
|
-
if (!authToken || !receivedState || receivedState !== expectedState) {
|
|
127
|
-
res.statusCode = 400
|
|
128
|
-
res.end(JSON.stringify({ error: 'invalid_callback_state' }))
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
if (worldId && receivedWorldId && receivedWorldId !== worldId) {
|
|
132
|
-
res.statusCode = 409
|
|
133
|
-
res.end(JSON.stringify({ error: 'world_id_mismatch' }))
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
if (worldUrl && receivedWorldUrl && normalizeWorldAdminBaseUrl(receivedWorldUrl) !== normalizeWorldAdminBaseUrl(worldUrl)) {
|
|
137
|
-
res.statusCode = 409
|
|
138
|
-
res.end(JSON.stringify({ error: 'world_url_mismatch' }))
|
|
139
|
-
return
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
settled = true
|
|
143
|
-
clearTimeout(timeoutId)
|
|
144
|
-
res.statusCode = 200
|
|
145
|
-
res.setHeader('Content-Type', 'application/json')
|
|
146
|
-
res.end(JSON.stringify({ ok: true }))
|
|
147
|
-
await close()
|
|
148
|
-
resolve(payload)
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
server.listen(0, '127.0.0.1', () => {
|
|
153
|
-
if (startupState === 'pending') {
|
|
154
|
-
startupState = 'ready'
|
|
155
|
-
startupResolve()
|
|
156
|
-
}
|
|
157
|
-
timeoutId = setTimeout(async () => {
|
|
158
|
-
if (settled) return
|
|
159
|
-
settled = true
|
|
160
|
-
await close()
|
|
161
|
-
reject(createError('auth_timeout', 'Timed out waiting for browser authentication'))
|
|
162
|
-
}, timeoutMs)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
server.on('error', async error => {
|
|
166
|
-
if (startupState === 'pending') {
|
|
167
|
-
startupState = 'failed'
|
|
168
|
-
startupReject(error instanceof Error ? error : createError('callback_server_failed'))
|
|
169
|
-
}
|
|
170
|
-
if (settled) return
|
|
171
|
-
settled = true
|
|
172
|
-
clearTimeout(timeoutId)
|
|
173
|
-
await close()
|
|
174
|
-
reject(error instanceof Error ? error : createError('callback_server_failed'))
|
|
175
|
-
})
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
state: expectedState,
|
|
180
|
-
async getCallbackUrl() {
|
|
181
|
-
await startup
|
|
182
|
-
const address = server.address()
|
|
183
|
-
if (!address || typeof address === 'string') {
|
|
184
|
-
throw createError('callback_server_failed')
|
|
185
|
-
}
|
|
186
|
-
return `http://127.0.0.1:${address.port}/callback`
|
|
187
|
-
},
|
|
188
|
-
result,
|
|
189
|
-
close,
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
59
|
async function launchBrowser(url) {
|
|
194
60
|
const commands =
|
|
195
61
|
process.platform === 'darwin'
|
|
@@ -218,9 +84,7 @@ async function launchBrowser(url) {
|
|
|
218
84
|
export function buildCliAuthUrl({
|
|
219
85
|
worldUrl,
|
|
220
86
|
worldId,
|
|
221
|
-
callbackUrl,
|
|
222
87
|
sessionId,
|
|
223
|
-
state,
|
|
224
88
|
requiredCapability = 'builder',
|
|
225
89
|
} = {}) {
|
|
226
90
|
const normalizedWorldUrl = normalizeWorldAdminBaseUrl(worldUrl)
|
|
@@ -228,10 +92,8 @@ export function buildCliAuthUrl({
|
|
|
228
92
|
throw createError('invalid_world_url', 'Invalid world URL')
|
|
229
93
|
}
|
|
230
94
|
const url = new URL(joinUrl(normalizedWorldUrl, '/auth/cli'))
|
|
231
|
-
if (callbackUrl) url.searchParams.set('callback', callbackUrl)
|
|
232
95
|
if (sessionId) url.searchParams.set('session', sessionId)
|
|
233
96
|
if (worldId) url.searchParams.set('worldId', worldId)
|
|
234
|
-
if (state) url.searchParams.set('state', state)
|
|
235
97
|
url.searchParams.set('required', normalizeCapability(requiredCapability))
|
|
236
98
|
return url.toString()
|
|
237
99
|
}
|
|
@@ -254,12 +116,6 @@ async function createRemoteCliAuthSession({ worldUrl, worldId, requiredCapabilit
|
|
|
254
116
|
})
|
|
255
117
|
const data = await response.json().catch(() => null)
|
|
256
118
|
if (!response.ok) {
|
|
257
|
-
if (response.status === 404 || response.status === 405) {
|
|
258
|
-
throw createError('cli_auth_session_unsupported', 'World does not support server-mediated CLI auth sessions', {
|
|
259
|
-
status: response.status,
|
|
260
|
-
data,
|
|
261
|
-
})
|
|
262
|
-
}
|
|
263
119
|
throw createError(
|
|
264
120
|
data?.error || `session_create_failed:${response.status}`,
|
|
265
121
|
data?.message || 'Failed to create CLI auth session',
|
|
@@ -333,7 +189,7 @@ async function openCliAuthUrl(authUrl, { log = console } = {}) {
|
|
|
333
189
|
log?.log?.('Opening browser for world auth...')
|
|
334
190
|
}
|
|
335
191
|
|
|
336
|
-
async function
|
|
192
|
+
export async function runBrowserCliAuth({
|
|
337
193
|
rootDir = process.cwd(),
|
|
338
194
|
worldUrl,
|
|
339
195
|
worldId,
|
|
@@ -341,89 +197,33 @@ async function runLoopbackBrowserCliAuth({
|
|
|
341
197
|
timeoutMs,
|
|
342
198
|
log = console,
|
|
343
199
|
} = {}) {
|
|
344
|
-
const
|
|
200
|
+
const session = await createRemoteCliAuthSession({
|
|
201
|
+
worldUrl,
|
|
202
|
+
worldId,
|
|
203
|
+
requiredCapability,
|
|
204
|
+
})
|
|
205
|
+
const authUrl = buildCliAuthUrl({
|
|
206
|
+
worldUrl,
|
|
345
207
|
worldId,
|
|
208
|
+
sessionId: session.sessionId,
|
|
209
|
+
requiredCapability,
|
|
210
|
+
})
|
|
211
|
+
await openCliAuthUrl(authUrl, { log })
|
|
212
|
+
const payload = await waitForRemoteCliAuthSession({
|
|
346
213
|
worldUrl,
|
|
214
|
+
sessionId: session.sessionId,
|
|
347
215
|
timeoutMs,
|
|
348
216
|
})
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
await openCliAuthUrl(authUrl, { log })
|
|
360
|
-
|
|
361
|
-
const payload = await callback.result
|
|
362
|
-
const entry = writeProjectAuthEntry(rootDir, {
|
|
363
|
-
worldUrl: payload.worldUrl || worldUrl,
|
|
364
|
-
worldId: payload.worldId || worldId,
|
|
365
|
-
authToken: payload.authToken,
|
|
366
|
-
userId: payload?.user?.id || null,
|
|
367
|
-
userName: payload?.user?.name || null,
|
|
368
|
-
})
|
|
369
|
-
return {
|
|
370
|
-
entry,
|
|
371
|
-
capabilities: payload?.capabilities || null,
|
|
372
|
-
}
|
|
373
|
-
} finally {
|
|
374
|
-
await callback.close().catch(() => {})
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
export async function runBrowserCliAuth({
|
|
379
|
-
rootDir = process.cwd(),
|
|
380
|
-
worldUrl,
|
|
381
|
-
worldId,
|
|
382
|
-
requiredCapability = 'builder',
|
|
383
|
-
timeoutMs,
|
|
384
|
-
log = console,
|
|
385
|
-
} = {}) {
|
|
386
|
-
try {
|
|
387
|
-
const session = await createRemoteCliAuthSession({
|
|
388
|
-
worldUrl,
|
|
389
|
-
worldId,
|
|
390
|
-
requiredCapability,
|
|
391
|
-
})
|
|
392
|
-
const authUrl = buildCliAuthUrl({
|
|
393
|
-
worldUrl,
|
|
394
|
-
worldId,
|
|
395
|
-
sessionId: session.sessionId,
|
|
396
|
-
requiredCapability,
|
|
397
|
-
})
|
|
398
|
-
await openCliAuthUrl(authUrl, { log })
|
|
399
|
-
const payload = await waitForRemoteCliAuthSession({
|
|
400
|
-
worldUrl,
|
|
401
|
-
sessionId: session.sessionId,
|
|
402
|
-
timeoutMs,
|
|
403
|
-
})
|
|
404
|
-
const entry = writeProjectAuthEntry(rootDir, {
|
|
405
|
-
worldUrl: payload.worldUrl || worldUrl,
|
|
406
|
-
worldId: payload.worldId || worldId,
|
|
407
|
-
authToken: payload.authToken,
|
|
408
|
-
userId: payload?.user?.id || null,
|
|
409
|
-
userName: payload?.user?.name || null,
|
|
410
|
-
})
|
|
411
|
-
return {
|
|
412
|
-
entry,
|
|
413
|
-
capabilities: payload?.capabilities || null,
|
|
414
|
-
}
|
|
415
|
-
} catch (error) {
|
|
416
|
-
if (error?.code === 'cli_auth_session_unsupported') {
|
|
417
|
-
return runLoopbackBrowserCliAuth({
|
|
418
|
-
rootDir,
|
|
419
|
-
worldUrl,
|
|
420
|
-
worldId,
|
|
421
|
-
requiredCapability,
|
|
422
|
-
timeoutMs,
|
|
423
|
-
log,
|
|
424
|
-
})
|
|
425
|
-
}
|
|
426
|
-
throw error
|
|
217
|
+
const entry = writeProjectAuthEntry(rootDir, {
|
|
218
|
+
worldUrl: payload.worldUrl || worldUrl,
|
|
219
|
+
worldId: payload.worldId || worldId,
|
|
220
|
+
authToken: payload.authToken,
|
|
221
|
+
userId: payload?.user?.id || null,
|
|
222
|
+
userName: payload?.user?.name || null,
|
|
223
|
+
})
|
|
224
|
+
return {
|
|
225
|
+
entry,
|
|
226
|
+
capabilities: payload?.capabilities || null,
|
|
427
227
|
}
|
|
428
228
|
}
|
|
429
229
|
|
package/app-server/commands.js
CHANGED
|
@@ -260,14 +260,14 @@ export class HyperfyCLI {
|
|
|
260
260
|
return process.env.HYPERFY_TARGET_CONFIRM === 'true'
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
async _connectAdminClient() {
|
|
263
|
+
async _connectAdminClient({ requiredCapability = 'builder' } = {}) {
|
|
264
264
|
this._requireWorldUrl()
|
|
265
265
|
this._requireWorldId()
|
|
266
266
|
const auth = await ensureProjectAuth({
|
|
267
267
|
rootDir: this.rootDir,
|
|
268
268
|
worldUrl: this.worldUrl,
|
|
269
269
|
worldId: this.worldId,
|
|
270
|
-
requiredCapability
|
|
270
|
+
requiredCapability,
|
|
271
271
|
interactive: process.stdin.isTTY,
|
|
272
272
|
log: console,
|
|
273
273
|
})
|
|
@@ -411,7 +411,7 @@ export class HyperfyCLI {
|
|
|
411
411
|
|
|
412
412
|
console.log(`🚀 Deploying app: ${appName}`)
|
|
413
413
|
|
|
414
|
-
const server = await this._connectAdminClient()
|
|
414
|
+
const server = await this._connectAdminClient({ requiredCapability: 'deploy' })
|
|
415
415
|
try {
|
|
416
416
|
if (!options.dryRun && !options.yes && this._shouldConfirmDeployTarget()) {
|
|
417
417
|
const target = process.env.HYPERFY_TARGET ? ` "${process.env.HYPERFY_TARGET}"` : ''
|
|
@@ -452,7 +452,7 @@ export class HyperfyCLI {
|
|
|
452
452
|
|
|
453
453
|
async rollback(snapshotId) {
|
|
454
454
|
console.log(`⏪ Rolling back deploy snapshot...`)
|
|
455
|
-
const server = await this._connectAdminClient()
|
|
455
|
+
const server = await this._connectAdminClient({ requiredCapability: 'deploy' })
|
|
456
456
|
try {
|
|
457
457
|
const owner = `hyperfy-cli:${process.env.HYPERFY_TARGET || 'default'}:${process.pid}`
|
|
458
458
|
const lock = await server.client.acquireDeployLock({ owner })
|
|
@@ -486,7 +486,7 @@ export class HyperfyCLI {
|
|
|
486
486
|
|
|
487
487
|
async status() {
|
|
488
488
|
console.log(`📊 Admin Status`)
|
|
489
|
-
const server = await this._connectAdminClient()
|
|
489
|
+
const server = await this._connectAdminClient({ requiredCapability: 'builder' })
|
|
490
490
|
try {
|
|
491
491
|
const snapshot = await server.client.getSnapshot()
|
|
492
492
|
const blueprints = Array.isArray(snapshot?.blueprints) ? snapshot.blueprints.length : 0
|
|
@@ -572,7 +572,7 @@ export class HyperfyCLI {
|
|
|
572
572
|
return false
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
-
const server = await this._connectAdminClient()
|
|
575
|
+
const server = await this._connectAdminClient({ requiredCapability: 'deploy' })
|
|
576
576
|
try {
|
|
577
577
|
const result = await server.resolveSyncConflict(id, { use })
|
|
578
578
|
if (result?.alreadyResolved) {
|
|
@@ -592,7 +592,7 @@ export class HyperfyCLI {
|
|
|
592
592
|
}
|
|
593
593
|
|
|
594
594
|
async syncResolveInteractive() {
|
|
595
|
-
const server = await this._connectAdminClient()
|
|
595
|
+
const server = await this._connectAdminClient({ requiredCapability: 'deploy' })
|
|
596
596
|
try {
|
|
597
597
|
const summary = await server.promptAndResolveSyncConflicts()
|
|
598
598
|
if (!summary?.prompted && summary?.remaining > 0) {
|
package/bin/gamedev.mjs
CHANGED
|
@@ -486,7 +486,7 @@ async function startCommand(args = []) {
|
|
|
486
486
|
rootDir: projectDir,
|
|
487
487
|
worldUrl: env.WORLD_URL,
|
|
488
488
|
worldId: env.WORLD_ID,
|
|
489
|
-
requiredCapability: '
|
|
489
|
+
requiredCapability: 'deploy',
|
|
490
490
|
interactive: process.stdin.isTTY,
|
|
491
491
|
log: console,
|
|
492
492
|
})
|
|
@@ -584,7 +584,7 @@ async function appServerCommand(args = []) {
|
|
|
584
584
|
rootDir: projectDir,
|
|
585
585
|
worldUrl: env.WORLD_URL,
|
|
586
586
|
worldId: env.WORLD_ID,
|
|
587
|
-
requiredCapability: '
|
|
587
|
+
requiredCapability: 'deploy',
|
|
588
588
|
interactive: process.stdin.isTTY,
|
|
589
589
|
log: console,
|
|
590
590
|
})
|
|
@@ -848,12 +848,12 @@ async function syncCommand(args) {
|
|
|
848
848
|
return runSyncCommand({ command, args: commandArgs, rootDir: projectDir, helpPrefix: 'gamedev sync' })
|
|
849
849
|
}
|
|
850
850
|
|
|
851
|
-
async function connectAdminServer({ worldUrl, worldId, rootDir }) {
|
|
851
|
+
async function connectAdminServer({ worldUrl, worldId, rootDir, requiredCapability = 'builder' }) {
|
|
852
852
|
const auth = await ensureProjectAuth({
|
|
853
853
|
rootDir,
|
|
854
854
|
worldUrl,
|
|
855
855
|
worldId,
|
|
856
|
-
requiredCapability
|
|
856
|
+
requiredCapability,
|
|
857
857
|
interactive: process.stdin.isTTY,
|
|
858
858
|
log: console,
|
|
859
859
|
})
|
|
@@ -976,12 +976,18 @@ async function worldCommand(args) {
|
|
|
976
976
|
|
|
977
977
|
let server
|
|
978
978
|
try {
|
|
979
|
-
server = await connectAdminServer({ worldUrl, worldId, rootDir: projectDir })
|
|
980
979
|
if (action === 'export') {
|
|
980
|
+
server = await connectAdminServer({ worldUrl, worldId, rootDir: projectDir })
|
|
981
981
|
const includeBuiltScripts = actionArgs.includes('--include-built-scripts')
|
|
982
982
|
await server.exportWorldToDisk(undefined, { includeBuiltScripts })
|
|
983
983
|
console.log('✅ World export complete')
|
|
984
984
|
} else {
|
|
985
|
+
server = await connectAdminServer({
|
|
986
|
+
worldUrl,
|
|
987
|
+
worldId,
|
|
988
|
+
rootDir: projectDir,
|
|
989
|
+
requiredCapability: 'deploy',
|
|
990
|
+
})
|
|
985
991
|
await server.importWorldFromDisk()
|
|
986
992
|
console.log('✅ World import complete')
|
|
987
993
|
}
|
package/build/index.js
CHANGED
|
@@ -63145,17 +63145,13 @@ async function createStandaloneGuestSession({
|
|
|
63145
63145
|
};
|
|
63146
63146
|
}
|
|
63147
63147
|
function buildCliAuthPage({
|
|
63148
|
-
callbackUrl,
|
|
63149
63148
|
sessionId,
|
|
63150
|
-
state,
|
|
63151
63149
|
worldId,
|
|
63152
63150
|
requiredCapability = "builder",
|
|
63153
63151
|
publicAuthUrl = null
|
|
63154
63152
|
} = {}) {
|
|
63155
63153
|
const config = JSON.stringify({
|
|
63156
|
-
callbackUrl: normalizeString2(callbackUrl),
|
|
63157
63154
|
sessionId: normalizeString2(sessionId),
|
|
63158
|
-
state: normalizeString2(state),
|
|
63159
63155
|
worldId: normalizeString2(worldId),
|
|
63160
63156
|
requiredCapability: normalizeString2(requiredCapability) || "builder",
|
|
63161
63157
|
publicAuthUrl: hasValue2(publicAuthUrl) ? publicAuthUrl.trim() : null
|
|
@@ -63544,18 +63540,6 @@ function buildCliAuthPage({
|
|
|
63544
63540
|
return !!capabilities?.builder
|
|
63545
63541
|
}
|
|
63546
63542
|
|
|
63547
|
-
function validateCallbackUrl(value) {
|
|
63548
|
-
try {
|
|
63549
|
-
const parsed = new URL(value)
|
|
63550
|
-
const hostname = parsed.hostname
|
|
63551
|
-
if (!hostname) return null
|
|
63552
|
-
if (hostname !== '127.0.0.1' && hostname !== 'localhost' && hostname !== '::1') return null
|
|
63553
|
-
return parsed.toString()
|
|
63554
|
-
} catch {
|
|
63555
|
-
return null
|
|
63556
|
-
}
|
|
63557
|
-
}
|
|
63558
|
-
|
|
63559
63543
|
async function fetchStatus(token) {
|
|
63560
63544
|
const response = await fetch(\`\${apiBaseUrl()}/auth/cli/status\`, {
|
|
63561
63545
|
headers: {
|
|
@@ -63613,47 +63597,24 @@ function buildCliAuthPage({
|
|
|
63613
63597
|
return token
|
|
63614
63598
|
}
|
|
63615
63599
|
|
|
63616
|
-
async function submitToken(token
|
|
63617
|
-
if (config.sessionId) {
|
|
63618
|
-
|
|
63619
|
-
method: 'POST',
|
|
63620
|
-
headers: {
|
|
63621
|
-
'content-type': 'application/json',
|
|
63622
|
-
accept: 'application/json',
|
|
63623
|
-
},
|
|
63624
|
-
body: JSON.stringify({
|
|
63625
|
-
worldUrl: worldRootUrl(),
|
|
63626
|
-
authToken: token,
|
|
63627
|
-
}),
|
|
63628
|
-
})
|
|
63629
|
-
if (!response.ok) {
|
|
63630
|
-
const payload = await response.json().catch(() => null)
|
|
63631
|
-
throw new Error(payload?.error || 'session_complete_failed')
|
|
63632
|
-
}
|
|
63633
|
-
return
|
|
63600
|
+
async function submitToken(token) {
|
|
63601
|
+
if (!config.sessionId) {
|
|
63602
|
+
throw new Error('Invalid session id')
|
|
63634
63603
|
}
|
|
63635
|
-
|
|
63636
|
-
const callbackUrl = validateCallbackUrl(config.callbackUrl)
|
|
63637
|
-
if (!callbackUrl) {
|
|
63638
|
-
throw new Error('Invalid callback URL')
|
|
63639
|
-
}
|
|
63640
|
-
const response = await fetch(callbackUrl, {
|
|
63604
|
+
const response = await fetch(\`\${apiBaseUrl()}/auth/cli/session/\${encodeURIComponent(config.sessionId)}\`, {
|
|
63641
63605
|
method: 'POST',
|
|
63642
63606
|
headers: {
|
|
63643
63607
|
'content-type': 'application/json',
|
|
63608
|
+
accept: 'application/json',
|
|
63644
63609
|
},
|
|
63645
63610
|
body: JSON.stringify({
|
|
63646
|
-
state: config.state,
|
|
63647
|
-
worldId: status?.worldId || config.worldId || '',
|
|
63648
63611
|
worldUrl: worldRootUrl(),
|
|
63649
63612
|
authToken: token,
|
|
63650
|
-
user: status?.user || null,
|
|
63651
|
-
capabilities: status?.capabilities || null,
|
|
63652
63613
|
}),
|
|
63653
63614
|
})
|
|
63654
63615
|
if (!response.ok) {
|
|
63655
63616
|
const payload = await response.json().catch(() => null)
|
|
63656
|
-
throw new Error(payload?.error || '
|
|
63617
|
+
throw new Error(payload?.error || 'session_complete_failed')
|
|
63657
63618
|
}
|
|
63658
63619
|
}
|
|
63659
63620
|
|
|
@@ -63695,7 +63656,7 @@ function buildCliAuthPage({
|
|
|
63695
63656
|
'success'
|
|
63696
63657
|
)
|
|
63697
63658
|
setHint('Permission confirmed. The CLI is storing this world token locally.', 'success')
|
|
63698
|
-
await submitToken(token
|
|
63659
|
+
await submitToken(token)
|
|
63699
63660
|
clearInterval(polling)
|
|
63700
63661
|
setTimeout(() => {
|
|
63701
63662
|
window.close()
|
|
@@ -65234,21 +65195,17 @@ async function handleCliAuthPage(req, reply) {
|
|
|
65234
65195
|
if (!isRuntimeReady(runtimeState)) {
|
|
65235
65196
|
return sendRuntimeNotReady2(reply, runtimeState, { html: true });
|
|
65236
65197
|
}
|
|
65237
|
-
const callbackUrl = typeof req.query?.callback === "string" ? req.query.callback.trim() : "";
|
|
65238
65198
|
const sessionId = typeof req.query?.session === "string" ? req.query.session.trim() : "";
|
|
65239
|
-
const state = typeof req.query?.state === "string" ? req.query.state.trim() : "";
|
|
65240
65199
|
const worldId = typeof req.query?.worldId === "string" ? req.query.worldId.trim() : resolveBoundWorldId() || "";
|
|
65241
65200
|
const requiredCapability = typeof req.query?.required === "string" ? req.query.required.trim() : "builder";
|
|
65242
|
-
if (!sessionId
|
|
65201
|
+
if (!sessionId) {
|
|
65243
65202
|
return reply.code(400).type("text/html").send(
|
|
65244
|
-
"<!doctype html><html><body>Missing session
|
|
65203
|
+
"<!doctype html><html><body>Missing session.</body></html>"
|
|
65245
65204
|
);
|
|
65246
65205
|
}
|
|
65247
65206
|
reply.type("text/html").send(
|
|
65248
65207
|
buildCliAuthPage({
|
|
65249
|
-
callbackUrl,
|
|
65250
65208
|
sessionId,
|
|
65251
|
-
state,
|
|
65252
65209
|
worldId,
|
|
65253
65210
|
requiredCapability,
|
|
65254
65211
|
publicAuthUrl: process.env.PUBLIC_AUTH_URL || null
|