@dxos/effect 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264 → 0.13.0

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 (130) hide show
  1. package/dist/lib/AtomEx.mjs +44 -0
  2. package/dist/lib/AtomEx.mjs.map +1 -0
  3. package/dist/lib/DynamicRuntime.mjs +93 -0
  4. package/dist/lib/DynamicRuntime.mjs.map +1 -0
  5. package/dist/lib/EffectEx.mjs +3 -0
  6. package/dist/lib/GlobalValue.mjs +22 -0
  7. package/dist/lib/GlobalValue.mjs.map +1 -0
  8. package/dist/lib/Hook.mjs +107 -0
  9. package/dist/lib/Hook.mjs.map +1 -0
  10. package/dist/lib/Performance.mjs +80 -0
  11. package/dist/lib/Performance.mjs.map +1 -0
  12. package/dist/lib/RuntimeProvider.mjs +43 -0
  13. package/dist/lib/RuntimeProvider.mjs.map +1 -0
  14. package/dist/lib/SchemaAST.mjs +172 -0
  15. package/dist/lib/SchemaAST.mjs.map +1 -0
  16. package/dist/lib/SchemaEx.mjs +2 -0
  17. package/dist/lib/SpanAttributes.mjs +63 -0
  18. package/dist/lib/SpanAttributes.mjs.map +1 -0
  19. package/dist/lib/Yield.mjs +11 -0
  20. package/dist/lib/Yield.mjs.map +1 -0
  21. package/dist/lib/chunk-EffectEx.mjs +158 -0
  22. package/dist/lib/chunk-EffectEx.mjs.map +1 -0
  23. package/dist/lib/chunk-KvsStore.mjs +37 -0
  24. package/dist/lib/chunk-KvsStore.mjs.map +1 -0
  25. package/dist/lib/chunk-SchemaEx.mjs +399 -0
  26. package/dist/lib/chunk-SchemaEx.mjs.map +1 -0
  27. package/dist/lib/chunk-errors.mjs +135 -0
  28. package/dist/lib/chunk-errors.mjs.map +1 -0
  29. package/dist/lib/chunk-otel.mjs +33 -0
  30. package/dist/lib/chunk-otel.mjs.map +1 -0
  31. package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
  32. package/dist/lib/index.mjs +14 -1017
  33. package/dist/lib/ns/KvsStore.mjs +2 -0
  34. package/dist/lib/ns/OtelTracer.mjs +12 -0
  35. package/dist/lib/ns/OtelTracer.mjs.map +1 -0
  36. package/dist/lib/testing.mjs +16 -3
  37. package/dist/lib/testing.mjs.map +1 -1
  38. package/dist/types/src/AtomEx.d.ts +40 -0
  39. package/dist/types/src/AtomEx.d.ts.map +1 -0
  40. package/dist/types/src/AtomEx.test.d.ts +2 -0
  41. package/dist/types/src/AtomEx.test.d.ts.map +1 -0
  42. package/dist/types/src/EffectEx.d.ts +5 -5
  43. package/dist/types/src/EffectEx.d.ts.map +1 -1
  44. package/dist/types/src/Hook.d.ts +87 -0
  45. package/dist/types/src/Hook.d.ts.map +1 -0
  46. package/dist/types/src/Hook.test.d.ts +2 -0
  47. package/dist/types/src/Hook.test.d.ts.map +1 -0
  48. package/dist/types/src/KvsStore.d.ts +2 -0
  49. package/dist/types/src/KvsStore.d.ts.map +1 -0
  50. package/dist/types/src/OtelTracer.d.ts +2 -0
  51. package/dist/types/src/OtelTracer.d.ts.map +1 -0
  52. package/dist/types/src/Performance.d.ts +45 -15
  53. package/dist/types/src/Performance.d.ts.map +1 -1
  54. package/dist/types/src/Performance.test.d.ts +2 -0
  55. package/dist/types/src/Performance.test.d.ts.map +1 -0
  56. package/dist/types/src/RuntimeProvider.d.ts.map +1 -1
  57. package/dist/types/src/RuntimeProvider.test.d.ts +2 -0
  58. package/dist/types/src/RuntimeProvider.test.d.ts.map +1 -0
  59. package/dist/types/src/SchemaEx.d.ts +3 -3
  60. package/dist/types/src/SchemaEx.d.ts.map +1 -1
  61. package/dist/types/src/SpanAttributes.d.ts +52 -0
  62. package/dist/types/src/SpanAttributes.d.ts.map +1 -0
  63. package/dist/types/src/SpanAttributes.test.d.ts +2 -0
  64. package/dist/types/src/SpanAttributes.test.d.ts.map +1 -0
  65. package/dist/types/src/Yield.d.ts +6 -0
  66. package/dist/types/src/Yield.d.ts.map +1 -0
  67. package/dist/types/src/atom-kvs.d.ts +1 -1
  68. package/dist/types/src/atom-kvs.d.ts.map +1 -1
  69. package/dist/types/src/context.test.d.ts +2 -0
  70. package/dist/types/src/context.test.d.ts.map +1 -0
  71. package/dist/types/src/index.d.ts +12 -10
  72. package/dist/types/src/index.d.ts.map +1 -1
  73. package/dist/types/src/internal/ast.d.ts +2 -2
  74. package/dist/types/src/internal/ast.d.ts.map +1 -1
  75. package/dist/types/src/internal/context.d.ts +21 -0
  76. package/dist/types/src/internal/context.d.ts.map +1 -1
  77. package/dist/types/src/internal/errors.d.ts.map +1 -1
  78. package/dist/types/src/internal/index.d.ts +3 -0
  79. package/dist/types/src/internal/index.d.ts.map +1 -0
  80. package/dist/types/src/internal/schema-ast.d.ts +1 -1
  81. package/dist/types/src/internal/schema-ast.d.ts.map +1 -1
  82. package/dist/types/src/internal/url.d.ts +1 -1
  83. package/dist/types/src/internal/url.d.ts.map +1 -1
  84. package/dist/types/src/otel.d.ts +17 -1
  85. package/dist/types/src/otel.d.ts.map +1 -1
  86. package/dist/types/src/testing.d.ts +6 -0
  87. package/dist/types/src/testing.d.ts.map +1 -1
  88. package/dist/types/tsconfig.tsbuildinfo +1 -1
  89. package/package.json +85 -16
  90. package/src/AtomEx.test.ts +77 -0
  91. package/src/AtomEx.ts +62 -0
  92. package/src/EffectEx.ts +5 -5
  93. package/src/Hook.test.ts +156 -0
  94. package/src/Hook.ts +169 -0
  95. package/src/KvsStore.ts +7 -0
  96. package/src/OtelTracer.ts +7 -0
  97. package/src/Performance.test.ts +63 -0
  98. package/src/Performance.ts +103 -25
  99. package/src/RuntimeProvider.test.ts +29 -0
  100. package/src/RuntimeProvider.ts +12 -3
  101. package/src/SchemaEx.ts +3 -3
  102. package/src/SpanAttributes.test.ts +35 -0
  103. package/src/SpanAttributes.ts +66 -0
  104. package/src/Yield.ts +13 -0
  105. package/src/ast.test.ts +61 -5
  106. package/src/atom-kvs.ts +1 -1
  107. package/src/context.test.ts +62 -0
  108. package/src/dynamic-runtime.test.ts +3 -3
  109. package/src/dynamic-runtime.ts +1 -1
  110. package/src/errors.test.ts +59 -1
  111. package/src/index.ts +12 -14
  112. package/src/internal/ast.ts +13 -6
  113. package/src/internal/context.ts +69 -1
  114. package/src/internal/errors.ts +44 -93
  115. package/src/internal/index.ts +6 -0
  116. package/src/internal/json-path.ts +2 -2
  117. package/src/internal/schema-ast.ts +1 -0
  118. package/src/internal/url.ts +1 -1
  119. package/src/interrupt.test.ts +1 -1
  120. package/src/json-path.test.ts +1 -1
  121. package/src/layer-memoization.test.ts +1 -1
  122. package/src/layers.test.ts +18 -18
  123. package/src/otel.test.ts +1 -1
  124. package/src/otel.ts +20 -1
  125. package/src/resource.test.ts +1 -1
  126. package/src/sanity.test.ts +1 -1
  127. package/src/testing.ts +17 -1
  128. package/src/url.test.ts +1 -1
  129. package/src/vite-env.d.ts +20 -0
  130. package/dist/lib/index.mjs.map +0 -1
