@deslop/scope 0.1.1254 → 0.1.1256

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.
@@ -15,7 +15,7 @@
15
15
  <link rel="manifest" href="/manifest.webmanifest" />
16
16
 
17
17
  <title>Scope</title>
18
- <script type="module" crossorigin src="/assets/index-0qg-BjQU.js"></script>
18
+ <script type="module" crossorigin src="/assets/index-DndFZKLB.js"></script>
19
19
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-WkwZ5CU-.js">
20
20
  <link rel="modulepreload" crossorigin href="/assets/effect-DGdI2y-R.js">
21
21
  <link rel="modulepreload" crossorigin href="/assets/react-COyt-gOi.js">
package/dist/server.js CHANGED
@@ -6106,6 +6106,36 @@ const has$4 = /*#__PURE__*/ dual(2, (self, key) => Object.hasOwn(self, key));
6106
6106
  */
6107
6107
  const get$11 = /*#__PURE__*/ dual(2, (self, key) => Object.hasOwn(self, key) ? some$1(self[key]) : none());
6108
6108
  /**
6109
+ * Removes a key from a record.
6110
+ *
6111
+ * **When to use**
6112
+ *
6113
+ * Use to create a shallow copy of a record without one property.
6114
+ *
6115
+ * **Details**
6116
+ *
6117
+ * If the key is not present, the result is still a shallow copy of the original
6118
+ * record.
6119
+ *
6120
+ * **Example** (Removing a key)
6121
+ *
6122
+ * ```ts import.meta.vitest
6123
+ * import { Record } from "effect"
6124
+ *
6125
+ * Record.remove({ a: 1, b: 2 }, "a") // => { b: 2 }
6126
+ * ```
6127
+ *
6128
+ * @stability stable
6129
+ * @category mutations
6130
+ * @since 2.0.0
6131
+ */
6132
+ const remove$6 = /*#__PURE__*/ dual(2, (self, key) => {
6133
+ if (!has$4(self, key)) return { ...self };
6134
+ const out = { ...self };
6135
+ delete out[key];
6136
+ return out;
6137
+ });
6138
+ /**
6109
6139
  * Maps a record into another record by applying a transformation function to each of its values.
6110
6140
  *
6111
6141
  * **Example** (Mapping record values)
@@ -39547,6 +39577,25 @@ function Redacted$1(value, options) {
39547
39577
  });
39548
39578
  return make$60(schema.ast, { value });
39549
39579
  }
39580
+ /**
39581
+ * Decodes a value and wraps it in `Redacted<A>`. Unlike {@link Redacted} which
39582
+ * expects the input to already be a `Redacted` instance, this schema decodes
39583
+ * the raw value and wraps it.
39584
+ *
39585
+ * @see {@link Redacted} for schemas whose input is already a `Redacted` value.
39586
+ * @stability stable
39587
+ * @category schemas
39588
+ * @since 4.0.0
39589
+ */
39590
+ function RedactedFromValue(value, options) {
39591
+ return decodeTo(Redacted$1(toType(value), {
39592
+ label: options?.label,
39593
+ disallowJsonEncode: options?.disallowEncode
39594
+ }), {
39595
+ decode: transform$3((t) => make$65(t, { label: options?.label })),
39596
+ encode: options?.disallowEncode ? forbidden((oe) => "Cannot encode Redacted" + (isSome(oe) && typeof oe.value.label === "string" ? ` with label: "${oe.value.label}"` : "")) : transform$3(value$2)
39597
+ })(value);
39598
+ }
39550
39599
  const immerable = /*#__PURE__*/ globalThis.Symbol.for("immer-draftable");
39551
39600
  const payloadToken = {};
39552
39601
  function makeClass(Inherited, identifier, struct$1, annotations, proto) {
@@ -53670,6 +53719,14 @@ const compressBody = /*#__PURE__*/ dual((args) => isHttpClientRequest(args[0]),
53670
53719
  return map$5(compressBody$1(self.body, algorithm, options), (body) => body === self.body ? self : makeWith$1(self.method, self.url, self.urlParams, self.hash, set$2(updateContentLength(self.headers, body), "content-encoding", algorithm), body));
53671
53720
  });
