@treeseed/sdk 0.5.0 → 0.5.2
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.
|
@@ -500,9 +500,9 @@ function parseDeployConfig(raw) {
|
|
|
500
500
|
buildOutputDir: optionalString(cloudflarePages.buildOutputDir)
|
|
501
501
|
},
|
|
502
502
|
r2: cloudflare.r2 === void 0 ? void 0 : {
|
|
503
|
-
binding: optionalString(process.env.TREESEED_CONTENT_BUCKET_BINDING),
|
|
504
|
-
bucketName: optionalString(process.env.TREESEED_CONTENT_BUCKET_NAME),
|
|
505
|
-
publicBaseUrl: optionalString(process.env.TREESEED_CONTENT_PUBLIC_BASE_URL),
|
|
503
|
+
binding: optionalString(process.env.TREESEED_CONTENT_BUCKET_BINDING) ?? optionalString(cloudflareR2.binding),
|
|
504
|
+
bucketName: optionalString(process.env.TREESEED_CONTENT_BUCKET_NAME) ?? optionalString(cloudflareR2.bucketName),
|
|
505
|
+
publicBaseUrl: optionalString(process.env.TREESEED_CONTENT_PUBLIC_BASE_URL) ?? optionalString(cloudflareR2.publicBaseUrl),
|
|
506
506
|
manifestKeyTemplate: optionalString(cloudflareR2.manifestKeyTemplate) ?? "teams/{teamId}/published/common.json",
|
|
507
507
|
previewRootTemplate: optionalString(cloudflareR2.previewRootTemplate) ?? "teams/{teamId}/previews",
|
|
508
508
|
previewTtlHours: optionalPositiveNumber(cloudflareR2.previewTtlHours, "cloudflare.r2.previewTtlHours") ?? 168
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdtempSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
2
|
import { basename, extname, join, resolve } from 'node:path';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { packageRoot } from './package-tools.js';
|
|
6
|
-
const npmCacheDir =
|
|
6
|
+
const npmCacheDir = mkdtempSync(join(tmpdir(), 'treeseed-sdk-npm-cache-'));
|
|
7
7
|
const textExtensions = new Set(['.js', '.ts', '.mjs', '.cjs', '.d.js', '.json', '.md']);
|
|
8
8
|
const forbiddenPatterns = [
|
|
9
9
|
/['"`]workspace:[^'"`\n]+['"`]/,
|
|
10
10
|
/['"`](?:\.\.\/|\.\/)[^'"`\n]*src\/[^'"`\n]*\.(?:[cm]?js|ts|tsx|json|astro|css)['"`]/,
|
|
11
11
|
/['"`][^'"`\n]*\/packages\/[^'"`\n]*\/src\/[^'"`\n]*['"`]/,
|
|
12
12
|
];
|
|
13
|
-
function run(command, args) {
|
|
13
|
+
function run(command, args, cwd = packageRoot) {
|
|
14
14
|
const result = spawnSync(command, args, {
|
|
15
|
-
cwd
|
|
15
|
+
cwd,
|
|
16
16
|
stdio: 'inherit',
|
|
17
17
|
env: {
|
|
18
18
|
...process.env,
|
|
@@ -24,6 +24,32 @@ function run(command, args) {
|
|
|
24
24
|
process.exit(result.status ?? 1);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
function assertNoLocalDependencyLinks() {
|
|
28
|
+
const packageJson = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf8'));
|
|
29
|
+
for (const sectionName of ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) {
|
|
30
|
+
for (const [dependencyName, version] of Object.entries(packageJson[sectionName] ?? {})) {
|
|
31
|
+
if (version.startsWith('workspace:') || version.startsWith('file:')) {
|
|
32
|
+
throw new Error(`package.json ${sectionName}.${dependencyName} must not use local dependency specifiers: ${version}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const lockfile = JSON.parse(readFileSync(resolve(packageRoot, 'package-lock.json'), 'utf8'));
|
|
37
|
+
for (const [entryKey, entryValue] of Object.entries(lockfile.packages ?? {})) {
|
|
38
|
+
if (entryKey.startsWith('../') || entryKey.includes('/../')) {
|
|
39
|
+
throw new Error(`package-lock.json contains forbidden local package entry: ${entryKey}`);
|
|
40
|
+
}
|
|
41
|
+
if (entryValue.link) {
|
|
42
|
+
throw new Error(`package-lock.json contains forbidden linked dependency entry: ${entryKey}`);
|
|
43
|
+
}
|
|
44
|
+
const resolved = entryValue.resolved ?? '';
|
|
45
|
+
if (resolved.startsWith('../')
|
|
46
|
+
|| resolved.startsWith('./')
|
|
47
|
+
|| resolved.startsWith('file:')
|
|
48
|
+
|| resolved.startsWith('workspace:')) {
|
|
49
|
+
throw new Error(`package-lock.json contains forbidden local resolution for ${entryKey}: ${resolved}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
27
53
|
function walkFiles(root) {
|
|
28
54
|
const files = [];
|
|
29
55
|
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
@@ -71,6 +97,7 @@ function assertCleanDistArtifacts() {
|
|
|
71
97
|
}
|
|
72
98
|
}
|
|
73
99
|
}
|
|
100
|
+
assertNoLocalDependencyLinks();
|
|
74
101
|
run('npm', ['run', 'lint']);
|
|
75
102
|
scanDirectory(resolve(packageRoot, 'dist'));
|
|
76
103
|
assertCleanDistArtifacts();
|
|
@@ -10,8 +10,12 @@ const packageRoot = resolve(scriptRoot, '..');
|
|
|
10
10
|
const sourceRunner = resolve(packageRoot, 'scripts', 'run-ts.mjs');
|
|
11
11
|
const sourceEntry = resolve(packageRoot, 'src', 'verification.ts');
|
|
12
12
|
const publishedEntry = resolve(packageRoot, 'dist', 'verification.js');
|
|
13
|
+
const entrypointCheckOnly = process.env.TREESEED_VERIFY_ENTRYPOINT_CHECK === 'true';
|
|
13
14
|
|
|
14
15
|
if (existsSync(sourceRunner) && existsSync(sourceEntry)) {
|
|
16
|
+
if (entrypointCheckOnly) {
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
15
19
|
const result = spawnSync(process.execPath, [sourceRunner, sourceEntry], {
|
|
16
20
|
cwd: process.cwd(),
|
|
17
21
|
env: process.env,
|
|
@@ -21,6 +25,9 @@ if (existsSync(sourceRunner) && existsSync(sourceEntry)) {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
if (existsSync(publishedEntry)) {
|
|
28
|
+
if (entrypointCheckOnly) {
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
24
31
|
const { runTreeseedVerifyDriver } = await import('../dist/verification.js');
|
|
25
32
|
process.exit(runTreeseedVerifyDriver({ packageRoot: process.cwd() }));
|
|
26
33
|
}
|
package/dist/verification.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdtempSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import * as childProcess from "node:child_process";
|
|
3
|
-
import { basename, resolve } from "node:path";
|
|
3
|
+
import { basename, relative, resolve } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
function defaultWrite(message, stream = "stdout") {
|
|
6
7
|
if (!message) return;
|
|
@@ -38,6 +39,84 @@ function readPackageManifest(packageJsonPath) {
|
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
function createWorkspaceActWorkflow(options) {
|
|
43
|
+
const relativePackageRoot = relative(options.workspaceRoot, options.packageRoot).replace(/\\/g, "/");
|
|
44
|
+
const siblingPreparationCommands = options.localTreeseedSiblingDependencies.map((packageName) => {
|
|
45
|
+
const packageDir = `packages/${packageName.split("/")[1]}`;
|
|
46
|
+
const manifest = readPackageManifest(resolve(options.workspaceRoot, packageDir, "package.json"));
|
|
47
|
+
if (!manifest) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const commands = [
|
|
51
|
+
`if test -f ${packageDir}/package-lock.json; then`,
|
|
52
|
+
` npm --prefix ${packageDir} ci`,
|
|
53
|
+
"else",
|
|
54
|
+
` npm --prefix ${packageDir} install --no-audit --no-fund`,
|
|
55
|
+
"fi"
|
|
56
|
+
];
|
|
57
|
+
if (manifest.scripts?.["build:dist"]) {
|
|
58
|
+
commands.push(`npm --prefix ${packageDir} run build:dist`);
|
|
59
|
+
}
|
|
60
|
+
return commands.join("\n");
|
|
61
|
+
}).filter((command) => Boolean(command)).join("\n");
|
|
62
|
+
const workflowRoot = mkdtempSync(resolve(tmpdir(), "treeseed-verify-act-"));
|
|
63
|
+
const workflowPath = resolve(workflowRoot, "verify.yml");
|
|
64
|
+
writeFileSync(
|
|
65
|
+
workflowPath,
|
|
66
|
+
`name: Treeseed Local Verify
|
|
67
|
+
|
|
68
|
+
on:
|
|
69
|
+
workflow_dispatch:
|
|
70
|
+
|
|
71
|
+
jobs:
|
|
72
|
+
verify:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
defaults:
|
|
75
|
+
run:
|
|
76
|
+
working-directory: ${relativePackageRoot}
|
|
77
|
+
env:
|
|
78
|
+
CI: "true"
|
|
79
|
+
TREESEED_GITHUB_AUTOMATION_MODE: stub
|
|
80
|
+
TREESEED_STAGE_WAIT_MODE: skip
|
|
81
|
+
TREESEED_AGENT_DISABLE_GIT: "true"
|
|
82
|
+
TREESEED_FIXTURE_ID: treeseed-working-site
|
|
83
|
+
steps:
|
|
84
|
+
- name: Checkout
|
|
85
|
+
uses: actions/checkout@v4
|
|
86
|
+
with:
|
|
87
|
+
submodules: recursive
|
|
88
|
+
|
|
89
|
+
- name: Setup Node
|
|
90
|
+
uses: actions/setup-node@v4
|
|
91
|
+
with:
|
|
92
|
+
node-version: 24.12.0
|
|
93
|
+
|
|
94
|
+
- name: Assert node:sqlite availability
|
|
95
|
+
run: node -e "import('node:sqlite').then(() => console.log('node:sqlite available')).catch((error) => { console.error(error); process.exit(1); })"
|
|
96
|
+
|
|
97
|
+
${siblingPreparationCommands ? ` - name: Prepare sibling packages
|
|
98
|
+
working-directory: .
|
|
99
|
+
run: |
|
|
100
|
+
${siblingPreparationCommands.split("\n").map((line) => ` ${line}`).join("\n")}
|
|
101
|
+
|
|
102
|
+
` : ""} - name: Install dependencies
|
|
103
|
+
run: |
|
|
104
|
+
if test -f package-lock.json; then
|
|
105
|
+
npm ci
|
|
106
|
+
else
|
|
107
|
+
npm install --no-audit --no-fund
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
- name: Verify package
|
|
111
|
+
run: npm run verify:direct
|
|
112
|
+
`,
|
|
113
|
+
"utf8"
|
|
114
|
+
);
|
|
115
|
+
return {
|
|
116
|
+
cwd: options.workspaceRoot,
|
|
117
|
+
args: ["act", options.eventName, "-W", workflowPath, "-j", "verify"]
|
|
118
|
+
};
|
|
119
|
+
}
|
|
41
120
|
function findWorkspaceRoot(packageRoot) {
|
|
42
121
|
let current = packageRoot;
|
|
43
122
|
while (true) {
|
|
@@ -150,6 +229,15 @@ function runTreeseedVerifyDriver(options = {}) {
|
|
|
150
229
|
write(detail || "Treeseed verify requires a running Docker daemon when TREESEED_VERIFY_DRIVER=act.", "stderr");
|
|
151
230
|
return 1;
|
|
152
231
|
}
|
|
232
|
+
if (status.workspaceRoot && status.localTreeseedSiblingDependencies.length > 0) {
|
|
233
|
+
const workspaceAct = createWorkspaceActWorkflow({
|
|
234
|
+
workspaceRoot: status.workspaceRoot,
|
|
235
|
+
packageRoot: status.packageRoot,
|
|
236
|
+
eventName: status.eventName,
|
|
237
|
+
localTreeseedSiblingDependencies: status.localTreeseedSiblingDependencies
|
|
238
|
+
});
|
|
239
|
+
return runCommand("gh", workspaceAct.args, workspaceAct.cwd);
|
|
240
|
+
}
|
|
153
241
|
return runCommand("gh", ["act", status.eventName, "-W", ".github/workflows/verify.yml", "-j", "verify"], status.packageRoot);
|
|
154
242
|
}
|
|
155
243
|
if (status.prefersDirectForLocalWorkspace) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"fixtures:check": "node ./scripts/run-ts.mjs ./scripts/fixture-tools.ts check",
|
|
43
43
|
"lint": "npm run fixtures:check && npm run build:dist",
|
|
44
44
|
"verify:direct": "npm run release:verify",
|
|
45
|
-
"verify:local": "node --input-type=module -e \"process.env.TREESEED_VERIFY_DRIVER='direct'; await import('
|
|
46
|
-
"verify:action": "node --input-type=module -e \"process.env.TREESEED_VERIFY_DRIVER='act'; await import('
|
|
45
|
+
"verify:local": "node --input-type=module -e \"process.env.TREESEED_VERIFY_DRIVER='direct'; await import('./scripts/verify-driver.mjs')\"",
|
|
46
|
+
"verify:action": "node --input-type=module -e \"process.env.TREESEED_VERIFY_DRIVER='act'; await import('./scripts/verify-driver.mjs')\"",
|
|
47
47
|
"verify": "node ./scripts/verify-driver.mjs",
|
|
48
48
|
"release:setup": "npm run setup:ci",
|
|
49
49
|
"release:check-tag": "node ./scripts/run-ts.mjs ./scripts/assert-release-tag-version.ts",
|
|
@@ -10,8 +10,12 @@ const packageRoot = resolve(scriptRoot, '..');
|
|
|
10
10
|
const sourceRunner = resolve(packageRoot, 'scripts', 'run-ts.mjs');
|
|
11
11
|
const sourceEntry = resolve(packageRoot, 'src', 'verification.ts');
|
|
12
12
|
const publishedEntry = resolve(packageRoot, 'dist', 'verification.js');
|
|
13
|
+
const entrypointCheckOnly = process.env.TREESEED_VERIFY_ENTRYPOINT_CHECK === 'true';
|
|
13
14
|
|
|
14
15
|
if (existsSync(sourceRunner) && existsSync(sourceEntry)) {
|
|
16
|
+
if (entrypointCheckOnly) {
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
15
19
|
const result = spawnSync(process.execPath, [sourceRunner, sourceEntry], {
|
|
16
20
|
cwd: process.cwd(),
|
|
17
21
|
env: process.env,
|
|
@@ -21,6 +25,9 @@ if (existsSync(sourceRunner) && existsSync(sourceEntry)) {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
if (existsSync(publishedEntry)) {
|
|
28
|
+
if (entrypointCheckOnly) {
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
24
31
|
const { runTreeseedVerifyDriver } = await import('../dist/verification.js');
|
|
25
32
|
process.exit(runTreeseedVerifyDriver({ packageRoot: process.cwd() }));
|
|
26
33
|
}
|