@deslop/workbench 0.0.320 → 0.0.321

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.
Files changed (2) hide show
  1. package/dist/server.js +180 -43
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -6250,6 +6250,96 @@ function isOutOfBounds(i, as) {
6250
6250
  }
6251
6251
  const clamp = (i, as) => Math.floor(Math.min(Math.max(0, i), as.length));
6252
6252
  /**
6253
+ * Reads an element at the given index safely, returning `Option.some` or
6254
+ * `Option.none` if the index is out of bounds.
6255
+ *
6256
+ * **When to use**
6257
+ *
6258
+ * Use when you need to read an array element by index and handle an
6259
+ * out-of-bounds index as `Option.none`.
6260
+ *
6261
+ * **Details**
6262
+ *
6263
+ * - The index is floored to an integer.
6264
+ * - Never throws.
6265
+ *
6266
+ * **Example** (Safe index access)
6267
+ *
6268
+ * ```ts
6269
+ * import { Array } from "effect"
6270
+ *
6271
+ * console.log(Array.get([1, 2, 3], 1)) // Some(2)
6272
+ * console.log(Array.get([1, 2, 3], 10)) // None
6273
+ * ```
6274
+ *
6275
+ * @see {@link getUnsafe} for indexed access that throws when the index is out of bounds
6276
+ * @see {@link head} for reading the first element as an `Option`
6277
+ * @see {@link last} for reading the last element as an `Option`
6278
+ *
6279
+ * @category getters
6280
+ * @since 2.0.0
6281
+ */
6282
+ const get$10 = /*#__PURE__*/ dual(2, (self, index) => {
6283
+ const i = Math.floor(index);
6284
+ return isOutOfBounds(i, self) ? none() : some$1(self[i]);
6285
+ });
6286
+ /**
6287
+ * Reads an element at the given index, throwing if the index is out of bounds.
6288
+ *
6289
+ * **When to use**
6290
+ *
6291
+ * Use to read an element at a known valid index when out-of-bounds would be a
6292
+ * programming error.
6293
+ *
6294
+ * **Details**
6295
+ *
6296
+ * - Throws an `Error` with the message `"Index out of bounds: <i>"`.
6297
+ * - Prefer {@link get} for safe access.
6298
+ *
6299
+ * **Example** (Unsafe index access)
6300
+ *
6301
+ * ```ts
6302
+ * import { Array } from "effect"
6303
+ *
6304
+ * console.log(Array.getUnsafe([1, 2, 3], 1)) // 2
6305
+ * // Array.getUnsafe([1, 2, 3], 10) // throws Error
6306
+ * ```
6307
+ *
6308
+ * @see {@link get} — safe version returning `Option`
6309
+ *
6310
+ * @category unsafe
6311
+ * @since 4.0.0
6312
+ */
6313
+ const getUnsafe$1 = /*#__PURE__*/ dual(2, (self, index) => {
6314
+ const i = Math.floor(index);
6315
+ if (isOutOfBounds(i, self)) throw new Error(`Index out of bounds: ${i}`);
6316
+ return self[i];
6317
+ });
6318
+ /**
6319
+ * Returns the first element of an array safely wrapped in `Option.some`, or
6320
+ * `Option.none` if the array is empty.
6321
+ *
6322
+ * **When to use**
6323
+ *
6324
+ * Use to safely get the first element of an array that may be empty.
6325
+ *
6326
+ * **Example** (Getting the first element)
6327
+ *
6328
+ * ```ts
6329
+ * import { Array } from "effect"
6330
+ *
6331
+ * console.log(Array.head([1, 2, 3])) // Some(1)
6332
+ * console.log(Array.head([])) // None
6333
+ * ```
6334
+ *
6335
+ * @see {@link headNonEmpty} — direct access when array is known non-empty
6336
+ * @see {@link last} — get the last element
6337
+ *
6338
+ * @category getters
6339
+ * @since 2.0.0
6340
+ */
6341
+ const head = /*#__PURE__*/ get$10(0);
6342
+ /**
6253
6343
  * Returns the first element of a `NonEmptyReadonlyArray` directly (no `Option`
6254
6344
  * wrapper).
6255
6345
  *
@@ -6271,11 +6361,7 @@ const clamp = (i, as) => Math.floor(Math.min(Math.max(0, i), as.length));
6271
6361
  * @category getters
6272
6362
  * @since 2.0.0
6273
6363
  */