53672
53721
  /**
53722
+ * Encodes a value as a JSON request body and sets it on the request, failing with `HttpBodyError` if encoding fails.
53723
+ *
53724
+ * @stability unstable
53725
+ * @category combinators
53726
+ * @since 4.0.0
53727
+ */
53728
+ const bodyJson = /*#__PURE__*/ dual(2, (self, body) => map$5(json$1(body), (body) => setBody$1(self, body)));
53729
+ /**
53673
53730
  * Sets a JSON request body using unsafe JSON encoding.
53674
53731
  *
53675
53732
  * **When to use**
@@ -54224,6 +54281,14 @@ const endSpanWithStatusError = (fiber, span, request, response) => {
54224
54281
  span.end(fiber.getRef(TracerTimingEnabled) ? fiber.getRef(Clock).currentTimeNanosUnsafe() : BigInt(0), exit);
54225
54282
  };
54226
54283
  /**
54284
+ * Appends an effectful transformation of the request object before sending it.
54285
+ *
54286
+ * @stability unstable
54287
+ * @category mapping
54288
+ * @since 4.0.0
54289
+ */
54290
+ const mapRequestEffect = /*#__PURE__*/ dual(2, (self, f) => makeWith(self.postprocess, (request) => flatMap$3(self.preprocess(request), f)));
54291
+ /**
54227
54292
  * Retries common transient errors, such as rate limiting, timeouts or network issues.
54228
54293
  *
54229
54294
  * **When to use**
@@ -88854,6 +88919,71 @@ function failureOptions(error, status) {
88854
88919
  }
88855
88920
  var CurrentUser = class extends Service$2()("@deslop/runtime/auth/lib/utils/CurrentUser") {};
88856
88921
  var RpcAuth = class extends Service$1()("@deslop/runtime/auth/lib/utils/RpcAuth", { error: AuthError }) {};
88922
+ Literals([
88923
+ "anthropic",
88924
+ "openrouter",
88925
+ "opencode-zen",
88926
+ "opencode-go"
88927
+ ]);
88928
+ // ../../packages/runtime/src/ai/service.ts
88929
+ var AiUnavailable = class extends TaggedError()("AiUnavailable", { message: String$6 }) {};
88930
+ fromJsonString(Struct({ error: Struct({ message: String$6 }) }));
88931
+ var AiGateway = class AiGateway extends Service$2()("@deslop/runtime/ai/service/AiGateway") {
88932
+ static layer = effect(this, gen(function* () {
88933
+ const gateway = yield* option(String$5("GATEWAY_URL"));
88934
+ const local = yield* localAuth;
88935
+ const app = yield* String$5("APP_URL");
88936
+ const client = yield* HttpClient;
88937
+ const store = toSchemaStore(yield* KeyValueStore, Record$1(String$6, RedactedFromValue(String$6)));
88938
+ const grants = yield* make$45(getOrElse(yield* store.get("ai-gateway-grants"), () => ({})));
88939
+ const lock = yield* make$72(1);
88940
+ return AiGateway.of({
88941
+ apiUrl: (provider) => match$8(gateway, {
88942
+ onNone: () => fail$6(AiUnavailable.make({ message: "Start the app with --gateway" })),
88943
+ onSome: (url) => succeed$5(`${url}/ai/${provider}${match$1(provider === "openrouter", {
88944
+ onFalse: () => "",
88945
+ onTrue: () => "/v1"
88946
+ })}`)
88947
+ }),
88948
+ authorize: (userId) => (http) => pipe(mapRequestEffect(http, (request) => gen(function* () {
88949
+ if (local) return request;
88950
+ const token = (yield* get$1(grants))[userId];
88951
+ if (token === void 0) return yield* new HttpClientError({ reason: new TransportError({
88952
+ description: "AI access is unavailable; sign in again to enroll with Gateway",
88953
+ request
88954
+ }) });
88955
+ return setHeader$1(request, "authorization", `Bearer ${value$2(token)}`);
88956
+ })), tap((response) => pipe(gen(function* () {
88957
+ if (local || response.headers["x-gateway-grant-refused"] === void 0 || !exists(gateway, (url) => startsWith(`${url}/ai/`)(response.request.url))) return;
88958
+ const current = yield* get$1(grants);
88959
+ const token = current[userId];
88960
+ if (token === void 0 || response.request.headers["authorization"] !== `Bearer ${value$2(token)}`) return;
88961
+ const next = remove$6(current, userId);
88962
+ yield* pipe(store.set("ai-gateway-grants", next), ignore$1({
88963
+ log: "Warn",
88964
+ message: "The rejected AI grant could not be removed from storage"
88965
+ }));
88966
+ yield* set(grants, next);
88967
+ }), withPermit(lock)))),
88968
+ enroll: fnUntraced(function* (userId, headers) {
88969
+ return yield* pipe(gen(function* () {
88970
+ if (local || isNone(gateway) || (yield* get$1(grants))[userId] !== void 0) return;
88971
+ const response = yield* client.execute(yield* bodyJson(post(`${getOrElse(gateway, () => "")}/ai/grants`, { headers: match$1(headers["authorization"] !== void 0, {
88972
+ onFalse: () => ({ cookie: headers["cookie"] ?? "" }),
88973
+ onTrue: () => ({ authorization: headers["authorization"] })
88974
+ }) }), { app }));
88975
+ const result = yield* schemaBodyJson$1(Struct({ token: String$6 }))(response);
88976
+ const next = {
88977
+ ...yield* get$1(grants),
88978
+ [userId]: make$65(result.token)
88979
+ };
88980
+ yield* store.set("ai-gateway-grants", next);
88981
+ yield* set(grants, next);
88982
+ }), withPermit(lock), timeout$1("10 seconds"), catch_$2(() => logWarning("AI Gateway enrollment failed")));
88983
+ })
88984
+ });
88985
+ }));
88986
+ };
88857
88987
  // ../../packages/runtime/src/auth/service.ts
88858
88988
  function rejected(message) {
88859
88989
  return mapError$2((cause) => {
@@ -88872,12 +89002,18 @@ function rejected(message) {
88872
89002
  function developer() {
88873
89003
  return succeed$5(DEVELOPER);
88874
89004
  }
89005
+ function enrolled(user, headers) {
89006
+ return gen(function* () {
89007
+ const gateway = getOrUndefined(yield* context(), AiGateway);
89008
+ if (gateway !== void 0) yield* gateway.enroll(user.id, headers);
89009
+ });
89010
+ }
88875
89011
  const unavailable = text$1("The authorization service is temporarily unavailable; retry later", {
88876
89012
  headers: { "retry-after": "5" },
88877
89013
  status: 503
88878
89014
  });
88879
89015
  var Auth = class Auth extends Service$2()("@deslop/runtime/auth/service/Auth") {
88880
- static makeContext = (auth) => pipe(make$81(Auth, auth), add$3(RpcAuth, RpcAuth.of((effect, request) => pipe(auth.user(request.headers), tap$1(() => {
89016
+ static makeContext = (auth) => pipe(make$81(Auth, auth), add$3(RpcAuth, RpcAuth.of((effect, request) => pipe(auth.user(request.headers), tap$1((user) => enrolled(user, request.headers)), tap$1(() => {
88881
89017
  if (isStreamSchema(request.rpc.successSchema)) return annotateCurrentSpan("rpc.stream", true);
88882
89018
  return void_$1;
88883
89019
  }), flatMap$3((user) => raceFirst(provideService(effect, CurrentUser, user), pipe(delay(auth.user(request.headers), "5 minutes"), retry({ while: (error) => error.error === "temporarily_unavailable" }), forever)))))));
@@ -88912,6 +89048,7 @@ middleware()(gen(function* () {
88912
89048
  if (user.failure.error === "temporarily_unavailable") return unavailable;
88913
89049
  return text$1("Sign in first", { status: 401 });
88914
89050
  }
89051
+ yield* enrolled(user.success, (yield* HttpServerRequest).headers);
88915
89052
  return yield* provideService(app, CurrentUser, user.success);
88916
89053
  });
88917
89054
  }));
@@ -88934,6 +89071,7 @@ function layerMcpAuth(resource) {
88934
89071
  status: 401
88935
89072
  });
88936
89073
  }
89074
+ yield* enrolled(user.success, headers);
88937
89075
  return yield* provideService(app, CurrentUser, user.success);
88938
89076
  });
88939
89077
  })).layer;
@@ -89032,7 +89170,7 @@ function layerKeyValueStore(directory) {
89032
89170
  });
89033
89171
  })), provide$2(layerFileSystem(directory)));
89034
89172
  }
89035
- unwrap$7(map$5(dataDirectory, layerKeyValueStore));
89173
+ const layerDataStore = unwrap$7(map$5(dataDirectory, layerKeyValueStore));
89036
89174
  const layerProtocol = mergeAll$1(layerSchemaBinary(), succeed$6(MaxBodySize)(mebibytes(10)), effect(TracerDisabledWhen, map$5(TracerDisabledWhen, (previous) => (request) => {
89037
89175
  const path = headNonEmpty(split$1(request.url, "?"));
89038
89176
  return previous(request) || path === "/api/rpc" && toLowerCase(request.headers["upgrade"] ?? "") === "websocket" || startsWith("/assets/")(path) || contains([
@@ -89324,6 +89462,11 @@ const SETTINGS = {
89324
89462
  flag: "auth",
89325
89463
  schema: SecureOrigin
89326
89464
  },
89465
+ GATEWAY_URL: {
89466
+ description: "Deslop Gateway origin for AI calls",
89467
+ flag: "gateway",
89468
+ schema: Origin
89469
+ },
89327
89470
  HOST: {
89328
89471
  description: `Listen address; defaults to ${DEFAULT_HOST}`,
89329
89472
  flag: "host",
@@ -89355,7 +89498,7 @@ function server(app) {
89355
89498
  return pipe(serve(pipe(mergeAll$1(app.routes, layerRoutes, layerIcon(app.icon), layerWeb, layerAnnounce), provide$2(match$8(fromUndefinedOr(app.middleware), {
89356
89499
  onNone: () => empty$10,
89357
89500
  onSome: (middleware$1) => middleware()(middleware$1).layer
89358
- })), provide$2(Auth.layer)), {
89501
+ })), provide$2(Auth.layer), provideMerge(pipe(AiGateway.layer, provide$2(layerDataStore)))), {
89359
89502
  disableLogger: true,
89360
89503
  middleware: guard
89361
89504
  }), provide$2(mergeAll$1(layerProtocol, match$1(app.telemetry === false, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deslop/scope",
3
- "version": "0.1.1254",
3
+ "version": "0.1.1256",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/MP281X/deslop.git",
@@ -32,5 +32,5 @@
32
32
  "engines": {
33
33
  "node": ">=26"
34
34
  },
35
- "fingerprint": "27809f25e06673c0c3320e3d058b0cdfad3fdd9cff85e48fc2210a219b8c67f8"
35
+ "fingerprint": "d9fbb4cb322dc4f972433644bd127eb3d2f01072cc4124fabc9d215182f0b30b"
36
36
  }