bitfab 0.54.8 → 0.54.10

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 (35) hide show
  1. package/dist/{chunk-XPCVDQDS.js → chunk-A3OBQOLV.js} +609 -8
  2. package/dist/chunk-A3OBQOLV.js.map +1 -0
  3. package/dist/{chunk-5H3D7J4K.js → chunk-B2O33DBH.js} +6 -4
  4. package/dist/chunk-B2O33DBH.js.map +1 -0
  5. package/dist/{chunk-5LXZGUKW.js → chunk-OGZLJINL.js} +3 -3
  6. package/dist/chunk-OGZLJINL.js.map +1 -0
  7. package/dist/{chunk-RUCVJQBI.js → chunk-PRXW4B5X.js} +85 -40
  8. package/dist/chunk-PRXW4B5X.js.map +1 -0
  9. package/dist/{chunk-RC3HOMLJ.js → chunk-XLWQOUOP.js} +4 -3
  10. package/dist/chunk-XLWQOUOP.js.map +1 -0
  11. package/dist/{http-7PL32JLX.js → http-AVWWAMFV.js} +2 -2
  12. package/dist/{http-4JG3XW5X.js → http-DH3O3L5X.js} +2 -2
  13. package/dist/index.cjs +669 -8
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +175 -4
  16. package/dist/index.d.ts +175 -4
  17. package/dist/index.js +5 -3
  18. package/dist/node.cjs +669 -8
  19. package/dist/node.cjs.map +1 -1
  20. package/dist/node.d.cts +1 -1
  21. package/dist/node.d.ts +1 -1
  22. package/dist/node.js +5 -3
  23. package/dist/node.js.map +1 -1
  24. package/dist/{replay-KWBZ2JQV.js → replay-BCWIDCKH.js} +3 -3
  25. package/dist/replayCli.js +2 -2
  26. package/dist/seedCli.js +2 -2
  27. package/package.json +1 -1
  28. package/dist/chunk-5H3D7J4K.js.map +0 -1
  29. package/dist/chunk-5LXZGUKW.js.map +0 -1
  30. package/dist/chunk-RC3HOMLJ.js.map +0 -1
  31. package/dist/chunk-RUCVJQBI.js.map +0 -1
  32. package/dist/chunk-XPCVDQDS.js.map +0 -1
  33. /package/dist/{http-4JG3XW5X.js.map → http-AVWWAMFV.js.map} +0 -0
  34. /package/dist/{http-7PL32JLX.js.map → http-DH3O3L5X.js.map} +0 -0
  35. /package/dist/{replay-KWBZ2JQV.js.map → replay-BCWIDCKH.js.map} +0 -0
@@ -11,6 +11,7 @@ import {
11
11
  } from "./chunk-EGWJYCNT.js";