@@ -0,0 +1,44 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import * as Duration from "effect/Duration";
3
+ import * as Registry from "effect/reactivity/AtomRegistry";
4
+ import { assertArgument } from "@dxos/invariant";
5
+ //#region src/AtomEx.ts
6
+ var AtomEx_exports = /* @__PURE__ */ __exportAll({
7
+ DEFAULT_IDLE_TTL: () => DEFAULT_IDLE_TTL,
8
+ OwnerId: () => OwnerId,
9
+ makeOwned: () => makeOwned,
10
+ makeRegistry: () => makeRegistry
11
+ });
12
+ /**
13
+ * Default grace period before an atom with no subscribers is removed from a registry.
14
+ */
15
+ var DEFAULT_IDLE_TTL = Duration.seconds(5);
16
+ /**
17
+ * An atom registry with the default idle grace period. Use it for any registry that hosts ECHO atoms,
18
+ * which carry no `keepAlive` of their own.
19
+ */
20
+ var makeRegistry = ({ idleTTL = DEFAULT_IDLE_TTL, ...options } = {}) => {
21
+ const millis = Duration.toMillis(idleTTL);
22
+ assertArgument(Number.isFinite(millis), "idleTTL", "Must be finite; use Atom.keepAlive to retain an atom");
23
+ return Registry.make({
24
+ ...options,
25
+ defaultIdleTTL: millis > 0 ? millis : void 0
26
+ });
27
+ };
28
+ /**
29
+ * Key under which an {@link Owner} exposes what its atoms are mounted with.
30
+ */
31
+ var OwnerId = Symbol.for("@dxos/effect/AtomEx/Owner");
32
+ /**
33
+ * Keeps `atom` mounted until `owner` is collected. Unlike `Atom.keepAlive`, it does not outlive the
34
+ * owner. Neither the atom nor its value may reference `owner`, or the registry keeps `owner` alive.
35
+ */
36
+ var makeOwned = (owner, atom) => {
37
+ const { registry, finalizer } = owner[OwnerId];
38
+ finalizer.register(owner, registry.mount(atom));
39
+ return atom;
40
+ };
41
+ //#endregion
42
+ export { DEFAULT_IDLE_TTL, OwnerId, makeOwned, makeRegistry, AtomEx_exports as t };
43
+
44
+ //# sourceMappingURL=AtomEx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AtomEx.mjs","names":[],"sources":["../../src/AtomEx.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Duration from 'effect/Duration';\nimport type * as Atom from 'effect/reactivity/Atom';\nimport * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { assertArgument } from '@dxos/invariant';\n\n// @import-as-namespace\n\n/**\n * Default grace period before an atom with no subscribers is removed from a registry.\n */\nexport const DEFAULT_IDLE_TTL = Duration.seconds(5);\n\nexport type RegistryOptions = Omit<NonNullable<Parameters<typeof Registry.make>[0]>, 'defaultIdleTTL'> & {\n /** Must be finite; use `Atom.keepAlive` to retain an atom indefinitely. Zero removes on the next task. */\n idleTTL?: Duration.Input;\n};\n\n/**\n * An atom registry with the default idle grace period. Use it for any registry that hosts ECHO atoms,\n * which carry no `keepAlive` of their own.\n */\nexport const makeRegistry = ({ idleTTL = DEFAULT_IDLE_TTL, ...options }: RegistryOptions = {}) => {\n const millis = Duration.toMillis(idleTTL);\n // An infinite TTL makes the registry's bucket arithmetic NaN, which removes nodes at once.\n assertArgument(Number.isFinite(millis), 'idleTTL', 'Must be finite; use Atom.keepAlive to retain an atom');\n return Registry.make({ ...options, defaultIdleTTL: millis > 0 ? millis : undefined });\n};\n\n/**\n * Key under which an {@link Owner} exposes what its atoms are mounted with.\n */\nexport const OwnerId = Symbol.for('@dxos/effect/AtomEx/Owner');\n\n/**\n * An object whose atoms live as long as it does; see {@link makeOwned}.\n */\nexport interface Owner {\n readonly [OwnerId]: {\n /** The registry the owner's atoms are mounted in. */\n readonly registry: Registry.AtomRegistry;\n /**\n * Unmounts a collected owner's atoms. One per class, held in a static field: a registry the\n * instance created would be collected with it and never run.\n */\n readonly finalizer: FinalizationRegistry<() => void>;\n };\n}\n\n/**\n * Keeps `atom` mounted until `owner` is collected. Unlike `Atom.keepAlive`, it does not outlive the\n * owner. Neither the atom nor its value may reference `owner`, or the registry keeps `owner` alive.\n */\nexport const makeOwned = <A extends Atom.Atom<unknown>>(owner: Owner, atom: A): A => {\n const { registry, finalizer } = owner[OwnerId];\n finalizer.register(owner, registry.mount(atom));\n return atom;\n};\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAa,mBAAmB,SAAS,QAAQ,CAAC;;;;;AAWlD,IAAa,gBAAgB,EAAE,UAAU,kBAAkB,GAAG,YAA6B,CAAC,MAAM;CAChG,MAAM,SAAS,SAAS,SAAS,OAAO;CAExC,eAAe,OAAO,SAAS,MAAM,GAAG,WAAW,sDAAsD;CACzG,OAAO,SAAS,KAAK;EAAE,GAAG;EAAS,gBAAgB,SAAS,IAAI,SAAS,KAAA;CAAU,CAAC;AACtF;;;;AAKA,IAAa,UAAU,OAAO,IAAI,2BAA2B;;;;;AAqB7D,IAAa,aAA2C,OAAc,SAAe;CACnF,MAAM,EAAE,UAAU,cAAc,MAAM;CACtC,UAAU,SAAS,OAAO,SAAS,MAAM,IAAI,CAAC;CAC9C,OAAO;AACT"}
@@ -0,0 +1,93 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { n as runAndForwardErrors, s as unwrapExit } from "./chunk-errors.mjs";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Context from "effect/Context";
5
+ import * as Exit from "effect/Exit";
6
+ import * as Option from "effect/Option";
7
+ //#region src/dynamic-runtime.ts
8
+ var dynamic_runtime_exports = /* @__PURE__ */ __exportAll({ make: () => make });
9
+ /**
10
+ * Validate that all required tags are present in the runtime context.
11
+ */
12
+ var validateTags = (context, tags) => Effect.gen(function* () {
13
+ const missingTags = [];
14
+ for (const tag of tags) {
15
+ const option = Context.getOption(context, tag);
16
+ if (Option.isNone(option)) missingTags.push(tag.key);
17
+ }
18
+ if (missingTags.length > 0) return yield* Effect.die(/* @__PURE__ */ new Error(`Missing required tags in runtime: ${missingTags.join(", ")}`));
19
+ });
20
+ /**
21
+ * Create a dynamic runtime from a managed runtime and validate required tags.
22
+ */
23
+ function make(managedRuntime, tags) {
24
+ const managedRuntimeAny = managedRuntime;
25
+ let cachedRuntime;
26
+ let validatedRuntimePromise;
27
+ const getValidatedRuntimeAsync = async () => {
28
+ if (!validatedRuntimePromise) validatedRuntimePromise = managedRuntimeAny.runPromise(Effect.gen(function* () {
29
+ const rt = yield* managedRuntimeAny.contextEffect;
30
+ yield* validateTags(rt, tags);
31
+ return rt;
32
+ }));
33
+ return validatedRuntimePromise;
34
+ };
35
+ const getValidatedRuntime = () => {
36
+ const validationExit = managedRuntimeAny.runSyncExit(Effect.gen(function* () {
37
+ const rt = yield* managedRuntimeAny.contextEffect;
38
+ yield* validateTags(rt, tags);
39
+ return rt;
40
+ }));
41
+ return unwrapExit(validationExit);
42
+ };
43
+ return {
44
+ managedRuntime: managedRuntimeAny,
45
+ runPromise: async (effect) => {
46
+ const runtime = await getValidatedRuntimeAsync();
47
+ return runAndForwardErrors(Effect.provideContext(effect, runtime));
48
+ },
49
+ runSync: (effect) => {
50
+ const runtime = getValidatedRuntime();
51
+ return Effect.runSync(Effect.provideContext(effect, runtime));
52
+ },
53
+ runSyncExit: (effect) => {
54
+ const validationExit = managedRuntimeAny.runSyncExit(Effect.gen(function* () {
55
+ const rt = yield* managedRuntimeAny.contextEffect;
56
+ yield* validateTags(rt, tags);
57
+ return rt;
58
+ }));
59
+ if (Exit.isSuccess(validationExit)) {
60
+ const runtime = validationExit.value;
61
+ return Effect.runSyncExit(Effect.provideContext(effect, runtime));
62
+ }
63
+ return validationExit;
64
+ },
65
+ runPromiseExit: async (effect) => {
66
+ try {
67
+ const runtime = await getValidatedRuntimeAsync();
68
+ return Effect.runPromiseExit(Effect.provideContext(effect, runtime));
69
+ } catch (error) {
70
+ return Exit.die(error);
71
+ }
72
+ },
73
+ runFork: (effect) => {
74
+ const runtime = getValidatedRuntime();
75
+ return Effect.runFork(Effect.provideContext(effect, runtime));
76
+ },
77
+ contextEffect: Effect.gen(function* () {
78
+ if (cachedRuntime) return cachedRuntime;
79
+ const rt = yield* managedRuntimeAny.contextEffect;
80
+ yield* validateTags(rt, tags);
81
+ const runtime = rt;
82
+ cachedRuntime = runtime;
83
+ return runtime;
84
+ }).pipe(Effect.catch(() => Effect.die(/* @__PURE__ */ new Error("Unexpected error in contextEffect validation")))),
85
+ dispose: async () => {
86
+ await managedRuntimeAny.dispose();
87
+ }
88
+ };
89
+ }
90
+ //#endregion
91
+ export { make, dynamic_runtime_exports as t };
92
+
93
+ //# sourceMappingURL=DynamicRuntime.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DynamicRuntime.mjs","names":[],"sources":["../../src/dynamic-runtime.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Exit from 'effect/Exit';\nimport type * as Fiber from 'effect/Fiber';\nimport type * as ManagedRuntime from 'effect/ManagedRuntime';\nimport * as Option from 'effect/Option';\n\nimport { runAndForwardErrors, unwrapExit } from './internal/errors.ts';\n\n/**\n * Helper type to construct a union of tag identifiers from an array of tags.\n */\nexport type TagsToContext<Tags extends ReadonlyArray<Context.Key<any, any>>> = Tags extends readonly [\n infer Head,\n ...infer Tail,\n]\n ? Head extends Context.Key<infer Id, any>\n ? Tail extends ReadonlyArray<Context.Key<any, any>>\n ? Id | TagsToContext<Tail>\n : Id\n : never\n : never;\n\n/**\n * A runtime wrapper that validates required tags are available at runtime\n * while providing type-level guarantees that effects require those tags.\n */\nexport interface DynamicRuntime<Tags extends ReadonlyArray<Context.Key<any, any>>> {\n /**\n * Run an effect as a promise that requires the specified tags.\n */\n readonly runPromise: <A, E>(effect: Effect.Effect<A, E, TagsToContext<Tags>>) => Promise<A>;\n\n /**\n * Run an effect synchronously that requires the specified tags.\n */\n readonly runSync: <A, E>(effect: Effect.Effect<A, E, TagsToContext<Tags>>) => A;\n\n /**\n * Run an effect synchronously returning exit that requires the specified tags.\n */\n readonly runSyncExit: <A, E>(effect: Effect.Effect<A, E, TagsToContext<Tags>>) => Exit.Exit<A, E>;\n\n /**\n * Run an effect as a promise returning exit that requires the specified tags.\n */\n readonly runPromiseExit: <A, E>(effect: Effect.Effect<A, E, TagsToContext<Tags>>) => Promise<Exit.Exit<A, E>>;\n\n /**\n * Fork an effect that requires the specified tags.\n */\n readonly runFork: <A, E>(effect: Effect.Effect<A, E, TagsToContext<Tags>>) => Fiber.Fiber<A, E>;\n\n /**\n * Get the runtime as an effect that requires the specified tags.\n */\n readonly contextEffect: Effect.Effect<Context.Context<TagsToContext<Tags>>, never, never>;\n\n /**\n * Dispose the underlying managed runtime.\n */\n readonly dispose: () => Promise<void>;\n\n /**\n * Get the underlying managed runtime.\n */\n readonly managedRuntime: ManagedRuntime.ManagedRuntime<any, any>;\n}\n\n/**\n * Validate that all required tags are present in the runtime context.\n */\nconst validateTags = <Tags extends ReadonlyArray<Context.Key<any, any>>>(\n context: Context.Context<any>,\n tags: Tags,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n const missingTags: string[] = [];\n for (const tag of tags) {\n const option = Context.getOption(context, tag);\n if (Option.isNone(option)) {\n missingTags.push(tag.key);\n }\n }\n\n if (missingTags.length > 0) {\n return yield* Effect.die(new Error(`Missing required tags in runtime: ${missingTags.join(', ')}`));\n }\n });\n\n/**\n * Create a dynamic runtime from a managed runtime and validate required tags.\n */\nexport function make<const Tags extends ReadonlyArray<Context.Key<any, any>>>(\n managedRuntime: ManagedRuntime.ManagedRuntime<any, any> | ManagedRuntime.ManagedRuntime<never, never>,\n tags: Tags,\n): DynamicRuntime<Tags> {\n type RequiredContext = TagsToContext<Tags>;\n const managedRuntimeAny = managedRuntime as ManagedRuntime.ManagedRuntime<any, any>;\n\n // Cache for the validated runtime - once resolved, can be used synchronously.\n let cachedRuntime: Context.Context<RequiredContext> | undefined;\n\n // Cache validated runtime for async operations.\n let validatedRuntimePromise: Promise<Context.Context<RequiredContext>> | undefined;\n\n const getValidatedRuntimeAsync = async (): Promise<Context.Context<RequiredContext>> => {\n if (!validatedRuntimePromise) {\n validatedRuntimePromise = managedRuntimeAny.runPromise(\n Effect.gen(function* () {\n const rt = yield* managedRuntimeAny.contextEffect;\n yield* validateTags(rt, tags);\n return rt as Context.Context<RequiredContext>;\n }),\n );\n }\n return validatedRuntimePromise;\n };\n\n // Get validated runtime for sync operations.\n const getValidatedRuntime = (): Context.Context<RequiredContext> => {\n const validationExit = managedRuntimeAny.runSyncExit(\n Effect.gen(function* () {\n const rt = yield* managedRuntimeAny.contextEffect;\n yield* validateTags(rt, tags);\n return rt as Context.Context<RequiredContext>;\n }),\n );\n return unwrapExit(validationExit);\n };\n\n return {\n managedRuntime: managedRuntimeAny,\n runPromise: async <A, E>(effect: Effect.Effect<A, E, RequiredContext>): Promise<A> => {\n const runtime = await getValidatedRuntimeAsync();\n return runAndForwardErrors(Effect.provideContext(effect, runtime));\n },\n runSync: <A, E>(effect: Effect.Effect<A, E, RequiredContext>): A => {\n const runtime = getValidatedRuntime();\n return Effect.runSync(Effect.provideContext(effect, runtime));\n },\n runSyncExit: <A, E>(effect: Effect.Effect<A, E, RequiredContext>): Exit.Exit<A, E> => {\n const validationExit = managedRuntimeAny.runSyncExit(\n Effect.gen(function* () {\n const rt = yield* managedRuntimeAny.contextEffect;\n yield* validateTags(rt, tags);\n return rt as Context.Context<RequiredContext>;\n }),\n );\n if (Exit.isSuccess(validationExit)) {\n const runtime = validationExit.value;\n return Effect.runSyncExit(Effect.provideContext(effect, runtime));\n }\n return validationExit as Exit.Exit<A, E>;\n },\n runPromiseExit: async <A, E>(effect: Effect.Effect<A, E, RequiredContext>): Promise<Exit.Exit<A, E>> => {\n try {\n const runtime = await getValidatedRuntimeAsync();\n return Effect.runPromiseExit(Effect.provideContext(effect, runtime));\n } catch (error) {\n // If validation failed, return a failure exit\n return Exit.die(error);\n }\n },\n runFork: <A, E>(effect: Effect.Effect<A, E, RequiredContext>): Fiber.Fiber<A, E> => {\n const runtime = getValidatedRuntime();\n return Effect.runFork(Effect.provideContext(effect, runtime));\n },\n contextEffect: Effect.gen(function* () {\n // Return cached runtime if available.\n if (cachedRuntime) {\n return cachedRuntime;\n }\n const rt = yield* managedRuntimeAny.contextEffect;\n yield* validateTags(rt, tags);\n const runtime = rt as Context.Context<RequiredContext>;\n // Cache for future sync calls.\n cachedRuntime = runtime;\n return runtime;\n }).pipe(\n Effect.catch(() =>\n // This should never happen since validateTags uses Effect.die\n Effect.die(new Error('Unexpected error in contextEffect validation')),\n ),\n ),\n dispose: async (): Promise<void> => {\n await managedRuntimeAny.dispose();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;AA4EA,IAAM,gBACJ,SACA,SAEA,OAAO,IAAI,aAAa;CACtB,MAAM,cAAwB,CAAC;CAC/B,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,SAAS,QAAQ,UAAU,SAAS,GAAG;EAC7C,IAAI,OAAO,OAAO,MAAM,GACtB,YAAY,KAAK,IAAI,GAAG;CAE5B;CAEA,IAAI,YAAY,SAAS,GACvB,OAAO,OAAO,OAAO,oBAAI,IAAI,MAAM,qCAAqC,YAAY,KAAK,IAAI,GAAG,CAAC;AAErG,CAAC;;;;AAKH,SAAgB,KACd,gBACA,MACsB;CAEtB,MAAM,oBAAoB;CAG1B,IAAI;CAGJ,IAAI;CAEJ,MAAM,2BAA2B,YAAuD;EACtF,IAAI,CAAC,yBACH,0BAA0B,kBAAkB,WAC1C,OAAO,IAAI,aAAa;GACtB,MAAM,KAAK,OAAO,kBAAkB;GACpC,OAAO,aAAa,IAAI,IAAI;GAC5B,OAAO;EACT,CAAC,CACH;EAEF,OAAO;CACT;CAGA,MAAM,4BAA8D;EAClE,MAAM,iBAAiB,kBAAkB,YACvC,OAAO,IAAI,aAAa;GACtB,MAAM,KAAK,OAAO,kBAAkB;GACpC,OAAO,aAAa,IAAI,IAAI;GAC5B,OAAO;EACT,CAAC,CACH;EACA,OAAO,WAAW,cAAc;CAClC;CAEA,OAAO;EACL,gBAAgB;EAChB,YAAY,OAAa,WAA6D;GACpF,MAAM,UAAU,MAAM,yBAAyB;GAC/C,OAAO,oBAAoB,OAAO,eAAe,QAAQ,OAAO,CAAC;EACnE;EACA,UAAgB,WAAoD;GAClE,MAAM,UAAU,oBAAoB;GACpC,OAAO,OAAO,QAAQ,OAAO,eAAe,QAAQ,OAAO,CAAC;EAC9D;EACA,cAAoB,WAAkE;GACpF,MAAM,iBAAiB,kBAAkB,YACvC,OAAO,IAAI,aAAa;IACtB,MAAM,KAAK,OAAO,kBAAkB;IACpC,OAAO,aAAa,IAAI,IAAI;IAC5B,OAAO;GACT,CAAC,CACH;GACA,IAAI,KAAK,UAAU,cAAc,GAAG;IAClC,MAAM,UAAU,eAAe;IAC/B,OAAO,OAAO,YAAY,OAAO,eAAe,QAAQ,OAAO,CAAC;GAClE;GACA,OAAO;EACT;EACA,gBAAgB,OAAa,WAA2E;GACtG,IAAI;IACF,MAAM,UAAU,MAAM,yBAAyB;IAC/C,OAAO,OAAO,eAAe,OAAO,eAAe,QAAQ,OAAO,CAAC;GACrE,SAAS,OAAO;IAEd,OAAO,KAAK,IAAI,KAAK;GACvB;EACF;EACA,UAAgB,WAAoE;GAClF,MAAM,UAAU,oBAAoB;GACpC,OAAO,OAAO,QAAQ,OAAO,eAAe,QAAQ,OAAO,CAAC;EAC9D;EACA,eAAe,OAAO,IAAI,aAAa;GAErC,IAAI,eACF,OAAO;GAET,MAAM,KAAK,OAAO,kBAAkB;GACpC,OAAO,aAAa,IAAI,IAAI;GAC5B,MAAM,UAAU;GAEhB,gBAAgB;GAChB,OAAO;EACT,CAAC,CAAC,CAAC,KACD,OAAO,YAEL,OAAO,oBAAI,IAAI,MAAM,8CAA8C,CAAC,CACtE,CACF;EACA,SAAS,YAA2B;GAClC,MAAM,kBAAkB,QAAQ;EAClC;CACF;AACF"}
@@ -0,0 +1,3 @@
1
+ import { a as runPromise, i as runInRuntime, n as runAndForwardErrors, o as throwCause, r as runDetached, s as unwrapExit, t as causeToError } from "./chunk-errors.mjs";
2
+ import { a as contextWithoutParentSpan, i as contextFromScope, n as streamFromEmitter, o as withContext, r as acquireReleaseResource, s as asyncTaskTaggingLayer } from "./chunk-EffectEx.mjs";
3
+ export { acquireReleaseResource, asyncTaskTaggingLayer, causeToError, contextFromScope, contextWithoutParentSpan, runAndForwardErrors, runDetached, runInRuntime, runPromise, streamFromEmitter, throwCause, unwrapExit, withContext };
@@ -0,0 +1,22 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ //#region src/internal/GlobalValue.ts
3
+ var GlobalValue_exports = /* @__PURE__ */ __exportAll({ globalValue: () => globalValue });
4
+ var REGISTRY = Symbol.for("@dxos/effect/globalValue");
5
+ var registry = () => {
6
+ const global = globalThis;
7
+ return global[REGISTRY] ??= /* @__PURE__ */ new Map();
8
+ };
9
+ /**
10
+ * Returns the value stored for `id`, computing and storing it on first use.
11
+ *
12
+ * @param id Stable identity for the value; equal ids share one instance process-wide.
13
+ */
14
+ var globalValue = (id, compute) => {
15
+ const map = registry();
16
+ if (!map.has(id)) map.set(id, compute());
17
+ return map.get(id);
18
+ };
19
+ //#endregion
20
+ export { globalValue, GlobalValue_exports as t };
21
+
22
+ //# sourceMappingURL=GlobalValue.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlobalValue.mjs","names":[],"sources":["../../src/internal/GlobalValue.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\n// Effect 4 removed `effect/GlobalValue`. This is a like-for-like replacement: a value memoised\n// against a registry on `globalThis`, so duplicate copies of a module -- bundler chunk splitting,\n// a dependency pulled in twice, a worker realm -- still share one instance.\n\nconst REGISTRY = Symbol.for('@dxos/effect/globalValue');\n\ntype Registry = Map<unknown, unknown>;\n\nconst registry = (): Registry => {\n const global = globalThis as Record<symbol, unknown>;\n return (global[REGISTRY] ??= new Map()) as Registry;\n};\n\n/**\n * Returns the value stored for `id`, computing and storing it on first use.\n *\n * @param id Stable identity for the value; equal ids share one instance process-wide.\n */\nexport const globalValue = <T>(id: unknown, compute: () => T): T => {\n const map = registry();\n if (!map.has(id)) {\n map.set(id, compute());\n }\n return map.get(id) as T;\n};\n"],"mappings":";;;AAUA,IAAM,WAAW,OAAO,IAAI,0BAA0B;AAItD,IAAM,iBAA2B;CAC/B,MAAM,SAAS;CACf,OAAQ,OAAO,8BAAc,IAAI,IAAI;AACvC;;;;;;AAOA,IAAa,eAAkB,IAAa,YAAwB;CAClE,MAAM,MAAM,SAAS;CACrB,IAAI,CAAC,IAAI,IAAI,EAAE,GACb,IAAI,IAAI,IAAI,QAAQ,CAAC;CAEvB,OAAO,IAAI,IAAI,EAAE;AACnB"}
@@ -0,0 +1,107 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import { invariant } from "@dxos/invariant";
5
+ import * as Context from "effect/Context";
6
+ import * as Function from "effect/Function";
7
+ import * as Pipeable from "effect/Pipeable";
8
+ import * as Scope from "effect/Scope";
9
+ //#region src/Hook.ts
10
+ var Hook_exports = /* @__PURE__ */ __exportAll({
11
+ Controller: () => Controller,
12
+ TypeId: () => TypeId,
13
+ controllerLayer: () => controllerLayer,
14
+ emit: () => emit,
15
+ handler: () => handler,
16
+ make: () => make,
17
+ makeController: () => makeController,
18
+ on: () => on,
19
+ subscribe: () => subscribe
20
+ });
21
+ var __dxlog_file = "/__w/dxos/dxos/packages/common/effect/src/Hook.ts";
22
+ var TypeId = "~@dxos/effect/Hook";
23
+ /**
24
+ * Pairs a hook with the function that runs on it, ready to pass to `subscribe`. Dual: called with
25
+ * one argument it returns the pipeable form, so `handler(fn)` composes onto the hook.
26
+ *
27
+ * @param hook The hook to bind to.
28
+ * @param handler Runs per emit, receiving the hook's payload.
29
+ * @returns The pairing `subscribe` registers.
30
+ */
31
+ var handler = Function.dual(2, (hook, handler) => ({
32
+ hook,
33
+ handler
34
+ }));
35
+ /**
36
+ * Declares a hook. Curried so the payload type is given explicitly while the id stays inferred:
37
+ * `make<Payload>()('my/id')`.
38
+ *
39
+ * @param id Identifies the hook across package and bundle boundaries, so it must be unique.
40
+ * @param options.strategy How subscribers are dispatched; `parallel` by default.
41
+ * @returns The hook to emit and subscribe to.
42
+ */
43
+ var make = () => (id, options) => ({
44
+ ...Pipeable.Prototype,
45
+ [TypeId]: { _Data: void 0 },
46
+ id,
47
+ strategy: options?.strategy ?? "parallel"
48
+ });
49
+ var Controller = class extends Context.Service()("@dxos/effect/Hook.Controller") {};
50
+ /**
51
+ * Registers the handler until the current scope closes; unsubscription is a plain removal.
52
+ */
53
+ var subscribe = (handler) => Controller.pipe(Effect.flatMap((controller) => controller.subscribe(handler)));
54
+ /**
55
+ * Subscribes `fn` to `hook` for the current scope: `handler` and `subscribe` in one call.
56
+ */
57
+ var on = (hook, fn) => subscribe(handler(hook, fn));
58
+ /**
59
+ * Dispatches to every subscriber and completes once all of them have — including the hooks those
60
+ * handlers emit in turn — so an emit doubles as a barrier for the work the hook triggers. A
61
+ * handler that fails fails the emitter as a defect, so this is not a fire-and-forget notification.
62
+ */
63
+ var emit = (hook, payload) => Controller.pipe(Effect.flatMap((controller) => controller.emit(hook, payload)));
64
+ var makeController = () => {
65
+ const subscribers = /* @__PURE__ */ new Map();
66
+ const controller = {
67
+ subscribe: (handler) => Effect.gen(function* () {
68
+ const scope = yield* Effect.scope;
69
+ const entry = subscribers.get(handler.hook.id) ?? {
70
+ hook: handler.hook,
71
+ handlers: /* @__PURE__ */ new Set()
72
+ };
73
+ invariant(entry.hook.strategy === handler.hook.strategy, `Hook id collision: ${handler.hook.id} is declared with two dispatch strategies`, {
74
+ "~LogMeta": "~LogMeta",
75
+ F: __dxlog_file,
76
+ L: 132,
77
+ S: this,
78
+ A: ["entry.hook.strategy === handler.hook.strategy", "`Hook id collision: ${handler.hook.id} is declared with two dispatch strategies`"]
79
+ });
80
+ subscribers.set(handler.hook.id, entry);
81
+ entry.handlers.add(handler);
82
+ yield* Scope.addFinalizer(scope, Effect.sync(() => {
83
+ entry.handlers.delete(handler);
84
+ if (entry.handlers.size === 0) subscribers.delete(handler.hook.id);
85
+ }));
86
+ }),
87
+ emit: (hook, payload) => Effect.gen(function* () {
88
+ const handlers = subscribers.get(hook.id)?.handlers;
89
+ if (handlers === void 0) return;
90
+ const dispatch = Array.from(handlers, (entry) => entry.handler(payload));
91
+ if (hook.strategy === "serial") yield* Effect.forEach(dispatch, (effect) => effect, { discard: true });
92
+ else yield* Effect.all(dispatch, {
93
+ concurrency: "unbounded",
94
+ discard: true
95
+ });
96
+ }).pipe(Effect.provideService(Controller, controller))
97
+ };
98
+ return controller;
99
+ };
100
+ /**
101
+ * One controller per layer build, so separate runtimes never share subscribers.
102
+ */
103
+ var controllerLayer = Layer.sync(Controller, makeController);
104
+ //#endregion
105
+ export { Controller, TypeId, controllerLayer, emit, handler, make, makeController, on, subscribe, Hook_exports as t };
106
+
107
+ //# sourceMappingURL=Hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Hook.mjs","names":[],"sources":["../../src/Hook.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Layer from 'effect/Layer';\nimport * as Pipeable from 'effect/Pipeable';\nimport * as Scope from 'effect/Scope';\n\nimport { invariant } from '@dxos/invariant';\n\n// @import-as-namespace\n\n/**\n * How the handlers of one hook are dispatched: `parallel` runs them concurrently and is the\n * default; `serial` runs them one after another in subscription order.\n */\nexport type Strategy = 'serial' | 'parallel';\n\nexport const TypeId = '~@dxos/effect/Hook';\nexport type TypeId = typeof TypeId;\n\nexport interface Hook<Id extends string, T> extends Pipeable.Pipeable {\n readonly [TypeId]: {\n _Data: T;\n };\n readonly id: Id;\n readonly strategy: Strategy;\n}\n\nexport type Any = {\n readonly [TypeId]: {\n _Data: any;\n };\n readonly id: string;\n readonly strategy: Strategy;\n};\n\nexport type Payload<E extends Any> = E[TypeId]['_Data'];\n\n/**\n * Handlers run in the subscriber's controller so they can emit further hooks; failures are defects\n * since a hook cannot enumerate the errors of every subscriber.\n */\nexport type HandlerFn<E extends Any> = (payload: Payload<E>) => Effect.Effect<void, never, Controller>;\n\nexport interface Handler<E extends Any> {\n readonly hook: E;\n readonly handler: HandlerFn<E>;\n}\n\n/**\n * Pairs a hook with the function that runs on it, ready to pass to `subscribe`. Dual: called with\n * one argument it returns the pipeable form, so `handler(fn)` composes onto the hook.\n *\n * @param hook The hook to bind to.\n * @param handler Runs per emit, receiving the hook's payload.\n * @returns The pairing `subscribe` registers.\n */\nexport const handler: {\n <E extends Any>(hook: E, handler: HandlerFn<E>): Handler<E>;\n <E extends Any>(handler: HandlerFn<E>): (hook: E) => Handler<E>;\n} = Function.dual(2, <E extends Any>(hook: E, handler: HandlerFn<E>): Handler<E> => ({ hook, handler }));\n\n/**\n * Declares a hook. Curried so the payload type is given explicitly while the id stays inferred:\n * `make<Payload>()('my/id')`.\n *\n * @param id Identifies the hook across package and bundle boundaries, so it must be unique.\n * @param options.strategy How subscribers are dispatched; `parallel` by default.\n * @returns The hook to emit and subscribe to.\n */\nexport const make =\n <const T>() =>\n <const Id extends string>(id: Id, options?: { strategy?: Strategy }): Hook<Id, T> => ({\n ...Pipeable.Prototype,\n [TypeId]: { _Data: undefined as any },\n id,\n strategy: options?.strategy ?? 'parallel',\n });\n\nexport interface ControllerService {\n subscribe<E extends Any>(handler: Handler<E>): Effect.Effect<void, never, Scope.Scope>;\n emit<E extends Any>(hook: E, payload: Payload<E>): Effect.Effect<void>;\n}\n\nexport class Controller extends Context.Service<Controller, ControllerService>()('@dxos/effect/Hook.Controller') {}\n\n/**\n * Registers the handler until the current scope closes; unsubscription is a plain removal.\n */\nexport const subscribe = <E extends Any>(handler: Handler<E>): Effect.Effect<void, never, Controller | Scope.Scope> =>\n Controller.pipe(Effect.flatMap((controller) => controller.subscribe(handler)));\n\n/**\n * Subscribes `fn` to `hook` for the current scope: `handler` and `subscribe` in one call.\n */\nexport const on = <E extends Any>(hook: E, fn: HandlerFn<E>): Effect.Effect<void, never, Controller | Scope.Scope> =>\n subscribe(handler(hook, fn));\n\n/**\n * Dispatches to every subscriber and completes once all of them have — including the hooks those\n * handlers emit in turn — so an emit doubles as a barrier for the work the hook triggers. A\n * handler that fails fails the emitter as a defect, so this is not a fire-and-forget notification.\n */\nexport const emit = <E extends Any>(hook: E, payload: Payload<E>): Effect.Effect<void, never, Controller> =>\n Controller.pipe(Effect.flatMap((controller) => controller.emit(hook, payload)));\n\n// Erases the payload type so handlers for different hooks can share one registry.\ntype AnyHandler = {\n readonly hook: Any;\n readonly handler: (payload: any) => Effect.Effect<void, never, Controller>;\n};\n\nexport const makeController = (): ControllerService => {\n // Keyed by id, not by the hook object: these hooks cross package and bundle boundaries, and a\n // module instantiated twice (dual resolution, a dep-optimizer re-bundle, HMR) would otherwise give\n // publisher and subscriber different objects for the same hook and turn the cascade into a silent\n // no-op. The registry holds the hook it first saw, so a genuine id collision is loud instead.\n const subscribers = new Map<string, { readonly hook: Any; readonly handlers: Set<AnyHandler> }>();\n\n const controller: ControllerService = {\n subscribe: (handler) =>\n Effect.gen(function* () {\n const scope = yield* Effect.scope;\n const entry = subscribers.get(handler.hook.id) ?? { hook: handler.hook, handlers: new Set<AnyHandler>() };\n // A duplicated module and a genuine id collision both present as two objects with one id, so\n // identity cannot separate them; a differing strategy is the one inconsistency that can only\n // be a collision, and it is worth failing on rather than dispatching two contracts as one.\n invariant(\n entry.hook.strategy === handler.hook.strategy,\n `Hook id collision: ${handler.hook.id} is declared with two dispatch strategies`,\n );\n subscribers.set(handler.hook.id, entry);\n entry.handlers.add(handler);\n yield* Scope.addFinalizer(\n scope,\n Effect.sync(() => {\n entry.handlers.delete(handler);\n if (entry.handlers.size === 0) {\n subscribers.delete(handler.hook.id);\n }\n }),\n );\n }),\n emit: (hook, payload) =>\n Effect.gen(function* () {\n const handlers = subscribers.get(hook.id)?.handlers;\n if (handlers === undefined) {\n return;\n }\n const dispatch = Array.from(handlers, (entry) => entry.handler(payload));\n if (hook.strategy === 'serial') {\n yield* Effect.forEach(dispatch, (effect) => effect, { discard: true });\n } else {\n yield* Effect.all(dispatch, { concurrency: 'unbounded', discard: true });\n }\n }).pipe(Effect.provideService(Controller, controller)),\n };\n\n return controller;\n};\n\n/**\n * One controller per layer build, so separate runtimes never share subscribers.\n */\nexport const controllerLayer: Layer.Layer<Controller> = Layer.sync(Controller, makeController);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,IAAa,SAAS;;;;;;;;;AAwCtB,IAAa,UAGT,SAAS,KAAK,IAAmB,MAAS,aAAuC;CAAE;CAAM;AAAQ,EAAE;;;;;;;;;AAUvG,IAAa,cAEe,IAAQ,aAAoD;CACpF,GAAG,SAAS;EACX,SAAS,EAAE,OAAO,KAAA,EAAiB;CACpC;CACA,UAAU,SAAS,YAAY;AACjC;AAOF,IAAa,aAAb,cAAgC,QAAQ,QAAuC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC;;;;AAKlH,IAAa,aAA4B,YACvC,WAAW,KAAK,OAAO,SAAS,eAAe,WAAW,UAAU,OAAO,CAAC,CAAC;;;;AAK/E,IAAa,MAAqB,MAAS,OACzC,UAAU,QAAQ,MAAM,EAAE,CAAC;;;;;;AAO7B,IAAa,QAAuB,MAAS,YAC3C,WAAW,KAAK,OAAO,SAAS,eAAe,WAAW,KAAK,MAAM,OAAO,CAAC,CAAC;AAQhF,IAAa,uBAA0C;CAKrD,MAAM,8BAAc,IAAI,IAAwE;CAEhG,MAAM,aAAgC;EACpC,YAAY,YACV,OAAO,IAAI,aAAa;GACtB,MAAM,QAAQ,OAAO,OAAO;GAC5B,MAAM,QAAQ,YAAY,IAAI,QAAQ,KAAK,EAAE,KAAK;IAAE,MAAM,QAAQ;IAAM,0BAAU,IAAI,IAAgB;GAAE;GAIxG,UACE,MAAM,KAAK,aAAa,QAAQ,KAAK,UACrC,sBAAsB,QAAQ,KAAK,GAAG,4CACzC;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,CAAA,iDAAA,kFAAA;GAAA,CAAC;GACA,YAAY,IAAI,QAAQ,KAAK,IAAI,KAAK;GACtC,MAAM,SAAS,IAAI,OAAO;GAC1B,OAAO,MAAM,aACX,OACA,OAAO,WAAW;IAChB,MAAM,SAAS,OAAO,OAAO;IAC7B,IAAI,MAAM,SAAS,SAAS,GAC1B,YAAY,OAAO,QAAQ,KAAK,EAAE;GAEtC,CAAC,CACH;EACF,CAAC;EACH,OAAO,MAAM,YACX,OAAO,IAAI,aAAa;GACtB,MAAM,WAAW,YAAY,IAAI,KAAK,EAAE,CAAC,EAAE;GAC3C,IAAI,aAAa,KAAA,GACf;GAEF,MAAM,WAAW,MAAM,KAAK,WAAW,UAAU,MAAM,QAAQ,OAAO,CAAC;GACvE,IAAI,KAAK,aAAa,UACpB,OAAO,OAAO,QAAQ,WAAW,WAAW,QAAQ,EAAE,SAAS,KAAK,CAAC;QAErE,OAAO,OAAO,IAAI,UAAU;IAAE,aAAa;IAAa,SAAS;GAAK,CAAC;EAE3E,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,YAAY,UAAU,CAAC;CACzD;CAEA,OAAO;AACT;;;;AAKA,IAAa,kBAA2C,MAAM,KAAK,YAAY,cAAc"}
@@ -0,0 +1,80 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import * as Effect from "effect/Effect";
3
+ //#region src/Performance.ts
4
+ var Performance_exports = /* @__PURE__ */ __exportAll({
5
+ TRACK_ENTRIES_ENABLED: () => TRACK_ENTRIES_ENABLED,
6
+ addTrackEntry: () => addTrackEntry,
7
+ summarizeDetail: () => summarizeDetail,
8
+ trackEntry: () => trackEntry
9
+ });
10
+ /**
11
+ * Whether track entries reach the performance timeline: on under the dev server, off in a production
12
+ * build unless it was made with `VITE_PERF_TRACK_ENTRIES=true`. The bundler folds the constant, so a
13
+ * gated call site costs nothing in a build that has it off.
14
+ *
15
+ * Entries are not free. `performance.measure` structured-clones `detail` on every call and keeps every
16
+ * entry for the life of the realm, so a per-query entry carrying bound parameters was the largest
17
+ * allocating mechanism in a Composer tab once the log store's sweep was fixed.
18
+ */
19
+ var TRACK_ENTRIES_ENABLED = Boolean(false) || false;
20
+ /** Longer strings are cut in the entry, since the clone would otherwise copy them whole. */
21
+ var MAX_STRING_LENGTH = 256;
22
+ var MAX_ARRAY_LENGTH = 64;
23
+ var MAX_DEPTH = 3;
24
+ var summarize = (value, depth) => {
25
+ if (typeof value === "string") return value.length > MAX_STRING_LENGTH ? `${value.slice(0, MAX_STRING_LENGTH)}…(${value.length} chars)` : value;
26
+ if (value instanceof Uint8Array) return `<Uint8Array ${value.length} bytes>`;
27
+ if (value instanceof ArrayBuffer) return `<ArrayBuffer ${value.byteLength} bytes>`;
28
+ if (Array.isArray(value)) {
29
+ if (value.length > MAX_ARRAY_LENGTH) return `<Array ${value.length} items>`;
30
+ return depth >= MAX_DEPTH ? `<Array ${value.length} items>` : value.map((item) => summarize(item, depth + 1));
31
+ }
32
+ if (value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
33
+ if (depth >= MAX_DEPTH) return `<Object ${Object.keys(value).length} keys>`;
34
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, summarize(item, depth + 1)]));
35
+ }
36
+ return value;
37
+ };
38
+ /**
39
+ * Bounds a value before it goes into an entry's `detail`: a blob or long string becomes a type-and-size
40
+ * marker, a large array a count, and nesting stops at a fixed depth. Anything with a prototype other than
41
+ * `Object` (class instances, ECHO objects) passes through untouched, as the clone would fail on it anyway.
42
+ */
43
+ var summarizeDetail = (value) => summarize(value, 0);
44
+ /**
45
+ * Puts one entry on the performance timeline, with `detail` and `devtools.properties` bounded by
46
+ * {@link summarizeDetail}. A no-op unless {@link TRACK_ENTRIES_ENABLED}.
47
+ */
48
+ var trackEntry = (options) => {
49
+ if (!TRACK_ENTRIES_ENABLED) return;
50
+ performance.measure(options.name, {
51
+ start: options.start,
52
+ end: options.end ?? performance.now(),
53
+ detail: {
54
+ ...options.detail && summarizeDetail(options.detail),
55
+ devtools: options.devtools && {
56
+ ...options.devtools,
57
+ properties: options.devtools.properties?.map(([key, value]) => [key, summarizeDetail(value)])
58
+ }
59
+ }
60
+ });
61
+ };
62
+ /**
63
+ * Puts the effect span on the performance timeline in DevTools. See {@link trackEntry}.
64
+ */
65
+ var addTrackEntry = (options) => (effect) => {
66
+ if (!TRACK_ENTRIES_ENABLED) return effect;
67
+ return Effect.gen(function* () {
68
+ const start = performance.now();
69
+ const exit = yield* Effect.exit(effect);
70
+ trackEntry({
71
+ start,
72
+ ...typeof options === "function" ? options(exit) : options
73
+ });
74
+ return yield* exit;
75
+ });
76
+ };
77
+ //#endregion
78
+ export { TRACK_ENTRIES_ENABLED, addTrackEntry, summarizeDetail, Performance_exports as t, trackEntry };
79
+
80
+ //# sourceMappingURL=Performance.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Performance.mjs","names":[],"sources":["../../src/Performance.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport type * as Exit from 'effect/Exit';\n\n/**\n * Whether track entries reach the performance timeline: on under the dev server, off in a production\n * build unless it was made with `VITE_PERF_TRACK_ENTRIES=true`. The bundler folds the constant, so a\n * gated call site costs nothing in a build that has it off.\n *\n * Entries are not free. `performance.measure` structured-clones `detail` on every call and keeps every\n * entry for the life of the realm, so a per-query entry carrying bound parameters was the largest\n * allocating mechanism in a Composer tab once the log store's sweep was fixed.\n */\nexport const TRACK_ENTRIES_ENABLED: boolean =\n Boolean(import.meta.env?.DEV) || import.meta.env?.VITE_PERF_TRACK_ENTRIES === 'true';\n\n/** Longer strings are cut in the entry, since the clone would otherwise copy them whole. */\nconst MAX_STRING_LENGTH = 256;\nconst MAX_ARRAY_LENGTH = 64;\nconst MAX_DEPTH = 3;\n\nconst summarize = (value: unknown, depth: number): unknown => {\n if (typeof value === 'string') {\n return value.length > MAX_STRING_LENGTH ? `${value.slice(0, MAX_STRING_LENGTH)}…(${value.length} chars)` : value;\n }\n if (value instanceof Uint8Array) {\n return `<Uint8Array ${value.length} bytes>`;\n }\n if (value instanceof ArrayBuffer) {\n return `<ArrayBuffer ${value.byteLength} bytes>`;\n }\n if (Array.isArray(value)) {\n if (value.length > MAX_ARRAY_LENGTH) {\n return `<Array ${value.length} items>`;\n }\n return depth >= MAX_DEPTH ? `<Array ${value.length} items>` : value.map((item) => summarize(item, depth + 1));\n }\n if (value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {\n if (depth >= MAX_DEPTH) {\n return `<Object ${Object.keys(value).length} keys>`;\n }\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, summarize(item, depth + 1)]));\n }\n return value;\n};\n\n/**\n * Bounds a value before it goes into an entry's `detail`: a blob or long string becomes a type-and-size\n * marker, a large array a count, and nesting stops at a fixed depth. Anything with a prototype other than\n * `Object` (class instances, ECHO objects) passes through untouched, as the clone would fail on it anyway.\n */\nexport const summarizeDetail = (value: unknown): unknown => summarize(value, 0);\n\nexport interface DevtoolsOptions {\n /**\n * @example 'track-entry'\n */\n dataType: string;\n track: string;\n trackGroup: string;\n /**\n * @example 'tertiary-dark'\n */\n color: string;\n properties?: [string, any][];\n tooltipText?: string;\n}\n\nexport interface TrackEntryOptions {\n name: string;\n start: number;\n /** Defaults to now. */\n end?: number;\n devtools?: DevtoolsOptions;\n detail?: Record<string, unknown>;\n}\n\nexport interface AddTrackEntryOptions {\n name: string;\n devtools?: DevtoolsOptions;\n detail?: Record<string, unknown>;\n}\n\n/**\n * Puts one entry on the performance timeline, with `detail` and `devtools.properties` bounded by\n * {@link summarizeDetail}. A no-op unless {@link TRACK_ENTRIES_ENABLED}.\n */\nexport const trackEntry = (options: TrackEntryOptions): void => {\n if (!TRACK_ENTRIES_ENABLED) {\n return;\n }\n performance.measure(options.name, {\n start: options.start,\n end: options.end ?? performance.now(),\n detail: {\n ...(options.detail && (summarizeDetail(options.detail) as Record<string, unknown>)),\n devtools: options.devtools && {\n ...options.devtools,\n properties: options.devtools.properties?.map(([key, value]) => [key, summarizeDetail(value)]),\n },\n },\n });\n};\n\n/**\n * Puts the effect span on the performance timeline in DevTools. See {@link trackEntry}.\n */\nexport const addTrackEntry =\n <A, E>(options: AddTrackEntryOptions | ((exit: Exit.Exit<A, E>) => AddTrackEntryOptions)) =>\n <R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => {\n if (!TRACK_ENTRIES_ENABLED) {\n return effect;\n }\n return Effect.gen(function* () {\n const start = performance.now();\n const exit = yield* Effect.exit(effect);\n trackEntry({ start, ...(typeof options === 'function' ? options(exit) : options) });\n return yield* exit;\n });\n };\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgBA,IAAa,wBACX,QAAA,KAA4B,KAAK;;AAGnC,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,YAAY;AAElB,IAAM,aAAa,OAAgB,UAA2B;CAC5D,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,SAAS,oBAAoB,GAAG,MAAM,MAAM,GAAG,iBAAiB,EAAE,IAAI,MAAM,OAAO,WAAW;CAE7G,IAAI,iBAAiB,YACnB,OAAO,eAAe,MAAM,OAAO;CAErC,IAAI,iBAAiB,aACnB,OAAO,gBAAgB,MAAM,WAAW;CAE1C,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,IAAI,MAAM,SAAS,kBACjB,OAAO,UAAU,MAAM,OAAO;EAEhC,OAAO,SAAS,YAAY,UAAU,MAAM,OAAO,WAAW,MAAM,KAAK,SAAS,UAAU,MAAM,QAAQ,CAAC,CAAC;CAC9G;CACA,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,eAAe,KAAK,MAAM,OAAO,WAAW;EACpG,IAAI,SAAS,WACX,OAAO,WAAW,OAAO,KAAK,KAAK,CAAC,CAAC,OAAO;EAE9C,OAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;CACzG;CACA,OAAO;AACT;;;;;;AAOA,IAAa,mBAAmB,UAA4B,UAAU,OAAO,CAAC;;;;;AAoC9E,IAAa,cAAc,YAAqC;CAC9D,IAAI,CAAC,uBACH;CAEF,YAAY,QAAQ,QAAQ,MAAM;EAChC,OAAO,QAAQ;EACf,KAAK,QAAQ,OAAO,YAAY,IAAI;EACpC,QAAQ;GACN,GAAI,QAAQ,UAAW,gBAAgB,QAAQ,MAAM;GACrD,UAAU,QAAQ,YAAY;IAC5B,GAAG,QAAQ;IACX,YAAY,QAAQ,SAAS,YAAY,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,gBAAgB,KAAK,CAAC,CAAC;GAC9F;EACF;CACF,CAAC;AACH;;;;AAKA,IAAa,iBACJ,aACH,WAA2D;CAC7D,IAAI,CAAC,uBACH,OAAO;CAET,OAAO,OAAO,IAAI,aAAa;EAC7B,MAAM,QAAQ,YAAY,IAAI;EAC9B,MAAM,OAAO,OAAO,OAAO,KAAK,MAAM;EACtC,WAAW;GAAE;GAAO,GAAI,OAAO,YAAY,aAAa,QAAQ,IAAI,IAAI;EAAS,CAAC;EAClF,OAAO,OAAO;CAChB,CAAC;AACH"}
@@ -0,0 +1,43 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { n as makeGlobalTracer } from "./chunk-otel.mjs";
3
+ import { n as runAndForwardErrors, s as unwrapExit } from "./chunk-errors.mjs";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Layer from "effect/Layer";
6
+ import * as Context from "effect/Context";
7
+ import * as Tracer from "effect/Tracer";
8
+ //#region src/RuntimeProvider.ts
9
+ var RuntimeProvider_exports = /* @__PURE__ */ __exportAll({
10
+ currentRuntime: () => currentRuntime,
11
+ provide: () => provide,
12
+ runPromise: () => runPromise,
13
+ toLayer: () => toLayer
14
+ });
15
+ var defaultTracer;
16
+ var withDefaultTracer = (context) => {
17
+ defaultTracer ??= Context.make(Tracer.Tracer, makeGlobalTracer("@dxos/effect/RuntimeProvider"));
18
+ return Context.merge(defaultTracer, context);
19
+ };
20
+ /**
21
+ * Bridges a runtime provider into a {@link Layer} exposing its services, so a stack that resolves
22
+ * dependencies via `RuntimeProvider.currentRuntime` can be provided from an existing runtime.
23
+ */
24
+ var toLayer = (provider) => Layer.effectContext(provider);
25
+ /**
26
+ * @returns Runtime provider from the current context.
27
+ */
28
+ var currentRuntime = () => Effect.context().pipe(Effect.map(Effect.succeed));
29
+ /**
30
+ * Run effect, within runtime, clean errors and fix stack-traces.
31
+ */
32
+ var runPromise = (provider) => async (effect) => {
33
+ const context = await runAndForwardErrors(provider);
34
+ return unwrapExit(await Effect.runPromiseExit(Effect.provideContext(effect, withDefaultTracer(context))));
35
+ };
36
+ /**
37
+ * Provide services from runtime provider to effect.
38
+ */
39
+ var provide = (runtimeProvider) => (effect) => Effect.flatMap(runtimeProvider, (context) => Effect.provideContext(effect, withDefaultTracer(context)));
40
+ //#endregion
41
+ export { currentRuntime, provide, runPromise, RuntimeProvider_exports as t, toLayer };
42
+
43
+ //# sourceMappingURL=RuntimeProvider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RuntimeProvider.mjs","names":[],"sources":["../../src/RuntimeProvider.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Tracer from 'effect/Tracer';\n\nimport { runAndForwardErrors, unwrapExit } from './internal/errors.ts';\nimport { makeGlobalTracer } from './otel.ts';\n\nlet defaultTracer: Context.Context<never> | undefined;\n\nconst withDefaultTracer = <R>(context: Context.Context<R>): Context.Context<R> => {\n defaultTracer ??= Context.make(Tracer.Tracer, makeGlobalTracer('@dxos/effect/RuntimeProvider'));\n return Context.merge(defaultTracer, context);\n};\n\n/**\n * Provides effect runtime with services to run effects.\n *\n * Effect 4 removed the `Runtime<R>` value this used to carry -- its `Runtime` module is now only\n * about `runMain` -- so the provider yields the service context directly. That is what every\n * consumer actually used the runtime for, and it drops a layer of indirection.\n */\nexport type RuntimeProvider<R> = Effect.Effect<Context.Context<R>>;\n\n/**\n * Bridges a runtime provider into a {@link Layer} exposing its services, so a stack that resolves\n * dependencies via `RuntimeProvider.currentRuntime` can be provided from an existing runtime.\n */\nexport const toLayer = <R>(provider: RuntimeProvider<R>): Layer.Layer<R> => Layer.effectContext(provider);\n\n/**\n * @returns Runtime provider from the current context.\n */\nexport const currentRuntime = <R = never>(): Effect.Effect<RuntimeProvider<R>, never, R> =>\n Effect.context<R>().pipe(Effect.map(Effect.succeed));\n\n/**\n * Run effect, within runtime, clean errors and fix stack-traces.\n */\nexport const runPromise =\n <R>(provider: RuntimeProvider<R>) =>\n async <A>(effect: Effect.Effect<A, any, R>): Promise<A> => {\n const context = await runAndForwardErrors(provider);\n return unwrapExit(await Effect.runPromiseExit(Effect.provideContext(effect, withDefaultTracer(context))));\n };\n\n/**\n * Provide services from runtime provider to effect.\n */\nexport const provide: {\n <R2>(runtime: RuntimeProvider<R2>): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, R2>>;\n} = (runtimeProvider) => (effect) =>\n Effect.flatMap(runtimeProvider, (context) => Effect.provideContext(effect, withDefaultTracer(context)));\n"],"mappings":";;;;;;;;;;;;;;AAYA,IAAI;AAEJ,IAAM,qBAAwB,YAAoD;CAChF,kBAAkB,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,8BAA8B,CAAC;CAC9F,OAAO,QAAQ,MAAM,eAAe,OAAO;AAC7C;;;;;AAeA,IAAa,WAAc,aAAiD,MAAM,cAAc,QAAQ;;;;AAKxG,IAAa,uBACX,OAAO,QAAW,CAAC,CAAC,KAAK,OAAO,IAAI,OAAO,OAAO,CAAC;;;;AAKrD,IAAa,cACP,aACJ,OAAU,WAAiD;CACzD,MAAM,UAAU,MAAM,oBAAoB,QAAQ;CAClD,OAAO,WAAW,MAAM,OAAO,eAAe,OAAO,eAAe,QAAQ,kBAAkB,OAAO,CAAC,CAAC,CAAC;AAC1G;;;;AAKF,IAAa,WAER,qBAAqB,WACxB,OAAO,QAAQ,kBAAkB,YAAY,OAAO,eAAe,QAAQ,kBAAkB,OAAO,CAAC,CAAC"}