@deslop/scope 0.1.1100 → 0.1.1102

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 +979 -45
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -3728,6 +3728,38 @@ const isLessThanOrEqualTo$1 = (O) => dual(2, (self, that) => O(self, that) !== 1
3728
3728
  */
3729
3729
  const isGreaterThanOrEqualTo$2 = (O) => dual(2, (self, that) => O(self, that) !== -1);
3730
3730
  /**
3731
+ * Returns the minimum of two values according to the given order. If they are equal, returns the first argument.
3732
+ *
3733
+ * **When to use**
3734
+ *
3735
+ * Use when you need to select the smaller of two values according to an
3736
+ * `Order`.
3737
+ *
3738
+ * **Details**
3739
+ *
3740
+ * Returns the value that compares as less than or equal to the other value. If
3741
+ * values are equal, the first argument is returned.
3742
+ *
3743
+ * **Example** (Selecting the minimum value)
3744
+ *
3745
+ * ```ts import.meta.vitest
3746
+ * import { Order } from "effect"
3747
+ *
3748
+ * const minNumber = Order.min(Order.Number)
3749
+ *
3750
+ * minNumber(1, 2) // => 1
3751
+ * minNumber(2, 1) // => 1
3752
+ * minNumber(1, 1) // => 1
3753
+ * ```
3754
+ *
3755
+ * @see {@link max} for the maximum of two values
3756
+ * @see {@link clamp} to clamp a value between min and max
3757
+ * @stability stable
3758
+ * @category comparisons
3759
+ * @since 2.0.0
3760
+ */
3761
+ const min$1 = (O) => dual(2, (self, that) => self === that || O(self, that) < 1 ? self : that);
3762
+ /**
3731
3763
  * Returns the maximum of two values according to the given order. If they are equal, returns the first argument.
3732
3764
  *
3733
3765
  * **When to use**
@@ -7330,7 +7362,7 @@ const some = /*#__PURE__*/ dual(2, (self, predicate) => self.some(predicate));
7330
7362
  * @category constructors
7331
7363
  * @since 2.0.0
7332
7364
  */
7333
- const unfold = (b, f) => {
7365
+ const unfold$1 = (b, f) => {
7334
7366
  const out = [];
7335
7367
  let next = b;
7336
7368
  while (true) {
@@ -13908,6 +13940,51 @@ const formatIso$1 = (self) => toDateUtc$1(self).toISOString();
13908
13940
  */
13909
13941
  const Number$4 = globalThis.Number;
13910
13942
  /**
13943
+ * Order instance for `number` values.
13944
+ *
13945
+ * **When to use**
13946
+ *
13947
+ * Use when you need to sort or compare numbers through APIs that accept an
13948
+ * ordering instance.
13949
+ *
13950
+ * **Example** (Comparing numbers)
13951
+ *
13952
+ * ```ts import.meta.vitest
13953
+ * import { Number } from "effect"
13954
+ *
13955
+ * Number.Order(1, 2) // => -1
13956
+ * Number.Order(2, 1) // => 1
13957
+ * Number.Order(1, 1) // => 0
13958
+ * ```
13959
+ *
13960
+ * @stability stable
13961
+ * @category instances
13962
+ * @since 2.0.0
13963
+ */
13964
+ const Order$2 = Number$5;
13965
+ /**
13966
+ * Returns the minimum between two `number`s.
13967
+ *
13968
+ * **When to use**
13969
+ *
13970
+ * Use to select the smaller of two numbers.
13971
+ *
13972
+ * **Example** (Finding the minimum)
13973
+ *
13974
+ * ```ts import.meta.vitest
13975
+ * import { Number } from "effect"
13976
+ *
13977
+ * Number.min(2, 3) // => 2
13978
+ * ```
13979
+ *
13980
+ * @see {@link max} for selecting the larger value
13981
+ *
13982
+ * @stability stable
13983
+ * @category math
13984
+ * @since 2.0.0
13985
+ */
13986
+ const min = /*#__PURE__*/ min$1(Order$2);
13987
+ /**
13911
13988
  * Returns the maximum between two `number`s.
13912
13989
  *
13913
13990
  * **When to use**
@@ -13928,7 +14005,31 @@ const Number$4 = globalThis.Number;
13928
14005
  * @category math
13929
14006
  * @since 2.0.0
13930
14007
  */
13931
- const max = /*#__PURE__*/ max$1(Number$5);
14008
+ const max = /*#__PURE__*/ max$1(Order$2);
14009
+ /**
14010
+ * Returns the next power of 2 from the given number.
14011
+ *
14012
+ * **When to use**
14013
+ *
14014
+ * Use to round a number up to the next power of two.
14015
+ *
14016
+ * **Example** (Finding the next power of two)
14017
+ *
14018
+ * ```ts import.meta.vitest
14019
+ * import { Number } from "effect"
14020
+ *
14021
+ * Number.nextPow2(5) // => 8
14022
+ * Number.nextPow2(17) // => 32
14023
+ * ```
14024
+ *
14025
+ * @stability stable
14026
+ * @category math
14027
+ * @since 2.0.0
14028
+ */
14029
+ const nextPow2 = (n) => {
14030
+ const nextPow = Math.ceil(Math.log(n) / Math.log(2));
14031
+ return Math.max(Math.pow(2, nextPow), 2);
14032
+ };
13932
14033
  /**
13933
14034
  * Parses a `number` from a `string` safely using the `Number()` function.
13934
14035
  * The following special string values are supported: "NaN", "Infinity", "-Infinity".
@@ -21199,6 +21300,19 @@ const filter = (self, f) => {
21199
21300
  const remove$2 = (self, value) => filter(self, (v) => v !== value);
21200
21301
  //#endregion
21201
21302
  //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/PubSub.js
21303
+ /**
21304
+ * Broadcasts values from publishers to many subscribers.
21305
+ *
21306
+ * Publishers add messages with `publish` or `publishAll`, and each active
21307
+ * `Subscription` receives its own copy of every accepted message. Unlike a
21308
+ * queue, subscribers do not compete for messages. This module includes bounded,
21309
+ * dropping, sliding, and unbounded hubs, optional replay buffers for late
21310
+ * subscribers, message-taking helpers, capacity and shutdown operations, a
21311
+ * type guard, and low-level types for custom hub strategies.
21312
+ *
21313
+ * @stability stable
21314
+ * @since 2.0.0
21315
+ */
21202
21316
  const TypeId$47 = "~effect/PubSub";
21203
21317
  const SubscriptionTypeId = "~effect/PubSub/Subscription";
21204
21318
  /**
@@ -21232,6 +21346,48 @@ const SubscriptionTypeId = "~effect/PubSub/Subscription";
21232
21346
  */
21233
21347
  const make$62 = (options) => sync(() => makePubSubUnsafe(options.atomicPubSub(), /* @__PURE__ */ new Map(), makeUnsafe$6(), makeUnsafe$4(false), make$64(false), options.strategy(), make$64(none())));
21234
21348
  /**
21349
+ * Creates a bounded `PubSub` with the sliding strategy. The `PubSub` will add new
21350
+ * messages and drop old messages if the `PubSub` is at capacity.
21351
+ *
21352
+ * **Details**
21353
+ *
21354
+ * The capacity must be a positive integer or `Infinity` for unbounded storage.
21355
+ * Invalid capacities cause the effect to die.
21356
+ * For best performance use capacities that are powers of two.
21357
+ *
21358
+ * **Example** (Sliding old messages when full)
21359
+ *
21360
+ * ```ts import.meta.vitest
21361
+ * import { Effect, PubSub } from "effect"
21362
+ *
21363
+ * const program = Effect.scoped(Effect.gen(function*() {
21364
+ * // Create sliding PubSub that evicts old messages when full
21365
+ * const pubsub = yield* PubSub.sliding<string>(3)
21366
+ *
21367
+ * const subscription = yield* PubSub.subscribe(pubsub)
21368
+ *
21369
+ * // Fill and overflow the PubSub
21370
+ * yield* PubSub.publish(pubsub, "msg1")
21371
+ * yield* PubSub.publish(pubsub, "msg2")
21372
+ * yield* PubSub.publish(pubsub, "msg3")
21373
+ * yield* PubSub.publish(pubsub, "msg4") // "msg1" is evicted
21374
+ *
21375
+ * return yield* PubSub.takeAll(subscription)
21376
+ * }))
21377
+ *
21378
+ * const actual = await Effect.runPromise(program)
21379
+ * actual // => ["msg2", "msg3", "msg4"]
21380
+ * ```
21381
+ *
21382
+ * @stability stable
21383
+ * @category constructors
21384
+ * @since 2.0.0
21385
+ */
21386
+ const sliding = (capacity) => make$62({
21387
+ atomicPubSub: () => makeAtomicBounded(capacity),
21388
+ strategy: () => new SlidingStrategy()
21389
+ });
21390
+ /**
21235
21391
  * Creates an unbounded `PubSub`.
21236
21392
  *
21237
21393
  * **Example** (Creating an unbounded PubSub)
@@ -21266,6 +21422,45 @@ const unbounded = (options) => make$62({
21266
21422
  strategy: () => new DroppingStrategy()
21267
21423
  });
21268
21424
  /**
21425
+ * Creates a bounded atomic PubSub implementation with optional replay buffer.
21426
+ *
21427
+ * **When to use**
21428
+ *
21429
+ * Use to provide bounded message storage when building a custom `PubSub` with
21430
+ * `make` and an explicit delivery strategy.
21431
+ *
21432
+ * **Details**
21433
+ *
21434
+ * Pass either a capacity number or an options object with `capacity` and
21435
+ * optional `replay`. A positive `replay` value enables a replay buffer for late
21436
+ * subscribers, and fractional replay sizes are rounded up.
21437
+ *
21438
+ * **Gotchas**
21439
+ *
21440
+ * The capacity must be a positive integer or `Infinity` for unbounded storage;
21441
+ * invalid capacities throw synchronously before an atomic implementation is
21442
+ * created.
21443
+ *
21444
+ * @see {@link make} for constructing a `PubSub` from an atomic implementation and delivery strategy
21445
+ * @see {@link makeAtomicUnbounded} for an atomic implementation without a bounded capacity
21446
+ * @see {@link bounded} for the higher-level backpressure constructor
21447
+ * @see {@link dropping} for the higher-level dropping constructor
21448
+ * @see {@link sliding} for the higher-level sliding constructor
21449
+ *
21450
+ * @stability stable
21451
+ * @category constructors
21452
+ * @since 4.0.0
21453
+ */
21454
+ const makeAtomicBounded = (capacity) => {
21455
+ const options = typeof capacity === "number" ? { capacity } : capacity;
21456
+ ensureCapacity(options.capacity);
21457
+ if (options.capacity === Infinity) return makeAtomicUnbounded(options);
21458
+ const replayBuffer = options.replay && options.replay > 0 ? new ReplayBuffer(Math.ceil(options.replay)) : void 0;
21459
+ if (options.capacity === 1) return new BoundedPubSubSingle(replayBuffer);
21460
+ else if (nextPow2(options.capacity) === options.capacity) return new BoundedPubSubPow2(options.capacity, replayBuffer);
21461
+ else return new BoundedPubSubArb(options.capacity, replayBuffer);
21462
+ };
21463
+ /**
21269
21464
  * Creates an unbounded atomic PubSub implementation with optional replay buffer.
21270
21465
  *
21271
21466
  * **When to use**
@@ -21491,6 +21686,406 @@ const removeSubscribers = (subscribers, subscription, pollers) => {
21491
21686
  if (set.size === 0) subscribers.delete(subscription);
21492
21687
  };
21493
21688
  const makeSubscriptionUnsafe = (pubsub, subscribers, strategy, ended) => new SubscriptionImpl(pubsub, subscribers, pubsub.subscribe(), make$63(), makeUnsafe$4(false), make$64(false), strategy, pubsub.replayWindow(), ended);
21689
+ var BoundedPubSubArb = class {
21690
+ array;
21691
+ replayIndices;
21692
+ publisherIndex = 0;
21693
+ subscribers;
21694
+ subscriberCount = 0;
21695
+ subscribersIndex = 0;
21696
+ capacity;
21697
+ replayBuffer;
21698
+ constructor(capacity, replayBuffer) {
21699
+ this.capacity = capacity;
21700
+ this.replayBuffer = replayBuffer;
21701
+ this.array = Array.from({ length: capacity });
21702
+ this.replayIndices = replayBuffer ? Array.from({ length: capacity }) : [];
21703
+ this.subscribers = Array.from({ length: capacity });
21704
+ }
21705
+ replayWindow() {
21706
+ return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow;
21707
+ }
21708
+ isEmpty() {
21709
+ return this.publisherIndex === this.subscribersIndex;
21710
+ }
21711
+ isFull() {
21712
+ return this.publisherIndex === this.subscribersIndex + this.capacity;
21713
+ }
21714
+ size() {
21715
+ return this.publisherIndex - this.subscribersIndex;
21716
+ }
21717
+ publish(value) {
21718
+ if (this.isFull()) return false;
21719
+ const replayIndex = this.replayBuffer?.offer(value);
21720
+ if (this.subscriberCount !== 0) {
21721
+ const index = this.publisherIndex % this.capacity;
21722
+ this.array[index] = value;
21723
+ if (replayIndex !== void 0) this.replayIndices[index] = replayIndex;
21724
+ this.subscribers[index] = this.subscriberCount;
21725
+ this.publisherIndex += 1;
21726
+ }
21727
+ return true;
21728
+ }
21729
+ publishAll(elements) {
21730
+ if (this.subscriberCount === 0) {
21731
+ if (this.replayBuffer) this.replayBuffer.offerAll(elements);
21732
+ return [];
21733
+ }
21734
+ const chunk = fromIterable$5(elements);
21735
+ const n = chunk.length;
21736
+ const size = this.publisherIndex - this.subscribersIndex;
21737
+ const available = this.capacity - size;
21738
+ const forPubSub = Math.min(n, available);
21739
+ if (forPubSub === 0) return chunk;
21740
+ let iteratorIndex = 0;
21741
+ const publishAllIndex = this.publisherIndex + forPubSub;
21742
+ while (this.publisherIndex !== publishAllIndex) {
21743
+ const a = chunk[iteratorIndex++];
21744
+ const index = this.publisherIndex % this.capacity;
21745
+ this.array[index] = a;
21746
+ const replayIndex = this.replayBuffer?.offer(a);
21747
+ if (replayIndex !== void 0) this.replayIndices[index] = replayIndex;
21748
+ this.subscribers[index] = this.subscriberCount;
21749
+ this.publisherIndex += 1;
21750
+ }
21751
+ return chunk.slice(iteratorIndex);
21752
+ }
21753
+ slide() {
21754
+ if (this.subscribersIndex !== this.publisherIndex) {
21755
+ const index = this.subscribersIndex % this.capacity;
21756
+ const value = this.array[index];
21757
+ this.array[index] = AbsentValue;
21758
+ this.subscribers[index] = 0;
21759
+ this.subscribersIndex += 1;
21760
+ this.replayBuffer?.slide(value, this.replayIndices[index]);
21761
+ }
21762
+ }
21763
+ subscribe() {
21764
+ this.subscriberCount += 1;
21765
+ return new BoundedPubSubArbSubscription(this, this.publisherIndex, false);
21766
+ }
21767
+ };
21768
+ var BoundedPubSubArbSubscription = class {
21769
+ self;
21770
+ subscriberIndex;
21771
+ unsubscribed;
21772
+ constructor(self, subscriberIndex, unsubscribed) {
21773
+ this.self = self;
21774
+ this.subscriberIndex = subscriberIndex;
21775
+ this.unsubscribed = unsubscribed;
21776
+ }
21777
+ isEmpty() {
21778
+ return this.unsubscribed || this.self.publisherIndex === this.subscriberIndex || this.self.publisherIndex === this.self.subscribersIndex;
21779
+ }
21780
+ size() {
21781
+ if (this.unsubscribed) return 0;
21782
+ return this.self.publisherIndex - Math.max(this.subscriberIndex, this.self.subscribersIndex);
21783
+ }
21784
+ poll() {
21785
+ if (this.unsubscribed) return Empty$2;
21786
+ this.subscriberIndex = Math.max(this.subscriberIndex, this.self.subscribersIndex);
21787
+ if (this.subscriberIndex !== this.self.publisherIndex) {
21788
+ const index = this.subscriberIndex % this.self.capacity;
21789
+ const elem = this.self.array[index];
21790
+ this.self.subscribers[index] -= 1;
21791
+ if (this.self.subscribers[index] === 0) {
21792
+ this.self.array[index] = AbsentValue;
21793
+ this.self.subscribersIndex += 1;
21794
+ }
21795
+ this.subscriberIndex += 1;
21796
+ return elem;
21797
+ }
21798
+ return Empty$2;
21799
+ }
21800
+ pollUpTo(n) {
21801
+ n = normalize$1(n);
21802
+ if (this.unsubscribed) return [];
21803
+ this.subscriberIndex = Math.max(this.subscriberIndex, this.self.subscribersIndex);
21804
+ const size = this.self.publisherIndex - this.subscriberIndex;
21805
+ const toPoll = Math.min(n, size);
21806
+ if (toPoll <= 0) return [];
21807
+ const builder = [];
21808
+ const pollUpToIndex = this.subscriberIndex + toPoll;
21809
+ while (this.subscriberIndex !== pollUpToIndex) {
21810
+ const index = this.subscriberIndex % this.self.capacity;
21811
+ const a = this.self.array[index];
21812
+ this.self.subscribers[index] -= 1;
21813
+ if (this.self.subscribers[index] === 0) {
21814
+ this.self.array[index] = AbsentValue;
21815
+ this.self.subscribersIndex += 1;
21816
+ }
21817
+ builder.push(a);
21818
+ this.subscriberIndex += 1;
21819
+ }
21820
+ return builder;
21821
+ }
21822
+ unsubscribe() {
21823
+ if (!this.unsubscribed) {
21824
+ this.unsubscribed = true;
21825
+ this.self.subscriberCount -= 1;
21826
+ this.subscriberIndex = Math.max(this.subscriberIndex, this.self.subscribersIndex);
21827
+ while (this.subscriberIndex !== this.self.publisherIndex) {
21828
+ const index = this.subscriberIndex % this.self.capacity;
21829
+ this.self.subscribers[index] -= 1;
21830
+ if (this.self.subscribers[index] === 0) {
21831
+ this.self.array[index] = AbsentValue;
21832
+ this.self.subscribersIndex += 1;
21833
+ }
21834
+ this.subscriberIndex += 1;
21835
+ }
21836
+ }
21837
+ }
21838
+ };
21839
+ var BoundedPubSubPow2 = class {
21840
+ array;
21841
+ replayIndices;
21842
+ mask;
21843
+ publisherIndex = 0;
21844
+ subscribers;
21845
+ subscriberCount = 0;
21846
+ subscribersIndex = 0;
21847
+ capacity;
21848
+ replayBuffer;
21849
+ constructor(capacity, replayBuffer) {
21850
+ this.capacity = capacity;
21851
+ this.replayBuffer = replayBuffer;
21852
+ this.array = Array.from({ length: capacity });
21853
+ this.replayIndices = replayBuffer ? Array.from({ length: capacity }) : [];
21854
+ this.mask = capacity - 1;
21855
+ this.subscribers = Array.from({ length: capacity });
21856
+ }
21857
+ replayWindow() {
21858
+ return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow;
21859
+ }
21860
+ isEmpty() {
21861
+ return this.publisherIndex === this.subscribersIndex;
21862
+ }
21863
+ isFull() {
21864
+ return this.publisherIndex === this.subscribersIndex + this.capacity;
21865
+ }
21866
+ size() {
21867
+ return this.publisherIndex - this.subscribersIndex;
21868
+ }
21869
+ publish(value) {
21870
+ if (this.isFull()) return false;
21871
+ const replayIndex = this.replayBuffer?.offer(value);
21872
+ if (this.subscriberCount !== 0) {
21873
+ const index = this.publisherIndex & this.mask;
21874
+ this.array[index] = value;
21875
+ if (replayIndex !== void 0) this.replayIndices[index] = replayIndex;
21876
+ this.subscribers[index] = this.subscriberCount;
21877
+ this.publisherIndex += 1;
21878
+ }
21879
+ return true;
21880
+ }
21881
+ publishAll(elements) {
21882
+ if (this.subscriberCount === 0) {
21883
+ if (this.replayBuffer) this.replayBuffer.offerAll(elements);
21884
+ return [];
21885
+ }
21886
+ const chunk = fromIterable$5(elements);
21887
+ const n = chunk.length;
21888
+ const size = this.publisherIndex - this.subscribersIndex;
21889
+ const available = this.capacity - size;
21890
+ const forPubSub = Math.min(n, available);
21891
+ if (forPubSub === 0) return chunk;
21892
+ let iteratorIndex = 0;
21893
+ const publishAllIndex = this.publisherIndex + forPubSub;
21894
+ while (this.publisherIndex !== publishAllIndex) {
21895
+ const elem = chunk[iteratorIndex++];
21896
+ const index = this.publisherIndex & this.mask;
21897
+ this.array[index] = elem;
21898
+ const replayIndex = this.replayBuffer?.offer(elem);
21899
+ if (replayIndex !== void 0) this.replayIndices[index] = replayIndex;
21900
+ this.subscribers[index] = this.subscriberCount;
21901
+ this.publisherIndex += 1;
21902
+ }
21903
+ return chunk.slice(iteratorIndex);
21904
+ }
21905
+ slide() {
21906
+ if (this.subscribersIndex !== this.publisherIndex) {
21907
+ const index = this.subscribersIndex & this.mask;
21908
+ const value = this.array[index];
21909
+ this.array[index] = AbsentValue;
21910
+ this.subscribers[index] = 0;
21911
+ this.subscribersIndex += 1;
21912
+ this.replayBuffer?.slide(value, this.replayIndices[index]);
21913
+ }
21914
+ }
21915
+ subscribe() {
21916
+ this.subscriberCount += 1;
21917
+ return new BoundedPubSubPow2Subscription(this, this.publisherIndex, false);
21918
+ }
21919
+ };
21920
+ var BoundedPubSubPow2Subscription = class {
21921
+ self;
21922
+ subscriberIndex;
21923
+ unsubscribed;
21924
+ constructor(self, subscriberIndex, unsubscribed) {
21925
+ this.self = self;
21926
+ this.subscriberIndex = subscriberIndex;
21927
+ this.unsubscribed = unsubscribed;
21928
+ }
21929
+ isEmpty() {
21930
+ return this.unsubscribed || this.self.publisherIndex === this.subscriberIndex || this.self.publisherIndex === this.self.subscribersIndex;
21931
+ }
21932
+ size() {
21933
+ if (this.unsubscribed) return 0;
21934
+ return this.self.publisherIndex - Math.max(this.subscriberIndex, this.self.subscribersIndex);
21935
+ }
21936
+ poll() {
21937
+ if (this.unsubscribed) return Empty$2;
21938
+ this.subscriberIndex = Math.max(this.subscriberIndex, this.self.subscribersIndex);
21939
+ if (this.subscriberIndex !== this.self.publisherIndex) {
21940
+ const index = this.subscriberIndex & this.self.mask;
21941
+ const elem = this.self.array[index];
21942
+ this.self.subscribers[index] -= 1;
21943
+ if (this.self.subscribers[index] === 0) {
21944
+ this.self.array[index] = AbsentValue;
21945
+ this.self.subscribersIndex += 1;
21946
+ }
21947
+ this.subscriberIndex += 1;
21948
+ return elem;
21949
+ }
21950
+ return Empty$2;
21951
+ }
21952
+ pollUpTo(n) {
21953
+ n = normalize$1(n);
21954
+ if (this.unsubscribed) return [];
21955
+ this.subscriberIndex = Math.max(this.subscriberIndex, this.self.subscribersIndex);
21956
+ const size = this.self.publisherIndex - this.subscriberIndex;
21957
+ const toPoll = Math.min(n, size);
21958
+ if (toPoll <= 0) return [];
21959
+ const builder = [];
21960
+ const pollUpToIndex = this.subscriberIndex + toPoll;
21961
+ while (this.subscriberIndex !== pollUpToIndex) {
21962
+ const index = this.subscriberIndex & this.self.mask;
21963
+ const elem = this.self.array[index];
21964
+ this.self.subscribers[index] -= 1;
21965
+ if (this.self.subscribers[index] === 0) {
21966
+ this.self.array[index] = AbsentValue;
21967
+ this.self.subscribersIndex += 1;
21968
+ }
21969
+ builder.push(elem);
21970
+ this.subscriberIndex += 1;
21971
+ }
21972
+ return builder;
21973
+ }
21974
+ unsubscribe() {
21975
+ if (!this.unsubscribed) {
21976
+ this.unsubscribed = true;
21977
+ this.self.subscriberCount -= 1;
21978
+ this.subscriberIndex = Math.max(this.subscriberIndex, this.self.subscribersIndex);
21979
+ while (this.subscriberIndex !== this.self.publisherIndex) {
21980
+ const index = this.subscriberIndex & this.self.mask;
21981
+ this.self.subscribers[index] -= 1;
21982
+ if (this.self.subscribers[index] === 0) {
21983
+ this.self.array[index] = AbsentValue;
21984
+ this.self.subscribersIndex += 1;
21985
+ }
21986
+ this.subscriberIndex += 1;
21987
+ }
21988
+ }
21989
+ }
21990
+ };
21991
+ var BoundedPubSubSingle = class {
21992
+ publisherIndex = 0;
21993
+ subscriberCount = 0;
21994
+ subscribers = 0;
21995
+ value = AbsentValue;
21996
+ replayIndex = 0;
21997
+ capacity = 1;
21998
+ replayBuffer;
21999
+ constructor(replayBuffer) {
22000
+ this.replayBuffer = replayBuffer;
22001
+ }
22002
+ replayWindow() {
22003
+ return this.replayBuffer ? new ReplayWindowImpl(this.replayBuffer) : emptyReplayWindow;
22004
+ }
22005
+ pipe() {
22006
+ return pipeArguments(this, arguments);
22007
+ }
22008
+ isEmpty() {
22009
+ return this.subscribers === 0;
22010
+ }
22011
+ isFull() {
22012
+ return !this.isEmpty();
22013
+ }
22014
+ size() {
22015
+ return this.isEmpty() ? 0 : 1;
22016
+ }
22017
+ publish(value) {
22018
+ if (this.isFull()) return false;
22019
+ const replayIndex = this.replayBuffer?.offer(value);
22020
+ if (this.subscriberCount !== 0) {
22021
+ this.value = value;
22022
+ if (replayIndex !== void 0) this.replayIndex = replayIndex;
22023
+ this.subscribers = this.subscriberCount;
22024
+ this.publisherIndex += 1;
22025
+ }
22026
+ return true;
22027
+ }
22028
+ publishAll(elements) {
22029
+ if (this.subscriberCount === 0) {
22030
+ if (this.replayBuffer) this.replayBuffer.offerAll(elements);
22031
+ return [];
22032
+ }
22033
+ const chunk = fromIterable$5(elements);
22034
+ if (chunk.length === 0) return chunk;
22035
+ if (this.publish(chunk[0])) return chunk.slice(1);
22036
+ else return chunk;
22037
+ }
22038
+ slide() {
22039
+ if (this.isFull()) {
22040
+ const value = this.value;
22041
+ this.subscribers = 0;
22042
+ this.value = AbsentValue;
22043
+ this.replayBuffer?.slide(value, this.replayIndex);
22044
+ }
22045
+ }
22046
+ subscribe() {
22047
+ this.subscriberCount += 1;
22048
+ return new BoundedPubSubSingleSubscription(this, this.publisherIndex, false);
22049
+ }
22050
+ };
22051
+ var BoundedPubSubSingleSubscription = class {
22052
+ self;
22053
+ subscriberIndex;
22054
+ unsubscribed;
22055
+ constructor(self, subscriberIndex, unsubscribed) {
22056
+ this.self = self;
22057
+ this.subscriberIndex = subscriberIndex;
22058
+ this.unsubscribed = unsubscribed;
22059
+ }
22060
+ isEmpty() {
22061
+ return this.unsubscribed || this.self.subscribers === 0 || this.subscriberIndex === this.self.publisherIndex;
22062
+ }
22063
+ size() {
22064
+ return this.isEmpty() ? 0 : 1;
22065
+ }
22066
+ poll() {
22067
+ if (this.isEmpty()) return Empty$2;
22068
+ const elem = this.self.value;
22069
+ this.self.subscribers -= 1;
22070
+ if (this.self.subscribers === 0) this.self.value = AbsentValue;
22071
+ this.subscriberIndex = this.self.publisherIndex;
22072
+ return elem;
22073
+ }
22074
+ pollUpTo(n) {
22075
+ if (normalize$1(n) < 1 || this.isEmpty()) return [];
22076
+ return [this.poll()];
22077
+ }
22078
+ unsubscribe() {
22079
+ if (!this.unsubscribed) {
22080
+ this.unsubscribed = true;
22081
+ this.self.subscriberCount -= 1;
22082
+ if (this.self.subscribers !== 0 && this.subscriberIndex !== this.self.publisherIndex) {
22083
+ this.self.subscribers -= 1;
22084
+ if (this.self.subscribers === 0) this.self.value = AbsentValue;
22085
+ }
22086
+ }
22087
+ }
22088
+ };
21494
22089
  var UnboundedPubSub = class {
21495
22090
  publisherHead = {
21496
22091
  value: AbsentValue,
@@ -21686,6 +22281,9 @@ var PubSubImpl = class {
21686
22281
  }
21687
22282
  };
21688
22283
  const makePubSubUnsafe = (pubsub, subscribers, scope, shutdownHook, shutdownFlag, strategy, ended) => new PubSubImpl(pubsub, subscribers, scope, shutdownHook, shutdownFlag, strategy, ended);
22284
+ const ensureCapacity = (capacity) => {
22285
+ if (capacity <= 0 || capacity !== Infinity && !Number.isInteger(capacity)) throw new Error(`Cannot construct PubSub with capacity of ${capacity}`);
22286
+ };
21689
22287
  /**
21690
22288
  * Represents the dropping strategy for bounded `PubSub` values.
21691
22289
  *
@@ -21750,6 +22348,89 @@ var DroppingStrategy = class {
21750
22348
  return strategyCompleteSubscribersUnsafe(this, pubsub, subscribers);
21751
22349
  }
21752
22350
  };
22351
+ /**
22352
+ * Represents the sliding strategy for bounded `PubSub` values.
22353
+ *
22354
+ * **When to use**
22355
+ *
22356
+ * Use to keep the most recent messages when the `PubSub` is at capacity.
22357
+ *
22358
+ * **Details**
22359
+ *
22360
+ * New messages are accepted by evicting older messages from the bounded
22361
+ * `PubSub`.
22362
+ *
22363
+ * **Gotchas**
22364
+ *
22365
+ * Slow subscribers may miss older messages that are evicted before they are
22366
+ * consumed.
22367
+ *
22368
+ * **Example** (Applying a sliding strategy)
22369
+ *
22370
+ * ```ts import.meta.vitest
22371
+ * import { Effect, PubSub } from "effect"
22372
+ *
22373
+ * const program = Effect.scoped(Effect.gen(function*() {
22374
+ * // Explicitly create a PubSub with a sliding strategy
22375
+ * const pubsub = yield* PubSub.make<string>({
22376
+ * atomicPubSub: () => PubSub.makeAtomicBounded(2),
22377
+ * strategy: () => new PubSub.SlidingStrategy()
22378
+ * })
22379
+ *
22380
+ * const subscription = yield* PubSub.subscribe(pubsub)
22381
+ *
22382
+ * // Publish messages that exceed capacity
22383
+ * yield* PubSub.publish(pubsub, "msg1") // stored
22384
+ * yield* PubSub.publish(pubsub, "msg2") // stored
22385
+ * yield* PubSub.publish(pubsub, "msg3") // "msg1" evicted, "msg3" stored
22386
+ * yield* PubSub.publish(pubsub, "msg4") // "msg2" evicted, "msg4" stored
22387
+ *
22388
+ * // Subscribers will see the most recent messages
22389
+ * return yield* PubSub.takeAll(subscription)
22390
+ * }))
22391
+ *
22392
+ * const actual = await Effect.runPromise(program)
22393
+ * actual // => ["msg3", "msg4"]
22394
+ * ```
22395
+ *
22396
+ * @stability stable
22397
+ * @category models
22398
+ * @since 4.0.0
22399
+ */
22400
+ var SlidingStrategy = class {
22401
+ get shutdown() {
22402
+ return void_$1;
22403
+ }
22404
+ handleSurplus(pubsub, subscribers, elements, _isShutdown, ended) {
22405
+ return sync(() => {
22406
+ if (isSome(ended.current)) return false;
22407
+ this.slidingPublishUnsafe(pubsub, elements);
22408
+ this.completeSubscribersUnsafe(pubsub, subscribers);
22409
+ return true;
22410
+ });
22411
+ }
22412
+ onPubSubEmptySpaceUnsafe(_pubsub, _subscribers) {}
22413
+ completePollersUnsafe(pubsub, subscribers, subscription, pollers) {
22414
+ return strategyCompletePollersUnsafe(this, pubsub, subscribers, subscription, pollers);
22415
+ }
22416
+ completeSubscribersUnsafe(pubsub, subscribers) {
22417
+ return strategyCompleteSubscribersUnsafe(this, pubsub, subscribers);
22418
+ }
22419
+ slidingPublishUnsafe(pubsub, elements) {
22420
+ const it = elements[Symbol.iterator]();
22421
+ let next = it.next();
22422
+ if (!next.done && pubsub.capacity > 0) {
22423
+ let a = next.value;
22424
+ let loop = true;
22425
+ while (loop) {
22426
+ pubsub.slide();
22427
+ const pub = pubsub.publish(a);
22428
+ if (pub && (next = it.next()) && !next.done) a = next.value;
22429
+ else if (pub) loop = false;
22430
+ }
22431
+ }
22432
+ }
22433
+ };
21753
22434
  const strategyCompletePollersUnsafe = (strategy, pubsub, subscribers, subscription, pollers) => {
21754
22435
  let keepPolling = true;
21755
22436
  while (keepPolling && !subscription.isEmpty()) {
@@ -25554,6 +26235,41 @@ const fromQueue = (queue) => fromChannel(fromQueueArray(queue));
25554
26235
  */
25555
26236
  const fromReadableStream = (options) => fromChannel(fromReadableStream$1(options));
25556
26237
  /**
26238
+ * Creates a stream by repeatedly applying an effectful step function to a
26239
+ * state.
26240
+ *
26241
+ * **Details**
26242
+ *
26243
+ * Each `readonly [value, nextState]` result emits `value` and continues with
26244
+ * `nextState`; returning `undefined` ends the stream.
26245
+ *
26246
+ * **Example** (Unfolding stream state)
26247
+ *
26248
+ * ```ts import.meta.vitest
26249
+ * import { Effect, Stream } from "effect"
26250
+ *
26251
+ * const program = Effect.gen(function*() {
26252
+ * const stream = Stream.unfold(1, (n) => Effect.succeed([n, n + 1] as const))
26253
+ * const values = yield* Stream.runCollect(stream.pipe(Stream.take(5)))
26254
+ * values // => [ 1, 2, 3, 4, 5 ]
26255
+ * })
26256
+ *
26257
+ * await Effect.runPromise(program)
26258
+ * ```
26259
+ *
26260
+ * @stability stable
26261
+ * @category constructors
26262
+ * @since 2.0.0
26263
+ */
26264
+ const unfold = (s, f) => fromPull(sync(() => {
26265
+ let state = s;
26266
+ return flatMap$1(suspend$2(() => f(state)), (next) => {
26267
+ if (next === void 0) return done();
26268
+ state = next[1];
26269
+ return succeed$4(of(next[0]));
26270
+ });
26271
+ }));
26272
+ /**
25557
26273
  * Creates a stream produced from an `Effect`.
25558
26274
  *
25559
26275
  * **Example** (Unwrapping a stream effect)
@@ -25753,6 +26469,53 @@ const mapError = /*#__PURE__*/ dual(2, (self, f) => fromChannel(mapError$1(self.
25753
26469
  */
25754
26470
  const orDie = (self) => fromChannel(orDie$1(self.channel));
25755
26471
  /**
26472
+ * Takes elements until the predicate matches.
26473
+ *
26474
+ * **Details**
26475
+ *
26476
+ * When `excludeLast` is `true`, the matching element is dropped.
26477
+ *
26478
+ * **Example** (Taking until a predicate matches)
26479
+ *
26480
+ * ```ts import.meta.vitest
26481
+ * import { Effect, Stream } from "effect"
26482
+ *
26483
+ * const stream = Stream.range(1, 5)
26484
+ *
26485
+ * const program = Effect.gen(function*() {
26486
+ * const inclusive = yield* stream.pipe(
26487
+ * Stream.takeUntil((n) => n % 3 === 0),
26488
+ * Stream.runCollect
26489
+ * )
26490
+ * inclusive // => [ 1, 2, 3 ]
26491
+ *
26492
+ * const exclusive = yield* stream.pipe(
26493
+ * Stream.takeUntil((n) => n % 3 === 0, { excludeLast: true }),
26494
+ * Stream.runCollect
26495
+ * )
26496
+ * exclusive // => [ 1, 2 ]
26497
+ * })
26498
+ * await Effect.runPromise(program)
26499
+ * ```
26500
+ *
26501
+ * @stability stable
26502
+ * @category filtering
26503
+ * @since 2.0.0
26504
+ */
26505
+ const takeUntil = /*#__PURE__*/ dual((args) => isStream(args[0]), (self, predicate, options) => transformPull(self, (pull, _scope) => sync(() => {
26506
+ let i = 0;
26507
+ let done$8 = false;
26508
+ return flatMap$1(suspend$2(() => done$8 ? done() : pull), (chunk) => {
26509
+ const index = chunk.findIndex((a) => predicate(a, i++));
26510
+ if (index >= 0) {
26511
+ done$8 = true;
26512
+ const arr = chunk.slice(0, options?.excludeLast ? index : index + 1);
26513
+ return isReadonlyArrayNonEmpty(arr) ? succeed$4(arr) : done();
26514
+ }
26515
+ return succeed$4(chunk);
26516
+ });
26517
+ })));
26518
+ /**
25756
26519
  * Drops the first `n` elements from this stream.
25757
26520
  *
25758
26521
  * **Details**
@@ -35886,6 +36649,35 @@ function toRepresentations(asts, options) {
35886
36649
  //#endregion
35887
36650
  //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/Struct.js
35888
36651
  /**
36652
+ * Creates a new struct containing only the specified keys.
36653
+ *
36654
+ * **When to use**
36655
+ *
36656
+ * Use to narrow a struct down to a subset of its properties.
36657
+ *
36658
+ * **Gotchas**
36659
+ *
36660
+ * Keys not present in the struct are silently ignored.
36661
+ *
36662
+ * **Example** (Selecting specific properties)
36663
+ *
36664
+ * ```ts import.meta.vitest
36665
+ * import { pipe, Struct } from "effect"
36666
+ *
36667
+ * const user = { name: "Alice", age: 30, admin: true }
36668
+ * pipe(user, Struct.pick(["name", "age"])) // => { name: "Alice", age: 30 }
36669
+ * ```
36670
+ *
36671
+ * @see {@link omit} – the inverse (exclude keys instead)
36672
+ * @see {@link get} – extract a single value
36673
+ * @stability stable
36674
+ * @category filtering
36675
+ * @since 2.0.0
36676
+ */
36677
+ const pick = /*#__PURE__*/ dual(2, (self, keys) => {
36678
+ return buildStruct(self, (k, v) => hasPropertyKey(keys, k) ? [k, v] : void 0);
36679
+ });
36680
+ /**
35889
36681
  * Creates a new struct with the specified keys removed.
35890
36682
  *
35891
36683
  * **When to use**
@@ -66247,17 +67039,31 @@ const Resource$1 = Literals([
66247
67039
  "https://portfolio.mp281x.xyz/mcp",
66248
67040
  "https://otel.mp281x.xyz"
66249
67041
  ]);
66250
- const Authorization = Struct({
67042
+ const authorizationFields = {
66251
67043
  challenge: NonEmptyString,
66252
67044
  clientId: NonEmptyString,
66253
67045
  redirectUri: NonEmptyString,
66254
67046
  resources: ArraySchema(Resource$1),
66255
67047
  state: NonEmptyString
66256
- });
67048
+ };
66257
67049
  const Registration = Struct({
67050
+ client_name: optionalKey(String$2.check(isMaxLength(100))),
66258
67051
  redirect_uris: NonEmptyArray(NonEmptyString),
66259
67052
  token_endpoint_auth_method: optionalKey(Literal("none"))
66260
67053
  });
67054
+ const PendingAuthorization = Struct({
67055
+ clientName: String$2,
67056
+ createdAt: Finite,
67057
+ expiresAt: Finite,
67058
+ id: NonEmptyString,
67059
+ redirectUri: NonEmptyString,
67060
+ resources: ArraySchema(Resource$1)
67061
+ });
67062
+ const AuthorizationStatus = TaggedUnion({
67063
+ Completed: { url: NonEmptyString },
67064
+ Expired: {},
67065
+ Waiting: { request: PendingAuthorization }
67066
+ });
66261
67067
  const AuthorizeParams = Struct({
66262
67068
  client_id: NonEmptyString,
66263
67069
  code_challenge: NonEmptyString,
@@ -66287,11 +67093,18 @@ const Stored = TaggedUnion({
66287
67093
  resources: ArraySchema(Resource$1),
66288
67094
  user: User
66289
67095
  },
66290
- Client: { redirects: NonEmptyArray(NonEmptyString) },
67096
+ Client: {
67097
+ name: optionalKey(String$2),
67098
+ redirects: NonEmptyArray(NonEmptyString)
67099
+ },
66291
67100
  Code: {
66292
- ...Authorization.fields,
67101
+ ...authorizationFields,
66293
67102
  user: User
66294
67103
  },
67104
+ Delivered: {
67105
+ id: NonEmptyString,
67106
+ url: NonEmptyString
67107
+ },
66295
67108
  Login: {
66296
67109
  request: optionalKey(NonEmptyString),
66297
67110
  verifier: NonEmptyString
@@ -66302,7 +67115,17 @@ const Stored = TaggedUnion({
66302
67115
  resources: ArraySchema(Resource$1),
66303
67116
  user: User
66304
67117
  },
66305
- Request: Authorization.fields,
67118
+ Request: {
67119
+ ...authorizationFields,
67120
+ clientName: String$2,
67121
+ createdAt: Finite,
67122
+ decision: TaggedUnion({
67123
+ Approved: { user: User },
67124
+ Denied: {},
67125
+ Pending: {}
67126
+ }),
67127
+ id: NonEmptyString
67128
+ },
66306
67129
  Session: { user: User },
66307
67130
  UsedRefresh: {
66308
67131
  clientId: NonEmptyString,
@@ -66310,6 +67133,11 @@ const Stored = TaggedUnion({
66310
67133
  }
66311
67134
  });
66312
67135
  const StoredRow = Struct({ payload: String$2 });
67136
+ const AuthorizationRow = Struct({
67137
+ expiresAt: Finite,
67138
+ hash: String$2,
67139
+ payload: String$2
67140
+ });
66313
67141
  const RequestParams = Struct({ request: NonEmptyString });
66314
67142
  const SignInParams = Struct({ request: optionalKey(NonEmptyString) });
66315
67143
  const ConsentParams = Struct({
@@ -66341,7 +67169,6 @@ Struct({
66341
67169
  expires_in: Finite,
66342
67170
  refresh_token: NonEmptyString
66343
67171
  });
66344
- Struct({ url: NonEmptyString });
66345
67172
  const VerificationParams = Struct({ resource: Resource$1 });
66346
67173
  //#endregion
66347
67174
  //#region ../../packages/auth/src/lib/utils.ts
@@ -66359,7 +67186,7 @@ var RpcAuth = class RpcAuth extends Service$1()("@deslop/auth/lib/utils/RpcAuth"
66359
67186
  //#region ../../packages/auth/src/service.ts
66360
67187
  const SESSION_COOKIE = "__Secure-session";
66361
67188
  const LOGIN_COOKIE = "__Host-login";
66362
- const REQUEST_COOKIE = "__Host-request";
67189
+ const REQUEST_COOKIE = "__Host-request-";
66363
67190
  const COOKIE = {
66364
67191
  httpOnly: true,
66365
67192
  path: "/",
@@ -66391,6 +67218,7 @@ function allowedRedirect(redirect) {
66391
67218
  onSuccess: (target) => target.protocol === "http:" && (target.hostname === "127.0.0.1" || target.hostname === "localhost") && isEmpty$1(target.username) && isEmpty$1(target.password) && isEmpty$1(target.search) && isEmpty$1(target.hash)
66392
67219
  });
66393
67220
  }
67221
+ var Authorizations = class extends Service$2()("@deslop/auth/service/Authorizations") {};
66394
67222
  var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66395
67223
  static layer = (resource) => effectContext(gen(function* () {
66396
67224
  const url = yield* pipe(String$1("AUTH_URL"), withDefault(AUTH_URL));
@@ -66414,6 +67242,7 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66414
67242
  static layerIssuer = pipe(effectContext(gen(function* () {
66415
67243
  const sql = yield* SqliteClient;
66416
67244
  const random = yield* Crypto;
67245
+ const changes = yield* sliding(1);
66417
67246
  const router = yield* HttpRouter;
66418
67247
  const client = filterStatusOk(yield* HttpClient);
66419
67248
  const url = yield* pipe(String$1("AUTH_URL"), withDefault(AUTH_URL));
@@ -66424,6 +67253,7 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66424
67253
  users: Array$1(String$2, "GITHUB_USERS")
66425
67254
  });
66426
67255
  yield* sql`CREATE TABLE IF NOT EXISTS auth_state (hash TEXT PRIMARY KEY, payload TEXT NOT NULL, expires_at INTEGER NOT NULL)`;
67256
+ yield* sql`DELETE FROM auth_state WHERE json_extract(payload, '$._tag') = 'Request' AND json_extract(payload, '$.id') IS NULL`;
66427
67257
  const hash = fnUntraced(function* (value) {
66428
67258
  return encode(yield* random.digest("SHA-256", new TextEncoder().encode(value)));
66429
67259
  });
@@ -66464,18 +67294,128 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66464
67294
  if (stored._tag !== "Access" || !some(stored.resources, (value) => value === resource)) return yield* AuthError.make({ message: "The token is not valid for this app" });
66465
67295
  return yield* allowed(stored.user);
66466
67296
  }, rejected("Sign in first"));
66467
- const sameOrigin = gen(function* () {
66468
- if ((yield* HttpServerRequest).headers["origin"] !== new URL(url).origin) return yield* AuthError.make({
67297
+ const checkOrigin = fnUntraced(function* (headers) {
67298
+ if (headers["origin"] !== new URL(url).origin) return yield* AuthError.make({
66469
67299
  error: "access_denied",
66470
67300
  message: "The request comes from another origin"
66471
67301
  });
66472
67302
  });
67303
+ const sameOrigin = flatMap$1(HttpServerRequest, (request) => checkOrigin(request.headers));
67304
+ const requestRow = fnUntraced(function* (id) {
67305
+ return yield* pipe(sql`SELECT hash, payload, expires_at AS "expiresAt" FROM auth_state WHERE json_extract(payload, '$.id') = ${id} AND expires_at > ${yield* currentTimeMillis}`, flatMap$1(decodeUnknownEffect(ArraySchema(AuthorizationRow))), map$2(head));
67306
+ });
66473
67307
  const requestState = fnUntraced(function* (id) {
66474
- if ((yield* HttpServerRequest).cookies[REQUEST_COOKIE] !== id) return yield* AuthError.make({ message: "Open the authorization link again" });
66475
- const stored = yield* load(id);
67308
+ const row = yield* fromOption(yield* requestRow(id));
67309
+ const stored = yield* decodeEffect(fromJsonString(Stored))(row.payload);
66476
67310
  if (stored._tag !== "Request") return yield* AuthError.make({ message: "The authorization request expired" });
66477
67311
  return stored;
67312
+ }, rejected("The authorization request expired"));
67313
+ const receiver = fnUntraced(function* (id, headers) {
67314
+ const token = parseHeader(headers["cookie"] ?? "")[`${REQUEST_COOKIE}${id}`];
67315
+ if (token === void 0) return yield* AuthError.make({ message: "Open the authorization link again" });
67316
+ return yield* match$4(yield* requestRow(id), {
67317
+ onNone: () => succeedNone,
67318
+ onSome: fnUntraced(function* (row) {
67319
+ if (row.hash !== (yield* hash(token))) return yield* AuthError.make({ message: "The authorization belongs to another browser" });
67320
+ return some$1(row);
67321
+ })
67322
+ });
66478
67323
  });
67324
+ function watch(read, expires) {
67325
+ return unwrap$2(gen(function* () {
67326
+ const subscription = yield* subscribe(changes);
67327
+ return unfold(none(), (previous) => gen(function* () {
67328
+ yield* match$4(previous, {
67329
+ onNone: () => void_$1,
67330
+ onSome: (expiresAt) => raceFirst(take$1(subscription), match(expiresAt === Infinity, {
67331
+ onFalse: () => flatMap$1(currentTimeMillis, (now) => sleep(max(0, expiresAt - now))),
67332
+ onTrue: () => never$1
67333
+ }))
67334
+ });
67335
+ const value = yield* read;
67336
+ return [value, some$1(expires(value))];
67337
+ }));
67338
+ }));
67339
+ }
67340
+ function publicRequest(request, expiresAt) {
67341
+ return {
67342
+ ...pipe(request, pick([
67343
+ "clientName",
67344
+ "createdAt",
67345
+ "id",
67346
+ "redirectUri",
67347
+ "resources"
67348
+ ])),
67349
+ expiresAt
67350
+ };
67351
+ }
67352
+ const pending = fnUntraced(function* (headers) {
67353
+ yield* session(headers);
67354
+ const rows = yield* pipe(sql`SELECT payload, hash, expires_at AS "expiresAt" FROM auth_state WHERE json_extract(payload, '$._tag') = 'Request' AND json_extract(payload, '$.decision._tag') = 'Pending' AND expires_at > ${yield* currentTimeMillis} ORDER BY json_extract(payload, '$.createdAt') DESC, hash`, flatMap$1(decodeUnknownEffect(ArraySchema(AuthorizationRow))));
67355
+ return yield* forEach$1(rows, fnUntraced(function* (row) {
67356
+ return publicRequest(yield* decodeEffect(fromJsonString(Stored.cases.Request))(row.payload), row.expiresAt);
67357
+ }), { concurrency: 1 });
67358
+ }, rejected("Cannot read pending authorizations"));
67359
+ const respond = fn("Authorizations.respond")(function* (params, headers) {
67360
+ yield* checkOrigin(headers);
67361
+ const user = yield* session(headers);
67362
+ yield* sql.withTransaction(gen(function* () {
67363
+ const request = yield* requestState(params.request);
67364
+ if (request.decision._tag !== "Pending") return yield* AuthError.make({ message: "This authorization has already been answered" });
67365
+ yield* sql`UPDATE auth_state SET payload = ${yield* encodeEffect(fromJsonString(Stored))({
67366
+ ...request,
67367
+ decision: match(params.accept, {
67368
+ onFalse: () => ({ _tag: "Denied" }),
67369
+ onTrue: () => ({
67370
+ _tag: "Approved",
67371
+ user
67372
+ })
67373
+ })
67374
+ })} WHERE json_extract(payload, '$.id') = ${params.request}`;
67375
+ }));
67376
+ yield* publish(changes, true);
67377
+ }, rejected("Cannot answer the authorization request"));
67378
+ const receive = fnUntraced(function* (id, headers) {
67379
+ return yield* sql.withTransaction(flatMap$1(receiver(id, headers), (result) => match$4(result, {
67380
+ onNone: () => succeed$4(AuthorizationStatus.make({ _tag: "Expired" })),
67381
+ onSome: fnUntraced(function* (row) {
67382
+ const request = yield* decodeEffect(fromJsonString(Stored))(row.payload);
67383
+ if (request._tag === "Delivered") return AuthorizationStatus.make({
67384
+ _tag: "Completed",
67385
+ url: request.url
67386
+ });
67387
+ if (request._tag !== "Request") return yield* AuthError.make({ message: "Invalid authorization request" });
67388
+ if (request.decision._tag === "Pending") return AuthorizationStatus.make({
67389
+ _tag: "Waiting",
67390
+ request: publicRequest(request, row.expiresAt)
67391
+ });
67392
+ const target = new URL(request.redirectUri);
67393
+ target.searchParams.set("state", request.state);
67394
+ target.searchParams.set("iss", issuer);
67395
+ if (request.decision._tag === "Approved") target.searchParams.set("code", yield* save({
67396
+ ...pipe(request, pick([
67397
+ "challenge",
67398
+ "clientId",
67399
+ "redirectUri",
67400
+ "resources",
67401
+ "state"
67402
+ ])),
67403
+ _tag: "Code",
67404
+ user: request.decision.user
67405
+ }, 60));
67406
+ else target.searchParams.set("error", "access_denied");
67407
+ yield* sql`UPDATE auth_state SET payload = ${yield* encodeEffect(fromJsonString(Stored))({
67408
+ _tag: "Delivered",
67409
+ id,
67410
+ url: target.href
67411
+ })}, expires_at = ${yield* currentTimeMillis} + 60000 WHERE hash = ${row.hash}`;
67412
+ return AuthorizationStatus.make({
67413
+ _tag: "Completed",
67414
+ url: target.href
67415
+ });
67416
+ })
67417
+ })));
67418
+ }, rejected("Cannot complete the authorization request"));
66479
67419
  const grantTokens = fnUntraced(function* (grant, resources) {
66480
67420
  yield* allowed(grant.user);
66481
67421
  const seconds = match(contains(resources, "https://stash.mp281x.xyz"), {
@@ -66525,6 +67465,7 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66525
67465
  return jsonUnsafe({
66526
67466
  client_id: yield* save({
66527
67467
  _tag: "Client",
67468
+ name: params.client_name ?? "Unknown client",
66528
67469
  redirects: params.redirect_uris
66529
67470
  }, 31536e3),
66530
67471
  grant_types: ["authorization_code", "refresh_token"],
@@ -66533,7 +67474,7 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66533
67474
  token_endpoint_auth_method: "none"
66534
67475
  }, { status: 201 });
66535
67476
  })));
66536
- yield* router.add("GET", "/api/auth/oauth2/authorize", oauth(gen(function* () {
67477
+ yield* router.add("GET", "/api/auth/oauth2/authorize", oauth(pipe(sql.withTransaction(gen(function* () {
66537
67478
  const params = yield* pipe(schemaSearchParams(AuthorizeParams), rejected("Invalid authorization request"));
66538
67479
  const registration = yield* load(params.client_id);
66539
67480
  if (registration._tag !== "Client" || !contains(registration.redirects, params.redirect_uri)) return yield* AuthError.make({
@@ -66544,40 +67485,30 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66544
67485
  error: "invalid_scope",
66545
67486
  message: "Only Deslop access is supported"
66546
67487
  });
66547
- const id = yield* save({
67488
+ const now = yield* currentTimeMillis;
67489
+ const id = encode(yield* random.randomBytes(16));
67490
+ const token = yield* save({
66548
67491
  _tag: "Request",
66549
67492
  challenge: params.code_challenge,
66550
67493
  clientId: params.client_id,
67494
+ clientName: registration.name ?? "Unknown client",
67495
+ createdAt: now,
67496
+ decision: { _tag: "Pending" },
67497
+ id,
66551
67498
  redirectUri: params.redirect_uri,
66552
67499
  resources: params.resource,
66553
67500
  state: params.state
66554
- }, 600);
66555
- return setCookieUnsafe(redirect(`/?request=${id}`), REQUEST_COOKIE, id, {
67501
+ }, 240);
67502
+ return setCookieUnsafe(redirect(`/?request=${id}`), `${REQUEST_COOKIE}${id}`, token, {
66556
67503
  ...COOKIE,
66557
- maxAge: "10 minutes"
67504
+ maxAge: "5 minutes"
66558
67505
  });
66559
- })));
66560
- yield* router.add("GET", "/auth/request", oauth(gen(function* () {
66561
- const params = yield* pipe(schemaSearchParams(RequestParams), rejected("Open the authorization link again"));
66562
- return yield* schemaJson(Authorization)(yield* requestState(params.request));
66563
- })));
66564
- yield* router.add("POST", "/api/auth/oauth2/consent", oauth(sql.withTransaction(gen(function* () {
66565
- yield* sameOrigin;
67506
+ })), tap(() => publish(changes, true)))));
67507
+ yield* router.add("POST", "/api/auth/oauth2/consent", oauth(gen(function* () {
66566
67508
  const params = yield* pipe(schemaBodyJson(ConsentParams), rejected("Invalid authorization response"));
66567
- const grant = yield* requestState(params.request);
66568
- const user = yield* session((yield* HttpServerRequest).headers);
66569
- yield* remove(params.request);
66570
- const target = new URL(grant.redirectUri);
66571
- target.searchParams.set("state", grant.state);
66572
- target.searchParams.set("iss", issuer);
66573
- if (params.accept) target.searchParams.set("code", yield* save({
66574
- ...grant,
66575
- _tag: "Code",
66576
- user
66577
- }, 60));
66578
- else target.searchParams.set("error", "access_denied");
66579
- return expireCookieUnsafe(jsonUnsafe({ url: target.href }, { headers: { "cache-control": "no-store" } }), REQUEST_COOKIE, COOKIE);
66580
- }))));
67509
+ yield* respond(params, (yield* HttpServerRequest).headers);
67510
+ return empty();
67511
+ })));
66581
67512
  yield* router.add("POST", "/api/auth/oauth2/token", oauth(gen(function* () {
66582
67513
  const params = yield* pipe(schemaBodyUrlParams(TokenParams), rejected("Invalid token request"));
66583
67514
  return yield* sql.withTransaction(gen(function* () {
@@ -66637,7 +67568,7 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66637
67568
  }));
66638
67569
  yield* router.add("GET", "/auth/github", oauth(gen(function* () {
66639
67570
  const params = yield* pipe(schemaSearchParams(SignInParams), rejected("Invalid sign-in request"));
66640
- if (params.request !== void 0) yield* requestState(params.request);
67571
+ if (params.request !== void 0) yield* receiver(params.request, (yield* HttpServerRequest).headers);
66641
67572
  const verifier = encode(yield* random.randomBytes(32));
66642
67573
  const state = yield* save({
66643
67574
  _tag: "Login",
@@ -66696,7 +67627,7 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66696
67627
  yield* logWarning("GitHub sign-in failed", cause);
66697
67628
  return expireCookieUnsafe(redirect(`/?${toString$1(fromInput({
66698
67629
  error: "github",
66699
- request: (yield* HttpServerRequest).cookies[REQUEST_COOKIE]
67630
+ request: void 0
66700
67631
  }))}`), LOGIN_COOKIE, COOKIE);
66701
67632
  }))));
66702
67633
  yield* router.add("POST", "/auth/sign-out", oauth(gen(function* () {
@@ -66707,12 +67638,15 @@ var Auth = class Auth extends Service$2()("@deslop/auth/service/Auth") {
66707
67638
  domain: pipe(new URL(url).hostname, split$1("."), drop$1(1), join$2("."))
66708
67639
  });
66709
67640
  })));
66710
- return provide(Auth.of({
67641
+ return pipe(provide(Auth.of({
66711
67642
  access,
66712
67643
  user: fn("Auth.user")(function* (headers) {
66713
67644
  return yield* session(headers);
66714
67645
  })
66715
- }));
67646
+ })), add$3(Authorizations, Authorizations.of({
67647
+ pending: (headers) => watch(pending(headers), (requests) => reduce(requests, Infinity, (expiresAt, request) => min(expiresAt, request.expiresAt))),
67648
+ wait: (id, headers) => pipe(watch(receive(id, headers), (status) => pipe(value(status), tag("Waiting", (value) => value.request.expiresAt), orElse(() => Infinity))), takeUntil((status) => status._tag !== "Waiting"))
67649
+ })));
66716
67650
  })), provide$3(unwrap$5(gen(function* () {
66717
67651
  const fs = yield* FileSystem;
66718
67652
  const path = yield* Path$1;
@@ -66777,7 +67711,7 @@ const layerNodeHttpServer = layerConfig(createServer, {
66777
67711
  });
66778
67712
  //#endregion
66779
67713
  //#region package.json
66780
- var version = "0.1.1100";
67714
+ var version = "0.1.1102";
66781
67715
  //#endregion
66782
67716
  //#region src/services/telemetry/schema.ts
66783
67717
  var TelemetryError = class extends TaggedError()("TelemetryError", {
@@ -67030,7 +67964,7 @@ function traceView(entries, id) {
67030
67964
  }));
67031
67965
  const logs = filter$1(ordered, (entry) => entry.signal === "log");
67032
67966
  const nodes = map$5(spans, (span) => {
67033
- const ancestors = reverse(unfold({
67967
+ const ancestors = reverse(unfold$1({
67034
67968
  entry: span.entry,
67035
67969
  seen: make$46(span.entry.spanId)
67036
67970
  }, (current) => pipe(get$9(byId, parentId(current.entry)), filter$3((parent) => !has(current.seen, parent.entry.spanId)), map$8((parent) => [parent, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deslop/scope",
3
- "version": "0.1.1100",
3
+ "version": "0.1.1102",
4
4
  "description": "An Effect development debugger: an OTLP/HTTP JSON receiver whose traces and logs agents query over MCP.",
5
5
  "repository": {
6
6
  "type": "git",