6274
- const headNonEmpty = /*#__PURE__*/ (/* @__PURE__ */ dual(2, (self, index) => {
6275
- const i = Math.floor(index);
6276
- if (isOutOfBounds(i, self)) throw new Error(`Index out of bounds: ${i}`);
6277
- return self[i];
6278
- }))(0);
6364
+ const headNonEmpty = /*#__PURE__*/ getUnsafe$1(0);
6279
6365
  /**
6280
6366
  * Returns the last element of an array safely wrapped in `Option.some`, or
6281
6367
  * `Option.none` if the array is empty.
@@ -32223,6 +32309,28 @@ function decodeUnknownEffect$1(schema, options) {
32223
32309
  return options === void 0 ? parser : (input, overrideOptions) => parser(input, mergeParseOptions(options, overrideOptions));
32224
32310
  }
32225
32311
  /**
32312
+ * Creates a decoder for `unknown` input that returns an `Option` safely.
32313
+ *
32314
+ * **When to use**
32315
+ *
32316
+ * Use when you need a synchronous yes/no decode from untyped input and do not
32317
+ * need schema issue details.
32318
+ *
32319
+ * **Details**
32320
+ *
32321
+ * The returned function produces `Option.some` with the decoded `Type` on success
32322
+ * or `Option.none` on failure, discarding issue details.
32323
+ *
32324
+ * @see {@link decodeOption} for input already typed as the schema's `Encoded` type
32325
+ * @see {@link decodeUnknownResult} for retaining schema issues as data
32326
+ *
32327
+ * @category decoding
32328
+ * @since 3.10.0
32329
+ */
32330
+ function decodeUnknownOption$1(schema, options) {
32331
+ return asOption(decodeUnknownEffect$1(schema, options));
32332
+ }
32333
+ /**
32226
32334
  * Creates an effectful encoder for `unknown` input.
32227
32335
  *
32228
32336
  * **When to use**
@@ -32306,6 +32414,11 @@ function run(ast) {
32306
32414
  function asExit(parser) {
32307
32415
  return (input, options) => runSyncExit(parser(input, options));
32308
32416
  }
32417
+ /** @internal */
32418
+ function asOption(parser) {
32419
+ const parserExit = asExit(parser);
32420
+ return (input, options) => getSuccess(parserExit(input, options));
32421
+ }
32309
32422
  function asSync(parser) {
32310
32423
  return (input, options) => runSync(mapErrorEager(parser(input, options), (issue) => new Error(issue.toString(), { cause: issue })));
32311
32424
  }
@@ -32597,6 +32710,26 @@ function decodeUnknownEffect(schema, options) {
32597
32710
  */
32598
32711
  const decodeEffect = decodeUnknownEffect;
32599
32712
  /**
32713
+ * Decodes an `unknown` input against a schema, returning an `Option` that is
32714
+ * `Some` with the decoded value on success or `None` on failure.
32715
+ *
32716
+ * **When to use**
32717
+ *
32718
+ * Use when the input type is not statically known and you only need to know
32719
+ * whether decoding succeeded.
32720
+ *
32721
+ * **Details**
32722
+ *
32723
+ * Prefer this over {@link decodeUnknownExit} or {@link decodeUnknownEffect}
32724
+ * when you don't need error details. For typed input use {@link decodeOption}.
32725
+ * Options may be provided either when creating the decoder or when applying it;
32726
+ * application options override creation options.
32727
+ *
32728
+ * @category decoding
32729
+ * @since 3.10.0
32730
+ */
32731
+ const decodeUnknownOption = decodeUnknownOption$1;
32732
+ /**
32600
32733
  * Encodes an `unknown` input against a schema, returning an `Effect` that
32601
32734
  * succeeds with the encoded value or fails with a {@link SchemaError}.
32602
32735
  *
@@ -52449,6 +52582,7 @@ var GitWorktree = class extends Service()("@deslop/git/service/GitWorktree", { m
52449
52582
  };
52450
52583
  //#endregion
52451
52584
  //#region ../../packages/portless/src/lib/utils.ts
52585
+ const PackageJson = Struct({ scripts: optional(Record(String$1, String$1)) });
52452
52586
  function command(script, port) {
52453
52587
  return make$40("vp", [
52454
52588
  "run",
@@ -52474,23 +52608,23 @@ const discover = fnUntraced(function* (cwd, input) {
52474
52608
  "package.json",
52475
52609
  "**/package.json"
52476
52610
  ], { cwd }));
