@devvit/server 0.11.17-next-2025-06-03-f993e3a25.0 → 0.11.17-next-2025-06-04-b6703d5a9.0

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.
@@ -1,10 +1,14 @@
1
- import { createServer as nodeCreateServer } from 'node:http';
1
+ import type { IncomingMessage, Server, ServerOptions, ServerResponse } from 'node:http';
2
2
  /**
3
3
  * Creates a new Devvit server. This implements the same API as Node.js's `createServer` function,
4
4
  * but we do not guarantee that this actually creates an HTTP server of any kind - it may be any
5
5
  * kind of server under the hood. However, it will behave like an HTTP server in terms of the API.
6
6
  */
7
- export declare const createServer: typeof nodeCreateServer;
7
+ export declare const createServer: <Request extends typeof IncomingMessage = typeof IncomingMessage, Response extends typeof ServerResponse = typeof ServerResponse>(optionsOrRequestListener?: ServerOptions<Request, Response> | ((req: InstanceType<Request>, res: InstanceType<Response> & {
8
+ req: InstanceType<Request>;
9
+ }) => any), requestListener?: (req: InstanceType<Request>, res: InstanceType<Response> & {
10
+ req: InstanceType<Request>;
11
+ }) => any) => Server<Request, Response>;
8
12
  declare global {
9
13
  namespace globalThis {
10
14
  var enableWebbitBundlingHack: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../src/create-server.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAI7D;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,OAAO,gBAYjC,CAAC;AAuCF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,UAAU,CAAC;QAEnB,IAAI,wBAAwB,EAAE,OAAO,CAAC;KACvC;CACF"}
1
+ {"version":3,"file":"create-server.d.ts","sourceRoot":"","sources":["../src/create-server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAWxF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,OAAO,SAAS,OAAO,eAAe,GAAG,OAAO,eAAe,EAC/D,QAAQ,SAAS,OAAO,cAAc,GAAG,OAAO,cAAc,EAE9D,2BACI,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,GAChC,CAAC,CACC,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,EAC1B,GAAG,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG;IAAE,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,CAAA;CAAE,KACzD,GAAG,CAAC,EACb,kBAAkB,CAChB,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,EAC1B,GAAG,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG;IAAE,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,CAAA;CAAE,KACzD,GAAG,KACP,MAAM,CAAC,OAAO,EAAE,QAAQ,CAM1B,CAAC;AA4CF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,UAAU,CAAC;QAEnB,IAAI,wBAAwB,EAAE,OAAO,CAAC;KACvC;CACF"}
package/create-server.js CHANGED
@@ -1,6 +1,11 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import { createServer as nodeCreateServer } from 'node:http';
2
3
  import { runWithContext } from './context.js';
3
4
  import { RequestContext } from './request-context.js';
5
+ import { runWithSourceMap } from './source-maps/source-maps.js';
6
+ // This constant represents the bundle ID to match code to its source map
7
+ // and needs to match the one the source map was initiated with from WebbitLoader.
8
+ const WEBBIT_BUNDLE_ID = 'webbit-server';
4
9
  /**
5
10
  * Creates a new Devvit server. This implements the same API as Node.js's `createServer` function,
6
11
  * but we do not guarantee that this actually creates an HTTP server of any kind - it may be any
@@ -16,7 +21,9 @@ function _createServer(options, requestListener) {
16
21
  const server = nodeCreateServer(options, async (req, res) => {
17
22
  const context = RequestContext(req.headers);
18
23
  return runWithContext(context, async () => {
19
- return requestListener?.(req, res);
24
+ return await runWithSourceMap(WEBBIT_BUNDLE_ID, () => {
25
+ return requestListener?.(req, res);
26
+ });
20
27
  });
21
28
  });
22
29
  // Modify the listen callback slightly, to do the Devvit-y bundling hack
package/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { createServer } from './create-server.js';
3
3
  export { defineConfig } from './define-config.js';
4
4
  export { getServerPort } from './get-server-port.js';
5
5
  export { RequestContext, setRequestContext } from './request-context.js';
6
+ export { initializeSourceMap, runWithSourceMap } from './source-maps/source-maps.js';
6
7
  //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC"}
package/index.js CHANGED
@@ -3,3 +3,4 @@ export { createServer } from './create-server.js';
3
3
  export { defineConfig } from './define-config.js';
4
4
  export { getServerPort } from './get-server-port.js';
5
5
  export { RequestContext, setRequestContext } from './request-context.js';
6
+ export { initializeSourceMap, runWithSourceMap } from './source-maps/source-maps.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devvit/server",
3
- "version": "0.11.17-next-2025-06-03-f993e3a25.0",
3
+ "version": "0.11.17-next-2025-06-04-b6703d5a9.0",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,13 +23,15 @@
23
23
  },
24
24
  "types": "./index.d.ts",
25
25
  "dependencies": {
26
- "@devvit/protos": "0.11.17-next-2025-06-03-f993e3a25.0",
27
- "@devvit/public-api": "0.11.17-next-2025-06-03-f993e3a25.0",
28
- "@devvit/shared-types": "0.11.17-next-2025-06-03-f993e3a25.0"
26
+ "@devvit/protos": "0.11.17-next-2025-06-04-b6703d5a9.0",
27
+ "@devvit/public-api": "0.11.17-next-2025-06-04-b6703d5a9.0",
28
+ "@devvit/shared-types": "0.11.17-next-2025-06-04-b6703d5a9.0",
29
+ "@gunsch/source-map": "0.7.6"
29
30
  },
30
31
  "devDependencies": {
31
- "@devvit/repo-tools": "0.11.17-next-2025-06-03-f993e3a25.0",
32
- "@devvit/tsconfig": "0.11.17-next-2025-06-03-f993e3a25.0",
32
+ "@devvit/repo-tools": "0.11.17-next-2025-06-04-b6703d5a9.0",
33
+ "@devvit/tsconfig": "0.11.17-next-2025-06-04-b6703d5a9.0",
34
+ "esbuild": "0.23.0",
33
35
  "eslint": "9.11.1",
34
36
  "typescript": "5.8.3",
35
37
  "vitest": "1.6.1"
@@ -38,5 +40,5 @@
38
40
  "directory": "dist"
39
41
  },
40
42
  "source": "./src/index.ts",
41
- "gitHead": "50a1674071cd8d3890c29ce34a9a0b4393d64bbf"
43
+ "gitHead": "c542e5d2968a5c769cfc7032f9a2f44d62a32ff6"
42
44
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Initializes source map for exception handling within this process. Multiple source maps
3
+ * may be reigstered with unique bundle IDs.
4
+ * If no source map is provided, this method exits early.
5
+ * @param codeBundleId Identifier for the code bundle, should be 1:1 with unique source maps within this process.
6
+ * @param sourceMap Source map for this code bundle, undefined if no source map is available.
7
+ */
8
+ export declare function initializeSourceMap(codeBundleId: string, sourceMap: string | undefined): void;
9
+ /**
10
+ * Executes code with exception handling that will be unwound using the provided source map.
11
+ * @param codeBundleId Identifier for the code bundle, should be 1:1 with unique source maps.
12
+ * @param callback Function to execute that may throw an error
13
+ */
14
+ export declare function runWithSourceMap<T>(codeBundleId: string, callback: () => T): Promise<T>;
15
+ //# sourceMappingURL=source-maps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-maps.d.ts","sourceRoot":"","sources":["../../src/source-maps/source-maps.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAO7F;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAY7F"}
@@ -0,0 +1,72 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { SourceMapConsumer } from '@gunsch/source-map';
3
+ const currentCodeBundle = new AsyncLocalStorage();
4
+ const sourceMapRegistry = new Map();
5
+ /**
6
+ * Initializes source map for exception handling within this process. Multiple source maps
7
+ * may be reigstered with unique bundle IDs.
8
+ * If no source map is provided, this method exits early.
9
+ * @param codeBundleId Identifier for the code bundle, should be 1:1 with unique source maps within this process.
10
+ * @param sourceMap Source map for this code bundle, undefined if no source map is available.
11
+ */
12
+ export function initializeSourceMap(codeBundleId, sourceMap) {
13
+ if (sourceMapRegistry.has(codeBundleId)) {
14
+ throw new Error(`Source map for code bundle ID "${codeBundleId}" is already registered. Please use a unique ID for each source map.`);
15
+ }
16
+ sourceMapRegistry.set(codeBundleId, sourceMap || '');
17
+ }
18
+ /**
19
+ * Executes code with exception handling that will be unwound using the provided source map.
20
+ * @param codeBundleId Identifier for the code bundle, should be 1:1 with unique source maps.
21
+ * @param callback Function to execute that may throw an error
22
+ */
23
+ export async function runWithSourceMap(codeBundleId, callback) {
24
+ return currentCodeBundle.run(codeBundleId, async () => {
25
+ try {
26
+ return await callback();
27
+ }
28
+ catch (error) {
29
+ // Ensure we dump this to the logs, since it's not always logged by default.
30
+ if (error instanceof Error && error.stack) {
31
+ console.error(error);
32
+ }
33
+ throw error;
34
+ }
35
+ });
36
+ }
37
+ // Override Node's stack trace formatter to guarantee we can unwind stack traces
38
+ // created in any context.
39
+ const originalPrepareStackTrace = Error.prepareStackTrace;
40
+ Error.prepareStackTrace = function (error, stackTraces) {
41
+ try {
42
+ // Use the original stack trace formatter if we don't have a source map or don't know what
43
+ // code bundle we're currently operating in
44
+ const currentCodeBundleId = currentCodeBundle.getStore();
45
+ const sourceMap = currentCodeBundleId && sourceMapRegistry.get(currentCodeBundleId);
46
+ if (!sourceMap) {
47
+ return originalPrepareStackTrace ? originalPrepareStackTrace(error, stackTraces) : undefined;
48
+ }
49
+ const sourceMapConsumer = new SourceMapConsumer(sourceMap);
50
+ const mappedStack = stackTraces.map((site) => {
51
+ const fileName = site.getFileName() || '';
52
+ const lineNumber = site.getLineNumber() || 0;
53
+ const columnNumber = site.getColumnNumber() || 0;
54
+ if (!lineNumber) {
55
+ return ` at ${site.getFunctionName() || '<anonymous>'} (${fileName || '??'}:??:${columnNumber || '??'})`;
56
+ }
57
+ const originalPos = sourceMapConsumer.originalPositionFor({
58
+ line: lineNumber,
59
+ column: columnNumber,
60
+ });
61
+ if (originalPos.source) {
62
+ return ` at ${site.getFunctionName() || '<anonymous>'} (${originalPos.source}:${originalPos.line}:${originalPos.column})`;
63
+ }
64
+ return ` at ${site.getFunctionName() || '<anonymous>'} (${fileName}:${lineNumber}:${columnNumber})`;
65
+ });
66
+ return `${error.name}: ${error.message}\n${mappedStack.join('\n')}`;
67
+ }
68
+ catch {
69
+ // If there are any issues, fall back to the original stack trace formatter
70
+ return originalPrepareStackTrace ? originalPrepareStackTrace(error, stackTraces) : undefined;
71
+ }
72
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-maps.test.d.ts","sourceRoot":"","sources":["../../src/source-maps/source-maps.test.ts"],"names":[],"mappings":""}
@@ -1,4 +0,0 @@
1
- import { type WebbitServer } from '@devvit/protos/types/devvit/actor/webbit/webbit.js';
2
- export declare function webbitEnable(): void;
3
- export declare function newWebbitServer(): WebbitServer;
4
- //# sourceMappingURL=webbit-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webbit-server.d.ts","sourceRoot":"","sources":["../src/webbit-server.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,oDAAoD,CAAC;AAM5D,wBAAgB,YAAY,IAAI,IAAI,CAInC;AAED,wBAAgB,eAAe,IAAI,YAAY,CAsB9C"}
package/webbit-server.js DELETED
@@ -1,30 +0,0 @@
1
- import { HttpMethod, WebbitServerDefinition, } from '@devvit/protos/types/devvit/actor/webbit/webbit.js';
2
- import { Devvit } from '@devvit/public-api';
3
- import { extendDevvitPrototype } from '@devvit/public-api/devvit/internals/helpers/extendDevvitPrototype.js';
4
- import { getServerPort } from './get-server-port.js';
5
- export function webbitEnable() {
6
- const server = newWebbitServer();
7
- extendDevvitPrototype('Request', server.Request);
8
- Devvit.provide(WebbitServerDefinition);
9
- }
10
- export function newWebbitServer() {
11
- return {
12
- async Request(req, meta) {
13
- const port = getServerPort();
14
- // only set the body if the method is not GET or HEAD
15
- const body = [HttpMethod.GET, HttpMethod.HEAD].includes(req.method) ? null : req.body;
16
- const rsp = await fetch(new URL(req.path, `http://webbit.local:${port}`), {
17
- body,
18
- headers: [
19
- ...Object.entries(req.headers),
20
- // devvit- headers alway have priority.
21
- ...Object.entries(meta ?? {}).map(([k, v]) => [k, v.values.join()]),
22
- ],
23
- method: HttpMethod[req.method],
24
- });
25
- const headers = {};
26
- rsp.headers.forEach((v, k) => (headers[k] = v));
27
- return { body: new Uint8Array(await rsp.arrayBuffer()), headers, statusCode: rsp.status };
28
- },
29
- };
30
- }