apphx 1.1.0 → 2.0.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/README.md +50 -182
- package/benchmarks/peer-context-worker.mjs +186 -0
- package/benchmarks/peer-context.mjs +150 -0
- package/dist/apple-types.js.map +1 -1
- package/dist/cli.js +370 -118
- package/dist/cli.js.map +1 -1
- package/dist/config.js +42 -4
- package/dist/config.js.map +1 -1
- package/dist/dependencies.js +455 -16
- package/dist/dependencies.js.map +1 -1
- package/dist/export-options.js +44 -2
- package/dist/export-options.js.map +1 -1
- package/dist/flutter.js +13 -25
- package/dist/flutter.js.map +1 -1
- package/dist/go-dependencies.js +389 -0
- package/dist/go-dependencies.js.map +1 -0
- package/dist/inbox.js +7 -8
- package/dist/inbox.js.map +1 -1
- package/dist/integrations.js +3 -3
- package/dist/isolation.js +190 -0
- package/dist/isolation.js.map +1 -0
- package/dist/macos.js +57 -0
- package/dist/macos.js.map +1 -0
- package/dist/mygo-build.js +55 -0
- package/dist/mygo-build.js.map +1 -0
- package/dist/policy.js +35 -0
- package/dist/policy.js.map +1 -0
- package/dist/preflight.js +1 -1
- package/dist/process.js +3 -3
- package/dist/project-profiles.js +163 -0
- package/dist/project-profiles.js.map +1 -0
- package/dist/proof.js +33 -0
- package/dist/proof.js.map +1 -0
- package/dist/remote.js +1 -1
- package/dist/runner.js +269 -287
- package/dist/runner.js.map +1 -1
- package/dist/scheduler.js +0 -3
- package/dist/scheduler.js.map +1 -1
- package/dist/schemas.js +156 -44
- package/dist/schemas.js.map +1 -1
- package/dist/store.js +166 -44
- package/dist/store.js.map +1 -1
- package/dist/vendor/obfuscator/dist/cli.js +72 -0
- package/dist/vendor/obfuscator/dist/cli.js.map +1 -0
- package/dist/vendor/obfuscator/dist/code.js +585 -0
- package/dist/vendor/obfuscator/dist/code.js.map +1 -0
- package/dist/vendor/obfuscator/dist/common.js +262 -0
- package/dist/vendor/obfuscator/dist/common.js.map +1 -0
- package/dist/vendor/obfuscator/dist/config.js +123 -0
- package/dist/vendor/obfuscator/dist/config.js.map +1 -0
- package/dist/vendor/obfuscator/dist/content.js +89 -0
- package/dist/vendor/obfuscator/dist/content.js.map +1 -0
- package/dist/vendor/obfuscator/dist/obfuscate.js +93 -0
- package/dist/vendor/obfuscator/dist/obfuscate.js.map +1 -0
- package/dist/vendor/obfuscator/dist/png.js +283 -0
- package/dist/vendor/obfuscator/dist/png.js.map +1 -0
- package/dist/vendor/obfuscator/dist/project.js +159 -0
- package/dist/vendor/obfuscator/dist/project.js.map +1 -0
- package/dist/vendor/obfuscator/dist/resources.js +335 -0
- package/dist/vendor/obfuscator/dist/resources.js.map +1 -0
- package/dist/vendor/obfuscator/package.json +22 -0
- package/dist/workspace.js +113 -0
- package/dist/workspace.js.map +1 -0
- package/evals/control.mjs +73 -0
- package/evals/expectations.mjs +37 -0
- package/evals/host.mjs +51 -0
- package/evals/oracle.mjs +80 -0
- package/evals/policy.mjs +268 -0
- package/examples/android-java.factory.json +18 -0
- package/examples/android-java.json +16 -0
- package/examples/existing-project.factory.json +18 -0
- package/examples/existing-project.json +17 -0
- package/examples/expo.eas.json +17 -0
- package/examples/expo.factory.json +18 -0
- package/examples/expo.json +16 -0
- package/examples/factory.json +0 -2
- package/examples/flutter.factory.json +13 -0
- package/examples/flutter.json +16 -0
- package/examples/luggage.json +5 -3
- package/examples/mygo-web.factory.json +18 -0
- package/examples/mygo-web.json +16 -0
- package/examples/mygo.factory.json +18 -0
- package/examples/mygo.json +16 -0
- package/examples/react-native.factory.json +18 -0
- package/examples/react-native.json +16 -0
- package/examples/runtime/android-java/app/build.gradle +7 -0
- package/examples/runtime/android-java/app/src/main/AndroidManifest.xml +8 -0
- package/examples/runtime/android-java/app/src/main/java/dev/apphx/runtime/MainActivity.java +44 -0
- package/examples/runtime/android-java/sdk-build.mjs +29 -0
- package/examples/runtime/android-java/settings.gradle +2 -0
- package/examples/runtime/android-ui.mjs +70 -0
- package/examples/runtime/mygo-native/go.mod +13 -0
- package/examples/runtime/mygo-native/go.sum +10 -0
- package/examples/runtime/mygo-native/main.go +173 -0
- package/examples/runtime/mygo-native/main_test.go +14 -0
- package/examples/runtime/mygo-native/mygo.json +1 -0
- package/examples/runtime/mygo-web/bun.lock +15 -0
- package/examples/runtime/mygo-web/go.mod +9 -0
- package/examples/runtime/mygo-web/go.sum +8 -0
- package/examples/runtime/mygo-web/index.html +1 -0
- package/examples/runtime/mygo-web/main.go +60 -0
- package/examples/runtime/mygo-web/mygo.config.ts +10 -0
- package/examples/runtime/mygo-web/package.json +1 -0
- package/examples/runtime/mygo-web/src/main.ts +23 -0
- package/examples/runtime/mygo-web/src/mygo.ts +14 -0
- package/examples/swift.factory.json +18 -0
- package/examples/swift.json +16 -0
- package/examples/uni-app.factory.json +18 -0
- package/examples/uni-app.json +16 -0
- package/package.json +12 -5
- package/scripts/bundle-obfuscator.mjs +19 -0
- package/scripts/runtime-smoke.mjs +209 -0
- package/skills/apphx/SKILL.md +94 -17
- package/skills/apphx/resources/google-play-research-result.json +6 -0
- package/skills/apphx/resources/local-research-result.json +6 -0
- package/skills/apphx/resources/requirement.json +5 -8
- package/skills/apphx/resources/research-result.json +5 -14
- package/skills/apphx/resources/review-result.json +1 -1
- package/dist/apple.js +0 -900
- package/dist/apple.js.map +0 -1
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { lstatSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
|
|
3
|
+
import { parseDocument } from "yaml";
|
|
4
|
+
// src/go-dependencies.ts
|
|
5
|
+
const MYGO_INPUT_CACHES = {
|
|
6
|
+
node_modules: true,
|
|
7
|
+
".mygo": true,
|
|
8
|
+
".git": true,
|
|
9
|
+
".factory-cache": true,
|
|
10
|
+
".yarn": true
|
|
11
|
+
};
|
|
12
|
+
/** Static go.mod/go.work grammar only: never evaluates Go or consults the Go environment. */
|
|
13
|
+
function parseGoManifest(text, path = "go.mod") {
|
|
14
|
+
const tokens = [];
|
|
15
|
+
const fail = (reason) => {
|
|
16
|
+
throw new Error(`Cannot prove Go manifest ${path}: ${reason}`);
|
|
17
|
+
};
|
|
18
|
+
const escapeCharacters = {
|
|
19
|
+
a: "\x07",
|
|
20
|
+
b: "\b",
|
|
21
|
+
f: "\f",
|
|
22
|
+
n: "\n",
|
|
23
|
+
r: "\r",
|
|
24
|
+
t: " ",
|
|
25
|
+
v: "\v",
|
|
26
|
+
"\\": "\\",
|
|
27
|
+
"\"": "\""
|
|
28
|
+
};
|
|
29
|
+
const utf8 = new TextDecoder("utf-8", {
|
|
30
|
+
fatal: true,
|
|
31
|
+
ignoreBOM: true
|
|
32
|
+
});
|
|
33
|
+
let offset = 0;
|
|
34
|
+
while (offset < text.length) {
|
|
35
|
+
const character = text[offset];
|
|
36
|
+
if (character === "\n") {
|
|
37
|
+
tokens.push({
|
|
38
|
+
value: "\n",
|
|
39
|
+
punctuation: true
|
|
40
|
+
});
|
|
41
|
+
offset++;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (/\s/.test(character)) {
|
|
45
|
+
offset++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (text.startsWith("//", offset)) {
|
|
49
|
+
while (offset < text.length && text[offset] !== "\n") offset++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (text.startsWith("/*", offset)) {
|
|
53
|
+
const end = text.indexOf("*/", offset + 2);
|
|
54
|
+
if (end < 0) fail("unterminated comment");
|
|
55
|
+
for (const line of text.slice(offset, end + 2).matchAll(/\n/g)) tokens.push({
|
|
56
|
+
value: line[0],
|
|
57
|
+
punctuation: true
|
|
58
|
+
});
|
|
59
|
+
offset = end + 2;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (character === "(" || character === ")") {
|
|
63
|
+
tokens.push({
|
|
64
|
+
value: character,
|
|
65
|
+
punctuation: true
|
|
66
|
+
});
|
|
67
|
+
offset++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (character === "\"" || character === "`") {
|
|
71
|
+
const quote = character;
|
|
72
|
+
offset++;
|
|
73
|
+
let value = "", closed = false;
|
|
74
|
+
const bytes = [];
|
|
75
|
+
function flushBytes() {
|
|
76
|
+
if (!bytes.length) return;
|
|
77
|
+
try {
|
|
78
|
+
value += utf8.decode(Uint8Array.from(bytes));
|
|
79
|
+
} catch {
|
|
80
|
+
fail("non-UTF-8 path escape is unsupported");
|
|
81
|
+
}
|
|
82
|
+
bytes.length = 0;
|
|
83
|
+
}
|
|
84
|
+
while (offset < text.length) {
|
|
85
|
+
const next = text[offset++];
|
|
86
|
+
if (next === quote) {
|
|
87
|
+
closed = true;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (next === "\n" || next === "\r") fail("newline in quoted token");
|
|
91
|
+
if (next !== "\\" || quote === "`") {
|
|
92
|
+
flushBytes();
|
|
93
|
+
value += next;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const escape = text[offset++] ?? fail("unterminated escape");
|
|
97
|
+
if (Object.hasOwn(escapeCharacters, escape)) {
|
|
98
|
+
flushBytes();
|
|
99
|
+
value += escapeCharacters[escape];
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const count = escape === "x" ? 2 : escape === "u" ? 4 : escape === "U" ? 8 : /[0-7]/.test(escape) ? 3 : 0;
|
|
103
|
+
if (!count) fail("unsupported string escape");
|
|
104
|
+
const octal = /[0-7]/.test(escape);
|
|
105
|
+
const digits = octal ? escape + text.slice(offset, offset + 2) : text.slice(offset, offset + count);
|
|
106
|
+
if (digits.length !== count || !(octal ? /^[0-7]+$/ : /^[\da-f]+$/i).test(digits)) fail("invalid string escape");
|
|
107
|
+
offset += octal ? 2 : count;
|
|
108
|
+
const code = Number.parseInt(digits, octal ? 8 : 16);
|
|
109
|
+
if (code > (octal || escape === "x" ? 255 : 1114111) || code >= 55296 && code <= 57343) fail("invalid string code point");
|
|
110
|
+
if (octal || escape === "x") bytes.push(code);
|
|
111
|
+
else {
|
|
112
|
+
flushBytes();
|
|
113
|
+
value += String.fromCodePoint(code);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!closed) fail("unterminated quoted token");
|
|
117
|
+
flushBytes();
|
|
118
|
+
tokens.push({ value });
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const start = offset;
|
|
122
|
+
while (offset < text.length && !/[\s()"`]/.test(text[offset]) && !text.startsWith("//", offset) && !text.startsWith("/*", offset)) offset++;
|
|
123
|
+
if (offset === start) fail("invalid token");
|
|
124
|
+
const value = text.slice(start, offset);
|
|
125
|
+
tokens.push({
|
|
126
|
+
value,
|
|
127
|
+
...value === "=>" ? { punctuation: true } : {}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const requires = /* @__PURE__ */ new Map();
|
|
131
|
+
const tools = [], uses = [], replacements = [];
|
|
132
|
+
let module;
|
|
133
|
+
const supported = {
|
|
134
|
+
module: true,
|
|
135
|
+
go: true,
|
|
136
|
+
toolchain: true,
|
|
137
|
+
godebug: true,
|
|
138
|
+
require: true,
|
|
139
|
+
exclude: true,
|
|
140
|
+
replace: true,
|
|
141
|
+
retract: true,
|
|
142
|
+
tool: true,
|
|
143
|
+
use: true,
|
|
144
|
+
ignore: true
|
|
145
|
+
};
|
|
146
|
+
const punctuation = (index, value) => tokens[index]?.punctuation && tokens[index]?.value === value;
|
|
147
|
+
function row(directive, values) {
|
|
148
|
+
if (!values.length) fail(`empty ${directive} directive`);
|
|
149
|
+
if (directive === "replace") {
|
|
150
|
+
const arrow = values.findIndex((token) => token.punctuation && token.value === "=>");
|
|
151
|
+
const before = values.slice(0, arrow), after = values.slice(arrow + 1);
|
|
152
|
+
if (arrow < 0 || before.length < 1 || before.length > 2 || after.length < 1 || after.length > 2 || [...before, ...after].some((token) => token.punctuation)) fail("invalid replace directive");
|
|
153
|
+
replacements.push({
|
|
154
|
+
module: before[0].value,
|
|
155
|
+
...before[1] ? { version: before[1].value } : {},
|
|
156
|
+
target: after[0].value,
|
|
157
|
+
...after[1] ? { targetVersion: after[1].value } : {}
|
|
158
|
+
});
|
|
159
|
+
} else {
|
|
160
|
+
if (values.some((token) => token.punctuation)) fail(`invalid ${directive} directive`);
|
|
161
|
+
if (directive === "module") {
|
|
162
|
+
if (values.length !== 1 || module !== void 0) fail("invalid module declaration");
|
|
163
|
+
module = values[0].value;
|
|
164
|
+
} else if (directive === "require") {
|
|
165
|
+
if (values.length !== 2) fail("invalid require directive");
|
|
166
|
+
requires.set(values[0].value, values[1].value);
|
|
167
|
+
} else if (directive === "use" || directive === "tool") {
|
|
168
|
+
if (values.length !== 1) fail(`invalid ${directive} directive`);
|
|
169
|
+
(directive === "use" ? uses : tools).push(values[0].value);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
let index = 0;
|
|
174
|
+
while (index < tokens.length) {
|
|
175
|
+
if (punctuation(index, "\n")) {
|
|
176
|
+
index++;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const directive = tokens[index++];
|
|
180
|
+
if (directive.punctuation || !Object.hasOwn(supported, directive.value)) fail(`unsupported directive ${directive.value}`);
|
|
181
|
+
if (punctuation(index, "(")) {
|
|
182
|
+
index++;
|
|
183
|
+
while (index < tokens.length && !punctuation(index, ")")) {
|
|
184
|
+
if (punctuation(index, "\n")) {
|
|
185
|
+
index++;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const values = [];
|
|
189
|
+
while (index < tokens.length && !punctuation(index, "\n") && !punctuation(index, ")")) values.push(tokens[index++]);
|
|
190
|
+
row(directive.value, values);
|
|
191
|
+
}
|
|
192
|
+
if (!punctuation(index, ")")) fail("unterminated directive block");
|
|
193
|
+
index++;
|
|
194
|
+
if (index < tokens.length && !punctuation(index, "\n")) fail("unexpected token after block");
|
|
195
|
+
} else {
|
|
196
|
+
const values = [];
|
|
197
|
+
while (index < tokens.length && !punctuation(index, "\n")) values.push(tokens[index++]);
|
|
198
|
+
row(directive.value, values);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
...module === void 0 ? {} : { module },
|
|
203
|
+
requires,
|
|
204
|
+
tools,
|
|
205
|
+
uses,
|
|
206
|
+
replacements
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function ownedPath(root, value, base = root, allowMissing = false) {
|
|
210
|
+
if (!value || value.includes("\0") || /[\r\n]/.test(value) || isAbsolute(value) || win32.isAbsolute(value) || /^[a-z]:/i.test(value)) throw new Error(`Go local dependency requires a workspace-relative path: ${value}`);
|
|
211
|
+
const absolute = resolve(base, value), child = relative(resolve(root), absolute);
|
|
212
|
+
if (child === ".." || child.startsWith(`..${sep}`) || isAbsolute(child)) throw new Error(`Go local dependency escapes fingerprinted workspace source: ${value}`);
|
|
213
|
+
let current = resolve(root);
|
|
214
|
+
for (const part of ["", ...child.split(sep).filter(Boolean)]) {
|
|
215
|
+
if (part) current = join(current, part);
|
|
216
|
+
const stat = lstatSync(current, { throwIfNoEntry: false });
|
|
217
|
+
if (!stat && allowMissing) break;
|
|
218
|
+
if (!stat) throw new Error(`Go local dependency does not exist: ${current}`);
|
|
219
|
+
if (stat.isSymbolicLink()) throw new Error(`Go dependency source symlinks are not trusted: ${current}`);
|
|
220
|
+
}
|
|
221
|
+
return absolute;
|
|
222
|
+
}
|
|
223
|
+
function regularFile(path) {
|
|
224
|
+
const stat = lstatSync(path, { throwIfNoEntry: false });
|
|
225
|
+
if (!stat?.isFile() || stat.isSymbolicLink()) throw new Error(`Go manifest must be a regular owned source file: ${path}`);
|
|
226
|
+
}
|
|
227
|
+
/** Absolute closest owned workspace path; callers MUST set GOWORK to this or 'off'. */
|
|
228
|
+
function closestOwnedGoWorkspace(root, directory = ".") {
|
|
229
|
+
let current = ownedPath(root, directory);
|
|
230
|
+
if (!lstatSync(current).isDirectory()) throw new Error("Go project directory must be a regular owned directory");
|
|
231
|
+
while (true) {
|
|
232
|
+
const work = join(current, "go.work");
|
|
233
|
+
if (lstatSync(work, { throwIfNoEntry: false })) {
|
|
234
|
+
regularFile(work);
|
|
235
|
+
return work;
|
|
236
|
+
}
|
|
237
|
+
if (current === resolve(root)) return void 0;
|
|
238
|
+
current = dirname(current);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** JSON is static; TS configuration remains trusted executable code, not inferred paths. */
|
|
242
|
+
function myGoConfigInputs(root, project, generated, files, local) {
|
|
243
|
+
const config = join(project, "mygo.json");
|
|
244
|
+
if (!lstatSync(config, { throwIfNoEntry: false })) return;
|
|
245
|
+
regularFile(config);
|
|
246
|
+
const portable = (path) => relative(resolve(root), path);
|
|
247
|
+
files.add(portable(config));
|
|
248
|
+
function record(value, field) {
|
|
249
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`MyGo ${field} must be a JSON object`);
|
|
250
|
+
const result = Object.create(null);
|
|
251
|
+
for (const [key, child] of Object.entries(value)) {
|
|
252
|
+
const normalized = key.toLowerCase().replace(/ſ/g, "s");
|
|
253
|
+
if (Object.hasOwn(result, normalized)) throw new Error(`MyGo ${field} has duplicate field ${key}`);
|
|
254
|
+
result[normalized] = child;
|
|
255
|
+
}
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
const text = readFileSync(config, "utf8");
|
|
259
|
+
const value = JSON.parse(text);
|
|
260
|
+
const document = parseDocument(text, { uniqueKeys: true });
|
|
261
|
+
if (document.errors.length) throw new Error(`MyGo JSON fields must be unambiguous: ${document.errors.map((error) => error.message).join("; ")}`);
|
|
262
|
+
const spec = record(value, "mygo.json");
|
|
263
|
+
function input(value, field, kind) {
|
|
264
|
+
if (typeof value !== "string" || !value || value.startsWith("~/")) throw new Error(`MyGo ${field} requires a nonempty workspace-relative path`);
|
|
265
|
+
const absolute = ownedPath(root, value, project, kind === "write" || field === "frontendDist");
|
|
266
|
+
const path = portable(absolute);
|
|
267
|
+
const projectPath = relative(project, absolute);
|
|
268
|
+
if (field === "frontendDist" && projectPath.split(sep).some((part) => Object.hasOwn(MYGO_INPUT_CACHES, part))) throw new Error(`MyGo frontendDist cannot embed dependency or development caches: ${value}`);
|
|
269
|
+
const generatedFrontend = field === "frontendDist" && (projectPath === "dist" || projectPath.startsWith(`dist${sep}`) || projectPath.startsWith(`build${sep}`)) && !/^build[\\/]darwin-(?:arm64|amd64|universal)(?:[\\/]|$)/.test(projectPath);
|
|
270
|
+
if (generated(path) && !generatedFrontend) throw new Error(`MyGo ${field} is outside fingerprinted workspace source: ${value}`);
|
|
271
|
+
const stat = lstatSync(absolute, { throwIfNoEntry: false });
|
|
272
|
+
if (generatedFrontend && !stat) return;
|
|
273
|
+
if (kind === "file" && !stat?.isFile() || kind === "directory" && !stat?.isDirectory() || (kind === "source" || kind === "resource") && !stat?.isFile() && !stat?.isDirectory() || kind === "write" && stat && !stat.isFile()) throw new Error(`MyGo ${field} requires a regular owned ${kind === "directory" ? "directory" : "file or directory"}: ${value}`);
|
|
274
|
+
function tree(current) {
|
|
275
|
+
const child = portable(current), info = lstatSync(current);
|
|
276
|
+
if (!generatedFrontend && generated(child) || relative(absolute, current).split(sep).some((part) => Object.hasOwn(MYGO_INPUT_CACHES, part))) throw new Error(`MyGo ${field} includes excluded mutable input: ${child}`);
|
|
277
|
+
if (info.isSymbolicLink()) throw new Error(`MyGo ${field} source symlinks are not trusted: ${child}`);
|
|
278
|
+
if (info.isDirectory()) for (const entry of readdirSync(current).sort()) tree(join(current, entry));
|
|
279
|
+
else if (!info.isFile()) throw new Error(`MyGo ${field} requires regular owned source: ${child}`);
|
|
280
|
+
else if (generatedFrontend) files.add(child);
|
|
281
|
+
}
|
|
282
|
+
if (kind === "resource" || field === "frontendDist") tree(absolute);
|
|
283
|
+
local.add(path);
|
|
284
|
+
}
|
|
285
|
+
function optional(spec, key, field, kind = "file") {
|
|
286
|
+
if (Object.hasOwn(spec, key)) input(spec[key], field, kind);
|
|
287
|
+
}
|
|
288
|
+
input(Object.hasOwn(spec, "main") ? spec.main : ".", "main", "source");
|
|
289
|
+
optional(spec, "icon", "icon");
|
|
290
|
+
optional(spec, "frontenddist", "frontendDist", "directory");
|
|
291
|
+
if (Object.hasOwn(spec, "resources")) {
|
|
292
|
+
if (!Array.isArray(spec.resources)) throw new Error("MyGo resources must be an array of owned paths");
|
|
293
|
+
for (const value of spec.resources) input(value, "resources", "resource");
|
|
294
|
+
}
|
|
295
|
+
if (lstatSync(join(project, "resources"), { throwIfNoEntry: false })) input("resources", "resources", "resource");
|
|
296
|
+
if (Object.hasOwn(spec, "bindings")) input(spec.bindings, "bindings", "write");
|
|
297
|
+
else if (lstatSync(join(project, "frontend"), { throwIfNoEntry: false })?.isDirectory()) input("frontend/src/mygo.ts", "bindings", "write");
|
|
298
|
+
else if (lstatSync(join(project, "package.json"), { throwIfNoEntry: false })) input("src/mygo.ts", "bindings", "write");
|
|
299
|
+
else if ([
|
|
300
|
+
"devurl",
|
|
301
|
+
"devcommand",
|
|
302
|
+
"buildcommand",
|
|
303
|
+
"frontenddist"
|
|
304
|
+
].some((key) => spec[key])) input("mygo.ts", "bindings", "write");
|
|
305
|
+
if (spec.macos !== void 0 && spec.macos !== null) {
|
|
306
|
+
const macos = record(spec.macos, "macos");
|
|
307
|
+
optional(macos, "icon", "macos.icon");
|
|
308
|
+
optional(macos, "entitlements", "macos.entitlements");
|
|
309
|
+
if (macos.helperentitlements !== void 0 && macos.helperentitlements !== null) {
|
|
310
|
+
if (typeof macos.helperentitlements !== "object" || Array.isArray(macos.helperentitlements)) throw new Error("MyGo macos.helperEntitlements must be an object");
|
|
311
|
+
for (const [helper, value] of Object.entries(macos.helperentitlements)) {
|
|
312
|
+
if (!helper || helper.includes("\0") || /[\r\n\\]/.test(helper) || isAbsolute(helper) || win32.isAbsolute(helper) || /^[a-z]:/i.test(helper) || helper.split("/").includes("..")) throw new Error(`MyGo helperEntitlements helper must stay inside bundle resources: ${helper}`);
|
|
313
|
+
input(value, "macos.helperEntitlements", "file");
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (spec.updates !== void 0 && spec.updates !== null) {
|
|
318
|
+
const updates = record(spec.updates, "updates");
|
|
319
|
+
optional(updates, "privatekey", "updates.privateKey");
|
|
320
|
+
optional(updates, "changelog", "updates.changelog");
|
|
321
|
+
if (!Object.hasOwn(updates, "changelog") && lstatSync(join(project, "CHANGELOG.md"), { throwIfNoEntry: false })) input("CHANGELOG.md", "updates.changelog", "file");
|
|
322
|
+
}
|
|
323
|
+
if (spec.windows !== void 0 && spec.windows !== null) optional(record(spec.windows, "windows"), "certificate", "windows.certificate");
|
|
324
|
+
}
|
|
325
|
+
/** Only the selected module, its owned workspace and local replacement closure are active. */
|
|
326
|
+
function goDependencyInputs(root, directory, generated) {
|
|
327
|
+
const files = /* @__PURE__ */ new Set(), local = /* @__PURE__ */ new Set(), visited = /* @__PURE__ */ new Set();
|
|
328
|
+
const project = ownedPath(root, directory);
|
|
329
|
+
const portable = (path) => relative(resolve(root), path);
|
|
330
|
+
if (generated(portable(project))) throw new Error("Go project is outside fingerprinted workspace source");
|
|
331
|
+
function source(value, base) {
|
|
332
|
+
const absolute = ownedPath(root, value, base);
|
|
333
|
+
if (generated(portable(absolute))) throw new Error(`Go local dependency is outside fingerprinted workspace source: ${value}`);
|
|
334
|
+
if (!lstatSync(absolute).isDirectory()) throw new Error(`Go local dependency must identify a regular source directory: ${value}`);
|
|
335
|
+
local.add(portable(absolute));
|
|
336
|
+
return absolute;
|
|
337
|
+
}
|
|
338
|
+
function manifest(path) {
|
|
339
|
+
regularFile(path);
|
|
340
|
+
files.add(portable(path));
|
|
341
|
+
const sum = path === join(dirname(path), "go.work") ? `${path}.sum` : join(dirname(path), "go.sum");
|
|
342
|
+
if (lstatSync(sum, { throwIfNoEntry: false })) {
|
|
343
|
+
regularFile(sum);
|
|
344
|
+
files.add(portable(sum));
|
|
345
|
+
}
|
|
346
|
+
return parseGoManifest(readFileSync(path, "utf8"), portable(path));
|
|
347
|
+
}
|
|
348
|
+
function replacements(parsed, base) {
|
|
349
|
+
for (const replacement of parsed.replacements) {
|
|
350
|
+
if (replacement.targetVersion !== void 0) {
|
|
351
|
+
if (!/^v\d/.test(replacement.targetVersion) || !replacement.target || /[\s\\:]/.test(replacement.target) || replacement.target.split("/").some((part) => !part || part === "." || part === "..") || isAbsolute(replacement.target) || win32.isAbsolute(replacement.target)) throw new Error(`Invalid versioned Go replacement: ${replacement.target}`);
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
visit(source(replacement.target, base));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function visit(moduleRoot) {
|
|
358
|
+
if (visited.has(moduleRoot)) return;
|
|
359
|
+
visited.add(moduleRoot);
|
|
360
|
+
const parsed = manifest(join(moduleRoot, "go.mod"));
|
|
361
|
+
if (!parsed.module || parsed.uses.length) throw new Error(`Invalid Go module declaration: ${moduleRoot}`);
|
|
362
|
+
const vendor = join(moduleRoot, "vendor", "modules.txt");
|
|
363
|
+
if (lstatSync(vendor, { throwIfNoEntry: false })) {
|
|
364
|
+
regularFile(vendor);
|
|
365
|
+
files.add(portable(vendor));
|
|
366
|
+
local.add(portable(join(moduleRoot, "vendor")));
|
|
367
|
+
}
|
|
368
|
+
replacements(parsed, moduleRoot);
|
|
369
|
+
}
|
|
370
|
+
visit(project);
|
|
371
|
+
const workspace = closestOwnedGoWorkspace(root, directory);
|
|
372
|
+
if (workspace) {
|
|
373
|
+
if (generated(portable(workspace))) throw new Error("Go workspace is outside fingerprinted workspace source");
|
|
374
|
+
const parsed = manifest(workspace);
|
|
375
|
+
if (parsed.module || parsed.requires.size || parsed.tools.length) throw new Error(`Invalid Go workspace declaration: ${workspace}`);
|
|
376
|
+
const modules = parsed.uses.map((value) => source(value, dirname(workspace)));
|
|
377
|
+
if (!modules.includes(project)) throw new Error("Closest owned go.work must include the selected Go module");
|
|
378
|
+
for (const moduleRoot of modules) visit(moduleRoot);
|
|
379
|
+
replacements(parsed, dirname(workspace));
|
|
380
|
+
}
|
|
381
|
+
myGoConfigInputs(root, project, generated, files, local);
|
|
382
|
+
return {
|
|
383
|
+
files,
|
|
384
|
+
local
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
export { closestOwnedGoWorkspace, goDependencyInputs, parseGoManifest };
|
|
388
|
+
|
|
389
|
+
//# sourceMappingURL=go-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"go-dependencies.js","names":[],"sources":["../src/go-dependencies.ts"],"sourcesContent":["import { lstatSync, readFileSync, readdirSync } from 'node:fs';\nimport { dirname, isAbsolute, join, relative, resolve, sep, win32 } from 'node:path';\nimport { parseDocument } from 'yaml';\n\nconst MYGO_INPUT_CACHES: Record<string, true> = { node_modules: true, '.mygo': true, '.git': true, '.factory-cache': true, '.yarn': true };\n\nexport interface GoReplacement {\n module: string;\n version?: string;\n target: string;\n targetVersion?: string;\n}\n\nexport interface GoManifest {\n module?: string;\n requires: ReadonlyMap<string, string>;\n tools: readonly string[];\n uses: readonly string[];\n replacements: readonly GoReplacement[];\n}\n\ninterface Token { value: string; punctuation?: boolean }\n\n/** Static go.mod/go.work grammar only: never evaluates Go or consults the Go environment. */\nexport function parseGoManifest(text: string, path = 'go.mod'): GoManifest {\n const tokens: Token[] = [];\n const fail = (reason: string): never => { throw new Error(`Cannot prove Go manifest ${path}: ${reason}`); };\n const escapeCharacters: Record<string, string> = { a: '\\x07', b: '\\b', f: '\\f', n: '\\n', r: '\\r', t: '\\t', v: '\\v', '\\\\': '\\\\', '\"': '\"' };\n const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });\n let offset = 0;\n while (offset < text.length) {\n const character = text[offset]!;\n if (character === '\\n') { tokens.push({ value: '\\n', punctuation: true }); offset++; continue; }\n if (/\\s/.test(character)) { offset++; continue; }\n if (text.startsWith('//', offset)) {\n while (offset < text.length && text[offset] !== '\\n') offset++;\n continue;\n }\n if (text.startsWith('/*', offset)) {\n const end = text.indexOf('*/', offset + 2);\n if (end < 0) fail('unterminated comment');\n for (const line of text.slice(offset, end + 2).matchAll(/\\n/g)) tokens.push({ value: line[0], punctuation: true });\n offset = end + 2;\n continue;\n }\n if (character === '(' || character === ')') {\n tokens.push({ value: character, punctuation: true }); offset++; continue;\n }\n if (character === '\"' || character === '`') {\n const quote = character;\n offset++;\n let value = '', closed = false;\n const bytes: number[] = [];\n function flushBytes(): void {\n if (!bytes.length) return;\n try { value += utf8.decode(Uint8Array.from(bytes)); }\n catch { fail('non-UTF-8 path escape is unsupported'); }\n bytes.length = 0;\n }\n while (offset < text.length) {\n const next = text[offset++]!;\n if (next === quote) { closed = true; break; }\n if (next === '\\n' || next === '\\r') fail('newline in quoted token');\n if (next !== '\\\\' || quote === '`') { flushBytes(); value += next; continue; }\n const escape = text[offset++] ?? fail('unterminated escape');\n if (Object.hasOwn(escapeCharacters, escape)) { flushBytes(); value += escapeCharacters[escape]; continue; }\n const count = escape === 'x' ? 2 : escape === 'u' ? 4 : escape === 'U' ? 8 : /[0-7]/.test(escape) ? 3 : 0;\n if (!count) fail('unsupported string escape');\n const octal = /[0-7]/.test(escape);\n const digits = octal ? escape + text.slice(offset, offset + 2) : text.slice(offset, offset + count);\n if (digits.length !== count || !(octal ? /^[0-7]+$/ : /^[\\da-f]+$/i).test(digits)) fail('invalid string escape');\n offset += octal ? 2 : count;\n const code = Number.parseInt(digits, octal ? 8 : 16);\n if (code > (octal || escape === 'x' ? 255 : 0x10ffff) || (code >= 0xd800 && code <= 0xdfff)) fail('invalid string code point');\n if (octal || escape === 'x') bytes.push(code);\n else { flushBytes(); value += String.fromCodePoint(code); }\n }\n if (!closed) fail('unterminated quoted token');\n flushBytes();\n tokens.push({ value });\n continue;\n }\n const start = offset;\n while (offset < text.length && !/[\\s()\"`]/.test(text[offset]!) && !text.startsWith('//', offset) && !text.startsWith('/*', offset)) offset++;\n if (offset === start) fail('invalid token');\n const value = text.slice(start, offset);\n tokens.push({ value, ...(value === '=>' ? { punctuation: true } : {}) });\n }\n const requires = new Map<string, string>();\n const tools: string[] = [], uses: string[] = [], replacements: GoReplacement[] = [];\n let module: string | undefined;\n const supported: Record<string, true> = { module: true, go: true, toolchain: true, godebug: true, require: true, exclude: true, replace: true, retract: true, tool: true, use: true, ignore: true };\n const punctuation = (index: number, value: string) => tokens[index]?.punctuation && tokens[index]?.value === value;\n function row(directive: string, values: Token[]): void {\n if (!values.length) fail(`empty ${directive} directive`);\n if (directive === 'replace') {\n const arrow = values.findIndex(token => token.punctuation && token.value === '=>');\n const before = values.slice(0, arrow), after = values.slice(arrow + 1);\n if (arrow < 0 || before.length < 1 || before.length > 2 || after.length < 1 || after.length > 2 || [...before, ...after].some(token => token.punctuation)) fail('invalid replace directive');\n replacements.push({ module: before[0]!.value, ...(before[1] ? { version: before[1].value } : {}), target: after[0]!.value, ...(after[1] ? { targetVersion: after[1].value } : {}) });\n } else {\n if (values.some(token => token.punctuation)) fail(`invalid ${directive} directive`);\n if (directive === 'module') {\n if (values.length !== 1 || module !== undefined) fail('invalid module declaration');\n module = values[0]!.value;\n } else if (directive === 'require') {\n if (values.length !== 2) fail('invalid require directive');\n requires.set(values[0]!.value, values[1]!.value);\n } else if (directive === 'use' || directive === 'tool') {\n if (values.length !== 1) fail(`invalid ${directive} directive`);\n (directive === 'use' ? uses : tools).push(values[0]!.value);\n }\n }\n }\n let index = 0;\n while (index < tokens.length) {\n if (punctuation(index, '\\n')) { index++; continue; }\n const directive = tokens[index++]!;\n if (directive.punctuation || !Object.hasOwn(supported, directive.value)) fail(`unsupported directive ${directive.value}`);\n if (punctuation(index, '(')) {\n index++;\n while (index < tokens.length && !punctuation(index, ')')) {\n if (punctuation(index, '\\n')) { index++; continue; }\n const values: Token[] = [];\n while (index < tokens.length && !punctuation(index, '\\n') && !punctuation(index, ')')) values.push(tokens[index++]!);\n row(directive.value, values);\n }\n if (!punctuation(index, ')')) fail('unterminated directive block');\n index++;\n if (index < tokens.length && !punctuation(index, '\\n')) fail('unexpected token after block');\n } else {\n const values: Token[] = [];\n while (index < tokens.length && !punctuation(index, '\\n')) values.push(tokens[index++]!);\n row(directive.value, values);\n }\n }\n return { ...(module === undefined ? {} : { module }), requires, tools, uses, replacements };\n}\n\nfunction ownedPath(root: string, value: string, base = root, allowMissing = false): string {\n if (!value || value.includes('\\0') || /[\\r\\n]/.test(value) || isAbsolute(value) || win32.isAbsolute(value) || /^[a-z]:/i.test(value)) throw new Error(`Go local dependency requires a workspace-relative path: ${value}`);\n const absolute = resolve(base, value), child = relative(resolve(root), absolute);\n if (child === '..' || child.startsWith(`..${sep}`) || isAbsolute(child)) throw new Error(`Go local dependency escapes fingerprinted workspace source: ${value}`);\n let current = resolve(root);\n for (const part of ['', ...child.split(sep).filter(Boolean)]) {\n if (part) current = join(current, part);\n const stat = lstatSync(current, { throwIfNoEntry: false });\n if (!stat && allowMissing) break;\n if (!stat) throw new Error(`Go local dependency does not exist: ${current}`);\n if (stat.isSymbolicLink()) throw new Error(`Go dependency source symlinks are not trusted: ${current}`);\n }\n return absolute;\n}\n\nfunction regularFile(path: string): void {\n const stat = lstatSync(path, { throwIfNoEntry: false });\n if (!stat?.isFile() || stat.isSymbolicLink()) throw new Error(`Go manifest must be a regular owned source file: ${path}`);\n}\n\n/** Absolute closest owned workspace path; callers MUST set GOWORK to this or 'off'. */\nexport function closestOwnedGoWorkspace(root: string, directory = '.'): string | undefined {\n let current = ownedPath(root, directory);\n if (!lstatSync(current).isDirectory()) throw new Error('Go project directory must be a regular owned directory');\n while (true) {\n const work = join(current, 'go.work');\n if (lstatSync(work, { throwIfNoEntry: false })) { regularFile(work); return work; }\n if (current === resolve(root)) return undefined;\n current = dirname(current);\n }\n}\n\nexport interface GoDependencyInputs {\n files: ReadonlySet<string>;\n local: ReadonlySet<string>;\n}\n\n/** JSON is static; TS configuration remains trusted executable code, not inferred paths. */\nfunction myGoConfigInputs(root: string, project: string, generated: (path: string) => boolean, files: Set<string>, local: Set<string>): void {\n const config = join(project, 'mygo.json');\n if (!lstatSync(config, { throwIfNoEntry: false })) return;\n regularFile(config);\n const portable = (path: string) => relative(resolve(root), path);\n files.add(portable(config));\n // encoding/json matches Go field names case-insensitively. Do not let aliases\n // evade the ownership check, or ambiguous duplicates choose a different input.\n function record(value: unknown, field: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`MyGo ${field} must be a JSON object`);\n const result: Record<string, unknown> = Object.create(null);\n for (const [key, child] of Object.entries(value)) {\n const normalized = key.toLowerCase().replace(/ſ/g, 's');\n if (Object.hasOwn(result, normalized)) throw new Error(`MyGo ${field} has duplicate field ${key}`);\n result[normalized] = child;\n }\n return result;\n }\n const text = readFileSync(config, 'utf8');\n const value: unknown = JSON.parse(text);\n const document = parseDocument(text, { uniqueKeys: true });\n if (document.errors.length) throw new Error(`MyGo JSON fields must be unambiguous: ${document.errors.map(error => error.message).join('; ')}`);\n const spec = record(value, 'mygo.json');\n function input(value: unknown, field: string, kind: 'file' | 'directory' | 'source' | 'resource' | 'write'): void {\n if (typeof value !== 'string' || !value || value.startsWith('~/')) throw new Error(`MyGo ${field} requires a nonempty workspace-relative path`);\n const absolute = ownedPath(root, value, project, kind === 'write' || field === 'frontendDist');\n const path = portable(absolute);\n const projectPath = relative(project, absolute);\n if (field === 'frontendDist' && projectPath.split(sep).some(part => Object.hasOwn(MYGO_INPUT_CACHES, part))) throw new Error(`MyGo frontendDist cannot embed dependency or development caches: ${value}`);\n const generatedFrontend = field === 'frontendDist' && (projectPath === 'dist' || projectPath.startsWith(`dist${sep}`) || projectPath.startsWith(`build${sep}`)) && !/^build[\\\\/]darwin-(?:arm64|amd64|universal)(?:[\\\\/]|$)/.test(projectPath);\n if (generated(path) && !generatedFrontend) throw new Error(`MyGo ${field} is outside fingerprinted workspace source: ${value}`);\n const stat = lstatSync(absolute, { throwIfNoEntry: false });\n if (generatedFrontend && !stat) return; // Import snapshots rebuild this output before verification.\n if ((kind === 'file' && !stat?.isFile()) || (kind === 'directory' && !stat?.isDirectory()) || ((kind === 'source' || kind === 'resource') && !stat?.isFile() && !stat?.isDirectory()) || (kind === 'write' && stat && !stat.isFile())) throw new Error(`MyGo ${field} requires a regular owned ${kind === 'directory' ? 'directory' : 'file or directory'}: ${value}`);\n // Resource and frontend trees are copied/embedded whole by MyGo, unlike\n // source traversal: even an excluded child would otherwise reach the app.\n function tree(current: string): void {\n const child = portable(current), info = lstatSync(current);\n if ((!generatedFrontend && generated(child)) || relative(absolute, current).split(sep).some(part => Object.hasOwn(MYGO_INPUT_CACHES, part))) throw new Error(`MyGo ${field} includes excluded mutable input: ${child}`);\n if (info.isSymbolicLink()) throw new Error(`MyGo ${field} source symlinks are not trusted: ${child}`);\n if (info.isDirectory()) {\n for (const entry of readdirSync(current).sort()) tree(join(current, entry));\n } else if (!info.isFile()) throw new Error(`MyGo ${field} requires regular owned source: ${child}`);\n else if (generatedFrontend) files.add(child);\n }\n if (kind === 'resource' || field === 'frontendDist') tree(absolute);\n local.add(path);\n }\n function optional(spec: Record<string, unknown>, key: string, field: string, kind: 'file' | 'directory' | 'source' | 'resource' | 'write' = 'file'): void {\n if (Object.hasOwn(spec, key)) input(spec[key], field, kind);\n }\n input(Object.hasOwn(spec, 'main') ? spec.main : '.', 'main', 'source');\n optional(spec, 'icon', 'icon');\n optional(spec, 'frontenddist', 'frontendDist', 'directory');\n if (Object.hasOwn(spec, 'resources')) {\n if (!Array.isArray(spec.resources)) throw new Error('MyGo resources must be an array of owned paths');\n for (const value of spec.resources) input(value, 'resources', 'resource');\n }\n // The resources directory (including platform resources and default icon)\n // ships implicitly even when no resources field appears in the JSON.\n if (lstatSync(join(project, 'resources'), { throwIfNoEntry: false })) input('resources', 'resources', 'resource');\n if (Object.hasOwn(spec, 'bindings')) input(spec.bindings, 'bindings', 'write');\n else if (lstatSync(join(project, 'frontend'), { throwIfNoEntry: false })?.isDirectory()) input('frontend/src/mygo.ts', 'bindings', 'write');\n else if (lstatSync(join(project, 'package.json'), { throwIfNoEntry: false })) input('src/mygo.ts', 'bindings', 'write');\n else if (['devurl', 'devcommand', 'buildcommand', 'frontenddist'].some(key => spec[key])) input('mygo.ts', 'bindings', 'write');\n if (spec.macos !== undefined && spec.macos !== null) {\n const macos = record(spec.macos, 'macos');\n optional(macos, 'icon', 'macos.icon');\n optional(macos, 'entitlements', 'macos.entitlements');\n if (macos.helperentitlements !== undefined && macos.helperentitlements !== null) {\n // Helper keys name paths inside the assembled resources, not project files.\n if (typeof macos.helperentitlements !== 'object' || Array.isArray(macos.helperentitlements)) throw new Error('MyGo macos.helperEntitlements must be an object');\n for (const [helper, value] of Object.entries(macos.helperentitlements as Record<string, unknown>)) {\n if (!helper || helper.includes('\\0') || /[\\r\\n\\\\]/.test(helper) || isAbsolute(helper) || win32.isAbsolute(helper) || /^[a-z]:/i.test(helper) || helper.split('/').includes('..')) throw new Error(`MyGo helperEntitlements helper must stay inside bundle resources: ${helper}`);\n input(value, 'macos.helperEntitlements', 'file');\n }\n }\n }\n if (spec.updates !== undefined && spec.updates !== null) {\n const updates = record(spec.updates, 'updates');\n optional(updates, 'privatekey', 'updates.privateKey');\n optional(updates, 'changelog', 'updates.changelog');\n if (!Object.hasOwn(updates, 'changelog') && lstatSync(join(project, 'CHANGELOG.md'), { throwIfNoEntry: false })) input('CHANGELOG.md', 'updates.changelog', 'file');\n }\n if (spec.windows !== undefined && spec.windows !== null) optional(record(spec.windows, 'windows'), 'certificate', 'windows.certificate');\n}\n\n/** Only the selected module, its owned workspace and local replacement closure are active. */\nexport function goDependencyInputs(root: string, directory: string, generated: (path: string) => boolean): GoDependencyInputs {\n const files = new Set<string>(), local = new Set<string>(), visited = new Set<string>();\n const project = ownedPath(root, directory);\n const portable = (path: string) => relative(resolve(root), path);\n if (generated(portable(project))) throw new Error('Go project is outside fingerprinted workspace source');\n function source(value: string, base: string): string {\n const absolute = ownedPath(root, value, base);\n if (generated(portable(absolute))) throw new Error(`Go local dependency is outside fingerprinted workspace source: ${value}`);\n if (!lstatSync(absolute).isDirectory()) throw new Error(`Go local dependency must identify a regular source directory: ${value}`);\n local.add(portable(absolute));\n return absolute;\n }\n function manifest(path: string): GoManifest {\n regularFile(path);\n files.add(portable(path));\n const sum = path === join(dirname(path), 'go.work') ? `${path}.sum` : join(dirname(path), 'go.sum');\n if (lstatSync(sum, { throwIfNoEntry: false })) { regularFile(sum); files.add(portable(sum)); }\n return parseGoManifest(readFileSync(path, 'utf8'), portable(path));\n }\n function replacements(parsed: GoManifest, base: string): void {\n for (const replacement of parsed.replacements) {\n if (replacement.targetVersion !== undefined) {\n // A versioned RHS is remote only when it is a module path, never a local path.\n if (!/^v\\d/.test(replacement.targetVersion) || !replacement.target || /[\\s\\\\:]/.test(replacement.target) || replacement.target.split('/').some(part => !part || part === '.' || part === '..') || isAbsolute(replacement.target) || win32.isAbsolute(replacement.target)) throw new Error(`Invalid versioned Go replacement: ${replacement.target}`);\n continue;\n }\n const target = source(replacement.target, base);\n visit(target);\n }\n }\n function visit(moduleRoot: string): void {\n if (visited.has(moduleRoot)) return;\n visited.add(moduleRoot);\n const parsed = manifest(join(moduleRoot, 'go.mod'));\n if (!parsed.module || parsed.uses.length) throw new Error(`Invalid Go module declaration: ${moduleRoot}`);\n const vendor = join(moduleRoot, 'vendor', 'modules.txt');\n if (lstatSync(vendor, { throwIfNoEntry: false })) { regularFile(vendor); files.add(portable(vendor)); local.add(portable(join(moduleRoot, 'vendor'))); }\n replacements(parsed, moduleRoot);\n }\n visit(project);\n const workspace = closestOwnedGoWorkspace(root, directory);\n if (workspace) {\n if (generated(portable(workspace))) throw new Error('Go workspace is outside fingerprinted workspace source');\n const parsed = manifest(workspace);\n if (parsed.module || parsed.requires.size || parsed.tools.length) throw new Error(`Invalid Go workspace declaration: ${workspace}`);\n const modules = parsed.uses.map(value => source(value, dirname(workspace)));\n if (!modules.includes(project)) throw new Error('Closest owned go.work must include the selected Go module');\n for (const moduleRoot of modules) visit(moduleRoot);\n replacements(parsed, dirname(workspace));\n }\n myGoConfigInputs(root, project, generated, files, local);\n return { files, local };\n}\n"],"mappings":"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"}
|
package/dist/inbox.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { toError } from "./schemas.js";
|
|
2
|
-
import { validateAppleSpec } from "./apple.js";
|
|
1
|
+
import { toError, validateJobConfig } from "./schemas.js";
|
|
3
2
|
import { MAX_INPUT_BYTES, parseRequirement, readInputFile } from "./requirements.js";
|
|
4
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
5
|
-
import { join, resolve } from "node:path";
|
|
6
3
|
import { closeSync, fsyncSync, linkSync, mkdirSync, openSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
7
6
|
import { setImmediate } from "node:timers/promises";
|
|
8
7
|
// src/inbox.ts
|
|
9
8
|
function canonical(value) {
|
|
@@ -23,7 +22,7 @@ function requestValue({ spec, baseJobId }) {
|
|
|
23
22
|
function submitRequirement(config, value) {
|
|
24
23
|
if (!config.inbox) throw new Error("No inbox is configured; set inbox.directory before submitting a requirement");
|
|
25
24
|
const request = parseRequirement(value);
|
|
26
|
-
|
|
25
|
+
validateJobConfig(request.spec, config);
|
|
27
26
|
const serialized = canonical(requestValue(request));
|
|
28
27
|
const content = `${serialized}\n`;
|
|
29
28
|
if (Buffer.byteLength(content) > 1048576) throw new Error(`Requirement exceeds ${MAX_INPUT_BYTES} bytes; reduce its size`);
|
|
@@ -32,9 +31,9 @@ function submitRequirement(config, value) {
|
|
|
32
31
|
recursive: true,
|
|
33
32
|
mode: 448
|
|
34
33
|
});
|
|
35
|
-
const version = request.spec
|
|
34
|
+
const { platform, channel, version } = request.spec;
|
|
36
35
|
const versionKey = createHash("sha256").update(version).digest("hex");
|
|
37
|
-
const path = join(directory, `${request.spec.id}-${versionKey}.json`);
|
|
36
|
+
const path = join(directory, `${request.spec.id}-${platform}-${channel}-${versionKey}.json`);
|
|
38
37
|
const temporary = join(directory, `.requirement-${randomUUID()}.tmp`);
|
|
39
38
|
const fd = openSync(temporary, "wx", 384);
|
|
40
39
|
try {
|
|
@@ -85,7 +84,7 @@ async function scanInbox(store, config, options = {}) {
|
|
|
85
84
|
const bytes = readInputFile(source);
|
|
86
85
|
digest = createHash("sha256").update(bytes).digest("hex");
|
|
87
86
|
const request = parseRequirement(JSON.parse(bytes.toString("utf8")));
|
|
88
|
-
|
|
87
|
+
validateJobConfig(request.spec, config);
|
|
89
88
|
const old = previous.get(source);
|
|
90
89
|
if (!observed && old?.status === "accepted" && old.digest === digest && old.jobId && store.get(old.jobId).requestSpec !== null) {
|
|
91
90
|
store.checkIngest(request.spec, request.baseJobId);
|
package/dist/inbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbox.js","names":["yieldTurn"],"sources":["../src/inbox.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { closeSync, fsyncSync, linkSync, mkdirSync, openSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { setImmediate as yieldTurn } from 'node:timers/promises';\nimport {
|
|
1
|
+
{"version":3,"file":"inbox.js","names":["yieldTurn"],"sources":["../src/inbox.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { closeSync, fsyncSync, linkSync, mkdirSync, openSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { setImmediate as yieldTurn } from 'node:timers/promises';\nimport { toError, validateJobConfig, type Config, type InboxEntry } from './schemas.js';\nimport { MAX_INPUT_BYTES, parseRequirement, readInputFile, type Requirement } from './requirements.js';\nimport type { Store } from './store.js';\n\nexport type InboxScan = { entries: InboxEntry[]; error: string | null; observed: boolean };\n\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;\n if (value !== null && typeof value === 'object') {\n const object = value as Record<string, unknown>;\n return `{${Object.keys(object).filter(key => object[key] !== undefined).sort().map(key => `${JSON.stringify(key)}:${canonical(object[key])}`).join(',')}}`;\n }\n return JSON.stringify(value) ?? 'null';\n}\n\nfunction requestValue({ spec, baseJobId }: Requirement): unknown {\n return { ...spec, ...(baseJobId === undefined ? {} : { baseJobId }) };\n}\n\n\nexport function submitRequirement(config: Config, value: unknown): { path: string } {\n if (!config.inbox) throw new Error('No inbox is configured; set inbox.directory before submitting a requirement');\n const request = parseRequirement(value);\n validateJobConfig(request.spec, config);\n const serialized = canonical(requestValue(request));\n const content = `${serialized}\\n`;\n if (Buffer.byteLength(content) > MAX_INPUT_BYTES) throw new Error(`Requirement exceeds ${MAX_INPUT_BYTES} bytes; reduce its size`);\n const directory = resolve(config.inbox.directory);\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n const { platform, channel, version } = request.spec;\n const versionKey = createHash('sha256').update(version).digest('hex');\n const path = join(directory, `${request.spec.id}-${platform}-${channel}-${versionKey}.json`);\n const temporary = join(directory, `.requirement-${randomUUID()}.tmp`);\n const fd = openSync(temporary, 'wx', 0o600);\n try {\n try {\n writeFileSync(fd, content);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n try {\n // A hard link publishes complete bytes atomically without replacing another writer's request.\n linkSync(temporary, path);\n } catch (error) {\n if (toError(error).code !== 'EEXIST') throw error;\n const existing = parseRequirement(JSON.parse(readInputFile(path).toString('utf8')) as unknown);\n if (canonical(requestValue(existing)) !== serialized) {\n throw new Error(`Requirement ${request.spec.id} ${version} already exists at ${path} with different content; use a new product version`);\n }\n }\n return { path };\n } finally {\n unlinkSync(temporary);\n }\n}\n\nexport async function scanInbox(store: Store, config: Config, options: { observe?: boolean; signal?: AbortSignal } = {}): Promise<InboxScan> {\n const observed = options.observe === true;\n if (!config.inbox) return { entries: [], error: null, observed };\n const directory = resolve(config.inbox.directory);\n let names: string[];\n try {\n names = readdirSync(directory).filter(name => name.endsWith('.json')).sort();\n } catch (error) {\n return { entries: [], error: `Cannot read inbox ${directory}: ${toError(error).message}`, observed };\n }\n const previous = new Map(store.inboxEntries().map(entry => [entry.source, entry]));\n const entries: InboxEntry[] = [];\n const pending: Requirement[] = [];\n for (const name of names) {\n await yieldTurn();\n if (options.signal?.aborted) break;\n const source = join(directory, name);\n let digest: string | null = null;\n try {\n const bytes = readInputFile(source);\n digest = createHash('sha256').update(bytes).digest('hex');\n const request = parseRequirement(JSON.parse(bytes.toString('utf8')) as unknown);\n validateJobConfig(request.spec, config);\n const old = previous.get(source);\n if (!observed && old?.status === 'accepted' && old.digest === digest && old.jobId && store.get(old.jobId).requestSpec !== null) {\n store.checkIngest(request.spec, request.baseJobId);\n entries.push(old);\n } else if (observed) {\n const existing = store.checkIngest(request.spec, request.baseJobId, pending);\n entries.push({ source, digest, status: 'accepted', jobId: existing?.id ?? null, error: null, observedAt: Date.now() });\n pending.push(request);\n } else {\n entries.push(store.ingest(source, digest, request.spec, config, request.baseJobId));\n }\n } catch (error) {\n const message = `Cannot accept requirement ${source}: ${toError(error).message}`;\n const old = previous.get(source);\n if (observed) {\n entries.push({ source, digest, status: 'error', jobId: null, error: message, observedAt: Date.now() });\n } else if (old?.status === 'error' && old.digest === digest && old.error === message) {\n entries.push(old);\n } else {\n entries.push(store.inboxError(source, digest, message));\n }\n }\n }\n return { entries, error: null, observed };\n}\n"],"mappings":"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"}
|
package/dist/integrations.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { dirname, isAbsolute, join, parse, resolve, sep } from "node:path";
|
|
5
2
|
import { closeSync, constants, fstatSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, join, parse, resolve, sep } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
6
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
7
|
// src/integrations.ts
|
|
8
8
|
const skill = "apphx";
|
|
9
9
|
const marker = ".apphx-install.json";
|