saasfunnels 0.5.0 → 0.5.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 +2 -0
- package/dist/library.js +1 -1
- package/dist/saasfunnels.js +72 -9
- package/dist/types/identity.d.ts +1 -1
- package/dist/types/mcp.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,6 +114,8 @@ CLI 0.5.0 requires Setup contract 4 and stops before creating a run against an o
|
|
|
114
114
|
|
|
115
115
|
Discovery follows Git ignore rules (including custom build folders) while keeping tracked application sources and new, non-ignored source files. Standalone folders without Git use the standard source filters.
|
|
116
116
|
|
|
117
|
+
The coding-agent installation handoff can also create `.saasfunnels/shared-installation.json` with the shared host's source binding, supported entry families, and `entryBindings` naming each installed application event, API invocation, or lifecycle entry by its exact `kind` and `key`. Setup submits that binding once using the existing workspace, integration, environment, and installation revision. It records progress after each accepted stage. If the file is absent, existing workspace installation evidence is preserved; creating another Funnel never requires this file or another catalog upload. The application must still verify the installed host and hooks at runtime before Setup marks them connected.
|
|
118
|
+
|
|
117
119
|
The command does not implement arbitrary payment code, approve feature access, or verify transactions. Complete **Review and verify** in Setup after deploying the runtime and payment integration. Requires the server's guided setup API release.
|
|
118
120
|
|
|
119
121
|
### Discovery accuracy and review
|
package/dist/library.js
CHANGED
|
@@ -235858,7 +235858,7 @@ function validateFeatureCatalogManifest(value) {
|
|
|
235858
235858
|
|
|
235859
235859
|
// src/identity.ts
|
|
235860
235860
|
var SAASFUNNELS_CLI_NAME = "saasfunnels";
|
|
235861
|
-
var SAASFUNNELS_CLI_VERSION = "0.5.
|
|
235861
|
+
var SAASFUNNELS_CLI_VERSION = "0.5.1";
|
|
235862
235862
|
var SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
|
|
235863
235863
|
var SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
|
|
235864
235864
|
var SAASFUNNELS_ENV = Object.freeze({
|
package/dist/saasfunnels.js
CHANGED
|
@@ -218902,6 +218902,10 @@ var require_dist = __commonJS({
|
|
|
218902
218902
|
// src/saasfunnels.ts
|
|
218903
218903
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
218904
218904
|
|
|
218905
|
+
// src/cli.ts
|
|
218906
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
218907
|
+
import { promisify as promisify5 } from "node:util";
|
|
218908
|
+
|
|
218905
218909
|
// src/setup-access.ts
|
|
218906
218910
|
import { execFile } from "node:child_process";
|
|
218907
218911
|
import { readFile } from "node:fs/promises";
|
|
@@ -234044,7 +234048,7 @@ function extractSetupPatch(source, catalog, baseline) {
|
|
|
234044
234048
|
|
|
234045
234049
|
// src/identity.ts
|
|
234046
234050
|
var SAASFUNNELS_CLI_NAME = "saasfunnels";
|
|
234047
|
-
var SAASFUNNELS_CLI_VERSION = "0.5.
|
|
234051
|
+
var SAASFUNNELS_CLI_VERSION = "0.5.1";
|
|
234048
234052
|
var SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
|
|
234049
234053
|
var SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
|
|
234050
234054
|
var SAASFUNNELS_ENV = Object.freeze({
|
|
@@ -238214,6 +238218,7 @@ var contextSchema = external_exports.object({
|
|
|
238214
238218
|
installationId: external_exports.string().nullable(),
|
|
238215
238219
|
integrationId: external_exports.string().nullable(),
|
|
238216
238220
|
environment: external_exports.enum(["test", "production"]),
|
|
238221
|
+
sharedInstallation: external_exports.object({ registryRevision: external_exports.number().int().nonnegative().nullable(), fingerprint: external_exports.string().nullable(), verified: external_exports.boolean() }).optional(),
|
|
238217
238222
|
catalogReady: external_exports.boolean(),
|
|
238218
238223
|
planNames: external_exports.array(external_exports.string()),
|
|
238219
238224
|
catalogPrices: external_exports.array(
|
|
@@ -238386,7 +238391,7 @@ async function runGuidedSetup(options) {
|
|
|
238386
238391
|
})).run;
|
|
238387
238392
|
if (!run) throw new Error("Setup did not return a run.");
|
|
238388
238393
|
await mkdir3(join6(options.cwd, ".saasfunnels"), { recursive: true });
|
|
238389
|
-
|
|
238394
|
+
const saveRun = () => writeFile3(
|
|
238390
238395
|
statePath,
|
|
238391
238396
|
JSON.stringify(
|
|
238392
238397
|
{
|
|
@@ -238394,13 +238399,32 @@ async function runGuidedSetup(options) {
|
|
|
238394
238399
|
generation: context.generation,
|
|
238395
238400
|
repositoryKey,
|
|
238396
238401
|
revision,
|
|
238397
|
-
runId: run.id
|
|
238402
|
+
runId: run.id,
|
|
238403
|
+
receipts: run.receipts
|
|
238398
238404
|
},
|
|
238399
238405
|
null,
|
|
238400
238406
|
2
|
|
238401
238407
|
) + "\n",
|
|
238402
238408
|
{ mode: 384 }
|
|
238403
238409
|
);
|
|
238410
|
+
await saveRun();
|
|
238411
|
+
try {
|
|
238412
|
+
const shared = JSON.parse(await readFile6(join6(options.cwd, ".saasfunnels", "shared-installation.json"), "utf8"));
|
|
238413
|
+
if (context.sharedInstallation?.registryRevision == null)
|
|
238414
|
+
throw new Error("The app connection has not issued a verified identity yet. Complete its shared installation first.");
|
|
238415
|
+
await request("/api/developer-tools/setup/installation", {
|
|
238416
|
+
...shared,
|
|
238417
|
+
schemaVersion: 1,
|
|
238418
|
+
installationId: context.installationId,
|
|
238419
|
+
installationRevision: context.sharedInstallation.registryRevision,
|
|
238420
|
+
integrationId: context.integrationId,
|
|
238421
|
+
environment: context.environment,
|
|
238422
|
+
repositoryKey,
|
|
238423
|
+
repositoryRevision: head
|
|
238424
|
+
});
|
|
238425
|
+
} catch (error51) {
|
|
238426
|
+
if (error51.code !== "ENOENT") throw error51;
|
|
238427
|
+
}
|
|
238404
238428
|
const update = (state, failureCode = null) => {
|
|
238405
238429
|
progressState = state;
|
|
238406
238430
|
progressFailure = failureCode;
|
|
@@ -238446,6 +238470,7 @@ async function runGuidedSetup(options) {
|
|
|
238446
238470
|
if (typeof result3.sequence === "number")
|
|
238447
238471
|
run.sequence = result3.sequence;
|
|
238448
238472
|
run.receipts[currentStage] = result3.receipt ?? { complete: true };
|
|
238473
|
+
await saveRun();
|
|
238449
238474
|
if (currentStage === "plans")
|
|
238450
238475
|
run.planNames = result3.planNames ?? evidence.plans.flatMap((plan) => [plan.key, plan.name]);
|
|
238451
238476
|
});
|
|
@@ -240767,7 +240792,14 @@ async function commandFeatures(args, flags, options) {
|
|
|
240767
240792
|
}
|
|
240768
240793
|
if (args[0] === "handoff") {
|
|
240769
240794
|
const path2 = flagString(flags, "file") ?? ".saasfunnels/catalog.yaml";
|
|
240770
|
-
const
|
|
240795
|
+
const gitValue = async (...args2) => {
|
|
240796
|
+
try {
|
|
240797
|
+
return (await promisify5(execFile5)("git", args2, { cwd: cwd(options), timeout: 5e3, maxBuffer: 8192 })).stdout.trim();
|
|
240798
|
+
} catch {
|
|
240799
|
+
return "";
|
|
240800
|
+
}
|
|
240801
|
+
};
|
|
240802
|
+
const repositoryRevision = flagString(flags, "repository-revision") ?? await gitValue("rev-parse", "HEAD");
|
|
240771
240803
|
if (!repositoryRevision) {
|
|
240772
240804
|
return result(
|
|
240773
240805
|
2,
|
|
@@ -240775,7 +240807,16 @@ async function commandFeatures(args, flags, options) {
|
|
|
240775
240807
|
"Missing --repository-revision for the structured Feature handoff.\n"
|
|
240776
240808
|
);
|
|
240777
240809
|
}
|
|
240778
|
-
|
|
240810
|
+
let repositoryKey = flagString(flags, "repository-key");
|
|
240811
|
+
if (!repositoryKey) {
|
|
240812
|
+
const remote = await gitValue("remote", "get-url", "origin");
|
|
240813
|
+
if (remote) {
|
|
240814
|
+
try {
|
|
240815
|
+
repositoryKey = safeRepositoryKey(remote);
|
|
240816
|
+
} catch {
|
|
240817
|
+
}
|
|
240818
|
+
}
|
|
240819
|
+
}
|
|
240779
240820
|
if (!repositoryKey) {
|
|
240780
240821
|
return result(
|
|
240781
240822
|
2,
|
|
@@ -240796,10 +240837,32 @@ async function commandFeatures(args, flags, options) {
|
|
|
240796
240837
|
);
|
|
240797
240838
|
}
|
|
240798
240839
|
const discoveryRoots = (flagString(flags, "discovery-roots") ?? "").split(",").map((root) => root.trim()).filter(Boolean);
|
|
240799
|
-
|
|
240800
|
-
|
|
240801
|
-
"utf8"
|
|
240802
|
-
)
|
|
240840
|
+
let source;
|
|
240841
|
+
try {
|
|
240842
|
+
source = await filesystem(options).readFile(resolve5(cwd(options), path2), "utf8");
|
|
240843
|
+
} catch (error51) {
|
|
240844
|
+
if (error51.code !== "ENOENT") throw error51;
|
|
240845
|
+
const key4 = envValue2(options, SAASFUNNELS_ENV.apiKey);
|
|
240846
|
+
if (key4 && !flagString(flags, "file")) {
|
|
240847
|
+
const query = new URLSearchParams({ repositoryKey, repositoryRevision, environment: flagString(flags, "environment") ?? "production", ...flagString(flags, "discovery-roots") ? { discoveryRoots: JSON.stringify([...discoveryRoots].sort()) } : {} });
|
|
240848
|
+
try {
|
|
240849
|
+
const response = await (options.fetch ?? fetch)(`${apiBaseUrl2(options, flags)}/api/developer-tools/features/instrumentation?${query}`, { headers: { authorization: `Bearer ${key4}` }, signal: AbortSignal.timeout(15e3) });
|
|
240850
|
+
if (response.ok) {
|
|
240851
|
+
const evidence = await response.json();
|
|
240852
|
+
if (evidence.reused === true) return jsonMode(flags) ? jsonResult(0, { reused: true, currentRevision: evidence.currentRevision === true, manifestFingerprint: evidence.manifestFingerprint, validatedAt: evidence.validatedAt }) : result(
|
|
240853
|
+
0,
|
|
240854
|
+
`Reused the existing workspace Feature evidence. No catalog was uploaded.${evidence.currentRevision ? "" : " This is the previous scan, not verification of this checkout; Setup shows any remaining review."} Open Setup to continue.
|
|
240855
|
+
`
|
|
240856
|
+
);
|
|
240857
|
+
} else if (response.status !== 404) {
|
|
240858
|
+
return result(2, "", "Workspace Feature evidence could not be checked. Open Setup to check the connection and resume; your existing catalog has not changed.\n");
|
|
240859
|
+
}
|
|
240860
|
+
} catch {
|
|
240861
|
+
return result(2, "", "Workspace Feature evidence could not be checked. Open Setup to check the connection and resume; your existing catalog has not changed.\n");
|
|
240862
|
+
}
|
|
240863
|
+
}
|
|
240864
|
+
return result(2, "", "No local discovery file was found. Open Setup to reuse your workspace catalog and finish any missing connection steps. Do not recreate the catalog.\n");
|
|
240865
|
+
}
|
|
240803
240866
|
const validation = parseFeatureManifestSource(source);
|
|
240804
240867
|
if (!validation.ok || !validation.manifest) {
|
|
240805
240868
|
return jsonMode(flags) ? jsonResult(1, validation) : result(
|
package/dist/types/identity.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const SAASFUNNELS_CLI_NAME = "saasfunnels";
|
|
2
|
-
export declare const SAASFUNNELS_CLI_VERSION = "0.5.
|
|
2
|
+
export declare const SAASFUNNELS_CLI_VERSION = "0.5.1";
|
|
3
3
|
export declare const SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
|
|
4
4
|
export declare const SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
|
|
5
5
|
export declare const SAASFUNNELS_ENV: Readonly<{
|
package/dist/types/mcp.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export type SaaSFunnelsMcpOptions = {
|
|
|
77
77
|
output?: Pick<NodeJS.WritableStream, "write">;
|
|
78
78
|
};
|
|
79
79
|
declare const mcpProtocolVersion = "2025-06-18";
|
|
80
|
-
declare const mcpServerVersion = "0.5.
|
|
80
|
+
declare const mcpServerVersion = "0.5.1";
|
|
81
81
|
export declare function saasFunnelsMcpResources(): McpResourceDefinition[];
|
|
82
82
|
export declare function readSaaSFunnelsMcpResource(uri: string, options?: SaaSFunnelsMcpOptions): string;
|
|
83
83
|
export declare function saasFunnelsMcpToolDefinitions({ allowFunnelTests, allowFunnelWrites, allowTestWrites, includeHostedAccountTools, }?: {
|