@playcademy/sandbox 0.1.1 → 0.1.2
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/cli.js +176 -26
- package/dist/server.js +78 -3
- package/package.json +1 -1
- package/dist/utils/port.d.ts +0 -18
- package/dist/utils/port.js +0 -54
package/dist/cli.js
CHANGED
|
@@ -83909,7 +83909,7 @@ var logger = (fn = console.log) => {
|
|
|
83909
83909
|
// package.json
|
|
83910
83910
|
var package_default = {
|
|
83911
83911
|
name: "@playcademy/sandbox",
|
|
83912
|
-
version: "0.1.
|
|
83912
|
+
version: "0.1.1",
|
|
83913
83913
|
description: "Local development server for Playcademy game development",
|
|
83914
83914
|
type: "module",
|
|
83915
83915
|
exports: {
|
|
@@ -117798,7 +117798,10 @@ class CloudflareProvider {
|
|
|
117798
117798
|
namespace: this.config.dispatchNamespace
|
|
117799
117799
|
});
|
|
117800
117800
|
if (deleteBindings) {
|
|
117801
|
-
await
|
|
117801
|
+
await Promise.all([
|
|
117802
|
+
this.deleteD1DatabaseIfExists(deploymentId),
|
|
117803
|
+
this.deleteKVNamespaceIfExists(deploymentId)
|
|
117804
|
+
]);
|
|
117802
117805
|
}
|
|
117803
117806
|
} catch (error2) {
|
|
117804
117807
|
log2.error("[CloudflareProvider] Deletion from dispatch namespace failed", {
|
|
@@ -117849,7 +117852,12 @@ class CloudflareProvider {
|
|
|
117849
117852
|
}
|
|
117850
117853
|
}
|
|
117851
117854
|
for (const kvName of resourceBindings.kv) {
|
|
117852
|
-
|
|
117855
|
+
const namespaceId = await this.ensureKVNamespace(kvName);
|
|
117856
|
+
bindings.push({
|
|
117857
|
+
type: "kv_namespace",
|
|
117858
|
+
name: "KV",
|
|
117859
|
+
namespace_id: namespaceId
|
|
117860
|
+
});
|
|
117853
117861
|
}
|
|
117854
117862
|
for (const r2Name of resourceBindings.r2) {
|
|
117855
117863
|
log2.warn("[CloudflareProvider] R2 bucket binding not yet implemented", { r2Name });
|
|
@@ -117961,6 +117969,73 @@ class CloudflareProvider {
|
|
|
117961
117969
|
throw new Error(`Failed to execute schema: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
117962
117970
|
}
|
|
117963
117971
|
}
|
|
117972
|
+
async ensureKVNamespace(namespaceName) {
|
|
117973
|
+
log2.debug("[CloudflareProvider] Ensuring KV namespace exists", { namespaceName });
|
|
117974
|
+
try {
|
|
117975
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
117976
|
+
account_id: this.config.accountId
|
|
117977
|
+
});
|
|
117978
|
+
for await (const ns of namespaces) {
|
|
117979
|
+
if (ns.title === namespaceName && ns.id) {
|
|
117980
|
+
log2.info("[CloudflareProvider] KV namespace already exists", {
|
|
117981
|
+
namespaceName,
|
|
117982
|
+
namespaceId: ns.id
|
|
117983
|
+
});
|
|
117984
|
+
return ns.id;
|
|
117985
|
+
}
|
|
117986
|
+
}
|
|
117987
|
+
log2.debug("[CloudflareProvider] Creating new KV namespace", { namespaceName });
|
|
117988
|
+
const createResult = await this.client.kv.namespaces.create({
|
|
117989
|
+
account_id: this.config.accountId,
|
|
117990
|
+
title: namespaceName
|
|
117991
|
+
});
|
|
117992
|
+
if (!createResult.id) {
|
|
117993
|
+
throw new Error("KV namespace creation succeeded but no ID returned");
|
|
117994
|
+
}
|
|
117995
|
+
log2.info("[CloudflareProvider] KV namespace created successfully", {
|
|
117996
|
+
namespaceName,
|
|
117997
|
+
namespaceId: createResult.id
|
|
117998
|
+
});
|
|
117999
|
+
return createResult.id;
|
|
118000
|
+
} catch (error2) {
|
|
118001
|
+
log2.error("[CloudflareProvider] Failed to ensure KV namespace", {
|
|
118002
|
+
namespaceName,
|
|
118003
|
+
error: error2
|
|
118004
|
+
});
|
|
118005
|
+
throw new Error(`Failed to ensure KV namespace: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
118006
|
+
}
|
|
118007
|
+
}
|
|
118008
|
+
async deleteKVNamespaceIfExists(namespaceName) {
|
|
118009
|
+
try {
|
|
118010
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
118011
|
+
account_id: this.config.accountId
|
|
118012
|
+
});
|
|
118013
|
+
for await (const ns of namespaces) {
|
|
118014
|
+
if (ns.title === namespaceName && ns.id) {
|
|
118015
|
+
log2.debug("[CloudflareProvider] Deleting KV namespace", {
|
|
118016
|
+
namespaceName,
|
|
118017
|
+
namespaceId: ns.id
|
|
118018
|
+
});
|
|
118019
|
+
await this.client.kv.namespaces.delete(ns.id, {
|
|
118020
|
+
account_id: this.config.accountId
|
|
118021
|
+
});
|
|
118022
|
+
log2.info("[CloudflareProvider] KV namespace deleted successfully", {
|
|
118023
|
+
namespaceName,
|
|
118024
|
+
namespaceId: ns.id
|
|
118025
|
+
});
|
|
118026
|
+
return;
|
|
118027
|
+
}
|
|
118028
|
+
}
|
|
118029
|
+
log2.debug("[CloudflareProvider] KV namespace not found, nothing to delete", {
|
|
118030
|
+
namespaceName
|
|
118031
|
+
});
|
|
118032
|
+
} catch (error2) {
|
|
118033
|
+
log2.warn("[CloudflareProvider] Failed to delete KV namespace", {
|
|
118034
|
+
namespaceName,
|
|
118035
|
+
error: error2
|
|
118036
|
+
});
|
|
118037
|
+
}
|
|
118038
|
+
}
|
|
117964
118039
|
}
|
|
117965
118040
|
// ../cloudflare/src/utils/hostname.ts
|
|
117966
118041
|
var RESERVED_SUBDOMAINS = new Set([
|
|
@@ -129396,27 +129471,6 @@ async function startServer(port, project, options = {}) {
|
|
|
129396
129471
|
}
|
|
129397
129472
|
var version3 = package_default.version;
|
|
129398
129473
|
|
|
129399
|
-
// src/utils/port.ts
|
|
129400
|
-
import { createServer } from "node:net";
|
|
129401
|
-
async function findAvailablePort(startPort = 4321) {
|
|
129402
|
-
return new Promise((resolve2, reject) => {
|
|
129403
|
-
const server2 = createServer();
|
|
129404
|
-
server2.listen(startPort, () => {
|
|
129405
|
-
const address = server2.address();
|
|
129406
|
-
const port = address && typeof address === "object" ? address.port : startPort;
|
|
129407
|
-
server2.close(() => resolve2(port));
|
|
129408
|
-
});
|
|
129409
|
-
server2.on("error", () => {
|
|
129410
|
-
findAvailablePort(startPort + 1).then(resolve2).catch(reject);
|
|
129411
|
-
});
|
|
129412
|
-
});
|
|
129413
|
-
}
|
|
129414
|
-
async function allocateSandboxPorts(preferred = 4321) {
|
|
129415
|
-
const apiPort = await findAvailablePort(preferred);
|
|
129416
|
-
const realtimePort = await findAvailablePort(apiPort + 1);
|
|
129417
|
-
return { apiPort, realtimePort };
|
|
129418
|
-
}
|
|
129419
|
-
|
|
129420
129474
|
// node_modules/commander/esm.mjs
|
|
129421
129475
|
var import__4 = __toESM(require_commander(), 1);
|
|
129422
129476
|
var {
|
|
@@ -129435,6 +129489,92 @@ var {
|
|
|
129435
129489
|
|
|
129436
129490
|
// src/cli.ts
|
|
129437
129491
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
129492
|
+
|
|
129493
|
+
// ../utils/src/port.ts
|
|
129494
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
|
|
129495
|
+
import { createServer } from "node:net";
|
|
129496
|
+
import { homedir } from "node:os";
|
|
129497
|
+
import { join as join3 } from "node:path";
|
|
129498
|
+
async function isPortAvailableOnHost(port, host) {
|
|
129499
|
+
return new Promise((resolve2) => {
|
|
129500
|
+
const server2 = createServer();
|
|
129501
|
+
server2.once("error", () => {
|
|
129502
|
+
resolve2(false);
|
|
129503
|
+
});
|
|
129504
|
+
server2.once("listening", () => {
|
|
129505
|
+
server2.close();
|
|
129506
|
+
resolve2(true);
|
|
129507
|
+
});
|
|
129508
|
+
server2.listen(port, host);
|
|
129509
|
+
});
|
|
129510
|
+
}
|
|
129511
|
+
async function findAvailablePort(startPort = 4321) {
|
|
129512
|
+
const ipv4Available = await isPortAvailableOnHost(startPort, "127.0.0.1");
|
|
129513
|
+
const ipv6Available = await isPortAvailableOnHost(startPort, "::1");
|
|
129514
|
+
if (ipv4Available && ipv6Available) {
|
|
129515
|
+
return startPort;
|
|
129516
|
+
}
|
|
129517
|
+
return findAvailablePort(startPort + 1);
|
|
129518
|
+
}
|
|
129519
|
+
function getRegistryPath() {
|
|
129520
|
+
const home = homedir();
|
|
129521
|
+
const dir = join3(home, ".playcademy");
|
|
129522
|
+
if (!existsSync2(dir)) {
|
|
129523
|
+
mkdirSync2(dir, { recursive: true });
|
|
129524
|
+
}
|
|
129525
|
+
return join3(dir, ".proc");
|
|
129526
|
+
}
|
|
129527
|
+
function readRegistry() {
|
|
129528
|
+
const registryPath = getRegistryPath();
|
|
129529
|
+
if (!existsSync2(registryPath)) {
|
|
129530
|
+
return {};
|
|
129531
|
+
}
|
|
129532
|
+
try {
|
|
129533
|
+
const content = readFileSync(registryPath, "utf-8");
|
|
129534
|
+
return JSON.parse(content);
|
|
129535
|
+
} catch {
|
|
129536
|
+
return {};
|
|
129537
|
+
}
|
|
129538
|
+
}
|
|
129539
|
+
function writeRegistry(registry2) {
|
|
129540
|
+
const registryPath = getRegistryPath();
|
|
129541
|
+
writeFileSync(registryPath, JSON.stringify(registry2, null, 2), "utf-8");
|
|
129542
|
+
}
|
|
129543
|
+
function getServerKey(type, port) {
|
|
129544
|
+
return `${type}-${port}`;
|
|
129545
|
+
}
|
|
129546
|
+
function writeServerInfo(type, info2) {
|
|
129547
|
+
const registry2 = readRegistry();
|
|
129548
|
+
const key = getServerKey(type, info2.port);
|
|
129549
|
+
registry2[key] = info2;
|
|
129550
|
+
writeRegistry(registry2);
|
|
129551
|
+
}
|
|
129552
|
+
function cleanupServerInfo(type, projectRoot, pid) {
|
|
129553
|
+
const registry2 = readRegistry();
|
|
129554
|
+
const keysToRemove = [];
|
|
129555
|
+
for (const [key, info2] of Object.entries(registry2)) {
|
|
129556
|
+
if (key.startsWith(`${type}-`)) {
|
|
129557
|
+
let matches = true;
|
|
129558
|
+
if (projectRoot && info2.projectRoot !== projectRoot) {
|
|
129559
|
+
matches = false;
|
|
129560
|
+
}
|
|
129561
|
+
if (pid !== undefined && info2.pid !== pid) {
|
|
129562
|
+
matches = false;
|
|
129563
|
+
}
|
|
129564
|
+
if (matches) {
|
|
129565
|
+
keysToRemove.push(key);
|
|
129566
|
+
}
|
|
129567
|
+
}
|
|
129568
|
+
}
|
|
129569
|
+
for (const key of keysToRemove) {
|
|
129570
|
+
delete registry2[key];
|
|
129571
|
+
}
|
|
129572
|
+
if (keysToRemove.length > 0) {
|
|
129573
|
+
writeRegistry(registry2);
|
|
129574
|
+
}
|
|
129575
|
+
}
|
|
129576
|
+
|
|
129577
|
+
// src/cli.ts
|
|
129438
129578
|
var program2 = new Command;
|
|
129439
129579
|
program2.name("playcademy-sandbox").description("Local development server for Playcademy game development").version("0.1.0").option("-p, --port <number>", "Port to run the server on", "4321").option("-v, --verbose", "Enable verbose logging", false).option("--project-name <name>", "Name of the current project").option("--project-slug <slug>", "Slug of the current project").option("--realtime", "Enable the realtime server", false).option("--realtime-port <number>", "Port for the realtime server (defaults to main port + 1)").option("--no-seed", "Do not seed the database with demo data").option("--timeback-local", "Use local TimeBack instance").option("--timeback-oneroster-url <url>", "TimeBack OneRoster API URL").option("--timeback-caliper-url <url>", "TimeBack Caliper API URL").option("--timeback-course-id <id>", "TimeBack course ID for seeding").option("--timeback-student-id <id>", "TimeBack student ID for demo user").action(async (options) => {
|
|
129440
129580
|
try {
|
|
@@ -129468,6 +129608,13 @@ program2.name("playcademy-sandbox").description("Local development server for Pl
|
|
|
129468
129608
|
},
|
|
129469
129609
|
timeback: timebackOptions
|
|
129470
129610
|
});
|
|
129611
|
+
writeServerInfo("sandbox", {
|
|
129612
|
+
pid: process.pid,
|
|
129613
|
+
port: availablePort,
|
|
129614
|
+
url: `http://localhost:${availablePort}/api`,
|
|
129615
|
+
startedAt: Date.now(),
|
|
129616
|
+
projectRoot: process.cwd()
|
|
129617
|
+
});
|
|
129471
129618
|
console.log("");
|
|
129472
129619
|
console.log(` ${import_picocolors.default.green(import_picocolors.default.bold("PLAYCADEMY"))} ${import_picocolors.default.green(`v${version3}`)}`);
|
|
129473
129620
|
console.log("");
|
|
@@ -129483,10 +129630,13 @@ program2.name("playcademy-sandbox").description("Local development server for Pl
|
|
|
129483
129630
|
console.log("");
|
|
129484
129631
|
console.log(` ${import_picocolors.default.dim("Press")} ${import_picocolors.default.bold("Ctrl+C")} ${import_picocolors.default.dim("to stop the server")}`);
|
|
129485
129632
|
console.log("");
|
|
129486
|
-
|
|
129633
|
+
const cleanup = () => {
|
|
129634
|
+
cleanupServerInfo("sandbox", process.cwd(), process.pid);
|
|
129487
129635
|
servers.stop();
|
|
129488
129636
|
process.exit(0);
|
|
129489
|
-
}
|
|
129637
|
+
};
|
|
129638
|
+
process.on("SIGINT", cleanup);
|
|
129639
|
+
process.on("SIGTERM", cleanup);
|
|
129490
129640
|
} catch (error2) {
|
|
129491
129641
|
console.error(import_picocolors.default.red(`❌ Failed to start sandbox: ${error2}`));
|
|
129492
129642
|
process.exit(1);
|
package/dist/server.js
CHANGED
|
@@ -81999,7 +81999,7 @@ var logger = (fn = console.log) => {
|
|
|
81999
81999
|
// package.json
|
|
82000
82000
|
var package_default = {
|
|
82001
82001
|
name: "@playcademy/sandbox",
|
|
82002
|
-
version: "0.1.
|
|
82002
|
+
version: "0.1.1",
|
|
82003
82003
|
description: "Local development server for Playcademy game development",
|
|
82004
82004
|
type: "module",
|
|
82005
82005
|
exports: {
|
|
@@ -115888,7 +115888,10 @@ class CloudflareProvider {
|
|
|
115888
115888
|
namespace: this.config.dispatchNamespace
|
|
115889
115889
|
});
|
|
115890
115890
|
if (deleteBindings) {
|
|
115891
|
-
await
|
|
115891
|
+
await Promise.all([
|
|
115892
|
+
this.deleteD1DatabaseIfExists(deploymentId),
|
|
115893
|
+
this.deleteKVNamespaceIfExists(deploymentId)
|
|
115894
|
+
]);
|
|
115892
115895
|
}
|
|
115893
115896
|
} catch (error2) {
|
|
115894
115897
|
log2.error("[CloudflareProvider] Deletion from dispatch namespace failed", {
|
|
@@ -115939,7 +115942,12 @@ class CloudflareProvider {
|
|
|
115939
115942
|
}
|
|
115940
115943
|
}
|
|
115941
115944
|
for (const kvName of resourceBindings.kv) {
|
|
115942
|
-
|
|
115945
|
+
const namespaceId = await this.ensureKVNamespace(kvName);
|
|
115946
|
+
bindings.push({
|
|
115947
|
+
type: "kv_namespace",
|
|
115948
|
+
name: "KV",
|
|
115949
|
+
namespace_id: namespaceId
|
|
115950
|
+
});
|
|
115943
115951
|
}
|
|
115944
115952
|
for (const r2Name of resourceBindings.r2) {
|
|
115945
115953
|
log2.warn("[CloudflareProvider] R2 bucket binding not yet implemented", { r2Name });
|
|
@@ -116051,6 +116059,73 @@ class CloudflareProvider {
|
|
|
116051
116059
|
throw new Error(`Failed to execute schema: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
116052
116060
|
}
|
|
116053
116061
|
}
|
|
116062
|
+
async ensureKVNamespace(namespaceName) {
|
|
116063
|
+
log2.debug("[CloudflareProvider] Ensuring KV namespace exists", { namespaceName });
|
|
116064
|
+
try {
|
|
116065
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
116066
|
+
account_id: this.config.accountId
|
|
116067
|
+
});
|
|
116068
|
+
for await (const ns of namespaces) {
|
|
116069
|
+
if (ns.title === namespaceName && ns.id) {
|
|
116070
|
+
log2.info("[CloudflareProvider] KV namespace already exists", {
|
|
116071
|
+
namespaceName,
|
|
116072
|
+
namespaceId: ns.id
|
|
116073
|
+
});
|
|
116074
|
+
return ns.id;
|
|
116075
|
+
}
|
|
116076
|
+
}
|
|
116077
|
+
log2.debug("[CloudflareProvider] Creating new KV namespace", { namespaceName });
|
|
116078
|
+
const createResult = await this.client.kv.namespaces.create({
|
|
116079
|
+
account_id: this.config.accountId,
|
|
116080
|
+
title: namespaceName
|
|
116081
|
+
});
|
|
116082
|
+
if (!createResult.id) {
|
|
116083
|
+
throw new Error("KV namespace creation succeeded but no ID returned");
|
|
116084
|
+
}
|
|
116085
|
+
log2.info("[CloudflareProvider] KV namespace created successfully", {
|
|
116086
|
+
namespaceName,
|
|
116087
|
+
namespaceId: createResult.id
|
|
116088
|
+
});
|
|
116089
|
+
return createResult.id;
|
|
116090
|
+
} catch (error2) {
|
|
116091
|
+
log2.error("[CloudflareProvider] Failed to ensure KV namespace", {
|
|
116092
|
+
namespaceName,
|
|
116093
|
+
error: error2
|
|
116094
|
+
});
|
|
116095
|
+
throw new Error(`Failed to ensure KV namespace: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
116096
|
+
}
|
|
116097
|
+
}
|
|
116098
|
+
async deleteKVNamespaceIfExists(namespaceName) {
|
|
116099
|
+
try {
|
|
116100
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
116101
|
+
account_id: this.config.accountId
|
|
116102
|
+
});
|
|
116103
|
+
for await (const ns of namespaces) {
|
|
116104
|
+
if (ns.title === namespaceName && ns.id) {
|
|
116105
|
+
log2.debug("[CloudflareProvider] Deleting KV namespace", {
|
|
116106
|
+
namespaceName,
|
|
116107
|
+
namespaceId: ns.id
|
|
116108
|
+
});
|
|
116109
|
+
await this.client.kv.namespaces.delete(ns.id, {
|
|
116110
|
+
account_id: this.config.accountId
|
|
116111
|
+
});
|
|
116112
|
+
log2.info("[CloudflareProvider] KV namespace deleted successfully", {
|
|
116113
|
+
namespaceName,
|
|
116114
|
+
namespaceId: ns.id
|
|
116115
|
+
});
|
|
116116
|
+
return;
|
|
116117
|
+
}
|
|
116118
|
+
}
|
|
116119
|
+
log2.debug("[CloudflareProvider] KV namespace not found, nothing to delete", {
|
|
116120
|
+
namespaceName
|
|
116121
|
+
});
|
|
116122
|
+
} catch (error2) {
|
|
116123
|
+
log2.warn("[CloudflareProvider] Failed to delete KV namespace", {
|
|
116124
|
+
namespaceName,
|
|
116125
|
+
error: error2
|
|
116126
|
+
});
|
|
116127
|
+
}
|
|
116128
|
+
}
|
|
116054
116129
|
}
|
|
116055
116130
|
// ../cloudflare/src/utils/hostname.ts
|
|
116056
116131
|
var RESERVED_SUBDOMAINS = new Set([
|
package/package.json
CHANGED
package/dist/utils/port.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export declare function findAvailablePort(startPort?: number): Promise<number>;
|
|
2
|
-
/**
|
|
3
|
-
* Allocate a pair of ports for the sandbox: one for the main HTTP API server
|
|
4
|
-
* and one for the realtime WebSocket server.
|
|
5
|
-
*
|
|
6
|
-
* • We first look for an available port starting from `preferred` (defaults to
|
|
7
|
-
* 4321). That becomes the API port.
|
|
8
|
-
* • We then look for the next available port **after** the chosen API port for
|
|
9
|
-
* the realtime server. This guarantees the two ports are distinct and
|
|
10
|
-
* stable for the lifetime of the sandbox.
|
|
11
|
-
*
|
|
12
|
-
* The helper centralises the port-allocation logic so that the sandbox CLI,
|
|
13
|
-
* integration-test harness and Vite plugin all follow the exact same rules.
|
|
14
|
-
*/
|
|
15
|
-
export declare function allocateSandboxPorts(preferred?: number): Promise<{
|
|
16
|
-
apiPort: number;
|
|
17
|
-
realtimePort: number;
|
|
18
|
-
}>;
|
package/dist/utils/port.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
19
|
-
var __export = (target, all) => {
|
|
20
|
-
for (var name in all)
|
|
21
|
-
__defProp(target, name, {
|
|
22
|
-
get: all[name],
|
|
23
|
-
enumerable: true,
|
|
24
|
-
configurable: true,
|
|
25
|
-
set: (newValue) => all[name] = () => newValue
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
|
-
|
|
31
|
-
// src/utils/port.ts
|
|
32
|
-
import { createServer } from "node:net";
|
|
33
|
-
async function findAvailablePort(startPort = 4321) {
|
|
34
|
-
return new Promise((resolve, reject) => {
|
|
35
|
-
const server = createServer();
|
|
36
|
-
server.listen(startPort, () => {
|
|
37
|
-
const address = server.address();
|
|
38
|
-
const port = address && typeof address === "object" ? address.port : startPort;
|
|
39
|
-
server.close(() => resolve(port));
|
|
40
|
-
});
|
|
41
|
-
server.on("error", () => {
|
|
42
|
-
findAvailablePort(startPort + 1).then(resolve).catch(reject);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
async function allocateSandboxPorts(preferred = 4321) {
|
|
47
|
-
const apiPort = await findAvailablePort(preferred);
|
|
48
|
-
const realtimePort = await findAvailablePort(apiPort + 1);
|
|
49
|
-
return { apiPort, realtimePort };
|
|
50
|
-
}
|
|
51
|
-
export {
|
|
52
|
-
findAvailablePort,
|
|
53
|
-
allocateSandboxPorts
|
|
54
|
-
};
|