@devvit/server 0.11.18 → 0.11.19-next-2025-07-01-14-39-04-3a189619a.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.
- package/define-config.d.ts +2 -1
- package/define-config.d.ts.map +1 -1
- package/define-config.js +61 -17
- package/package.json +8 -7
package/define-config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Devvit } from '@devvit/public-api';
|
|
2
|
-
import type { AppConfig, AppMenuActionConfig, AppPermissionConfig, AppPostCreateConfig } from '@devvit/shared-types/schemas/config-file.v1.js';
|
|
2
|
+
import type { AppConfig, AppFormsConfig, AppMenuActionConfig, AppPermissionConfig, AppPostCreateConfig } from '@devvit/shared-types/schemas/config-file.v1.js';
|
|
3
3
|
/**
|
|
4
4
|
* A subset of AppConfig (see config-file.v1.json) available in V8-flavored
|
|
5
5
|
* LinkedBundles except for the deprecated Blocks callbacks. This config is used
|
|
@@ -13,6 +13,7 @@ export type DynamicAppConfig = {
|
|
|
13
13
|
permissions: AppPermissionConfig;
|
|
14
14
|
post?: DynamicAppPostConfig | undefined;
|
|
15
15
|
menuActions?: AppMenuActionConfig[];
|
|
16
|
+
forms?: AppFormsConfig;
|
|
16
17
|
};
|
|
17
18
|
/** @experimental */
|
|
18
19
|
export type DynamicAppPostConfig = {
|
package/define-config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-config.d.ts","sourceRoot":"","sources":["../src/define-config.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"define-config.d.ts","sourceRoot":"","sources":["../src/define-config.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAOP,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,gDAAgD,CAAC;AAIxD;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,mBAAmB,CAAC;IACjC,IAAI,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACxC,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB,CAAC;AAEF,oBAAoB;AACpB,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,kBAAkB;QAClB,MAAM,CAAC,EAAE;YACP,iDAAiD;YACjD,MAAM,CAAC,EACH,QAAQ,GACR;gBACE,IAAI,EAAE,OAAO,CAAC;gBACd;;;mBAGG;gBACH,KAAK,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;aACpC,GACD,MAAM,CAAC,mBAAmB,GAC1B,SAAS,CAAC;SACf,CAAC;KACH,CAAC;IACF,MAAM,EAAE,0BAA0B,CAAC;CACpC,CAAC;AAEF,oBAAoB;AACpB,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,GAAG;IAC7D,kBAAkB;IAClB,MAAM,CAAC,EACH;QACE;;;;WAIG;QACH,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC;QACnC;;;WAGG;QACH,KAAK,CAAC,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;KAChD,GACD,SAAS,CAAC;CACf,CAAC;AAKF,oBAAoB;AACpB,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,OAAO,MAAM,CAM1F"}
|
package/define-config.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Devvit, useWebView, } from '@devvit/public-api';
|
|
2
2
|
import { getServerPort } from './get-server-port.js';
|
|
3
|
+
/** [state] Map of devvit.json form keys to Devvit-singleton form keys. */
|
|
4
|
+
const formKeyMap = {};
|
|
3
5
|
/** @experimental */
|
|
4
6
|
export function defineConfig(config) {
|
|
5
7
|
configurePermissions(config.permissions);
|
|
@@ -7,6 +9,8 @@ export function defineConfig(config) {
|
|
|
7
9
|
configurePost(config.post);
|
|
8
10
|
if (config.menuActions)
|
|
9
11
|
configureMenuActions(config.menuActions);
|
|
12
|
+
if (config.forms)
|
|
13
|
+
configureForms(config.forms);
|
|
10
14
|
return Devvit;
|
|
11
15
|
}
|
|
12
16
|
function configurePermissions(permissions) {
|
|
@@ -70,23 +74,10 @@ function configureMenuActions(menuActions) {
|
|
|
70
74
|
label: action.label,
|
|
71
75
|
location: action.location,
|
|
72
76
|
onPress: async (ev, ctx) => {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
78
|
-
headers['Content-Type'] = 'application/json';
|
|
79
|
-
const response = await fetch(url, {
|
|
80
|
-
method: 'POST',
|
|
81
|
-
body: JSON.stringify(ev),
|
|
82
|
-
headers,
|
|
83
|
-
});
|
|
84
|
-
if (!response.ok) {
|
|
85
|
-
const body = await response.text();
|
|
86
|
-
throw new Error(`Failed to fetch from ${action.endpoint}: ${response.statusText}, body: ${body}`);
|
|
87
|
-
}
|
|
88
|
-
// TODO: implement UI effect handling.
|
|
89
|
-
ctx.ui.showToast('it was clicked! ' + JSON.stringify(await response.json()));
|
|
77
|
+
const responseJson = await callWebbitEndpoint(action.endpoint, ev, ctx.debug.metadata);
|
|
78
|
+
// TODO: validate UiResponse format for DX reasons. Throw an error if
|
|
79
|
+
// it doesn't conform.
|
|
80
|
+
await handleUiResponse(ctx, responseJson);
|
|
90
81
|
},
|
|
91
82
|
};
|
|
92
83
|
// "user" type is blank in Devvit classic. So if it's present in
|
|
@@ -102,6 +93,59 @@ function configureMenuActions(menuActions) {
|
|
|
102
93
|
Devvit.addMenuItem(menuItem);
|
|
103
94
|
}
|
|
104
95
|
}
|
|
96
|
+
function configureForms(forms) {
|
|
97
|
+
for (const [name, endpoint] of Object.entries(forms)) {
|
|
98
|
+
formKeyMap[name] = Devvit.createForm({ fields: [] }, (ev, ctx) => handleFormResponse(endpoint, ev, ctx));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function handleFormResponse(endpoint, event, ctx) {
|
|
102
|
+
const responseJson = await callWebbitEndpoint(endpoint, event.values, ctx.debug.metadata);
|
|
103
|
+
// TODO: validate UiResponse format for DX reasons. Throw an error if
|
|
104
|
+
// it doesn't conform.
|
|
105
|
+
await handleUiResponse(ctx, responseJson);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Handle a UiResponse from a Webbit handler (menu action or form handler).
|
|
109
|
+
* This is used to create client-side UI effects in Reddit clients as responses
|
|
110
|
+
* to user actions in cases where the Devvit app is not in the direct code path.
|
|
111
|
+
*
|
|
112
|
+
* If multiple effects are present in the UiResponse, they will all be applied.
|
|
113
|
+
*/
|
|
114
|
+
async function handleUiResponse(ctx, uiResponse) {
|
|
115
|
+
if (uiResponse.showToast) {
|
|
116
|
+
ctx.ui.showToast(uiResponse.showToast);
|
|
117
|
+
}
|
|
118
|
+
if (uiResponse.navigateTo) {
|
|
119
|
+
ctx.ui.navigateTo(uiResponse.navigateTo);
|
|
120
|
+
}
|
|
121
|
+
if (uiResponse.showForm) {
|
|
122
|
+
const formKey = formKeyMap[uiResponse.showForm.name];
|
|
123
|
+
if (!formKey) {
|
|
124
|
+
const name = uiResponse.showForm.name;
|
|
125
|
+
throw new Error(`Form with name ${name} not found in devvit.json. Consider adding '"forms"."${name}"="/internal/your/endpoint"'.`);
|
|
126
|
+
}
|
|
127
|
+
ctx.ui.showFormInternal(formKey, uiResponse.showForm.data, uiResponse.showForm.form);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function callWebbitEndpoint(endpoint, body, metadata) {
|
|
131
|
+
const url = new URL(endpoint, `http://webbit.local:${getServerPort()}/`);
|
|
132
|
+
const headers = {};
|
|
133
|
+
Object.entries(metadata).forEach(([key, metadata]) => {
|
|
134
|
+
headers[key] = metadata.values[0];
|
|
135
|
+
});
|
|
136
|
+
headers['Content-Type'] = 'application/json';
|
|
137
|
+
headers['Accept'] = 'application/json';
|
|
138
|
+
const response = await fetch(url, {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
body: JSON.stringify(body),
|
|
141
|
+
headers,
|
|
142
|
+
});
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
const body = await response.text();
|
|
145
|
+
throw new Error(`Failed to fetch from ${endpoint}: ${response.statusText}, body: ${body.substring(0, 100)}`);
|
|
146
|
+
}
|
|
147
|
+
return await response.json();
|
|
148
|
+
}
|
|
105
149
|
async function createPost(ctx, create) {
|
|
106
150
|
if (!ctx.subredditName)
|
|
107
151
|
throw Error('no sub name');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devvit/server",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,13 +23,14 @@
|
|
|
23
23
|
},
|
|
24
24
|
"types": "./index.d.ts",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@devvit/protos": "0.11.
|
|
27
|
-
"@devvit/public-api": "0.11.
|
|
28
|
-
"@devvit/shared
|
|
26
|
+
"@devvit/protos": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0",
|
|
27
|
+
"@devvit/public-api": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0",
|
|
28
|
+
"@devvit/shared": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0",
|
|
29
|
+
"@devvit/shared-types": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@devvit/repo-tools": "0.11.
|
|
32
|
-
"@devvit/tsconfig": "0.11.
|
|
32
|
+
"@devvit/repo-tools": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0",
|
|
33
|
+
"@devvit/tsconfig": "0.11.19-next-2025-07-01-14-39-04-3a189619a.0",
|
|
33
34
|
"eslint": "9.11.1",
|
|
34
35
|
"typescript": "5.8.3",
|
|
35
36
|
"vitest": "1.6.1"
|
|
@@ -38,5 +39,5 @@
|
|
|
38
39
|
"directory": "dist"
|
|
39
40
|
},
|
|
40
41
|
"source": "./src/index.ts",
|
|
41
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "67f59b874319a6daf673d2245be80709aeaf8f1d"
|
|
42
43
|
}
|