@insforge/sdk 1.2.4 → 1.2.5

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.mts CHANGED
@@ -755,19 +755,13 @@ interface FunctionInvokeOptions {
755
755
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
756
756
  }
757
757
  /**
758
- * Edge Functions client for invoking serverless functions
758
+ * Edge Functions client for invoking serverless functions.
759
759
  *
760
760
  * @example
761
761
  * ```typescript
762
- * // Invoke a function with JSON body
763
762
  * const { data, error } = await client.functions.invoke('hello-world', {
764
763
  * body: { name: 'World' }
765
764
  * });
766
- *
767
- * // GET request
768
- * const { data, error } = await client.functions.invoke('get-data', {
769
- * method: 'GET'
770
- * });
771
765
  * ```
772
766
  */
773
767
  declare class Functions {
@@ -782,10 +776,19 @@ declare class Functions {
782
776
  */
783
777
  private static deriveSubhostingUrl;
784
778
  /**
785
- * Invokes an Edge Function
779
+ * Build a Request for in-process dispatch. The host is a non-routable
780
+ * placeholder; the router only reads pathname.
781
+ */
782
+ private buildInProcessRequest;
783
+ /**
784
+ * Invoke an Edge Function.
786
785
  *
787
- * If functionsUrl is configured, tries direct subhosting first.
788
- * Falls back to proxy URL if subhosting returns 404.
786
+ * Dispatch order:
787
+ * 1. If `globalThis.__insforge_dispatch__` is present, call it in-process.
788
+ * This avoids Deno Subhosting's 508 Loop Detected when one bundled
789
+ * function invokes another inside the same deployment.
790
+ * 2. Otherwise, try the configured subhosting URL.
791
+ * 3. On 404 from subhosting, fall back to the proxy path.
789
792
  *
790
793
  * @param slug The function slug to invoke
791
794
  * @param options Request options
package/dist/index.d.ts CHANGED
@@ -755,19 +755,13 @@ interface FunctionInvokeOptions {
755
755
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
756
756
  }
757
757
  /**
758
- * Edge Functions client for invoking serverless functions
758
+ * Edge Functions client for invoking serverless functions.
759
759
  *
760
760
  * @example
761
761
  * ```typescript
762
- * // Invoke a function with JSON body
763
762
  * const { data, error } = await client.functions.invoke('hello-world', {
764
763
  * body: { name: 'World' }
765
764
  * });
766
- *
767
- * // GET request
768
- * const { data, error } = await client.functions.invoke('get-data', {
769
- * method: 'GET'
770
- * });
771
765
  * ```
772
766
  */
773
767
  declare class Functions {
@@ -782,10 +776,19 @@ declare class Functions {
782
776
  */
783
777
  private static deriveSubhostingUrl;
784
778
  /**
785
- * Invokes an Edge Function
779
+ * Build a Request for in-process dispatch. The host is a non-routable
780
+ * placeholder; the router only reads pathname.
781
+ */
782
+ private buildInProcessRequest;
783
+ /**
784
+ * Invoke an Edge Function.
786
785
  *
787
- * If functionsUrl is configured, tries direct subhosting first.
788
- * Falls back to proxy URL if subhosting returns 404.
786
+ * Dispatch order:
787
+ * 1. If `globalThis.__insforge_dispatch__` is present, call it in-process.
788
+ * This avoids Deno Subhosting's 508 Loop Detected when one bundled
789
+ * function invokes another inside the same deployment.
790
+ * 2. Otherwise, try the configured subhosting URL.
791
+ * 3. On 404 from subhosting, fall back to the proxy path.
789
792
  *
790
793
  * @param slug The function slug to invoke
791
794
  * @param options Request options
package/dist/index.js CHANGED
@@ -324,6 +324,51 @@ var TokenManager = class {
324
324
  // src/lib/http-client.ts
325
325
  var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
326
326
  var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
327
+ function serializeBody(method, body, headers) {
328
+ if (body === void 0) return void 0;
329
+ if (method === "GET" || method === "HEAD") return void 0;
330
+ if (typeof FormData !== "undefined" && body instanceof FormData) {
331
+ return body;
332
+ }
333
+ headers["Content-Type"] = "application/json;charset=UTF-8";
334
+ return JSON.stringify(body);
335
+ }
336
+ async function parseResponse(response) {
337
+ if (response.status === 204) return void 0;
338
+ let data;
339
+ const contentType = response.headers.get("content-type");
340
+ try {
341
+ if (contentType?.includes("json")) {
342
+ data = await response.json();
343
+ } else {
344
+ data = await response.text();
345
+ }
346
+ } catch (parseErr) {
347
+ throw new InsForgeError(
348
+ `Failed to parse response body: ${parseErr?.message || "Unknown error"}`,
349
+ response.status,
350
+ response.ok ? "PARSE_ERROR" : "REQUEST_FAILED"
351
+ );
352
+ }
353
+ if (!response.ok) {
354
+ if (data && typeof data === "object" && "error" in data) {
355
+ data.statusCode ?? (data.statusCode = data.status ?? response.status);
356
+ const error = InsForgeError.fromApiError(data);
357
+ Object.keys(data).forEach((key) => {
358
+ if (key !== "error" && key !== "message" && key !== "statusCode") {
359
+ error[key] = data[key];
360
+ }
361
+ });
362
+ throw error;
363
+ }
364
+ throw new InsForgeError(
365
+ `Request failed: ${response.statusText}`,
366
+ response.status,
367
+ "REQUEST_FAILED"
368
+ );
369
+ }
370
+ return data;
371
+ }
327
372
  var HttpClient = class {
328
373
  /**
329
374
  * Creates a new HttpClient instance.
@@ -417,17 +462,7 @@ var HttpClient = class {
417
462
  if (authToken) {
418
463
  requestHeaders["Authorization"] = `Bearer ${authToken}`;
419
464
  }
420
- let processedBody;
421
- if (body !== void 0) {
422
- if (typeof FormData !== "undefined" && body instanceof FormData) {
423
- processedBody = body;
424
- } else {
425
- if (method !== "GET") {
426
- requestHeaders["Content-Type"] = "application/json;charset=UTF-8";
427
- }
428
- processedBody = JSON.stringify(body);
429
- }
430
- }
465
+ const processedBody = serializeBody(method, body, requestHeaders);
431
466
  if (headers instanceof Headers) {
432
467
  headers.forEach((value, key) => {
433
468
  requestHeaders[key] = value;
@@ -506,53 +541,23 @@ var HttpClient = class {
506
541
  );
507
542
  continue;
508
543
  }
509
- if (response.status === 204) {
510
- if (timer !== void 0) clearTimeout(timer);
511
- return void 0;
512
- }
513
544
  let data;
514
- const contentType = response.headers.get("content-type");
515
545
  try {
516
- if (contentType?.includes("json")) {
517
- data = await response.json();
518
- } else {
519
- data = await response.text();
520
- }
521
- } catch (parseErr) {
546
+ data = await parseResponse(response);
547
+ } catch (err) {
522
548
  if (timer !== void 0) clearTimeout(timer);
523
- throw new InsForgeError(
524
- `Failed to parse response body: ${parseErr?.message || "Unknown error"}`,
525
- response.status,
526
- response.ok ? "PARSE_ERROR" : "REQUEST_FAILED"
527
- );
528
- }
529
- if (timer !== void 0) clearTimeout(timer);
530
- if (!response.ok) {
531
- this.logger.logResponse(
532
- method,
533
- url,
534
- response.status,
535
- Date.now() - startTime,
536
- data
537
- );
538
- if (data && typeof data === "object" && "error" in data) {
539
- if (!data.statusCode && !data.status) {
540
- data.statusCode = response.status;
541
- }
542
- const error = InsForgeError.fromApiError(data);
543
- Object.keys(data).forEach((key) => {
544
- if (key !== "error" && key !== "message" && key !== "statusCode") {
545
- error[key] = data[key];
546
- }
547
- });
548
- throw error;
549
+ if (err instanceof InsForgeError) {
550
+ this.logger.logResponse(
551
+ method,
552
+ url,
553
+ err.statusCode || response.status,
554
+ Date.now() - startTime,
555
+ err
556
+ );
549
557
  }
550
- throw new InsForgeError(
551
- `Request failed: ${response.statusText}`,
552
- response.status,
553
- "REQUEST_FAILED"
554
- );
558
+ throw err;
555
559
  }
560
+ if (timer !== void 0) clearTimeout(timer);
556
561
  this.logger.logResponse(
557
562
  method,
558
563
  url,
@@ -1918,16 +1923,55 @@ var Functions = class _Functions {
1918
1923
  }
1919
1924
  }
1920
1925
  /**
1921
- * Invokes an Edge Function
1926
+ * Build a Request for in-process dispatch. The host is a non-routable
1927
+ * placeholder; the router only reads pathname.
1928
+ */
1929
+ buildInProcessRequest(slug, method, body, callerHeaders) {
1930
+ const url = new URL("/" + slug, "http://insforge.local").toString();
1931
+ const headers = { ...this.http.getHeaders() };
1932
+ const reqBody = serializeBody(method, body, headers);
1933
+ Object.assign(headers, callerHeaders);
1934
+ return new Request(url, {
1935
+ method,
1936
+ headers,
1937
+ body: reqBody
1938
+ });
1939
+ }
1940
+ /**
1941
+ * Invoke an Edge Function.
1922
1942
  *
1923
- * If functionsUrl is configured, tries direct subhosting first.
1924
- * Falls back to proxy URL if subhosting returns 404.
1943
+ * Dispatch order:
1944
+ * 1. If `globalThis.__insforge_dispatch__` is present, call it in-process.
1945
+ * This avoids Deno Subhosting's 508 Loop Detected when one bundled
1946
+ * function invokes another inside the same deployment.
1947
+ * 2. Otherwise, try the configured subhosting URL.
1948
+ * 3. On 404 from subhosting, fall back to the proxy path.
1925
1949
  *
1926
1950
  * @param slug The function slug to invoke
1927
1951
  * @param options Request options
1928
1952
  */
1929
1953
  async invoke(slug, options = {}) {
1930
1954
  const { method = "POST", body, headers = {} } = options;
1955
+ const dispatch = globalThis.__insforge_dispatch__;
1956
+ const localFunctionsUrl = _Functions.deriveSubhostingUrl(this.http.baseUrl);
1957
+ if (typeof dispatch === "function" && !!localFunctionsUrl && this.functionsUrl === localFunctionsUrl) {
1958
+ try {
1959
+ const req = this.buildInProcessRequest(slug, method, body, headers);
1960
+ const res = await dispatch(req);
1961
+ const data = await parseResponse(res);
1962
+ return { data, error: null };
1963
+ } catch (error) {
1964
+ if (error instanceof Error && error.name === "AbortError") throw error;
1965
+ return {
1966
+ data: null,
1967
+ error: error instanceof InsForgeError ? error : new InsForgeError(
1968
+ error instanceof Error ? error.message : "Function invocation failed",
1969
+ 500,
1970
+ "FUNCTION_ERROR"
1971
+ )
1972
+ };
1973
+ }
1974
+ }
1931
1975
  if (this.functionsUrl) {
1932
1976
  try {
1933
1977
  const data = await this.http.request(method, `${this.functionsUrl}/${slug}`, {