@devvit/build-pack 0.12.0-next-2025-04-30-5d2b49b36.0 → 0.12.0-next-2025-08-12-20-06-14-50f19bb3e.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/BuildInfoUtil.d.ts +6 -8
- package/esbuild/BuildInfoUtil.d.ts.map +1 -1
- package/esbuild/BuildInfoUtil.js +40 -26
- package/esbuild/BundleModule.d.ts.map +1 -1
- package/esbuild/BundleModule.js +6 -13
- package/esbuild/ESBuildPack.d.ts +38 -14
- package/esbuild/ESBuildPack.d.ts.map +1 -1
- package/esbuild/ESBuildPack.js +136 -98
- package/esbuild/dependency-spec-util.d.ts +10 -0
- package/esbuild/dependency-spec-util.d.ts.map +1 -0
- package/esbuild/dependency-spec-util.js +135 -0
- package/esbuild/dependency-spec-util.test.d.ts.map +1 -0
- package/esbuild/templatizer/blocks.template.d.ts +10 -0
- package/esbuild/templatizer/blocks.template.d.ts.map +1 -0
- package/esbuild/templatizer/blocks.template.js +343 -0
- package/esbuild/templatizer/blocks.template.test.d.ts.map +1 -0
- package/esbuild/templatizer/templatizer.d.ts +4 -0
- package/esbuild/templatizer/templatizer.d.ts.map +1 -0
- package/esbuild/templatizer/templatizer.js +12 -0
- package/esbuild/templatizer/templatizer.test.d.ts.map +1 -0
- package/esbuild/utils.d.ts +0 -4
- package/esbuild/utils.d.ts.map +1 -1
- package/esbuild/utils.js +0 -21
- package/index.d.ts +0 -1
- package/index.d.ts.map +1 -1
- package/index.js +0 -1
- package/lib/BuildPack.d.ts +6 -16
- package/lib/BuildPack.d.ts.map +1 -1
- package/lib/BuildPack.js +10 -6
- package/package.json +26 -15
- package/esbuild/type-checkers/TscTypeChecker.d.ts +0 -13
- package/esbuild/type-checkers/TscTypeChecker.d.ts.map +0 -1
- package/esbuild/type-checkers/TscTypeChecker.js +0 -93
- package/esbuild/type-checkers/types.d.ts +0 -10
- package/esbuild/type-checkers/types.d.ts.map +0 -1
- package/esbuild/type-checkers/types.js +0 -1
package/esbuild/ESBuildPack.js
CHANGED
|
@@ -9,24 +9,26 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _Watcher_instances, _Watcher_disableExternDevvitProtos,
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import { Bundle
|
|
12
|
+
var _Watcher_instances, _Watcher_disableExternDevvitProtos, _Watcher_config, _Watcher_root, _Watcher_observable, _Watcher_disposedNotifier, _Watcher_disposeWatcher, _Watcher_namespace, _Watcher_buildTargets, _Watcher_ready, _Watcher_init, _Watcher_makeEntry, _Watcher_makeEsbuildContext, _Watcher_onBuildEnd, _ESBuildPack_bundleWatchers, _ESBuildPack_namespace, _ESBuildPack_disableExternDevvitProtos;
|
|
13
|
+
import fs, { readFileSync } from 'node:fs';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { Bundle } from '@devvit/protos/types/devvit/plugin/buildpack/buildpack_common.js';
|
|
16
16
|
import { TargetRuntime, } from '@devvit/protos/types/devvit/runtime/bundle.js';
|
|
17
17
|
import { ConfigImpl as Config } from '@devvit/shared-types/ConfigImpl.js';
|
|
18
|
-
import {
|
|
18
|
+
import { NonNull } from '@devvit/shared-types/NonNull.js';
|
|
19
19
|
import { StringUtil } from '@devvit/shared-types/StringUtil.js';
|
|
20
20
|
import esbuild, {} from 'esbuild';
|
|
21
21
|
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
|
22
|
+
import { of } from 'rxjs';
|
|
22
23
|
import { takeUntil } from 'rxjs/operators';
|
|
23
|
-
import
|
|
24
|
-
import { getModuleEntrypoint } from '../lib/BuildPack.js';
|
|
24
|
+
import { getClassicModuleEntrypoint, getModuleEntrypoint } from '../lib/BuildPack.js';
|
|
25
25
|
import { newBuildInfoDependencies } from './BuildInfoUtil.js';
|
|
26
26
|
import { dangerouslyGetBundleActor } from './BundleModule.js';
|
|
27
|
+
import { createDependencySpec } from './dependency-spec-util.js';
|
|
27
28
|
import { externalizeDevvitProtos } from './plugins/externalizeDevvitProtos.js';
|
|
28
29
|
import { postProcessServerStubCode, serverClientCodeSplit, } from './plugins/serverClientCodeSplit.js';
|
|
29
|
-
import {
|
|
30
|
+
import { templatize } from './templatizer/templatizer.js';
|
|
31
|
+
import { prefixBuildResultLogs } from './utils.js';
|
|
30
32
|
const FAKE_FACTORY = {
|
|
31
33
|
// TODO: remove use of any below
|
|
32
34
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -38,11 +40,10 @@ export class Watcher {
|
|
|
38
40
|
* The default behavior is to externalize @devvit/protos. Set
|
|
39
41
|
* disableExternDevvitProtos to bundle this large dependency.
|
|
40
42
|
*/
|
|
41
|
-
constructor(namespace, root, actorSpec, options) {
|
|
43
|
+
constructor(config, namespace, root, actorSpec, options) {
|
|
42
44
|
_Watcher_instances.add(this);
|
|
43
45
|
_Watcher_disableExternDevvitProtos.set(this, void 0);
|
|
44
|
-
|
|
45
|
-
_Watcher_targetRuntimes.set(this, void 0);
|
|
46
|
+
_Watcher_config.set(this, void 0);
|
|
46
47
|
_Watcher_root.set(this, void 0);
|
|
47
48
|
/**
|
|
48
49
|
* the actual emitter of updates
|
|
@@ -59,11 +60,10 @@ export class Watcher {
|
|
|
59
60
|
_Watcher_namespace.set(this, void 0);
|
|
60
61
|
_Watcher_buildTargets.set(this, new Map());
|
|
61
62
|
_Watcher_ready.set(this, void 0);
|
|
63
|
+
__classPrivateFieldSet(this, _Watcher_config, config, "f");
|
|
62
64
|
__classPrivateFieldSet(this, _Watcher_namespace, namespace, "f");
|
|
63
65
|
__classPrivateFieldSet(this, _Watcher_root, root, "f");
|
|
64
66
|
__classPrivateFieldSet(this, _Watcher_disableExternDevvitProtos, options?.disableExternDevvitProtos ?? false, "f");
|
|
65
|
-
__classPrivateFieldSet(this, _Watcher_typeChecker, options?.typeChecker, "f");
|
|
66
|
-
__classPrivateFieldSet(this, _Watcher_targetRuntimes, options?.targetRuntimes ?? BUILD_TARGETS, "f");
|
|
67
67
|
// observers of this will be subscribed until this.disposedNotifier emits a value
|
|
68
68
|
const sourceObservable = new Observable().pipe(takeUntil(__classPrivateFieldGet(this, _Watcher_disposedNotifier, "f")));
|
|
69
69
|
// our observable is a BehaviorSubject used to multicast the source observer
|
|
@@ -88,11 +88,12 @@ export class Watcher {
|
|
|
88
88
|
__classPrivateFieldGet(this, _Watcher_disposedNotifier, "f").complete();
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
_Watcher_disableExternDevvitProtos = new WeakMap(),
|
|
91
|
+
_Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_config = new WeakMap(), _Watcher_root = new WeakMap(), _Watcher_observable = new WeakMap(), _Watcher_disposedNotifier = new WeakMap(), _Watcher_disposeWatcher = new WeakMap(), _Watcher_namespace = new WeakMap(), _Watcher_buildTargets = new WeakMap(), _Watcher_ready = new WeakMap(), _Watcher_instances = new WeakSet(), _Watcher_init = async function _Watcher_init(actorSpec) {
|
|
92
|
+
const entry = __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_makeEntry).call(this);
|
|
92
93
|
// Building for Universal and Client targets. May include Server in the future.
|
|
93
|
-
for (const target of
|
|
94
|
+
for (const target of BUILD_TARGETS) {
|
|
94
95
|
__classPrivateFieldGet(this, _Watcher_buildTargets, "f").set(target, {
|
|
95
|
-
ctx: await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_makeEsbuildContext).call(this, actorSpec, target),
|
|
96
|
+
ctx: await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_makeEsbuildContext).call(this, actorSpec, target, entry),
|
|
96
97
|
});
|
|
97
98
|
}
|
|
98
99
|
__classPrivateFieldSet(this, _Watcher_disposeWatcher, async () => {
|
|
@@ -110,12 +111,19 @@ _Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_typeChecker = new W
|
|
|
110
111
|
watchers.push(target.ctx.watch());
|
|
111
112
|
}
|
|
112
113
|
await Promise.all(watchers);
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
const
|
|
114
|
+
}, _Watcher_makeEntry = function _Watcher_makeEntry() {
|
|
115
|
+
// The watched file doesn't change but its dependencies do.
|
|
116
|
+
const entry = getModuleEntrypoint(__classPrivateFieldGet(this, _Watcher_config, "f"), __classPrivateFieldGet(this, _Watcher_root, "f"));
|
|
117
|
+
if (__classPrivateFieldGet(this, _Watcher_config, "f")) {
|
|
118
|
+
const template = templatize(__classPrivateFieldGet(this, _Watcher_root, "f"), __classPrivateFieldGet(this, _Watcher_config, "f").blocks?.entry);
|
|
119
|
+
fs.writeFileSync(entry, template);
|
|
120
|
+
}
|
|
121
|
+
return entry;
|
|
122
|
+
}, _Watcher_makeEsbuildContext = async function _Watcher_makeEsbuildContext(actorSpec, targetRuntime, entry) {
|
|
123
|
+
const cfg = esbuildConfig(__classPrivateFieldGet(this, _Watcher_config, "f"), __classPrivateFieldGet(this, _Watcher_disableExternDevvitProtos, "f"), targetRuntime, true);
|
|
116
124
|
return await esbuild.context({
|
|
117
125
|
...cfg,
|
|
118
|
-
entryPoints: [
|
|
126
|
+
entryPoints: [entry],
|
|
119
127
|
minify: false,
|
|
120
128
|
sourcemap: 'external',
|
|
121
129
|
outfile: 'main.js',
|
|
@@ -125,7 +133,7 @@ _Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_typeChecker = new W
|
|
|
125
133
|
name: 'optionally-type-check-and-publish-compile-result-on-build-end',
|
|
126
134
|
setup: (build) => {
|
|
127
135
|
build.onEnd(async (result) => {
|
|
128
|
-
await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_onBuildEnd).call(this, actorSpec, result,
|
|
136
|
+
await __classPrivateFieldGet(this, _Watcher_instances, "m", _Watcher_onBuildEnd).call(this, actorSpec, result, targetRuntime);
|
|
129
137
|
});
|
|
130
138
|
},
|
|
131
139
|
},
|
|
@@ -137,7 +145,7 @@ _Watcher_disableExternDevvitProtos = new WeakMap(), _Watcher_typeChecker = new W
|
|
|
137
145
|
/**
|
|
138
146
|
* @description The callback function for esbuild's onEnd hook. This is called after esbuild has finished building.
|
|
139
147
|
*/
|
|
140
|
-
async function _Watcher_onBuildEnd(actorSpec, esbuildResult,
|
|
148
|
+
async function _Watcher_onBuildEnd(actorSpec, esbuildResult, targetRuntime) {
|
|
141
149
|
await __classPrivateFieldGet(this, _Watcher_ready, "f");
|
|
142
150
|
__classPrivateFieldGet(this, _Watcher_buildTargets, "f").get(targetRuntime).result = esbuildResult;
|
|
143
151
|
const results = new Map();
|
|
@@ -147,22 +155,12 @@ async function _Watcher_onBuildEnd(actorSpec, esbuildResult, entryPoint, targetR
|
|
|
147
155
|
return;
|
|
148
156
|
results.set(targetRuntime, target.result);
|
|
149
157
|
}
|
|
150
|
-
const esbuildCompileRes = await newCompileResponse(__classPrivateFieldGet(this, _Watcher_namespace, "f"), actorSpec, results,
|
|
158
|
+
const esbuildCompileRes = await newCompileResponse(__classPrivateFieldGet(this, _Watcher_config, "f"), __classPrivateFieldGet(this, _Watcher_namespace, "f"), actorSpec, results, __classPrivateFieldGet(this, _Watcher_root, "f"));
|
|
151
159
|
// clear saved values so we don't double-fire the next time we get results
|
|
152
160
|
for (const [_, target] of __classPrivateFieldGet(this, _Watcher_buildTargets, "f")) {
|
|
153
161
|
target.result = undefined;
|
|
154
162
|
}
|
|
155
|
-
|
|
156
|
-
// all projects).
|
|
157
|
-
if (!__classPrivateFieldGet(this, _Watcher_typeChecker, "f") || (await hasTsxFiles(__classPrivateFieldGet(this, _Watcher_root, "f")))) {
|
|
158
|
-
console.warn('Type checking is disabled.');
|
|
159
|
-
__classPrivateFieldGet(this, _Watcher_observable, "f").next(esbuildCompileRes);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
const typeCheckCompileRes = await __classPrivateFieldGet(this, _Watcher_typeChecker, "f").check({
|
|
163
|
-
filename: __classPrivateFieldGet(this, _Watcher_root, "f"),
|
|
164
|
-
});
|
|
165
|
-
__classPrivateFieldGet(this, _Watcher_observable, "f").next(mergeCompileRes(esbuildCompileRes, typeCheckCompileRes));
|
|
163
|
+
__classPrivateFieldGet(this, _Watcher_observable, "f").next(esbuildCompileRes);
|
|
166
164
|
};
|
|
167
165
|
export class ESBuildPack {
|
|
168
166
|
/**
|
|
@@ -178,35 +176,32 @@ export class ESBuildPack {
|
|
|
178
176
|
_ESBuildPack_namespace.set(this, void 0);
|
|
179
177
|
// EsbuildPack options
|
|
180
178
|
_ESBuildPack_disableExternDevvitProtos.set(this, void 0);
|
|
181
|
-
// type chcecking will be disabled if typeChecker is undefined
|
|
182
|
-
_ESBuildPack_typeChecker.set(this, void 0);
|
|
183
|
-
// don't print out warnings if this is set
|
|
184
|
-
_ESBuildPack_disableTypeCheckerWarning.set(this, void 0);
|
|
185
179
|
__classPrivateFieldSet(this, _ESBuildPack_namespace, namespace, "f");
|
|
186
180
|
__classPrivateFieldSet(this, _ESBuildPack_disableExternDevvitProtos, options?.disableExternDevvitProtos ?? false, "f");
|
|
187
|
-
__classPrivateFieldSet(this, _ESBuildPack_typeChecker, options?.typeChecker, "f");
|
|
188
|
-
__classPrivateFieldSet(this, _ESBuildPack_disableTypeCheckerWarning, options?.disableTypeCheckerWarning ?? false, "f");
|
|
189
181
|
}
|
|
190
|
-
async
|
|
191
|
-
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
182
|
+
async compile({ config, minify, info, includeMetafile, root, }) {
|
|
183
|
+
const entry = getModuleEntrypoint(config, root);
|
|
184
|
+
if (config) {
|
|
185
|
+
const template = templatize(root, config.blocks?.entry);
|
|
186
|
+
try {
|
|
187
|
+
fs.writeFileSync(entry, template);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
return unknownToErrorCompileResponse('Compilation', err);
|
|
191
|
+
}
|
|
195
192
|
}
|
|
196
|
-
assertNonNull(info, "Expected 'info' of CompileParams to be non-null");
|
|
197
|
-
const entrypoint = getModuleEntrypoint(filename);
|
|
198
193
|
const buildResults = new Map();
|
|
199
194
|
for (const targetRuntime of BUILD_TARGETS) {
|
|
200
|
-
const cfg = esbuildConfig(__classPrivateFieldGet(this, _ESBuildPack_disableExternDevvitProtos, "f"), targetRuntime);
|
|
195
|
+
const cfg = esbuildConfig(config, __classPrivateFieldGet(this, _ESBuildPack_disableExternDevvitProtos, "f"), targetRuntime);
|
|
201
196
|
try {
|
|
202
197
|
const buildResult = await esbuild.build({
|
|
203
198
|
...cfg,
|
|
204
|
-
entryPoints: [
|
|
199
|
+
entryPoints: [entry],
|
|
205
200
|
metafile: true,
|
|
206
201
|
sourcemap: 'external',
|
|
207
202
|
plugins: [excludeNodeModulesFromSourceMapsPlugin(), ...(cfg.plugins || [])],
|
|
208
203
|
sourcesContent: false,
|
|
209
|
-
minify: minify ===
|
|
204
|
+
minify: minify === 'All',
|
|
210
205
|
outfile: 'main.js',
|
|
211
206
|
treeShaking: true,
|
|
212
207
|
});
|
|
@@ -214,46 +209,40 @@ export class ESBuildPack {
|
|
|
214
209
|
}
|
|
215
210
|
catch (err) {
|
|
216
211
|
return isEsbuildResult(err)
|
|
217
|
-
? await newCompileResponse(__classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, new Map([[targetRuntime, err]]),
|
|
212
|
+
? await newCompileResponse(config, __classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, new Map([[targetRuntime, err]]), root, includeMetafile)
|
|
218
213
|
: unknownToErrorCompileResponse('Compilation', err);
|
|
219
214
|
}
|
|
220
215
|
}
|
|
221
|
-
const esbuildCompileResult = await newCompileResponse(__classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, buildResults,
|
|
216
|
+
const esbuildCompileResult = await newCompileResponse(config, __classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), info, buildResults, root, includeMetafile);
|
|
222
217
|
if (esbuildCompileResult.bundles.length === 0) {
|
|
223
218
|
throw new Error(esbuildCompileResult.errors?.[0]?.text ?? 'Missing bundle');
|
|
224
219
|
}
|
|
225
|
-
|
|
226
|
-
// all projects).
|
|
227
|
-
if (!__classPrivateFieldGet(this, _ESBuildPack_typeChecker, "f") || (await hasTsxFiles(filename))) {
|
|
228
|
-
if (!__classPrivateFieldGet(this, _ESBuildPack_disableTypeCheckerWarning, "f"))
|
|
229
|
-
console.warn('Type checking is disabled.');
|
|
230
|
-
return esbuildCompileResult;
|
|
231
|
-
}
|
|
232
|
-
const typeCheckingResult = await __classPrivateFieldGet(this, _ESBuildPack_typeChecker, "f").check({ filename });
|
|
233
|
-
return mergeCompileRes(esbuildCompileResult, typeCheckingResult);
|
|
220
|
+
return esbuildCompileResult;
|
|
234
221
|
}
|
|
235
222
|
async dispose() {
|
|
236
223
|
await Promise.all(Array.from(__classPrivateFieldGet(this, _ESBuildPack_bundleWatchers, "f").values()).map((watcher) => watcher.dispose()));
|
|
237
224
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (!__classPrivateFieldGet(this, _ESBuildPack_bundleWatchers, "f").has(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
225
|
+
watch({ config, root, info }) {
|
|
226
|
+
// Use a stable entrypoint, not a template.
|
|
227
|
+
const blocksEntry = config?.blocks?.entry ?? getClassicModuleEntrypoint(root);
|
|
228
|
+
if (!__classPrivateFieldGet(this, _ESBuildPack_bundleWatchers, "f").has(blocksEntry)) {
|
|
229
|
+
let watcher;
|
|
230
|
+
try {
|
|
231
|
+
watcher = new Watcher(config, __classPrivateFieldGet(this, _ESBuildPack_namespace, "f"), root, info, {
|
|
232
|
+
disableExternDevvitProtos: __classPrivateFieldGet(this, _ESBuildPack_disableExternDevvitProtos, "f"),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
return of(unknownToErrorCompileResponse('Compilation', err));
|
|
237
|
+
}
|
|
238
|
+
__classPrivateFieldGet(this, _ESBuildPack_bundleWatchers, "f").set(root, watcher);
|
|
247
239
|
return watcher.getObservable();
|
|
248
240
|
}
|
|
249
|
-
return NonNull(__classPrivateFieldGet(this, _ESBuildPack_bundleWatchers, "f").get(
|
|
241
|
+
return NonNull(__classPrivateFieldGet(this, _ESBuildPack_bundleWatchers, "f").get(blocksEntry)).getObservable();
|
|
250
242
|
}
|
|
251
243
|
}
|
|
252
|
-
_ESBuildPack_bundleWatchers = new WeakMap(), _ESBuildPack_namespace = new WeakMap(), _ESBuildPack_disableExternDevvitProtos = new WeakMap()
|
|
253
|
-
|
|
254
|
-
// TODO: Owner should come from project root's config file
|
|
255
|
-
async function newCompileResponse(namespace, actorSpec, buildResults, entryPoint, includeMetafile = false) {
|
|
256
|
-
assertNonNull(actorSpec, 'Expected actorSpec to be non-null');
|
|
244
|
+
_ESBuildPack_bundleWatchers = new WeakMap(), _ESBuildPack_namespace = new WeakMap(), _ESBuildPack_disableExternDevvitProtos = new WeakMap();
|
|
245
|
+
async function newCompileResponse(config, namespace, actorSpec, buildResults, root, includeMetafile = false) {
|
|
257
246
|
const errors = [];
|
|
258
247
|
const warnings = [];
|
|
259
248
|
const bundles = [];
|
|
@@ -289,8 +278,7 @@ async function newCompileResponse(namespace, actorSpec, buildResults, entryPoint
|
|
|
289
278
|
}
|
|
290
279
|
let dependencies;
|
|
291
280
|
try {
|
|
292
|
-
|
|
293
|
-
dependencies = await makeDependencySpec(namespace, actorSpec, ActorClass);
|
|
281
|
+
dependencies = await getDependencySpec(actorSpec, code, config, namespace);
|
|
294
282
|
}
|
|
295
283
|
catch (err) {
|
|
296
284
|
return unknownToErrorCompileResponse('Evaluation', err);
|
|
@@ -306,31 +294,25 @@ async function newCompileResponse(namespace, actorSpec, buildResults, entryPoint
|
|
|
306
294
|
dependencies,
|
|
307
295
|
buildInfo: {
|
|
308
296
|
created: new Date(),
|
|
309
|
-
dependencies: newBuildInfoDependencies(
|
|
297
|
+
dependencies: newBuildInfoDependencies(root),
|
|
310
298
|
targetRuntime,
|
|
311
299
|
},
|
|
312
300
|
webviewAssetIds: {},
|
|
313
301
|
metafile,
|
|
314
302
|
});
|
|
315
303
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const bundleHashes = new Set();
|
|
319
|
-
bundles.forEach((bundle) => {
|
|
320
|
-
const algo = crypto.createHash('sha256');
|
|
321
|
-
algo.update(bundle.code);
|
|
322
|
-
const hash = algo.digest('hex');
|
|
323
|
-
if (!bundleHashes.has(hash)) {
|
|
324
|
-
bundleHashes.add(hash);
|
|
325
|
-
filteredBundles.push(bundle);
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
if (filteredBundles.length === 1) {
|
|
329
|
-
filteredBundles[0].buildInfo.targetRuntime = TargetRuntime.UNIVERSAL;
|
|
304
|
+
try {
|
|
305
|
+
updateBundleServer(bundles, root, config?.server);
|
|
330
306
|
}
|
|
331
|
-
|
|
307
|
+
catch {
|
|
308
|
+
const serverEntry = config?.server
|
|
309
|
+
? path.join(config.server.dir, config.server.entry)
|
|
310
|
+
: undefined;
|
|
311
|
+
return unknownToErrorCompileResponse('Evaluation', `Cannot read \`config.server.entry\` file (${serverEntry}).`);
|
|
312
|
+
}
|
|
313
|
+
return { bundles, errors, warnings };
|
|
332
314
|
}
|
|
333
|
-
async function
|
|
315
|
+
async function dangerouslyMakeDependencySpec(namespace, actorSpec, ActorClass) {
|
|
334
316
|
const config = new Config(FAKE_FACTORY, actorSpec, {}, {});
|
|
335
317
|
new ActorClass(config);
|
|
336
318
|
const spec = config.export(namespace);
|
|
@@ -368,10 +350,22 @@ function esbuildMessageToBuildLog(msg) {
|
|
|
368
350
|
function isEsbuildResult(err) {
|
|
369
351
|
return err instanceof Object && 'errors' in err && 'warnings' in err;
|
|
370
352
|
}
|
|
371
|
-
|
|
353
|
+
/** Call with defined config for v1 behavior. */
|
|
354
|
+
function esbuildConfig(config, disableExternDevvitProtos, targetRuntime, watchMode = false) {
|
|
372
355
|
return {
|
|
356
|
+
// When Blocks migration is used, the Devvit singleton used in the template
|
|
357
|
+
// must be the same instance as that used elsewhere. Aliases are resolved
|
|
358
|
+
// from the current working directory, not the compiled file's directory, so
|
|
359
|
+
// this effectively maps the template's @devvit/public-api to the app's
|
|
360
|
+
// version. The same could be done for @devvit/server but apps don't
|
|
361
|
+
// necessarily have a copy.
|
|
362
|
+
alias: config?.blocks ? { '@devvit/public-api': '@devvit/public-api' } : {},
|
|
373
363
|
// Recursively inline any imported dependencies.
|
|
374
364
|
bundle: true,
|
|
365
|
+
// Tightly coupled to blocks.template.tsx.
|
|
366
|
+
define: {
|
|
367
|
+
'globalThis.__devvit__': config ? JSON.stringify({ config }, undefined, 2) : 'undefined',
|
|
368
|
+
},
|
|
375
369
|
external: [
|
|
376
370
|
'node:*',
|
|
377
371
|
// All .js files from https://github.com/nodejs/node/tree/b2405e9/lib that
|
|
@@ -474,6 +468,50 @@ function excludeNodeModulesFromSourceMapsPlugin() {
|
|
|
474
468
|
},
|
|
475
469
|
};
|
|
476
470
|
}
|
|
477
|
-
async function
|
|
478
|
-
|
|
471
|
+
async function getDependencySpec(actorSpec, code, config, namespace) {
|
|
472
|
+
if (config)
|
|
473
|
+
return createDependencySpec(actorSpec, config, namespace);
|
|
474
|
+
const ActorClass = await dangerouslyGetBundleActor(code);
|
|
475
|
+
return await dangerouslyMakeDependencySpec(namespace, actorSpec, ActorClass);
|
|
476
|
+
}
|
|
477
|
+
/** Throws when unable to read config.server.entry. */
|
|
478
|
+
function newServerBundle(root, server) {
|
|
479
|
+
const serverEntry = path.join(server.dir, server.entry);
|
|
480
|
+
let code;
|
|
481
|
+
try {
|
|
482
|
+
code = readFileSync(path.resolve(root, serverEntry), 'utf8');
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
throw Error(`Cannot read \`config.server.entry\` file (${serverEntry}).`, {
|
|
486
|
+
cause: err,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
const sourceMapFilename = findSourceMapURL(code) ?? `${serverEntry}.map`;
|
|
490
|
+
let sourceMap = '';
|
|
491
|
+
try {
|
|
492
|
+
sourceMap = readFileSync(path.resolve(root, sourceMapFilename), 'utf8');
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
// source map files aren't required, safe to swallow this error
|
|
496
|
+
}
|
|
497
|
+
return { code, sourceMap };
|
|
498
|
+
}
|
|
499
|
+
/** @internal */
|
|
500
|
+
export function findSourceMapURL(src) {
|
|
501
|
+
return /[@#]\s*sourceMappingURL=([^\s*]+)(?![\s\S]*sourceMappingURL)/.exec(src)?.[1];
|
|
502
|
+
}
|
|
503
|
+
/** Throws when unable to read config.server.entry. */
|
|
504
|
+
export function updateBundleServer(bundles, root, server) {
|
|
505
|
+
if (!server)
|
|
506
|
+
return;
|
|
507
|
+
for (const bundle of bundles)
|
|
508
|
+
if (bundle.buildInfo?.targetRuntime === TargetRuntime.UNIVERSAL)
|
|
509
|
+
bundle.server = newServerBundle(root, server);
|
|
510
|
+
}
|
|
511
|
+
export function updateBundleVersion(bundles, version) {
|
|
512
|
+
for (const bundle of bundles) {
|
|
513
|
+
bundle.dependencies ??= { hostname: '', provides: [], uses: [], permissions: [] };
|
|
514
|
+
bundle.dependencies.actor ??= { name: '', owner: '', version: '' };
|
|
515
|
+
bundle.dependencies.actor.version = version.toString();
|
|
516
|
+
}
|
|
479
517
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ActorSpec, DependencySpec } from '@devvit/protos/community.js';
|
|
2
|
+
import type { Namespace } from '@devvit/shared-types/Namespace.js';
|
|
3
|
+
import type { AppConfig } from '@devvit/shared-types/schemas/config-file.v1.js';
|
|
4
|
+
/**
|
|
5
|
+
* Convert a static `AppConfig` to a `DependencySpec`. Similar to the classic
|
|
6
|
+
* `Devvit` singleton, `ConfigImpl`, `addPaymentHandler()`, and
|
|
7
|
+
* `paymentsPlugin`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createDependencySpec(actorSpec: Readonly<ActorSpec>, config: Readonly<Omit<AppConfig, 'json'>>, namespace: Readonly<Namespace>): DependencySpec;
|
|
10
|
+
//# sourceMappingURL=dependency-spec-util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-spec-util.d.ts","sourceRoot":"","sources":["../../src/esbuild/dependency-spec-util.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAK7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gDAAgD,CAAC;AAEhF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,EACzC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,GAC7B,cAAc,CAgHhB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { AppSettingsDefinition, ContextActionDefinition, CustomPostDefinition, Definition, FlairDefinition, GraphQLDefinition, HTTPDefinition, InstallationSettingsDefinition, LinksAndCommentsDefinition, ListingsDefinition, MediaServiceDefinition, ModerationDefinition, ModlogDefinition, ModNoteDefinition, NewModmailDefinition, OnAppInstallDefinition, OnAppUpgradeDefinition, OnAutomoderatorFilterCommentDefinition, OnAutomoderatorFilterPostDefinition, OnCommentCreateDefinition, OnCommentDeleteDefinition, OnCommentReportDefinition, OnCommentSubmitDefinition, OnCommentUpdateDefinition, OnModActionDefinition, OnModMailDefinition, OnPostCreateDefinition, OnPostDeleteDefinition, OnPostFlairUpdateDefinition, OnPostNsfwUpdateDefinition, OnPostReportDefinition, OnPostSpoilerUpdateDefinition, OnPostSubmitDefinition, OnPostUpdateDefinition, PrivateMessagesDefinition, RealtimeDefinition, RedisAPIDefinition, SchedulerHandlerDefinition, SettingsDefinition, SubredditsDefinition, UIEventHandlerDefinition, UserActionsDefinition, UsersDefinition, WidgetsDefinition, WikiDefinition, } from '@devvit/protos';
|
|
2
|
+
import { PaymentProcessorDefinition, PaymentsServiceDefinition } from '@devvit/protos/payments.js';
|
|
3
|
+
import { WebbitServerDefinition } from '@devvit/protos/types/devvit/actor/webbit/webbit.js';
|
|
4
|
+
import { normalizeDomains } from '@devvit/shared-types/fetch-domains.js';
|
|
5
|
+
import { PLUGIN_NAME, resolveActorHostname } from '@devvit/shared-types/HostnameUtil.js';
|
|
6
|
+
/**
|
|
7
|
+
* Convert a static `AppConfig` to a `DependencySpec`. Similar to the classic
|
|
8
|
+
* `Devvit` singleton, `ConfigImpl`, `addPaymentHandler()`, and
|
|
9
|
+
* `paymentsPlugin`.
|
|
10
|
+
*/
|
|
11
|
+
export function createDependencySpec(actorSpec, config, namespace) {
|
|
12
|
+
const spec = {
|
|
13
|
+
actor: actorSpec,
|
|
14
|
+
hostname: resolveActorHostname(actorSpec.name, namespace),
|
|
15
|
+
permissions: [],
|
|
16
|
+
provides: [],
|
|
17
|
+
uses: [],
|
|
18
|
+
};
|
|
19
|
+
const permissions = {
|
|
20
|
+
requestedFetchDomains: [],
|
|
21
|
+
asUserScopes: [],
|
|
22
|
+
};
|
|
23
|
+
if (config.permissions.http.enable) {
|
|
24
|
+
use(spec, HTTPDefinition);
|
|
25
|
+
permissions.requestedFetchDomains.push(...normalizeDomains(config.permissions.http.domains));
|
|
26
|
+
}
|
|
27
|
+
if (config.permissions.media)
|
|
28
|
+
use(spec, MediaServiceDefinition);
|
|
29
|
+
if (config.permissions.payments) {
|
|
30
|
+
use(spec, PaymentsServiceDefinition);
|
|
31
|
+
provide(spec, PaymentProcessorDefinition);
|
|
32
|
+
}
|
|
33
|
+
if (config.permissions.realtime)
|
|
34
|
+
use(spec, RealtimeDefinition);
|
|
35
|
+
if (config.permissions.reddit.enable) {
|
|
36
|
+
use(spec, FlairDefinition, GraphQLDefinition, LinksAndCommentsDefinition, ListingsDefinition, ModerationDefinition, ModNoteDefinition, NewModmailDefinition, PrivateMessagesDefinition, SubredditsDefinition, UsersDefinition, WidgetsDefinition, WikiDefinition);
|
|
37
|
+
if (config.permissions.reddit.scope === 'moderator')
|
|
38
|
+
use(spec, ModlogDefinition);
|
|
39
|
+
if (config.permissions.reddit.asUser.length > 0) {
|
|
40
|
+
use(spec, UserActionsDefinition);
|
|
41
|
+
if (config.permissions.reddit.asUser.length > 0) {
|
|
42
|
+
permissions.asUserScopes.push(...config.permissions.reddit.asUser);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (config.permissions.redis)
|
|
47
|
+
use(spec, RedisAPIDefinition);
|
|
48
|
+
if (permissions.requestedFetchDomains.length > 0 || permissions.asUserScopes.length > 0) {
|
|
49
|
+
spec.permissions.push(permissions);
|
|
50
|
+
}
|
|
51
|
+
if (config.post) {
|
|
52
|
+
provide(spec, CustomPostDefinition, UIEventHandlerDefinition);
|
|
53
|
+
}
|
|
54
|
+
if (config.server)
|
|
55
|
+
provide(spec, WebbitServerDefinition);
|
|
56
|
+
if (config.permissions.menu)
|
|
57
|
+
provide(spec, ContextActionDefinition);
|
|
58
|
+
if (config.permissions.settings) {
|
|
59
|
+
use(spec, SettingsDefinition);
|
|
60
|
+
provide(spec, AppSettingsDefinition, InstallationSettingsDefinition);
|
|
61
|
+
}
|
|
62
|
+
if (config.forms)
|
|
63
|
+
provide(spec, UIEventHandlerDefinition);
|
|
64
|
+
if (config.scheduler) {
|
|
65
|
+
provide(spec, SchedulerHandlerDefinition);
|
|
66
|
+
if (Object.values(config.scheduler.tasks).some((task) => task.cron)) {
|
|
67
|
+
provide(spec, OnAppInstallDefinition);
|
|
68
|
+
provide(spec, OnAppUpgradeDefinition);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (config.triggers) {
|
|
72
|
+
if (config.triggers.onAppInstall)
|
|
73
|
+
provide(spec, OnAppInstallDefinition);
|
|
74
|
+
if (config.triggers.onAppUpgrade)
|
|
75
|
+
provide(spec, OnAppUpgradeDefinition);
|
|
76
|
+
if (config.triggers.onAutomoderatorFilterComment)
|
|
77
|
+
provide(spec, OnAutomoderatorFilterCommentDefinition);
|
|
78
|
+
if (config.triggers.onAutomoderatorFilterPost)
|
|
79
|
+
provide(spec, OnAutomoderatorFilterPostDefinition);
|
|
80
|
+
if (config.triggers.onCommentCreate)
|
|
81
|
+
provide(spec, OnCommentCreateDefinition);
|
|
82
|
+
if (config.triggers.onCommentDelete)
|
|
83
|
+
provide(spec, OnCommentDeleteDefinition);
|
|
84
|
+
if (config.triggers.onCommentReport)
|
|
85
|
+
provide(spec, OnCommentReportDefinition);
|
|
86
|
+
if (config.triggers.onCommentSubmit)
|
|
87
|
+
provide(spec, OnCommentSubmitDefinition);
|
|
88
|
+
if (config.triggers.onCommentUpdate)
|
|
89
|
+
provide(spec, OnCommentUpdateDefinition);
|
|
90
|
+
if (config.triggers.onModAction)
|
|
91
|
+
provide(spec, OnModActionDefinition);
|
|
92
|
+
if (config.triggers.onModMail)
|
|
93
|
+
provide(spec, OnModMailDefinition);
|
|
94
|
+
if (config.triggers.onPostCreate)
|
|
95
|
+
provide(spec, OnPostCreateDefinition);
|
|
96
|
+
if (config.triggers.onPostDelete)
|
|
97
|
+
provide(spec, OnPostDeleteDefinition);
|
|
98
|
+
if (config.triggers.onPostFlairUpdate)
|
|
99
|
+
provide(spec, OnPostFlairUpdateDefinition);
|
|
100
|
+
if (config.triggers.onPostNsfwUpdate)
|
|
101
|
+
provide(spec, OnPostNsfwUpdateDefinition);
|
|
102
|
+
if (config.triggers.onPostReport)
|
|
103
|
+
provide(spec, OnPostReportDefinition);
|
|
104
|
+
if (config.triggers.onPostSpoilerUpdate)
|
|
105
|
+
provide(spec, OnPostSpoilerUpdateDefinition);
|
|
106
|
+
if (config.triggers.onPostSubmit)
|
|
107
|
+
provide(spec, OnPostSubmitDefinition);
|
|
108
|
+
if (config.triggers.onPostUpdate)
|
|
109
|
+
provide(spec, OnPostUpdateDefinition);
|
|
110
|
+
}
|
|
111
|
+
if (config.settings) {
|
|
112
|
+
use(spec, SettingsDefinition);
|
|
113
|
+
if (config.settings.global) {
|
|
114
|
+
provide(spec, AppSettingsDefinition);
|
|
115
|
+
}
|
|
116
|
+
if (config.settings.subreddit) {
|
|
117
|
+
provide(spec, InstallationSettingsDefinition);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return spec;
|
|
121
|
+
}
|
|
122
|
+
function provide(spec, ...definitions) {
|
|
123
|
+
spec.provides.push(...definitions
|
|
124
|
+
.filter((def) => !spec.provides.some((provide) => provide.definition?.fullName === def.fullName))
|
|
125
|
+
.map((def) => ({
|
|
126
|
+
actor: structuredClone(spec.actor),
|
|
127
|
+
definition: Definition.toSerializable(def),
|
|
128
|
+
partitionsBy: [],
|
|
129
|
+
})));
|
|
130
|
+
}
|
|
131
|
+
function use(spec, ...definitions) {
|
|
132
|
+
spec.uses.push(...definitions
|
|
133
|
+
.filter((def) => !spec.uses.some((use) => use.typeName === def.fullName))
|
|
134
|
+
.map((def) => ({ name: PLUGIN_NAME, typeName: def.fullName })));
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-spec-util.test.d.ts","sourceRoot":"","sources":["../../src/esbuild/dependency-spec-util.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Devvit, type FormKey } from '@devvit/public-api';
|
|
2
|
+
import type { UiResponse } from '@devvit/shared';
|
|
3
|
+
/** @internal [state] Map of devvit.json form keys to Devvit-singleton form keys. */
|
|
4
|
+
export declare const formKeyMap: {
|
|
5
|
+
[formKey: string]: FormKey;
|
|
6
|
+
};
|
|
7
|
+
/** @internal */
|
|
8
|
+
export declare function validateUiResponse(uiResponse: UiResponse): void;
|
|
9
|
+
export default Devvit;
|
|
10
|
+
//# sourceMappingURL=blocks.template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.template.d.ts","sourceRoot":"","sources":["../../../src/esbuild/templatizer/blocks.template.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,MAAM,EACN,KAAK,OAAO,EAOb,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAA8C,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAwB7F,oFAAoF;AACpF,eAAO,MAAM,UAAU,EAAE;IAAE,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;CAAO,CAAC;AAkH7D,gBAAgB;AAChB,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CA4D/D;AA4OD,eAAe,MAAM,CAAC"}
|