52477
- return yield* pipe(pipe(split$1("\n")(output), filter$2((path) => path === "package.json" || endsWith("/package.json")(path))), map$7((packagePath) => pipe(pipe(fs.readFileString(path.join(cwd, packagePath)), map$4((source) => ({
52478
- packageJson: JSON.parse(source),
52479
- packagePath
52480
- })), catch_$2(() => succeed$3(void 0))), flatMap$2((result) => {
52481
- if (result === void 0) return succeed$3([]);
52482
- const packageDirectory = result.packagePath === "package.json" ? cwd : path.join(cwd, path.dirname(result.packagePath));
52611
+ return yield* pipe(pipe(split$1("\n")(output), filter$2((path) => path === "package.json" || endsWith("/package.json")(path))), map$7((packagePath) => pipe(fs.readFileString(path.join(cwd, packagePath)), flatMap$2((source) => try_({
52612
+ catch: (error) => error,
52613
+ try: () => pipe(JSON.parse(source), decodeUnknownOption(PackageJson))
52614
+ })), catch_$2(() => succeed$3(none())), flatMap$2((packageJson) => {
52615
+ if (isNone(packageJson)) return succeed$3([]);
52616
+ const packageDirectory = packagePath === "package.json" ? cwd : path.join(cwd, path.dirname(packagePath));
52483
52617
  const folder = path.basename(packageDirectory);
52484
- const scriptEntries = pipe(Object.entries(result.packageJson.scripts ?? {}), filter$2((entry) => entry[0] === "dev" || startsWith("dev:")(entry[0])));
52485
- const packageOrigin = `http://${[
52618
+ const scriptEntries = pipe(Object.entries(packageJson.value.scripts ?? {}), filter$2((entry) => entry[0] === "dev" || startsWith("dev:")(entry[0])));
52619
+ const packageOrigin = input.origin([
52486
52620
  folder,
52487
52621
  path.basename(cwd),
52488
52622
  "localhost"
52489
- ].join(".")}:${input.proxyPort}`;
52623
+ ].join("."));
52490
52624
  return pipe(scriptEntries, map$7((entry) => {
52491
52625
  const name = entry[0];
52492
52626
  const scriptCommand = entry[1];
52493
- return map$4(input.port(`${result.packagePath}:${name}`), (port) => {
52627
+ return map$4(input.port(`${packagePath}:${name}`), (port) => {
52494
52628
  const service = /^dev:(.+)$/u.exec(name)?.[1] ?? "dev";
52495
52629
  const host = [
52496
52630
  service,
@@ -52498,7 +52632,7 @@ const discover = fnUntraced(function* (cwd, input) {
52498
52632
  path.basename(cwd),
52499
52633
  "localhost"
52500
52634
  ].join(".");
52501
- const origin = `http://${host}:${input.proxyPort}`;
52635
+ const origin = input.origin(host);
52502
52636
  return {
52503
52637
  host,
52504
52638
  port,
@@ -52517,9 +52651,9 @@ const discover = fnUntraced(function* (cwd, input) {
52517
52651
  name,
52518
52652
  origin,
52519
52653
  packageFolder: folder,
52520
- packagePath: result.packagePath,
52654
+ packagePath,
52521
52655
  service,
52522
- sessionId: `${result.packagePath}:${name}:${Date.now()}:${Math.random()}`
52656
+ sessionId: `${packagePath}:${name}:${Date.now()}:${Math.random()}`
52523
52657
  }
52524
52658
  };
52525
52659
  });
@@ -52587,9 +52721,9 @@ const INJECTED_HEAD = `<script>
52587
52721
  <\/script>
52588
52722
  <script crossorigin="anonymous" src="//unpkg.com/react-scan/dist/auto.global.js" onload="window.reactScan?.({allowInIframe: true, _debug: 'verbose'})"><\/script>
52589
52723
  <script src="https://unpkg.com/react-grab/dist/index.global.js"><\/script>`;
52590
- const injectScripts = fnUntraced(function* (html) {
52724
+ function injectScripts(html) {
52591
52725
  return /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (match) => `${match}\n${INJECTED_HEAD}`) : `${INJECTED_HEAD}\n${html}`;
52592
- });
52726
+ }
52593
52727
  const proxy = fnUntraced(function* (request, origin) {
52594
52728
  const webRequest = yield* toWeb(request);
52595
52729
  const [pathname = "/", search = ""] = request.url.split("?");
@@ -52613,7 +52747,7 @@ const proxy = fnUntraced(function* (request, origin) {
52613
52747
  }));
52614
52748
  const body = yield* tryPromise(() => upstreamResponse.text());
52615
52749
  headers.set("content-type", "text/html; charset=utf-8");
52616
- return fromWeb(new Response(yield* injectScripts(body), {
52750
+ return fromWeb(new Response(injectScripts(body), {
52617
52751
  headers,
52618
52752
  status: upstreamResponse.status,
52619
52753
  statusText: upstreamResponse.statusText
@@ -52621,41 +52755,46 @@ const proxy = fnUntraced(function* (request, origin) {
52621
52755
  });
52622
52756
  const proxyWebSocket = fnUntraced(function* (request, origin) {
52623
52757
  const [pathname = "/", search = ""] = request.url.split("?");
52624
- const protocols = request.headers["sec-websocket-protocol"]?.split(",").map((protocol) => protocol.trim()).filter((protocol) => protocol.length > 0);
52758
+ const protocols = pipe(fromUndefinedOr(request.headers["sec-websocket-protocol"]), map$9((protocols) => pipe(protocols, split$1(","), map$7(trim), filter$2(isNonEmpty$1))));
52625
52759
  const inbound = yield* request.upgrade;
52626
52760
  const upstreamUrl = new URL(origin);
52627
52761
  upstreamUrl.protocol = upstreamUrl.protocol === "https:" ? "wss:" : "ws:";
52628
52762
  upstreamUrl.pathname = pathname;
52629
52763
  upstreamUrl.search = search;
52630
- const outbound = yield* makeWebSocket(upstreamUrl.toString(), { protocols }).pipe(provide(layerWebSocketConstructorGlobal));
52764
+ const outbound = yield* makeWebSocket(upstreamUrl.toString(), { protocols: getOrUndefined$1(protocols) }).pipe(provide(layerWebSocketConstructorGlobal));
52631
52765
  const writeInbound = yield* inbound.writer;
52632
52766
  const writeOutbound = yield* outbound.writer;
52633
52767
  yield* outbound.runRaw((message) => writeInbound(message)).pipe(catchReason("SocketError", "SocketCloseError", (reason) => writeInbound(new CloseEvent(reason.code, reason.closeReason)).pipe(catch_$2(() => void_$1))), catch_$2(() => writeInbound(new CloseEvent(1011, "proxy error")).pipe(catch_$2(() => void_$1))), forkScoped);
52634
- yield* inbound.runRaw((message) => writeOutbound(typeof message === "string" ? message : message.slice())).pipe(catch_$2(() => void_$1), ensuring$2(writeOutbound(new CloseEvent()).pipe(catch_$2(() => void_$1))));
52768
+ yield* inbound.runRaw((message) => writeOutbound(isString(message) ? message : message.slice())).pipe(catch_$2(() => void_$1), ensuring$2(writeOutbound(new CloseEvent()).pipe(catch_$2(() => void_$1))));
52635
52769
  return empty();
52636
52770
  });
52637
- const requestHostname = fnUntraced(function* (host) {
52638
- return fromUndefinedOr(host?.split(":")[0]);
52639
- });
52771
+ function requestHostname(host) {
52772
+ return pipe(fromUndefinedOr(host), flatMap$6((host) => pipe(host, split$1(":"), head)));
52773
+ }
52640
52774
  function isLocalHostname(hostname) {
52641
52775
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
52642
52776
  }
52643
- var Portless = class Portless extends Service()("@deslop/portless/Portless", { make: sync(() => {
52777
+ var Portless = class Portless extends Service()("@deslop/portless/Portless", { make: gen(function* () {
52778
+ const server = yield* HttpServer;
52779
+ const proxyPort = server.address._tag === "TcpAddress" ? server.address.port.toString() : yield* die$1(/* @__PURE__ */ new Error("portless requires a TCP HTTP server address"));
52644
52780
  const ports = /* @__PURE__ */ new Map();
52645
52781
  const routes = /* @__PURE__ */ new Map();
52782
+ function origin(host) {
52783
+ return `http://${host}:${proxyPort}`;
52784
+ }
52646
52785
  const middleware = fnUntraced(function* (app) {
52647
52786
  const request = yield* HttpServerRequest;
52648
- const hostname = yield* requestHostname(request.headers["host"]);
52787
+ const hostname = requestHostname(request.headers["host"]);
52649
52788
  if (isNone(hostname) || isLocalHostname(hostname.value)) return yield* app;
52650
52789
  if (!hostname.value.endsWith(".localhost")) return yield* app;
52651
- const route = yield* lookup(request.headers["host"]);
52790
+ const route = lookup(request.headers["host"]);
52652
52791
  if (isNone(route)) return empty({ status: 404 });
52653
52792
  if (request.headers["upgrade"]?.toLowerCase() === "websocket") return yield* proxyWebSocket(request, route.value);
52654
52793
  return yield* proxy(request, route.value);
52655
52794
  });
52656
- const lookup = fnUntraced(function* (host) {
52657
- return pipe(yield* requestHostname(host), flatMap$6((hostname) => fromUndefinedOr(routes.get(hostname))));
52658
- });
52795
+ function lookup(host) {
52796
+ return pipe(requestHostname(host), flatMap$6((hostname) => fromUndefinedOr(routes.get(hostname))));
52797
+ }
52659
52798
  const port = fnUntraced(function* (key) {
52660
52799
  const existing = ports.get(key);
52661
52800
  if (existing !== void 0) return existing;
@@ -52671,15 +52810,13 @@ var Portless = class Portless extends Service()("@deslop/portless/Portless", { m
52671
52810
  });
52672
52811
  return {
52673
52812
  middleware,
52674
- port,
52675
- register: fnUntraced(function* (host, port) {
52676
- routes.set(host, `http://127.0.0.1:${port}`);
52677
- }),
52678
- scripts: fnUntraced(function* (cwd, input) {
52813
+ scripts: fnUntraced(function* (cwd) {
52679
52814
  return yield* pipe(discover(cwd, {
52680
- port: (sessionId) => port(`${cwd}:${sessionId}`),
52681
- proxyPort: input.proxyPort
52682
- }), map$4((routes) => routes.map((route) => ({
52815
+ origin,
52816
+ port: (sessionId) => port(`${cwd}:${sessionId}`)
52817
+ }), tap((discovered) => sync(() => {
52818
+ for (const route of discovered) routes.set(route.host, `http://127.0.0.1:${route.port}`);
52819
+ })), map$4((routes) => routes.map((route) => ({
52683
52820
  host: route.host,
52684
52821
  port: route.port,
52685
52822
  script: {
@@ -53055,11 +53192,11 @@ const RpcHandlers = RpcContracts.toLayer(gen(function* () {
53055
53192
  const portlessWorktrees = yield* make$46({
53056
53193
  idleTimeToLive: infinity,
53057
53194
  lookup: fnUntraced(function* (cwd) {
53058
- const scripts = yield* pipe(portless.scripts(cwd, { proxyPort: process.env["PORT"] ?? "4010" }), mapError$2((cause) => new TerminalError({
53195
+ const scripts = yield* pipe(portless.scripts(cwd), mapError$2((cause) => new TerminalError({
53059
53196
  cause,
53060
53197
  message: `failed to discover portless scripts in ${cwd}`
53061
53198
  })));
53062
- yield* all(pipe(scripts, map$7((script) => all([portless.register(script.host, script.port), update$1(portlessScripts, (current) => set$2(current, script.script.sessionId, script.script))], { discard: true }))), { discard: true });
53199
+ yield* all(pipe(scripts, map$7((script) => update$1(portlessScripts, (current) => set$2(current, script.script.sessionId, script.script)))), { discard: true });
53063
53200
  return pipe(scripts, map$7((route) => ({
53064
53201
  baseOrigin: route.script.baseOrigin,
53065
53202
  command: route.script.command,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "sideEffects": false,
4
4
  "name": "@deslop/workbench",
5
- "version": "0.0.320",
5
+ "version": "0.0.321",
6
6
  "files": [
7
7
  "dist"
8
8
  ],