@resonatehq/supabase 0.1.1 → 0.1.4

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
@@ -17,4 +17,5 @@ export declare class Resonate {
17
17
  }): void;
18
18
  setDependency(name: string, obj: any): void;
19
19
  handler(req: Request): Promise<Response>;
20
+ httpHandler(): Deno.HttpServer;
20
21
  }
package/dist/index.js CHANGED
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Resonate = void 0;
4
4
  const sdk_1 = require("@resonatehq/sdk");
5
5
  const encryptor_1 = require("@resonatehq/sdk/dist/src/encryptor");
6
+ const options_1 = require("@resonatehq/sdk/dist/src/options");
7
+ const tracer_1 = require("@resonatehq/sdk/dist/src/tracer");
6
8
  class Resonate {
7
9
  constructor({ verbose = false, encryptor = undefined, } = {}) {
8
10
  this.registry = new sdk_1.Registry();
@@ -45,6 +47,8 @@ class Resonate {
45
47
  });
46
48
  }
47
49
  const encoder = new sdk_1.JsonEncoder();
50
+ const clock = new sdk_1.WallClock();
51
+ const tracer = new tracer_1.NoopTracer();
48
52
  const network = new sdk_1.HttpNetwork({
49
53
  headers: {},
50
54
  timeout: 60 * 1000, // 60s
@@ -52,22 +56,25 @@ class Resonate {
52
56
  verbose: this.verbose,
53
57
  });
54
58
  const resonateInner = new sdk_1.ResonateInner({
55
- anycastNoPreference: url,
56
- anycastPreference: url,
57
- clock: new sdk_1.WallClock(),
58
- dependencies: this.dependencies,
59
- handler: new sdk_1.Handler(network, encoder, this.encryptor),
60
- heartbeat: new sdk_1.NoopHeartbeat(),
61
- network,
59
+ unicast: url,
60
+ anycast: url,
62
61
  pid: `pid-${Math.random().toString(36).substring(7)}`,
62
+ ttl: 30 * 1000,
63
+ clock,
64
+ network,
65
+ handler: new sdk_1.Handler(network, encoder, this.encryptor),
63
66
  registry: this.registry,
64
- ttl: 30 * 1000, // 30s
65
- unicast: url,
67
+ heartbeat: new sdk_1.NoopHeartbeat(),
68
+ dependencies: this.dependencies,
69
+ optsBuilder: new options_1.OptionsBuilder({
70
+ match: (_) => url,
71
+ }),
66
72
  verbose: this.verbose,
73
+ tracer,
67
74
  });
68
75
  const task = { kind: "unclaimed", task: body.task };
69
76
  const completion = new Promise((resolve) => {
70
- resonateInner.process(task, (error, status) => {
77
+ resonateInner.process(tracer.startSpan(task.task.rootPromiseId, clock.now()), task, (error, status) => {
71
78
  if (error || !status) {
72
79
  resolve(new Response(JSON.stringify({
73
80
  error: "Task processing failed",
@@ -106,6 +113,17 @@ class Resonate {
106
113
  }), { status: 500 });
107
114
  }
108
115
  }
116
+ httpHandler() {
117
+ return Deno.serve(async (req) => {
118
+ const resp = await this.handler(req);
119
+ return new Response(JSON.stringify(resp), {
120
+ headers: {
121
+ "Content-Type": "application/json",
122
+ Connection: "keep-alive",
123
+ },
124
+ });
125
+ });
126
+ }
109
127
  }
110
128
  exports.Resonate = Resonate;
111
129
  function buildForwardedURL(req) {
@@ -123,7 +141,7 @@ function buildForwardedURL(req) {
123
141
  // Dev: We need the port (e.g., :54321).
124
142
  // Prod: We rarely need :443 explicitly in the URL string.
125
143
  const forwardedPort = headers.get("x-forwarded-port");
126
- const port = (forwardedHost && forwardedPort) ? `:${forwardedPort}` : "";
144
+ const port = forwardedHost && forwardedPort ? `:${forwardedPort}` : "";
127
145
  // 4. Path Logic
128
146
  // Dev: "x-forwarded-path" contains the full path (/functions/v1/hello-world)
129
147
  // Prod: We must use url.pathname.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resonatehq/supabase",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "Resonate FaaS handler for Supabase Edge Functions (TypeScript)",
5
5
  "repository": {
6
6
  "url": "https://github.com/resonatehq/resonate-faas-supabase-ts"
@@ -23,12 +23,13 @@
23
23
  "devDependencies": {
24
24
  "@biomejs/biome": "2.3.6",
25
25
  "@types/bun": "latest",
26
+ "@types/deno": "^2.5.0",
26
27
  "open": "^10.2.0"
27
28
  },
28
29
  "peerDependencies": {
29
30
  "typescript": "^5.9.3"
30
31
  },
31
32
  "dependencies": {
32
- "@resonatehq/sdk": "^0.8.6"
33
+ "@resonatehq/sdk": "^0.9.3"
33
34
  }
34
35
  }
package/src/index.ts CHANGED
@@ -13,6 +13,8 @@ import {
13
13
  type Encryptor,
14
14
  NoopEncryptor,
15
15
  } from "@resonatehq/sdk/dist/src/encryptor";
16
+ import { OptionsBuilder } from "@resonatehq/sdk/dist/src/options";
17
+ import { NoopTracer } from "@resonatehq/sdk/dist/src/tracer";
16
18
 
17
19
  export class Resonate {
18
20
  private registry = new Registry();
@@ -107,6 +109,8 @@ export class Resonate {
107
109
  }
108
110
 
109
111
  const encoder = new JsonEncoder();
112
+ const clock = new WallClock();
113
+ const tracer = new NoopTracer();
110
114
  const network = new HttpNetwork({
111
115
  headers: {},
112
116
  timeout: 60 * 1000, // 60s
@@ -115,68 +119,75 @@ export class Resonate {
115
119
  });
116
120
 
117
121
  const resonateInner = new ResonateInner({
118
- anycastNoPreference: url,
119
- anycastPreference: url,
120
- clock: new WallClock(),
121
- dependencies: this.dependencies,
122
- handler: new Handler(network, encoder, this.encryptor),
123
- heartbeat: new NoopHeartbeat(),
124
- network,
122
+ unicast: url,
123
+ anycast: url,
125
124
  pid: `pid-${Math.random().toString(36).substring(7)}`,
125
+ ttl: 30 * 1000,
126
+ clock,
127
+ network,
128
+ handler: new Handler(network, encoder, this.encryptor),
126
129
  registry: this.registry,
127
- ttl: 30 * 1000, // 30s
128
- unicast: url,
130
+ heartbeat: new NoopHeartbeat(),
131
+ dependencies: this.dependencies,
132
+ optsBuilder: new OptionsBuilder({
133
+ match: (_: string): string => url,
134
+ }),
129
135
  verbose: this.verbose,
136
+ tracer,
130
137
  });
131
138
 
132
139
  const task: Task = { kind: "unclaimed", task: body.task };
133
140
 
134
141
  const completion: Promise<Response> = new Promise((resolve) => {
135
- resonateInner.process(task, (error, status) => {
136
- if (error || !status) {
137
- resolve(
138
- new Response(
139
- JSON.stringify({
140
- error: "Task processing failed",
141
- details: { error, status },
142
- }),
143
- {
144
- status: 500,
145
- },
146
- ),
147
- );
148
- return;
149
- }
150
-
151
- if (status.kind === "completed") {
152
- resolve(
153
- new Response(
154
- JSON.stringify({
155
- status: "completed",
156
- result: status.promise.value,
157
- requestUrl: url,
158
- }),
159
- {
160
- status: 200,
161
- },
162
- ),
163
- );
164
- return;
165
- } else if (status.kind === "suspended") {
166
- resolve(
167
- new Response(
168
- JSON.stringify({
169
- status: "suspended",
170
- requestUrl: url,
171
- }),
172
- {
173
- status: 200,
174
- },
175
- ),
176
- );
177
- return;
178
- }
179
- });
142
+ resonateInner.process(
143
+ tracer.startSpan(task.task.rootPromiseId, clock.now()),
144
+ task,
145
+ (error, status) => {
146
+ if (error || !status) {
147
+ resolve(
148
+ new Response(
149
+ JSON.stringify({
150
+ error: "Task processing failed",
151
+ details: { error, status },
152
+ }),
153
+ {
154
+ status: 500,
155
+ },
156
+ ),
157
+ );
158
+ return;
159
+ }
160
+
161
+ if (status.kind === "completed") {
162
+ resolve(
163
+ new Response(
164
+ JSON.stringify({
165
+ status: "completed",
166
+ result: status.promise.value,
167
+ requestUrl: url,
168
+ }),
169
+ {
170
+ status: 200,
171
+ },
172
+ ),
173
+ );
174
+ return;
175
+ } else if (status.kind === "suspended") {
176
+ resolve(
177
+ new Response(
178
+ JSON.stringify({
179
+ status: "suspended",
180
+ requestUrl: url,
181
+ }),
182
+ {
183
+ status: 200,
184
+ },
185
+ ),
186
+ );
187
+ return;
188
+ }
189
+ },
190
+ );
180
191
  });
181
192
  return completion;
182
193
  } catch (error) {
@@ -188,39 +199,51 @@ export class Resonate {
188
199
  );
189
200
  }
190
201
  }
202
+
203
+ public httpHandler(): Deno.HttpServer {
204
+ return Deno.serve(async (req: Request) => {
205
+ const resp = await this.handler(req);
206
+ return new Response(JSON.stringify(resp), {
207
+ headers: {
208
+ "Content-Type": "application/json",
209
+ Connection: "keep-alive",
210
+ },
211
+ });
212
+ });
213
+ }
191
214
  }
192
215
 
193
216
  function buildForwardedURL(req: Request) {
194
- const headers = req.headers;
195
- const url = new URL(req.url);
196
-
197
- // 1. Hostname Logic
198
- // Dev: "x-forwarded-host" is present (e.g., 127.0.0.1)
199
- // Prod: "x-forwarded-host" is missing, so we use url.hostname (e.g., project.supabase.co)
200
- const forwardedHost = headers.get("x-forwarded-host");
201
- const host = forwardedHost ?? url.hostname;
202
-
203
- // 2. Protocol Logic
204
- // Always prefer "x-forwarded-proto" (usually https in prod), fallback to "http"
205
- const proto = headers.get("x-forwarded-proto") ?? "http";
206
-
207
- // 3. Port Logic
208
- // Dev: We need the port (e.g., :54321).
209
- // Prod: We rarely need :443 explicitly in the URL string.
210
- const forwardedPort = headers.get("x-forwarded-port");
211
- const port = (forwardedHost && forwardedPort) ? `:${forwardedPort}` : "";
212
-
213
- // 4. Path Logic
214
- // Dev: "x-forwarded-path" contains the full path (/functions/v1/hello-world)
215
- // Prod: We must use url.pathname.
216
- let path = headers.get("x-forwarded-path") ?? url.pathname;
217
-
218
- // 5. Production Path Fix
219
- // In Prod, the internal req.url often strips '/functions/v1'.
220
- // We re-add it if we are in Prod (no forwardedHost) and it's missing.
221
- if (!forwardedHost && !path.startsWith("/functions/v1")) {
222
- path = `/functions/v1${path}`;
223
- }
224
-
225
- return `${proto}://${host}${port}${path}`;
217
+ const headers = req.headers;
218
+ const url = new URL(req.url);
219
+
220
+ // 1. Hostname Logic
221
+ // Dev: "x-forwarded-host" is present (e.g., 127.0.0.1)
222
+ // Prod: "x-forwarded-host" is missing, so we use url.hostname (e.g., project.supabase.co)
223
+ const forwardedHost = headers.get("x-forwarded-host");
224
+ const host = forwardedHost ?? url.hostname;
225
+
226
+ // 2. Protocol Logic
227
+ // Always prefer "x-forwarded-proto" (usually https in prod), fallback to "http"
228
+ const proto = headers.get("x-forwarded-proto") ?? "http";
229
+
230
+ // 3. Port Logic
231
+ // Dev: We need the port (e.g., :54321).
232
+ // Prod: We rarely need :443 explicitly in the URL string.
233
+ const forwardedPort = headers.get("x-forwarded-port");
234
+ const port = forwardedHost && forwardedPort ? `:${forwardedPort}` : "";
235
+
236
+ // 4. Path Logic
237
+ // Dev: "x-forwarded-path" contains the full path (/functions/v1/hello-world)
238
+ // Prod: We must use url.pathname.
239
+ let path = headers.get("x-forwarded-path") ?? url.pathname;
240
+
241
+ // 5. Production Path Fix
242
+ // In Prod, the internal req.url often strips '/functions/v1'.
243
+ // We re-add it if we are in Prod (no forwardedHost) and it's missing.
244
+ if (!forwardedHost && !path.startsWith("/functions/v1")) {
245
+ path = `/functions/v1${path}`;
246
+ }
247
+
248
+ return `${proto}://${host}${port}${path}`;
226
249
  }