@sequenceholdings/artifact-studio 0.8.1 → 0.9.1
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 +14 -0
- package/dist/api.d.ts +2 -1
- package/dist/api.js +15 -5
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +58 -20
- package/dist/next-build.d.ts +3 -1
- package/dist/next-build.js +10 -6
- package/dist/sdk.d.ts +2 -0
- package/dist/templates/react-vite/package.json +1 -1
- package/package.json +2 -2
- package/templates/react-vite/package.json +1 -1
package/README.md
CHANGED
|
@@ -500,3 +500,17 @@ streaming and file-transfer helpers retain their ordinary host tracing behavior.
|
|
|
500
500
|
Tracing does not grant permissions, change service-account behavior or guarantee
|
|
501
501
|
that every transport is instrumented. Traces availability depends on the deployed
|
|
502
502
|
platform version and your app/resource permissions.
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
### Microphone dictation in an isolated application
|
|
506
|
+
|
|
507
|
+
Explicitly declare browser API read `/api/files/speech/config/get` and write
|
|
508
|
+
`/api/files/speech/stt` to opt an isolated application iframe into microphone
|
|
509
|
+
requests. Both exact paths are required; broad API wildcards do not enable it.
|
|
510
|
+
The browser still asks the user for permission. Existing sandbox origin privileges
|
|
511
|
+
are unchanged, and camera/geolocation remain unavailable. Legacy opaque-origin
|
|
512
|
+
static frames do not receive microphone delegation.
|
|
513
|
+
Upload with `api.upload` option `{ fieldName: 'audio' }`; ordinary uploads still
|
|
514
|
+
default to `file`. Atlas transcription trims silence by default; multipart
|
|
515
|
+
`trimSilence=false` opts out. Speech uses the declared host paths without requiring
|
|
516
|
+
the separate general Next host API rollout flag.
|
package/dist/api.d.ts
CHANGED
|
@@ -12,11 +12,12 @@ export declare function getJson<T>({ baseUrl, token, path }: ApiClientOptions &
|
|
|
12
12
|
export declare function getJsonOr404<T>({ baseUrl, token, path }: ApiClientOptions & {
|
|
13
13
|
path: string;
|
|
14
14
|
}): Promise<T | null>;
|
|
15
|
-
export declare function postJson<T>({ baseUrl, token, path, body, retry503, signal, }: ApiClientOptions & {
|
|
15
|
+
export declare function postJson<T>({ baseUrl, token, path, body, retry503, signal, headers, }: ApiClientOptions & {
|
|
16
16
|
path: string;
|
|
17
17
|
body?: unknown;
|
|
18
18
|
retry503?: boolean;
|
|
19
19
|
signal?: AbortSignal;
|
|
20
|
+
headers?: Record<string, string>;
|
|
20
21
|
}): Promise<T>;
|
|
21
22
|
export declare function deleteJson({ baseUrl, token, path, signal }: ApiClientOptions & {
|
|
22
23
|
path: string;
|
package/dist/api.js
CHANGED
|
@@ -19,7 +19,17 @@ const DEFAULT_RETRY_AFTER_SECONDS = 2;
|
|
|
19
19
|
* Content-Type) always win over anything here. Malformed JSON is ignored — a
|
|
20
20
|
* bad bypass header should never crash a deploy before the request is even made.
|
|
21
21
|
*/
|
|
22
|
-
function extraHeaders() {
|
|
22
|
+
function extraHeaders(baseUrl) {
|
|
23
|
+
// Preview gateway credentials belong only to the target, never to a separately
|
|
24
|
+
// authenticated source repository. An unbound header set fails closed.
|
|
25
|
+
const target = process.env.ARTIFACT_STUDIO_BASE_URL;
|
|
26
|
+
try {
|
|
27
|
+
if (!target || new URL(target).origin !== new URL(baseUrl).origin)
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
23
33
|
const raw = process.env.ARTIFACT_STUDIO_EXTRA_HEADERS?.trim();
|
|
24
34
|
if (!raw)
|
|
25
35
|
return {};
|
|
@@ -33,7 +43,7 @@ function extraHeaders() {
|
|
|
33
43
|
// Prevent case-variant duplicates from being merged by Headers/fetch
|
|
34
44
|
// (e.g. `authorization` + `Authorization` => "a, b"). The client always
|
|
35
45
|
// sets these explicitly below, so ignore any env-supplied variants.
|
|
36
|
-
if (lower === 'authorization' || lower === 'content-type')
|
|
46
|
+
if (lower === 'authorization' || lower === 'content-type' || lower === 'x-sequence-source-authorization')
|
|
37
47
|
continue;
|
|
38
48
|
if (typeof value === 'string')
|
|
39
49
|
headers[key] = value;
|
|
@@ -64,7 +74,7 @@ async function authenticatedFetch({ baseUrl, init = {}, path, token, retry503 =
|
|
|
64
74
|
...init,
|
|
65
75
|
redirect: 'manual',
|
|
66
76
|
headers: {
|
|
67
|
-
...extraHeaders(),
|
|
77
|
+
...extraHeaders(baseUrl),
|
|
68
78
|
...init.headers,
|
|
69
79
|
Authorization: `Bearer ${token}`,
|
|
70
80
|
},
|
|
@@ -84,7 +94,7 @@ export async function getJsonOr404({ baseUrl, token, path }) {
|
|
|
84
94
|
throw new ArtifactApiError(await responseError('GET', path, response), response.status);
|
|
85
95
|
return response.json();
|
|
86
96
|
}
|
|
87
|
-
export async function postJson({ baseUrl, token, path, body, retry503 = true, signal, }) {
|
|
97
|
+
export async function postJson({ baseUrl, token, path, body, retry503 = true, signal, headers, }) {
|
|
88
98
|
const response = await authenticatedFetch({
|
|
89
99
|
baseUrl,
|
|
90
100
|
token,
|
|
@@ -92,7 +102,7 @@ export async function postJson({ baseUrl, token, path, body, retry503 = true, si
|
|
|
92
102
|
retry503,
|
|
93
103
|
init: {
|
|
94
104
|
method: 'POST',
|
|
95
|
-
headers: { 'Content-Type': 'application/json' },
|
|
105
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
96
106
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
97
107
|
...(signal ? { signal } : {}),
|
|
98
108
|
},
|
package/dist/cli.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare function getConfiguredDefaultEnv(): Promise<string | undefined>;
|
|
|
32
32
|
*/
|
|
33
33
|
export interface TokenProviderOptions {
|
|
34
34
|
allowInteractiveLogin: boolean;
|
|
35
|
+
/** A separate source session; omitted for target requests. Never a caller URL. */
|
|
36
|
+
sourceEnvironment?: string;
|
|
35
37
|
}
|
|
36
38
|
export interface ProvidedToken {
|
|
37
39
|
authMode: SourceAuthMode;
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { constants, existsSync } from 'node:fs';
|
|
|
3
3
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { getJson, getJsonOr404, postJson } from './api.js';
|
|
6
|
-
import { ENV_URLS, readLocalConfig, resolveEnvironment, writeLocalConfig, } from './config.js';
|
|
6
|
+
import { ENV_URLS, knownEnvUrls, readLocalConfig, resolveEnvironment, writeLocalConfig, } from './config.js';
|
|
7
7
|
import { writeBuildArtifact } from './build.js';
|
|
8
8
|
import { buildArtifactStudioProjectIsolated } from './build-subprocess.js';
|
|
9
9
|
import { resolveArtifactStudioPeerVersions, } from './peer-versions.js';
|
|
@@ -33,9 +33,9 @@ const USAGE = `usage:
|
|
|
33
33
|
seq-studio artifact list --env <env> [--json]
|
|
34
34
|
seq-studio artifact show <slug-or-id> --env <env> [--json]
|
|
35
35
|
seq-studio artifact validate [dir]
|
|
36
|
-
seq-studio artifact build [dir | --repo <ns>/<name> | --git-url <url>] [--ref <ref>] [--path <dir>] [--out dist/artifact-bundle.json]
|
|
37
|
-
seq-studio artifact plan [dir | --repo <ns>/<name> | --git-url <url>] [--ref <ref>] [--path <dir>] --env <env>
|
|
38
|
-
seq-studio artifact deploy [dir | --repo <ns>/<name> | --git-url <url>] [--ref <ref>] [--path <dir>] --env <env> [--skip-unchanged] [--no-create] [--project <id>]
|
|
36
|
+
seq-studio artifact build [dir | --repo <ns>/<name> | --git-url <url>] [--ref <ref>] [--path <dir>] [--source-env <env>] [--out dist/artifact-bundle.json]
|
|
37
|
+
seq-studio artifact plan [dir | --repo <ns>/<name> | --git-url <url>] [--ref <ref>] [--path <dir>] [--source-env <env>] --env <env>
|
|
38
|
+
seq-studio artifact deploy [dir | --repo <ns>/<name> | --git-url <url>] [--ref <ref>] [--path <dir>] [--source-env <env>] --env <env> [--skip-unchanged] [--no-create] [--project <id>]
|
|
39
39
|
seq-studio artifact dev [dir] --env <env> [--once] [--key default] [--link <pkgDir>[,<pkgDir>]] [--port <port>]
|
|
40
40
|
seq-studio artifact promote <deployment-id> --env <env>
|
|
41
41
|
seq-studio artifact pull <project-id> --env <env> --out <dir>
|
|
@@ -51,7 +51,7 @@ const USAGE = `usage:
|
|
|
51
51
|
--repo / --git-url repository (default: its root). The target project comes from
|
|
52
52
|
the source's artifact.bundle.yml project_id.
|
|
53
53
|
|
|
54
|
-
Official (active) deploys
|
|
54
|
+
Official (active) deploys require \`main\` (or \`staging\` for staging targets) with a
|
|
55
55
|
resolved git commit and a clean artifact source directory. Dirty files
|
|
56
56
|
outside a nested local source directory are ignored with a warning.
|
|
57
57
|
Deployments targeting \`local\` may use any branch, including dirty working
|
|
@@ -61,7 +61,11 @@ const USAGE = `usage:
|
|
|
61
61
|
Interactive --repo builds clone over smart-HTTP using your seq-studio login
|
|
62
62
|
and repository read access. No PAT is needed. Headless M2M builds use JSON
|
|
63
63
|
materialize and accept only platform-managed --repo sources. Use --env to
|
|
64
|
-
select the
|
|
64
|
+
select the target environment. Next.js build/plan/deploy accept --source-env
|
|
65
|
+
to read a Git Service repository from a separately authenticated environment.
|
|
66
|
+
Log in to both environments; source read and target deploy permissions apply.
|
|
67
|
+
The target must support verified cross-environment builds. Source credentials
|
|
68
|
+
are used only to fetch source, never passed to the build or stored with it.
|
|
65
69
|
|
|
66
70
|
Next.js: init --template nextjs, then pnpm install with Node.js 24. dev starts
|
|
67
71
|
a local Next server and an owner-only Atlas preview tunnel (no cloud credentials).
|
|
@@ -114,9 +118,9 @@ function validateKnownOptions(args) {
|
|
|
114
118
|
link: { values: ['env', 'project'], booleans: [] }, env: { values: [], booleans: [] },
|
|
115
119
|
status: { values: ['env'], booleans: [] }, list: { values: ['env'], booleans: ['json'] },
|
|
116
120
|
show: { values: ['env'], booleans: ['json'] }, validate: { values: [], booleans: [] },
|
|
117
|
-
build: { values: ['env', 'repo', 'git-url', 'ref', 'path', 'out'], booleans: [] },
|
|
118
|
-
plan: { values: ['env', 'repo', 'git-url', 'ref', 'path'], booleans: [] },
|
|
119
|
-
deploy: { values: ['env', 'repo', 'git-url', 'ref', 'path', 'project', 'out'], booleans: ['skip-unchanged', 'no-create'] },
|
|
121
|
+
build: { values: ['source-env', 'env', 'repo', 'git-url', 'ref', 'path', 'out'], booleans: [] },
|
|
122
|
+
plan: { values: ['source-env', 'env', 'repo', 'git-url', 'ref', 'path'], booleans: [] },
|
|
123
|
+
deploy: { values: ['source-env', 'env', 'repo', 'git-url', 'ref', 'path', 'project', 'out'], booleans: ['skip-unchanged', 'no-create'] },
|
|
120
124
|
dev: { values: ['env', 'key', 'link', 'port'], booleans: ['once'] },
|
|
121
125
|
promote: { values: ['env'], booleans: [] }, pull: { values: ['env', 'out'], booleans: [] },
|
|
122
126
|
rollback: { values: ['env'], booleans: [] },
|
|
@@ -441,16 +445,17 @@ function reportBuildDiagnostics(result) {
|
|
|
441
445
|
}
|
|
442
446
|
async function buildCommand(args) {
|
|
443
447
|
const spec = parseSourceSpec(args);
|
|
448
|
+
const sourceEnvironment = sourceEnvironmentFromArgs(args);
|
|
444
449
|
// Local builds stay offline. Public git URLs need no bearer token, but an
|
|
445
450
|
// optional auth lookup still identifies a selected M2M principal so the
|
|
446
451
|
// source policy can reject arbitrary CI input before cloning.
|
|
447
|
-
const auth = spec.kind === 'git-service'
|
|
448
|
-
? await
|
|
452
|
+
const auth = spec.kind === 'git-service' || sourceEnvironment
|
|
453
|
+
? await getSourceAuth(args)
|
|
449
454
|
: spec.kind === 'git-url'
|
|
450
455
|
? await getOptionalAuth(args)
|
|
451
456
|
: null;
|
|
452
457
|
const remote = spec.kind === 'git-service' && auth
|
|
453
|
-
? { authMode: auth.authMode, baseUrl: (await envFromArgs(args)).url, token: auth.token }
|
|
458
|
+
? { authMode: auth.authMode, baseUrl: (sourceEnvironment ?? await envFromArgs(args)).url, token: auth.token }
|
|
454
459
|
: auth
|
|
455
460
|
? { authMode: auth.authMode }
|
|
456
461
|
: {};
|
|
@@ -459,6 +464,7 @@ async function buildCommand(args) {
|
|
|
459
464
|
if (isNextArtifactManifest(await readArtifactStudioManifest(source.dir))) {
|
|
460
465
|
return await buildNextCommand({ args, source, active: false });
|
|
461
466
|
}
|
|
467
|
+
assertSourceEnvironmentSupportsManifest(args);
|
|
462
468
|
const result = await buildPreparedArtifactSource(source);
|
|
463
469
|
reportBuildDiagnostics(result);
|
|
464
470
|
// A remote source's dir is a temp dir we tear down below, so default the
|
|
@@ -483,10 +489,12 @@ async function planCommand(args) {
|
|
|
483
489
|
const auth = await getOptionalAuth(args);
|
|
484
490
|
const token = auth?.token ?? null;
|
|
485
491
|
const spec = parseSourceSpec(args);
|
|
492
|
+
const sourceEnvironment = sourceEnvironmentFromArgs(args);
|
|
493
|
+
const sourceAuth = sourceEnvironment ? await getSourceAuth(args) : auth;
|
|
486
494
|
const source = await resolveArtifactSource(spec, {
|
|
487
|
-
...(
|
|
488
|
-
baseUrl: env.url,
|
|
489
|
-
token,
|
|
495
|
+
...(sourceAuth ? { authMode: sourceAuth.authMode } : {}),
|
|
496
|
+
baseUrl: (sourceEnvironment ?? env).url,
|
|
497
|
+
token: sourceAuth?.token ?? null,
|
|
490
498
|
});
|
|
491
499
|
try {
|
|
492
500
|
const manifest = await readArtifactStudioManifest(source.dir);
|
|
@@ -494,6 +502,7 @@ async function planCommand(args) {
|
|
|
494
502
|
const { planNextProject } = await import('./next-build.js');
|
|
495
503
|
return await planNextProject({ root: source.dir, manifest, environment: env.name });
|
|
496
504
|
}
|
|
505
|
+
assertSourceEnvironmentSupportsManifest(args);
|
|
497
506
|
const result = await buildPreparedArtifactSource(source);
|
|
498
507
|
reportBuildDiagnostics(result);
|
|
499
508
|
console.log(`[seq-studio] plan ${result.manifest.artifact.project_id} -> ${env.name}`);
|
|
@@ -539,10 +548,12 @@ async function deployCommand(args) {
|
|
|
539
548
|
const { token } = auth;
|
|
540
549
|
const spec = parseSourceSpec(args);
|
|
541
550
|
const explicitProjectId = typeof args.flags.project === 'string' ? args.flags.project : null;
|
|
551
|
+
const sourceEnvironment = sourceEnvironmentFromArgs(args);
|
|
552
|
+
const sourceAuth = sourceEnvironment ? await getSourceAuth(args) : auth;
|
|
542
553
|
const source = await resolveArtifactSource(spec, {
|
|
543
|
-
authMode:
|
|
544
|
-
baseUrl: env.url,
|
|
545
|
-
token,
|
|
554
|
+
authMode: sourceAuth.authMode,
|
|
555
|
+
baseUrl: (sourceEnvironment ?? env).url,
|
|
556
|
+
token: sourceAuth.token,
|
|
546
557
|
});
|
|
547
558
|
try {
|
|
548
559
|
// Fail closed before build / project create for deployed environments.
|
|
@@ -558,6 +569,7 @@ async function deployCommand(args) {
|
|
|
558
569
|
if (isNextArtifactManifest(manifest)) {
|
|
559
570
|
return await buildNextCommand({ args, source, active: true });
|
|
560
571
|
}
|
|
572
|
+
assertSourceEnvironmentSupportsManifest(args);
|
|
561
573
|
// --skip-unchanged: hash the raw source (no build needed) and no-op when
|
|
562
574
|
// the remote active deployment already matches *and* was built with the
|
|
563
575
|
// same CLI/atlas-ui pin. Lets CI redeploy every artifact on every release
|
|
@@ -618,8 +630,10 @@ async function buildNextCommand({ args, source, active }) {
|
|
|
618
630
|
if (active) {
|
|
619
631
|
assertActiveDeployProvenance({ ...source.provenance, environment: env.name });
|
|
620
632
|
}
|
|
621
|
-
const
|
|
622
|
-
|
|
633
|
+
const sourceEnvironment = sourceEnvironmentFromArgs(args);
|
|
634
|
+
const sourceToken = sourceEnvironment ? (await getSourceAuth(args)).token : token;
|
|
635
|
+
const repositoryId = active || spec.kind === 'git-service' || sourceEnvironment
|
|
636
|
+
? await resolveNextRepositoryId({ spec, repository, baseUrl: (sourceEnvironment ?? env).url, token: sourceToken })
|
|
623
637
|
: undefined;
|
|
624
638
|
const project = await ensureRemoteProject({
|
|
625
639
|
env: env.url, token, result: { manifest }, linkConfigDir: spec.kind === 'local' ? source.dir : null,
|
|
@@ -632,6 +646,7 @@ async function buildNextCommand({ args, source, active }) {
|
|
|
632
646
|
return submitNextBuild({
|
|
633
647
|
root: source.dir, sourceRoot: source.sourceRoot, manifest, projectId: project.id, baseUrl: env.url,
|
|
634
648
|
getToken: () => getRequiredToken(args), provenance: source.provenance, repository, repositoryId,
|
|
649
|
+
...(sourceEnvironment ? { sourceEnvironment: sourceEnvironment.name, sourceToken } : {}),
|
|
635
650
|
channel: active ? 'active' : 'preview', out: typeof args.flags.out === 'string' ? resolve(args.flags.out) : undefined,
|
|
636
651
|
});
|
|
637
652
|
}
|
|
@@ -1027,6 +1042,29 @@ export async function getConfiguredDefaultEnv() {
|
|
|
1027
1042
|
async function envFromArgs(args) {
|
|
1028
1043
|
return resolveEnvironment(typeof args.flags.env === 'string' ? args.flags.env : undefined, await getConfiguredDefaultEnv());
|
|
1029
1044
|
}
|
|
1045
|
+
/** Source selection must never inherit the target URL override. */
|
|
1046
|
+
function sourceEnvironmentFromArgs(args) {
|
|
1047
|
+
const name = args.flags['source-env'];
|
|
1048
|
+
if (typeof name !== 'string')
|
|
1049
|
+
return undefined;
|
|
1050
|
+
const url = knownEnvUrls()[name];
|
|
1051
|
+
if (typeof url !== 'string' || !url)
|
|
1052
|
+
throw new Error(`Unknown source environment "${name}". Run seq-studio envs list and login to the source environment.`);
|
|
1053
|
+
return { name, url };
|
|
1054
|
+
}
|
|
1055
|
+
async function getSourceAuth(args) {
|
|
1056
|
+
const source = sourceEnvironmentFromArgs(args);
|
|
1057
|
+
if (!source)
|
|
1058
|
+
return getRequiredAuth(args);
|
|
1059
|
+
const auth = await resolveAuth({ allowInteractiveLogin: true, sourceEnvironment: source.name });
|
|
1060
|
+
if (!auth)
|
|
1061
|
+
throw new Error(`Authenticate to the source with seq-studio login -e ${source.name}.`);
|
|
1062
|
+
return auth;
|
|
1063
|
+
}
|
|
1064
|
+
function assertSourceEnvironmentSupportsManifest(args) {
|
|
1065
|
+
if (args.flags['source-env'])
|
|
1066
|
+
throw new Error('--source-env is supported for Next.js repository builds only.');
|
|
1067
|
+
}
|
|
1030
1068
|
let tokenProvider = null;
|
|
1031
1069
|
export function setTokenProvider(provider) {
|
|
1032
1070
|
tokenProvider = provider;
|
package/dist/next-build.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare function resolveNextRepositoryId({ spec, repository, baseUrl, tok
|
|
|
15
15
|
baseUrl: string;
|
|
16
16
|
token: string;
|
|
17
17
|
}): Promise<string>;
|
|
18
|
-
export declare function submitNextBuild({ root, sourceRoot, manifest, projectId, baseUrl, getToken, provenance, repository, repositoryId, channel, out }: {
|
|
18
|
+
export declare function submitNextBuild({ root, sourceRoot, manifest, projectId, baseUrl, getToken, provenance, repository, repositoryId, sourceEnvironment, sourceToken, channel, out }: {
|
|
19
19
|
root: string;
|
|
20
20
|
sourceRoot: string;
|
|
21
21
|
manifest: ArtifactStudioNextManifest;
|
|
@@ -25,6 +25,8 @@ export declare function submitNextBuild({ root, sourceRoot, manifest, projectId,
|
|
|
25
25
|
provenance: SourceProvenance;
|
|
26
26
|
repository: string;
|
|
27
27
|
repositoryId?: string;
|
|
28
|
+
sourceEnvironment?: string;
|
|
29
|
+
sourceToken?: string;
|
|
28
30
|
channel: 'active' | 'preview';
|
|
29
31
|
out?: string;
|
|
30
32
|
}): Promise<number>;
|
package/dist/next-build.js
CHANGED
|
@@ -58,16 +58,16 @@ export async function resolveNextRepositoryId({ spec, repository, baseUrl, token
|
|
|
58
58
|
return match[1];
|
|
59
59
|
}
|
|
60
60
|
catch { /* Opaque labels/SSH origins are valid preview provenance but cannot attest a release. */ }
|
|
61
|
-
throw new Error('Official Next.js releases require a Git Service repository in
|
|
61
|
+
throw new Error('Official Next.js releases require a Git Service repository in the selected source environment. Use --source-env <env> when its repository lives in another environment. Push the reviewed revision, then run artifact deploy --repo <namespace>/<name> --ref main --env <env> (or --ref staging for a staging environment).');
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
64
|
* A verified repository build names a commit and the application's directory in it;
|
|
65
65
|
* anything else uploads the committed source snapshot. The repository root is omitted
|
|
66
66
|
* so the request stays valid for Atlas versions that predate `sourceRoot`.
|
|
67
67
|
*/
|
|
68
|
-
function nextBuildRequestBody({ manifest, files, commit, provenance, repository, repositoryId, sourceRoot, channel }) {
|
|
68
|
+
function nextBuildRequestBody({ manifest, files, commit, provenance, repository, repositoryId, sourceEnvironment, sourceRoot, channel }) {
|
|
69
69
|
if (repositoryId)
|
|
70
|
-
return { repositoryId, commit, ...(sourceRoot === '.' ? {} : { sourceRoot }), idempotencyKey: randomUUID(), channel };
|
|
70
|
+
return { repositoryId, ...(sourceEnvironment ? { sourceEnvironment } : {}), commit, ...(sourceRoot === '.' ? {} : { sourceRoot }), idempotencyKey: randomUUID(), channel };
|
|
71
71
|
return {
|
|
72
72
|
manifest,
|
|
73
73
|
files: files.map(({ path, content, encoding }) => ({ path, content, encoding: encoding ?? 'utf8' })),
|
|
@@ -75,7 +75,7 @@ function nextBuildRequestBody({ manifest, files, commit, provenance, repository,
|
|
|
75
75
|
idempotencyKey: randomUUID(), channel,
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
export async function submitNextBuild({ root, sourceRoot, manifest, projectId, baseUrl, getToken, provenance, repository, repositoryId, channel, out }) {
|
|
78
|
+
export async function submitNextBuild({ root, sourceRoot, manifest, projectId, baseUrl, getToken, provenance, repository, repositoryId, sourceEnvironment, sourceToken, channel, out }) {
|
|
79
79
|
if (!provenance.gitCommit || !/^[a-f0-9]{40}$/i.test(provenance.gitCommit)) {
|
|
80
80
|
throw new Error('Commit the application source before requesting a hosted build. Use artifact dev for uncommitted local development.');
|
|
81
81
|
}
|
|
@@ -84,8 +84,12 @@ export async function submitNextBuild({ root, sourceRoot, manifest, projectId, b
|
|
|
84
84
|
if (channel === 'active' && !repositoryId)
|
|
85
85
|
throw new Error('An official release requires a verified Git Service repository.');
|
|
86
86
|
const path = `/api/artifact-studio/projects/${encodeURIComponent(projectId)}/next`;
|
|
87
|
-
const body = nextBuildRequestBody({ manifest, files: source.files, commit: provenance.gitCommit, provenance, repository, repositoryId, sourceRoot, channel });
|
|
88
|
-
|
|
87
|
+
const body = nextBuildRequestBody({ manifest, files: source.files, commit: provenance.gitCommit, provenance, repository, repositoryId, sourceEnvironment, sourceRoot, channel });
|
|
88
|
+
if (sourceEnvironment && !sourceToken)
|
|
89
|
+
throw new Error('Cross-environment builds require a separately authenticated source session.');
|
|
90
|
+
const response = operationSchema.parse(await postJson({ baseUrl, token: await getToken(), path: `${path}/builds${repositoryId ? '/from-repository' : ''}`, body, ...(sourceEnvironment ? { headers: { 'x-sequence-source-authorization': `Bearer ${sourceToken}` } } : {}) }));
|
|
91
|
+
if (sourceEnvironment)
|
|
92
|
+
console.log(`[seq-studio] source: ${sourceEnvironment} / ${repository} -> target: ${baseUrl}`);
|
|
89
93
|
const directory = repositoryId && sourceRoot !== '.' ? ` (${sourceRoot})` : '';
|
|
90
94
|
console.log(`[seq-studio] Atlas build ${response.operation.id} (${channel}) from ${provenance.gitCommit.slice(0, 12)}${directory}`);
|
|
91
95
|
console.log(`${baseUrl}/artifact-studio/projects/${projectId}`);
|
package/dist/sdk.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ export interface SequenceApiFetchResponse<TBody = unknown> {
|
|
|
44
44
|
headers?: Record<string, string>;
|
|
45
45
|
}
|
|
46
46
|
export interface SequenceApiUploadOptions {
|
|
47
|
+
/** Multipart binary field name. Defaults to file. */
|
|
48
|
+
fieldName?: string;
|
|
47
49
|
timeoutMs?: number;
|
|
48
50
|
/**
|
|
49
51
|
* HTTP method for the multipart request. Defaults to POST; PUT is allowed
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {},
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@sequenceholdings/artifact-studio": "^0.
|
|
13
|
+
"@sequenceholdings/artifact-studio": "^0.9.0",
|
|
14
14
|
"@sequenceholdings/atlas-ui": "^3.1.1",
|
|
15
15
|
"@tailwindcss/postcss": "^4.2.2",
|
|
16
16
|
"@tailwindcss/vite": "^4.2.2",
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.9.1",
|
|
13
13
|
"description": "SDK types and CLI library for building Artifact Studio apps. Driven via `seq-studio artifact <sub>` (@sequenceholdings/studio-cli), which runs the `./cli` runCli export.",
|
|
14
14
|
"type": "module",
|
|
15
15
|
"exports": {
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"server-only": "0.0.1",
|
|
169
169
|
"parse5": "7.3.0",
|
|
170
170
|
"@sequenceholdings/lattice-form-renderer": "0.2.0",
|
|
171
|
-
"@sequenceholdings/storage": "0.1.
|
|
171
|
+
"@sequenceholdings/storage": "0.1.2",
|
|
172
172
|
"@sequenceholdings/orm": "2.6.2"
|
|
173
173
|
},
|
|
174
174
|
"devDependencies": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {},
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@sequenceholdings/artifact-studio": "^0.
|
|
13
|
+
"@sequenceholdings/artifact-studio": "^0.9.0",
|
|
14
14
|
"@sequenceholdings/atlas-ui": "^3.1.1",
|
|
15
15
|
"@tailwindcss/postcss": "^4.2.2",
|
|
16
16
|
"@tailwindcss/vite": "^4.2.2",
|