@tomflow/proflow-dev-tunnel 0.1.6 → 0.1.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/DOCS.md +27 -0
- package/SETUP.md +7 -0
- package/dist/deployment/adapter.d.ts +111 -115
- package/dist/deployment/adapter.js +299 -260
- package/dist/deployment/descriptor.d.ts +10 -49
- package/dist/deployment/descriptor.js +12 -71
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +5 -4
- package/proflow.module.json +12 -71
- package/CONFIGURATION.md +0 -25
- package/dist/deployment/verification.d.ts +0 -19
- package/dist/deployment/verification.js +0 -2
package/DOCS.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @tomflow/proflow-dev-tunnel — Module Docs
|
|
2
|
+
|
|
3
|
+
Module ref: `dev-tunnel`
|
|
4
|
+
Domain: `deployment-governance`
|
|
5
|
+
Kind: `external-resource`
|
|
6
|
+
|
|
7
|
+
Governs the Microsoft Dev Tunnel public HTTPS ingress resource and its managed local host process.
|
|
8
|
+
|
|
9
|
+
## Standard management surface
|
|
10
|
+
|
|
11
|
+
`install / uninstall / status / setup / docs / start / stop`
|
|
12
|
+
|
|
13
|
+
## Provides
|
|
14
|
+
|
|
15
|
+
- None.
|
|
16
|
+
|
|
17
|
+
## Requires
|
|
18
|
+
|
|
19
|
+
- None.
|
|
20
|
+
|
|
21
|
+
## Public setup inputs
|
|
22
|
+
|
|
23
|
+
- None. Deterministic/private values and cross-Module shared facts are not public configuration.
|
|
24
|
+
|
|
25
|
+
## Ownership boundary
|
|
26
|
+
|
|
27
|
+
Module business APIs and any module-specific extra commands remain package-owned. Platform does not proxy or interpret them. Current human/external preparation is documented in `SETUP.md`.
|
package/SETUP.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @tomflow/proflow-dev-tunnel — Module Setup
|
|
2
|
+
|
|
3
|
+
Authenticate with Microsoft Dev Tunnels when requested, create or select the required tunnel, and allow the Module to establish and verify the public HTTPS ingress. The resulting tunnel id/public URL/evidence are Module-owned state or shared facts, not values to copy into Platform config.
|
|
4
|
+
|
|
5
|
+
## Completion
|
|
6
|
+
|
|
7
|
+
Setup is complete only when the Module's own `status` reports `setupStatus=READY`. Re-running setup must re-observe reality; it must not resume from a blind historical step index.
|
|
@@ -1,141 +1,137 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
export declare function readDevTunnelVerificationEvidence(file: string | undefined, publicBaseUrl: string): Promise<DevTunnelVerificationEvidence | undefined>;
|
|
12
|
-
export declare function createBehaviorAdapter(input?: {
|
|
13
|
-
runtime: DevTunnelRuntime;
|
|
14
|
-
verifyErrorSemantics?: () => Promise<ErrorSemanticsProof>;
|
|
15
|
-
verifyFileRelay?: () => Promise<FileRelayProof>;
|
|
16
|
-
}, config?: Record<string, string>): {
|
|
17
|
-
describe: () => {
|
|
18
|
-
result: ModuleOperationResult;
|
|
19
|
-
observedEffects: never[];
|
|
20
|
-
};
|
|
21
|
-
preflight: () => {
|
|
22
|
-
result: ModuleOperationResult;
|
|
23
|
-
observedEffects: never[];
|
|
24
|
-
};
|
|
25
|
-
status: () => Promise<{
|
|
26
|
-
result: ModuleOperationResult;
|
|
1
|
+
import { type ModuleCommandContext } from "@tomflow/proflow-module-contract";
|
|
2
|
+
export declare const behaviorAdapter: {
|
|
3
|
+
readonly install: (context: ModuleCommandContext) => Promise<{
|
|
4
|
+
result: {
|
|
5
|
+
readonly contract: "deployment.result.v1";
|
|
6
|
+
readonly ok: true;
|
|
7
|
+
readonly status: "SUCCEEDED";
|
|
8
|
+
readonly moduleRef: "dev-tunnel";
|
|
9
|
+
readonly moduleVersion: "0.1.7";
|
|
10
|
+
};
|
|
27
11
|
observedEffects: never[];
|
|
28
12
|
}>;
|
|
29
|
-
|
|
30
|
-
result:
|
|
31
|
-
|
|
13
|
+
readonly uninstall: (context: ModuleCommandContext) => Promise<{
|
|
14
|
+
result: {
|
|
15
|
+
readonly contract: "deployment.result.v1";
|
|
16
|
+
readonly ok: true;
|
|
17
|
+
readonly status: "SUCCEEDED";
|
|
18
|
+
readonly moduleRef: "dev-tunnel";
|
|
19
|
+
readonly moduleVersion: "0.1.7";
|
|
20
|
+
};
|
|
21
|
+
observedEffects: string[];
|
|
32
22
|
} | {
|
|
33
23
|
result: {
|
|
34
24
|
contract: "deployment.result.v1";
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
description: string;
|
|
42
|
-
} | undefined;
|
|
43
|
-
error?: {
|
|
44
|
-
code: "APPLY_FAILED" | "COMMAND_FAILED" | "COMPATIBILITY_MISMATCH" | "CONFIG_REQUIRED" | "CONFORMANCE_FAILED" | "CONTRACT_INVALID" | "CORE_PACKAGE_REQUIRED" | "DEPENDENCY_UNRESOLVED" | "DOCTOR_FAILED" | "EXTERNAL_RESOURCE_UNAVAILABLE" | "INVALID_REQUEST" | "LIFECYCLE_UNSUPPORTED" | "MODULE_NOT_FOUND" | "PLAN_INVALID" | "PLAN_STALE" | "REQUIREMENT_UNMET" | "UNINSTALL_FAILED" | "UPGRADE_FAILED" | "VERIFY_FAILED";
|
|
25
|
+
moduleRef: "dev-tunnel";
|
|
26
|
+
moduleVersion: "0.1.7";
|
|
27
|
+
ok: false;
|
|
28
|
+
status: "FAILED";
|
|
29
|
+
error: {
|
|
30
|
+
code: "UNINSTALL_FAILED";
|
|
45
31
|
message: string;
|
|
46
32
|
retryable: boolean;
|
|
47
|
-
}
|
|
48
|
-
resourceVersion?: string | undefined;
|
|
49
|
-
data?: unknown;
|
|
50
|
-
checks: import("../src/resource-adapter.ts").IngressCheck[];
|
|
33
|
+
};
|
|
51
34
|
};
|
|
52
|
-
observedEffects: string[];
|
|
53
|
-
}>;
|
|
54
|
-
doctor: () => Promise<{
|
|
55
|
-
result: ModuleOperationResult;
|
|
56
35
|
observedEffects: never[];
|
|
57
36
|
}>;
|
|
58
|
-
|
|
59
|
-
result:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
restart: () => Promise<{
|
|
71
|
-
result: ModuleOperationResult;
|
|
72
|
-
observedEffects: string[];
|
|
73
|
-
}>;
|
|
74
|
-
};
|
|
75
|
-
export declare const behaviorAdapter: {
|
|
76
|
-
describe: () => {
|
|
77
|
-
result: ModuleOperationResult;
|
|
37
|
+
readonly status: (context: ModuleCommandContext) => Promise<{
|
|
38
|
+
result: {
|
|
39
|
+
contract: "deployment.result.v1";
|
|
40
|
+
ok: true;
|
|
41
|
+
status: "SUCCEEDED";
|
|
42
|
+
moduleRef: "dev-tunnel";
|
|
43
|
+
moduleVersion: "0.1.7";
|
|
44
|
+
data: {
|
|
45
|
+
setupStatus: "ACTION_REQUIRED" | "READY";
|
|
46
|
+
runtimeStatus: "FAILED" | "RUNNING" | "STOPPED";
|
|
47
|
+
};
|
|
48
|
+
};
|
|
78
49
|
observedEffects: never[];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
result:
|
|
50
|
+
}>;
|
|
51
|
+
readonly setup: (context: ModuleCommandContext) => Promise<{
|
|
52
|
+
result: {
|
|
53
|
+
contract: "deployment.result.v1";
|
|
54
|
+
moduleRef: "dev-tunnel";
|
|
55
|
+
moduleVersion: "0.1.7";
|
|
56
|
+
ok: false;
|
|
57
|
+
status: "ACTION_REQUIRED";
|
|
58
|
+
actionRequired: {
|
|
59
|
+
action: string;
|
|
60
|
+
description: string;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
82
63
|
observedEffects: never[];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
64
|
+
} | {
|
|
65
|
+
result: {
|
|
66
|
+
readonly contract: "deployment.result.v1";
|
|
67
|
+
readonly ok: true;
|
|
68
|
+
readonly status: "SUCCEEDED";
|
|
69
|
+
readonly moduleRef: "dev-tunnel";
|
|
70
|
+
readonly moduleVersion: "0.1.7";
|
|
71
|
+
};
|
|
86
72
|
observedEffects: never[];
|
|
87
73
|
}>;
|
|
88
|
-
|
|
89
|
-
result:
|
|
74
|
+
readonly docs: (_context: ModuleCommandContext) => Promise<{
|
|
75
|
+
result: {
|
|
76
|
+
contract: "deployment.result.v1";
|
|
77
|
+
ok: true;
|
|
78
|
+
status: "SUCCEEDED";
|
|
79
|
+
moduleRef: "dev-tunnel";
|
|
80
|
+
moduleVersion: "0.1.7";
|
|
81
|
+
data: {
|
|
82
|
+
docs: string;
|
|
83
|
+
setup: string;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
90
86
|
observedEffects: never[];
|
|
91
|
-
}
|
|
87
|
+
}>;
|
|
88
|
+
readonly start: (context: ModuleCommandContext) => Promise<{
|
|
92
89
|
result: {
|
|
93
90
|
contract: "deployment.result.v1";
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
description: string;
|
|
101
|
-
} | undefined;
|
|
102
|
-
error?: {
|
|
103
|
-
code: "APPLY_FAILED" | "COMMAND_FAILED" | "COMPATIBILITY_MISMATCH" | "CONFIG_REQUIRED" | "CONFORMANCE_FAILED" | "CONTRACT_INVALID" | "CORE_PACKAGE_REQUIRED" | "DEPENDENCY_UNRESOLVED" | "DOCTOR_FAILED" | "EXTERNAL_RESOURCE_UNAVAILABLE" | "INVALID_REQUEST" | "LIFECYCLE_UNSUPPORTED" | "MODULE_NOT_FOUND" | "PLAN_INVALID" | "PLAN_STALE" | "REQUIREMENT_UNMET" | "UNINSTALL_FAILED" | "UPGRADE_FAILED" | "VERIFY_FAILED";
|
|
91
|
+
moduleRef: "dev-tunnel";
|
|
92
|
+
moduleVersion: "0.1.7";
|
|
93
|
+
ok: false;
|
|
94
|
+
status: "FAILED";
|
|
95
|
+
error: {
|
|
96
|
+
code: "START_FAILED";
|
|
104
97
|
message: string;
|
|
105
98
|
retryable: boolean;
|
|
106
|
-
}
|
|
107
|
-
resourceVersion?: string | undefined;
|
|
108
|
-
data?: unknown;
|
|
109
|
-
checks: import("../src/resource-adapter.ts").IngressCheck[];
|
|
99
|
+
};
|
|
110
100
|
};
|
|
111
|
-
observedEffects: string[];
|
|
112
|
-
}>;
|
|
113
|
-
doctor: () => Promise<{
|
|
114
|
-
result: ModuleOperationResult;
|
|
115
101
|
observedEffects: never[];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
uninstall: () => Promise<{
|
|
126
|
-
result: ModuleOperationResult;
|
|
102
|
+
} | {
|
|
103
|
+
result: {
|
|
104
|
+
contract: "deployment.result.v1";
|
|
105
|
+
ok: true;
|
|
106
|
+
status: "SUCCEEDED";
|
|
107
|
+
moduleRef: "dev-tunnel";
|
|
108
|
+
moduleVersion: "0.1.7";
|
|
109
|
+
data: import("../src/resource-adapter.ts").DevTunnelObservation;
|
|
110
|
+
};
|
|
127
111
|
observedEffects: string[];
|
|
128
112
|
}>;
|
|
129
|
-
|
|
130
|
-
result:
|
|
113
|
+
readonly stop: (context: ModuleCommandContext) => Promise<{
|
|
114
|
+
result: {
|
|
115
|
+
readonly contract: "deployment.result.v1";
|
|
116
|
+
readonly ok: true;
|
|
117
|
+
readonly status: "SUCCEEDED";
|
|
118
|
+
readonly moduleRef: "dev-tunnel";
|
|
119
|
+
readonly moduleVersion: "0.1.7";
|
|
120
|
+
};
|
|
131
121
|
observedEffects: string[];
|
|
122
|
+
} | {
|
|
123
|
+
result: {
|
|
124
|
+
contract: "deployment.result.v1";
|
|
125
|
+
moduleRef: "dev-tunnel";
|
|
126
|
+
moduleVersion: "0.1.7";
|
|
127
|
+
ok: false;
|
|
128
|
+
status: "FAILED";
|
|
129
|
+
error: {
|
|
130
|
+
code: "STOP_FAILED";
|
|
131
|
+
message: string;
|
|
132
|
+
retryable: boolean;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
observedEffects: never[];
|
|
132
136
|
}>;
|
|
133
137
|
};
|
|
134
|
-
export declare function createProductionBinding(input: {
|
|
135
|
-
moduleRef: string;
|
|
136
|
-
config: Record<string, string>;
|
|
137
|
-
workspaceRoot: string;
|
|
138
|
-
}): Promise<{
|
|
139
|
-
behaviorAdapter: Record<string, unknown>;
|
|
140
|
-
} | undefined>;
|
|
141
|
-
export {};
|
|
@@ -1,43 +1,29 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { writeModuleSharedFacts, } from "@tomflow/proflow-module-contract";
|
|
4
|
+
import { createDevTunnelRuntime } from "../src/resource-adapter.js";
|
|
5
5
|
import { descriptor } from "./descriptor.js";
|
|
6
|
-
const
|
|
6
|
+
const base = {
|
|
7
7
|
contract: "deployment.result.v1",
|
|
8
8
|
ok: true,
|
|
9
9
|
status: "SUCCEEDED",
|
|
10
10
|
moduleRef: descriptor.moduleRef,
|
|
11
11
|
moduleVersion: descriptor.moduleVersion,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
moduleRef: descriptor.moduleRef,
|
|
19
|
-
moduleVersion: descriptor.moduleVersion,
|
|
20
|
-
actionRequired: { action, description },
|
|
21
|
-
});
|
|
22
|
-
export async function readDevTunnelVerificationEvidence(file, publicBaseUrl) {
|
|
23
|
-
if (!file)
|
|
24
|
-
return undefined;
|
|
12
|
+
};
|
|
13
|
+
const processEffect = "Manage the dev-tunnel public ingress process";
|
|
14
|
+
const stateDir = (context) => join(resolve(context.workspaceRoot), ".proflow", "runtime", "external-resources", "dev-tunnel");
|
|
15
|
+
const stateFile = (context) => join(stateDir(context), "setup.json");
|
|
16
|
+
const processFile = (context) => join(stateDir(context), "process.json");
|
|
17
|
+
async function readState(context) {
|
|
25
18
|
try {
|
|
26
|
-
const raw = JSON.parse(await readFile(
|
|
27
|
-
if (raw.contract !== "proflow.dev-tunnel-
|
|
28
|
-
raw.
|
|
29
|
-
raw.
|
|
30
|
-
typeof raw.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
typeof raw.fileRelay.verified !== "boolean" ||
|
|
35
|
-
typeof raw.fileRelay.message !== "string" ||
|
|
36
|
-
typeof raw.errorSemantics !== "object" ||
|
|
37
|
-
raw.errorSemantics === null ||
|
|
38
|
-
typeof raw.errorSemantics.rateLimit429Verified !== "boolean" ||
|
|
39
|
-
typeof raw.errorSemantics.server5xxVerified !== "boolean" ||
|
|
40
|
-
typeof raw.errorSemantics.message !== "string")
|
|
19
|
+
const raw = JSON.parse(await readFile(stateFile(context), "utf8"));
|
|
20
|
+
if (raw.contract !== "proflow.dev-tunnel-setup.v1" ||
|
|
21
|
+
typeof raw.tunnelId !== "string" ||
|
|
22
|
+
!raw.tunnelId ||
|
|
23
|
+
typeof raw.publicBaseUrl !== "string")
|
|
24
|
+
return undefined;
|
|
25
|
+
const url = new URL(raw.publicBaseUrl);
|
|
26
|
+
if (url.protocol !== "https:")
|
|
41
27
|
return undefined;
|
|
42
28
|
return raw;
|
|
43
29
|
}
|
|
@@ -45,254 +31,307 @@ export async function readDevTunnelVerificationEvidence(file, publicBaseUrl) {
|
|
|
45
31
|
return undefined;
|
|
46
32
|
}
|
|
47
33
|
}
|
|
48
|
-
|
|
34
|
+
async function writeState(context, state) {
|
|
35
|
+
await mkdir(stateDir(context), { recursive: true, mode: 0o700 });
|
|
36
|
+
const tmp = `${stateFile(context)}.${process.pid}.tmp`;
|
|
37
|
+
await writeFile(tmp, `${JSON.stringify(state, null, 2)}
|
|
38
|
+
`, { encoding: "utf8", mode: 0o600 });
|
|
39
|
+
await rename(tmp, stateFile(context));
|
|
40
|
+
}
|
|
41
|
+
function setupInput(context) {
|
|
42
|
+
if (typeof context.input !== "object" ||
|
|
43
|
+
context.input === null ||
|
|
44
|
+
Array.isArray(context.input))
|
|
45
|
+
return {};
|
|
46
|
+
const tunnelId = Reflect.get(context.input, "tunnelId");
|
|
47
|
+
const publicBaseUrl = Reflect.get(context.input, "publicBaseUrl");
|
|
49
48
|
return {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
49
|
+
...(typeof tunnelId === "string" && tunnelId ? { tunnelId } : {}),
|
|
50
|
+
...(typeof publicBaseUrl === "string" && publicBaseUrl
|
|
51
|
+
? { publicBaseUrl }
|
|
52
|
+
: {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function runtime(context, state) {
|
|
56
|
+
return createDevTunnelRuntime({
|
|
57
|
+
...(state
|
|
58
|
+
? { tunnelId: state.tunnelId, publicBaseUrl: state.publicBaseUrl }
|
|
59
|
+
: {}),
|
|
60
|
+
processStateFile: processFile(context),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export const behaviorAdapter = {
|
|
64
|
+
install: async (context) => {
|
|
65
|
+
await mkdir(stateDir(context), { recursive: true, mode: 0o700 });
|
|
66
|
+
const state = await readState(context);
|
|
67
|
+
if (state)
|
|
68
|
+
await writeModuleSharedFacts(context, descriptor.moduleRef, {
|
|
69
|
+
tunnelId: state.tunnelId,
|
|
70
|
+
publicBaseUrl: state.publicBaseUrl,
|
|
71
|
+
});
|
|
72
|
+
return { result: base, observedEffects: [] };
|
|
73
|
+
},
|
|
74
|
+
uninstall: async (context) => {
|
|
75
|
+
const state = await readState(context);
|
|
76
|
+
if (!state)
|
|
77
|
+
return { result: base, observedEffects: [] };
|
|
78
|
+
try {
|
|
79
|
+
const stopped = await runtime(context, state).stop();
|
|
80
|
+
return stopped.state === "STOPPED"
|
|
81
|
+
? { result: base, observedEffects: [processEffect] }
|
|
82
|
+
: {
|
|
83
|
+
result: {
|
|
84
|
+
...base,
|
|
85
|
+
ok: false,
|
|
86
|
+
status: "FAILED",
|
|
87
|
+
error: {
|
|
88
|
+
code: "UNINSTALL_FAILED",
|
|
89
|
+
message: "dev-tunnel stop state is UNKNOWN",
|
|
90
|
+
retryable: true,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
observedEffects: [],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
71
97
|
return {
|
|
72
|
-
result:
|
|
98
|
+
result: {
|
|
99
|
+
...base,
|
|
100
|
+
ok: false,
|
|
101
|
+
status: "FAILED",
|
|
102
|
+
error: {
|
|
103
|
+
code: "UNINSTALL_FAILED",
|
|
104
|
+
message: error instanceof Error
|
|
105
|
+
? error.message
|
|
106
|
+
: "failed to stop dev-tunnel",
|
|
107
|
+
retryable: true,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
73
110
|
observedEffects: [],
|
|
74
111
|
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
observedEffects: [],
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
if ((await input.runtime.loginStatus()) !== "LOGGED_IN") {
|
|
84
|
-
return {
|
|
85
|
-
result: actionRequired("complete-tunnel-login", "Complete the interactive dev-tunnel login before verifying public ingress"),
|
|
86
|
-
observedEffects: [],
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
const publicBaseUrl = input.runtime.publicBaseUrl();
|
|
90
|
-
if (publicBaseUrl === undefined) {
|
|
91
|
-
return {
|
|
92
|
-
result: actionRequired("configure-tunnel", "publicBaseUrl must be configured before public ingress verification"),
|
|
93
|
-
observedEffects: [],
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
const verification = await verifyPublicIngress(publicBaseUrl, {
|
|
97
|
-
...(input.verifyErrorSemantics === undefined
|
|
98
|
-
? {}
|
|
99
|
-
: { verifyErrorSemantics: input.verifyErrorSemantics }),
|
|
100
|
-
...(input.verifyFileRelay === undefined
|
|
101
|
-
? {}
|
|
102
|
-
: { verifyFileRelay: input.verifyFileRelay }),
|
|
103
|
-
});
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
status: async (context) => {
|
|
115
|
+
const state = await readState(context);
|
|
116
|
+
if (!state) {
|
|
104
117
|
return {
|
|
105
|
-
result:
|
|
106
|
-
|
|
107
|
-
: {
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
result: {
|
|
119
|
+
...base,
|
|
120
|
+
data: {
|
|
121
|
+
setupStatus: "ACTION_REQUIRED",
|
|
122
|
+
runtimeStatus: "STOPPED",
|
|
110
123
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
: [],
|
|
124
|
+
},
|
|
125
|
+
observedEffects: [],
|
|
114
126
|
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
}
|
|
128
|
+
await writeModuleSharedFacts(context, descriptor.moduleRef, {
|
|
129
|
+
tunnelId: state.tunnelId,
|
|
130
|
+
publicBaseUrl: state.publicBaseUrl,
|
|
131
|
+
});
|
|
132
|
+
const rt = runtime(context, state);
|
|
133
|
+
const login = await rt.loginStatus();
|
|
134
|
+
const observed = await rt.status();
|
|
135
|
+
const configured = state !== undefined && login === "LOGGED_IN";
|
|
136
|
+
const runtimeStatus = observed.state === "RUNNING"
|
|
137
|
+
? "RUNNING"
|
|
138
|
+
: observed.state === "STOPPED"
|
|
139
|
+
? "STOPPED"
|
|
140
|
+
: configured
|
|
141
|
+
? "FAILED"
|
|
142
|
+
: "STOPPED";
|
|
143
|
+
return {
|
|
144
|
+
result: {
|
|
145
|
+
...base,
|
|
146
|
+
data: {
|
|
147
|
+
setupStatus: configured
|
|
148
|
+
? "READY"
|
|
149
|
+
: "ACTION_REQUIRED",
|
|
150
|
+
runtimeStatus,
|
|
131
151
|
},
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
152
|
+
},
|
|
153
|
+
observedEffects: [],
|
|
154
|
+
};
|
|
155
|
+
},
|
|
156
|
+
setup: async (context) => {
|
|
157
|
+
await mkdir(stateDir(context), { recursive: true, mode: 0o700 });
|
|
158
|
+
const previous = await readState(context);
|
|
159
|
+
const supplied = setupInput(context);
|
|
160
|
+
const candidate = { ...(previous ?? {}), ...supplied };
|
|
161
|
+
const rt = runtime(context, previous);
|
|
162
|
+
const login = await rt.loginStatus();
|
|
163
|
+
if (login !== "LOGGED_IN")
|
|
164
|
+
return {
|
|
165
|
+
result: {
|
|
166
|
+
...base,
|
|
167
|
+
ok: false,
|
|
168
|
+
status: "ACTION_REQUIRED",
|
|
169
|
+
actionRequired: {
|
|
170
|
+
action: "complete-tunnel-login",
|
|
171
|
+
description: "Complete Microsoft Dev Tunnel login, then rerun setup.",
|
|
172
|
+
},
|
|
140
173
|
},
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
174
|
+
observedEffects: [],
|
|
175
|
+
};
|
|
176
|
+
if (typeof candidate.tunnelId !== "string" ||
|
|
177
|
+
typeof candidate.publicBaseUrl !== "string")
|
|
178
|
+
return {
|
|
179
|
+
result: {
|
|
180
|
+
...base,
|
|
181
|
+
ok: false,
|
|
182
|
+
status: "ACTION_REQUIRED",
|
|
183
|
+
actionRequired: {
|
|
184
|
+
action: "select-or-create-tunnel",
|
|
185
|
+
description: "Create or select the persistent Dev Tunnel and provide tunnelId plus publicBaseUrl to this setup step.",
|
|
186
|
+
},
|
|
147
187
|
},
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
188
|
+
observedEffects: [],
|
|
189
|
+
};
|
|
190
|
+
try {
|
|
191
|
+
const url = new URL(candidate.publicBaseUrl);
|
|
192
|
+
if (url.protocol !== "https:")
|
|
193
|
+
throw new TypeError("publicBaseUrl must be HTTPS");
|
|
194
|
+
const state = {
|
|
195
|
+
contract: "proflow.dev-tunnel-setup.v1",
|
|
196
|
+
tunnelId: candidate.tunnelId,
|
|
197
|
+
publicBaseUrl: url.href,
|
|
198
|
+
};
|
|
199
|
+
await writeState(context, state);
|
|
200
|
+
await writeModuleSharedFacts(context, descriptor.moduleRef, {
|
|
201
|
+
tunnelId: state.tunnelId,
|
|
202
|
+
publicBaseUrl: state.publicBaseUrl,
|
|
203
|
+
});
|
|
204
|
+
return { result: base, observedEffects: [] };
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
152
207
|
return {
|
|
153
|
-
result:
|
|
154
|
-
|
|
155
|
-
:
|
|
156
|
-
|
|
157
|
-
|
|
208
|
+
result: {
|
|
209
|
+
...base,
|
|
210
|
+
ok: false,
|
|
211
|
+
status: "ACTION_REQUIRED",
|
|
212
|
+
actionRequired: {
|
|
213
|
+
action: "correct-tunnel-facts",
|
|
214
|
+
description: error instanceof Error
|
|
215
|
+
? error.message
|
|
216
|
+
: "Tunnel setup facts are invalid",
|
|
158
217
|
},
|
|
218
|
+
},
|
|
159
219
|
observedEffects: [],
|
|
160
220
|
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
result: actionRequired("complete-tunnel-login", "Complete the interactive dev-tunnel login before starting the tunnel"),
|
|
172
|
-
observedEffects: [],
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
try {
|
|
176
|
-
const observation = await input.runtime.start();
|
|
177
|
-
return {
|
|
178
|
-
result: success(observation),
|
|
179
|
-
observedEffects: ["Manage the dev-tunnel public ingress process"],
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
return {
|
|
184
|
-
result: actionRequired("start-tunnel", error instanceof Error
|
|
185
|
-
? error.message
|
|
186
|
-
: "failed to start the dev-tunnel process"),
|
|
187
|
-
observedEffects: [],
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
stop: async () => {
|
|
192
|
-
if (!input) {
|
|
193
|
-
return {
|
|
194
|
-
result: actionRequired("configure-tunnel", "No bound dev-tunnel resource to stop"),
|
|
195
|
-
observedEffects: [],
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
const stopped = await input.runtime.stop();
|
|
199
|
-
if (stopped.state === "STOPPED") {
|
|
200
|
-
return {
|
|
201
|
-
result: success(),
|
|
202
|
-
observedEffects: ["Manage the dev-tunnel public ingress process"],
|
|
203
|
-
};
|
|
204
|
-
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
docs: async (_context) => ({
|
|
224
|
+
result: { ...base, data: { docs: "DOCS.md", setup: "SETUP.md" } },
|
|
225
|
+
observedEffects: [],
|
|
226
|
+
}),
|
|
227
|
+
start: async (context) => {
|
|
228
|
+
const state = await readState(context);
|
|
229
|
+
if (!state)
|
|
205
230
|
return {
|
|
206
|
-
result:
|
|
231
|
+
result: {
|
|
232
|
+
...base,
|
|
233
|
+
ok: false,
|
|
234
|
+
status: "FAILED",
|
|
235
|
+
error: {
|
|
236
|
+
code: "START_FAILED",
|
|
237
|
+
message: "dev-tunnel setup is not READY",
|
|
238
|
+
retryable: true,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
207
241
|
observedEffects: [],
|
|
208
242
|
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (!input) {
|
|
212
|
-
return {
|
|
213
|
-
// No bound tunnel means there is no managed external resource to
|
|
214
|
-
// stop. Whole-instance uninstall must remain idempotent.
|
|
215
|
-
result: success(),
|
|
216
|
-
observedEffects: [],
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
const stopped = await input.runtime.stop();
|
|
220
|
-
if (stopped.state === "STOPPED") {
|
|
221
|
-
return {
|
|
222
|
-
result: success(),
|
|
223
|
-
observedEffects: ["Manage the dev-tunnel public ingress process"],
|
|
224
|
-
};
|
|
225
|
-
}
|
|
243
|
+
const rt = runtime(context, state);
|
|
244
|
+
if ((await rt.loginStatus()) !== "LOGGED_IN")
|
|
226
245
|
return {
|
|
227
|
-
result:
|
|
246
|
+
result: {
|
|
247
|
+
...base,
|
|
248
|
+
ok: false,
|
|
249
|
+
status: "FAILED",
|
|
250
|
+
error: {
|
|
251
|
+
code: "START_FAILED",
|
|
252
|
+
message: "Microsoft Dev Tunnel login is not ready",
|
|
253
|
+
retryable: true,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
228
256
|
observedEffects: [],
|
|
229
257
|
};
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
result:
|
|
235
|
-
observedEffects: [],
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
try {
|
|
259
|
+
const observed = await rt.start();
|
|
260
|
+
return observed.state === "RUNNING"
|
|
261
|
+
? {
|
|
262
|
+
result: { ...base, data: observed },
|
|
263
|
+
observedEffects: [processEffect],
|
|
264
|
+
}
|
|
265
|
+
: {
|
|
266
|
+
result: {
|
|
267
|
+
...base,
|
|
268
|
+
ok: false,
|
|
269
|
+
status: "FAILED",
|
|
270
|
+
error: {
|
|
271
|
+
code: "START_FAILED",
|
|
272
|
+
message: "dev-tunnel did not reach RUNNING",
|
|
273
|
+
retryable: true,
|
|
274
|
+
},
|
|
275
|
+
},
|
|
248
276
|
observedEffects: [],
|
|
249
277
|
};
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
:
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
return {
|
|
281
|
+
result: {
|
|
282
|
+
...base,
|
|
283
|
+
ok: false,
|
|
284
|
+
status: "FAILED",
|
|
285
|
+
error: {
|
|
286
|
+
code: "START_FAILED",
|
|
287
|
+
message: error instanceof Error
|
|
288
|
+
? error.message
|
|
289
|
+
: "failed to start dev-tunnel",
|
|
290
|
+
retryable: true,
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
observedEffects: [],
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
stop: async (context) => {
|
|
298
|
+
const state = await readState(context);
|
|
299
|
+
if (!state)
|
|
300
|
+
return { result: base, observedEffects: [] };
|
|
301
|
+
try {
|
|
302
|
+
const observed = await runtime(context, state).stop();
|
|
303
|
+
return observed.state === "STOPPED"
|
|
304
|
+
? { result: base, observedEffects: [processEffect] }
|
|
305
|
+
: {
|
|
306
|
+
result: {
|
|
307
|
+
...base,
|
|
308
|
+
ok: false,
|
|
309
|
+
status: "FAILED",
|
|
310
|
+
error: {
|
|
311
|
+
code: "STOP_FAILED",
|
|
312
|
+
message: "dev-tunnel stop state is UNKNOWN",
|
|
313
|
+
retryable: true,
|
|
314
|
+
},
|
|
315
|
+
},
|
|
263
316
|
observedEffects: [],
|
|
264
317
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
processStateFile: join(input.workspaceRoot, ".proflow", "runtime", "external-resources", "dev-tunnel", "process.json"),
|
|
286
|
-
}),
|
|
287
|
-
verifyFileRelay: async () => (await readEvidence())?.fileRelay ?? {
|
|
288
|
-
verified: false,
|
|
289
|
-
message: "dev-tunnel verification evidence is missing, stale, or invalid",
|
|
290
|
-
},
|
|
291
|
-
verifyErrorSemantics: async () => (await readEvidence())?.errorSemantics ?? {
|
|
292
|
-
rateLimit429Verified: false,
|
|
293
|
-
server5xxVerified: false,
|
|
294
|
-
message: "dev-tunnel verification evidence is missing, stale, or invalid",
|
|
295
|
-
},
|
|
296
|
-
}, input.config),
|
|
297
|
-
};
|
|
298
|
-
}
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
return {
|
|
321
|
+
result: {
|
|
322
|
+
...base,
|
|
323
|
+
ok: false,
|
|
324
|
+
status: "FAILED",
|
|
325
|
+
error: {
|
|
326
|
+
code: "STOP_FAILED",
|
|
327
|
+
message: error instanceof Error
|
|
328
|
+
? error.message
|
|
329
|
+
: "failed to stop dev-tunnel",
|
|
330
|
+
retryable: true,
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
observedEffects: [],
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
};
|
|
@@ -3,7 +3,7 @@ export declare const descriptor: {
|
|
|
3
3
|
readonly contractVersion: "1.0.0";
|
|
4
4
|
readonly moduleRef: "dev-tunnel";
|
|
5
5
|
readonly packageName: "@tomflow/proflow-dev-tunnel";
|
|
6
|
-
readonly moduleVersion: "0.1.
|
|
6
|
+
readonly moduleVersion: "0.1.7";
|
|
7
7
|
readonly kind: "external-resource";
|
|
8
8
|
readonly templateVersion: "1.0.0";
|
|
9
9
|
readonly platformCompatibility: ">=1.0.0 <2.0.0";
|
|
@@ -11,7 +11,10 @@ export declare const descriptor: {
|
|
|
11
11
|
readonly domain: "deployment-governance";
|
|
12
12
|
readonly summary: "Governs the Microsoft Dev Tunnel public HTTPS ingress resource and its managed local host process.";
|
|
13
13
|
};
|
|
14
|
-
readonly provides: readonly [
|
|
14
|
+
readonly provides: readonly [{
|
|
15
|
+
readonly contractRef: "public-ingress";
|
|
16
|
+
readonly version: "1.0.0";
|
|
17
|
+
}];
|
|
15
18
|
readonly requires: readonly [];
|
|
16
19
|
readonly requirements: readonly [{
|
|
17
20
|
readonly kind: "executable";
|
|
@@ -20,44 +23,7 @@ export declare const descriptor: {
|
|
|
20
23
|
readonly kind: "human";
|
|
21
24
|
readonly action: "Complete Microsoft Dev Tunnel login when required";
|
|
22
25
|
}];
|
|
23
|
-
readonly configSlots: readonly [
|
|
24
|
-
readonly key: "publicBaseUrl";
|
|
25
|
-
readonly type: "url";
|
|
26
|
-
readonly required: true;
|
|
27
|
-
readonly description: "Public HTTPS URL supplied by the dev-tunnel resource";
|
|
28
|
-
}, {
|
|
29
|
-
readonly key: "tunnelId";
|
|
30
|
-
readonly type: "string";
|
|
31
|
-
readonly required: false;
|
|
32
|
-
readonly description: "Persistent Microsoft Dev Tunnel identifier used when this adapter owns lifecycle start/stop";
|
|
33
|
-
}, {
|
|
34
|
-
readonly key: "verificationEvidenceFile";
|
|
35
|
-
readonly type: "path";
|
|
36
|
-
readonly required: false;
|
|
37
|
-
readonly description: "JSON evidence for real file-relay and 429/5xx verification behind the configured public ingress";
|
|
38
|
-
}];
|
|
39
|
-
readonly lifecycle: {
|
|
40
|
-
readonly supported: readonly ["describe", "preflight", "status", "verify", "doctor", "start", "stop", "restart", "uninstall"];
|
|
41
|
-
};
|
|
42
|
-
readonly verification: {
|
|
43
|
-
readonly checks: readonly [{
|
|
44
|
-
readonly id: "tunnel-status";
|
|
45
|
-
readonly description: "dev-tunnel process reports a real running or stopped state";
|
|
46
|
-
readonly lifecycle: "status";
|
|
47
|
-
}, {
|
|
48
|
-
readonly id: "tunnel-public-ingress";
|
|
49
|
-
readonly description: "public HTTPS ingress passes the frozen TLS/port/size/latency contract";
|
|
50
|
-
readonly lifecycle: "verify";
|
|
51
|
-
}, {
|
|
52
|
-
readonly id: "tunnel-file-relay";
|
|
53
|
-
readonly description: "file relay behind the public ingress is reachable";
|
|
54
|
-
readonly lifecycle: "verify";
|
|
55
|
-
}, {
|
|
56
|
-
readonly id: "tunnel-diagnostics";
|
|
57
|
-
readonly description: "dev-tunnel configuration has actionable diagnostics";
|
|
58
|
-
readonly lifecycle: "doctor";
|
|
59
|
-
}];
|
|
60
|
-
};
|
|
26
|
+
readonly configSlots: readonly [];
|
|
61
27
|
readonly effects: readonly [{
|
|
62
28
|
readonly kind: "process";
|
|
63
29
|
readonly description: "Manage the dev-tunnel public ingress process";
|
|
@@ -71,13 +37,8 @@ export declare const descriptor: {
|
|
|
71
37
|
readonly description: "Exposes the local platform via a public HTTPS tunnel";
|
|
72
38
|
readonly retention: "preserve";
|
|
73
39
|
}];
|
|
74
|
-
readonly documentation:
|
|
75
|
-
readonly
|
|
76
|
-
readonly
|
|
77
|
-
|
|
78
|
-
}, {
|
|
79
|
-
readonly id: "configuration";
|
|
80
|
-
readonly path: "./CONFIGURATION.md";
|
|
81
|
-
readonly description: "Module configuration fields, sources and materialization instructions";
|
|
82
|
-
}];
|
|
40
|
+
readonly documentation: {
|
|
41
|
+
readonly docs: "DOCS.md";
|
|
42
|
+
readonly setup: "SETUP.md";
|
|
43
|
+
};
|
|
83
44
|
};
|
|
@@ -3,7 +3,7 @@ export const descriptor = {
|
|
|
3
3
|
contractVersion: "1.0.0",
|
|
4
4
|
moduleRef: "dev-tunnel",
|
|
5
5
|
packageName: "@tomflow/proflow-dev-tunnel",
|
|
6
|
-
moduleVersion: "0.1.
|
|
6
|
+
moduleVersion: "0.1.7",
|
|
7
7
|
kind: "external-resource",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -11,7 +11,12 @@ export const descriptor = {
|
|
|
11
11
|
domain: "deployment-governance",
|
|
12
12
|
summary: "Governs the Microsoft Dev Tunnel public HTTPS ingress resource and its managed local host process.",
|
|
13
13
|
},
|
|
14
|
-
provides: [
|
|
14
|
+
provides: [
|
|
15
|
+
{
|
|
16
|
+
contractRef: "public-ingress",
|
|
17
|
+
version: "1.0.0",
|
|
18
|
+
},
|
|
19
|
+
],
|
|
15
20
|
requires: [],
|
|
16
21
|
requirements: [
|
|
17
22
|
{
|
|
@@ -23,63 +28,7 @@ export const descriptor = {
|
|
|
23
28
|
action: "Complete Microsoft Dev Tunnel login when required",
|
|
24
29
|
},
|
|
25
30
|
],
|
|
26
|
-
configSlots: [
|
|
27
|
-
{
|
|
28
|
-
key: "publicBaseUrl",
|
|
29
|
-
type: "url",
|
|
30
|
-
required: true,
|
|
31
|
-
description: "Public HTTPS URL supplied by the dev-tunnel resource",
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
key: "tunnelId",
|
|
35
|
-
type: "string",
|
|
36
|
-
required: false,
|
|
37
|
-
description: "Persistent Microsoft Dev Tunnel identifier used when this adapter owns lifecycle start/stop",
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
key: "verificationEvidenceFile",
|
|
41
|
-
type: "path",
|
|
42
|
-
required: false,
|
|
43
|
-
description: "JSON evidence for real file-relay and 429/5xx verification behind the configured public ingress",
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
lifecycle: {
|
|
47
|
-
supported: [
|
|
48
|
-
"describe",
|
|
49
|
-
"preflight",
|
|
50
|
-
"status",
|
|
51
|
-
"verify",
|
|
52
|
-
"doctor",
|
|
53
|
-
"start",
|
|
54
|
-
"stop",
|
|
55
|
-
"restart",
|
|
56
|
-
"uninstall",
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
verification: {
|
|
60
|
-
checks: [
|
|
61
|
-
{
|
|
62
|
-
id: "tunnel-status",
|
|
63
|
-
description: "dev-tunnel process reports a real running or stopped state",
|
|
64
|
-
lifecycle: "status",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: "tunnel-public-ingress",
|
|
68
|
-
description: "public HTTPS ingress passes the frozen TLS/port/size/latency contract",
|
|
69
|
-
lifecycle: "verify",
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
id: "tunnel-file-relay",
|
|
73
|
-
description: "file relay behind the public ingress is reachable",
|
|
74
|
-
lifecycle: "verify",
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
id: "tunnel-diagnostics",
|
|
78
|
-
description: "dev-tunnel configuration has actionable diagnostics",
|
|
79
|
-
lifecycle: "doctor",
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
},
|
|
31
|
+
configSlots: [],
|
|
83
32
|
effects: [
|
|
84
33
|
{
|
|
85
34
|
kind: "process",
|
|
@@ -97,16 +46,8 @@ export const descriptor = {
|
|
|
97
46
|
retention: "preserve",
|
|
98
47
|
},
|
|
99
48
|
],
|
|
100
|
-
documentation:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
description: "Dev Tunnel module overview",
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
id: "configuration",
|
|
108
|
-
path: "./CONFIGURATION.md",
|
|
109
|
-
description: "Module configuration fields, sources and materialization instructions",
|
|
110
|
-
},
|
|
111
|
-
],
|
|
49
|
+
documentation: {
|
|
50
|
+
docs: "DOCS.md",
|
|
51
|
+
setup: "SETUP.md",
|
|
52
|
+
},
|
|
112
53
|
};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { behaviorAdapter
|
|
1
|
+
export { behaviorAdapter } from "../deployment/adapter.ts";
|
|
2
2
|
export { descriptor } from "../deployment/descriptor.ts";
|
package/dist/src/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { behaviorAdapter
|
|
1
|
+
export { behaviorAdapter } from "../deployment/adapter.js";
|
|
2
2
|
export { descriptor } from "../deployment/descriptor.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomflow/proflow-dev-tunnel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -15,13 +15,14 @@
|
|
|
15
15
|
"proflow.module.json",
|
|
16
16
|
"conformance.json",
|
|
17
17
|
"README.md",
|
|
18
|
-
"
|
|
18
|
+
"DOCS.md",
|
|
19
|
+
"SETUP.md"
|
|
19
20
|
],
|
|
20
21
|
"dependencies": {
|
|
21
|
-
"@tomflow/proflow-module-contract": "^0.1.
|
|
22
|
+
"@tomflow/proflow-module-contract": "^0.1.4"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
|
-
"@tomflow/proflow-deployment-conformance": "^0.1.
|
|
25
|
+
"@tomflow/proflow-deployment-conformance": "^0.1.4"
|
|
25
26
|
},
|
|
26
27
|
"description": "Governs the Microsoft Dev Tunnel public HTTPS ingress resource and its managed local host process.",
|
|
27
28
|
"keywords": [
|
package/proflow.module.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"contractVersion": "1.0.0",
|
|
4
4
|
"moduleRef": "dev-tunnel",
|
|
5
5
|
"packageName": "@tomflow/proflow-dev-tunnel",
|
|
6
|
-
"moduleVersion": "0.1.
|
|
6
|
+
"moduleVersion": "0.1.7",
|
|
7
7
|
"kind": "external-resource",
|
|
8
8
|
"templateVersion": "1.0.0",
|
|
9
9
|
"platformCompatibility": ">=1.0.0 <2.0.0",
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
"domain": "deployment-governance",
|
|
12
12
|
"summary": "Governs the Microsoft Dev Tunnel public HTTPS ingress resource and its managed local host process."
|
|
13
13
|
},
|
|
14
|
-
"provides": [
|
|
14
|
+
"provides": [
|
|
15
|
+
{
|
|
16
|
+
"contractRef": "public-ingress",
|
|
17
|
+
"version": "1.0.0"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
15
20
|
"requires": [],
|
|
16
21
|
"requirements": [
|
|
17
22
|
{
|
|
@@ -23,63 +28,7 @@
|
|
|
23
28
|
"action": "Complete Microsoft Dev Tunnel login when required"
|
|
24
29
|
}
|
|
25
30
|
],
|
|
26
|
-
"configSlots": [
|
|
27
|
-
{
|
|
28
|
-
"key": "publicBaseUrl",
|
|
29
|
-
"type": "url",
|
|
30
|
-
"required": true,
|
|
31
|
-
"description": "Public HTTPS URL supplied by the dev-tunnel resource"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"key": "tunnelId",
|
|
35
|
-
"type": "string",
|
|
36
|
-
"required": false,
|
|
37
|
-
"description": "Persistent Microsoft Dev Tunnel identifier used when this adapter owns lifecycle start/stop"
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
"key": "verificationEvidenceFile",
|
|
41
|
-
"type": "path",
|
|
42
|
-
"required": false,
|
|
43
|
-
"description": "JSON evidence for real file-relay and 429/5xx verification behind the configured public ingress"
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
"lifecycle": {
|
|
47
|
-
"supported": [
|
|
48
|
-
"describe",
|
|
49
|
-
"preflight",
|
|
50
|
-
"status",
|
|
51
|
-
"verify",
|
|
52
|
-
"doctor",
|
|
53
|
-
"start",
|
|
54
|
-
"stop",
|
|
55
|
-
"restart",
|
|
56
|
-
"uninstall"
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
"verification": {
|
|
60
|
-
"checks": [
|
|
61
|
-
{
|
|
62
|
-
"id": "tunnel-status",
|
|
63
|
-
"description": "dev-tunnel process reports a real running or stopped state",
|
|
64
|
-
"lifecycle": "status"
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"id": "tunnel-public-ingress",
|
|
68
|
-
"description": "public HTTPS ingress passes the frozen TLS/port/size/latency contract",
|
|
69
|
-
"lifecycle": "verify"
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"id": "tunnel-file-relay",
|
|
73
|
-
"description": "file relay behind the public ingress is reachable",
|
|
74
|
-
"lifecycle": "verify"
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
"id": "tunnel-diagnostics",
|
|
78
|
-
"description": "dev-tunnel configuration has actionable diagnostics",
|
|
79
|
-
"lifecycle": "doctor"
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
},
|
|
31
|
+
"configSlots": [],
|
|
83
32
|
"effects": [
|
|
84
33
|
{
|
|
85
34
|
"kind": "process",
|
|
@@ -97,16 +46,8 @@
|
|
|
97
46
|
"retention": "preserve"
|
|
98
47
|
}
|
|
99
48
|
],
|
|
100
|
-
"documentation":
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
"description": "Dev Tunnel module overview"
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
"id": "configuration",
|
|
108
|
-
"path": "./CONFIGURATION.md",
|
|
109
|
-
"description": "Module configuration fields, sources and materialization instructions"
|
|
110
|
-
}
|
|
111
|
-
]
|
|
49
|
+
"documentation": {
|
|
50
|
+
"docs": "DOCS.md",
|
|
51
|
+
"setup": "SETUP.md"
|
|
52
|
+
}
|
|
112
53
|
}
|
package/CONFIGURATION.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# dev-tunnel configuration
|
|
2
|
-
|
|
3
|
-
Canonical public config: `.proflow/config/dev-tunnel.json`
|
|
4
|
-
|
|
5
|
-
This file is Workspace-owned data. `platform uninstall` does not delete it. Values are JSON strings. Raw secrets must not be stored here; `secretRef` fields contain opaque references only.
|
|
6
|
-
|
|
7
|
-
## Fields
|
|
8
|
-
|
|
9
|
-
| Key | Type | Required | Sensitive | Source | Meaning |
|
|
10
|
-
|---|---|---:|---:|---|---|
|
|
11
|
-
| `publicBaseUrl` | `url` | yes | no | User or owning external/runtime Module supplies the reachable endpoint URL. | Public HTTPS URL supplied by the dev-tunnel resource |
|
|
12
|
-
| `tunnelId` | `string` | no | no | User or owning Module supplies this value according to the field description. | Persistent Microsoft Dev Tunnel identifier used when this adapter owns lifecycle start/stop |
|
|
13
|
-
| `verificationEvidenceFile` | `path` | no | no | User or owning Module supplies an absolute/local path that exists on this Workspace. | JSON evidence for real file-relay and 429/5xx verification behind the configured public ingress |
|
|
14
|
-
|
|
15
|
-
## Materialize
|
|
16
|
-
|
|
17
|
-
Create or update the canonical JSON object at:
|
|
18
|
-
|
|
19
|
-
`.proflow/config/dev-tunnel.json`
|
|
20
|
-
|
|
21
|
-
Use only declared keys and string values. Do not create a second Platform configuration database.
|
|
22
|
-
|
|
23
|
-
## Base completion check
|
|
24
|
-
|
|
25
|
-
Run `platform modules`. This Module should no longer report required keys in `missingConfig`. `platform start` performs the authoritative Module-owned validation before starting anything.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export declare const verification: {
|
|
2
|
-
readonly checks: readonly [{
|
|
3
|
-
readonly id: "tunnel-status";
|
|
4
|
-
readonly description: "dev-tunnel process reports a real running or stopped state";
|
|
5
|
-
readonly lifecycle: "status";
|
|
6
|
-
}, {
|
|
7
|
-
readonly id: "tunnel-public-ingress";
|
|
8
|
-
readonly description: "public HTTPS ingress passes the frozen TLS/port/size/latency contract";
|
|
9
|
-
readonly lifecycle: "verify";
|
|
10
|
-
}, {
|
|
11
|
-
readonly id: "tunnel-file-relay";
|
|
12
|
-
readonly description: "file relay behind the public ingress is reachable";
|
|
13
|
-
readonly lifecycle: "verify";
|
|
14
|
-
}, {
|
|
15
|
-
readonly id: "tunnel-diagnostics";
|
|
16
|
-
readonly description: "dev-tunnel configuration has actionable diagnostics";
|
|
17
|
-
readonly lifecycle: "doctor";
|
|
18
|
-
}];
|
|
19
|
-
};
|