| @@ -7,6 +7,7 @@ · 6 unmodified lines |
| 7 | 7 | * name (`@executor-js/sdk`) instead of relying on workspace resolution. |
| 8 | 8 | */ |
| 9 | 9 | import { $ } from "bun"; |
| 10 | +import { Schema } from "effect"; |
| 10 | 11 | import { existsSync, readdirSync } from "node:fs"; |
| 11 | 12 | import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; |
| 12 | 13 | import { tmpdir } from "node:os"; |
| @@ -14,10 +15,15 @@ import { dirname, join, resolve } from "node:path"; · 1 unmodified line |
| 14 | 15 | import { fileURLToPath } from "node:url"; |
| 15 | 16 | |
| 16 | 17 | const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); |
| 17 | | −const documentedPackages = ["@executor-js/sdk", "@executor-js/plugin-openapi"] as const; |
| 18 | +const documentedPackages = [ |
| 19 | + "@executor-js/sdk", |
| 20 | + "@executor-js/product-access", |
| 21 | + "@executor-js/plugin-openapi", |
| 22 | +] as const; |
| 18 | 23 | const publicPackageDirs = [ |
| 19 | 24 | "packages/core/fumadb", |
| 20 | 25 | "packages/core/sdk", |
| 26 | + "packages/core/product-access", |
| 21 | 27 | "packages/core/config", |
| 22 | 28 | "packages/plugins/openapi", |
| 23 | 29 | ] as const; |
| @@ -27,6 +33,21 @@ const readPackageName = async (pkgDir: string): Promise<string> => { · 3 unmodified lines |
| 27 | 33 | return (JSON.parse(raw) as { name: string }).name; |
| 28 | 34 | }; |
| 29 | 35 | |
| 36 | +// `effect` is the SDK's (and product-access's) required peer, and the docs |
| 37 | +// install command tells consumers to add it themselves. `npm install |
| 38 | +// --legacy-peer-deps` below skips auto-installing peers, so the fixture must |
| 39 | +// declare it like a real consumer would — pinned from the workspace catalog |
| 40 | +// so it matches what the packed manifests resolved `catalog:` to. |
| 41 | +const decodeCatalog = Schema.decodeUnknownSync( |
| 42 | + Schema.Struct({ catalog: Schema.Struct({ effect: Schema.NonEmptyString }) }), |
| 43 | +); |
| 44 | + |
| 45 | +const readCatalogEffectVersion = async (): Promise<string> => { |
| 46 | + const raw = await readFile(join(repoRoot, "package.json"), "utf8"); |
| 47 | + const manifest = decodeCatalog(JSON.parse(raw)); |
| 48 | + return manifest.catalog.effect; |
| 49 | +}; |
| 50 | + |
| 30 | 51 | const findTarball = (pkgDir: string, packageName: string): string => { |
| 31 | 52 | const tarball = readdirSync(pkgDir).find((entry) => entry.endsWith(".tgz")); |
| 32 | 53 | if (!tarball) { |
| @@ -48,7 +69,7 @@ for (const relDir of publicPackageDirs) { · 15 unmodified lines |
| 48 | 69 | const tmp = await mkdtemp(join(tmpdir(), "executor-docs-install-")); |
| 49 | 70 | |
| 50 | 71 | try { |
| 51 | | − const dependencies: Record<string, string> = {}; |
| 72 | + const dependencies: Record<string, string> = { effect: await readCatalogEffectVersion() }; |
| 52 | 73 | const overrides: Record<string, string> = {}; |
| 53 | 74 | for (const [name, tarball] of tarballs) { |
| 54 | 75 | overrides[name] = `file:${tarball}`; |
| @@ -89,9 +110,23 @@ try { · 34 unmodified lines |
| 89 | 110 | } |
| 90 | 111 | |
| 91 | 112 | console.log(`[docs-smoke] import documented SDK packages`); |
| 92 | | − await $`node --input-type=module --eval ${`const sdk = await import("@executor-js/sdk"); const openapi = await import("@executor-js/plugin-openapi"); if (typeof sdk.createExecutor !== "function") throw new Error("missing createExecutor"); if (typeof openapi.openApiPlugin !== "function") throw new Error("missing openApiPlugin");`}`.cwd( |
| 93 | | − tmp, |
| 94 | | − ); |
| 113 | + // The documented minimal embed: the SDK root export is the Promise façade |
| 114 | + // and ships no access posture of its own, so the probe constructs a |
| 115 | + // subject-less workspace-service executor with the posture from |
| 116 | + // `@executor-js/product-access` (ephemeral in-memory backend, nothing |
| 117 | + // invoked over the network) and closes it. |
| 118 | + const importProbe = [ |
| 119 | + `const sdk = await import("@executor-js/sdk");`, |
| 120 | + `const access = await import("@executor-js/product-access");`, |
| 121 | + `const openapi = await import("@executor-js/plugin-openapi");`, |
| 122 | + `if (typeof sdk.createExecutor !== "function") throw new Error("missing createExecutor");`, |
| 123 | + `if (typeof access.workspaceServiceAccess !== "function") throw new Error("missing workspaceServiceAccess");`, |
| 124 | + `if (typeof openapi.openApiPlugin !== "function") throw new Error("missing openApiPlugin");`, |
| 125 | + `const executor = await sdk.createExecutor({ access: access.workspaceServiceAccess(), onElicitation: "accept-all" });`, |
| 126 | + `if (typeof executor.close !== "function") throw new Error("missing executor.close");`, |
| 127 | + `await executor.close();`, |
| 128 | + ].join("\n"); |
| 129 | + await $`node --input-type=module --eval ${importProbe}`.cwd(tmp); |
| 95 | 130 | } finally { |
| 96 | 131 | await rm(tmp, { recursive: true, force: true }); |
| 97 | 132 | } |