@sequenceholdings/artifact-studio 0.6.4 → 0.6.7
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 +254 -10
- package/VERSION-PIN.md +78 -1
- package/dist/gateway/admission.d.ts +23 -1
- package/dist/gateway/admission.js +30 -13
- package/dist/gateway/control.d.ts +40 -0
- package/dist/gateway/control.js +76 -7
- package/dist/gateway/hosted-proxy.d.ts +11 -8
- package/dist/gateway/hosted-proxy.js +99 -91
- package/dist/gateway/ingress-admission.d.ts +77 -0
- package/dist/gateway/ingress-admission.js +150 -0
- package/dist/gateway/ingress-audit.d.ts +46 -0
- package/dist/gateway/ingress-audit.js +84 -0
- package/dist/gateway/ingress-context.d.ts +57 -0
- package/dist/gateway/ingress-context.js +57 -0
- package/dist/gateway/ingress-development.d.ts +12 -0
- package/dist/gateway/ingress-development.js +23 -0
- package/dist/gateway/ingress-handler.d.ts +44 -0
- package/dist/gateway/ingress-handler.js +320 -0
- package/dist/gateway/ingress-pass.d.ts +83 -0
- package/dist/gateway/ingress-pass.js +143 -0
- package/dist/gateway/ingress-response.d.ts +74 -0
- package/dist/gateway/ingress-response.js +98 -0
- package/dist/gateway/ingress-runtime.d.ts +86 -0
- package/dist/gateway/ingress-runtime.js +126 -0
- package/dist/gateway/ingress-snapshot.d.ts +54 -0
- package/dist/gateway/ingress-snapshot.js +63 -0
- package/dist/gateway/ingress-stages.d.ts +60 -0
- package/dist/gateway/ingress-stages.js +387 -0
- package/dist/gateway/ingress.d.ts +259 -0
- package/dist/gateway/ingress.js +204 -0
- package/dist/gateway/lattice-invoke.js +2 -0
- package/dist/gateway/lattice-upstream.d.ts +3 -4
- package/dist/gateway/lattice-upstream.js +11 -9
- package/dist/gateway/runtime-transport.d.ts +17 -0
- package/dist/gateway/runtime-transport.js +26 -0
- package/dist/gateway/server.d.ts +3 -0
- package/dist/gateway/server.js +21 -0
- package/dist/gateway/session-response.d.ts +15 -0
- package/dist/gateway/session-response.js +40 -0
- package/dist/gateway/usage.d.ts +8 -1
- package/dist/gateway-main.js +32 -8
- package/dist/manifest-next-browser-data.d.ts +17 -0
- package/dist/manifest-next-browser-data.js +46 -0
- package/dist/manifest-next-ingress.d.ts +5 -2
- package/dist/manifest-next-ingress.js +27 -2
- package/dist/manifest-next.d.ts +27 -10
- package/dist/manifest-next.js +16 -5
- package/dist/manifest.d.ts +13 -6
- package/dist/next-project.d.ts +4 -0
- package/dist/sdk.d.ts +12 -3
- package/dist/server/broker-contract.d.ts +62 -0
- package/dist/server/broker-contract.js +43 -1
- package/dist/server/client.js +38 -13
- package/dist/server/external-context.d.ts +8 -1
- package/dist/server/external-context.js +7 -2
- package/dist/server/internal/v1-context.js +17 -1
- package/dist/server/internal/verify-any.d.ts +25 -2
- package/dist/server/internal/verify-any.js +38 -4
- package/dist/server/process-run-sharing.d.ts +86 -0
- package/dist/server/process-run-sharing.js +29 -0
- package/dist/server/process-runs-page.d.ts +39 -0
- package/dist/server/process-runs-page.js +10 -0
- package/dist/server/processes.d.ts +8 -9
- package/dist/server/processes.js +4 -0
- package/dist/server/request-context.js +10 -3
- package/dist/server/runtime-config.d.ts +10 -1
- package/dist/server/runtime-config.js +11 -1
- package/dist/server/testing.d.ts +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1 -1
- package/dist/tunnel/broker.d.ts +18 -0
- package/dist/tunnel/broker.js +175 -17
- package/dist/tunnel/client.d.ts +13 -0
- package/dist/tunnel/client.js +40 -2
- package/dist/tunnel/external.d.ts +51 -0
- package/dist/tunnel/external.js +10 -0
- package/dist/tunnel/index.d.ts +1 -1
- package/dist/tunnel/protocol.d.ts +20 -2
- package/dist/tunnel/protocol.js +42 -6
- package/package.json +5 -5
|
@@ -6,11 +6,16 @@ import { verifyAnyArtifactContext } from './internal/verify-any.js';
|
|
|
6
6
|
* bound to the one route it was signed for. Refuses a v1 context (`external_context_required`)
|
|
7
7
|
* and a context from an ingress the handler did not name (`external_ingress_not_accepted`).
|
|
8
8
|
*/
|
|
9
|
-
export function verifyArtifactExternalContext({ token, publicKeys, projectId, environment, method, path, accept, now }) {
|
|
9
|
+
export function verifyArtifactExternalContext({ token, publicKeys, projectId, environment, method, path, accept, developmentSessionId, now }) {
|
|
10
10
|
if (!method || !path)
|
|
11
11
|
throw new ArtifactContextError();
|
|
12
12
|
// verifyAnyArtifactContext canonicalises `path` (canonicalizeIngressPath) before comparing it.
|
|
13
|
-
|
|
13
|
+
// A direct property, not a conditional spread: a spread member escapes excess-property
|
|
14
|
+
// checks, so a renamed verifier option would silently refuse every development context.
|
|
15
|
+
const context = verifyAnyArtifactContext({
|
|
16
|
+
token, publicKeys, projectId, environment, method, path, now,
|
|
17
|
+
development: developmentSessionId ? { sessionId: developmentSessionId } : undefined,
|
|
18
|
+
});
|
|
14
19
|
if (context.v !== 2)
|
|
15
20
|
throw new ArtifactContextError('external_context_required');
|
|
16
21
|
if (!accept.external.includes(context.principal.ingress))
|
|
@@ -15,7 +15,7 @@ export function parseV1Context({ payload, projectId, environment, method, path,
|
|
|
15
15
|
const context = parsed.data;
|
|
16
16
|
if (context.projectId !== projectId || context.environment !== environment ||
|
|
17
17
|
context.exp <= now || context.iat > now + 5 ||
|
|
18
|
-
(method !== undefined && context.method !== method.toUpperCase()) || (path !== undefined && context.path
|
|
18
|
+
(method !== undefined && context.method !== method.toUpperCase()) || (path !== undefined && !sameRequestTarget({ signed: context.path, actual: path })))
|
|
19
19
|
throw new ArtifactContextError();
|
|
20
20
|
Object.freeze(context.bridge);
|
|
21
21
|
Object.freeze(context.lattice);
|
|
@@ -24,3 +24,19 @@ export function parseV1Context({ payload, projectId, environment, method, path,
|
|
|
24
24
|
Object.freeze(context.taskRoutes);
|
|
25
25
|
return Object.freeze(context);
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The gateway signs the raw request target; a hosted Next.js handler only sees its query
|
|
29
|
+
* re-serialized (`:` → `%3A`, a space → `+`). The pathname must match exactly; the query
|
|
30
|
+
* matches when it carries the same parameters, in the same order, however it is encoded.
|
|
31
|
+
*/
|
|
32
|
+
function sameRequestTarget({ signed, actual }) {
|
|
33
|
+
if (signed === actual)
|
|
34
|
+
return true;
|
|
35
|
+
const [signedPath, signedQuery = ''] = splitTarget(signed);
|
|
36
|
+
const [actualPath, actualQuery = ''] = splitTarget(actual);
|
|
37
|
+
return signedPath === actualPath && new URLSearchParams(signedQuery).toString() === new URLSearchParams(actualQuery).toString();
|
|
38
|
+
}
|
|
39
|
+
function splitTarget(target) {
|
|
40
|
+
const separator = target.indexOf('?');
|
|
41
|
+
return separator === -1 ? [target] : [target.slice(0, separator), target.slice(separator + 1)];
|
|
42
|
+
}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { type ArtifactGatewayPublicKeys, type ArtifactRequestContext, type RequestContextV2External } from '../request-context.js';
|
|
2
2
|
export type AnyArtifactRequestContext = ArtifactRequestContext | RequestContextV2External;
|
|
3
|
+
/**
|
|
4
|
+
* Optional human-directory prefetch for hosted admission, never an authorization result. The
|
|
5
|
+
* signed project is not yet bound to the credential's database record. After loading that record,
|
|
6
|
+
* the caller must still run its ordinary verifier with the runtime's keys and authoritative
|
|
7
|
+
* project, rechecking the clock after the await. Ineligible or invalid contexts return null so
|
|
8
|
+
* credential failures and external admission keep their existing checks and error ordering.
|
|
9
|
+
*/
|
|
10
|
+
export declare function preverifyHostedBrowserContext({ token, publicKeys, environment, deploymentId, now }: {
|
|
11
|
+
token: string | null;
|
|
12
|
+
publicKeys: ArtifactGatewayPublicKeys;
|
|
13
|
+
environment: string;
|
|
14
|
+
deploymentId: string;
|
|
15
|
+
now?: number;
|
|
16
|
+
}): ArtifactRequestContext | null;
|
|
3
17
|
/**
|
|
4
18
|
* Version-dispatching verifier for platform code that must accept both Atlas-user (v1) and
|
|
5
19
|
* external (v2) contexts, such as the broker. Applications never get this: it is not exported
|
|
@@ -11,14 +25,23 @@ export type AnyArtifactRequestContext = ArtifactRequestContext | RequestContextV
|
|
|
11
25
|
* context must be signed by an `external-` kid. This pairing is the only thing standing between
|
|
12
26
|
* an `external-` kid and the v1 rules: the v1 branch goes straight to the shared v1 parser, not
|
|
13
27
|
* through the public verifier's own external gate. A v2 context in `development` mode is refused
|
|
14
|
-
*
|
|
28
|
+
* unless the caller names the one development session it serves (`development`), and then only
|
|
29
|
+
* for that session; the kid pairing above already confines it to an `external-` kid. The
|
|
30
|
+
* signature is checked once per call.
|
|
15
31
|
*/
|
|
16
|
-
export declare function verifyAnyArtifactContext({ token, publicKeys, projectId, environment, method, path, now }: {
|
|
32
|
+
export declare function verifyAnyArtifactContext({ token, publicKeys, projectId, environment, method, path, development, now }: {
|
|
17
33
|
token: string | null;
|
|
18
34
|
publicKeys: ArtifactGatewayPublicKeys;
|
|
19
35
|
projectId: string;
|
|
20
36
|
environment: string;
|
|
21
37
|
method?: string;
|
|
22
38
|
path?: string;
|
|
39
|
+
/**
|
|
40
|
+
* The development session this caller serves. Pass it only from a development lease (the SDK)
|
|
41
|
+
* or, in Atlas, only under APP_ENV=development; never from a value the request carries.
|
|
42
|
+
*/
|
|
43
|
+
development?: {
|
|
44
|
+
sessionId: string;
|
|
45
|
+
};
|
|
23
46
|
now?: number;
|
|
24
47
|
}): AnyArtifactRequestContext;
|
|
@@ -1,7 +1,33 @@
|
|
|
1
|
-
import { ArtifactContextError, requestContextV2ExternalSchema, } from '../request-context.js';
|
|
1
|
+
import { ArtifactContextError, ARTIFACT_SERVICE_ACCOUNT_SUB_PREFIX, artifactRequestContextSchema, requestContextV2ExternalSchema, } from '../request-context.js';
|
|
2
2
|
import { ARTIFACT_EXTERNAL_CONTEXT_KID_PREFIX, verifySignedContext } from './signed-token.js';
|
|
3
3
|
import { parseV1Context } from './v1-context.js';
|
|
4
4
|
import { canonicalizeIngressPath, signedIngressPath } from '../ingress-routes.js';
|
|
5
|
+
/**
|
|
6
|
+
* Optional human-directory prefetch for hosted admission, never an authorization result. The
|
|
7
|
+
* signed project is not yet bound to the credential's database record. After loading that record,
|
|
8
|
+
* the caller must still run its ordinary verifier with the runtime's keys and authoritative
|
|
9
|
+
* project, rechecking the clock after the await. Ineligible or invalid contexts return null so
|
|
10
|
+
* credential failures and external admission keep their existing checks and error ordering.
|
|
11
|
+
*/
|
|
12
|
+
export function preverifyHostedBrowserContext({ token, publicKeys, environment, deploymentId, now = Math.floor(Date.now() / 1000) }) {
|
|
13
|
+
try {
|
|
14
|
+
const { kid, payload } = verifySignedContext({ token, publicKeys });
|
|
15
|
+
if (kid.startsWith(ARTIFACT_EXTERNAL_CONTEXT_KID_PREFIX))
|
|
16
|
+
return null;
|
|
17
|
+
const parsed = artifactRequestContextSchema.safeParse(payload);
|
|
18
|
+
if (!parsed.success)
|
|
19
|
+
return null;
|
|
20
|
+
const context = parsed.data;
|
|
21
|
+
if (context.mode === 'development' || context.deploymentId !== deploymentId ||
|
|
22
|
+
context.sub.startsWith(ARTIFACT_SERVICE_ACCOUNT_SUB_PREFIX))
|
|
23
|
+
return null;
|
|
24
|
+
// Self-binding is safe only for this prefetch: ordinary admission binds the stored project.
|
|
25
|
+
return parseV1Context({ payload: context, projectId: context.projectId, environment, now });
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
5
31
|
/**
|
|
6
32
|
* Version-dispatching verifier for platform code that must accept both Atlas-user (v1) and
|
|
7
33
|
* external (v2) contexts, such as the broker. Applications never get this: it is not exported
|
|
@@ -13,9 +39,11 @@ import { canonicalizeIngressPath, signedIngressPath } from '../ingress-routes.js
|
|
|
13
39
|
* context must be signed by an `external-` kid. This pairing is the only thing standing between
|
|
14
40
|
* an `external-` kid and the v1 rules: the v1 branch goes straight to the shared v1 parser, not
|
|
15
41
|
* through the public verifier's own external gate. A v2 context in `development` mode is refused
|
|
16
|
-
*
|
|
42
|
+
* unless the caller names the one development session it serves (`development`), and then only
|
|
43
|
+
* for that session; the kid pairing above already confines it to an `external-` kid. The
|
|
44
|
+
* signature is checked once per call.
|
|
17
45
|
*/
|
|
18
|
-
export function verifyAnyArtifactContext({ token, publicKeys, projectId, environment, method, path, now = Math.floor(Date.now() / 1000) }) {
|
|
46
|
+
export function verifyAnyArtifactContext({ token, publicKeys, projectId, environment, method, path, development, now = Math.floor(Date.now() / 1000) }) {
|
|
19
47
|
let kid;
|
|
20
48
|
let payload;
|
|
21
49
|
try {
|
|
@@ -34,7 +62,7 @@ export function verifyAnyArtifactContext({ token, publicKeys, projectId, environ
|
|
|
34
62
|
if (!parsed.success)
|
|
35
63
|
throw new ArtifactContextError();
|
|
36
64
|
const context = parsed.data;
|
|
37
|
-
if (context
|
|
65
|
+
if (!modeAccepted({ context, development }))
|
|
38
66
|
throw new ArtifactContextError('external_mode_not_accepted');
|
|
39
67
|
// The gateway signs only a canonical path (plus its raw query); the caller's path is
|
|
40
68
|
// canonicalised the same way before comparing, so an encoded or dot-segment variant never binds.
|
|
@@ -46,6 +74,12 @@ export function verifyAnyArtifactContext({ token, publicKeys, projectId, environ
|
|
|
46
74
|
throw new ArtifactContextError();
|
|
47
75
|
return freezeExternalContext(context);
|
|
48
76
|
}
|
|
77
|
+
/** `published` always; `development` only for the one development session the caller names. */
|
|
78
|
+
function modeAccepted({ context, development }) {
|
|
79
|
+
if (context.mode === 'published')
|
|
80
|
+
return true;
|
|
81
|
+
return development !== undefined && context.devSessionId === development.sessionId;
|
|
82
|
+
}
|
|
49
83
|
function signedPathOf(raw) {
|
|
50
84
|
const canonical = canonicalizeIngressPath(raw);
|
|
51
85
|
return canonical && signedIngressPath(canonical);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type ArtifactServerMode, type ArtifactServerRequest } from './broker-contract.js';
|
|
2
|
+
/** Users (Auth0 `sub`) and chat groups (group id) to name in an assignment or a share. */
|
|
3
|
+
export interface ArtifactProcessPrincipals {
|
|
4
|
+
users?: string[];
|
|
5
|
+
groups?: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface ArtifactProcessRunViewerChange extends ArtifactProcessPrincipals {
|
|
8
|
+
runId: string;
|
|
9
|
+
}
|
|
10
|
+
/** Add collaborators to selected human nodes without replacing their existing run assignments. */
|
|
11
|
+
export interface ArtifactProcessShareRun extends ArtifactProcessPrincipals {
|
|
12
|
+
runId: string;
|
|
13
|
+
/** Explicitly assigned human nodes of this run, at most ARTIFACT_PROCESS_SHARE_NODES_LIMIT. */
|
|
14
|
+
nodeIds: string[];
|
|
15
|
+
/** Explicitly permit these users to share full-run viewing and the same or fewer nodes within this app's live audience. */
|
|
16
|
+
delegateSharing?: {
|
|
17
|
+
audience: 'current_app';
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface ArtifactProcessShareRunResult {
|
|
21
|
+
run_id: string;
|
|
22
|
+
nodes_updated: string[];
|
|
23
|
+
users: string[];
|
|
24
|
+
groups: string[];
|
|
25
|
+
/** True when the sharing grants have been applied; pending authorization rejects with 503. */
|
|
26
|
+
authorization_applied: boolean;
|
|
27
|
+
/** The root authority created or used by an explicitly delegated share. */
|
|
28
|
+
sharingAuthorityId?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ArtifactProcessRunSharingAuthoritiesQuery {
|
|
31
|
+
runId: string;
|
|
32
|
+
/** Default 20, at most ARTIFACT_PROCESS_SHARING_AUTHORITIES_LIMIT (50). */
|
|
33
|
+
limit?: number;
|
|
34
|
+
/** Authority id from the previous page's nextCursor. */
|
|
35
|
+
cursor?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ArtifactProcessRunSharingDelegate {
|
|
38
|
+
user_sub: string;
|
|
39
|
+
node_ids: string[];
|
|
40
|
+
granted_by: string;
|
|
41
|
+
granted_at: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ArtifactProcessRunSharingAuthority {
|
|
44
|
+
id: string;
|
|
45
|
+
run_id: string;
|
|
46
|
+
bundle_hash: string;
|
|
47
|
+
node_ids: string[];
|
|
48
|
+
audience: {
|
|
49
|
+
kind: 'artifact_project';
|
|
50
|
+
project_id: string;
|
|
51
|
+
};
|
|
52
|
+
created_by: string;
|
|
53
|
+
created_at: string;
|
|
54
|
+
revoked_at: string | null;
|
|
55
|
+
/** At most 100 individual delegates under this root authority. */
|
|
56
|
+
delegates: ArtifactProcessRunSharingDelegate[];
|
|
57
|
+
}
|
|
58
|
+
export interface ArtifactProcessRunSharingAuthoritiesPage {
|
|
59
|
+
authorities: ArtifactProcessRunSharingAuthority[];
|
|
60
|
+
nextCursor: string | null;
|
|
61
|
+
}
|
|
62
|
+
export interface ArtifactProcessRevokeRunSharingAuthority {
|
|
63
|
+
runId: string;
|
|
64
|
+
authorityId: string;
|
|
65
|
+
}
|
|
66
|
+
export interface ArtifactProcessRevokeRunSharingAuthorityResult {
|
|
67
|
+
authority_id: string;
|
|
68
|
+
revoked: true;
|
|
69
|
+
}
|
|
70
|
+
export interface ArtifactRunSharingOperations {
|
|
71
|
+
/** Add collaborators and full-run viewing; owners may explicitly authorize scoped onward sharing. */
|
|
72
|
+
shareRun(input: ArtifactProcessShareRun): Promise<ArtifactProcessShareRunResult>;
|
|
73
|
+
/** Owner-only, user-mode page of this run's sharing authorities and their delegates. */
|
|
74
|
+
listRunSharingAuthorities(query: ArtifactProcessRunSharingAuthoritiesQuery): Promise<ArtifactProcessRunSharingAuthoritiesPage>;
|
|
75
|
+
/** Owner-only, idempotent revocation of onward sharing; existing viewing and step access remain. */
|
|
76
|
+
revokeRunSharingAuthority(input: ArtifactProcessRevokeRunSharingAuthority): Promise<ArtifactProcessRevokeRunSharingAuthorityResult>;
|
|
77
|
+
}
|
|
78
|
+
export declare function shareArtifactProcessRun({ mode, json, input }: {
|
|
79
|
+
mode: ArtifactServerMode;
|
|
80
|
+
json: (operation: ArtifactServerRequest) => Promise<unknown>;
|
|
81
|
+
input: ArtifactProcessShareRun;
|
|
82
|
+
}): Promise<ArtifactProcessShareRunResult>;
|
|
83
|
+
export declare function createArtifactProcessSharingClient({ mode, json }: {
|
|
84
|
+
mode: ArtifactServerMode;
|
|
85
|
+
json: (operation: ArtifactServerRequest) => Promise<unknown>;
|
|
86
|
+
}): ArtifactRunSharingOperations;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { artifactServerRequestSchema } from './broker-contract.js';
|
|
2
|
+
import { ArtifactServerError } from './errors.js';
|
|
3
|
+
export async function shareArtifactProcessRun({ mode, json, input }) {
|
|
4
|
+
// Atlas owns assignment validation; its wire result names the optional authority in snake case.
|
|
5
|
+
const body = await json(artifactServerRequestSchema.parse({ operation: 'lattice_share_run', mode, ...input }));
|
|
6
|
+
const { sharing_authority_id, ...shared } = body;
|
|
7
|
+
if (sharing_authority_id !== undefined && typeof sharing_authority_id !== 'string') {
|
|
8
|
+
throw new ArtifactServerError(502, 'malformed_response', 'Atlas returned a malformed sharing authority id');
|
|
9
|
+
}
|
|
10
|
+
return { ...shared, ...(sharing_authority_id === undefined ? {} : { sharingAuthorityId: sharing_authority_id }) };
|
|
11
|
+
}
|
|
12
|
+
export function createArtifactProcessSharingClient({ mode, json }) {
|
|
13
|
+
return {
|
|
14
|
+
shareRun: (input) => shareArtifactProcessRun({ mode, json, input }),
|
|
15
|
+
listRunSharingAuthorities: async (query) => {
|
|
16
|
+
// Atlas returns the owner-authorized records; the SDK maps only the continuation envelope.
|
|
17
|
+
const body = await json(artifactServerRequestSchema.parse({ operation: 'lattice_sharing_authorities', mode, ...query }));
|
|
18
|
+
if (!Array.isArray(body?.authorities) || !(typeof body.next_cursor === 'string' || body.next_cursor === null)) {
|
|
19
|
+
throw new ArtifactServerError(502, 'malformed_response', 'Atlas returned a malformed sharing authority page');
|
|
20
|
+
}
|
|
21
|
+
// Record projection and authority checks belong to Atlas, as with the other process lists.
|
|
22
|
+
return { authorities: body.authorities, nextCursor: body.next_cursor };
|
|
23
|
+
},
|
|
24
|
+
revokeRunSharingAuthority: async (input) => {
|
|
25
|
+
// The owner-authorized service returns its idempotent revocation receipt.
|
|
26
|
+
return await json(artifactServerRequestSchema.parse({ operation: 'lattice_sharing_authority_revoke', mode, ...input }));
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ArtifactProcessRunStatus, type ArtifactServerMode, type ArtifactServerRequest } from './broker-contract.js';
|
|
2
|
+
import type { ArtifactProcessRunRecord } from './processes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Page visible runs of one declared process; filters stay the same while following its cursor.
|
|
5
|
+
* Atlas establishes the caller's complete authorization scope before selecting run rows.
|
|
6
|
+
* Unavailable authorization, an unsupported authorization model, or an incomplete grant scope
|
|
7
|
+
* returns 503 without partial runs or a cursor.
|
|
8
|
+
*/
|
|
9
|
+
export interface ArtifactProcessRunsPageQuery {
|
|
10
|
+
process: string;
|
|
11
|
+
statuses?: ArtifactProcessRunStatus[];
|
|
12
|
+
/** One entity type, optionally narrowed to one id or a set of up to 500 ids. */
|
|
13
|
+
entity?: {
|
|
14
|
+
type: string;
|
|
15
|
+
id?: string;
|
|
16
|
+
ids?: string[];
|
|
17
|
+
};
|
|
18
|
+
/** Maximum returned visible runs per page, default 100 and at most ARTIFACT_PROCESS_RUNS_LIMIT (500). */
|
|
19
|
+
limit?: number;
|
|
20
|
+
/** Encrypted continuation bound to this principal and these filters; expires after one hour. */
|
|
21
|
+
cursor?: string;
|
|
22
|
+
/** Soft-archived runs only, instead of the default active ones. */
|
|
23
|
+
archived?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** A compact activity-list row; read the run separately for its state, output and steps. */
|
|
26
|
+
export type ArtifactProcessRunSummary = Pick<ArtifactProcessRunRecord, 'id' | 'processId' | 'status' | 'entityType' | 'entityId' | 'startedAt' | 'completedAt' | 'error'>;
|
|
27
|
+
export interface ArtifactProcessRunsPage {
|
|
28
|
+
runs: ArtifactProcessRunSummary[];
|
|
29
|
+
/**
|
|
30
|
+
* Continues after the last returned visible run only when another visible run exists.
|
|
31
|
+
* Null ends the list; a successful empty page always has null.
|
|
32
|
+
*/
|
|
33
|
+
nextCursor: string | null;
|
|
34
|
+
}
|
|
35
|
+
export declare function readArtifactProcessRunsPage({ mode, json, query }: {
|
|
36
|
+
mode: ArtifactServerMode;
|
|
37
|
+
json: (operation: ArtifactServerRequest) => Promise<unknown>;
|
|
38
|
+
query: ArtifactProcessRunsPageQuery;
|
|
39
|
+
}): Promise<ArtifactProcessRunsPage>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { artifactServerRequestSchema } from './broker-contract.js';
|
|
2
|
+
import { ArtifactServerError } from './errors.js';
|
|
3
|
+
export async function readArtifactProcessRunsPage({ mode, json, query }) {
|
|
4
|
+
const body = await json(artifactServerRequestSchema.parse({ operation: 'lattice_runs_page', mode, ...query }));
|
|
5
|
+
if (!Array.isArray(body?.runs) || !(typeof body.nextCursor === 'string' || body.nextCursor === null)) {
|
|
6
|
+
throw new ArtifactServerError(502, 'malformed_response', 'Atlas returned a malformed run page');
|
|
7
|
+
}
|
|
8
|
+
// Atlas owns row projection and visibility filtering; the SDK preserves its continuation.
|
|
9
|
+
return body;
|
|
10
|
+
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { type ArtifactProcessPrincipalType, type ArtifactProcessRunStatus, type ArtifactProcessTaskView, type ArtifactServerMode, type ArtifactServerRequest } from './broker-contract.js';
|
|
2
|
+
import { type ArtifactProcessRunsPage, type ArtifactProcessRunsPageQuery } from './process-runs-page.js';
|
|
3
|
+
import { type ArtifactProcessPrincipals, type ArtifactProcessRunViewerChange, type ArtifactRunSharingOperations } from './process-run-sharing.js';
|
|
4
|
+
export type { ArtifactProcessRunSummary, ArtifactProcessRunsPage, ArtifactProcessRunsPageQuery } from './process-runs-page.js';
|
|
5
|
+
export type { ArtifactProcessPrincipals, ArtifactProcessRunViewerChange, ArtifactProcessShareRun, ArtifactProcessShareRunResult } from './process-run-sharing.js';
|
|
6
|
+
export type { ArtifactProcessRunSharingAuthoritiesQuery, ArtifactProcessRunSharingAuthoritiesPage, ArtifactProcessRunSharingAuthority, ArtifactProcessRunSharingDelegate, ArtifactProcessRevokeRunSharingAuthority, ArtifactProcessRevokeRunSharingAuthorityResult } from './process-run-sharing.js';
|
|
2
7
|
/** A run of a process declared under `server.capabilities.processes.start`. */
|
|
3
8
|
export interface ArtifactProcessStart {
|
|
4
9
|
process: string;
|
|
@@ -264,11 +269,6 @@ export interface ArtifactProcessRunEvents {
|
|
|
264
269
|
/** Pass as `since` on the next poll. Null only when the run has no events yet and no `since` was given. */
|
|
265
270
|
cursor: string | null;
|
|
266
271
|
}
|
|
267
|
-
/** Users (Auth0 `sub`) and chat groups (group id) to name in an assignment or a share. */
|
|
268
|
-
export interface ArtifactProcessPrincipals {
|
|
269
|
-
users?: string[];
|
|
270
|
-
groups?: string[];
|
|
271
|
-
}
|
|
272
272
|
/** Reassigning a parked human step: the step's advancers become exactly these principals. */
|
|
273
273
|
export interface ArtifactProcessAssign extends ArtifactProcessPrincipals {
|
|
274
274
|
runId: string;
|
|
@@ -288,9 +288,6 @@ export interface ArtifactProcessRunViewers {
|
|
|
288
288
|
users: string[];
|
|
289
289
|
groups: string[];
|
|
290
290
|
}
|
|
291
|
-
export interface ArtifactProcessRunViewerChange extends ArtifactProcessPrincipals {
|
|
292
|
-
runId: string;
|
|
293
|
-
}
|
|
294
291
|
export interface ArtifactProcessPrincipalSearch {
|
|
295
292
|
/** Empty browses the first `limit` users; 1–2 characters match groups only; 3+ search the directory. */
|
|
296
293
|
q: string;
|
|
@@ -309,11 +306,13 @@ export interface ArtifactProcessPrincipal {
|
|
|
309
306
|
/** Groups: active members. */
|
|
310
307
|
memberCount?: number;
|
|
311
308
|
}
|
|
312
|
-
export interface ArtifactServerProcesses {
|
|
309
|
+
export interface ArtifactServerProcesses extends ArtifactRunSharingOperations {
|
|
313
310
|
/** Start a run of a process declared under `processes.start`; the user's Invoker grant decides. */
|
|
314
311
|
start(input: ArtifactProcessStart): Promise<ArtifactProcessRun>;
|
|
315
312
|
/** List the runs of a process declared under `processes.read` that the user may view. */
|
|
316
313
|
listRuns(query: ArtifactProcessRunsQuery): Promise<ArtifactProcessRunRecord[]>;
|
|
314
|
+
/** Page compact run summaries the user may view; nextCursor names a continuation only when more visible runs exist. */
|
|
315
|
+
listRunsPage(query: ArtifactProcessRunsPageQuery): Promise<ArtifactProcessRunsPage>;
|
|
317
316
|
/** Read one run of a process declared under `processes.read`; the user's Viewer relation on the run decides. */
|
|
318
317
|
getRun(runId: string): Promise<ArtifactProcessRunSnapshot>;
|
|
319
318
|
/** Describe a process declared under `processes.read`; the user's Viewer relation on the process decides. */
|
package/dist/server/processes.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { artifactServerRequestSchema, } from './broker-contract.js';
|
|
2
2
|
import { ArtifactServerError } from './errors.js';
|
|
3
|
+
import { readArtifactProcessRunsPage } from './process-runs-page.js';
|
|
4
|
+
import { createArtifactProcessSharingClient } from './process-run-sharing.js';
|
|
3
5
|
/** `client.processes`: Lattice through the broker's typed `lattice*` operations. Atlas owns validation and redaction. */
|
|
4
6
|
export function createArtifactProcessesClient({ mode, json }) {
|
|
5
7
|
return {
|
|
@@ -14,6 +16,7 @@ export function createArtifactProcessesClient({ mode, json }) {
|
|
|
14
16
|
throw new ArtifactServerError(502, 'malformed_response', 'Atlas returned a malformed run list');
|
|
15
17
|
return body.runs;
|
|
16
18
|
},
|
|
19
|
+
listRunsPage: (query) => readArtifactProcessRunsPage({ mode, json, query }),
|
|
17
20
|
getRun: async (runId) => {
|
|
18
21
|
// The Lattice run-detail response; Atlas owns redaction and node-state derivation.
|
|
19
22
|
return await json(artifactServerRequestSchema.parse({ operation: 'lattice_run', mode, runId }));
|
|
@@ -36,6 +39,7 @@ export function createArtifactProcessesClient({ mode, json }) {
|
|
|
36
39
|
assign: async (input) => {
|
|
37
40
|
return await json(artifactServerRequestSchema.parse({ operation: 'lattice_assign', mode, ...input }));
|
|
38
41
|
},
|
|
42
|
+
...createArtifactProcessSharingClient({ mode, json }),
|
|
39
43
|
cancel: async (runId) => {
|
|
40
44
|
return await json(artifactServerRequestSchema.parse({ operation: 'lattice_cancel', mode, runId }));
|
|
41
45
|
},
|
|
@@ -72,8 +72,15 @@ export const ARTIFACT_SERVICE_ACCOUNT_SUB_PREFIX = 'service-account|';
|
|
|
72
72
|
export const ARTIFACT_EXTERNAL_CONTEXT_MAX_AGE_SECONDS = 60;
|
|
73
73
|
/** An IPv4 or IPv6 address, as the gateway observed it. The control contract reuses it. */
|
|
74
74
|
export const artifactIpAddressSchema = z.union([z.ipv4(), z.ipv6()]);
|
|
75
|
+
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
75
76
|
/** Signed by the gateway after it strips control characters and truncates; refused here otherwise. */
|
|
76
|
-
const observedUserAgent = z.string().max(512).refine(value =>
|
|
77
|
+
const observedUserAgent = z.string().max(512).refine(value => !CONTROL_CHARACTERS.test(value), 'Expected a user agent without control characters');
|
|
78
|
+
/**
|
|
79
|
+
* The principal's subject and email become the ORM's row-policy claims (`ext_subject`, `ext_email`),
|
|
80
|
+
* which refuse control characters; refusing them here keeps such a context a 401 at verification
|
|
81
|
+
* rather than a failure in the middle of a request.
|
|
82
|
+
*/
|
|
83
|
+
const externalSubject = id.refine(value => !CONTROL_CHARACTERS.test(value), 'Expected a subject without control characters');
|
|
77
84
|
/** The external caller as the gateway verified it at pass exchange. Strict: see the v2 key policy below. */
|
|
78
85
|
export const artifactExternalPrincipalSchema = z.object({
|
|
79
86
|
kind: z.literal('external'),
|
|
@@ -81,10 +88,10 @@ export const artifactExternalPrincipalSchema = z.object({
|
|
|
81
88
|
ingress: id,
|
|
82
89
|
provider: id,
|
|
83
90
|
issuer: z.string().min(1).max(2048),
|
|
84
|
-
subject:
|
|
91
|
+
subject: externalSubject,
|
|
85
92
|
clientId: id,
|
|
86
93
|
/** Normalized (trimmed, lowercase) by Atlas at exchange. */
|
|
87
|
-
email: z.string().min(3).max(320).refine(value => value === value.trim().toLowerCase() && value.includes('@'), 'Expected a normalized email'),
|
|
94
|
+
email: z.string().min(3).max(320).refine(value => value === value.trim().toLowerCase() && value.includes('@') && !CONTROL_CHARACTERS.test(value), 'Expected a normalized email'),
|
|
88
95
|
emailVerified: z.literal(true),
|
|
89
96
|
authTime: z.number().int().nonnegative().nullable(),
|
|
90
97
|
amr: z.array(z.string().min(1).max(64)).max(16).nullable(),
|
|
@@ -8,7 +8,16 @@ export declare const artifactRuntimeConfigSchema: z.ZodObject<{
|
|
|
8
8
|
devSessionId: z.ZodOptional<z.ZodString>;
|
|
9
9
|
deploymentId: z.ZodOptional<z.ZodString>;
|
|
10
10
|
}, z.core.$strict>;
|
|
11
|
-
export type ArtifactRuntimeConfig = z.infer<typeof artifactRuntimeConfigSchema
|
|
11
|
+
export type ArtifactRuntimeConfig = z.infer<typeof artifactRuntimeConfigSchema> & {
|
|
12
|
+
/**
|
|
13
|
+
* True only on a configuration read from a development lease: the owner-only file `artifact dev`
|
|
14
|
+
* writes and names in SEQUENCE_ARTIFACT_RUNTIME_FILE (`next-project.ts`), for one development
|
|
15
|
+
* session. Never parsed from JSON, so neither the lease file, the hosted configuration nor an
|
|
16
|
+
* explicit `runtime` option can claim it, and it does not survive a re-parse. Only under it does
|
|
17
|
+
* the SDK accept an external context in `development` mode.
|
|
18
|
+
*/
|
|
19
|
+
readonly development?: true;
|
|
20
|
+
};
|
|
12
21
|
export type ArtifactRequestHeaders = Pick<Headers, 'get'>;
|
|
13
22
|
/** Credentials are platform-provided and rotated by the CLI, never inferred from ambient cloud auth. */
|
|
14
23
|
export declare function readArtifactRuntimeConfig({ file }?: {
|
|
@@ -22,6 +22,16 @@ export const artifactRuntimeConfigSchema = z.object({
|
|
|
22
22
|
devSessionId: z.string().min(1).max(255).optional(),
|
|
23
23
|
deploymentId: z.string().min(1).max(255).optional(),
|
|
24
24
|
}).strict().refine(value => !(value.devSessionId && value.deploymentId), 'Runtime cannot be both local and hosted');
|
|
25
|
+
/**
|
|
26
|
+
* Marks a lease file's configuration. Non-enumerable, so the strict schema still accepts the
|
|
27
|
+
* object if a caller hands it back as an explicit `runtime` (which then drops the marker).
|
|
28
|
+
*/
|
|
29
|
+
function developmentLease(config) {
|
|
30
|
+
// A lease belongs to exactly one development session; anything else is not a development lease.
|
|
31
|
+
if (!config.devSessionId || config.deploymentId)
|
|
32
|
+
return config;
|
|
33
|
+
return Object.defineProperty(config, 'development', { value: true, enumerable: false, writable: false, configurable: false });
|
|
34
|
+
}
|
|
25
35
|
/** Credentials are platform-provided and rotated by the CLI, never inferred from ambient cloud auth. */
|
|
26
36
|
export async function readArtifactRuntimeConfig({ file = process.env.SEQUENCE_ARTIFACT_RUNTIME_FILE } = {}) {
|
|
27
37
|
if (!file) {
|
|
@@ -42,7 +52,7 @@ export async function readArtifactRuntimeConfig({ file = process.env.SEQUENCE_AR
|
|
|
42
52
|
const stat = await handle.stat();
|
|
43
53
|
if (!stat.isFile() || stat.size > 65536 || (process.platform !== 'win32' && ((stat.mode & 0o077) !== 0 || stat.uid !== process.getuid?.())))
|
|
44
54
|
throw new Error('Artifact runtime credential file must be owner-readable only, regular, and no larger than 64 KiB');
|
|
45
|
-
return artifactRuntimeConfigSchema.parse(JSON.parse(await handle.readFile('utf8')));
|
|
55
|
+
return developmentLease(artifactRuntimeConfigSchema.parse(JSON.parse(await handle.readFile('utf8'))));
|
|
46
56
|
}
|
|
47
57
|
finally {
|
|
48
58
|
await handle.close();
|
package/dist/server/testing.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface SignTestExternalContextInput {
|
|
|
19
19
|
/** Overrides on a verified-borrower default principal. */
|
|
20
20
|
principal?: Partial<Omit<ExternalPrincipalClaims, 'kind'>>;
|
|
21
21
|
serviceAccountId: string;
|
|
22
|
-
/** Defaults to `published`. Verifiers
|
|
22
|
+
/** Defaults to `published`. Verifiers accept `development` only under a development lease, for its session. */
|
|
23
23
|
mode?: RequestContextV2External['mode'];
|
|
24
24
|
deploymentId?: string | null;
|
|
25
25
|
devSessionId?: string | null;
|
package/dist/server.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import 'server-only';
|
|
|
2
2
|
export { createArtifactServerClient } from './server/client.js';
|
|
3
3
|
export { ArtifactPrincipalError, ArtifactServerError, INSUFFICIENT_USER_AUTHENTICATION, stepUpResponse } from './server/errors.js';
|
|
4
4
|
export type { ArtifactAtlasRefusal } from './server/errors.js';
|
|
5
|
-
export type { ArtifactAuditEvent, ArtifactOrmOperations, ArtifactOrmOptions, ArtifactProcessAdvance, ArtifactProcessAdvanceResult, ArtifactProcessArtifactRef, ArtifactProcessAssign, ArtifactProcessAssignResult, ArtifactProcessDefinition, ArtifactProcessDescribeQuery, ArtifactProcessEdge, ArtifactProcessHumanNode, ArtifactProcessNode, ArtifactProcessNodeBase, ArtifactProcessNodeState, ArtifactProcessPrincipal, ArtifactProcessPrincipalSearch, ArtifactProcessPrincipals, ArtifactProcessRun, ArtifactProcessRunRecord, ArtifactProcessRunSnapshot, ArtifactProcessRunsQuery, ArtifactProcessRunViewerChange, ArtifactProcessRunViewers, ArtifactProcessStart, ArtifactProcessStepRecord, ArtifactProcessTask, ArtifactProcessTasksQuery, ArtifactServerAudit, ArtifactServerClient, ArtifactServerClientOptions, ArtifactServerContext, ArtifactServerFetchOptions, ArtifactServerFlags, ArtifactServerProcesses, } from './server/client.js';
|
|
6
|
-
export { ARTIFACT_AUDIT_ACTIONS, ARTIFACT_AUDIT_RESOURCES_PER_EVENT, ARTIFACT_FLAGS_PER_REQUEST, ARTIFACT_PROCESS_PRINCIPAL_SEARCH_LIMIT, ARTIFACT_PROCESS_PRINCIPAL_TYPES, ARTIFACT_PROCESS_PRINCIPALS_PER_CALL, ARTIFACT_PROCESS_RUN_STATUSES, ARTIFACT_PROCESS_RUNS_LIMIT, ARTIFACT_PROCESS_TASK_VIEWS, ARTIFACT_PROCESS_TASKS_LIMIT, } from './server/broker-contract.js';
|
|
5
|
+
export type { ArtifactAuditEvent, ArtifactOrmOperations, ArtifactOrmOptions, ArtifactProcessAdvance, ArtifactProcessAdvanceResult, ArtifactProcessArtifactRef, ArtifactProcessAssign, ArtifactProcessAssignResult, ArtifactProcessDefinition, ArtifactProcessDescribeQuery, ArtifactProcessEdge, ArtifactProcessHumanNode, ArtifactProcessNode, ArtifactProcessNodeBase, ArtifactProcessNodeState, ArtifactProcessPrincipal, ArtifactProcessPrincipalSearch, ArtifactProcessPrincipals, ArtifactProcessRun, ArtifactProcessRunRecord, ArtifactProcessRunSnapshot, ArtifactProcessRunSummary, ArtifactProcessRunsPage, ArtifactProcessRunsPageQuery, ArtifactProcessRunsQuery, ArtifactProcessRunViewerChange, ArtifactProcessRunViewers, ArtifactProcessStart, ArtifactProcessStepRecord, ArtifactProcessShareRun, ArtifactProcessShareRunResult, ArtifactProcessRunSharingAuthoritiesQuery, ArtifactProcessRunSharingAuthoritiesPage, ArtifactProcessRunSharingAuthority, ArtifactProcessRunSharingDelegate, ArtifactProcessRevokeRunSharingAuthority, ArtifactProcessRevokeRunSharingAuthorityResult, ArtifactProcessTask, ArtifactProcessTasksQuery, ArtifactServerAudit, ArtifactServerClient, ArtifactServerClientOptions, ArtifactServerContext, ArtifactServerFetchOptions, ArtifactServerFlags, ArtifactServerProcesses, } from './server/client.js';
|
|
6
|
+
export { ARTIFACT_AUDIT_ACTIONS, ARTIFACT_AUDIT_RESOURCES_PER_EVENT, ARTIFACT_FLAGS_PER_REQUEST, ARTIFACT_PROCESS_PRINCIPAL_SEARCH_LIMIT, ARTIFACT_PROCESS_PRINCIPAL_TYPES, ARTIFACT_PROCESS_PRINCIPALS_PER_CALL, ARTIFACT_PROCESS_RUN_STATUSES, ARTIFACT_PROCESS_RUNS_LIMIT, ARTIFACT_PROCESS_RUN_ENTITIES_LIMIT, ARTIFACT_PROCESS_SHARE_NODES_LIMIT, ARTIFACT_PROCESS_SHARING_AUTHORITIES_LIMIT, ARTIFACT_PROCESS_TASK_VIEWS, ARTIFACT_PROCESS_TASKS_LIMIT, } from './server/broker-contract.js';
|
|
7
7
|
export type { ArtifactAuditAction, ArtifactProcessPrincipalType, ArtifactProcessRunStatus, ArtifactProcessTaskView, } from './server/broker-contract.js';
|
|
8
8
|
export { getArtifactRequestContext, readArtifactRuntimeConfig } from './server/runtime-config.js';
|
|
9
9
|
export type { ArtifactRuntimeConfig, ArtifactRequestHeaders } from './server/runtime-config.js';
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
export { createArtifactServerClient } from './server/client.js';
|
|
3
3
|
export { ArtifactPrincipalError, ArtifactServerError, INSUFFICIENT_USER_AUTHENTICATION, stepUpResponse } from './server/errors.js';
|
|
4
|
-
export { ARTIFACT_AUDIT_ACTIONS, ARTIFACT_AUDIT_RESOURCES_PER_EVENT, ARTIFACT_FLAGS_PER_REQUEST, ARTIFACT_PROCESS_PRINCIPAL_SEARCH_LIMIT, ARTIFACT_PROCESS_PRINCIPAL_TYPES, ARTIFACT_PROCESS_PRINCIPALS_PER_CALL, ARTIFACT_PROCESS_RUN_STATUSES, ARTIFACT_PROCESS_RUNS_LIMIT, ARTIFACT_PROCESS_TASK_VIEWS, ARTIFACT_PROCESS_TASKS_LIMIT, } from './server/broker-contract.js';
|
|
4
|
+
export { ARTIFACT_AUDIT_ACTIONS, ARTIFACT_AUDIT_RESOURCES_PER_EVENT, ARTIFACT_FLAGS_PER_REQUEST, ARTIFACT_PROCESS_PRINCIPAL_SEARCH_LIMIT, ARTIFACT_PROCESS_PRINCIPAL_TYPES, ARTIFACT_PROCESS_PRINCIPALS_PER_CALL, ARTIFACT_PROCESS_RUN_STATUSES, ARTIFACT_PROCESS_RUNS_LIMIT, ARTIFACT_PROCESS_RUN_ENTITIES_LIMIT, ARTIFACT_PROCESS_SHARE_NODES_LIMIT, ARTIFACT_PROCESS_SHARING_AUTHORITIES_LIMIT, ARTIFACT_PROCESS_TASK_VIEWS, ARTIFACT_PROCESS_TASKS_LIMIT, } from './server/broker-contract.js';
|
|
5
5
|
export { getArtifactRequestContext, readArtifactRuntimeConfig } from './server/runtime-config.js';
|
|
6
6
|
export { ArtifactContextError, getArtifactBrowserBootstrap } from './server/request-context.js';
|
|
7
7
|
export { verifyArtifactExternalContext } from './server/external-context.js';
|
package/dist/tunnel/broker.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
|
2
2
|
import type { Duplex } from 'node:stream';
|
|
3
3
|
import { type TunnelLimits } from './peer.js';
|
|
4
4
|
import type { TunnelRelay } from './transport.js';
|
|
5
|
+
import { type TunnelExternalRequest } from './external.js';
|
|
6
|
+
export type { TunnelExternalFailure, TunnelExternalRequest } from './external.js';
|
|
5
7
|
export interface TunnelLease {
|
|
6
8
|
sessionId: string;
|
|
7
9
|
epoch: number;
|
|
@@ -53,12 +55,28 @@ export declare class ArtifactTunnelBroker {
|
|
|
53
55
|
constructor(options: TunnelBrokerOptions);
|
|
54
56
|
handleTunnelUpgrade(request: IncomingMessage, socket: Duplex, head: Buffer): Promise<void>;
|
|
55
57
|
handleHttp(request: IncomingMessage, response: ServerResponse, sessionId: string): Promise<void>;
|
|
58
|
+
/** Proxies an admitted external ingress request over the session's tunnel. Never throws. */
|
|
59
|
+
handleExternalHttp(input: TunnelExternalRequest): Promise<void>;
|
|
56
60
|
handleWebSocketUpgrade(request: IncomingMessage, socket: Duplex, head: Buffer, sessionId: string): Promise<void>;
|
|
57
61
|
private authorize;
|
|
62
|
+
/**
|
|
63
|
+
* The live tunnel for an external request: the session's current lease, for the granted project
|
|
64
|
+
* and environment, still valid. Null otherwise. No browser owner is compared: Atlas's grant
|
|
65
|
+
* already checked the session and its owner's grant on the ingress service account.
|
|
66
|
+
*/
|
|
67
|
+
private externalConnection;
|
|
58
68
|
private valid;
|
|
59
69
|
private remoteConnection;
|
|
60
70
|
private attach;
|
|
61
71
|
private receive;
|
|
72
|
+
private receiveHead;
|
|
73
|
+
private receiveBody;
|
|
74
|
+
/**
|
|
75
|
+
* Backpressure from an external caller abandons the request after the idle timeout instead of
|
|
76
|
+
* holding its stream (and the caller's admission permit) until the request timeout. A write the
|
|
77
|
+
* abort interrupted is not a tunnel failure, so the session's other streams carry on.
|
|
78
|
+
*/
|
|
79
|
+
private writeExternalChunk;
|
|
62
80
|
private finish;
|
|
63
81
|
private abort;
|
|
64
82
|
/** Immediate revocation and graceful service shutdown hook. */
|