12
12
  import {
13
13
  NO_MOCK_OVERRIDE,
14
+ createIntegrationFixtureContext,
14
15
  deserializeInputs,
15
16
  deserializeValue,
16
17
  randomUuid,
@@ -18,7 +19,7 @@ import {
18
19
  serializeValue,
19
20
  toJsonSafe,
20
21
  toJsonSafeReport
21
- } from "./chunk-RUCVJQBI.js";
22
+ } from "./chunk-PRXW4B5X.js";
22
23
  import {
23
24
  BitfabError,
24
25
  DEFAULT_SERVICE_URL,
@@ -35,7 +36,7 @@ import {
35
36
  recordCallerTraceMetadata,
36
37
  retireTraceMetadata,
37
38
  warnOnce
38
- } from "./chunk-5H3D7J4K.js";
39
+ } from "./chunk-B2O33DBH.js";
39
40
  import {
40
41
  __privateAdd,
41
42
  __privateGet,
@@ -2485,6 +2486,527 @@ var ReplayBranch = class {
2485
2486
  _url = new WeakMap();
2486
2487
  _context = new WeakMap();
2487
2488
 
2489
+ // src/rivetContext.ts
2490
+ var storage = null;
2491
+ var browserBinding = null;
2492
+ var STORAGE_SYMBOL = /* @__PURE__ */ Symbol.for("bitfab.rivetContextStorage");
2493
+ function initializeStorage() {
2494
+ if (storage) {
2495
+ return;
2496
+ }
2497
+ const shared = globalThis;
2498
+ const existing = shared[STORAGE_SYMBOL];
2499
+ if (existing) {
2500
+ storage = existing;
2501
+ return;
2502
+ }
2503
+ const created = createAsyncLocalStorage();
2504
+ if (created) {
2505
+ shared[STORAGE_SYMBOL] = created;
2506
+ storage = created;
2507
+ }
2508
+ }
2509
+ var rivetContextReady = asyncStorageReady.then(() => {
2510
+ initializeStorage();
2511
+ });
2512
+ function getRivetContextBinding() {
2513
+ initializeStorage();
2514
+ return storage?.getStore() ?? browserBinding ?? void 0;
2515
+ }
2516
+ function runWithBrowserBinding(binding, fn) {
2517
+ const previous = browserBinding;
2518
+ browserBinding = binding;
2519
+ try {
2520
+ const result = fn();
2521
+ if (result instanceof Promise) {
2522
+ return result.finally(() => {
2523
+ browserBinding = previous;
2524
+ });
2525
+ }
2526
+ browserBinding = previous;
2527
+ return result;
2528
+ } catch (error) {
2529
+ browserBinding = previous;
2530
+ throw error;
2531
+ }
2532
+ }
2533
+ function runWithRivetContext(binding, fn) {
2534
+ initializeStorage();
2535
+ if (!storage && !isAsyncStorageInitDone()) {
2536
+ return rivetContextReady.then(() => runWithRivetContext(binding, fn));
2537
+ }
2538
+ if (storage) {
2539
+ return storage.run(binding, fn);
2540
+ }
2541
+ return runWithBrowserBinding(binding, fn);
2542
+ }
2543
+
2544
+ // src/rivetIntegration.ts
2545
+ var RIVET_DOCS_URL = "https://docs.bitfab.ai/frameworks/rivet";
2546
+ var RIVET_GROUP_EFFECT_METHODS = {
2547
+ db: ["execute", "nativeMetrics", "close"],
2548
+ kv: [
2549
+ "get",
2550
+ "put",
2551
+ "delete",
2552
+ "batchPut",
2553
+ "batchGet",
2554
+ "batchDelete",
2555
+ "deleteRange",
2556
+ "listPrefix",
2557
+ "listRange",
2558
+ "list"
2559
+ ],
2560
+ schedule: ["after", "at", "cancel", "get", "list"],
2561
+ cron: ["set", "every", "get", "list", "delete", "history"],
2562
+ queue: [
2563
+ "send",
2564
+ "next",
2565
+ "nextBatch",
2566
+ "waitForNames",
2567
+ "waitForAvailable",
2568
+ "complete",
2569
+ "enqueueAndWait",
2570
+ "tryNext",
2571
+ "tryNextBatch"
2572
+ ],
2573
+ run: ["setWakeAt"]
2574
+ };
2575
+ var RIVET_TOP_LEVEL_EFFECTS = [
2576
+ "broadcast",
2577
+ "saveState",
2578
+ "sleep",
2579
+ "destroy"
2580
+ ];
2581
+ var TOP_LEVEL_UNAVAILABLE_CAPABILITIES = /* @__PURE__ */ new Set([
2582
+ "conn",
2583
+ "conns",
2584
+ "log",
2585
+ "request",
2586
+ "actorRuntimeSocket",
2587
+ "keepAwake",
2588
+ "waitUntil",
2589
+ "client"
2590
+ ]);
2591
+ var SYNC_VOID_EFFECTS = /* @__PURE__ */ new Set([
2592
+ "broadcast",
2593
+ "sleep",
2594
+ "destroy"
2595
+ ]);
2596
+ var QUEUE_MESSAGE_EFFECTS = /* @__PURE__ */ new Set([
2597
+ "queue.next",
2598
+ "queue.nextBatch",
2599
+ "queue.waitForNames",
2600
+ "queue.tryNext",
2601
+ "queue.tryNextBatch"
2602
+ ]);
2603
+ function isRecord2(value) {
2604
+ return typeof value === "object" && value !== null;
2605
+ }
2606
+ function readProperty(value, property) {
2607
+ try {
2608
+ return Reflect.get(value, property, value);
2609
+ } catch {
2610
+ return void 0;
2611
+ }
2612
+ }
2613
+ function snapshotContext(context) {
2614
+ const source = context;
2615
+ const snapshot = {};
2616
+ for (const property of [
2617
+ "state",
2618
+ "vars",
2619
+ "actorId",
2620
+ "name",
2621
+ "key",
2622
+ "region",
2623
+ "aborted"
2624
+ ]) {
2625
+ const value = readProperty(source, property);
2626
+ if (value !== void 0) {
2627
+ snapshot[property] = value;
2628
+ }
2629
+ }
2630
+ return snapshot;
2631
+ }
2632
+ function unavailableCapability(path) {
2633
+ return new BitfabError(
2634
+ `Rivet context capability "${path}" is unavailable during replay. Add first-class support for that public context path before replaying code that uses it.`,
2635
+ RIVET_DOCS_URL
2636
+ );
2637
+ }
2638
+ function effectNode(traceFunctionKey, effect, mockSpanId) {
2639
+ return {
2640
+ traceFunctionKey,
2641
+ spanName: effect,
2642
+ type: "function",
2643
+ originalSpanId: mockSpanId
2644
+ };
2645
+ }
2646
+ function replayEffectStatus(replay, traceFunctionKey, effect, marked) {
2647
+ const counterKey = `${traceFunctionKey}:${effect}`;
2648
+ const callIndex = replay.callCounters?.get(counterKey) ?? 0;
2649
+ const mockSpan = replay.mockTree?.spans.get(`${counterKey}:${callIndex}`);
2650
+ const hasOverride = replay.mockOverrides?.some(
2651
+ (override) => override.match(
2652
+ effectNode(traceFunctionKey, effect, mockSpan?.sourceSpanId)
2653
+ )
2654
+ ) ?? false;
2655
+ return {
2656
+ willMock: hasOverride || replay.mockStrategy === "all" || replay.mockStrategy === "marked" && marked,
2657
+ hasRecordedSpan: mockSpan !== void 0,
2658
+ hasOverride,
2659
+ callIndex
2660
+ };
2661
+ }
2662
+ function assertReplayEffectAvailable(replay, traceFunctionKey, effect, marked) {
2663
+ if (!replay) {
2664
+ return;
2665
+ }
2666
+ const status = replayEffectStatus(replay, traceFunctionKey, effect, marked);
2667
+ if (!status.willMock) {
2668
+ throw new BitfabError(
2669
+ `Rivet effect "${effect}" has no live actor context during replay. Add "${effect}" to mockOnReplay or provide a replay override.`,
2670
+ RIVET_DOCS_URL
2671
+ );
2672
+ }
2673
+ if (!status.hasRecordedSpan && !status.hasOverride) {
2674
+ throw new BitfabError(
2675
+ `No recorded Rivet effect "${effect}" exists at call ${status.callIndex + 1}; the live effect was not executed.`,
2676
+ RIVET_DOCS_URL
2677
+ );
2678
+ }
2679
+ }
2680
+ function fixtureName(traceFunctionKey) {
2681
+ return `rivet:${traceFunctionKey}`;
2682
+ }
2683
+ function snapshotFromReplay(traceFunctionKey, replay) {
2684
+ const fixture = replay.integrationFixtures?.get(fixtureName(traceFunctionKey));
2685
+ if (!isRecord2(fixture)) {
2686
+ throw new BitfabError(
2687
+ `Trace "${traceFunctionKey}" has no Rivet context fixture. Capture a fresh trace with the Rivet integration before replaying it.`,
2688
+ RIVET_DOCS_URL
2689
+ );
2690
+ }
2691
+ return fixture;
2692
+ }
2693
+ var BitfabRivetIntegration = class {
2694
+ /** @internal Constructed by `Bitfab.getRivetIntegration()`. */
2695
+ constructor(traceFunctionKey, runtime, options = {}) {
2696
+ this.traceFunctionKey = traceFunctionKey;
2697
+ this.runtime = runtime;
2698
+ this.replayProxies = /* @__PURE__ */ new WeakMap();
2699
+ this.markedEffects = new Set(options.mockOnReplay ?? []);
2700
+ }
2701
+ /**
2702
+ * Run a callback with a live Rivet context bound to the current async chain.
2703
+ * This binds context only; it creates no trace or span.
2704
+ */
2705
+ withContext(context, fn) {
2706
+ if (!isRecord2(context)) {
2707
+ throw new BitfabError("Rivet withContext requires a context object");
2708
+ }
2709
+ const binding = {
2710
+ context,
2711
+ fixtureContext: createIntegrationFixtureContext(
2712
+ fixtureName(this.traceFunctionKey),
2713
+ snapshotContext(context)
2714
+ ),
2715
+ recordedRoots: /* @__PURE__ */ new Set()
2716
+ };
2717
+ return runWithRivetContext(binding, fn);
2718
+ }
2719
+ /**
2720
+ * Adapt a traced function into a Rivet handler whose first argument is the
2721
+ * live actor context. The context is not added to the traced root's inputs.
2722
+ */
2723
+ bind(fn) {
2724
+ const integration = this;
2725
+ return function(context, ...args) {
2726
+ return integration.withContext(context, () => fn.apply(this, args));
2727
+ };
2728
+ }
2729
+ /**
2730
+ * Return the current Rivet context proxy. In production it delegates to the
2731
+ * bound live context. During replay it hydrates recorded actor state and
2732
+ * intercepts supported effects without requiring a live Rivet actor.
2733
+ */
2734
+ getContext() {
2735
+ const replay = getReplayContext();
2736
+ if (replay) {
2737
+ const existing = this.replayProxies.get(replay);
2738
+ if (existing) {
2739
+ return existing;
2740
+ }
2741
+ const proxy = this.createContextProxy(
2742
+ snapshotFromReplay(this.traceFunctionKey, replay),
2743
+ void 0
2744
+ );
2745
+ this.replayProxies.set(replay, proxy);
2746
+ return proxy;
2747
+ }
2748
+ const binding = getRivetContextBinding();
2749
+ if (!binding) {
2750
+ throw new BitfabError(
2751
+ "No Rivet context is bound. Call rivet.bind(handler) or rivet.withContext(context, callback) at the Rivet boundary.",
2752
+ RIVET_DOCS_URL
2753
+ );
2754
+ }
2755
+ this.runtime.recordRootFixture(
2756
+ binding.fixtureContext,
2757
+ binding.recordedRoots
2758
+ );
2759
+ if (!binding.proxy) {
2760
+ binding.proxy = this.createContextProxy(
2761
+ binding.context,
2762
+ binding
2763
+ );
2764
+ }
2765
+ return binding.proxy;
2766
+ }
2767
+ createContextProxy(target, binding) {
2768
+ const replay = getReplayContext();
2769
+ const dbProxy = this.createDbProxy(binding, replay);
2770
+ const groupProxies = /* @__PURE__ */ new Map();
2771
+ for (const group of Object.keys(
2772
+ RIVET_GROUP_EFFECT_METHODS
2773
+ )) {
2774
+ if (group !== "db") {
2775
+ groupProxies.set(group, this.createGroupProxy(group, binding, replay));
2776
+ }
2777
+ }
2778
+ const topLevelEffects = /* @__PURE__ */ new Map();
2779
+ for (const effect of RIVET_TOP_LEVEL_EFFECTS) {
2780
+ topLevelEffects.set(
2781
+ effect,
2782
+ this.createEffect(
2783
+ effect,
2784
+ () => binding?.context,
2785
+ effect,
2786
+ replay
2787
+ )
2788
+ );
2789
+ }
2790
+ const replayTarget = replay ? { ...target } : target;
2791
+ if (replay) {
2792
+ const controller = new AbortController();
2793
+ if (target.aborted === true) {
2794
+ controller.abort();
2795
+ }
2796
+ replayTarget.abortSignal = controller.signal;
2797
+ }
2798
+ return new Proxy(replayTarget, {
2799
+ get: (source, property) => {
2800
+ if (property === "db") {
2801
+ return dbProxy;
2802
+ }
2803
+ if (typeof property === "string") {
2804
+ const group = groupProxies.get(property);
2805
+ if (group) {
2806
+ return group;
2807
+ }
2808
+ const effect = topLevelEffects.get(property);
2809
+ if (effect) {
2810
+ return effect;
2811
+ }
2812
+ }
2813
+ if (property === "setPreventSleep" && replay) {
2814
+ return (_preventSleep) => void 0;
2815
+ }
2816
+ if (replay && typeof property === "string" && TOP_LEVEL_UNAVAILABLE_CAPABILITIES.has(property)) {
2817
+ throw unavailableCapability(property);
2818
+ }
2819
+ const value = Reflect.get(source, property, source);
2820
+ return typeof value === "function" ? value.bind(source) : value;
2821
+ }
2822
+ });
2823
+ }
2824
+ createDbProxy(binding, replay) {
2825
+ const proxy = this.createGroupProxy("db", binding, replay);
2826
+ return new Proxy(proxy, {
2827
+ get: (source, property) => property === "transaction" ? this.createTransaction(binding, replay) : Reflect.get(source, property, source)
2828
+ });
2829
+ }
2830
+ createGroupProxy(group, binding, replay) {
2831
+ const targetProvider = () => {
2832
+ if (!binding) {
2833
+ return void 0;
2834
+ }
2835
+ const context = binding.context;
2836
+ const target = readProperty(context, group);
2837
+ return isRecord2(target) ? target : void 0;
2838
+ };
2839
+ const proxy = this.createMethodProxy(
2840
+ targetProvider,
2841
+ group,
2842
+ RIVET_GROUP_EFFECT_METHODS[group],
2843
+ replay
2844
+ );
2845
+ if (group !== "queue") {
2846
+ return proxy;
2847
+ }
2848
+ return new Proxy(proxy, {
2849
+ get: (source, property) => property === "iter" ? (options) => this.createQueueIterator(source, options) : Reflect.get(source, property, source)
2850
+ });
2851
+ }
2852
+ createMethodProxy(targetProvider, prefix, methods, replay) {
2853
+ const effects = /* @__PURE__ */ new Map();
2854
+ for (const method of methods) {
2855
+ const effect = `${prefix}.${method}`;
2856
+ effects.set(
2857
+ method,
2858
+ this.createEffect(effect, targetProvider, method, replay)
2859
+ );
2860
+ }
2861
+ return new Proxy(
2862
+ {},
2863
+ {
2864
+ get: (_source, property) => {
2865
+ if (typeof property === "string") {
2866
+ const effect = effects.get(property);
2867
+ if (effect) {
2868
+ return effect;
2869
+ }
2870
+ if (replay) {
2871
+ throw unavailableCapability(`${prefix}.${property}`);
2872
+ }
2873
+ }
2874
+ const target = targetProvider();
2875
+ if (!target) {
2876
+ return void 0;
2877
+ }
2878
+ const value = Reflect.get(target, property, target);
2879
+ return typeof value === "function" ? value.bind(target) : value;
2880
+ }
2881
+ }
2882
+ );
2883
+ }
2884
+ createEffect(effect, targetProvider, methodName, replay) {
2885
+ const marked = this.markedEffects.has(effect);
2886
+ const invoke = (...args) => {
2887
+ assertReplayEffectAvailable(
2888
+ getReplayContext(),
2889
+ this.traceFunctionKey,
2890
+ effect,
2891
+ marked
2892
+ );
2893
+ const target = targetProvider();
2894
+ const method = target ? readProperty(target, methodName) : void 0;
2895
+ if (typeof method !== "function") {
2896
+ throw unavailableCapability(effect);
2897
+ }
2898
+ return method.apply(target, args);
2899
+ };
2900
+ const wrapped = SYNC_VOID_EFFECTS.has(effect) ? this.runtime.wrapEffect(
2901
+ effect,
2902
+ marked,
2903
+ invoke,
2904
+ replay ? () => void 0 : void 0
2905
+ ) : this.runtime.wrapEffect(effect, marked, async (...args) => {
2906
+ return await invoke(...args);
2907
+ });
2908
+ return (...args) => {
2909
+ if (replay) {
2910
+ assertReplayEffectAvailable(
2911
+ replay,
2912
+ this.traceFunctionKey,
2913
+ effect,
2914
+ marked
2915
+ );
2916
+ }
2917
+ const result = wrapped(...args);
2918
+ if (!QUEUE_MESSAGE_EFFECTS.has(effect) || !(result instanceof Promise)) {
2919
+ return result;
2920
+ }
2921
+ return result.then(
2922
+ (value) => this.decorateQueueMessages(value, effect, args, replay)
2923
+ );
2924
+ };
2925
+ }
2926
+ createTransaction(binding, replay) {
2927
+ return async (callback, options) => {
2928
+ if (typeof callback !== "function") {
2929
+ throw new BitfabError("Rivet db.transaction requires a callback");
2930
+ }
2931
+ if (replay) {
2932
+ return await callback(
2933
+ this.createMethodProxy(
2934
+ () => void 0,
2935
+ "db.transaction",
2936
+ ["execute"],
2937
+ replay
2938
+ )
2939
+ );
2940
+ }
2941
+ const context = binding?.context;
2942
+ const db = context ? readProperty(context, "db") : void 0;
2943
+ const transaction = isRecord2(db) ? readProperty(db, "transaction") : void 0;
2944
+ if (!isRecord2(db) || typeof transaction !== "function") {
2945
+ throw unavailableCapability("db.transaction");
2946
+ }
2947
+ return await transaction.call(
2948
+ db,
2949
+ async (transactionDb) => {
2950
+ if (!isRecord2(transactionDb)) {
2951
+ throw unavailableCapability("db.transaction.execute");
2952
+ }
2953
+ return await callback(
2954
+ this.createMethodProxy(
2955
+ () => transactionDb,
2956
+ "db.transaction",
2957
+ ["execute"],
2958
+ replay
2959
+ )
2960
+ );
2961
+ },
2962
+ options
2963
+ );
2964
+ };
2965
+ }
2966
+ decorateQueueMessages(value, effect, args, replay) {
2967
+ if (!this.queueCallIsCompletable(effect, args)) {
2968
+ return value;
2969
+ }
2970
+ if (Array.isArray(value)) {
2971
+ return value.map((message) => this.decorateQueueMessage(message, replay));
2972
+ }
2973
+ return this.decorateQueueMessage(value, replay);
2974
+ }
2975
+ decorateQueueMessage(value, replay) {
2976
+ if (!isRecord2(value)) {
2977
+ return value;
2978
+ }
2979
+ const originalComplete = readProperty(value, "complete");
2980
+ const complete = this.createEffect(
2981
+ "queue.message.complete",
2982
+ () => typeof originalComplete === "function" ? { complete: originalComplete.bind(value) } : void 0,
2983
+ "complete",
2984
+ replay
2985
+ );
2986
+ return { ...value, complete };
2987
+ }
2988
+ queueCallIsCompletable(effect, args) {
2989
+ const options = effect === "queue.waitForNames" ? args[1] : args[0];
2990
+ return isRecord2(options) && options.completable === true;
2991
+ }
2992
+ createQueueIterator(queue, options) {
2993
+ return {
2994
+ async *[Symbol.asyncIterator]() {
2995
+ for (; ; ) {
2996
+ const next = Reflect.get(queue, "next", queue);
2997
+ if (typeof next !== "function") {
2998
+ throw unavailableCapability("queue.next");
2999
+ }
3000
+ const message = await next.call(queue, options);
3001
+ if (message !== void 0 && message !== null) {
3002
+ yield message;
3003
+ }
3004
+ }
3005
+ }
3006
+ };
3007
+ }
3008
+ };
3009
+
2488
3010
  // src/seedContext.ts
2489
3011
  var seedContextStorage = null;
2490
3012
  var SEED_CONTEXT_STORAGE_SYMBOL = /* @__PURE__ */ Symbol.for("bitfab.seedContextStorage");
@@ -4180,6 +4702,47 @@ var Bitfab = class {
4180
4702
  options
4181
4703
  });
4182
4704
  }
