1tube 0.1.0 → 0.1.1

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/.env.example CHANGED
@@ -23,4 +23,4 @@ FUNCTIONS_PATH=../sciobot-next/supabase/functions
23
23
  # SENTRY_DSN=
24
24
 
25
25
  # Optional: log function invocations to Supabase table
26
- # LOG_TO_DB=true
26
+ # LOG_TO_DB=true
package/README.md CHANGED
@@ -23,6 +23,12 @@ bun run dev -- --functions ../sciobot-next/supabase/functions
23
23
 
24
24
  The gateway starts on `http://localhost:3100`. Functions are available at `http://localhost:3100/functions/v1/<name>`.
25
25
 
26
+ In dev mode, 1tube also watches the functions directory and reloads handlers in-process on filesystem changes (including newly created function folders).
27
+
28
+ ### Deno npm lifecycle scripts
29
+
30
+ Deno does not run npm `postinstall` / build scripts unless you allow them. `deno.lock` may still list transitive packages such as `protobufjs`; the `check` script uses `--allow-scripts=npm:protobufjs` so `bun run check` / `npm publish` (via `prepublishOnly`) stays warning-free. That script is only needed for dependency install — **1tube’s runtime graph is just Hono + JSR std**.
31
+
26
32
  ## Endpoints
27
33
 
28
34
  | Path | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "1tube",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "description": "Self-hosted Supabase Edge Functions gateway for Deno, plus an ESLint plugin for consumers",
6
6
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "dev": "deno task dev",
34
34
  "serve": "deno task serve",
35
35
  "typecheck": "deno check src/server.ts eslint-plugin.js",
36
- "check": "deno cache src/server.ts",
36
+ "check": "deno cache --allow-scripts=npm:protobufjs src/server.ts",
37
37
  "prepublishOnly": "bun run typecheck && bun run check"
38
38
  },
39
39
  "dependencies": {
package/src/discovery.ts CHANGED
@@ -13,6 +13,7 @@ import type { FunctionRegistry } from "./registry.ts";
13
13
  export async function discoverAndLoad(
14
14
  functionsDir: string,
15
15
  registry: FunctionRegistry,
16
+ options?: { cacheBust?: string },
16
17
  ): Promise<{ loaded: string[]; skipped: string[]; errors: Array<{ name: string; error: string }> }> {
17
18
  const loaded: string[] = [];
18
19
  const skipped: string[] = [];
@@ -45,7 +46,11 @@ export async function discoverAndLoad(
45
46
  registry.setCurrentFunction(name);
46
47
 
47
48
  try {
48
- await import(toFileUrl(indexPath).href);
49
+ const moduleUrl = toFileUrl(indexPath);
50
+ if (options?.cacheBust) {
51
+ moduleUrl.searchParams.set("v", options.cacheBust);
52
+ }
53
+ await import(moduleUrl.href);
49
54
  loaded.push(name);
50
55
  } catch (err) {
51
56
  const msg = err instanceof Error ? err.message : String(err);
package/src/registry.ts CHANGED
@@ -73,6 +73,11 @@ export class FunctionRegistry {
73
73
  return this.handlers.get(name);
74
74
  }
75
75
 
76
+ clear(): void {
77
+ this.handlers.clear();
78
+ this._currentName = "";
79
+ }
80
+
76
81
  list(): string[] {
77
82
  return [...this.handlers.keys()].sort();
78
83
  }
package/src/server.ts CHANGED
@@ -77,20 +77,71 @@ applyLocalDefaults();
77
77
  const registry = new FunctionRegistry();
78
78
  (globalThis as any).__edgeFunctionRegistry = registry;
79
79
 
80
+ async function reloadFunctions(reason: string) {
81
+ console.log(`[1tube] Reloading functions (${reason})...`);
82
+ registry.clear();
83
+ const cacheBust = `${Date.now()}-${crypto.randomUUID()}`;
84
+ const { loaded, skipped, errors } = await discoverAndLoad(functionsPath, registry, { cacheBust });
85
+
86
+ console.log(`[1tube] Loaded ${loaded.length} functions, skipped ${skipped.length} directories`);
87
+ if (loaded.length > 0) {
88
+ console.log(`[1tube] Functions: ${loaded.join(", ")}`);
89
+ }
90
+ if (errors.length > 0) {
91
+ console.error(`[1tube] ${errors.length} function(s) failed to load (check .env for missing vars):`);
92
+ for (const e of errors) {
93
+ console.error(` ${e.name}: ${e.error}`);
94
+ }
95
+ }
96
+ }
97
+
80
98
  console.log(`[1tube] Loading functions from: ${functionsPath}`);
81
- const { loaded, skipped, errors } = await discoverAndLoad(functionsPath, registry);
99
+ await reloadFunctions("initial boot");
100
+
101
+ let reloadTimer: number | undefined;
102
+ let isReloading = false;
103
+ let needsAnotherReload = false;
82
104
 
83
- console.log(`[1tube] Loaded ${loaded.length} functions, skipped ${skipped.length} directories`);
84
- if (loaded.length > 0) {
85
- console.log(`[1tube] Functions: ${loaded.join(", ")}`);
105
+ function scheduleReload(reason: string) {
106
+ if (reloadTimer !== undefined) {
107
+ clearTimeout(reloadTimer);
108
+ }
109
+ reloadTimer = setTimeout(async () => {
110
+ if (isReloading) {
111
+ needsAnotherReload = true;
112
+ return;
113
+ }
114
+
115
+ isReloading = true;
116
+ try {
117
+ await reloadFunctions(reason);
118
+ } catch (err) {
119
+ console.error("[1tube] Reload failed:", err);
120
+ } finally {
121
+ isReloading = false;
122
+ if (needsAnotherReload) {
123
+ needsAnotherReload = false;
124
+ scheduleReload("batched filesystem updates");
125
+ }
126
+ }
127
+ }, 200);
86
128
  }
87
- if (errors.length > 0) {
88
- console.error(`[1tube] ${errors.length} function(s) failed to load (check .env for missing vars):`);
89
- for (const e of errors) {
90
- console.error(` ${e.name}: ${e.error}`);
129
+
130
+ async function watchFunctions() {
131
+ try {
132
+ const watcher = Deno.watchFs(functionsPath, { recursive: true });
133
+ console.log(`[1tube] HMR watching: ${functionsPath}`);
134
+ for await (const event of watcher) {
135
+ if (event.paths.length === 0) continue;
136
+ scheduleReload(`${event.kind} (${event.paths.length} path(s))`);
137
+ }
138
+ } catch (err) {
139
+ console.warn("[1tube] HMR watcher disabled:", err);
91
140
  }
92
141
  }
93
142
 
143
+ watchFunctions();
144
+
94
145
  // ---------------------------------------------------------------------------
95
146
  // HTTP Server
96
147
  // ---------------------------------------------------------------------------