@playcademy/sandbox 0.1.1 → 0.1.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/dist/cli.js +176 -27
- package/dist/server.js +78 -4
- package/package.json +1 -2
- 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.2",
|
|
83913
83913
|
description: "Local development server for Playcademy game development",
|
|
83914
83914
|
type: "module",
|
|
83915
83915
|
exports: {
|
|
@@ -83946,7 +83946,6 @@ var package_default = {
|
|
|
83946
83946
|
dependencies: {
|
|
83947
83947
|
"@electric-sql/pglite": "^0.3.2",
|
|
83948
83948
|
"@hono/node-server": "^1.14.2",
|
|
83949
|
-
"@playcademy/constants": "workspace:*",
|
|
83950
83949
|
commander: "^12.1.0",
|
|
83951
83950
|
"drizzle-kit": "^0.31.0",
|
|
83952
83951
|
"drizzle-orm": "^0.42.0",
|
|
@@ -117798,7 +117797,10 @@ class CloudflareProvider {
|
|
|
117798
117797
|
namespace: this.config.dispatchNamespace
|
|
117799
117798
|
});
|
|
117800
117799
|
if (deleteBindings) {
|
|
117801
|
-
await
|
|
117800
|
+
await Promise.all([
|
|
117801
|
+
this.deleteD1DatabaseIfExists(deploymentId),
|
|
117802
|
+
this.deleteKVNamespaceIfExists(deploymentId)
|
|
117803
|
+
]);
|
|
117802
117804
|
}
|
|
117803
117805
|
} catch (error2) {
|
|
117804
117806
|
log2.error("[CloudflareProvider] Deletion from dispatch namespace failed", {
|
|
@@ -117849,7 +117851,12 @@ class CloudflareProvider {
|
|
|
117849
117851
|
}
|
|
117850
117852
|
}
|
|
117851
117853
|
for (const kvName of resourceBindings.kv) {
|
|
117852
|
-
|
|
117854
|
+
const namespaceId = await this.ensureKVNamespace(kvName);
|
|
117855
|
+
bindings.push({
|
|
117856
|
+
type: "kv_namespace",
|
|
117857
|
+
name: "KV",
|
|
117858
|
+
namespace_id: namespaceId
|
|
117859
|
+
});
|
|
117853
117860
|
}
|
|
117854
117861
|
for (const r2Name of resourceBindings.r2) {
|
|
117855
117862
|
log2.warn("[CloudflareProvider] R2 bucket binding not yet implemented", { r2Name });
|
|
@@ -117961,6 +117968,73 @@ class CloudflareProvider {
|
|
|
117961
117968
|
throw new Error(`Failed to execute schema: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
117962
117969
|
}
|
|
117963
117970
|
}
|
|
117971
|
+
async ensureKVNamespace(namespaceName) {
|
|
117972
|
+
log2.debug("[CloudflareProvider] Ensuring KV namespace exists", { namespaceName });
|
|
117973
|
+
try {
|
|
117974
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
117975
|
+
account_id: this.config.accountId
|
|
117976
|
+
});
|
|
117977
|
+
for await (const ns of namespaces) {
|
|
117978
|
+
if (ns.title === namespaceName && ns.id) {
|
|
117979
|
+
log2.info("[CloudflareProvider] KV namespace already exists", {
|
|
117980
|
+
namespaceName,
|
|
117981
|
+
namespaceId: ns.id
|
|
117982
|
+
});
|
|
117983
|
+
return ns.id;
|
|
117984
|
+
}
|
|
117985
|
+
}
|
|
117986
|
+
log2.debug("[CloudflareProvider] Creating new KV namespace", { namespaceName });
|
|
117987
|
+
const createResult = await this.client.kv.namespaces.create({
|
|
117988
|
+
account_id: this.config.accountId,
|
|
117989
|
+
title: namespaceName
|
|
117990
|
+
});
|
|
117991
|
+
if (!createResult.id) {
|
|
117992
|
+
throw new Error("KV namespace creation succeeded but no ID returned");
|
|
117993
|
+
}
|
|
117994
|
+
log2.info("[CloudflareProvider] KV namespace created successfully", {
|
|
117995
|
+
namespaceName,
|
|
117996
|
+
namespaceId: createResult.id
|
|
117997
|
+
});
|
|
117998
|
+
return createResult.id;
|
|
117999
|
+
} catch (error2) {
|
|
118000
|
+
log2.error("[CloudflareProvider] Failed to ensure KV namespace", {
|
|
118001
|
+
namespaceName,
|
|
118002
|
+
error: error2
|
|
118003
|
+
});
|
|
118004
|
+
throw new Error(`Failed to ensure KV namespace: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
118005
|
+
}
|
|
118006
|
+
}
|
|
118007
|
+
async deleteKVNamespaceIfExists(namespaceName) {
|
|
118008
|
+
try {
|
|
118009
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
118010
|
+
account_id: this.config.accountId
|
|
118011
|
+
});
|
|
118012
|
+
for await (const ns of namespaces) {
|
|
118013
|
+
if (ns.title === namespaceName && ns.id) {
|
|
118014
|
+
log2.debug("[CloudflareProvider] Deleting KV namespace", {
|
|
118015
|
+
namespaceName,
|
|
118016
|
+
namespaceId: ns.id
|
|
118017
|
+
});
|
|
118018
|
+
await this.client.kv.namespaces.delete(ns.id, {
|
|
118019
|
+
account_id: this.config.accountId
|
|
118020
|
+
});
|
|
118021
|
+
log2.info("[CloudflareProvider] KV namespace deleted successfully", {
|
|
118022
|
+
namespaceName,
|
|
118023
|
+
namespaceId: ns.id
|
|
118024
|
+
});
|
|
118025
|
+
return;
|
|
118026
|
+
}
|
|
118027
|
+
}
|
|
118028
|
+
log2.debug("[CloudflareProvider] KV namespace not found, nothing to delete", {
|
|
118029
|
+
namespaceName
|
|
118030
|
+
});
|
|
118031
|
+
} catch (error2) {
|
|
118032
|
+
log2.warn("[CloudflareProvider] Failed to delete KV namespace", {
|
|
118033
|
+
namespaceName,
|
|
118034
|
+
error: error2
|
|
118035
|
+
});
|
|
118036
|
+
}
|
|
118037
|
+
}
|
|
117964
118038
|
}
|
|
117965
118039
|
// ../cloudflare/src/utils/hostname.ts
|
|
117966
118040
|
var RESERVED_SUBDOMAINS = new Set([
|
|
@@ -129396,27 +129470,6 @@ async function startServer(port, project, options = {}) {
|
|
|
129396
129470
|
}
|
|
129397
129471
|
var version3 = package_default.version;
|
|
129398
129472
|
|
|
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
129473
|
// node_modules/commander/esm.mjs
|
|
129421
129474
|
var import__4 = __toESM(require_commander(), 1);
|
|
129422
129475
|
var {
|
|
@@ -129435,6 +129488,92 @@ var {
|
|
|
129435
129488
|
|
|
129436
129489
|
// src/cli.ts
|
|
129437
129490
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
129491
|
+
|
|
129492
|
+
// ../utils/src/port.ts
|
|
129493
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
|
|
129494
|
+
import { createServer } from "node:net";
|
|
129495
|
+
import { homedir } from "node:os";
|
|
129496
|
+
import { join as join3 } from "node:path";
|
|
129497
|
+
async function isPortAvailableOnHost(port, host) {
|
|
129498
|
+
return new Promise((resolve2) => {
|
|
129499
|
+
const server2 = createServer();
|
|
129500
|
+
server2.once("error", () => {
|
|
129501
|
+
resolve2(false);
|
|
129502
|
+
});
|
|
129503
|
+
server2.once("listening", () => {
|
|
129504
|
+
server2.close();
|
|
129505
|
+
resolve2(true);
|
|
129506
|
+
});
|
|
129507
|
+
server2.listen(port, host);
|
|
129508
|
+
});
|
|
129509
|
+
}
|
|
129510
|
+
async function findAvailablePort(startPort = 4321) {
|
|
129511
|
+
const ipv4Available = await isPortAvailableOnHost(startPort, "127.0.0.1");
|
|
129512
|
+
const ipv6Available = await isPortAvailableOnHost(startPort, "::1");
|
|
129513
|
+
if (ipv4Available && ipv6Available) {
|
|
129514
|
+
return startPort;
|
|
129515
|
+
}
|
|
129516
|
+
return findAvailablePort(startPort + 1);
|
|
129517
|
+
}
|
|
129518
|
+
function getRegistryPath() {
|
|
129519
|
+
const home = homedir();
|
|
129520
|
+
const dir = join3(home, ".playcademy");
|
|
129521
|
+
if (!existsSync2(dir)) {
|
|
129522
|
+
mkdirSync2(dir, { recursive: true });
|
|
129523
|
+
}
|
|
129524
|
+
return join3(dir, ".proc");
|
|
129525
|
+
}
|
|
129526
|
+
function readRegistry() {
|
|
129527
|
+
const registryPath = getRegistryPath();
|
|
129528
|
+
if (!existsSync2(registryPath)) {
|
|
129529
|
+
return {};
|
|
129530
|
+
}
|
|
129531
|
+
try {
|
|
129532
|
+
const content = readFileSync(registryPath, "utf-8");
|
|
129533
|
+
return JSON.parse(content);
|
|
129534
|
+
} catch {
|
|
129535
|
+
return {};
|
|
129536
|
+
}
|
|
129537
|
+
}
|
|
129538
|
+
function writeRegistry(registry2) {
|
|
129539
|
+
const registryPath = getRegistryPath();
|
|
129540
|
+
writeFileSync(registryPath, JSON.stringify(registry2, null, 2), "utf-8");
|
|
129541
|
+
}
|
|
129542
|
+
function getServerKey(type, port) {
|
|
129543
|
+
return `${type}-${port}`;
|
|
129544
|
+
}
|
|
129545
|
+
function writeServerInfo(type, info2) {
|
|
129546
|
+
const registry2 = readRegistry();
|
|
129547
|
+
const key = getServerKey(type, info2.port);
|
|
129548
|
+
registry2[key] = info2;
|
|
129549
|
+
writeRegistry(registry2);
|
|
129550
|
+
}
|
|
129551
|
+
function cleanupServerInfo(type, projectRoot, pid) {
|
|
129552
|
+
const registry2 = readRegistry();
|
|
129553
|
+
const keysToRemove = [];
|
|
129554
|
+
for (const [key, info2] of Object.entries(registry2)) {
|
|
129555
|
+
if (key.startsWith(`${type}-`)) {
|
|
129556
|
+
let matches = true;
|
|
129557
|
+
if (projectRoot && info2.projectRoot !== projectRoot) {
|
|
129558
|
+
matches = false;
|
|
129559
|
+
}
|
|
129560
|
+
if (pid !== undefined && info2.pid !== pid) {
|
|
129561
|
+
matches = false;
|
|
129562
|
+
}
|
|
129563
|
+
if (matches) {
|
|
129564
|
+
keysToRemove.push(key);
|
|
129565
|
+
}
|
|
129566
|
+
}
|
|
129567
|
+
}
|
|
129568
|
+
for (const key of keysToRemove) {
|
|
129569
|
+
delete registry2[key];
|
|
129570
|
+
}
|
|
129571
|
+
if (keysToRemove.length > 0) {
|
|
129572
|
+
writeRegistry(registry2);
|
|
129573
|
+
}
|
|
129574
|
+
}
|
|
129575
|
+
|
|
129576
|
+
// src/cli.ts
|
|
129438
129577
|
var program2 = new Command;
|
|
129439
129578
|
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
129579
|
try {
|
|
@@ -129468,6 +129607,13 @@ program2.name("playcademy-sandbox").description("Local development server for Pl
|
|
|
129468
129607
|
},
|
|
129469
129608
|
timeback: timebackOptions
|
|
129470
129609
|
});
|
|
129610
|
+
writeServerInfo("sandbox", {
|
|
129611
|
+
pid: process.pid,
|
|
129612
|
+
port: availablePort,
|
|
129613
|
+
url: `http://localhost:${availablePort}/api`,
|
|
129614
|
+
startedAt: Date.now(),
|
|
129615
|
+
projectRoot: process.cwd()
|
|
129616
|
+
});
|
|
129471
129617
|
console.log("");
|
|
129472
129618
|
console.log(` ${import_picocolors.default.green(import_picocolors.default.bold("PLAYCADEMY"))} ${import_picocolors.default.green(`v${version3}`)}`);
|
|
129473
129619
|
console.log("");
|
|
@@ -129483,10 +129629,13 @@ program2.name("playcademy-sandbox").description("Local development server for Pl
|
|
|
129483
129629
|
console.log("");
|
|
129484
129630
|
console.log(` ${import_picocolors.default.dim("Press")} ${import_picocolors.default.bold("Ctrl+C")} ${import_picocolors.default.dim("to stop the server")}`);
|
|
129485
129631
|
console.log("");
|
|
129486
|
-
|
|
129632
|
+
const cleanup = () => {
|
|
129633
|
+
cleanupServerInfo("sandbox", process.cwd(), process.pid);
|
|
129487
129634
|
servers.stop();
|
|
129488
129635
|
process.exit(0);
|
|
129489
|
-
}
|
|
129636
|
+
};
|
|
129637
|
+
process.on("SIGINT", cleanup);
|
|
129638
|
+
process.on("SIGTERM", cleanup);
|
|
129490
129639
|
} catch (error2) {
|
|
129491
129640
|
console.error(import_picocolors.default.red(`❌ Failed to start sandbox: ${error2}`));
|
|
129492
129641
|
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.2",
|
|
82003
82003
|
description: "Local development server for Playcademy game development",
|
|
82004
82004
|
type: "module",
|
|
82005
82005
|
exports: {
|
|
@@ -82036,7 +82036,6 @@ var package_default = {
|
|
|
82036
82036
|
dependencies: {
|
|
82037
82037
|
"@electric-sql/pglite": "^0.3.2",
|
|
82038
82038
|
"@hono/node-server": "^1.14.2",
|
|
82039
|
-
"@playcademy/constants": "workspace:*",
|
|
82040
82039
|
commander: "^12.1.0",
|
|
82041
82040
|
"drizzle-kit": "^0.31.0",
|
|
82042
82041
|
"drizzle-orm": "^0.42.0",
|
|
@@ -115888,7 +115887,10 @@ class CloudflareProvider {
|
|
|
115888
115887
|
namespace: this.config.dispatchNamespace
|
|
115889
115888
|
});
|
|
115890
115889
|
if (deleteBindings) {
|
|
115891
|
-
await
|
|
115890
|
+
await Promise.all([
|
|
115891
|
+
this.deleteD1DatabaseIfExists(deploymentId),
|
|
115892
|
+
this.deleteKVNamespaceIfExists(deploymentId)
|
|
115893
|
+
]);
|
|
115892
115894
|
}
|
|
115893
115895
|
} catch (error2) {
|
|
115894
115896
|
log2.error("[CloudflareProvider] Deletion from dispatch namespace failed", {
|
|
@@ -115939,7 +115941,12 @@ class CloudflareProvider {
|
|
|
115939
115941
|
}
|
|
115940
115942
|
}
|
|
115941
115943
|
for (const kvName of resourceBindings.kv) {
|
|
115942
|
-
|
|
115944
|
+
const namespaceId = await this.ensureKVNamespace(kvName);
|
|
115945
|
+
bindings.push({
|
|
115946
|
+
type: "kv_namespace",
|
|
115947
|
+
name: "KV",
|
|
115948
|
+
namespace_id: namespaceId
|
|
115949
|
+
});
|
|
115943
115950
|
}
|
|
115944
115951
|
for (const r2Name of resourceBindings.r2) {
|
|
115945
115952
|
log2.warn("[CloudflareProvider] R2 bucket binding not yet implemented", { r2Name });
|
|
@@ -116051,6 +116058,73 @@ class CloudflareProvider {
|
|
|
116051
116058
|
throw new Error(`Failed to execute schema: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
116052
116059
|
}
|
|
116053
116060
|
}
|
|
116061
|
+
async ensureKVNamespace(namespaceName) {
|
|
116062
|
+
log2.debug("[CloudflareProvider] Ensuring KV namespace exists", { namespaceName });
|
|
116063
|
+
try {
|
|
116064
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
116065
|
+
account_id: this.config.accountId
|
|
116066
|
+
});
|
|
116067
|
+
for await (const ns of namespaces) {
|
|
116068
|
+
if (ns.title === namespaceName && ns.id) {
|
|
116069
|
+
log2.info("[CloudflareProvider] KV namespace already exists", {
|
|
116070
|
+
namespaceName,
|
|
116071
|
+
namespaceId: ns.id
|
|
116072
|
+
});
|
|
116073
|
+
return ns.id;
|
|
116074
|
+
}
|
|
116075
|
+
}
|
|
116076
|
+
log2.debug("[CloudflareProvider] Creating new KV namespace", { namespaceName });
|
|
116077
|
+
const createResult = await this.client.kv.namespaces.create({
|
|
116078
|
+
account_id: this.config.accountId,
|
|
116079
|
+
title: namespaceName
|
|
116080
|
+
});
|
|
116081
|
+
if (!createResult.id) {
|
|
116082
|
+
throw new Error("KV namespace creation succeeded but no ID returned");
|
|
116083
|
+
}
|
|
116084
|
+
log2.info("[CloudflareProvider] KV namespace created successfully", {
|
|
116085
|
+
namespaceName,
|
|
116086
|
+
namespaceId: createResult.id
|
|
116087
|
+
});
|
|
116088
|
+
return createResult.id;
|
|
116089
|
+
} catch (error2) {
|
|
116090
|
+
log2.error("[CloudflareProvider] Failed to ensure KV namespace", {
|
|
116091
|
+
namespaceName,
|
|
116092
|
+
error: error2
|
|
116093
|
+
});
|
|
116094
|
+
throw new Error(`Failed to ensure KV namespace: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
116095
|
+
}
|
|
116096
|
+
}
|
|
116097
|
+
async deleteKVNamespaceIfExists(namespaceName) {
|
|
116098
|
+
try {
|
|
116099
|
+
const namespaces = await this.client.kv.namespaces.list({
|
|
116100
|
+
account_id: this.config.accountId
|
|
116101
|
+
});
|
|
116102
|
+
for await (const ns of namespaces) {
|
|
116103
|
+
if (ns.title === namespaceName && ns.id) {
|
|
116104
|
+
log2.debug("[CloudflareProvider] Deleting KV namespace", {
|
|
116105
|
+
namespaceName,
|
|
116106
|
+
namespaceId: ns.id
|
|
116107
|
+
});
|
|
116108
|
+
await this.client.kv.namespaces.delete(ns.id, {
|
|
116109
|
+
account_id: this.config.accountId
|
|
116110
|
+
});
|
|
116111
|
+
log2.info("[CloudflareProvider] KV namespace deleted successfully", {
|
|
116112
|
+
namespaceName,
|
|
116113
|
+
namespaceId: ns.id
|
|
116114
|
+
});
|
|
116115
|
+
return;
|
|
116116
|
+
}
|
|
116117
|
+
}
|
|
116118
|
+
log2.debug("[CloudflareProvider] KV namespace not found, nothing to delete", {
|
|
116119
|
+
namespaceName
|
|
116120
|
+
});
|
|
116121
|
+
} catch (error2) {
|
|
116122
|
+
log2.warn("[CloudflareProvider] Failed to delete KV namespace", {
|
|
116123
|
+
namespaceName,
|
|
116124
|
+
error: error2
|
|
116125
|
+
});
|
|
116126
|
+
}
|
|
116127
|
+
}
|
|
116054
116128
|
}
|
|
116055
116129
|
// ../cloudflare/src/utils/hostname.ts
|
|
116056
116130
|
var RESERVED_SUBDOMAINS = new Set([
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcademy/sandbox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Local development server for Playcademy game development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@electric-sql/pglite": "^0.3.2",
|
|
39
39
|
"@hono/node-server": "^1.14.2",
|
|
40
|
-
"@playcademy/constants": "0.0.1",
|
|
41
40
|
"commander": "^12.1.0",
|
|
42
41
|
"drizzle-kit": "^0.31.0",
|
|
43
42
|
"drizzle-orm": "^0.42.0",
|
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
|
-
};
|