1tube 0.1.21 → 0.1.23

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/src/discovery.ts CHANGED
@@ -28,13 +28,6 @@ export interface DiscoveryProgress {
28
28
  export interface DiscoveryOptions {
29
29
  /** When set, appended as `?v=` to module URLs to force re-transpilation. */
30
30
  cacheBust?: string;
31
- /**
32
- * Optional alternate root for dynamic imports. Discovery and manifests still
33
- * read from `functionsDir`; only module URLs are resolved under this root.
34
- * Used by Deno-backend HMR snapshots so transitive relative imports get a
35
- * fresh file URL namespace.
36
- */
37
- importRoot?: string;
38
31
  /** Restrict loading to this set of function names (others are skipped entirely). */
39
32
  only?: ReadonlySet<string>;
40
33
  /** Max number of concurrent dynamic imports. Defaults to 8. */
@@ -80,9 +73,6 @@ export async function discoverAndLoad(
80
73
  const errors: Array<{ name: string; error: string }> = [];
81
74
 
82
75
  const resolvedDir = await Deno.realPath(functionsDir);
83
- const importRoot = options?.importRoot
84
- ? await Deno.realPath(options.importRoot)
85
- : resolvedDir;
86
76
 
87
77
  const candidates: string[] = [];
88
78
  for await (const entry of Deno.readDir(resolvedDir)) {
@@ -131,7 +121,7 @@ export async function discoverAndLoad(
131
121
  let completed = 0;
132
122
 
133
123
  const loadOne = async (name: string): Promise<void> => {
134
- const indexPath = join(importRoot, name, "index.ts");
124
+ const indexPath = join(resolvedDir, name, "index.ts");
135
125
  // pathToFileURL is the node:url equivalent of std/path's toFileUrl;
136
126
  // both produce a `file://` URL whose searchParams we mutate below for
137
127
  // HMR cache-busting.
@@ -153,11 +143,7 @@ export async function discoverAndLoad(
153
143
  // on demand. This is the single biggest startup-time win for sites
154
144
  // with many rarely-called functions.
155
145
  if (options?.lazy && !manifest.warm) {
156
- registry.registerCandidate({
157
- name,
158
- moduleUrl: moduleUrl.href,
159
- manifest,
160
- });
146
+ registry.registerCandidate({ name, moduleUrl: moduleUrl.href, manifest });
161
147
  deferred.push(name);
162
148
  const durationMs = performance.now() - start;
163
149
  options?.onProgress?.({
@@ -174,11 +160,7 @@ export async function discoverAndLoad(
174
160
  // Even in lazy mode, eagerly-warm functions still register a candidate
175
161
  // so HMR reloads can re-import via the same URL.
176
162
  if (options?.lazy && manifest.warm) {
177
- registry.registerCandidate({
178
- name,
179
- moduleUrl: moduleUrl.href,
180
- manifest,
181
- });
163
+ registry.registerCandidate({ name, moduleUrl: moduleUrl.href, manifest });
182
164
  }
183
165
  await registry.runWithCurrentFunction(name, async () => {
184
166
  await import(moduleUrl.href);
@@ -211,16 +193,13 @@ export async function discoverAndLoad(
211
193
  // internally, but we still benefit from overlapping transpile + JSR fetches.
212
194
  const concurrency = Math.max(1, options?.concurrency ?? 8);
213
195
  let cursor = 0;
214
- const workers = Array.from(
215
- { length: Math.min(concurrency, work.length) },
216
- async () => {
217
- while (true) {
218
- const i = cursor++;
219
- if (i >= work.length) return;
220
- await loadOne(work[i]);
221
- }
222
- },
223
- );
196
+ const workers = Array.from({ length: Math.min(concurrency, work.length) }, async () => {
197
+ while (true) {
198
+ const i = cursor++;
199
+ if (i >= work.length) return;
200
+ await loadOne(work[i]);
201
+ }
202
+ });
224
203
  await Promise.all(workers);
225
204
 
226
205
  return { loaded, skipped, errors, removed, deferred };
package/src/registry.ts CHANGED
@@ -77,6 +77,29 @@ export interface FunctionCandidate {
77
77
  manifest: FunctionManifest;
78
78
  }
79
79
 
80
+ /**
81
+ * Out-of-process function handle used by the Worker-backed Deno backend.
82
+ * The gateway holds a `WorkerFunctionHandle` instead of a JS handler;
83
+ * `dispatch()` forwards the request through `postMessage` to the
84
+ * function's Web Worker.
85
+ *
86
+ * Defined here (rather than in `backends/deno/`) so the registry can
87
+ * type its `workerHandles` map without a circular import. The actual
88
+ * implementation lives in `src/backends/deno/worker-host.ts`.
89
+ */
90
+ export interface WorkerFunctionHandle {
91
+ readonly name: string;
92
+ readonly manifest: FunctionManifest;
93
+ readonly isPublic: boolean;
94
+ readonly timeoutMs?: number;
95
+ dispatch(
96
+ req: Request,
97
+ auth: AuthContext | null,
98
+ signal: AbortSignal,
99
+ ): Promise<Response>;
100
+ terminate(): Promise<void>;
101
+ }
102
+
80
103
  export class FunctionRegistry {
81
104
  private handlers = new Map<string, RegisteredFunction>();
82
105
  private pendingManifests = new Map<string, FunctionManifest>();
@@ -91,6 +114,14 @@ export class FunctionRegistry {
91
114
  * a JS handler exists.
92
115
  */
93
116
  private externalManifests = new Map<string, FunctionManifest>();
117
+ /**
118
+ * Out-of-process worker handles for the Deno backend's Worker-per-function
119
+ * execution model. Treated as live, dispatchable functions: `has()` /
120
+ * `knownNames()` / `manifestFor()` all surface them, but they live in a
121
+ * separate Map so the in-process `handlers` / `candidates` paths used by
122
+ * tests and the legacy in-isolate model stay unaffected.
123
+ */
124
+ private workerHandles = new Map<string, WorkerFunctionHandle>();
94
125
  /** In-flight import dedupe: many concurrent first-requests await the same Promise. */
95
126
  private loading = new Map<string, Promise<RegisteredFunction | null>>();
96
127
 
@@ -153,16 +184,18 @@ export class FunctionRegistry {
153
184
  return (
154
185
  this.handlers.has(name) ||
155
186
  this.candidates.has(name) ||
156
- this.externalManifests.has(name)
187
+ this.externalManifests.has(name) ||
188
+ this.workerHandles.has(name)
157
189
  );
158
190
  }
159
191
 
160
- /** Names visible to dispatch (loaded handlers + unloaded candidates). */
192
+ /** Names visible to dispatch (loaded handlers + unloaded candidates + worker handles). */
161
193
  knownNames(): string[] {
162
194
  const out = new Set<string>();
163
195
  for (const k of this.handlers.keys()) out.add(k);
164
196
  for (const k of this.candidates.keys()) out.add(k);
165
197
  for (const k of this.externalManifests.keys()) out.add(k);
198
+ for (const k of this.workerHandles.keys()) out.add(k);
166
199
  return [...out].sort();
167
200
  }
168
201
 
@@ -206,10 +239,28 @@ export class FunctionRegistry {
206
239
  return (
207
240
  this.handlers.get(name)?.manifest ??
208
241
  this.candidates.get(name)?.manifest ??
242
+ this.workerHandles.get(name)?.manifest ??
209
243
  this.externalManifests.get(name)
210
244
  );
211
245
  }
212
246
 
247
+ /**
248
+ * Register a Worker-backed function handle (Deno backend). Replaces any
249
+ * prior handle for `name` — callers are expected to terminate the old
250
+ * worker themselves; the registry doesn't own worker lifecycles.
251
+ */
252
+ setWorkerHandle(name: string, handle: WorkerFunctionHandle): void {
253
+ this.workerHandles.set(name, handle);
254
+ }
255
+
256
+ workerHandle(name: string): WorkerFunctionHandle | undefined {
257
+ return this.workerHandles.get(name);
258
+ }
259
+
260
+ clearWorkerHandle(name: string): boolean {
261
+ return this.workerHandles.delete(name);
262
+ }
263
+
213
264
  /**
214
265
  * Return the loaded handler if present, otherwise dynamically import the
215
266
  * candidate module (deduped across concurrent callers) and return the
@@ -253,6 +304,7 @@ export class FunctionRegistry {
253
304
  this.pendingManifests.delete(name);
254
305
  this.candidates.delete(name);
255
306
  this.loading.delete(name);
307
+ this.workerHandles.delete(name);
256
308
  return this.handlers.delete(name);
257
309
  }
258
310
 
@@ -261,6 +313,7 @@ export class FunctionRegistry {
261
313
  this.pendingManifests.clear();
262
314
  this.candidates.clear();
263
315
  this.loading.clear();
316
+ this.workerHandles.clear();
264
317
  }
265
318
 
266
319
  list(): string[] {