@drawcall/market 0.1.95 → 0.1.96

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.
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,eAAe,CAAA;AAEtB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;IACd,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CAoFf;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQlE"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,eAAe,CAAA;AAEtB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;IACd,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CAiIf;AAuBD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQlE"}
@@ -3,6 +3,7 @@ import semver from 'semver';
3
3
  import { getCliClient } from '../cli-client.js';
4
4
  import { packAsset, packPolicyFromInstallMetadata, parsePackDependencies } from '../pack.js';
5
5
  import { unchangedUploadResult, uploadResult } from '../output.js';
6
+ import { buildTemplateDeployment, getTemplateDeploymentStatus, uploadTemplateDeployment, } from '../template-deployment.js';
6
7
  import { assetDescriptionSchema, assetNameSchema, semverSchema, MAX_ASSET_DESCRIPTION_LENGTH, } from '../schemas.js';
7
8
  export async function uploadCommand(name, zipFilter, description, opts) {
8
9
  const spinner = ora({
@@ -22,7 +23,12 @@ export async function uploadCommand(name, zipFilter, description, opts) {
22
23
  });
23
24
  const cwd = opts.cwd ?? process.cwd();
24
25
  const type = opts.type;
25
- const { client } = await getCliClient({ baseUrl: opts.baseUrl, requireAuth: true });
26
+ const { client, baseUrl, authToken } = await getCliClient({
27
+ baseUrl: opts.baseUrl,
28
+ requireAuth: true,
29
+ });
30
+ if (!authToken)
31
+ throw new Error('Not logged in. Run `market login` first.');
26
32
  const installMetadata = await client.asset.installMetadata();
27
33
  const packed = await packAsset(zipFilter, {
28
34
  cwd,
@@ -43,23 +49,53 @@ export async function uploadCommand(name, zipFilter, description, opts) {
43
49
  if (existing && existing.ownerId !== profile.id) {
44
50
  throw new Error(`Asset "${parsedName}" already exists and is owned by another user`);
45
51
  }
52
+ let unchanged = false;
46
53
  if (existing) {
47
54
  const latestZip = await client.asset.downloadZip({
48
55
  name: parsedName,
49
56
  version: existing.latestVersion,
50
57
  });
51
58
  const latestBytes = new Uint8Array(await latestZip.arrayBuffer());
52
- if (existing.description === parsedDescription &&
53
- depsEqual(existing.npmDependencies, npmDependencies) &&
54
- depsEqual(existing.assetDependencies, assetDependencies) &&
55
- depsEqual(existing.skillDependencies, skillDependencies) &&
56
- bytesEqual(latestBytes, zip)) {
57
- spinner.stop();
58
- console.log(unchangedUploadResult(parsedName, existing.latestVersion));
59
- return;
59
+ unchanged =
60
+ existing.description === parsedDescription &&
61
+ depsEqual(existing.npmDependencies, npmDependencies) &&
62
+ depsEqual(existing.assetDependencies, assetDependencies) &&
63
+ depsEqual(existing.skillDependencies, skillDependencies) &&
64
+ bytesEqual(latestBytes, zip);
65
+ }
66
+ if (unchanged && existing) {
67
+ if (type === 'template') {
68
+ const status = await getTemplateDeploymentStatus({
69
+ baseUrl,
70
+ authToken,
71
+ name: parsedName,
72
+ version: existing.latestVersion,
73
+ });
74
+ if (!status.ready) {
75
+ spinner.stop();
76
+ const root = await buildTemplateDeployment(zipFilter, cwd);
77
+ spinner.start(`Uploading deployment for ${parsedName}@${existing.latestVersion}`);
78
+ await uploadDeployment({
79
+ baseUrl,
80
+ authToken,
81
+ name: parsedName,
82
+ version: existing.latestVersion,
83
+ root,
84
+ spinner,
85
+ });
86
+ }
60
87
  }
88
+ spinner.stop();
89
+ console.log(unchangedUploadResult(parsedName, existing.latestVersion));
90
+ return;
61
91
  }
62
92
  const version = parsedVersion ?? nextVersion(existing?.latestVersion);
93
+ let deploymentRoot = null;
94
+ if (type === 'template') {
95
+ spinner.stop();
96
+ deploymentRoot = await buildTemplateDeployment(zipFilter, cwd);
97
+ spinner.start(`Uploading ${parsedName}@${version}`);
98
+ }
63
99
  spinner.text = `Uploading ${parsedName}@${version}`;
64
100
  const uploaded = await client.asset.uploadZip({
65
101
  name: parsedName,
@@ -75,6 +111,16 @@ export async function uploadCommand(name, zipFilter, description, opts) {
75
111
  type: 'application/zip',
76
112
  }),
77
113
  });
114
+ if (deploymentRoot) {
115
+ await uploadDeployment({
116
+ baseUrl,
117
+ authToken,
118
+ name: parsedName,
119
+ version: uploaded.version,
120
+ root: deploymentRoot,
121
+ spinner,
122
+ });
123
+ }
78
124
  spinner.stop();
79
125
  console.log(uploadResult(parsedName, uploaded.version));
80
126
  }
@@ -83,6 +129,19 @@ export async function uploadCommand(name, zipFilter, description, opts) {
83
129
  throw err;
84
130
  }
85
131
  }
132
+ async function uploadDeployment(input) {
133
+ input.spinner.text = `Uploading deployment for ${input.name}@${input.version}`;
134
+ await uploadTemplateDeployment({
135
+ baseUrl: input.baseUrl,
136
+ authToken: input.authToken,
137
+ name: input.name,
138
+ version: input.version,
139
+ root: input.root,
140
+ onProgress(uploaded, total) {
141
+ input.spinner.text = `Uploading deployment for ${input.name}@${input.version} (${uploaded}/${total})`;
142
+ },
143
+ });
144
+ }
86
145
  export function parseUploadDescription(description) {
87
146
  try {
88
147
  return assetDescriptionSchema.parse(description);
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface TemplateDeploymentStatus {
2
+ ready: boolean;
3
+ url: string | null;
4
+ }
5
+ export interface UploadTemplateDeploymentInput {
6
+ baseUrl: string;
7
+ authToken: string;
8
+ name: string;
9
+ version: string;
10
+ root: string;
11
+ onProgress?(uploaded: number, total: number): void;
12
+ }
13
+ export declare function buildTemplateDeployment(zipFilter: string, cwd: string): Promise<string>;
14
+ export declare function getTemplateDeploymentStatus(input: Omit<UploadTemplateDeploymentInput, 'root' | 'onProgress'>): Promise<TemplateDeploymentStatus>;
15
+ export declare function uploadTemplateDeployment(input: UploadTemplateDeploymentInput): Promise<string>;
16
+ export declare function deploymentFiles(root: string): Promise<Array<{
17
+ absolutePath: string;
18
+ path: string;
19
+ }>>;
20
+ //# sourceMappingURL=template-deployment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-deployment.d.ts","sourceRoot":"","sources":["../src/template-deployment.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACnD;AAED,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa7F;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,IAAI,CAAC,6BAA6B,EAAE,MAAM,GAAG,YAAY,CAAC,GAChE,OAAO,CAAC,wBAAwB,CAAC,CAOnC;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,MAAM,CAAC,CAwCjB;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAuBxD"}
@@ -0,0 +1,117 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { detectPackageManager, runScript } from 'nypm';
4
+ import { z } from 'zod';
5
+ const deploymentStatusSchema = z.object({
6
+ ready: z.boolean(),
7
+ url: z.string().url().nullable(),
8
+ });
9
+ const deploymentCompleteSchema = z.object({
10
+ url: z.string().url(),
11
+ });
12
+ export async function buildTemplateDeployment(zipFilter, cwd) {
13
+ const sourceRoot = path.resolve(cwd, zipFilter);
14
+ const stat = await fs.stat(sourceRoot).catch(() => null);
15
+ if (!stat?.isDirectory()) {
16
+ throw new Error('Template uploads require a project directory so Market can run its build');
17
+ }
18
+ const packageManager = (await detectPackageManager(sourceRoot)) ?? 'npm';
19
+ await runScript('build', { cwd: sourceRoot, packageManager });
20
+ const deploymentRoot = path.join(sourceRoot, 'dist');
21
+ await requireFile(path.join(deploymentRoot, 'index.html'), 'dist/index.html');
22
+ await requireFile(path.join(deploymentRoot, 'schema.json'), 'dist/schema.json');
23
+ return deploymentRoot;
24
+ }
25
+ export async function getTemplateDeploymentStatus(input) {
26
+ const response = await fetch(deploymentEndpoint(input), {
27
+ headers: authHeaders(input.authToken),
28
+ });
29
+ const body = await responseBody(response);
30
+ if (!response.ok)
31
+ throw httpError('read template deployment', response, body);
32
+ return deploymentStatusSchema.parse(body);
33
+ }
34
+ export async function uploadTemplateDeployment(input) {
35
+ const files = await deploymentFiles(input.root);
36
+ if (files.length === 0)
37
+ throw new Error('Template deployment is empty');
38
+ await checkedFetch(new URL(`${deploymentEndpoint(input).pathname}/prepare`, input.baseUrl), { method: 'POST', headers: authHeaders(input.authToken) }, 'prepare template deployment');
39
+ let uploaded = 0;
40
+ for (let start = 0; start < files.length; start += 6) {
41
+ await Promise.all(files.slice(start, start + 6).map(async (file) => {
42
+ const url = deploymentEndpoint(input);
43
+ url.searchParams.set('path', file.path);
44
+ const bytes = await fs.readFile(file.absolutePath);
45
+ await checkedFetch(url, {
46
+ method: 'PUT',
47
+ headers: authHeaders(input.authToken),
48
+ body: new Blob([bytes]),
49
+ }, `upload ${file.path}`);
50
+ uploaded += 1;
51
+ input.onProgress?.(uploaded, files.length);
52
+ }));
53
+ }
54
+ const completeUrl = new URL(`${deploymentEndpoint(input).pathname}/complete`, input.baseUrl);
55
+ const response = await fetch(completeUrl, {
56
+ method: 'POST',
57
+ headers: authHeaders(input.authToken),
58
+ });
59
+ const body = await responseBody(response);
60
+ if (!response.ok)
61
+ throw httpError('publish template deployment', response, body);
62
+ return deploymentCompleteSchema.parse(body).url;
63
+ }
64
+ export async function deploymentFiles(root) {
65
+ const files = [];
66
+ async function visit(directory) {
67
+ const entries = await fs.readdir(directory, { withFileTypes: true });
68
+ for (const entry of entries) {
69
+ const absolutePath = path.join(directory, entry.name);
70
+ if (entry.isDirectory()) {
71
+ await visit(absolutePath);
72
+ continue;
73
+ }
74
+ if (!entry.isFile()) {
75
+ throw new Error(`Template deployment contains an unsupported entry: ${absolutePath}`);
76
+ }
77
+ files.push({
78
+ absolutePath,
79
+ path: path.relative(root, absolutePath).split(path.sep).join('/'),
80
+ });
81
+ }
82
+ }
83
+ await visit(root);
84
+ return files.sort((a, b) => a.path.localeCompare(b.path));
85
+ }
86
+ function deploymentEndpoint(input) {
87
+ return new URL(`/api/templates/${encodeURIComponent(input.name)}/${encodeURIComponent(input.version)}/deployment`, input.baseUrl);
88
+ }
89
+ function authHeaders(token) {
90
+ return new Headers({ authorization: `Bearer ${token}` });
91
+ }
92
+ async function checkedFetch(url, init, action) {
93
+ const response = await fetch(url, init);
94
+ if (response.ok)
95
+ return;
96
+ throw httpError(action, response, await responseBody(response));
97
+ }
98
+ async function responseBody(response) {
99
+ const text = await response.text();
100
+ if (!text)
101
+ return {};
102
+ try {
103
+ return JSON.parse(text);
104
+ }
105
+ catch {
106
+ return { raw: text };
107
+ }
108
+ }
109
+ function httpError(action, response, body) {
110
+ return new Error(`${action} failed (${response.status}): ${JSON.stringify(body)}`);
111
+ }
112
+ async function requireFile(file, label) {
113
+ const stat = await fs.stat(file).catch(() => null);
114
+ if (!stat?.isFile())
115
+ throw new Error(`Template build did not produce ${label}`);
116
+ }
117
+ //# sourceMappingURL=template-deployment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-deployment.js","sourceRoot":"","sources":["../src/template-deployment.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawcall/market",
3
- "version": "0.1.95",
3
+ "version": "0.1.96",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/drawcall-ai/market",
@@ -3,6 +3,11 @@ import semver from 'semver'
3
3
  import { getCliClient } from '../cli-client.js'
4
4
  import { packAsset, packPolicyFromInstallMetadata, parsePackDependencies } from '../pack.js'
5
5
  import { unchangedUploadResult, uploadResult } from '../output.js'
6
+ import {
7
+ buildTemplateDeployment,
8
+ getTemplateDeploymentStatus,
9
+ uploadTemplateDeployment,
10
+ } from '../template-deployment.js'
6
11
  import {
7
12
  assetDescriptionSchema,
8
13
  assetNameSchema,
@@ -51,7 +56,11 @@ export async function uploadCommand(
51
56
  })
52
57
  const cwd = opts.cwd ?? process.cwd()
53
58
  const type = opts.type
54
- const { client } = await getCliClient({ baseUrl: opts.baseUrl, requireAuth: true })
59
+ const { client, baseUrl, authToken } = await getCliClient({
60
+ baseUrl: opts.baseUrl,
61
+ requireAuth: true,
62
+ })
63
+ if (!authToken) throw new Error('Not logged in. Run `market login` first.')
55
64
  const installMetadata = await client.asset.installMetadata()
56
65
  const packed = await packAsset(zipFilter, {
57
66
  cwd,
@@ -74,26 +83,56 @@ export async function uploadCommand(
74
83
  throw new Error(`Asset "${parsedName}" already exists and is owned by another user`)
75
84
  }
76
85
 
86
+ let unchanged = false
77
87
  if (existing) {
78
88
  const latestZip = await client.asset.downloadZip({
79
89
  name: parsedName,
80
90
  version: existing.latestVersion,
81
91
  })
82
92
  const latestBytes = new Uint8Array(await latestZip.arrayBuffer())
83
- if (
93
+ unchanged =
84
94
  existing.description === parsedDescription &&
85
95
  depsEqual(existing.npmDependencies, npmDependencies) &&
86
96
  depsEqual(existing.assetDependencies, assetDependencies) &&
87
97
  depsEqual(existing.skillDependencies, skillDependencies) &&
88
98
  bytesEqual(latestBytes, zip)
89
- ) {
90
- spinner.stop()
91
- console.log(unchangedUploadResult(parsedName, existing.latestVersion))
92
- return
99
+ }
100
+
101
+ if (unchanged && existing) {
102
+ if (type === 'template') {
103
+ const status = await getTemplateDeploymentStatus({
104
+ baseUrl,
105
+ authToken,
106
+ name: parsedName,
107
+ version: existing.latestVersion,
108
+ })
109
+ if (!status.ready) {
110
+ spinner.stop()
111
+ const root = await buildTemplateDeployment(zipFilter, cwd)
112
+ spinner.start(`Uploading deployment for ${parsedName}@${existing.latestVersion}`)
113
+ await uploadDeployment({
114
+ baseUrl,
115
+ authToken,
116
+ name: parsedName,
117
+ version: existing.latestVersion,
118
+ root,
119
+ spinner,
120
+ })
121
+ }
93
122
  }
123
+ spinner.stop()
124
+ console.log(unchangedUploadResult(parsedName, existing.latestVersion))
125
+ return
94
126
  }
95
127
 
96
128
  const version = parsedVersion ?? nextVersion(existing?.latestVersion)
129
+ let deploymentRoot: string | null = null
130
+ if (type === 'template') {
131
+ spinner.stop()
132
+ deploymentRoot = await buildTemplateDeployment(zipFilter, cwd)
133
+ spinner.start(`Uploading ${parsedName}@${version}`)
134
+ }
135
+
97
136
  spinner.text = `Uploading ${parsedName}@${version}`
98
137
  const uploaded = await client.asset.uploadZip({
99
138
  name: parsedName,
@@ -110,6 +149,17 @@ export async function uploadCommand(
110
149
  }),
111
150
  })
112
151
 
152
+ if (deploymentRoot) {
153
+ await uploadDeployment({
154
+ baseUrl,
155
+ authToken,
156
+ name: parsedName,
157
+ version: uploaded.version,
158
+ root: deploymentRoot,
159
+ spinner,
160
+ })
161
+ }
162
+
113
163
  spinner.stop()
114
164
  console.log(uploadResult(parsedName, uploaded.version))
115
165
  } catch (err) {
@@ -118,6 +168,27 @@ export async function uploadCommand(
118
168
  }
119
169
  }
120
170
 
171
+ async function uploadDeployment(input: {
172
+ baseUrl: string
173
+ authToken: string
174
+ name: string
175
+ version: string
176
+ root: string
177
+ spinner: ReturnType<typeof ora>
178
+ }): Promise<void> {
179
+ input.spinner.text = `Uploading deployment for ${input.name}@${input.version}`
180
+ await uploadTemplateDeployment({
181
+ baseUrl: input.baseUrl,
182
+ authToken: input.authToken,
183
+ name: input.name,
184
+ version: input.version,
185
+ root: input.root,
186
+ onProgress(uploaded, total) {
187
+ input.spinner.text = `Uploading deployment for ${input.name}@${input.version} (${uploaded}/${total})`
188
+ },
189
+ })
190
+ }
191
+
121
192
  export function parseUploadDescription(description: string): string {
122
193
  try {
123
194
  return assetDescriptionSchema.parse(description)
@@ -0,0 +1,160 @@
1
+ import * as fs from 'node:fs/promises'
2
+ import * as path from 'node:path'
3
+ import { detectPackageManager, runScript } from 'nypm'
4
+ import { z } from 'zod'
5
+
6
+ const deploymentStatusSchema = z.object({
7
+ ready: z.boolean(),
8
+ url: z.string().url().nullable(),
9
+ })
10
+
11
+ const deploymentCompleteSchema = z.object({
12
+ url: z.string().url(),
13
+ })
14
+
15
+ export interface TemplateDeploymentStatus {
16
+ ready: boolean
17
+ url: string | null
18
+ }
19
+
20
+ export interface UploadTemplateDeploymentInput {
21
+ baseUrl: string
22
+ authToken: string
23
+ name: string
24
+ version: string
25
+ root: string
26
+ onProgress?(uploaded: number, total: number): void
27
+ }
28
+
29
+ export async function buildTemplateDeployment(zipFilter: string, cwd: string): Promise<string> {
30
+ const sourceRoot = path.resolve(cwd, zipFilter)
31
+ const stat = await fs.stat(sourceRoot).catch(() => null)
32
+ if (!stat?.isDirectory()) {
33
+ throw new Error('Template uploads require a project directory so Market can run its build')
34
+ }
35
+
36
+ const packageManager = (await detectPackageManager(sourceRoot)) ?? 'npm'
37
+ await runScript('build', { cwd: sourceRoot, packageManager })
38
+ const deploymentRoot = path.join(sourceRoot, 'dist')
39
+ await requireFile(path.join(deploymentRoot, 'index.html'), 'dist/index.html')
40
+ await requireFile(path.join(deploymentRoot, 'schema.json'), 'dist/schema.json')
41
+ return deploymentRoot
42
+ }
43
+
44
+ export async function getTemplateDeploymentStatus(
45
+ input: Omit<UploadTemplateDeploymentInput, 'root' | 'onProgress'>,
46
+ ): Promise<TemplateDeploymentStatus> {
47
+ const response = await fetch(deploymentEndpoint(input), {
48
+ headers: authHeaders(input.authToken),
49
+ })
50
+ const body = await responseBody(response)
51
+ if (!response.ok) throw httpError('read template deployment', response, body)
52
+ return deploymentStatusSchema.parse(body)
53
+ }
54
+
55
+ export async function uploadTemplateDeployment(
56
+ input: UploadTemplateDeploymentInput,
57
+ ): Promise<string> {
58
+ const files = await deploymentFiles(input.root)
59
+ if (files.length === 0) throw new Error('Template deployment is empty')
60
+
61
+ await checkedFetch(
62
+ new URL(`${deploymentEndpoint(input).pathname}/prepare`, input.baseUrl),
63
+ { method: 'POST', headers: authHeaders(input.authToken) },
64
+ 'prepare template deployment',
65
+ )
66
+
67
+ let uploaded = 0
68
+ for (let start = 0; start < files.length; start += 6) {
69
+ await Promise.all(
70
+ files.slice(start, start + 6).map(async (file) => {
71
+ const url = deploymentEndpoint(input)
72
+ url.searchParams.set('path', file.path)
73
+ const bytes = await fs.readFile(file.absolutePath)
74
+ await checkedFetch(
75
+ url,
76
+ {
77
+ method: 'PUT',
78
+ headers: authHeaders(input.authToken),
79
+ body: new Blob([bytes]),
80
+ },
81
+ `upload ${file.path}`,
82
+ )
83
+ uploaded += 1
84
+ input.onProgress?.(uploaded, files.length)
85
+ }),
86
+ )
87
+ }
88
+
89
+ const completeUrl = new URL(`${deploymentEndpoint(input).pathname}/complete`, input.baseUrl)
90
+ const response = await fetch(completeUrl, {
91
+ method: 'POST',
92
+ headers: authHeaders(input.authToken),
93
+ })
94
+ const body = await responseBody(response)
95
+ if (!response.ok) throw httpError('publish template deployment', response, body)
96
+ return deploymentCompleteSchema.parse(body).url
97
+ }
98
+
99
+ export async function deploymentFiles(
100
+ root: string,
101
+ ): Promise<Array<{ absolutePath: string; path: string }>> {
102
+ const files: Array<{ absolutePath: string; path: string }> = []
103
+
104
+ async function visit(directory: string): Promise<void> {
105
+ const entries = await fs.readdir(directory, { withFileTypes: true })
106
+ for (const entry of entries) {
107
+ const absolutePath = path.join(directory, entry.name)
108
+ if (entry.isDirectory()) {
109
+ await visit(absolutePath)
110
+ continue
111
+ }
112
+ if (!entry.isFile()) {
113
+ throw new Error(`Template deployment contains an unsupported entry: ${absolutePath}`)
114
+ }
115
+ files.push({
116
+ absolutePath,
117
+ path: path.relative(root, absolutePath).split(path.sep).join('/'),
118
+ })
119
+ }
120
+ }
121
+
122
+ await visit(root)
123
+ return files.sort((a, b) => a.path.localeCompare(b.path))
124
+ }
125
+
126
+ function deploymentEndpoint(input: { baseUrl: string; name: string; version: string }): URL {
127
+ return new URL(
128
+ `/api/templates/${encodeURIComponent(input.name)}/${encodeURIComponent(input.version)}/deployment`,
129
+ input.baseUrl,
130
+ )
131
+ }
132
+
133
+ function authHeaders(token: string): Headers {
134
+ return new Headers({ authorization: `Bearer ${token}` })
135
+ }
136
+
137
+ async function checkedFetch(url: URL, init: RequestInit, action: string): Promise<void> {
138
+ const response = await fetch(url, init)
139
+ if (response.ok) return
140
+ throw httpError(action, response, await responseBody(response))
141
+ }
142
+
143
+ async function responseBody(response: Response): Promise<unknown> {
144
+ const text = await response.text()
145
+ if (!text) return {}
146
+ try {
147
+ return JSON.parse(text)
148
+ } catch {
149
+ return { raw: text }
150
+ }
151
+ }
152
+
153
+ function httpError(action: string, response: Response, body: unknown): Error {
154
+ return new Error(`${action} failed (${response.status}): ${JSON.stringify(body)}`)
155
+ }
156
+
157
+ async function requireFile(file: string, label: string): Promise<void> {
158
+ const stat = await fs.stat(file).catch(() => null)
159
+ if (!stat?.isFile()) throw new Error(`Template build did not produce ${label}`)
160
+ }