@junejs/db 0.0.34-dev.1 → 0.1.0-dev.2

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.
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { RequestScope, blob, currentLocale, currentServices, db, ensureScope, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale } from "./scope.js";
2
- export { type RequestScope, blob, currentLocale, currentServices, db, ensureScope, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
1
+ import { RequestScope, blob, currentLocale, currentServices, db, ensureScope, isolateLocal, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale } from "./scope.js";
2
+ export { type RequestScope, blob, currentLocale, currentServices, db, ensureScope, isolateLocal, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { blob, currentLocale, currentServices, db, ensureScope, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale } from "./scope.js";
2
- export { blob, currentLocale, currentServices, db, ensureScope, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
1
+ import { blob, currentLocale, currentServices, db, ensureScope, isolateLocal, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale } from "./scope.js";
2
+ export { blob, currentLocale, currentServices, db, ensureScope, isolateLocal, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
package/dist/scope.d.ts CHANGED
@@ -9,6 +9,7 @@ type RequestScope = {
9
9
  declare function ensureScope(): Promise<void>;
10
10
  declare function runInScope<T>(scope: RequestScope, fn: () => T): T;
11
11
  declare function requestLocal<T>(key: symbol, make: () => T): T;
12
+ declare function isolateLocal<T>(key: string | symbol, make: () => T): T;
12
13
  declare function setRequestLocale(locale: string): void;
13
14
  declare function currentLocale(): string | undefined;
14
15
  declare function currentServices<T = unknown>(): T | undefined;
@@ -17,4 +18,4 @@ declare const db: JuneDb;
17
18
  declare const kv: JuneKv;
18
19
  declare const blob: JuneBlob;
19
20
  //#endregion
20
- export { RequestScope, blob, currentLocale, currentServices, db, ensureScope, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
21
+ export { RequestScope, blob, currentLocale, currentServices, db, ensureScope, isolateLocal, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
package/dist/scope.js CHANGED
@@ -20,6 +20,12 @@ function requestLocal(key, make) {
20
20
  if (!locals.has(key)) locals.set(key, make());
21
21
  return locals.get(key);
22
22
  }
23
+ const ISOLATE_LOCALS_KEY = Symbol.for("june.isolateLocals");
24
+ const isolateLocals = globalThis[ISOLATE_LOCALS_KEY] ??= /* @__PURE__ */ new Map();
25
+ function isolateLocal(key, make) {
26
+ if (!isolateLocals.has(key)) isolateLocals.set(key, make());
27
+ return isolateLocals.get(key);
28
+ }
23
29
  function setRequestLocale(locale) {
24
30
  const store = als?.getStore();
25
31
  if (store) store.locale = locale;
@@ -59,4 +65,4 @@ const db = new Proxy({}, { get(_t, prop) {
59
65
  const kv = ambient("kv");
60
66
  const blob = ambient("blob");
61
67
  //#endregion
62
- export { blob, currentLocale, currentServices, db, ensureScope, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
68
+ export { blob, currentLocale, currentServices, db, ensureScope, isolateLocal, kv, registerSqlTagger, requestLocal, runInScope, setRequestLocale };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junejs/db",
3
- "version": "0.0.34-dev.1",
3
+ "version": "0.1.0-dev.2",
4
4
  "description": "June — the agent-native React framework. Ambient data resources (db/kv/blob).",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ export {
10
10
  runInScope,
11
11
  ensureScope,
12
12
  requestLocal,
13
+ isolateLocal,
13
14
  setRequestLocale,
14
15
  currentLocale,
15
16
  currentServices,
package/src/scope.ts CHANGED
@@ -95,6 +95,48 @@ export function requestLocal<T>(key: symbol, make: () => T): T {
95
95
  return locals.get(key) as T;
96
96
  }
97
97
 
98
+ // ── isolate-scoped state (the sibling of requestLocal) ────────────────────────
99
+ //
100
+ // `requestLocal` holds state that MUST die with the request. This holds state
101
+ // that must OUTLIVE it: a connection pool, a token cache, a compiled index —
102
+ // anything expensive whose whole value is being reused across requests.
103
+ //
104
+ // It exists because June's own architecture makes the naive version wrong. A
105
+ // ChannelFactory and the `services` provider are resolved PER REQUEST (a Worker
106
+ // has no env at module top-level, so the host must call them inside an
107
+ // invocation). Anything they construct — including a `new Map()` cache — is
108
+ // therefore rebuilt per request, and an app that "added a 5-minute cache"
109
+ // silently never gets a hit. Hoisting to module scope by hand works but has to
110
+ // be re-derived by every app, and a hand-rolled module Map also splits in two
111
+ // when workspace symlinks give the app and the framework different copies of a
112
+ // module. This keys off `globalThis` (the same trick ACTION_REGISTRY uses), so
113
+ // one key means one value per isolate however many module instances load.
114
+ //
115
+ // ⚠ That cross-instance guarantee needs a key with cross-instance identity: a
116
+ // STRING, or `Symbol.for("…")` from the global symbol registry. A plain
117
+ // `Symbol("…")` is a fresh identity in each module instance, so two copies of
118
+ // the module would each make their own value — fine when a single module owns
119
+ // the key privately, wrong if sharing is the point.
120
+ //
121
+ // "Isolate" = the Worker isolate, or the Node/Bun process. Lifetime is the
122
+ // host's, not the request's: values are never evicted here, so anything with a
123
+ // bound (a TTL cache, an LRU) must bound itself.
124
+ //
125
+ // const tokens = isolateLocal("myapp.tokens", () => new Map<string, string>());
126
+ //
127
+ // Keys are namespaced strings (or symbols) — prefix with your app/package name.
128
+ // A key collision returns the FIRST value, so an unprefixed "cache" is a bug
129
+ // waiting to happen across packages.
130
+ const ISOLATE_LOCALS_KEY = Symbol.for("june.isolateLocals");
131
+ const isolateLocals: Map<string | symbol, unknown> = ((
132
+ globalThis as Record<symbol, Map<string | symbol, unknown> | undefined>
133
+ )[ISOLATE_LOCALS_KEY] ??= new Map());
134
+
135
+ export function isolateLocal<T>(key: string | symbol, make: () => T): T {
136
+ if (!isolateLocals.has(key)) isolateLocals.set(key, make());
137
+ return isolateLocals.get(key) as T;
138
+ }
139
+
98
140
  // The host sets the resolved locale onto the active scope after it resolves it
99
141
  // (the scope is opened before routing, so the locale arrives mid-request). A no-op
100
142
  // outside a scope, like the ambient resources.