@devvit/build-pack 0.12.1-next-2025-09-03-00-10-50-b9d7687ff.0 → 0.12.1-next-2025-09-03-18-30-49-c39f0866a.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/esbuild/templatizer/blocks.template.d.ts +19 -2
- package/esbuild/templatizer/blocks.template.d.ts.map +1 -1
- package/esbuild/templatizer/blocks.template.js +131 -113
- package/esbuild/templatizer/templatizer.d.ts.map +1 -1
- package/esbuild/templatizer/templatizer.js +6 -4
- package/package.json +11 -11
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { Metadata } from '@devvit/protos';
|
|
1
2
|
import { Devvit, type FormKey } from '@devvit/public-api';
|
|
2
|
-
import type { UiResponse } from '@devvit/shared';
|
|
3
|
+
import type { SettingsValidationResponse, UiResponse } from '@devvit/shared';
|
|
4
|
+
import type { JsonObject, PartialJsonObject } from '@devvit/shared-types/json.js';
|
|
3
5
|
declare module '@devvit/public-api' {
|
|
4
6
|
namespace Devvit {
|
|
5
7
|
function _initForms(): void;
|
|
@@ -13,6 +15,21 @@ export declare const formKeyMap: {
|
|
|
13
15
|
[formKey: string]: FormKey;
|
|
14
16
|
};
|
|
15
17
|
/** @internal */
|
|
16
|
-
export declare function
|
|
18
|
+
export declare function abbreviate(str: string): string;
|
|
19
|
+
/** @internal */
|
|
20
|
+
export declare function assertUiResponse(endpoint: string, rsp: Readonly<PartialJsonObject>): asserts rsp is UiResponse;
|
|
21
|
+
/** @internal */
|
|
22
|
+
export declare function assertSettingsValidationResponse(rsp: Readonly<JsonObject>): asserts rsp is SettingsValidationResponse;
|
|
23
|
+
/**
|
|
24
|
+
* Post to endpoint and return user Node.js server response. All responses are
|
|
25
|
+
* expected to be empty or a JSON _object_.
|
|
26
|
+
*
|
|
27
|
+
* @throws Throws on `!Response.ok`.
|
|
28
|
+
* @throws Response body is nonempty and content-type is not JSON.
|
|
29
|
+
* @throws Response body is nonempty and unparsable.
|
|
30
|
+
* @throws Response body is nonempty and not a JSON object.
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export declare function fetchWebbit(endpoint: string, body: Readonly<PartialJsonObject>, meta: Readonly<Metadata>): Promise<JsonObject | undefined>;
|
|
17
34
|
export default Devvit;
|
|
18
35
|
//# sourceMappingURL=blocks.template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blocks.template.d.ts","sourceRoot":"","sources":["../../../src/esbuild/templatizer/blocks.template.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"blocks.template.d.ts","sourceRoot":"","sources":["../../../src/esbuild/templatizer/blocks.template.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAGvD,OAAO,EAEL,MAAM,EACN,KAAK,OAAO,EAMb,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,0BAA0B,EAAkB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7F,OAAO,KAAK,EAAE,UAAU,EAAa,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAgB7F,OAAO,QAAQ,oBAAoB,CAAC;IAGlC,UAAU,MAAM,CAAC;QACf,SAAS,UAAU,IAAI,IAAI,CAAC;QAC5B,SAAS,SAAS,IAAI,IAAI,CAAC;QAC3B,SAAS,cAAc,IAAI,IAAI,CAAC;QAChC,SAAS,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;KAC7D;CACF;AAQD,oFAAoF;AACpF,eAAO,MAAM,UAAU,EAAE;IAAE,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;CAAO,CAAC;AAE7D,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAuGD,gBAAgB;AAChB,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAC/B,OAAO,CAAC,GAAG,IAAI,UAAU,CAiE3B;AAED,gBAAgB;AAChB,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,QAAQ,CAAC,UAAU,CAAC,GACxB,OAAO,CAAC,GAAG,IAAI,0BAA0B,CAO3C;AA4CD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACjC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,GACvB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CA0DjC;AAmJD,eAAe,MAAM,CAAC"}
|
|
@@ -14,6 +14,10 @@ import { backgroundUrl } from '@devvit/splash/utils/assets.js';
|
|
|
14
14
|
const config2 = globalThis.__devvit__?.config;
|
|
15
15
|
/** @internal [state] Map of devvit.json form keys to Devvit-singleton form keys. */
|
|
16
16
|
export const formKeyMap = {};
|
|
17
|
+
/** @internal */
|
|
18
|
+
export function abbreviate(str) {
|
|
19
|
+
return str.length > 256 ? `${str.slice(0, 256)}…` : str;
|
|
20
|
+
}
|
|
17
21
|
function configurePermissions(permissions) {
|
|
18
22
|
// to-do: remove. This is a relic of LinkedBundle generation.
|
|
19
23
|
Devvit.configure({
|
|
@@ -62,11 +66,12 @@ function configureMenuItems(menuItems) {
|
|
|
62
66
|
const menuItem = {
|
|
63
67
|
label: action.label,
|
|
64
68
|
location: action.location,
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
async onPress(ev, ctx) {
|
|
70
|
+
const rsp = await fetchWebbit(action.endpoint, ev, ctx.metadata);
|
|
71
|
+
if (!rsp)
|
|
72
|
+
return;
|
|
73
|
+
assertUiResponse(action.endpoint, rsp);
|
|
74
|
+
handleUiResponse(ctx, rsp);
|
|
70
75
|
},
|
|
71
76
|
};
|
|
72
77
|
// "user" type is blank in Devvit classic. So if it's present in
|
|
@@ -85,7 +90,69 @@ function configureMenuItems(menuItems) {
|
|
|
85
90
|
function configureForms(forms) {
|
|
86
91
|
Devvit._initForms();
|
|
87
92
|
for (const [name, endpoint] of Object.entries(forms)) {
|
|
88
|
-
formKeyMap[name] = Devvit.createForm({ fields: [] }, (ev, ctx) =>
|
|
93
|
+
formKeyMap[name] = Devvit.createForm({ fields: [] }, async (ev, ctx) => {
|
|
94
|
+
const rsp = await fetchWebbit(endpoint, ev.values, ctx.metadata);
|
|
95
|
+
if (!rsp)
|
|
96
|
+
return;
|
|
97
|
+
assertUiResponse(endpoint, rsp);
|
|
98
|
+
handleUiResponse(ctx, rsp);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// TODO: expand this to include Form definitions.
|
|
103
|
+
/** @internal */
|
|
104
|
+
export function assertUiResponse(endpoint, rsp) {
|
|
105
|
+
const preamble = `Node.js server endpoint ${endpoint} returned the wrong UiResponse;`;
|
|
106
|
+
const keyset = {
|
|
107
|
+
navigateTo: undefined,
|
|
108
|
+
showToast: undefined,
|
|
109
|
+
showForm: undefined,
|
|
110
|
+
};
|
|
111
|
+
for (const k in rsp)
|
|
112
|
+
if (!(k in keyset))
|
|
113
|
+
throw Error(`${preamble} unknown key "${k}": ${abbreviate(JSON.stringify(rsp))}`);
|
|
114
|
+
if ('navigateTo' in rsp) {
|
|
115
|
+
if (rsp.navigateTo == null ||
|
|
116
|
+
Array.isArray(rsp.navigateTo) ||
|
|
117
|
+
(typeof rsp.navigateTo !== 'string' && typeof rsp.navigateTo !== 'object') ||
|
|
118
|
+
(typeof rsp.navigateTo === 'object' && typeof rsp.navigateTo.url !== 'string'))
|
|
119
|
+
throw Error(`${preamble} navigateTo must be a string or \`{"url": string}\`: ${abbreviate(JSON.stringify(rsp.navigateTo))}`);
|
|
120
|
+
// navigateTo must be a valid URL or a Post object. (this is validated
|
|
121
|
+
// client-side, so we don't need to validate it here).
|
|
122
|
+
}
|
|
123
|
+
if ('showToast' in rsp) {
|
|
124
|
+
if (rsp.showToast == null ||
|
|
125
|
+
Array.isArray(rsp.showToast) ||
|
|
126
|
+
(typeof rsp.showToast !== 'string' && typeof rsp.showToast !== 'object') ||
|
|
127
|
+
(typeof rsp.showToast === 'object' &&
|
|
128
|
+
(typeof rsp.showToast.text !== 'string' ||
|
|
129
|
+
(rsp.showToast.appearance !== 'neutral' && rsp.showToast.appearance !== 'success'))))
|
|
130
|
+
throw Error(`${preamble} showToast must be a string or \`{"text": string}\`: ${abbreviate(JSON.stringify(rsp.showToast))}`);
|
|
131
|
+
}
|
|
132
|
+
if ('showForm' in rsp) {
|
|
133
|
+
if (rsp.showForm == null ||
|
|
134
|
+
Array.isArray(rsp.showForm) ||
|
|
135
|
+
typeof rsp.showForm !== 'object' ||
|
|
136
|
+
typeof rsp.showForm.name !== 'string' ||
|
|
137
|
+
typeof rsp.showForm.form !== 'object' ||
|
|
138
|
+
('data' in rsp.showForm && typeof rsp.showForm.data !== 'object'))
|
|
139
|
+
throw Error(`${preamble} showForm must be a ShowForm: ${abbreviate(JSON.stringify(rsp.showForm))}`);
|
|
140
|
+
if (!formKeyMap[rsp.showForm.name]) {
|
|
141
|
+
throw new Error(`${preamble} form with name "${rsp.showForm.name}" not found in devvit.json. Consider adding:\n\n "forms": {"${rsp.showForm.name}":"/internal/your/endpoint"}\n\n`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// navigateTo and showForm are mutually exclusive.
|
|
145
|
+
if (rsp.navigateTo && rsp.showForm) {
|
|
146
|
+
throw new Error('navigateTo and showForm cannot be used together in UiResponse');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** @internal */
|
|
150
|
+
export function assertSettingsValidationResponse(rsp) {
|
|
151
|
+
if (!('success' in rsp) || typeof rsp.success !== 'boolean') {
|
|
152
|
+
throw new Error('SettingsValidationResponse must have a boolean "success" field');
|
|
153
|
+
}
|
|
154
|
+
if ('error' in rsp && typeof rsp.error !== 'string') {
|
|
155
|
+
throw new Error('"error" field in SettingsValidationResponse must be a string');
|
|
89
156
|
}
|
|
90
157
|
}
|
|
91
158
|
function configureTriggers(triggers) {
|
|
@@ -99,78 +166,12 @@ function configureTriggers(triggers) {
|
|
|
99
166
|
// Convert the hydrated old Protobuf to JSON. Don't use
|
|
100
167
|
// Protobuf.toJSON() which would omit default values.
|
|
101
168
|
const body = JSON.parse(JSON.stringify(ev));
|
|
102
|
-
|
|
103
|
-
|
|
169
|
+
await fetchWebbit(endpoint, body, ctx.metadata);
|
|
170
|
+
// Don't care about response.
|
|
104
171
|
},
|
|
105
172
|
});
|
|
106
173
|
}
|
|
107
174
|
}
|
|
108
|
-
async function handleFormResponse(endpoint, event, ctx) {
|
|
109
|
-
const responseJson = await callWebbitEndpoint(endpoint, event.values, ctx.metadata);
|
|
110
|
-
const uiResponse = responseJson;
|
|
111
|
-
validateUiResponse(uiResponse);
|
|
112
|
-
await handleUiResponse(ctx, uiResponse);
|
|
113
|
-
}
|
|
114
|
-
// TODO: expand this to fully validate the UiResponse format, including Form definitions,
|
|
115
|
-
// and convert signature to validateUiResponse(uiResponse: JsonValue): uiResponse is UiResponse
|
|
116
|
-
/** @internal */
|
|
117
|
-
export function validateUiResponse(uiResponse) {
|
|
118
|
-
// Validations:
|
|
119
|
-
// (1) The only valid fields on uiResponse are showToast, navigateTo, and showForm.
|
|
120
|
-
const validKeys = ['showToast', 'navigateTo', 'showForm'];
|
|
121
|
-
const invalidKeys = Object.keys(uiResponse).filter((key) => !validKeys.includes(key));
|
|
122
|
-
if (invalidKeys.length > 0) {
|
|
123
|
-
throw new Error(`Invalid fields found in UiResponse: "${invalidKeys.join('", "')}". Valid fields are: "${validKeys.join('", "')}"`);
|
|
124
|
-
}
|
|
125
|
-
// (2) showForm must have a name that exists in the formKeyMap.
|
|
126
|
-
if (uiResponse.showForm) {
|
|
127
|
-
if (!uiResponse.showForm.name) {
|
|
128
|
-
throw new Error('showForm must have a name');
|
|
129
|
-
}
|
|
130
|
-
if (!formKeyMap[uiResponse.showForm.name]) {
|
|
131
|
-
throw new Error(`Form with name "${uiResponse.showForm.name}" not found in devvit.json. Consider adding:\n\n "forms": {"${uiResponse.showForm.name}":"/internal/your/endpoint"}\n\n`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// (3) showToast must be a string or an object with only fields [text, appearance]
|
|
135
|
-
// and text is a mandatory string.
|
|
136
|
-
if (uiResponse.showToast !== undefined) {
|
|
137
|
-
if (typeof uiResponse.showToast === 'string') {
|
|
138
|
-
// Valid case: showToast is a string
|
|
139
|
-
}
|
|
140
|
-
else if (typeof uiResponse.showToast === 'object' && uiResponse.showToast !== null) {
|
|
141
|
-
// Check if it's an object with valid fields
|
|
142
|
-
const toastKeys = Object.keys(uiResponse.showToast);
|
|
143
|
-
const validToastKeys = ['text', 'appearance'];
|
|
144
|
-
const invalidToastKeys = toastKeys.filter((key) => !validToastKeys.includes(key));
|
|
145
|
-
if (invalidToastKeys.length > 0) {
|
|
146
|
-
throw new Error(`Invalid fields found in showToast: "${invalidToastKeys.join('", "')}". Valid fields are: "${validToastKeys.join('", ')}"`);
|
|
147
|
-
}
|
|
148
|
-
if (typeof uiResponse.showToast.text !== 'string') {
|
|
149
|
-
throw new Error('showToast.text is required and must be a string');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
throw new Error('showToast must be a string or an object with text and optional appearance fields');
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// (4) navigateTo must be a valid URL or a Post object. (this is validated client-side, so
|
|
157
|
-
// we don't need to validate it here).
|
|
158
|
-
// (5) navigateTo and showForm are mutually exclusive.
|
|
159
|
-
if (uiResponse.navigateTo && uiResponse.showForm) {
|
|
160
|
-
throw new Error('navigateTo and showForm cannot be used together in UiResponse');
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
function validateSettingsValidationResponse(response) {
|
|
164
|
-
if (typeof response !== 'object' || response === null) {
|
|
165
|
-
throw new Error('SettingsValidationResponse must be an object');
|
|
166
|
-
}
|
|
167
|
-
if (!('success' in response) || typeof response.success !== 'boolean') {
|
|
168
|
-
throw new Error('SettingsValidationResponse must have a boolean "success" field');
|
|
169
|
-
}
|
|
170
|
-
if ('error' in response && typeof response.error !== 'string') {
|
|
171
|
-
throw new Error('"error" field in SettingsValidationResponse must be a string');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
175
|
/**
|
|
175
176
|
* Handle a UiResponse from a Webbit handler (menu action or form handler).
|
|
176
177
|
* This is used to create client-side UI effects in Reddit clients as responses
|
|
@@ -178,7 +179,7 @@ function validateSettingsValidationResponse(response) {
|
|
|
178
179
|
*
|
|
179
180
|
* If multiple effects are present in the UiResponse, they will all be applied.
|
|
180
181
|
*/
|
|
181
|
-
|
|
182
|
+
function handleUiResponse(ctx, uiResponse) {
|
|
182
183
|
if (uiResponse.showToast) {
|
|
183
184
|
ctx.ui.showToast(uiResponse.showToast);
|
|
184
185
|
}
|
|
@@ -189,49 +190,63 @@ async function handleUiResponse(ctx, uiResponse) {
|
|
|
189
190
|
ctx.ui.showFormInternal(formKeyMap[uiResponse.showForm.name], uiResponse.showForm.data, uiResponse.showForm.form);
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Post to endpoint and return user Node.js server response. All responses are
|
|
195
|
+
* expected to be empty or a JSON _object_.
|
|
196
|
+
*
|
|
197
|
+
* @throws Throws on `!Response.ok`.
|
|
198
|
+
* @throws Response body is nonempty and content-type is not JSON.
|
|
199
|
+
* @throws Response body is nonempty and unparsable.
|
|
200
|
+
* @throws Response body is nonempty and not a JSON object.
|
|
201
|
+
* @internal
|
|
202
|
+
*/
|
|
203
|
+
export async function fetchWebbit(endpoint, body, meta) {
|
|
193
204
|
const url = new URL(endpoint, `http://webbit.local:${getServerPort()}/`);
|
|
194
205
|
const headers = {};
|
|
195
|
-
|
|
196
|
-
headers[
|
|
197
|
-
});
|
|
206
|
+
for (const [k, v] of Object.entries(meta))
|
|
207
|
+
headers[k] = v.values.join();
|
|
198
208
|
headers['Content-Type'] = 'application/json';
|
|
199
209
|
headers['Accept'] = 'application/json';
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return jsonResponse;
|
|
213
|
-
}
|
|
214
|
-
catch {
|
|
215
|
-
let errorMessage = `Failed to POST ${endpoint}: ${response.statusText}, `;
|
|
216
|
-
if (response.status === 404) {
|
|
217
|
-
errorMessage += `ensure that you're handling this endpoint in your server code.`;
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
errorMessage += `body: ${bodyText.substring(0, 100)}`;
|
|
221
|
-
}
|
|
222
|
-
throw new Error(errorMessage);
|
|
223
|
-
}
|
|
210
|
+
const preamble = `Failed to POST to Node.js server endpoint ${endpoint}; server responded with`;
|
|
211
|
+
let rsp;
|
|
212
|
+
try {
|
|
213
|
+
rsp = await fetch(url, {
|
|
214
|
+
body: JSON.stringify(body),
|
|
215
|
+
headers,
|
|
216
|
+
method: 'POST',
|
|
217
|
+
// to-do: redirect: 'manual'?
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
throw `${preamble} error: ${err instanceof Error ? err.message : err}`;
|
|
224
222
|
}
|
|
225
|
-
|
|
223
|
+
if (rsp.status === 404)
|
|
224
|
+
throw Error(`${preamble} HTTP status ${rsp.status}: ensure the server handles the \`${endpoint}\` endpoint`);
|
|
225
|
+
if (!rsp.ok)
|
|
226
|
+
throw Error(`${preamble} HTTP status ${rsp.status}: ${rsp.statusText}`);
|
|
227
|
+
if (!Number(rsp.headers.get('Content-Length')))
|
|
228
|
+
return;
|
|
229
|
+
const contentType = rsp.headers.get('Content-Type');
|
|
226
230
|
if (!contentType || !contentType.includes('application/json')) {
|
|
227
|
-
throw
|
|
231
|
+
throw Error(`${preamble} Content-Type header "${contentType}" but only "application/json" is supported`);
|
|
232
|
+
}
|
|
233
|
+
let text;
|
|
234
|
+
try {
|
|
235
|
+
text = await rsp.text();
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
throw Error(`${preamble} an unreadable JSON body`);
|
|
228
239
|
}
|
|
240
|
+
let json;
|
|
229
241
|
try {
|
|
230
|
-
|
|
242
|
+
json = JSON.parse(text);
|
|
231
243
|
}
|
|
232
|
-
catch
|
|
233
|
-
throw
|
|
244
|
+
catch {
|
|
245
|
+
throw Error(`${preamble} an unparsable JSON body: ${abbreviate(text)}`);
|
|
234
246
|
}
|
|
247
|
+
if (!json || typeof json !== 'object' || Array.isArray(json))
|
|
248
|
+
throw Error(`${preamble} an unrecognized JSON body instead of an object \`{}\`: ${abbreviate(text)}`);
|
|
249
|
+
return json;
|
|
235
250
|
}
|
|
236
251
|
function configureScheduler(schedulerConfig) {
|
|
237
252
|
Devvit._initScheduler();
|
|
@@ -240,7 +255,8 @@ function configureScheduler(schedulerConfig) {
|
|
|
240
255
|
Devvit.addSchedulerJob({
|
|
241
256
|
name: name,
|
|
242
257
|
onRun: async (event, context) => {
|
|
243
|
-
await
|
|
258
|
+
await fetchWebbit(task.endpoint, { name: event.name, data: event.data }, context.metadata);
|
|
259
|
+
// Don't care about response.
|
|
244
260
|
},
|
|
245
261
|
});
|
|
246
262
|
// Tasks with cron specified require a bit more work further down
|
|
@@ -326,12 +342,14 @@ function coerceSettingForClassic(setting, scope) {
|
|
|
326
342
|
}
|
|
327
343
|
if (setting.validationEndpoint) {
|
|
328
344
|
classicSetting.onValidate = async function validateSettingsField(event, context) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
345
|
+
const rsp = await fetchWebbit(setting.validationEndpoint, { value: event.value, isEditing: event.isEditing }, context.metadata);
|
|
346
|
+
if (!rsp)
|
|
347
|
+
return; // Assume success.
|
|
348
|
+
assertSettingsValidationResponse(rsp);
|
|
349
|
+
if (rsp.success) {
|
|
332
350
|
return;
|
|
333
351
|
}
|
|
334
|
-
return
|
|
352
|
+
return rsp.error;
|
|
335
353
|
};
|
|
336
354
|
}
|
|
337
355
|
return classicSetting;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templatizer.d.ts","sourceRoot":"","sources":["../../../src/esbuild/templatizer/templatizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"templatizer.d.ts","sourceRoot":"","sources":["../../../src/esbuild/templatizer/templatizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYxF"}
|
|
@@ -3,10 +3,12 @@ import path from 'node:path';
|
|
|
3
3
|
export function templatize(root, blocksEntry) {
|
|
4
4
|
const template = path.join(import.meta.dirname, 'blocks.template.js');
|
|
5
5
|
const blocks = blocksEntry ? path.join(root, blocksEntry) : undefined;
|
|
6
|
-
// Import user code second so that it has precedence.
|
|
6
|
+
// Import user code second so that it has precedence. Add `|| {}` to avoid
|
|
7
|
+
// esbuild warning on apps that don't have a default export.
|
|
7
8
|
return `
|
|
8
9
|
import Devvit from ${JSON.stringify(template.replaceAll('\\', '/'))};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
${blocks ? `import * as blocks from ${JSON.stringify(blocks.replaceAll('\\', '/'))};` : 'const blocks = undefined;'}
|
|
11
|
+
const Actor = (blocks || {}).default ?? Devvit;
|
|
12
|
+
export default Actor;
|
|
13
|
+
`.trim();
|
|
12
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devvit/build-pack",
|
|
3
|
-
"version": "0.12.1-next-2025-09-03-
|
|
3
|
+
"version": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
},
|
|
32
32
|
"types": "./dist/index.d.ts",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@devvit/protos": "0.12.1-next-2025-09-03-
|
|
35
|
-
"@devvit/shared-types": "0.12.1-next-2025-09-03-
|
|
36
|
-
"@devvit/splash": "0.12.1-next-2025-09-03-
|
|
34
|
+
"@devvit/protos": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
35
|
+
"@devvit/shared-types": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
36
|
+
"@devvit/splash": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
37
37
|
"esbuild": "0.23.0",
|
|
38
38
|
"rxjs": "7.8.1",
|
|
39
39
|
"tsv": "0.2.0",
|
|
@@ -44,16 +44,16 @@
|
|
|
44
44
|
"@devvit/shared": "*"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@devvit/public-api": "0.12.1-next-2025-09-03-
|
|
48
|
-
"@devvit/repo-tools": "0.12.1-next-2025-09-03-
|
|
49
|
-
"@devvit/scheduler": "0.12.1-next-2025-09-03-
|
|
50
|
-
"@devvit/server": "0.12.1-next-2025-09-03-
|
|
51
|
-
"@devvit/shared": "0.12.1-next-2025-09-03-
|
|
52
|
-
"@devvit/tsconfig": "0.12.1-next-2025-09-03-
|
|
47
|
+
"@devvit/public-api": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
48
|
+
"@devvit/repo-tools": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
49
|
+
"@devvit/scheduler": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
50
|
+
"@devvit/server": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
51
|
+
"@devvit/shared": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
52
|
+
"@devvit/tsconfig": "0.12.1-next-2025-09-03-18-30-49-c39f0866a.0",
|
|
53
53
|
"@types/tsv": "0.2.1",
|
|
54
54
|
"eslint": "9.11.1",
|
|
55
55
|
"vitest": "1.6.1"
|
|
56
56
|
},
|
|
57
57
|
"source": "./src/index.ts",
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "75b507a70c64212d4e530f17bc55547ed0e8551c"
|
|
59
59
|
}
|