4705
+ /**
4706
+ * Get the first-class Rivet actor-context integration for an existing trace
4707
+ * root. The integration binds context and records effect spans; it never
4708
+ * creates another root.
4709
+ *
4710
+ * @param traceFunctionKey - Key used by the enclosing `withTrace()` root
4711
+ * @param options - Explicit per-context-path replay mocking policy
4712
+ * @experimental This API may change before it is stable.
4713
+ */
4714
+ getRivetIntegration(traceFunctionKey, options) {
4715
+ return new BitfabRivetIntegration(
4716
+ traceFunctionKey,
4717
+ {
4718
+ wrapEffect: (effect, mockOnReplay, fn, replayOutput) => {
4719
+ const spanOptions = {
4720
+ name: effect,
4721
+ type: "function",
4722
+ captureWhen: "nested",
4723
+ mockOnReplay,
4724
+ surface: "inherit",
4725
+ instrumentation: "rivet",
4726
+ ...replayOutput !== void 0 && { replayOutput }
4727
+ };
4728
+ return this.withSpan(traceFunctionKey, spanOptions, fn);
4729
+ },
4730
+ recordRootFixture: (context, recordedRoots) => {
4731
+ const root = getSpanStack()[0];
4732
+ if (!root) {
4733
+ return;
4734
+ }
4735
+ const rootId = `${root.traceId}:${root.spanId}`;
4736
+ if (recordedRoots.has(rootId)) {
4737
+ return;
4738
+ }
4739
+ root.contexts.push(context);
4740
+ recordedRoots.add(rootId);
4741
+ }
4742
+ },
4743
+ options
4744
+ );
4745
+ }
4183
4746
  /**
4184
4747
  * Get a Claude Agent SDK handler for tracing.
4185
4748
  *
@@ -4678,6 +5241,7 @@ var Bitfab = class {
4678
5241
  }
4679
5242
  return output;
4680
5243
  };
5244
+ const resolveBaseOutput = () => options.replayOutput !== void 0 ? options.replayOutput() : resolveRecordedOutput();
4681
5245
  const shouldMockWithBaseStrategy = replayCtxForMock.mockStrategy === "all" || replayCtxForMock.mockStrategy === "marked" && options.mockOnReplay === true;
4682
5246
  if (replayCtxForMock.mockOverrides?.length) {
4683
5247
  const nodeMeta = {
@@ -4734,7 +5298,7 @@ var Bitfab = class {
4734
5298
  }
4735
5299
  if (shouldMockWithBaseStrategy) {
4736
5300
  const output = await resolveMockOrAbort(
4737
- () => resolveRecordedOutput()
5301
+ () => resolveBaseOutput()
4738
5302
  );
4739
5303
  void sendSpan({
4740
5304
  result: output,
@@ -4757,7 +5321,7 @@ var Bitfab = class {
4757
5321
  );
4758
5322
  }
4759
5323
  if (shouldMockWithBaseStrategy) {
4760
- const recorded = resolveRecordedOutput();
5324
+ const recorded = resolveBaseOutput();
4761
5325
  if (recorded instanceof Promise) {
4762
5326
  return emitMockAsync(recorded, "recorded");
4763
5327
  }
@@ -5237,7 +5801,7 @@ var Bitfab = class {
5237
5801
  await runWithSeedContext({ traceId }, async () => target(...args));
5238
5802
  } finally {
5239
5803
  try {
5240
- const { flushTraces: flushTraces2 } = await import("./http-7PL32JLX.js");
5804
+ const { flushTraces: flushTraces2 } = await import("./http-AVWWAMFV.js");
5241
5805
  await flushTraces2(3e4);
5242
5806
  } finally {
5243
5807
  unrecorded = activeTraceStates.delete(traceId);
@@ -5296,7 +5860,7 @@ var Bitfab = class {
5296
5860
  `Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
5297
5861
  );
5298
5862
  }
5299
- const { replay: doReplay } = await import("./replay-KWBZ2JQV.js");
5863
+ const { replay: doReplay } = await import("./replay-BCWIDCKH.js");
5300
5864
  return doReplay(
5301
5865
  this.httpClient,
5302
5866
  this.serviceUrl,
@@ -5359,6 +5923,28 @@ var BitfabFunction = class {
5359
5923
  span(options = {}) {
5360
5924
  return this.client.span(this.traceFunctionKey, options);
5361
5925
  }
5926
+ withTrace(optionsOrFn, maybeFn) {
5927
+ if (typeof optionsOrFn === "function") {
5928
+ return this.client.withTrace(this.traceFunctionKey, optionsOrFn);
5929
+ }
5930
+ if (!maybeFn) {
5931
+ throw new BitfabError("BitfabFunction.withTrace requires a function");
5932
+ }
5933
+ return this.client.withTrace(this.traceFunctionKey, optionsOrFn, maybeFn);
5934
+ }
5935
+ /**
5936
+ * Create a trace method decorator bound to this function's key.
5937
+ *
5938
+ * Equivalent to `client.trace(key, options)` but reuses the key bound on
5939
+ * this handle.
5940
+ *
5941
+ * @param options - Trace configuration applied to the decorated method
5942
+ * @returns A method decorator configured for this key
5943
+ * @experimental Automatic child-call instrumentation is experimental.
5944
+ */
5945
+ trace(options = {}) {
5946
+ return this.client.trace(this.traceFunctionKey, options);
5947
+ }
5362
5948
  /**
5363
5949
  * Get a Vercel AI SDK language-model middleware bound to this function's key.
5364
5950
  *
@@ -5456,6 +6042,20 @@ var BitfabFunction = class {
5456
6042
  getLangGraphIntegration(options) {
5457
6043
  return this.client.getLangGraphIntegration(this.traceFunctionKey, options);
5458
6044
  }
6045
+ /**
6046
+ * Get the first-class Rivet actor-context integration bound to this key.
6047
+ * Use its `bind()` or `withContext()` outside this handle's `withTrace()`
6048
+ * root, then call `getContext()` inside the root.
6049
+ *
6050
+ * @param options - Explicit per-context-path replay mocking policy
6051
+ * @experimental This API may change before it is stable.
6052
+ */
6053
+ getRivetIntegration(options) {
6054
+ return this.client.getRivetIntegration(
6055
+ this.traceFunctionKey,
6056
+ options
6057
+ );
6058
+ }
5459
6059
  /**
5460
6060
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
5461
6061
  * Delegates to the parent client's wrapBAML method.
@@ -5580,7 +6180,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
5580
6180
  sessionId: seedCase.sessionId
5581
6181
  })
5582
6182
  );
5583
- const { flushTraces: flushTraces2 } = await import("./http-7PL32JLX.js");
6183
+ const { flushTraces: flushTraces2 } = await import("./http-AVWWAMFV.js");
5584
6184
  await flushTraces2(3e4);
5585
6185
  return { pipeline, traceFunctionKey, traceIds };
5586
6186
  }
@@ -5605,6 +6205,7 @@ export {
5605
6205
  BitfabLangGraphCallbackHandler,
5606
6206
  BitfabLangGraphIntegration,
5607
6207
  BitfabOpenAIAgentHandler,
6208
+ BitfabRivetIntegration,
5608
6209
  TracesClient,
5609
6210
  BitfabOpenAITracingProcessor,
5610
6211
  BitfabVercelAiHandler,
@@ -5618,4 +6219,4 @@ export {
5618
6219
  reseedFromRegistry,
5619
6220
  seedFromRegistry
5620
6221
  };
5621
- //# sourceMappingURL=chunk-XPCVDQDS.js.map
6222
+ //# sourceMappingURL=chunk-A3OBQOLV.js.map